From ec9b58ada9738ca4f5cdcb0b25e4e9d822a6546a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 28 Jul 2009 21:26:36 +0200 Subject: [PATCH] Add i3-msg, a sample implementation and hopefully useful utility --- Makefile | 75 ++++------------------------------ common.mk | 70 ++++++++++++++++++++++++++++++++ i3-msg/Makefile | 28 +++++++++++++ i3-msg/main.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 68 deletions(-) create mode 100644 common.mk create mode 100644 i3-msg/Makefile create mode 100644 i3-msg/main.c diff --git a/Makefile b/Makefile index a42099d4..8666d9ef 100644 --- a/Makefile +++ b/Makefile @@ -1,72 +1,6 @@ -UNAME=$(shell uname) -DEBUG=1 -INSTALL=install -GIT_VERSION=$(shell git describe --tags --always) -VERSION=$(shell git describe --tags --abbrev=0) +TOPDIR=$(shell pwd) -CFLAGS += -std=c99 -CFLAGS += -pipe -CFLAGS += -Wall -CFLAGS += -Wunused -CFLAGS += -Iinclude -CFLAGS += -I/usr/local/include -CFLAGS += -DI3_VERSION=\"${GIT_VERSION}\" - -# Check if pkg-config is installed, because without pkg-config, the following -# check for the version of libxcb cannot be done. -ifeq ($(shell which pkg-config 2>/dev/null 1>/dev/null || echo 1),1) -$(error "pkg-config was not found") -endif - -ifeq ($(shell pkg-config --exists xcb-keysyms || echo 1),1) -$(error "pkg-config could not find xcb-keysyms.pc") -endif - -ifeq ($(shell pkg-config --exact-version=0.3.3 xcb-keysyms && echo 1),1) -# xcb-keysyms fixed API from 0.3.3 to 0.3.4, so for some months, we will -# have this here. Distributions should upgrade their libxcb in the meantime. -CFLAGS += -DOLD_XCB_KEYSYMS_API -endif - -LDFLAGS += -lm -LDFLAGS += -lxcb-event -LDFLAGS += -lxcb-property -LDFLAGS += -lxcb-keysyms -LDFLAGS += -lxcb-atom -LDFLAGS += -lxcb-aux -LDFLAGS += -lxcb-icccm -LDFLAGS += -lxcb-xinerama -LDFLAGS += -lX11 -LDFLAGS += -lev -LDFLAGS += -L/usr/local/lib -L/usr/pkg/lib - -ifeq ($(UNAME),NetBSD) -# We need -idirafter instead of -I to prefer the system’s iconv over GNU libiconv -CFLAGS += -idirafter /usr/pkg/include -LDFLAGS += -Wl,-rpath,/usr/local/lib -Wl,-rpath,/usr/pkg/lib -endif - -ifeq ($(UNAME),FreeBSD) -LDFLAGS += -liconv -endif - -ifeq ($(UNAME),Linux) -CFLAGS += -D_GNU_SOURCE -endif - -ifeq ($(DEBUG),1) -# Extended debugging flags, macros shall be available in gcc -CFLAGS += -gdwarf-2 -CFLAGS += -g3 -else -CFLAGS += -O2 -endif - -# Don’t print command lines which are run -.SILENT: - -# Always remake the following targets -.PHONY: install clean dist distclean +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 src/*.c)) @@ -80,6 +14,9 @@ src/%.o: src/%.c ${HEADERS} all: ${FILES} echo "LINK i3" $(CC) -o i3 ${FILES} $(LDFLAGS) + echo "" + echo "SUBDIR i3-msg" + $(MAKE) TOPDIR=$(TOPDIR) -C i3-msg install: all echo "INSTALL" @@ -89,6 +26,7 @@ install: all $(INSTALL) -m 0755 i3 $(DESTDIR)/usr/bin/ 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 dist: clean [ ! -d i3-${VERSION} ] || rm -rf i3-${VERSION} @@ -108,6 +46,7 @@ clean: rm -f src/*.o $(MAKE) -C docs clean $(MAKE) -C man clean + $(MAKE) TOPDIR=$(TOPDIR) -C i3-msg clean distclean: clean rm -f i3 diff --git a/common.mk b/common.mk new file mode 100644 index 00000000..7944196c --- /dev/null +++ b/common.mk @@ -0,0 +1,70 @@ +UNAME=$(shell uname) +DEBUG=1 +INSTALL=install +GIT_VERSION=$(shell git describe --tags --always) +VERSION=$(shell git describe --tags --abbrev=0) + +CFLAGS += -std=c99 +CFLAGS += -pipe +CFLAGS += -Wall +CFLAGS += -Wunused +CFLAGS += -Iinclude +CFLAGS += -I/usr/local/include +CFLAGS += -DI3_VERSION=\"${GIT_VERSION}\" + +# Check if pkg-config is installed, because without pkg-config, the following +# check for the version of libxcb cannot be done. +ifeq ($(shell which pkg-config 2>/dev/null 1>/dev/null || echo 1),1) +$(error "pkg-config was not found") +endif + +ifeq ($(shell pkg-config --exists xcb-keysyms || echo 1),1) +$(error "pkg-config could not find xcb-keysyms.pc") +endif + +ifeq ($(shell pkg-config --exact-version=0.3.3 xcb-keysyms && echo 1),1) +# xcb-keysyms fixed API from 0.3.3 to 0.3.4, so for some months, we will +# have this here. Distributions should upgrade their libxcb in the meantime. +CFLAGS += -DOLD_XCB_KEYSYMS_API +endif + +LDFLAGS += -lm +LDFLAGS += -lxcb-event +LDFLAGS += -lxcb-property +LDFLAGS += -lxcb-keysyms +LDFLAGS += -lxcb-atom +LDFLAGS += -lxcb-aux +LDFLAGS += -lxcb-icccm +LDFLAGS += -lxcb-xinerama +LDFLAGS += -lX11 +LDFLAGS += -lev +LDFLAGS += -L/usr/local/lib -L/usr/pkg/lib + +ifeq ($(UNAME),NetBSD) +# We need -idirafter instead of -I to prefer the system’s iconv over GNU libiconv +CFLAGS += -idirafter /usr/pkg/include +LDFLAGS += -Wl,-rpath,/usr/local/lib -Wl,-rpath,/usr/pkg/lib +endif + +ifeq ($(UNAME),FreeBSD) +LDFLAGS += -liconv +endif + +ifeq ($(UNAME),Linux) +CFLAGS += -D_GNU_SOURCE +endif + +ifeq ($(DEBUG),1) +# Extended debugging flags, macros shall be available in gcc +CFLAGS += -gdwarf-2 +CFLAGS += -g3 +else +CFLAGS += -O2 +endif + +# Don’t print command lines which are run +.SILENT: + +# Always remake the following targets +.PHONY: install clean dist distclean + diff --git a/i3-msg/Makefile b/i3-msg/Makefile new file mode 100644 index 00000000..a5e15b6e --- /dev/null +++ b/i3-msg/Makefile @@ -0,0 +1,28 @@ +# Default value so one can compile i3-msg 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-msg" + $(CC) -o i3-msg ${FILES} $(LDFLAGS) + +install: all + echo "INSTALL" + $(INSTALL) -d -m 0755 $(DESTDIR)/usr/bin + $(INSTALL) -m 0755 i3-msg $(DESTDIR)/usr/bin/ + +clean: + rm -f *.o + +distclean: clean + rm -f i3-msg diff --git a/i3-msg/main.c b/i3-msg/main.c new file mode 100644 index 00000000..8404be3e --- /dev/null +++ b/i3-msg/main.c @@ -0,0 +1,105 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * © 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + * i3-msg/main.c: Utility which sends messages to a running i3-instance using + * IPC via UNIX domain sockets. + * + * This serves as an example for how to send your own messages to i3. + * Additionally, it’s even useful sometimes :-). + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static 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; + } +} + +int main(int argc, char *argv[]) { + char *socket_path = "/tmp/i3-ipc.sock"; + int o, option_index = 0; + + static struct option long_options[] = { + {"socket", required_argument, 0, 's'}, + {"type", required_argument, 0, 't'}, + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + char *options_string = "s:t:vh"; + + while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { + if (o == 's') { + socket_path = strdup(optarg); + break; + } else if (o == 't') { + printf("currently only commands are implemented\n"); + } else if (o == 'v') { + printf("i3-msg " I3_VERSION); + return 0; + } else if (o == 'h') { + printf("i3-msg " I3_VERSION); + printf("i3-msg [-s ] [-t ] \n"); + return 0; + } + } + + if (optind >= argc) { + fprintf(stderr, "Error: missing message\n"); + fprintf(stderr, "i3-msg [-s ] [-t ] \n"); + return 1; + } + + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + 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, &addr, sizeof(struct sockaddr_un)) < 0) + err(-1, "Could not connect to i3"); + + ipc_send_message(sockfd, strlen(argv[optind]), 0, (uint8_t*)argv[optind]); + + close(sockfd); + + return 0; +} -- 2.39.5