From 02df973564f67edd4a91a0ff8bc74df057860b5b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 22 Jul 2010 01:15:18 +0200 Subject: [PATCH 001/185] Start tracking changes --- i3bar/.gitignore | 1 + i3bar/Makefile | 18 ++ i3bar/common.mk | 9 + i3bar/include/common.h | 19 ++ i3bar/include/ipc.h | 14 + i3bar/include/outputs.h | 27 ++ i3bar/include/queue.h | 527 ++++++++++++++++++++++++++++++++++++ i3bar/include/util.h | 22 ++ i3bar/include/workspaces.h | 26 ++ i3bar/include/xcb.h | 24 ++ i3bar/include/xcb_atoms.def | 4 + i3bar/src/ipc.c | 308 +++++++++++++++++++++ i3bar/src/main.c | 29 ++ i3bar/src/outputs.c | 225 +++++++++++++++ i3bar/src/workspaces.c | 229 ++++++++++++++++ i3bar/src/xcb.c | 125 +++++++++ 16 files changed, 1607 insertions(+) create mode 100644 i3bar/.gitignore create mode 100644 i3bar/Makefile create mode 100644 i3bar/common.mk create mode 100644 i3bar/include/common.h create mode 100644 i3bar/include/ipc.h create mode 100644 i3bar/include/outputs.h create mode 100644 i3bar/include/queue.h create mode 100644 i3bar/include/util.h create mode 100644 i3bar/include/workspaces.h create mode 100644 i3bar/include/xcb.h create mode 100644 i3bar/include/xcb_atoms.def create mode 100644 i3bar/src/ipc.c create mode 100644 i3bar/src/main.c create mode 100644 i3bar/src/outputs.c create mode 100644 i3bar/src/workspaces.c create mode 100644 i3bar/src/xcb.c diff --git a/i3bar/.gitignore b/i3bar/.gitignore new file mode 100644 index 00000000..a890aa1d --- /dev/null +++ b/i3bar/.gitignore @@ -0,0 +1 @@ +i3bar diff --git a/i3bar/Makefile b/i3bar/Makefile new file mode 100644 index 00000000..172a442d --- /dev/null +++ b/i3bar/Makefile @@ -0,0 +1,18 @@ +TOPDIR=$(shell pwd) + +include $(TOPDIR)/common.mk + +FILES:=$(wildcard src/*.c) +FILES:=$(FILES:.c=.o) +HEADERS:=$(wildcard include/*.h) + +all: ${FILES} + echo "LINK" + $(CC) -o i3bar ${FILES} ${LDFLAGS} + +src/%.o: src/%.c ${HEADERS} + echo "CC $<" + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm src/*.o diff --git a/i3bar/common.mk b/i3bar/common.mk new file mode 100644 index 00000000..e2be3aab --- /dev/null +++ b/i3bar/common.mk @@ -0,0 +1,9 @@ +CFLAGS += -Wall +CFLAGS += -pipe +CFLAGS += -Iinclude +CFLAGS += -g +LDFLAGS += -lev +LDFLAGS += -lyajl +LDFLAGS += -lxcb +LDFLAGS += -lxcb-atom +.SILENT: diff --git a/i3bar/include/common.h b/i3bar/include/common.h new file mode 100644 index 00000000..431c4694 --- /dev/null +++ b/i3bar/include/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H_ +#define COMMON_H_ + +#include "util.h" + +typedef int bool; + +typedef struct rect_t rect; + +struct rect_t { + int x; + int y; + int w; + int h; +}; + +struct ev_loop* main_loop; + +#endif diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h new file mode 100644 index 00000000..45565618 --- /dev/null +++ b/i3bar/include/ipc.h @@ -0,0 +1,14 @@ +#ifndef IPC_H_ +#define IPC_H_ + +#include + +ev_io* i3_events; +ev_io* outputs_watcher; +ev_io* workspaces_watcher; + +void init_i3(const char* socket_path); +void get_outputs_json(void (*callback)(char*, void*), void* params); +void get_workspaces_json(void (*callback)(char*, void*), void* params); + +#endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h new file mode 100644 index 00000000..83364c2f --- /dev/null +++ b/i3bar/include/outputs.h @@ -0,0 +1,27 @@ +#ifndef OUTPUTS_H_ +#define OUTPUTS_H_ + +#include "common.h" +#include + +typedef struct i3_output_t i3_output; + +i3_output* outputs; + +void refresh_outputs(); +void free_outputs(); +i3_output* get_output_by_name(char* name); + +struct i3_output_t { + char* name; + bool active; + int ws; + rect rect; + + xcb_window_t win; + xcb_gcontext_t gctx; + + i3_output* next; +}; + +#endif diff --git a/i3bar/include/queue.h b/i3bar/include/queue.h new file mode 100644 index 00000000..75bb957a --- /dev/null +++ b/i3bar/include/queue.h @@ -0,0 +1,527 @@ +/* $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/i3bar/include/util.h b/i3bar/include/util.h new file mode 100644 index 00000000..2e55e114 --- /dev/null +++ b/i3bar/include/util.h @@ -0,0 +1,22 @@ +#ifndef UTIL_H_ +#define UTIL_H_ + +/* Securely free p */ +#define FREE(p) do { \ + if (p != NULL) { \ + free(p); \ + p = NULL; \ + } \ +} while (0) + +/* Securely fee single-linked list */ +#define FREE_LIST(l, type) do { \ + type* FREE_LIST_TMP; \ + while (l != NULL) { \ + FREE_LIST_TMP = l; \ + free(l); \ + l = l->next; \ + } \ +} while (0) + +#endif diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h new file mode 100644 index 00000000..ad6ac787 --- /dev/null +++ b/i3bar/include/workspaces.h @@ -0,0 +1,26 @@ +#ifndef WORKSPACES_H_ +#define WORKSPACES_H_ + +#include "common.h" +#include "outputs.h" + +typedef struct i3_ws_t i3_ws; + +i3_ws* workspaces; + +void refresh_workspaces(); +void free_workspaces(); + +struct i3_ws_t { + int num; + char* name; + bool visible; + bool focused; + bool urgent; + rect rect; + i3_output* output; + + i3_ws* next; +}; + +#endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h new file mode 100644 index 00000000..69c53b83 --- /dev/null +++ b/i3bar/include/xcb.h @@ -0,0 +1,24 @@ +#ifndef XCB_H_ +#define XCB_H_ + +#include + +#define NUM_ATOMS 3 + +enum { + #define ATOM_DO(name) name, + #include "xcb_atoms.def" +}; + +xcb_atom_t atoms[NUM_ATOMS]; + +xcb_connection_t* xcb_connection; +xcb_screen_t* xcb_screens; +xcb_window_t xcb_root; + +void init_xcb(); +void clean_xcb(); +void get_atoms(); +void create_windows(); + +#endif diff --git a/i3bar/include/xcb_atoms.def b/i3bar/include/xcb_atoms.def new file mode 100644 index 00000000..5084231c --- /dev/null +++ b/i3bar/include/xcb_atoms.def @@ -0,0 +1,4 @@ +ATOM_DO(ATOM) +ATOM_DO(_NET_WM_WINDOW_TYPE) +ATOM_DO(_NET_WM_WINDOW_TYPE_DOCK) +#undef ATOM_DO diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c new file mode 100644 index 00000000..35d3d5be --- /dev/null +++ b/i3bar/src/ipc.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "ipc.h" + +struct callback_t { + void (*callback)(char*, void*); + void* params; + struct callback_t* next; +}; + +struct callback_t* outputs_cb_queue; +struct callback_t* workspaces_cb_queue; + +int get_ipc_fd(const char* socket_path) { + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) { + printf("ERROR: Could not create Socket!\n"); + exit(EXIT_FAILURE); + } + + 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) { + printf("ERROR: Could not connct to i3\n"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void get_outputs_cb(struct ev_loop* loop, ev_io *watcher, int revents) { + +} + +void init_i3(const char* socket_path) { + int sockfd = get_ipc_fd(socket_path); + + struct get_outputs_callback* cb = malloc(sizeof(struct get_outputs_callback)); + cb->callback = callback; + cb->params = params; + + ev_io* get_outputs_write = malloc(sizeof(ev_io)); + + ev_io_init(get_outputs_write, &get_outputs_write_cb, sockfd, EV_WRITE); + get_outputs_write->data = (void*) cb; + ev_io_start(main_loop, get_outputs_write); + + ev_io* get_outputs_read = malloc(sizeof(ev_io)); + ev_io_init(get_outputs_read, &get_outputs_read_cb, sockfd, EV_READ); + get_outputs_read->data = (void*) cb; + ev_io_start(main_loop, get_outputs_read); +} + + +void get_outputs_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { + ev_io_stop(loop, watcher); + + int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); + char msg[buffer_size]; + char *walk = msg; + uint32_t msg_size = 0; + uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS; + int sockfd = watcher->fd; + + strcpy(walk, I3_IPC_MAGIC); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &msg_size, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &msg_type, sizeof(uint32_t)); + + 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) { + printf("ERROR: write() failed!\n"); + exit(EXIT_FAILURE); + } + + sent_bytes += n; + bytes_to_go -= n; + } + FREE(watcher); +} + +void get_outputs_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { + ev_io_stop(loop, watcher); + + int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); + char msg[to_read]; + char *walk = msg; + int sockfd = watcher->fd; + uint8_t *reply; + struct get_outputs_callback* cb = watcher->data; + + uint32_t reply_length; + + uint32_t read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, msg + read_bytes, to_read); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + if (n == 0) { + printf("ERROR: No reply!\n"); + exit(EXIT_FAILURE); + } + + read_bytes += n; + to_read -= n; + } + + if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { + printf("ERROR: Wrong magic!\n"); + exit(EXIT_FAILURE); + } + + walk += strlen(I3_IPC_MAGIC); + reply_length = *((uint32_t*) walk); + walk += sizeof(uint32_t); + if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_OUTPUTS) { + printf("ERROR: Wrong reply type (%d) expected %d!\n", + *((uint32_t*) walk), + I3_IPC_MESSAGE_TYPE_GET_OUTPUTS); + exit(EXIT_FAILURE); + } + walk += sizeof(uint32_t); + + reply = malloc(reply_length); + if (reply == NULL) { + printf("ERROR: malloc() failed!\n"); + exit(EXIT_FAILURE); + } + + to_read = reply_length; + read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, reply + read_bytes, to_read); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + + read_bytes += n; + to_read -= n; + } + + cb->callback((char*) reply, cb->params); + FREE(cb); + FREE(watcher); +} + +void get_outputs_json(void (*callback)(char*, void*), void* params) { +} + + + +struct get_workspaces_callback { + void (*callback)(char*, void*); + void* params; +}; + +void get_workspaces_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { + ev_io_stop(loop, watcher); + //FREE(watcher); + + int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); + char msg[buffer_size]; + char *walk = msg; + uint32_t msg_size = 0; + uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES; + int sockfd = watcher->fd; + + strcpy(walk, I3_IPC_MAGIC); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &msg_size, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &msg_type, sizeof(uint32_t)); + + 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) { + printf("ERROR: write() failed!\n"); + exit(EXIT_FAILURE); + } + + sent_bytes += n; + bytes_to_go -= n; + } + FREE(watcher); +} + +void get_workspaces_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { + ev_io_stop(loop, watcher); + //FREE(watcher); + + int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); + char msg[to_read]; + char *walk = msg; + int sockfd = watcher->fd; + uint8_t *reply; + struct get_workspaces_callback* cb = watcher->data; + + uint32_t reply_length; + + uint32_t read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, msg + read_bytes, to_read); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + if (n == 0) { + printf("ERROR: No reply!\n"); + exit(EXIT_FAILURE); + } + + read_bytes += n; + to_read -= n; + } + + if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { + printf("ERROR: Wrong magic!\n"); + exit(EXIT_FAILURE); + } + + walk += strlen(I3_IPC_MAGIC); + reply_length = *((uint32_t*) walk); + walk += sizeof(uint32_t); + if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_WORKSPACES) { + printf("ERROR: Wrong reply type (%d) expected %d!\n", + *((uint32_t*) walk), + I3_IPC_MESSAGE_TYPE_GET_WORKSPACES); + exit(EXIT_FAILURE); + } + walk += sizeof(uint32_t); + + reply = malloc(reply_length); + if (reply == NULL) { + printf("ERROR: malloc() failed!\n"); + exit(EXIT_FAILURE); + } + + to_read = reply_length; + read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, reply + read_bytes, to_read); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + + read_bytes += n; + to_read -= n; + } + + cb->callback((char*) reply, cb->params); + FREE(cb); + + FREE(watcher); +} + +void get_workspaces_json(void (*callback)(char*, void*), void* params) { + socket_path = "/home/mero/.i3/ipc.sock"; + + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) { + printf("ERROR: Could not create Socket!\n"); + exit(EXIT_FAILURE); + } + + 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) { + printf("ERROR: Could not connct to i3\n"); + exit(EXIT_FAILURE); + } + + struct get_workspaces_callback* cb = malloc(sizeof(struct get_workspaces_callback)); + cb->callback = callback; + cb->params = params; + + ev_io* get_workspaces_write = malloc(sizeof(ev_io)); + + ev_io_init(get_workspaces_write, &get_workspaces_write_cb, sockfd, EV_WRITE); + get_workspaces_write->data = (void*) cb; + ev_io_start(main_loop, get_workspaces_write); + + ev_io* get_workspaces_read = malloc(sizeof(ev_io)); + ev_io_init(get_workspaces_read, &get_workspaces_read_cb, sockfd, EV_READ); + get_workspaces_read->data = (void*) cb; + ev_io_start(main_loop, get_workspaces_read); +} diff --git a/i3bar/src/main.c b/i3bar/src/main.c new file mode 100644 index 00000000..90a48ee2 --- /dev/null +++ b/i3bar/src/main.c @@ -0,0 +1,29 @@ +#include "ipc.h" +#include "outputs.h" +#include "workspaces.h" +#include "common.h" +#include "xcb.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) { + main_loop = ev_default_loop(0); + + init_xcb(); + + refresh_outputs(&create_windows, NULL); + refresh_workspaces(NULL, NULL); + + ev_loop(main_loop, 0); + + ev_default_destroy(); + clean_xcb(); + free_outputs(); + free_workspaces(); + + //sleep(5); + return 0; +} diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c new file mode 100644 index 00000000..2b2600b5 --- /dev/null +++ b/i3bar/src/outputs.c @@ -0,0 +1,225 @@ +#include +#include +#include + +#include + +#include "common.h" +#include "outputs.h" +#include "ipc.h" + +struct outputs_json_params { + i3_output* outputs; + i3_output* outputs_walk; + char* cur_key; + char* json; + void (*callback)(void*); + void* cb_params; +}; + +static int outputs_null_cb(void* params_) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + + if (strcmp(params->cur_key, "current_workspace")) { + return 0; + } + + FREE(params->cur_key); + + return 1; +} + +static int outputs_boolean_cb(void* params_, bool val) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + + if (strcmp(params->cur_key, "active")) { + return 0; + } + + params->outputs_walk->active = val; + + FREE(params->cur_key); + + return 1; +} + +static int outputs_integer_cb(void* params_, long val) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + + if (!strcmp(params->cur_key, "current_workspace")) { + params->outputs_walk->ws = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "x")) { + params->outputs_walk->rect.x = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "y")) { + params->outputs_walk->rect.y = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "width")) { + params->outputs_walk->rect.w = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "height")) { + params->outputs_walk->rect.h = (int) val; + FREE(params->cur_key); + return 1; + } + + return 0; +} + +static int outputs_string_cb(void* params_, const unsigned char* val, unsigned int len) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + + if (strcmp(params->cur_key, "name")) { + return 0; + } + + params->outputs_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(params->outputs_walk->name, (const char*) val, len); + params->outputs_walk->name[len] = '\0'; + + FREE(params->cur_key); + + return 1; +} + +static int outputs_start_map_cb(void* params_) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + i3_output* new_output = NULL; + + if (params->cur_key == NULL) { + new_output = malloc(sizeof(i3_output)); + new_output->name = NULL; + new_output->ws = 0, + memset(&new_output->rect, 0, sizeof(rect)); + new_output->next = NULL; + + if (params->outputs == NULL) { + params->outputs = new_output; + } else { + params->outputs_walk->next = new_output; + } + + params->outputs_walk = new_output; + return 1; + } + + return 1; +} + +static int outputs_map_key_cb(void* params_, const unsigned char* keyVal, unsigned int keyLen) { + struct outputs_json_params* params = (struct outputs_json_params*) params_; + FREE(params->cur_key); + + params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + strncpy(params->cur_key, (const char*) keyVal, keyLen); + params->cur_key[keyLen] = '\0'; + + return 1; +} + +yajl_callbacks outputs_callbacks = { + &outputs_null_cb, + &outputs_boolean_cb, + &outputs_integer_cb, + NULL, + NULL, + &outputs_string_cb, + &outputs_start_map_cb, + &outputs_map_key_cb, + NULL, + NULL, + NULL +}; + +void got_outputs_json_cb(char* json, void* params_) { + /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret + * JSON in chunks */ + struct outputs_json_params* params = (struct outputs_json_params*) params_; + + yajl_handle handle; + yajl_parser_config parse_conf = { 0, 0 }; + yajl_status state; + + params->json = json; + + handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) params); + + state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); + + /* FIXME: Propper errorhandling for JSON-parsing */ + switch (state) { + case yajl_status_ok: + break; + case yajl_status_client_canceled: + case yajl_status_insufficient_data: + case yajl_status_error: + printf("ERROR: Could not parse outputs-reply!\n"); + exit(EXIT_FAILURE); + break; + } + + yajl_free(handle); + + free_outputs(); + outputs = params->outputs; + + if (params->callback != NULL) { + params->callback(params->cb_params); + } + + FREE(params->json); + FREE(params); +} + +void refresh_outputs(void (*callback)(void*), void* cb_params) { + struct outputs_json_params* params = malloc(sizeof(struct outputs_json_params)); + + params->outputs = NULL; + params->outputs_walk = NULL; + params->cur_key = NULL; + params->json = NULL; + params->callback = callback; + params->cb_params = cb_params; + + get_outputs_json(&got_outputs_json_cb, params); +} + +void free_outputs() { + i3_output* tmp; + while (outputs != NULL) { + tmp = outputs; + outputs = outputs->next; + FREE(tmp->name); + FREE(tmp); + } +} + +i3_output* get_output_by_name(char* name) { + if (outputs == NULL) { + refresh_outputs(NULL, NULL); + return NULL; + } + + i3_output* walk; + + for (walk = outputs; walk != NULL; walk = walk->next) { + if (strcmp(walk->name, name)) { + break; + } + } + + return walk; +} diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c new file mode 100644 index 00000000..15927631 --- /dev/null +++ b/i3bar/src/workspaces.c @@ -0,0 +1,229 @@ +#include +#include +#include + +#include + +#include "common.h" +#include "workspaces.h" +#include "ipc.h" + +struct workspaces_json_params { + i3_ws* workspaces; + i3_ws* workspaces_walk; + char* cur_key; + char* json; +}; + +static int workspaces_null_cb(void* params_) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + + if (strcmp(params->cur_key, "current_workspace")) { + return 0; + } + + FREE(params->cur_key); + + return 1; +} + +static int workspaces_boolean_cb(void* params_, bool val) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + + if (!strcmp(params->cur_key, "visible")) { + params->workspaces_walk->visible = val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "focused")) { + params->workspaces_walk->focused = val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "urgent")) { + params->workspaces_walk->focused = val; + FREE(params->cur_key); + return 1; + } + + FREE(params->cur_key); + + return 0; +} + +static int workspaces_integer_cb(void* params_, long val) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + + if (!strcmp(params->cur_key, "num")) { + params->workspaces_walk->num = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "x")) { + params->workspaces_walk->rect.x = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "y")) { + params->workspaces_walk->rect.y = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "width")) { + params->workspaces_walk->rect.w = (int) val; + FREE(params->cur_key); + return 1; + } + + if (!strcmp(params->cur_key, "height")) { + params->workspaces_walk->rect.h = (int) val; + FREE(params->cur_key); + return 1; + } + + FREE(params->cur_key); + return 0; +} + +static int workspaces_string_cb(void* params_, const unsigned char* val, unsigned int len) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + + char* output_name; + + if (!strcmp(params->cur_key, "name")) { + params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(params->workspaces_walk->name, (const char*) val, len); + params->workspaces_walk->name[len] = '\0'; + + FREE(params->cur_key); + + return 1; + } + + if (!strcmp(params->cur_key, "output")) { + output_name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(output_name, (const char*) val, len); + output_name[len] = '\0'; + params->workspaces_walk->output = get_output_by_name(output_name); + free(output_name); + + return 1; + } + + return 0; +} + +static int workspaces_start_map_cb(void* params_) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + i3_ws* new_workspace = NULL; + + if (params->cur_key == NULL) { + new_workspace = malloc(sizeof(i3_ws)); + new_workspace->num = -1; + new_workspace->name = NULL; + new_workspace->visible = 0; + new_workspace->focused = 0; + new_workspace->urgent = 0; + memset(&new_workspace->rect, 0, sizeof(rect)); + new_workspace->output = NULL; + new_workspace->next = NULL; + + if (params->workspaces == NULL) { + params->workspaces = new_workspace; + } else { + params->workspaces_walk->next = new_workspace; + } + + params->workspaces_walk = new_workspace; + return 1; + } + + return 1; +} + +static int workspaces_map_key_cb(void* params_, const unsigned char* keyVal, unsigned int keyLen) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + FREE(params->cur_key); + + params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + strncpy(params->cur_key, (const char*) keyVal, keyLen); + params->cur_key[keyLen] = '\0'; + + return 1; +} + +yajl_callbacks workspaces_callbacks = { + &workspaces_null_cb, + &workspaces_boolean_cb, + &workspaces_integer_cb, + NULL, + NULL, + &workspaces_string_cb, + &workspaces_start_map_cb, + &workspaces_map_key_cb, + NULL, + NULL, + NULL +}; + +void got_workspaces_json_cb(char* json, void* params_) { + /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret + * JSON in chunks */ + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + + yajl_handle handle; + yajl_parser_config parse_conf = { 0, 0 }; + yajl_status state; + + params->json = json; + + handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) params); + + state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); + + /* FIXME: Propper errorhandling for JSON-parsing */ + switch (state) { + case yajl_status_ok: + break; + case yajl_status_client_canceled: + case yajl_status_insufficient_data: + case yajl_status_error: + printf("ERROR: Could not parse workspaces-reply!\n"); + exit(EXIT_FAILURE); + break; + } + + yajl_free(handle); + + free_workspaces(); + workspaces = params->workspaces; + + FREE(params->json); + FREE(params); +} + +void refresh_workspaces() { + struct workspaces_json_params* params = malloc(sizeof(struct workspaces_json_params)); + + params->workspaces = NULL; + params->workspaces_walk = NULL; + params->cur_key = NULL; + params->json = NULL; + + get_workspaces_json(&got_workspaces_json_cb, params); +} + +void free_workspaces() { + i3_ws* tmp; + while (workspaces != NULL) { + tmp = workspaces; + workspaces = workspaces->next; + FREE(tmp->name); + FREE(tmp); + } +} diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c new file mode 100644 index 00000000..d23d114b --- /dev/null +++ b/i3bar/src/xcb.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#include "xcb.h" +#include "outputs.h" + +xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; + +void init_xcb() { + /* LEAK: xcb_connect leaks Memory */ + xcb_connection = xcb_connect(NULL, NULL); + if (xcb_connection_has_error(xcb_connection)) { + printf("Cannot open display\n"); + exit(EXIT_FAILURE); + } + printf("Connected to xcb\n"); + + /* We have to request the atoms we need */ + #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); + #include "xcb_atoms.def" + + xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; + xcb_root = xcb_screens->root; + + /* FIXME: Maybe we can push that further backwards */ + get_atoms(); +} + +void clean_xcb() { + xcb_disconnect(xcb_connection); +} + +void get_atoms() { + xcb_intern_atom_reply_t* reply; + #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ + atoms[name] = reply->atom; \ + free(reply); + + #include "xcb_atoms.def" + printf("Got Atoms\n"); +} + +void create_windows() { + uint32_t mask; + uint32_t values[2]; + + i3_output* walk = outputs; + while (walk != NULL) { + if (!walk->active) { + walk = walk->next; + continue; + } + printf("Creating Window for output %s\n", walk->name); + + walk->win = xcb_generate_id(xcb_connection); + mask = XCB_CW_BACK_PIXEL; + values[0] = xcb_screens->black_pixel; + xcb_create_window(xcb_connection, + xcb_screens->root_depth, + walk->win, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, 20, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->win, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + + xcb_map_window(xcb_connection, walk->win); + walk = walk->next; + } + xcb_flush(xcb_connection); +} + +#if 0 + xcb_screen_t* screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; + + xcb_gcontext_t ctx = xcb_generate_id(xcb_connection); + + xcb_window_t win = screens->root; + uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; + uint32_t values[2]; + values[0] = screens->black_pixel; + values[1] = 0; + xcb_create_gc(xcb_connection, ctx, win, mask, values); + + request_atoms(); + + /* Fenster erzeugen */ + win = xcb_generate_id(xcb_connection); + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + values[0] = screens->white_pixel; + values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; + xcb_create_window(xcb_connection, screens->root_depth, win, screens->root, + 10, 10, 20, 20, 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, screens->root_visual, + mask, values); + + get_atoms(); + + xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + win, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char *) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + + xcb_map_window(xcb_connection, win); + + xcb_flush(xcb_connection); +#endif From fb2afacce3fb5b805ce8e32e91edfd29ec3c84ca Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 23 Jul 2010 04:43:43 +0200 Subject: [PATCH 002/185] Rework the IPC-Code --- i3bar/include/ipc.h | 11 +- i3bar/include/outputs.h | 2 +- i3bar/include/workspaces.h | 2 +- i3bar/src/ipc.c | 354 +++++++++++++------------------------ i3bar/src/main.c | 15 +- i3bar/src/outputs.c | 39 ++-- i3bar/src/workspaces.c | 33 ++-- 7 files changed, 158 insertions(+), 298 deletions(-) diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index 45565618..278077e0 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -2,13 +2,10 @@ #define IPC_H_ #include +#include -ev_io* i3_events; -ev_io* outputs_watcher; -ev_io* workspaces_watcher; - -void init_i3(const char* socket_path); -void get_outputs_json(void (*callback)(char*, void*), void* params); -void get_workspaces_json(void (*callback)(char*, void*), void* params); +int init_connection(const char *socket_path); +int i3_send_msg(uint32_t type, const char* payload); +void subscribe_events(); #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 83364c2f..0c241527 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -8,7 +8,7 @@ typedef struct i3_output_t i3_output; i3_output* outputs; -void refresh_outputs(); +void parse_outputs_json(char* json); void free_outputs(); i3_output* get_output_by_name(char* name); diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index ad6ac787..339b8890 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -8,7 +8,7 @@ typedef struct i3_ws_t i3_ws; i3_ws* workspaces; -void refresh_workspaces(); +void parse_workspaces_json(); void free_workspaces(); struct i3_ws_t { diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 35d3d5be..b753c088 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -1,24 +1,19 @@ +#include #include -#include +#include +#include #include #include -#include -#include -#include -#include #include #include "common.h" +#include "outputs.h" +#include "workspaces.h" #include "ipc.h" -struct callback_t { - void (*callback)(char*, void*); - void* params; - struct callback_t* next; -}; +ev_io* i3_connection; -struct callback_t* outputs_cb_queue; -struct callback_t* workspaces_cb_queue; +typedef void(*handler_t)(char*); int get_ipc_fd(const char* socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); @@ -38,271 +33,164 @@ int get_ipc_fd(const char* socket_path) { return sockfd; } -void get_outputs_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - +void got_command_reply(char *reply) { } -void init_i3(const char* socket_path) { - int sockfd = get_ipc_fd(socket_path); - - struct get_outputs_callback* cb = malloc(sizeof(struct get_outputs_callback)); - cb->callback = callback; - cb->params = params; - - ev_io* get_outputs_write = malloc(sizeof(ev_io)); - - ev_io_init(get_outputs_write, &get_outputs_write_cb, sockfd, EV_WRITE); - get_outputs_write->data = (void*) cb; - ev_io_start(main_loop, get_outputs_write); - - ev_io* get_outputs_read = malloc(sizeof(ev_io)); - ev_io_init(get_outputs_read, &get_outputs_read_cb, sockfd, EV_READ); - get_outputs_read->data = (void*) cb; - ev_io_start(main_loop, get_outputs_read); +void got_workspace_reply(char *reply) { + printf("Got Workspace-Data!\n"); + parse_workspaces_json(reply); } - -void get_outputs_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - - int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[buffer_size]; - char *walk = msg; - uint32_t msg_size = 0; - uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS; - int sockfd = watcher->fd; - - strcpy(walk, I3_IPC_MAGIC); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &msg_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &msg_type, sizeof(uint32_t)); - - 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) { - printf("ERROR: write() failed!\n"); - exit(EXIT_FAILURE); - } - - sent_bytes += n; - bytes_to_go -= n; - } - FREE(watcher); +void got_subscribe_reply(char *reply) { + printf("Got Subscribe Reply: %s\n", reply); } -void get_outputs_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - - int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[to_read]; - char *walk = msg; - int sockfd = watcher->fd; - uint8_t *reply; - struct get_outputs_callback* cb = watcher->data; - - uint32_t reply_length; - - uint32_t read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, msg + read_bytes, to_read); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - if (n == 0) { - printf("ERROR: No reply!\n"); - exit(EXIT_FAILURE); - } - - read_bytes += n; - to_read -= n; - } - - if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { - printf("ERROR: Wrong magic!\n"); - exit(EXIT_FAILURE); - } - - walk += strlen(I3_IPC_MAGIC); - reply_length = *((uint32_t*) walk); - walk += sizeof(uint32_t); - if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_OUTPUTS) { - printf("ERROR: Wrong reply type (%d) expected %d!\n", - *((uint32_t*) walk), - I3_IPC_MESSAGE_TYPE_GET_OUTPUTS); - exit(EXIT_FAILURE); - } - walk += sizeof(uint32_t); - - reply = malloc(reply_length); - if (reply == NULL) { - printf("ERROR: malloc() failed!\n"); - exit(EXIT_FAILURE); - } - - to_read = reply_length; - read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, reply + read_bytes, to_read); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - - read_bytes += n; - to_read -= n; - } - - cb->callback((char*) reply, cb->params); - FREE(cb); - FREE(watcher); +void got_output_reply(char *reply) { + parse_outputs_json(reply); + printf("Got Outputs-Data!\n"); } -void get_outputs_json(void (*callback)(char*, void*), void* params) { -} - - - -struct get_workspaces_callback { - void (*callback)(char*, void*); - void* params; +handler_t reply_handlers[] = { + &got_command_reply, + &got_workspace_reply, + &got_subscribe_reply, + &got_output_reply, }; -void get_workspaces_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - //FREE(watcher); - - int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[buffer_size]; - char *walk = msg; - uint32_t msg_size = 0; - uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES; - int sockfd = watcher->fd; - - strcpy(walk, I3_IPC_MAGIC); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &msg_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &msg_type, sizeof(uint32_t)); - - 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) { - printf("ERROR: write() failed!\n"); - exit(EXIT_FAILURE); - } - - sent_bytes += n; - bytes_to_go -= n; - } - FREE(watcher); +void got_workspace_event(char *event) { + printf("Got Workspace Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } -void get_workspaces_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - //FREE(watcher); +void got_output_event(char *event) { + printf("Got Output Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); +} - int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[to_read]; - char *walk = msg; - int sockfd = watcher->fd; - uint8_t *reply; - struct get_workspaces_callback* cb = watcher->data; +handler_t event_handlers[] = { + &got_workspace_event, + &got_output_event +}; - uint32_t reply_length; +void got_data(struct ev_loop *loop, ev_io *watcher, int events) { + printf("Got data!\n"); + int fd = watcher->fd; + uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; + char *header = malloc(header_len); + if (header == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } - uint32_t read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, msg + read_bytes, to_read); + uint32_t rec = 0; + while (rec < header_len) { + int n = read(fd, header + rec, header_len - rec); if (n == -1) { printf("ERROR: read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: No reply!\n"); + printf("ERROR: Nothing to read!\n"); exit(EXIT_FAILURE); } - - read_bytes += n; - to_read -= n; + rec += n; } - - if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { - printf("ERROR: Wrong magic!\n"); + + if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { + printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", + (int) strlen(I3_IPC_MAGIC), + header, + I3_IPC_MAGIC); exit(EXIT_FAILURE); } - walk += strlen(I3_IPC_MAGIC); - reply_length = *((uint32_t*) walk); + char *walk = header + strlen(I3_IPC_MAGIC); + uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); - if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_WORKSPACES) { - printf("ERROR: Wrong reply type (%d) expected %d!\n", - *((uint32_t*) walk), - I3_IPC_MESSAGE_TYPE_GET_WORKSPACES); + uint32_t type = *((uint32_t*) walk); + char *buffer = malloc(size + 1); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory!\n"); exit(EXIT_FAILURE); } - walk += sizeof(uint32_t); + rec = 0; - reply = malloc(reply_length); - if (reply == NULL) { - printf("ERROR: malloc() failed!\n"); - exit(EXIT_FAILURE); - } - - to_read = reply_length; - read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, reply + read_bytes, to_read); + while (rec < size) { + int n = read(fd, buffer + rec, size - rec); if (n == -1) { printf("ERROR: read() failed!\n"); exit(EXIT_FAILURE); } - - read_bytes += n; - to_read -= n; + if (n == 0) { + printf("ERROR: Nothing to read!\n"); + exit(EXIT_FAILURE); + } + rec += n; } + buffer[size] = '\0'; - cb->callback((char*) reply, cb->params); - FREE(cb); + if (type & (1 << 31)) { + type ^= 1 << 31; + event_handlers[type](buffer); + } else { + reply_handlers[type](buffer); + } - FREE(watcher); + FREE(buffer); } -void get_workspaces_json(void (*callback)(char*, void*), void* params) { - socket_path = "/home/mero/.i3/ipc.sock"; +int i3_send_msg(uint32_t type, const char* payload) { + uint32_t len = 0; + if (payload != NULL) { + len = strlen(payload); + } - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) { - printf("ERROR: Could not create Socket!\n"); + uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; + char *buffer = malloc(to_write); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory\n"); exit(EXIT_FAILURE); } - 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) { - printf("ERROR: Could not connct to i3\n"); - exit(EXIT_FAILURE); + char *walk = buffer; + + strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &len, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &type, sizeof(uint32_t)); + walk += sizeof(uint32_t); + + strncpy(walk, payload, len); + + uint32_t written = 0; + + while (to_write > 0) { + int n = write(i3_connection->fd, buffer + written, to_write); + if (n == -1) { + printf("ERROR: write() failed!\n"); + exit(EXIT_FAILURE); + } + + to_write -= n; + written += n; } - struct get_workspaces_callback* cb = malloc(sizeof(struct get_workspaces_callback)); - cb->callback = callback; - cb->params = params; + FREE(buffer); - ev_io* get_workspaces_write = malloc(sizeof(ev_io)); - - ev_io_init(get_workspaces_write, &get_workspaces_write_cb, sockfd, EV_WRITE); - get_workspaces_write->data = (void*) cb; - ev_io_start(main_loop, get_workspaces_write); - - ev_io* get_workspaces_read = malloc(sizeof(ev_io)); - ev_io_init(get_workspaces_read, &get_workspaces_read_cb, sockfd, EV_READ); - get_workspaces_read->data = (void*) cb; - ev_io_start(main_loop, get_workspaces_read); + return 1; +} + +int init_connection(const char *socket_path) { + int sockfd = get_ipc_fd(socket_path); + + i3_connection = malloc(sizeof(ev_io)); + ev_io_init(i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, i3_connection); + + return 1; +} + +void subscribe_events() { + i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 90a48ee2..dbb6104c 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -1,21 +1,21 @@ +#include +#include +#include +#include + #include "ipc.h" #include "outputs.h" #include "workspaces.h" #include "common.h" #include "xcb.h" -#include -#include -#include -#include - int main(int argc, char **argv) { main_loop = ev_default_loop(0); init_xcb(); + init_connection("/home/mero/.i3/ipc.sock"); - refresh_outputs(&create_windows, NULL); - refresh_workspaces(NULL, NULL); + subscribe_events(); ev_loop(main_loop, 0); @@ -24,6 +24,5 @@ int main(int argc, char **argv) { free_outputs(); free_workspaces(); - //sleep(5); return 0; } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 2b2600b5..6ddfa8c9 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -13,8 +14,6 @@ struct outputs_json_params { i3_output* outputs_walk; char* cur_key; char* json; - void (*callback)(void*); - void* cb_params; }; static int outputs_null_cb(void* params_) { @@ -144,18 +143,20 @@ yajl_callbacks outputs_callbacks = { NULL }; -void got_outputs_json_cb(char* json, void* params_) { +void parse_outputs_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ - struct outputs_json_params* params = (struct outputs_json_params*) params_; + struct outputs_json_params params; + params.outputs = NULL; + params.outputs_walk = NULL; + params.cur_key = NULL; + params.json = json; yajl_handle handle; yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; - params->json = json; - - handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) params); + handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -174,27 +175,7 @@ void got_outputs_json_cb(char* json, void* params_) { yajl_free(handle); free_outputs(); - outputs = params->outputs; - - if (params->callback != NULL) { - params->callback(params->cb_params); - } - - FREE(params->json); - FREE(params); -} - -void refresh_outputs(void (*callback)(void*), void* cb_params) { - struct outputs_json_params* params = malloc(sizeof(struct outputs_json_params)); - - params->outputs = NULL; - params->outputs_walk = NULL; - params->cur_key = NULL; - params->json = NULL; - params->callback = callback; - params->cb_params = cb_params; - - get_outputs_json(&got_outputs_json_cb, params); + outputs = params.outputs; } void free_outputs() { @@ -209,7 +190,7 @@ void free_outputs() { i3_output* get_output_by_name(char* name) { if (outputs == NULL) { - refresh_outputs(NULL, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); return NULL; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 15927631..aa97bccc 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -91,6 +91,7 @@ static int workspaces_integer_cb(void* params_, long val) { } static int workspaces_string_cb(void* params_, const unsigned char* val, unsigned int len) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; char* output_name; @@ -151,6 +152,10 @@ static int workspaces_map_key_cb(void* params_, const unsigned char* keyVal, uns FREE(params->cur_key); params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + if (params->cur_key == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } strncpy(params->cur_key, (const char*) keyVal, keyLen); params->cur_key[keyLen] = '\0'; @@ -171,18 +176,20 @@ yajl_callbacks workspaces_callbacks = { NULL }; -void got_workspaces_json_cb(char* json, void* params_) { +void parse_workspaces_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + struct workspaces_json_params params; + params.workspaces = NULL; + params.workspaces_walk = NULL; + params.cur_key = NULL; + params.json = json; yajl_handle handle; yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; - params->json = json; - - handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) params); + handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -201,21 +208,9 @@ void got_workspaces_json_cb(char* json, void* params_) { yajl_free(handle); free_workspaces(); - workspaces = params->workspaces; + workspaces = params.workspaces; - FREE(params->json); - FREE(params); -} - -void refresh_workspaces() { - struct workspaces_json_params* params = malloc(sizeof(struct workspaces_json_params)); - - params->workspaces = NULL; - params->workspaces_walk = NULL; - params->cur_key = NULL; - params->json = NULL; - - get_workspaces_json(&got_workspaces_json_cb, params); + FREE(params.cur_key); } void free_workspaces() { From a3a7a2ca522dd6486259423d9a7eb9a2cceffe96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 23 Jul 2010 04:44:12 +0200 Subject: [PATCH 003/185] Add temporary files to .gitignore --- i3bar/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/.gitignore b/i3bar/.gitignore index a890aa1d..01e7ad61 100644 --- a/i3bar/.gitignore +++ b/i3bar/.gitignore @@ -1 +1,3 @@ i3bar +*.o +core From 72b55fdd4ff8fac8f103c9979807e30a613ccac8 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 23 Jul 2010 05:04:13 +0200 Subject: [PATCH 004/185] Get outputs on start. Create dock window for every output. --- i3bar/include/xcb.h | 1 + i3bar/src/ipc.c | 9 +++++++-- i3bar/src/main.c | 3 +++ i3bar/src/xcb.c | 48 ++++++++------------------------------------- 4 files changed, 19 insertions(+), 42 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 69c53b83..16bc2bdf 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -19,6 +19,7 @@ xcb_window_t xcb_root; void init_xcb(); void clean_xcb(); void get_atoms(); +void destroy_windows(); void create_windows(); #endif diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index b753c088..5d7a0bab 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -9,6 +9,7 @@ #include "common.h" #include "outputs.h" #include "workspaces.h" +#include "xcb.h" #include "ipc.h" ev_io* i3_connection; @@ -42,12 +43,16 @@ void got_workspace_reply(char *reply) { } void got_subscribe_reply(char *reply) { - printf("Got Subscribe Reply: %s\n", reply); + printf("Got Subscribe Reply: %s\n", reply); } void got_output_reply(char *reply) { + printf("Got Outputs-Data!\nDestroying Windows...\n"); + destroy_windows(); + printf("Parsing JSON...\n"); parse_outputs_json(reply); - printf("Got Outputs-Data!\n"); + printf("Creating_Windows,,,\n"); + create_windows(); } handler_t reply_handlers[] = { diff --git a/i3bar/src/main.c b/i3bar/src/main.c index dbb6104c..b42d227c 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,6 +18,8 @@ int main(int argc, char **argv) { subscribe_events(); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + ev_loop(main_loop, 0); ev_default_destroy(); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index d23d114b..20cc23c1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -42,6 +42,14 @@ void get_atoms() { printf("Got Atoms\n"); } +void destroy_windows() { + i3_output *walk = outputs; + while(walk != NULL) { + xcb_destroy_window(xcb_connection, walk->win); + walk->win = XCB_NONE; + } +} + void create_windows() { uint32_t mask; uint32_t values[2]; @@ -83,43 +91,3 @@ void create_windows() { } xcb_flush(xcb_connection); } - -#if 0 - xcb_screen_t* screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; - - xcb_gcontext_t ctx = xcb_generate_id(xcb_connection); - - xcb_window_t win = screens->root; - uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; - uint32_t values[2]; - values[0] = screens->black_pixel; - values[1] = 0; - xcb_create_gc(xcb_connection, ctx, win, mask, values); - - request_atoms(); - - /* Fenster erzeugen */ - win = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - values[0] = screens->white_pixel; - values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; - xcb_create_window(xcb_connection, screens->root_depth, win, screens->root, - 10, 10, 20, 20, 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, screens->root_visual, - mask, values); - - get_atoms(); - - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - win, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char *) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - - xcb_map_window(xcb_connection, win); - - xcb_flush(xcb_connection); -#endif From 8a274bd2790f950635b4908cbe79c29edb30f863 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 26 Jul 2010 17:21:46 +0200 Subject: [PATCH 005/185] Draw the workspace-buttons --- i3bar/include/outputs.h | 4 +- i3bar/include/xcb.h | 1 + i3bar/src/ipc.c | 5 ++- i3bar/src/main.c | 1 + i3bar/src/outputs.c | 3 +- i3bar/src/xcb.c | 97 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 100 insertions(+), 11 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 0c241527..75f0a359 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -18,8 +18,8 @@ struct i3_output_t { int ws; rect rect; - xcb_window_t win; - xcb_gcontext_t gctx; + xcb_window_t bar; + xcb_gcontext_t bargc; i3_output* next; }; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 16bc2bdf..5bd781c1 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -21,5 +21,6 @@ void clean_xcb(); void get_atoms(); void destroy_windows(); void create_windows(); +void draw_buttons(); #endif diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 5d7a0bab..46c1e8ca 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -35,15 +35,18 @@ int get_ipc_fd(const char* socket_path) { } void got_command_reply(char *reply) { + /* FIXME: Error handling for command-replies */ } void got_workspace_reply(char *reply) { printf("Got Workspace-Data!\n"); parse_workspaces_json(reply); + draw_buttons(); } void got_subscribe_reply(char *reply) { printf("Got Subscribe Reply: %s\n", reply); + /* FIXME: Error handling for subscribe-commands */ } void got_output_reply(char *reply) { @@ -51,7 +54,7 @@ void got_output_reply(char *reply) { destroy_windows(); printf("Parsing JSON...\n"); parse_outputs_json(reply); - printf("Creating_Windows,,,\n"); + printf("Creating_Windows...\n"); create_windows(); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index b42d227c..fbef9cf0 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -19,6 +19,7 @@ int main(int argc, char **argv) { subscribe_events(); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); ev_loop(main_loop, 0); diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 6ddfa8c9..2066b3d4 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -104,6 +104,7 @@ static int outputs_start_map_cb(void* params_) { new_output->ws = 0, memset(&new_output->rect, 0, sizeof(rect)); new_output->next = NULL; + new_output->bar = XCB_NONE; if (params->outputs == NULL) { params->outputs = new_output; @@ -197,7 +198,7 @@ i3_output* get_output_by_name(char* name) { i3_output* walk; for (walk = outputs; walk != NULL; walk = walk->next) { - if (strcmp(walk->name, name)) { + if (!strcmp(walk->name, name)) { break; } } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 20cc23c1..fbfc02ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -5,11 +5,22 @@ #include "xcb.h" #include "outputs.h" +#include "workspaces.h" xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; +uint32_t get_colorpixel(const char *s) { + char strings[3][3] = { { s[0], s[1], '\0'} , + { s[2], s[3], '\0'} , + { s[4], s[5], '\0'} }; + uint8_t r = strtol(strings[0], NULL, 16); + uint8_t g = strtol(strings[1], NULL, 16); + uint8_t b = strtol(strings[2], NULL, 16); + return (r << 16 | g << 8 | b); +} + void init_xcb() { - /* LEAK: xcb_connect leaks Memory */ + /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); if (xcb_connection_has_error(xcb_connection)) { printf("Cannot open display\n"); @@ -45,8 +56,11 @@ void get_atoms() { void destroy_windows() { i3_output *walk = outputs; while(walk != NULL) { - xcb_destroy_window(xcb_connection, walk->win); - walk->win = XCB_NONE; + if (walk->bar == XCB_NONE) { + continue; + } + xcb_destroy_window(xcb_connection, walk->bar); + walk->bar = XCB_NONE; } } @@ -62,12 +76,12 @@ void create_windows() { } printf("Creating Window for output %s\n", walk->name); - walk->win = xcb_generate_id(xcb_connection); + walk->bar = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL; values[0] = xcb_screens->black_pixel; xcb_create_window(xcb_connection, xcb_screens->root_depth, - walk->win, + walk->bar, xcb_root, walk->rect.x, walk->rect.y, walk->rect.w, 20, @@ -79,15 +93,84 @@ void create_windows() { xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, - walk->win, + walk->bar, atoms[_NET_WM_WINDOW_TYPE], atoms[ATOM], 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - xcb_map_window(xcb_connection, walk->win); + walk->bargc = xcb_generate_id(xcb_connection); + xcb_create_gc(xcb_connection, + walk->bargc, + walk->bar, + 0, + NULL); + + xcb_map_window(xcb_connection, walk->bar); walk = walk->next; } xcb_flush(xcb_connection); } + +void draw_buttons() { + printf("Drawing Buttons...\n"); + i3_output *outputs_walk = outputs; + int i = 0; + while (outputs_walk != NULL) { + if (!outputs_walk->active) { + printf("Output %s inactive, skipping...\n", outputs_walk->name); + outputs_walk = outputs_walk->next; + continue; + } + if (outputs_walk->bar == XCB_NONE) { + create_windows(); + } + uint32_t color = get_colorpixel("000000"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, 20 }; + xcb_poly_fill_rectangle(xcb_connection, + outputs_walk->bar, + outputs_walk->bargc, + 1, + &rect); + i3_ws *ws_walk = workspaces; + while (ws_walk != NULL) { + if (ws_walk->output != outputs_walk) { + printf("WS %s on wrong output, skipping...\n", ws_walk->name); + ws_walk = ws_walk->next; + continue; + } + printf("Drawing Button for WS %s...\n", ws_walk->name); + uint32_t color = get_colorpixel("240000"); + if (ws_walk->visible) { + color = get_colorpixel("480000"); + } + if (ws_walk->urgent) { + color = get_colorpixel("002400"); + } + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_BACKGROUND, + &color); + xcb_rectangle_t rect = { i + 1, 1, 18, 18 }; + xcb_poly_fill_rectangle(xcb_connection, + outputs_walk->bar, + outputs_walk->bargc, + 1, + &rect); + i += 20; + ws_walk = ws_walk->next; + } + outputs_walk = outputs_walk->next; + i = 0; + } + xcb_flush(xcb_connection); +} From 0f4164dd0f0ae2f44b504d86c37784bf60647cbf Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 26 Jul 2010 19:55:02 +0200 Subject: [PATCH 006/185] Print the workspace-names --- i3bar/src/xcb.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index fbfc02ad..fdd7dc15 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -117,6 +117,16 @@ void draw_buttons() { printf("Drawing Buttons...\n"); i3_output *outputs_walk = outputs; int i = 0; + xcb_font_t button_font = xcb_generate_id(xcb_connection); + char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; + xcb_open_font(xcb_connection, + button_font, + strlen(fontname), + fontname); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FONT, + &button_font); while (outputs_walk != NULL) { if (!outputs_walk->active) { printf("Output %s inactive, skipping...\n", outputs_walk->name); @@ -166,6 +176,17 @@ void draw_buttons() { outputs_walk->bargc, 1, &rect); + color = get_colorpixel("FFFFFF"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_image_text_8(xcb_connection, + strlen(ws_walk->name), + outputs_walk->bar, + outputs_walk->bargc, + i + 3, 14, + ws_walk->name); i += 20; ws_walk = ws_walk->next; } From 3883ae2738dd6f46dec672f608479fb158ca11f2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 26 Jul 2010 23:51:51 +0200 Subject: [PATCH 007/185] Handling Exposure-Events --- i3bar/src/main.c | 37 +++++++++++++++++++++++++++++++++++++ i3bar/src/xcb.c | 7 ++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index fbef9cf0..c58dc25e 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include #include "ipc.h" #include "outputs.h" @@ -10,6 +12,24 @@ #include "common.h" #include "xcb.h" +void ev_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { + xcb_flush(xcb_connection); +} + +void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { + xcb_generic_event_t *event; + if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: + draw_buttons(); + } + free(event); + } +} + +void xcb_io_cb(struct ev_loop *loop, ev_io *w, int revents) { +} + int main(int argc, char **argv) { main_loop = ev_default_loop(0); @@ -18,11 +38,28 @@ int main(int argc, char **argv) { subscribe_events(); + ev_io *xcb_io = malloc(sizeof(ev_io)); + ev_prepare *ev_prep = malloc(sizeof(ev_prepare)); + ev_check *ev_chk = malloc(sizeof(ev_check)); + + ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); + ev_prepare_init(ev_prep, &ev_prepare_cb); + ev_check_init(ev_chk, &ev_check_cb); + + ev_io_start(main_loop, xcb_io); + ev_prepare_start(main_loop, ev_prep); + ev_check_start(main_loop, ev_chk); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); ev_loop(main_loop, 0); + ev_prepare_stop(main_loop, ev_prep); + ev_check_stop(main_loop, ev_chk); + FREE(ev_prep); + FREE(ev_chk); + ev_default_destroy(); clean_xcb(); free_outputs(); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index fdd7dc15..297469fa 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -19,6 +19,10 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +void handle_xcb_event(xcb_generic_event_t ev) { + +} + void init_xcb() { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); @@ -77,8 +81,9 @@ void create_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL; + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = xcb_screens->black_pixel; + values[1] = XCB_EVENT_MASK_EXPOSURE; xcb_create_window(xcb_connection, xcb_screens->root_depth, walk->bar, From ff2ee04e0d2c23b2fcb6d5a499f80287f2d6f207 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 27 Jul 2010 02:16:49 +0200 Subject: [PATCH 008/185] Use font-size to correctly determine the size of the bars and buttons. --- i3bar/include/workspaces.h | 1 + i3bar/include/xcb.h | 3 ++ i3bar/src/workspaces.c | 6 ++++ i3bar/src/xcb.c | 63 ++++++++++++++++++++++++++++---------- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 339b8890..d4975a1e 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -14,6 +14,7 @@ void free_workspaces(); struct i3_ws_t { int num; char* name; + int name_width; bool visible; bool focused; bool urgent; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 5bd781c1..9b10348b 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -15,6 +15,8 @@ xcb_atom_t atoms[NUM_ATOMS]; xcb_connection_t* xcb_connection; xcb_screen_t* xcb_screens; xcb_window_t xcb_root; +xcb_font_t xcb_font; +int font_height; void init_xcb(); void clean_xcb(); @@ -22,5 +24,6 @@ void get_atoms(); void destroy_windows(); void create_windows(); void draw_buttons(); +int get_string_width(char *string); #endif diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index aa97bccc..e96ee9e3 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -6,6 +6,7 @@ #include "common.h" #include "workspaces.h" +#include "xcb.h" #include "ipc.h" struct workspaces_json_params { @@ -101,6 +102,11 @@ static int workspaces_string_cb(void* params_, const unsigned char* val, unsigne strncpy(params->workspaces_walk->name, (const char*) val, len); params->workspaces_walk->name[len] = '\0'; + params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->name); + + printf("Got Workspace %s, name_width: %d\n", + params->workspaces_walk->name, + params->workspaces_walk->name_width); FREE(params->cur_key); return 1; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 297469fa..6e0d9082 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -23,6 +23,23 @@ void handle_xcb_event(xcb_generic_event_t ev) { } +int get_string_width(char *string) { + xcb_query_text_extents_cookie_t cookie; + xcb_query_text_extents_reply_t *reply; + xcb_generic_error_t *error; + int width; + + cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t *)string); + if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { + printf("ERROR: Could not get text extents!"); + return 7; + } + + width = reply->overall_width; + free(reply); + return width; +} + void init_xcb() { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); @@ -39,6 +56,26 @@ void init_xcb() { xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; xcb_root = xcb_screens->root; + xcb_font = xcb_generate_id(xcb_connection); + char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; + xcb_open_font(xcb_connection, + xcb_font, + strlen(fontname), + fontname); + + xcb_list_fonts_with_info_cookie_t cookie; + cookie = xcb_list_fonts_with_info(xcb_connection, + 1, + strlen(fontname), + fontname); + xcb_list_fonts_with_info_reply_t *reply; + reply = xcb_list_fonts_with_info_reply(xcb_connection, + cookie, + NULL); + font_height = reply->font_ascent + reply->font_descent; + printf("Calculated Font-height: %d\n", font_height); + + /* FIXME: Maybe we can push that further backwards */ get_atoms(); } @@ -89,7 +126,7 @@ void create_windows() { walk->bar, xcb_root, walk->rect.x, walk->rect.y, - walk->rect.w, 20, + walk->rect.w, font_height + 6, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, xcb_screens->root_visual, @@ -106,11 +143,13 @@ void create_windows() { (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); walk->bargc = xcb_generate_id(xcb_connection); + mask = XCB_GC_FONT; + values[0] = xcb_font; xcb_create_gc(xcb_connection, walk->bargc, walk->bar, - 0, - NULL); + mask, + values); xcb_map_window(xcb_connection, walk->bar); walk = walk->next; @@ -122,16 +161,6 @@ void draw_buttons() { printf("Drawing Buttons...\n"); i3_output *outputs_walk = outputs; int i = 0; - xcb_font_t button_font = xcb_generate_id(xcb_connection); - char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; - xcb_open_font(xcb_connection, - button_font, - strlen(fontname), - fontname); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FONT, - &button_font); while (outputs_walk != NULL) { if (!outputs_walk->active) { printf("Output %s inactive, skipping...\n", outputs_walk->name); @@ -146,7 +175,7 @@ void draw_buttons() { outputs_walk->bargc, XCB_GC_FOREGROUND, &color); - xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, 20 }; + xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; xcb_poly_fill_rectangle(xcb_connection, outputs_walk->bar, outputs_walk->bargc, @@ -175,7 +204,7 @@ void draw_buttons() { outputs_walk->bargc, XCB_GC_BACKGROUND, &color); - xcb_rectangle_t rect = { i + 1, 1, 18, 18 }; + xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, outputs_walk->bar, outputs_walk->bargc, @@ -190,9 +219,9 @@ void draw_buttons() { strlen(ws_walk->name), outputs_walk->bar, outputs_walk->bargc, - i + 3, 14, + i + 5, font_height + 1, ws_walk->name); - i += 20; + i += 10 + ws_walk->name_width; ws_walk = ws_walk->next; } outputs_walk = outputs_walk->next; From 71cb49b84738b63d18a4486b41dd835448cb3081 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 27 Jul 2010 10:18:29 +0200 Subject: [PATCH 009/185] Move XCB-Event-Handling to xcb.c --- i3bar/src/main.c | 5 +---- i3bar/src/xcb.c | 6 +++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index c58dc25e..0be8a7a7 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -19,10 +19,7 @@ void ev_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { xcb_generic_event_t *event; if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { - switch (event->response_type & ~0x80) { - case XCB_EXPOSE: - draw_buttons(); - } + handle_xcb_event(event); free(event); } } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6e0d9082..38ceb947 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -20,7 +20,11 @@ uint32_t get_colorpixel(const char *s) { } void handle_xcb_event(xcb_generic_event_t ev) { - + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: + draw_buttons(); + break; + } } int get_string_width(char *string) { From 654b51fef104067ee083dfeb7d5a5ba6d277796a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 29 Jul 2010 20:19:59 +0200 Subject: [PATCH 010/185] Correctly parse the urgent-hint --- i3bar/src/workspaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index e96ee9e3..3d363ecb 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -44,7 +44,7 @@ static int workspaces_boolean_cb(void* params_, bool val) { } if (!strcmp(params->cur_key, "urgent")) { - params->workspaces_walk->focused = val; + params->workspaces_walk->urgent = val; FREE(params->cur_key); return 1; } From 43c057f19a7310319d42cbffdefcdbaab6695d89 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 30 Jul 2010 03:11:54 +0200 Subject: [PATCH 011/185] Migrate to queue.h --- i3bar/include/outputs.h | 15 +++++++---- i3bar/include/util.h | 24 ++++++++++++----- i3bar/include/workspaces.h | 24 ++++++++--------- i3bar/include/xcb.h | 1 + i3bar/src/main.c | 3 ++- i3bar/src/outputs.c | 53 +++++++++++++++----------------------- i3bar/src/workspaces.c | 42 ++++++++++++++---------------- i3bar/src/xcb.c | 32 ++++++++++------------- 8 files changed, 96 insertions(+), 98 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 75f0a359..50862bd5 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -1,18 +1,21 @@ #ifndef OUTPUTS_H_ #define OUTPUTS_H_ -#include "common.h" #include -typedef struct i3_output_t i3_output; +#include "common.h" +#include "workspaces.h" -i3_output* outputs; +typedef struct i3_output i3_output; + +SLIST_HEAD(outputs_head, i3_output); +struct outputs_head *outputs; void parse_outputs_json(char* json); void free_outputs(); i3_output* get_output_by_name(char* name); -struct i3_output_t { +struct i3_output { char* name; bool active; int ws; @@ -21,7 +24,9 @@ struct i3_output_t { xcb_window_t bar; xcb_gcontext_t bargc; - i3_output* next; + struct ws_head *workspaces; + + SLIST_ENTRY(i3_output) slist; }; #endif diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 2e55e114..a3fe76d9 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -1,6 +1,8 @@ #ifndef UTIL_H_ #define UTIL_H_ +#include "queue.h" + /* Securely free p */ #define FREE(p) do { \ if (p != NULL) { \ @@ -10,13 +12,23 @@ } while (0) /* Securely fee single-linked list */ -#define FREE_LIST(l, type) do { \ - type* FREE_LIST_TMP; \ - while (l != NULL) { \ - FREE_LIST_TMP = l; \ - free(l); \ - l = l->next; \ +#define FREE_SLIST(l, type) do { \ + type *walk = SLIST_FIRST(l); \ + while (!SLIST_EMPTY(l)) { \ + SLIST_REMOVE_HEAD(l, slist); \ + FREE(walk); \ + walk = SLIST_FIRST(l); \ } \ } while (0) #endif + +/* Securely fee tail-queues */ +#define FREE_TAILQ(l, type) do { \ + type *walk = TAILQ_FIRST(l); \ + while (!TAILQ_EMPTY(l)) { \ + TAILQ_REMOVE(l, TAILQ_FIRST(l), tailq); \ + FREE(walk); \ + walk = TAILQ_FIRST(l); \ + } \ +} while (0) diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index d4975a1e..56e36627 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -4,24 +4,24 @@ #include "common.h" #include "outputs.h" -typedef struct i3_ws_t i3_ws; +typedef struct i3_ws i3_ws; -i3_ws* workspaces; +TAILQ_HEAD(ws_head, i3_ws); void parse_workspaces_json(); void free_workspaces(); -struct i3_ws_t { - int num; - char* name; - int name_width; - bool visible; - bool focused; - bool urgent; - rect rect; - i3_output* output; +struct i3_ws { + int num; + char *name; + int name_width; + bool visible; + bool focused; + bool urgent; + rect rect; + struct i3_output *output; - i3_ws* next; + TAILQ_ENTRY(i3_ws) tailq; }; #endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 9b10348b..24cba56e 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -25,5 +25,6 @@ void destroy_windows(); void create_windows(); void draw_buttons(); int get_string_width(char *string); +void handle_xcb_event(xcb_generic_event_t *event); #endif diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 0be8a7a7..6cc70634 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -59,8 +59,9 @@ int main(int argc, char **argv) { ev_default_destroy(); clean_xcb(); - free_outputs(); + free_workspaces(); + FREE_SLIST(outputs, i3_output); return 0; } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 2066b3d4..1969c5dd 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -10,10 +10,10 @@ #include "ipc.h" struct outputs_json_params { - i3_output* outputs; - i3_output* outputs_walk; - char* cur_key; - char* json; + struct outputs_head *outputs; + i3_output *outputs_walk; + char* cur_key; + char* json; }; static int outputs_null_cb(void* params_) { @@ -96,23 +96,22 @@ static int outputs_string_cb(void* params_, const unsigned char* val, unsigned i static int outputs_start_map_cb(void* params_) { struct outputs_json_params* params = (struct outputs_json_params*) params_; - i3_output* new_output = NULL; + i3_output *new_output = NULL; if (params->cur_key == NULL) { new_output = malloc(sizeof(i3_output)); new_output->name = NULL; new_output->ws = 0, memset(&new_output->rect, 0, sizeof(rect)); - new_output->next = NULL; new_output->bar = XCB_NONE; - if (params->outputs == NULL) { - params->outputs = new_output; - } else { - params->outputs_walk->next = new_output; - } + new_output->workspaces = malloc(sizeof(struct ws_head)); + TAILQ_INIT(new_output->workspaces); + + SLIST_INSERT_HEAD(params->outputs, new_output, slist); + + params->outputs_walk = SLIST_FIRST(params->outputs); - params->outputs_walk = new_output; return 1; } @@ -148,7 +147,10 @@ void parse_outputs_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ struct outputs_json_params params; - params.outputs = NULL; + printf(json); + params.outputs = malloc(sizeof(struct outputs_head)); + SLIST_INIT(params.outputs); + params.outputs_walk = NULL; params.cur_key = NULL; params.json = json; @@ -175,29 +177,16 @@ void parse_outputs_json(char* json) { yajl_free(handle); - free_outputs(); + if (outputs != NULL) { + FREE_SLIST(outputs, i3_output); + } + outputs = params.outputs; } -void free_outputs() { - i3_output* tmp; - while (outputs != NULL) { - tmp = outputs; - outputs = outputs->next; - FREE(tmp->name); - FREE(tmp); - } -} - i3_output* get_output_by_name(char* name) { - if (outputs == NULL) { - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - return NULL; - } - - i3_output* walk; - - for (walk = outputs; walk != NULL; walk = walk->next) { + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { if (!strcmp(walk->name, name)) { break; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 3d363ecb..9087275b 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -10,10 +10,10 @@ #include "ipc.h" struct workspaces_json_params { - i3_ws* workspaces; - i3_ws* workspaces_walk; - char* cur_key; - char* json; + struct ws_head *workspaces; + i3_ws *workspaces_walk; + char *cur_key; + char *json; }; static int workspaces_null_cb(void* params_) { @@ -117,8 +117,12 @@ static int workspaces_string_cb(void* params_, const unsigned char* val, unsigne strncpy(output_name, (const char*) val, len); output_name[len] = '\0'; params->workspaces_walk->output = get_output_by_name(output_name); - free(output_name); + TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, + params->workspaces_walk, + tailq); + + free(output_name); return 1; } @@ -127,7 +131,8 @@ static int workspaces_string_cb(void* params_, const unsigned char* val, unsigne static int workspaces_start_map_cb(void* params_) { struct workspaces_json_params* params = (struct workspaces_json_params*) params_; - i3_ws* new_workspace = NULL; + + i3_ws *new_workspace = NULL; if (params->cur_key == NULL) { new_workspace = malloc(sizeof(i3_ws)); @@ -138,13 +143,6 @@ static int workspaces_start_map_cb(void* params_) { new_workspace->urgent = 0; memset(&new_workspace->rect, 0, sizeof(rect)); new_workspace->output = NULL; - new_workspace->next = NULL; - - if (params->workspaces == NULL) { - params->workspaces = new_workspace; - } else { - params->workspaces_walk->next = new_workspace; - } params->workspaces_walk = new_workspace; return 1; @@ -186,7 +184,9 @@ void parse_workspaces_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ struct workspaces_json_params params; - params.workspaces = NULL; + + free_workspaces(); + params.workspaces_walk = NULL; params.cur_key = NULL; params.json = json; @@ -212,19 +212,15 @@ void parse_workspaces_json(char* json) { } yajl_free(handle); - - free_workspaces(); - workspaces = params.workspaces; FREE(params.cur_key); } void free_workspaces() { - i3_ws* tmp; - while (workspaces != NULL) { - tmp = workspaces; - workspaces = workspaces->next; - FREE(tmp->name); - FREE(tmp); + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { + FREE_TAILQ(outputs_walk->workspaces, i3_ws); + } } } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 38ceb947..b0766ba8 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -19,7 +19,7 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } -void handle_xcb_event(xcb_generic_event_t ev) { +void handle_xcb_event(xcb_generic_event_t *event) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: draw_buttons(); @@ -99,8 +99,11 @@ void get_atoms() { } void destroy_windows() { - i3_output *walk = outputs; - while(walk != NULL) { + i3_output *walk; + if (outputs == NULL) { + return; + } + SLIST_FOREACH(walk, outputs, slist) { if (walk->bar == XCB_NONE) { continue; } @@ -113,10 +116,9 @@ void create_windows() { uint32_t mask; uint32_t values[2]; - i3_output* walk = outputs; - while (walk != NULL) { + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { - walk = walk->next; continue; } printf("Creating Window for output %s\n", walk->name); @@ -156,19 +158,17 @@ void create_windows() { values); xcb_map_window(xcb_connection, walk->bar); - walk = walk->next; } xcb_flush(xcb_connection); } void draw_buttons() { printf("Drawing Buttons...\n"); - i3_output *outputs_walk = outputs; int i = 0; - while (outputs_walk != NULL) { + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { if (!outputs_walk->active) { printf("Output %s inactive, skipping...\n", outputs_walk->name); - outputs_walk = outputs_walk->next; continue; } if (outputs_walk->bar == XCB_NONE) { @@ -185,19 +185,15 @@ void draw_buttons() { outputs_walk->bargc, 1, &rect); - i3_ws *ws_walk = workspaces; - while (ws_walk != NULL) { - if (ws_walk->output != outputs_walk) { - printf("WS %s on wrong output, skipping...\n", ws_walk->name); - ws_walk = ws_walk->next; - continue; - } + i3_ws *ws_walk; + TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { printf("Drawing Button for WS %s...\n", ws_walk->name); uint32_t color = get_colorpixel("240000"); if (ws_walk->visible) { color = get_colorpixel("480000"); } if (ws_walk->urgent) { + printf("WS %s is urgent!\n", ws_walk->name); color = get_colorpixel("002400"); } xcb_change_gc(xcb_connection, @@ -226,9 +222,7 @@ void draw_buttons() { i + 5, font_height + 1, ws_walk->name); i += 10 + ws_walk->name_width; - ws_walk = ws_walk->next; } - outputs_walk = outputs_walk->next; i = 0; } xcb_flush(xcb_connection); From f4b7394655d835136b33cd1ff9c46931b07a4b03 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 30 Jul 2010 03:48:46 +0200 Subject: [PATCH 012/185] Implement workspace-change on mouse-wheel --- i3bar/src/xcb.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index b0766ba8..099275d6 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -2,10 +2,12 @@ #include #include #include +#include #include "xcb.h" #include "outputs.h" #include "workspaces.h" +#include "ipc.h" xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; @@ -19,11 +21,62 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +void handle_button(xcb_button_press_event_t *event) { + i3_ws *cur_ws; + i3_output *walk; + xcb_window_t bar = event->event; + SLIST_FOREACH(walk, outputs, slist) { + if (walk->bar == bar) { + break; + } + } + + if (walk == NULL) { + printf("Unknown Bar klicked!\n"); + return; + } + + TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { + if (cur_ws->visible) { + break; + } + } + + if (cur_ws == NULL) { + printf("No Workspace active?\n"); + return; + } + + switch (event->detail) { + case 4: + if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { + cur_ws = TAILQ_FIRST(walk->workspaces); + } else { + cur_ws = TAILQ_NEXT(cur_ws, tailq); + } + break; + case 5: + if (cur_ws == TAILQ_FIRST(walk->workspaces)) { + cur_ws = TAILQ_LAST(walk->workspaces, ws_head); + } else { + cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); + } + break; + } + + char buffer[50]; + snprintf(buffer, 50, "%d", cur_ws->num); + i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); +} + void handle_xcb_event(xcb_generic_event_t *event) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: draw_buttons(); break; + case XCB_BUTTON_PRESS: + handle_button((xcb_button_press_event_t*) event); + break; } } @@ -126,7 +179,8 @@ void create_windows() { walk->bar = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = xcb_screens->black_pixel; - values[1] = XCB_EVENT_MASK_EXPOSURE; + values[1] = XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_BUTTON_PRESS; xcb_create_window(xcb_connection, xcb_screens->root_depth, walk->bar, From 49eef0db3ff6e4558834088bef26816c9db44dc6 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 30 Jul 2010 04:19:32 +0200 Subject: [PATCH 013/185] Making Mouse-clicks work --- i3bar/src/main.c | 2 +- i3bar/src/xcb.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 6cc70634..d0ce4162 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -20,8 +20,8 @@ void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { xcb_generic_event_t *event; if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { handle_xcb_event(event); - free(event); } + free(event); } void xcb_io_cb(struct ev_loop *loop, ev_io *w, int revents) { diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 099275d6..98ec186c 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -47,7 +47,23 @@ void handle_button(xcb_button_press_event_t *event) { return; } + int32_t x = event->event_x; + + printf("Got Button %d\n", event->detail); + switch (event->detail) { + case 1: + TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { + printf("x = %d\n", x); + if (x < cur_ws->name_width + 10) { + break; + } + x -= cur_ws->name_width + 10; + } + if (cur_ws == NULL) { + return; + } + break; case 4: if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { cur_ws = TAILQ_FIRST(walk->workspaces); @@ -241,7 +257,7 @@ void draw_buttons() { &rect); i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { - printf("Drawing Button for WS %s...\n", ws_walk->name); + printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); uint32_t color = get_colorpixel("240000"); if (ws_walk->visible) { color = get_colorpixel("480000"); From 8595d3bb48e75d2072a2023f92d8c182a085a59c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 3 Aug 2010 21:20:11 +0200 Subject: [PATCH 014/185] Change the indention-style --- i3bar/include/outputs.h | 6 +- i3bar/include/util.h | 32 +-- i3bar/include/workspaces.h | 18 +- i3bar/include/xcb.h | 10 +- i3bar/src/ipc.c | 272 ++++++++++----------- i3bar/src/main.c | 62 ++--- i3bar/src/outputs.c | 270 ++++++++++----------- i3bar/src/workspaces.c | 288 +++++++++++------------ i3bar/src/xcb.c | 470 ++++++++++++++++++------------------- 9 files changed, 714 insertions(+), 714 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 50862bd5..1c6abe3a 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -11,9 +11,9 @@ typedef struct i3_output i3_output; SLIST_HEAD(outputs_head, i3_output); struct outputs_head *outputs; -void parse_outputs_json(char* json); -void free_outputs(); -i3_output* get_output_by_name(char* name); +void parse_outputs_json(char* json); +void free_outputs(); +i3_output* get_output_by_name(char* name); struct i3_output { char* name; diff --git a/i3bar/include/util.h b/i3bar/include/util.h index a3fe76d9..08bdc335 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -5,30 +5,30 @@ /* Securely free p */ #define FREE(p) do { \ - if (p != NULL) { \ - free(p); \ - p = NULL; \ - } \ + if (p != NULL) { \ + free(p); \ + p = NULL; \ + } \ } while (0) /* Securely fee single-linked list */ #define FREE_SLIST(l, type) do { \ - type *walk = SLIST_FIRST(l); \ - while (!SLIST_EMPTY(l)) { \ - SLIST_REMOVE_HEAD(l, slist); \ - FREE(walk); \ - walk = SLIST_FIRST(l); \ - } \ + type *walk = SLIST_FIRST(l); \ + while (!SLIST_EMPTY(l)) { \ + SLIST_REMOVE_HEAD(l, slist); \ + FREE(walk); \ + walk = SLIST_FIRST(l); \ + } \ } while (0) #endif /* Securely fee tail-queues */ #define FREE_TAILQ(l, type) do { \ - type *walk = TAILQ_FIRST(l); \ - while (!TAILQ_EMPTY(l)) { \ - TAILQ_REMOVE(l, TAILQ_FIRST(l), tailq); \ - FREE(walk); \ - walk = TAILQ_FIRST(l); \ - } \ + type *walk = TAILQ_FIRST(l); \ + while (!TAILQ_EMPTY(l)) { \ + TAILQ_REMOVE(l, TAILQ_FIRST(l), tailq); \ + FREE(walk); \ + walk = TAILQ_FIRST(l); \ + } \ } while (0) diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 56e36627..64c1065e 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -12,16 +12,16 @@ void parse_workspaces_json(); void free_workspaces(); struct i3_ws { - int num; - char *name; - int name_width; - bool visible; - bool focused; - bool urgent; - rect rect; - struct i3_output *output; + int num; + char *name; + int name_width; + bool visible; + bool focused; + bool urgent; + rect rect; + struct i3_output *output; - TAILQ_ENTRY(i3_ws) tailq; + TAILQ_ENTRY(i3_ws) tailq; }; #endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 24cba56e..230ff6e6 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -12,11 +12,11 @@ enum { xcb_atom_t atoms[NUM_ATOMS]; -xcb_connection_t* xcb_connection; -xcb_screen_t* xcb_screens; -xcb_window_t xcb_root; -xcb_font_t xcb_font; -int font_height; +xcb_connection_t *xcb_connection; +xcb_screen_t *xcb_screens; +xcb_window_t xcb_root; +xcb_font_t xcb_font; +int font_height; void init_xcb(); void clean_xcb(); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 46c1e8ca..1553fc20 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -12,193 +12,193 @@ #include "xcb.h" #include "ipc.h" -ev_io* i3_connection; +ev_io *i3_connection; typedef void(*handler_t)(char*); -int get_ipc_fd(const char* socket_path) { - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) { - printf("ERROR: Could not create Socket!\n"); - exit(EXIT_FAILURE); - } +int get_ipc_fd(const char *socket_path) { + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) { + printf("ERROR: Could not create Socket!\n"); + exit(EXIT_FAILURE); + } - 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) { - printf("ERROR: Could not connct to i3\n"); - exit(EXIT_FAILURE); - } - return sockfd; + 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) { + printf("ERROR: Could not connct to i3\n"); + exit(EXIT_FAILURE); + } + return sockfd; } void got_command_reply(char *reply) { - /* FIXME: Error handling for command-replies */ + /* FIXME: Error handling for command-replies */ } void got_workspace_reply(char *reply) { - printf("Got Workspace-Data!\n"); - parse_workspaces_json(reply); - draw_buttons(); + printf("Got Workspace-Data!\n"); + parse_workspaces_json(reply); + draw_buttons(); } void got_subscribe_reply(char *reply) { - printf("Got Subscribe Reply: %s\n", reply); - /* FIXME: Error handling for subscribe-commands */ + printf("Got Subscribe Reply: %s\n", reply); + /* FIXME: Error handling for subscribe-commands */ } void got_output_reply(char *reply) { - printf("Got Outputs-Data!\nDestroying Windows...\n"); - destroy_windows(); - printf("Parsing JSON...\n"); - parse_outputs_json(reply); - printf("Creating_Windows...\n"); - create_windows(); + printf("Got Outputs-Data!\nDestroying Windows...\n"); + destroy_windows(); + printf("Parsing JSON...\n"); + parse_outputs_json(reply); + printf("Creating_Windows...\n"); + create_windows(); } handler_t reply_handlers[] = { - &got_command_reply, - &got_workspace_reply, - &got_subscribe_reply, - &got_output_reply, + &got_command_reply, + &got_workspace_reply, + &got_subscribe_reply, + &got_output_reply, }; void got_workspace_event(char *event) { - printf("Got Workspace Event!\n"); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + printf("Got Workspace Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } void got_output_event(char *event) { - printf("Got Output Event!\n"); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + printf("Got Output Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); } handler_t event_handlers[] = { - &got_workspace_event, - &got_output_event + &got_workspace_event, + &got_output_event }; void got_data(struct ev_loop *loop, ev_io *watcher, int events) { - printf("Got data!\n"); - int fd = watcher->fd; - uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; - char *header = malloc(header_len); - if (header == NULL) { - printf("ERROR: Could not allocate memory!\n"); - exit(EXIT_FAILURE); - } + printf("Got data!\n"); + int fd = watcher->fd; + uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; + char *header = malloc(header_len); + if (header == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } - uint32_t rec = 0; - while (rec < header_len) { - int n = read(fd, header + rec, header_len - rec); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - if (n == 0) { - printf("ERROR: Nothing to read!\n"); - exit(EXIT_FAILURE); - } - rec += n; - } - - if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { - printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", - (int) strlen(I3_IPC_MAGIC), - header, - I3_IPC_MAGIC); - exit(EXIT_FAILURE); - } + uint32_t rec = 0; + while (rec < header_len) { + int n = read(fd, header + rec, header_len - rec); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + if (n == 0) { + printf("ERROR: Nothing to read!\n"); + exit(EXIT_FAILURE); + } + rec += n; + } - char *walk = header + strlen(I3_IPC_MAGIC); - uint32_t size = *((uint32_t*) walk); - walk += sizeof(uint32_t); - uint32_t type = *((uint32_t*) walk); - char *buffer = malloc(size + 1); - if (buffer == NULL) { - printf("ERROR: Could not allocate memory!\n"); - exit(EXIT_FAILURE); - } - rec = 0; + if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { + printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", + (int) strlen(I3_IPC_MAGIC), + header, + I3_IPC_MAGIC); + exit(EXIT_FAILURE); + } - while (rec < size) { - int n = read(fd, buffer + rec, size - rec); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - if (n == 0) { - printf("ERROR: Nothing to read!\n"); - exit(EXIT_FAILURE); - } - rec += n; - } - buffer[size] = '\0'; - - if (type & (1 << 31)) { - type ^= 1 << 31; - event_handlers[type](buffer); - } else { - reply_handlers[type](buffer); - } + char *walk = header + strlen(I3_IPC_MAGIC); + uint32_t size = *((uint32_t*) walk); + walk += sizeof(uint32_t); + uint32_t type = *((uint32_t*) walk); + char *buffer = malloc(size + 1); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } + rec = 0; - FREE(buffer); + while (rec < size) { + int n = read(fd, buffer + rec, size - rec); + if (n == -1) { + printf("ERROR: read() failed!\n"); + exit(EXIT_FAILURE); + } + if (n == 0) { + printf("ERROR: Nothing to read!\n"); + exit(EXIT_FAILURE); + } + rec += n; + } + buffer[size] = '\0'; + + if (type & (1 << 31)) { + type ^= 1 << 31; + event_handlers[type](buffer); + } else { + reply_handlers[type](buffer); + } + + FREE(buffer); } -int i3_send_msg(uint32_t type, const char* payload) { - uint32_t len = 0; - if (payload != NULL) { - len = strlen(payload); - } +int i3_send_msg(uint32_t type, const char *payload) { + uint32_t len = 0; + if (payload != NULL) { + len = strlen(payload); + } - uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; - char *buffer = malloc(to_write); - if (buffer == NULL) { - printf("ERROR: Could not allocate memory\n"); - exit(EXIT_FAILURE); - } + uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; + char *buffer = malloc(to_write); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory\n"); + exit(EXIT_FAILURE); + } - char *walk = buffer; + char *walk = buffer; - strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &len, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &type, sizeof(uint32_t)); - walk += sizeof(uint32_t); + strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &len, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &type, sizeof(uint32_t)); + walk += sizeof(uint32_t); - strncpy(walk, payload, len); - - uint32_t written = 0; + strncpy(walk, payload, len); - while (to_write > 0) { - int n = write(i3_connection->fd, buffer + written, to_write); - if (n == -1) { - printf("ERROR: write() failed!\n"); - exit(EXIT_FAILURE); - } + uint32_t written = 0; - to_write -= n; - written += n; - } + while (to_write > 0) { + int n = write(i3_connection->fd, buffer + written, to_write); + if (n == -1) { + printf("ERROR: write() failed!\n"); + exit(EXIT_FAILURE); + } - FREE(buffer); + to_write -= n; + written += n; + } - return 1; + FREE(buffer); + + return 1; } int init_connection(const char *socket_path) { - int sockfd = get_ipc_fd(socket_path); + int sockfd = get_ipc_fd(socket_path); - i3_connection = malloc(sizeof(ev_io)); - ev_io_init(i3_connection, &got_data, sockfd, EV_READ); - ev_io_start(main_loop, i3_connection); + i3_connection = malloc(sizeof(ev_io)); + ev_io_init(i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, i3_connection); - return 1; + return 1; } void subscribe_events() { - i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index d0ce4162..9465fc12 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -13,55 +13,55 @@ #include "xcb.h" void ev_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { - xcb_flush(xcb_connection); + xcb_flush(xcb_connection); } void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { - xcb_generic_event_t *event; - if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { - handle_xcb_event(event); - } - free(event); + xcb_generic_event_t *event; + if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { + handle_xcb_event(event); + } + free(event); } void xcb_io_cb(struct ev_loop *loop, ev_io *w, int revents) { } int main(int argc, char **argv) { - main_loop = ev_default_loop(0); + main_loop = ev_default_loop(0); - init_xcb(); - init_connection("/home/mero/.i3/ipc.sock"); + init_xcb(); + init_connection("/home/mero/.i3/ipc.sock"); - subscribe_events(); + subscribe_events(); - ev_io *xcb_io = malloc(sizeof(ev_io)); - ev_prepare *ev_prep = malloc(sizeof(ev_prepare)); - ev_check *ev_chk = malloc(sizeof(ev_check)); + ev_io *xcb_io = malloc(sizeof(ev_io)); + ev_prepare *ev_prep = malloc(sizeof(ev_prepare)); + ev_check *ev_chk = malloc(sizeof(ev_check)); - ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); - ev_prepare_init(ev_prep, &ev_prepare_cb); - ev_check_init(ev_chk, &ev_check_cb); + ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); + ev_prepare_init(ev_prep, &ev_prepare_cb); + ev_check_init(ev_chk, &ev_check_cb); - ev_io_start(main_loop, xcb_io); - ev_prepare_start(main_loop, ev_prep); - ev_check_start(main_loop, ev_chk); + ev_io_start(main_loop, xcb_io); + ev_prepare_start(main_loop, ev_prep); + ev_check_start(main_loop, ev_chk); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); - ev_loop(main_loop, 0); + ev_loop(main_loop, 0); - ev_prepare_stop(main_loop, ev_prep); - ev_check_stop(main_loop, ev_chk); - FREE(ev_prep); - FREE(ev_chk); + ev_prepare_stop(main_loop, ev_prep); + ev_check_stop(main_loop, ev_chk); + FREE(ev_prep); + FREE(ev_chk); - ev_default_destroy(); - clean_xcb(); + ev_default_destroy(); + clean_xcb(); - free_workspaces(); - FREE_SLIST(outputs, i3_output); + free_workspaces(); + FREE_SLIST(outputs, i3_output); - return 0; + return 0; } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 1969c5dd..18abff51 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -10,187 +10,187 @@ #include "ipc.h" struct outputs_json_params { - struct outputs_head *outputs; - i3_output *outputs_walk; - char* cur_key; - char* json; + struct outputs_head *outputs; + i3_output *outputs_walk; + char *cur_key; + char *json; }; -static int outputs_null_cb(void* params_) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; +static int outputs_null_cb(void *params_) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; - if (strcmp(params->cur_key, "current_workspace")) { - return 0; - } + if (strcmp(params->cur_key, "current_workspace")) { + return 0; + } - FREE(params->cur_key); + FREE(params->cur_key); - return 1; + return 1; } -static int outputs_boolean_cb(void* params_, bool val) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; +static int outputs_boolean_cb(void *params_, bool val) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; - if (strcmp(params->cur_key, "active")) { - return 0; - } + if (strcmp(params->cur_key, "active")) { + return 0; + } - params->outputs_walk->active = val; + params->outputs_walk->active = val; - FREE(params->cur_key); + FREE(params->cur_key); - return 1; + return 1; } -static int outputs_integer_cb(void* params_, long val) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; +static int outputs_integer_cb(void *params_, long val) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; - if (!strcmp(params->cur_key, "current_workspace")) { - params->outputs_walk->ws = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "current_workspace")) { + params->outputs_walk->ws = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "x")) { - params->outputs_walk->rect.x = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "x")) { + params->outputs_walk->rect.x = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "y")) { - params->outputs_walk->rect.y = (int) val; - FREE(params->cur_key); - return 1; - } - - if (!strcmp(params->cur_key, "width")) { - params->outputs_walk->rect.w = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "y")) { + params->outputs_walk->rect.y = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "height")) { - params->outputs_walk->rect.h = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "width")) { + params->outputs_walk->rect.w = (int) val; + FREE(params->cur_key); + return 1; + } - return 0; + if (!strcmp(params->cur_key, "height")) { + params->outputs_walk->rect.h = (int) val; + FREE(params->cur_key); + return 1; + } + + return 0; } -static int outputs_string_cb(void* params_, const unsigned char* val, unsigned int len) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; - - if (strcmp(params->cur_key, "name")) { - return 0; - } +static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; - params->outputs_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); - strncpy(params->outputs_walk->name, (const char*) val, len); - params->outputs_walk->name[len] = '\0'; + if (strcmp(params->cur_key, "name")) { + return 0; + } - FREE(params->cur_key); - - return 1; + params->outputs_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(params->outputs_walk->name, (const char*) val, len); + params->outputs_walk->name[len] = '\0'; + + FREE(params->cur_key); + + return 1; } -static int outputs_start_map_cb(void* params_) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; - i3_output *new_output = NULL; +static int outputs_start_map_cb(void *params_) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; + i3_output *new_output = NULL; - if (params->cur_key == NULL) { - new_output = malloc(sizeof(i3_output)); - new_output->name = NULL; - new_output->ws = 0, - memset(&new_output->rect, 0, sizeof(rect)); - new_output->bar = XCB_NONE; + if (params->cur_key == NULL) { + new_output = malloc(sizeof(i3_output)); + new_output->name = NULL; + new_output->ws = 0, + memset(&new_output->rect, 0, sizeof(rect)); + new_output->bar = XCB_NONE; - new_output->workspaces = malloc(sizeof(struct ws_head)); - TAILQ_INIT(new_output->workspaces); + new_output->workspaces = malloc(sizeof(struct ws_head)); + TAILQ_INIT(new_output->workspaces); - SLIST_INSERT_HEAD(params->outputs, new_output, slist); + SLIST_INSERT_HEAD(params->outputs, new_output, slist); - params->outputs_walk = SLIST_FIRST(params->outputs); + params->outputs_walk = SLIST_FIRST(params->outputs); - return 1; - } + return 1; + } - return 1; + return 1; } -static int outputs_map_key_cb(void* params_, const unsigned char* keyVal, unsigned int keyLen) { - struct outputs_json_params* params = (struct outputs_json_params*) params_; - FREE(params->cur_key); +static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; + FREE(params->cur_key); - params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); - strncpy(params->cur_key, (const char*) keyVal, keyLen); - params->cur_key[keyLen] = '\0'; + params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + strncpy(params->cur_key, (const char*) keyVal, keyLen); + params->cur_key[keyLen] = '\0'; - return 1; + return 1; } yajl_callbacks outputs_callbacks = { - &outputs_null_cb, - &outputs_boolean_cb, - &outputs_integer_cb, - NULL, - NULL, - &outputs_string_cb, - &outputs_start_map_cb, - &outputs_map_key_cb, - NULL, - NULL, - NULL + &outputs_null_cb, + &outputs_boolean_cb, + &outputs_integer_cb, + NULL, + NULL, + &outputs_string_cb, + &outputs_start_map_cb, + &outputs_map_key_cb, + NULL, + NULL, + NULL }; -void parse_outputs_json(char* json) { - /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret - * JSON in chunks */ - struct outputs_json_params params; - printf(json); - params.outputs = malloc(sizeof(struct outputs_head)); - SLIST_INIT(params.outputs); +void parse_outputs_json(char *json) { + /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret + * JSON in chunks */ + struct outputs_json_params params; + printf(json); + params.outputs = malloc(sizeof(struct outputs_head)); + SLIST_INIT(params.outputs); - params.outputs_walk = NULL; - params.cur_key = NULL; - params.json = json; + params.outputs_walk = NULL; + params.cur_key = NULL; + params.json = json; - yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; - yajl_status state; - - handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); + yajl_handle handle; + yajl_parser_config parse_conf = { 0, 0 }; + yajl_status state; - state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); + handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); - /* FIXME: Propper errorhandling for JSON-parsing */ - switch (state) { - case yajl_status_ok: - break; - case yajl_status_client_canceled: - case yajl_status_insufficient_data: - case yajl_status_error: - printf("ERROR: Could not parse outputs-reply!\n"); - exit(EXIT_FAILURE); - break; - } - - yajl_free(handle); + state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); - if (outputs != NULL) { - FREE_SLIST(outputs, i3_output); - } + /* FIXME: Propper errorhandling for JSON-parsing */ + switch (state) { + case yajl_status_ok: + break; + case yajl_status_client_canceled: + case yajl_status_insufficient_data: + case yajl_status_error: + printf("ERROR: Could not parse outputs-reply!\n"); + exit(EXIT_FAILURE); + break; + } - outputs = params.outputs; + yajl_free(handle); + + if (outputs != NULL) { + FREE_SLIST(outputs, i3_output); + } + + outputs = params.outputs; } -i3_output* get_output_by_name(char* name) { - i3_output *walk; - SLIST_FOREACH(walk, outputs, slist) { - if (!strcmp(walk->name, name)) { - break; - } - } +i3_output *get_output_by_name(char *name) { + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { + if (!strcmp(walk->name, name)) { + break; + } + } - return walk; + return walk; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 9087275b..ee54c8b6 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -10,103 +10,103 @@ #include "ipc.h" struct workspaces_json_params { - struct ws_head *workspaces; - i3_ws *workspaces_walk; - char *cur_key; - char *json; + struct ws_head *workspaces; + i3_ws *workspaces_walk; + char *cur_key; + char *json; }; -static int workspaces_null_cb(void* params_) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; +static int workspaces_null_cb(void *params_) { + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - if (strcmp(params->cur_key, "current_workspace")) { - return 0; - } + if (strcmp(params->cur_key, "current_workspace")) { + return 0; + } - FREE(params->cur_key); + FREE(params->cur_key); - return 1; + return 1; } -static int workspaces_boolean_cb(void* params_, bool val) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; +static int workspaces_boolean_cb(void *params_, bool val) { + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - if (!strcmp(params->cur_key, "visible")) { - params->workspaces_walk->visible = val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "visible")) { + params->workspaces_walk->visible = val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "focused")) { - params->workspaces_walk->focused = val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "focused")) { + params->workspaces_walk->focused = val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "urgent")) { - params->workspaces_walk->urgent = val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "urgent")) { + params->workspaces_walk->urgent = val; + FREE(params->cur_key); + return 1; + } - FREE(params->cur_key); + FREE(params->cur_key); - return 0; + return 0; } -static int workspaces_integer_cb(void* params_, long val) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; +static int workspaces_integer_cb(void *params_, long val) { + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - if (!strcmp(params->cur_key, "num")) { - params->workspaces_walk->num = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "num")) { + params->workspaces_walk->num = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "x")) { - params->workspaces_walk->rect.x = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "x")) { + params->workspaces_walk->rect.x = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "y")) { - params->workspaces_walk->rect.y = (int) val; - FREE(params->cur_key); - return 1; - } - - if (!strcmp(params->cur_key, "width")) { - params->workspaces_walk->rect.w = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "y")) { + params->workspaces_walk->rect.y = (int) val; + FREE(params->cur_key); + return 1; + } - if (!strcmp(params->cur_key, "height")) { - params->workspaces_walk->rect.h = (int) val; - FREE(params->cur_key); - return 1; - } + if (!strcmp(params->cur_key, "width")) { + params->workspaces_walk->rect.w = (int) val; + FREE(params->cur_key); + return 1; + } - FREE(params->cur_key); - return 0; + if (!strcmp(params->cur_key, "height")) { + params->workspaces_walk->rect.h = (int) val; + FREE(params->cur_key); + return 1; + } + + FREE(params->cur_key); + return 0; } -static int workspaces_string_cb(void* params_, const unsigned char* val, unsigned int len) { +static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - char* output_name; + char *output_name; if (!strcmp(params->cur_key, "name")) { params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(params->workspaces_walk->name, (const char*) val, len); - params->workspaces_walk->name[len] = '\0'; + params->workspaces_walk->name[len] = '\0'; - params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->name); + params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->name); - printf("Got Workspace %s, name_width: %d\n", - params->workspaces_walk->name, - params->workspaces_walk->name_width); + printf("Got Workspace %s, name_width: %d\n", + params->workspaces_walk->name, + params->workspaces_walk->name_width); FREE(params->cur_key); return 1; @@ -115,12 +115,12 @@ static int workspaces_string_cb(void* params_, const unsigned char* val, unsigne if (!strcmp(params->cur_key, "output")) { output_name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(output_name, (const char*) val, len); - output_name[len] = '\0'; + output_name[len] = '\0'; params->workspaces_walk->output = get_output_by_name(output_name); - TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, - params->workspaces_walk, - tailq); + TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, + params->workspaces_walk, + tailq); free(output_name); return 1; @@ -129,98 +129,98 @@ static int workspaces_string_cb(void* params_, const unsigned char* val, unsigne return 0; } -static int workspaces_start_map_cb(void* params_) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; +static int workspaces_start_map_cb(void *params_) { + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - i3_ws *new_workspace = NULL; + i3_ws *new_workspace = NULL; - if (params->cur_key == NULL) { - new_workspace = malloc(sizeof(i3_ws)); - new_workspace->num = -1; - new_workspace->name = NULL; - new_workspace->visible = 0; - new_workspace->focused = 0; - new_workspace->urgent = 0; - memset(&new_workspace->rect, 0, sizeof(rect)); - new_workspace->output = NULL; + if (params->cur_key == NULL) { + new_workspace = malloc(sizeof(i3_ws)); + new_workspace->num = -1; + new_workspace->name = NULL; + new_workspace->visible = 0; + new_workspace->focused = 0; + new_workspace->urgent = 0; + memset(&new_workspace->rect, 0, sizeof(rect)); + new_workspace->output = NULL; - params->workspaces_walk = new_workspace; - return 1; - } + params->workspaces_walk = new_workspace; + return 1; + } - return 1; + return 1; } -static int workspaces_map_key_cb(void* params_, const unsigned char* keyVal, unsigned int keyLen) { - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; - FREE(params->cur_key); +static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { + struct workspaces_json_params *params = (struct workspaces_json_params*) params_; + FREE(params->cur_key); - params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); - if (params->cur_key == NULL) { - printf("ERROR: Could not allocate memory!\n"); - exit(EXIT_FAILURE); - } - strncpy(params->cur_key, (const char*) keyVal, keyLen); - params->cur_key[keyLen] = '\0'; + params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + if (params->cur_key == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } + strncpy(params->cur_key, (const char*) keyVal, keyLen); + params->cur_key[keyLen] = '\0'; - return 1; + return 1; } yajl_callbacks workspaces_callbacks = { - &workspaces_null_cb, - &workspaces_boolean_cb, - &workspaces_integer_cb, - NULL, - NULL, - &workspaces_string_cb, - &workspaces_start_map_cb, - &workspaces_map_key_cb, - NULL, - NULL, - NULL + &workspaces_null_cb, + &workspaces_boolean_cb, + &workspaces_integer_cb, + NULL, + NULL, + &workspaces_string_cb, + &workspaces_start_map_cb, + &workspaces_map_key_cb, + NULL, + NULL, + NULL }; -void parse_workspaces_json(char* json) { - /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret - * JSON in chunks */ - struct workspaces_json_params params; +void parse_workspaces_json(char *json) { + /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret + * JSON in chunks */ + struct workspaces_json_params params; - free_workspaces(); + free_workspaces(); - params.workspaces_walk = NULL; - params.cur_key = NULL; - params.json = json; + params.workspaces_walk = NULL; + params.cur_key = NULL; + params.json = json; - yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; - yajl_status state; - - handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); + yajl_handle handle; + yajl_parser_config parse_conf = { 0, 0 }; + yajl_status state; - state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); + handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); - /* FIXME: Propper errorhandling for JSON-parsing */ - switch (state) { - case yajl_status_ok: - break; - case yajl_status_client_canceled: - case yajl_status_insufficient_data: - case yajl_status_error: - printf("ERROR: Could not parse workspaces-reply!\n"); - exit(EXIT_FAILURE); - break; - } + state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); - yajl_free(handle); - - FREE(params.cur_key); + /* FIXME: Propper errorhandling for JSON-parsing */ + switch (state) { + case yajl_status_ok: + break; + case yajl_status_client_canceled: + case yajl_status_insufficient_data: + case yajl_status_error: + printf("ERROR: Could not parse workspaces-reply!\n"); + exit(EXIT_FAILURE); + break; + } + + yajl_free(handle); + + FREE(params.cur_key); } void free_workspaces() { - i3_output *outputs_walk; - SLIST_FOREACH(outputs_walk, outputs, slist) { - if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { - FREE_TAILQ(outputs_walk->workspaces, i3_ws); - } - } + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { + FREE_TAILQ(outputs_walk->workspaces, i3_ws); + } + } } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 98ec186c..6d7a38b3 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -12,288 +12,288 @@ xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; uint32_t get_colorpixel(const char *s) { - char strings[3][3] = { { s[0], s[1], '\0'} , - { s[2], s[3], '\0'} , - { s[4], s[5], '\0'} }; - uint8_t r = strtol(strings[0], NULL, 16); - uint8_t g = strtol(strings[1], NULL, 16); - uint8_t b = strtol(strings[2], NULL, 16); - return (r << 16 | g << 8 | b); + char strings[3][3] = { { s[0], s[1], '\0'} , + { s[2], s[3], '\0'} , + { s[4], s[5], '\0'} }; + uint8_t r = strtol(strings[0], NULL, 16); + uint8_t g = strtol(strings[1], NULL, 16); + uint8_t b = strtol(strings[2], NULL, 16); + return (r << 16 | g << 8 | b); } void handle_button(xcb_button_press_event_t *event) { - i3_ws *cur_ws; - i3_output *walk; - xcb_window_t bar = event->event; - SLIST_FOREACH(walk, outputs, slist) { - if (walk->bar == bar) { - break; - } - } + i3_ws *cur_ws; + i3_output *walk; + xcb_window_t bar = event->event; + SLIST_FOREACH(walk, outputs, slist) { + if (walk->bar == bar) { + break; + } + } - if (walk == NULL) { - printf("Unknown Bar klicked!\n"); - return; - } + if (walk == NULL) { + printf("Unknown Bar klicked!\n"); + return; + } - TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { - if (cur_ws->visible) { - break; - } - } + TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { + if (cur_ws->visible) { + break; + } + } - if (cur_ws == NULL) { - printf("No Workspace active?\n"); - return; - } + if (cur_ws == NULL) { + printf("No Workspace active?\n"); + return; + } - int32_t x = event->event_x; + int32_t x = event->event_x; - printf("Got Button %d\n", event->detail); + printf("Got Button %d\n", event->detail); - switch (event->detail) { - case 1: - TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { - printf("x = %d\n", x); - if (x < cur_ws->name_width + 10) { - break; - } - x -= cur_ws->name_width + 10; - } - if (cur_ws == NULL) { - return; - } - break; - case 4: - if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { - cur_ws = TAILQ_FIRST(walk->workspaces); - } else { - cur_ws = TAILQ_NEXT(cur_ws, tailq); - } - break; - case 5: - if (cur_ws == TAILQ_FIRST(walk->workspaces)) { - cur_ws = TAILQ_LAST(walk->workspaces, ws_head); - } else { - cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); - } - break; - } + switch (event->detail) { + case 1: + TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { + printf("x = %d\n", x); + if (x < cur_ws->name_width + 10) { + break; + } + x -= cur_ws->name_width + 10; + } + if (cur_ws == NULL) { + return; + } + break; + case 4: + if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { + cur_ws = TAILQ_FIRST(walk->workspaces); + } else { + cur_ws = TAILQ_NEXT(cur_ws, tailq); + } + break; + case 5: + if (cur_ws == TAILQ_FIRST(walk->workspaces)) { + cur_ws = TAILQ_LAST(walk->workspaces, ws_head); + } else { + cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); + } + break; + } - char buffer[50]; - snprintf(buffer, 50, "%d", cur_ws->num); - i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); + char buffer[50]; + snprintf(buffer, 50, "%d", cur_ws->num); + i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); } void handle_xcb_event(xcb_generic_event_t *event) { - switch (event->response_type & ~0x80) { - case XCB_EXPOSE: - draw_buttons(); - break; - case XCB_BUTTON_PRESS: - handle_button((xcb_button_press_event_t*) event); - break; - } + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: + draw_buttons(); + break; + case XCB_BUTTON_PRESS: + handle_button((xcb_button_press_event_t*) event); + break; + } } int get_string_width(char *string) { - xcb_query_text_extents_cookie_t cookie; - xcb_query_text_extents_reply_t *reply; - xcb_generic_error_t *error; - int width; + xcb_query_text_extents_cookie_t cookie; + xcb_query_text_extents_reply_t *reply; + xcb_generic_error_t *error; + int width; - cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t *)string); - if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { - printf("ERROR: Could not get text extents!"); - return 7; - } + cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t*) string); + if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { + printf("ERROR: Could not get text extents!"); + return 7; + } - width = reply->overall_width; - free(reply); - return width; + width = reply->overall_width; + free(reply); + return width; } void init_xcb() { - /* FIXME: xcb_connect leaks Memory */ - xcb_connection = xcb_connect(NULL, NULL); - if (xcb_connection_has_error(xcb_connection)) { - printf("Cannot open display\n"); - exit(EXIT_FAILURE); - } - printf("Connected to xcb\n"); + /* FIXME: xcb_connect leaks Memory */ + xcb_connection = xcb_connect(NULL, NULL); + if (xcb_connection_has_error(xcb_connection)) { + printf("Cannot open display\n"); + exit(EXIT_FAILURE); + } + printf("Connected to xcb\n"); - /* We have to request the atoms we need */ - #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); + /* We have to request the atoms we need */ + #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); #include "xcb_atoms.def" - xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; - xcb_root = xcb_screens->root; + xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; + xcb_root = xcb_screens->root; - xcb_font = xcb_generate_id(xcb_connection); - char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; - xcb_open_font(xcb_connection, - xcb_font, - strlen(fontname), - fontname); + xcb_font = xcb_generate_id(xcb_connection); + char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; + xcb_open_font(xcb_connection, + xcb_font, + strlen(fontname), + fontname); - xcb_list_fonts_with_info_cookie_t cookie; - cookie = xcb_list_fonts_with_info(xcb_connection, - 1, - strlen(fontname), - fontname); - xcb_list_fonts_with_info_reply_t *reply; - reply = xcb_list_fonts_with_info_reply(xcb_connection, - cookie, - NULL); - font_height = reply->font_ascent + reply->font_descent; - printf("Calculated Font-height: %d\n", font_height); + xcb_list_fonts_with_info_cookie_t cookie; + cookie = xcb_list_fonts_with_info(xcb_connection, + 1, + strlen(fontname), + fontname); + xcb_list_fonts_with_info_reply_t *reply; + reply = xcb_list_fonts_with_info_reply(xcb_connection, + cookie, + NULL); + font_height = reply->font_ascent + reply->font_descent; + printf("Calculated Font-height: %d\n", font_height); - /* FIXME: Maybe we can push that further backwards */ - get_atoms(); + /* FIXME: Maybe we can push that further backwards */ + get_atoms(); } void clean_xcb() { - xcb_disconnect(xcb_connection); + xcb_disconnect(xcb_connection); } void get_atoms() { - xcb_intern_atom_reply_t* reply; - #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ - atoms[name] = reply->atom; \ - free(reply); + xcb_intern_atom_reply_t *reply; + #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ + atoms[name] = reply->atom; \ + free(reply); - #include "xcb_atoms.def" - printf("Got Atoms\n"); + #include "xcb_atoms.def" + printf("Got Atoms\n"); } void destroy_windows() { - i3_output *walk; - if (outputs == NULL) { - return; - } - SLIST_FOREACH(walk, outputs, slist) { - if (walk->bar == XCB_NONE) { - continue; - } - xcb_destroy_window(xcb_connection, walk->bar); - walk->bar = XCB_NONE; - } + i3_output *walk; + if (outputs == NULL) { + return; + } + SLIST_FOREACH(walk, outputs, slist) { + if (walk->bar == XCB_NONE) { + continue; + } + xcb_destroy_window(xcb_connection, walk->bar); + walk->bar = XCB_NONE; + } } void create_windows() { - uint32_t mask; - uint32_t values[2]; + uint32_t mask; + uint32_t values[2]; - i3_output *walk; - SLIST_FOREACH(walk, outputs, slist) { - if (!walk->active) { - continue; - } - printf("Creating Window for output %s\n", walk->name); + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { + if (!walk->active) { + continue; + } + printf("Creating Window for output %s\n", walk->name); - walk->bar = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - values[0] = xcb_screens->black_pixel; - values[1] = XCB_EVENT_MASK_EXPOSURE | - XCB_EVENT_MASK_BUTTON_PRESS; - xcb_create_window(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); + walk->bar = xcb_generate_id(xcb_connection); + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + values[0] = xcb_screens->black_pixel; + values[1] = XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_BUTTON_PRESS; + xcb_create_window(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - walk->bargc = xcb_generate_id(xcb_connection); - mask = XCB_GC_FONT; - values[0] = xcb_font; - xcb_create_gc(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + walk->bargc = xcb_generate_id(xcb_connection); + mask = XCB_GC_FONT; + values[0] = xcb_font; + xcb_create_gc(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); - xcb_map_window(xcb_connection, walk->bar); - } - xcb_flush(xcb_connection); + xcb_map_window(xcb_connection, walk->bar); + } + xcb_flush(xcb_connection); } void draw_buttons() { - printf("Drawing Buttons...\n"); - int i = 0; - i3_output *outputs_walk; - SLIST_FOREACH(outputs_walk, outputs, slist) { - if (!outputs_walk->active) { - printf("Output %s inactive, skipping...\n", outputs_walk->name); - continue; - } - if (outputs_walk->bar == XCB_NONE) { - create_windows(); - } - uint32_t color = get_colorpixel("000000"); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FOREGROUND, - &color); - xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; - xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, - outputs_walk->bargc, - 1, - &rect); - i3_ws *ws_walk; - TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { - printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); - uint32_t color = get_colorpixel("240000"); - if (ws_walk->visible) { - color = get_colorpixel("480000"); - } - if (ws_walk->urgent) { - printf("WS %s is urgent!\n", ws_walk->name); - color = get_colorpixel("002400"); - } - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FOREGROUND, - &color); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_BACKGROUND, - &color); - xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; - xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, - outputs_walk->bargc, - 1, - &rect); - color = get_colorpixel("FFFFFF"); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FOREGROUND, - &color); - xcb_image_text_8(xcb_connection, - strlen(ws_walk->name), - outputs_walk->bar, - outputs_walk->bargc, - i + 5, font_height + 1, - ws_walk->name); - i += 10 + ws_walk->name_width; - } - i = 0; - } - xcb_flush(xcb_connection); + printf("Drawing Buttons...\n"); + int i = 0; + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + if (!outputs_walk->active) { + printf("Output %s inactive, skipping...\n", outputs_walk->name); + continue; + } + if (outputs_walk->bar == XCB_NONE) { + create_windows(); + } + uint32_t color = get_colorpixel("000000"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; + xcb_poly_fill_rectangle(xcb_connection, + outputs_walk->bar, + outputs_walk->bargc, + 1, + &rect); + i3_ws *ws_walk; + TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { + printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); + uint32_t color = get_colorpixel("240000"); + if (ws_walk->visible) { + color = get_colorpixel("480000"); + } + if (ws_walk->urgent) { + printf("WS %s is urgent!\n", ws_walk->name); + color = get_colorpixel("002400"); + } + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_BACKGROUND, + &color); + xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; + xcb_poly_fill_rectangle(xcb_connection, + outputs_walk->bar, + outputs_walk->bargc, + 1, + &rect); + color = get_colorpixel("FFFFFF"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + xcb_image_text_8(xcb_connection, + strlen(ws_walk->name), + outputs_walk->bar, + outputs_walk->bargc, + i + 5, font_height + 1, + ws_walk->name); + i += 10 + ws_walk->name_width; + } + i = 0; + } + xcb_flush(xcb_connection); } From 27aa9a640e4f7754a0068c0db6c42c05e9867ea5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 4 Aug 2010 03:34:18 +0200 Subject: [PATCH 015/185] Display statusline (without formats) --- i3bar/include/common.h | 7 +-- i3bar/include/outputs.h | 14 +++--- i3bar/include/xcb.h | 2 +- i3bar/src/ipc.c | 2 +- i3bar/src/main.c | 104 ++++++++++++++++++++++++++++++++++++++++ i3bar/src/xcb.c | 28 +++++++++-- 6 files changed, 142 insertions(+), 15 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 431c4694..e2bfb40b 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -3,9 +3,12 @@ #include "util.h" +typedef struct rect_t rect; typedef int bool; -typedef struct rect_t rect; +struct ev_loop* main_loop; +pid_t child_pid; +char *statusline; struct rect_t { int x; @@ -14,6 +17,4 @@ struct rect_t { int h; }; -struct ev_loop* main_loop; - #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 1c6abe3a..05383615 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -16,15 +16,15 @@ void free_outputs(); i3_output* get_output_by_name(char* name); struct i3_output { - char* name; - bool active; - int ws; - rect rect; + char* name; + bool active; + int ws; + rect rect; - xcb_window_t bar; - xcb_gcontext_t bargc; + xcb_window_t bar; + xcb_gcontext_t bargc; - struct ws_head *workspaces; + struct ws_head *workspaces; SLIST_ENTRY(i3_output) slist; }; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 230ff6e6..d97113a9 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -23,7 +23,7 @@ void clean_xcb(); void get_atoms(); void destroy_windows(); void create_windows(); -void draw_buttons(); +void draw_bars(); int get_string_width(char *string); void handle_xcb_event(xcb_generic_event_t *event); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 1553fc20..80ada521 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -41,7 +41,7 @@ void got_command_reply(char *reply) { void got_workspace_reply(char *reply) { printf("Got Workspace-Data!\n"); parse_workspaces_json(reply); - draw_buttons(); + draw_bars(); } void got_subscribe_reply(char *reply) { diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 9465fc12..3bd2183e 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -12,6 +14,8 @@ #include "common.h" #include "xcb.h" +#define STDIN_CHUNK_SIZE 1024 + void ev_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { xcb_flush(xcb_connection); } @@ -27,6 +31,99 @@ void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { void xcb_io_cb(struct ev_loop *loop, ev_io *w, int revents) { } +void start_child(char *command) { + int fd[2]; + pipe(fd); + child_pid = fork(); + switch (child_pid) { + case -1: + printf("ERROR: Couldn't fork()"); + exit(EXIT_FAILURE); + case 0: + close(fd[0]); + + dup2(fd[1], STDOUT_FILENO); + + static const char *shell = NULL; + + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; + + execl(shell, shell, "-c", command, (char*) NULL); + break; + default: + close(fd[1]); + + dup2(fd[0], STDIN_FILENO); + + break; + } +} + +void strip_dzen_formats(char *buffer) { + char *src = buffer; + char *dest = buffer; + while (*src != '\0') { + if (*src == '^') { + if (!strncmp(src, "^ro", strlen("^ro"))) { + *(dest++) = ' '; + *(dest++) = '|'; + *(dest++) = ' '; + } + while (*src != ')') { + src++; + } + src++; + } else { + *dest = *src; + src++; + dest++; + } + } + *(--dest) = '\0'; +} + +void child_io_cb(struct ev_loop *loop, ev_io *w, int revents) { + int fd = w->fd; + int n = 0; + int rec = 0; + int buffer_len = STDIN_CHUNK_SIZE; + char *buffer = malloc(buffer_len); + memset(buffer, '\0', buffer_len); + while(1) { + n = read(fd, buffer + rec, buffer_len - rec); + if (n == -1) { + if (errno == EAGAIN) { + break; + } + printf("ERROR: read() failed!"); + exit(EXIT_FAILURE); + } + if (n == 0) { + if (rec == buffer_len) { + char *tmp = buffer; + buffer = malloc(buffer_len + STDIN_CHUNK_SIZE); + memset(buffer, '\0', buffer_len); + strncpy(buffer, tmp, buffer_len); + buffer_len += STDIN_CHUNK_SIZE; + FREE(tmp); + } else { + break; + } + } + rec += n; + } + if (strlen(buffer) == 0) { + FREE(buffer); + return; + } + strip_dzen_formats(buffer); + FREE(statusline); + statusline = buffer; + printf("%s", buffer); + draw_bars(); +} + int main(int argc, char **argv) { main_loop = ev_default_loop(0); @@ -50,6 +147,13 @@ int main(int argc, char **argv) { i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + start_child("i3status"); + + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + ev_io *child_io = malloc(sizeof(ev_io)); + ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); + ev_io_start(main_loop, child_io); + ev_loop(main_loop, 0); ev_prepare_stop(main_loop, ev_prep); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6d7a38b3..6b16b45f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -7,6 +7,7 @@ #include "xcb.h" #include "outputs.h" #include "workspaces.h" +#include "common.h" #include "ipc.h" xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; @@ -88,7 +89,7 @@ void handle_button(xcb_button_press_event_t *event) { void handle_xcb_event(xcb_generic_event_t *event) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: - draw_buttons(); + draw_bars(); break; case XCB_BUTTON_PRESS: handle_button((xcb_button_press_event_t*) event); @@ -232,8 +233,8 @@ void create_windows() { xcb_flush(xcb_connection); } -void draw_buttons() { - printf("Drawing Buttons...\n"); +void draw_bars() { + printf("Drawing Bars...\n"); int i = 0; i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { @@ -255,6 +256,26 @@ void draw_buttons() { outputs_walk->bargc, 1, &rect); + if (statusline != NULL) { + printf("Printing statusline!\n"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_BACKGROUND, + &color); + color = get_colorpixel("FFFFFF"); + xcb_change_gc(xcb_connection, + outputs_walk->bargc, + XCB_GC_FOREGROUND, + &color); + + xcb_image_text_8(xcb_connection, + strlen(statusline), + outputs_walk->bar, + outputs_walk->bargc, + outputs_walk->rect.w - get_string_width(statusline) - 4, + font_height + 1, + statusline); + } i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); @@ -293,6 +314,7 @@ void draw_buttons() { ws_walk->name); i += 10 + ws_walk->name_width; } + i = 0; } xcb_flush(xcb_connection); From 51d466c41cda43551fab04831ea205d5926277e7 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 4 Aug 2010 04:07:16 +0200 Subject: [PATCH 016/185] Cleanup some Memory Leaks --- i3bar/src/ipc.c | 1 + i3bar/src/main.c | 7 +++++++ i3bar/src/xcb.c | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 80ada521..bf91420e 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -144,6 +144,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { reply_handlers[type](buffer); } + FREE(header); FREE(buffer); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 3bd2183e..ab362d5c 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -158,8 +158,15 @@ int main(int argc, char **argv) { ev_prepare_stop(main_loop, ev_prep); ev_check_stop(main_loop, ev_chk); + ev_io_stop(main_loop, xcb_io); + ev_io_stop(main_loop, child_io); + + FREE(xcb_io); FREE(ev_prep); FREE(ev_chk); + free(child_io); + + FREE(statusline); ev_default_destroy(); clean_xcb(); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6b16b45f..eff74ac4 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -147,9 +147,9 @@ void init_xcb() { cookie, NULL); font_height = reply->font_ascent + reply->font_descent; + FREE(reply); printf("Calculated Font-height: %d\n", font_height); - /* FIXME: Maybe we can push that further backwards */ get_atoms(); } From 7d7867acce523abac9b20f86fe3c476e8c92c7a8 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 5 Aug 2010 05:09:59 +0200 Subject: [PATCH 017/185] Be more strict with encapsulation I.e. move the xcb-event-handling into xcb.c and the child-process-communications into newly created child.c. Also change some includes. --- i3bar/include/child.h | 9 +++ i3bar/include/common.h | 10 ++- i3bar/include/ipc.h | 1 - i3bar/include/outputs.h | 1 - i3bar/include/workspaces.h | 1 - i3bar/include/xcb.h | 18 +---- i3bar/src/child.c | 135 ++++++++++++++++++++++++++++++++++ i3bar/src/ipc.c | 5 +- i3bar/src/main.c | 145 +------------------------------------ i3bar/src/outputs.c | 3 - i3bar/src/workspaces.c | 4 - i3bar/src/xcb.c | 59 ++++++++++++++- 12 files changed, 211 insertions(+), 180 deletions(-) create mode 100644 i3bar/include/child.h create mode 100644 i3bar/src/child.c diff --git a/i3bar/include/child.h b/i3bar/include/child.h new file mode 100644 index 00000000..3d3c28c9 --- /dev/null +++ b/i3bar/include/child.h @@ -0,0 +1,9 @@ +#ifndef CHILD_H_ +#define CHILD_H_ + +#define STDIN_CHUNK_SIZE 1024 + +void start_child(char *command); +void kill_child(); + +#endif diff --git a/i3bar/include/common.h b/i3bar/include/common.h index e2bfb40b..3feab698 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -1,8 +1,6 @@ #ifndef COMMON_H_ #define COMMON_H_ -#include "util.h" - typedef struct rect_t rect; typedef int bool; @@ -17,4 +15,12 @@ struct rect_t { int h; }; +#include "queue.h" +#include "child.h" +#include "ipc.h" +#include "outputs.h" +#include "util.h" +#include "workspaces.h" +#include "xcb.h" + #endif diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index 278077e0..b3760d2a 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -1,7 +1,6 @@ #ifndef IPC_H_ #define IPC_H_ -#include #include int init_connection(const char *socket_path); diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 05383615..b00a93b4 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -4,7 +4,6 @@ #include #include "common.h" -#include "workspaces.h" typedef struct i3_output i3_output; diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 64c1065e..ae3c1303 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -2,7 +2,6 @@ #define WORKSPACES_H_ #include "common.h" -#include "outputs.h" typedef struct i3_ws i3_ws; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index d97113a9..a75b7154 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -1,22 +1,7 @@ #ifndef XCB_H_ #define XCB_H_ -#include - -#define NUM_ATOMS 3 - -enum { - #define ATOM_DO(name) name, - #include "xcb_atoms.def" -}; - -xcb_atom_t atoms[NUM_ATOMS]; - -xcb_connection_t *xcb_connection; -xcb_screen_t *xcb_screens; -xcb_window_t xcb_root; -xcb_font_t xcb_font; -int font_height; +int font_height; void init_xcb(); void clean_xcb(); @@ -25,6 +10,5 @@ void destroy_windows(); void create_windows(); void draw_bars(); int get_string_width(char *string); -void handle_xcb_event(xcb_generic_event_t *event); #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c new file mode 100644 index 00000000..5fe9ca8c --- /dev/null +++ b/i3bar/src/child.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +ev_io *child_io; +ev_child *child_sig; + +void cleanup() { + ev_io_stop(main_loop, child_io); + ev_child_stop(main_loop, child_sig); + FREE(child_io); + FREE(child_sig); + FREE(statusline); +} + +void strip_dzen_formats(char *buffer) { + char *src = buffer; + char *dest = buffer; + while (*src != '\0') { + if (*src == '^') { + if (!strncmp(src, "^ro", strlen("^ro"))) { + *(dest++) = ' '; + *(dest++) = '|'; + *(dest++) = ' '; + } + while (*src != ')') { + src++; + } + src++; + } else { + *dest = *src; + src++; + dest++; + } + } + *(--dest) = '\0'; +} + +void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { + int fd = watcher->fd; + int n = 0; + int rec = 0; + int buffer_len = STDIN_CHUNK_SIZE; + char *buffer = malloc(buffer_len); + memset(buffer, '\0', buffer_len); + while(1) { + n = read(fd, buffer + rec, buffer_len - rec); + if (n == -1) { + if (errno == EAGAIN) { + break; + } + printf("ERROR: read() failed!"); + exit(EXIT_FAILURE); + } + if (n == 0) { + if (rec == buffer_len) { + char *tmp = buffer; + buffer = malloc(buffer_len + STDIN_CHUNK_SIZE); + memset(buffer, '\0', buffer_len); + strncpy(buffer, tmp, buffer_len); + buffer_len += STDIN_CHUNK_SIZE; + FREE(tmp); + } else { + break; + } + } + rec += n; + } + if (strlen(buffer) == 0) { + FREE(buffer); + return; + } + strip_dzen_formats(buffer); + FREE(statusline); + statusline = buffer; + printf("%s", buffer); + draw_bars(); +} + +void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { + printf("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus); + cleanup(); +} + +void start_child(char *command) { + int fd[2]; + pipe(fd); + child_pid = fork(); + switch (child_pid) { + case -1: + printf("ERROR: Couldn't fork()"); + exit(EXIT_FAILURE); + case 0: + close(fd[0]); + + dup2(fd[1], STDOUT_FILENO); + + static const char *shell = NULL; + + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; + + execl(shell, shell, "-c", command, (char*) NULL); + break; + default: + close(fd[1]); + + dup2(fd[0], STDIN_FILENO); + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + + child_io = malloc(sizeof(ev_io)); + ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); + ev_io_start(main_loop, child_io); + + /* We must cleanup, if the child unexpectedly terminates */ + child_sig = malloc(sizeof(ev_io)); + ev_child_init(child_sig, &child_sig_cb, child_pid, 0); + ev_child_start(main_loop, child_sig); + + break; + } +} + +void kill_child() { + kill(child_pid, SIGQUIT); + cleanup(); +} diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index bf91420e..4b17a4bc 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -5,12 +5,9 @@ #include #include #include +#include #include "common.h" -#include "outputs.h" -#include "workspaces.h" -#include "xcb.h" -#include "ipc.h" ev_io *i3_connection; diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ab362d5c..6ce7a38a 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -3,126 +3,10 @@ #include #include #include -#include #include #include -#include -#include "ipc.h" -#include "outputs.h" -#include "workspaces.h" #include "common.h" -#include "xcb.h" - -#define STDIN_CHUNK_SIZE 1024 - -void ev_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { - xcb_flush(xcb_connection); -} - -void ev_check_cb(struct ev_loop *loop, ev_check *w, int revents) { - xcb_generic_event_t *event; - if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { - handle_xcb_event(event); - } - free(event); -} - -void xcb_io_cb(struct ev_loop *loop, ev_io *w, int revents) { -} - -void start_child(char *command) { - int fd[2]; - pipe(fd); - child_pid = fork(); - switch (child_pid) { - case -1: - printf("ERROR: Couldn't fork()"); - exit(EXIT_FAILURE); - case 0: - close(fd[0]); - - dup2(fd[1], STDOUT_FILENO); - - static const char *shell = NULL; - - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; - - execl(shell, shell, "-c", command, (char*) NULL); - break; - default: - close(fd[1]); - - dup2(fd[0], STDIN_FILENO); - - break; - } -} - -void strip_dzen_formats(char *buffer) { - char *src = buffer; - char *dest = buffer; - while (*src != '\0') { - if (*src == '^') { - if (!strncmp(src, "^ro", strlen("^ro"))) { - *(dest++) = ' '; - *(dest++) = '|'; - *(dest++) = ' '; - } - while (*src != ')') { - src++; - } - src++; - } else { - *dest = *src; - src++; - dest++; - } - } - *(--dest) = '\0'; -} - -void child_io_cb(struct ev_loop *loop, ev_io *w, int revents) { - int fd = w->fd; - int n = 0; - int rec = 0; - int buffer_len = STDIN_CHUNK_SIZE; - char *buffer = malloc(buffer_len); - memset(buffer, '\0', buffer_len); - while(1) { - n = read(fd, buffer + rec, buffer_len - rec); - if (n == -1) { - if (errno == EAGAIN) { - break; - } - printf("ERROR: read() failed!"); - exit(EXIT_FAILURE); - } - if (n == 0) { - if (rec == buffer_len) { - char *tmp = buffer; - buffer = malloc(buffer_len + STDIN_CHUNK_SIZE); - memset(buffer, '\0', buffer_len); - strncpy(buffer, tmp, buffer_len); - buffer_len += STDIN_CHUNK_SIZE; - FREE(tmp); - } else { - break; - } - } - rec += n; - } - if (strlen(buffer) == 0) { - FREE(buffer); - return; - } - strip_dzen_formats(buffer); - FREE(statusline); - statusline = buffer; - printf("%s", buffer); - draw_bars(); -} int main(int argc, char **argv) { main_loop = ev_default_loop(0); @@ -132,44 +16,19 @@ int main(int argc, char **argv) { subscribe_events(); - ev_io *xcb_io = malloc(sizeof(ev_io)); - ev_prepare *ev_prep = malloc(sizeof(ev_prepare)); - ev_check *ev_chk = malloc(sizeof(ev_check)); - - ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); - ev_prepare_init(ev_prep, &ev_prepare_cb); - ev_check_init(ev_chk, &ev_check_cb); - - ev_io_start(main_loop, xcb_io); - ev_prepare_start(main_loop, ev_prep); - ev_check_start(main_loop, ev_chk); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); start_child("i3status"); - fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); - ev_io *child_io = malloc(sizeof(ev_io)); - ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); - ev_io_start(main_loop, child_io); - ev_loop(main_loop, 0); - ev_prepare_stop(main_loop, ev_prep); - ev_check_stop(main_loop, ev_chk); - ev_io_stop(main_loop, xcb_io); - ev_io_stop(main_loop, child_io); - - FREE(xcb_io); - FREE(ev_prep); - FREE(ev_chk); - free(child_io); + kill_child(); FREE(statusline); - ev_default_destroy(); clean_xcb(); + ev_default_destroy(); free_workspaces(); FREE_SLIST(outputs, i3_output); diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 18abff51..dc61cb47 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -2,12 +2,9 @@ #include #include #include - #include #include "common.h" -#include "outputs.h" -#include "ipc.h" struct outputs_json_params { struct outputs_head *outputs; diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index ee54c8b6..abc3a572 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -1,13 +1,9 @@ #include #include #include - #include #include "common.h" -#include "workspaces.h" -#include "xcb.h" -#include "ipc.h" struct workspaces_json_params { struct ws_head *workspaces; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index eff74ac4..154af575 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -3,14 +3,28 @@ #include #include #include +#include -#include "xcb.h" -#include "outputs.h" -#include "workspaces.h" #include "common.h" -#include "ipc.h" + +#define NUM_ATOMS 3 + +enum { + #define ATOM_DO(name) name, + #include "xcb_atoms.def" +}; xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; +xcb_atom_t atoms[NUM_ATOMS]; + +xcb_connection_t *xcb_connection; +xcb_screen_t *xcb_screens; +xcb_window_t xcb_root; +xcb_font_t xcb_font; + +ev_prepare *xcb_prep; +ev_check *xcb_chk; +ev_io *xcb_io; uint32_t get_colorpixel(const char *s) { char strings[3][3] = { { s[0], s[1], '\0'} , @@ -97,6 +111,23 @@ void handle_xcb_event(xcb_generic_event_t *event) { } } +void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { + xcb_flush(xcb_connection); +} + +void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { + xcb_generic_event_t *event; + if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { + handle_xcb_event(event); + } + FREE(event); +} + +void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { + /* Dummy Callback. We only need this, so that xcb-events trigger + * Prepare- and Check-Watchers */ +} + int get_string_width(char *string) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; @@ -150,12 +181,32 @@ void init_xcb() { FREE(reply); printf("Calculated Font-height: %d\n", font_height); + xcb_io = malloc(sizeof(ev_io)); + xcb_prep = malloc(sizeof(ev_prepare)); + xcb_chk = malloc(sizeof(ev_check)); + + ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); + ev_prepare_init(xcb_prep, &xcb_prep_cb); + ev_check_init(xcb_chk, &xcb_chk_cb); + + ev_io_start(main_loop, xcb_io); + ev_prepare_start(main_loop, xcb_prep); + ev_check_start(main_loop, xcb_chk); + /* FIXME: Maybe we can push that further backwards */ get_atoms(); } void clean_xcb() { xcb_disconnect(xcb_connection); + + ev_check_stop(main_loop, xcb_chk); + ev_prepare_stop(main_loop, xcb_prep); + ev_io_stop(main_loop, xcb_io); + + FREE(xcb_chk); + FREE(xcb_prep); + FREE(xcb_io); } void get_atoms() { From 1daa395a77bf3a3f8e8467518b479fc16e060784 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 03:32:05 +0200 Subject: [PATCH 018/185] Added Unicode-Support --- i3bar/include/common.h | 1 + i3bar/include/outputs.h | 1 + i3bar/include/ucs2_to_utf8.h | 1 + i3bar/include/workspaces.h | 4 + i3bar/include/xcb.h | 4 +- i3bar/src/child.c | 69 +++++++++------- i3bar/src/ipc.c | 8 +- i3bar/src/main.c | 58 ++++++++++++- i3bar/src/outputs.c | 48 ++++++----- i3bar/src/ucs2_to_utf8.c | 103 ++++++++++++++++++++++++ i3bar/src/workspaces.c | 44 +++++----- i3bar/src/xcb.c | 152 ++++++++++++++++++++--------------- 12 files changed, 352 insertions(+), 141 deletions(-) create mode 100644 i3bar/include/ucs2_to_utf8.h create mode 100644 i3bar/src/ucs2_to_utf8.c diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 3feab698..b77ac8ea 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -22,5 +22,6 @@ struct rect_t { #include "util.h" #include "workspaces.h" #include "xcb.h" +#include "ucs2_to_utf8.h" #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index b00a93b4..64fa8563 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -11,6 +11,7 @@ SLIST_HEAD(outputs_head, i3_output); struct outputs_head *outputs; void parse_outputs_json(char* json); +void init_outputs(); void free_outputs(); i3_output* get_output_by_name(char* name); diff --git a/i3bar/include/ucs2_to_utf8.h b/i3bar/include/ucs2_to_utf8.h new file mode 100644 index 00000000..2fb3862a --- /dev/null +++ b/i3bar/include/ucs2_to_utf8.h @@ -0,0 +1 @@ +char *convert_utf8_to_ucs2(char *input, int *real_strlen); diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index ae3c1303..e32e7c21 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -1,6 +1,8 @@ #ifndef WORKSPACES_H_ #define WORKSPACES_H_ +#include + #include "common.h" typedef struct i3_ws i3_ws; @@ -13,6 +15,8 @@ void free_workspaces(); struct i3_ws { int num; char *name; + xcb_char2b_t *ucs2_name; + int name_glyphs; int name_width; bool visible; bool focused; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index a75b7154..7bc76e62 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -7,8 +7,8 @@ void init_xcb(); void clean_xcb(); void get_atoms(); void destroy_windows(); -void create_windows(); +void reconfig_windows(); void draw_bars(); -int get_string_width(char *string); +int get_string_width(xcb_char2b_t *string, int glyph_len); #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 5fe9ca8c..362a56d4 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -81,7 +81,7 @@ void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { strip_dzen_formats(buffer); FREE(statusline); statusline = buffer; - printf("%s", buffer); + printf("%s\n", buffer); draw_bars(); } @@ -91,45 +91,52 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { } void start_child(char *command) { - int fd[2]; - pipe(fd); - child_pid = fork(); - switch (child_pid) { - case -1: - printf("ERROR: Couldn't fork()"); - exit(EXIT_FAILURE); - case 0: - close(fd[0]); + child_pid = 0; + if (command != NULL) { + int fd[2]; + pipe(fd); + child_pid = fork(); + switch (child_pid) { + case -1: + printf("ERROR: Couldn't fork()"); + exit(EXIT_FAILURE); + case 0: + close(fd[0]); - dup2(fd[1], STDOUT_FILENO); + dup2(fd[1], STDOUT_FILENO); - static const char *shell = NULL; + static const char *shell = NULL; - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - execl(shell, shell, "-c", command, (char*) NULL); - break; - default: - close(fd[1]); + execl(shell, shell, "-c", command, (char*) NULL); + return; + default: + close(fd[1]); - dup2(fd[0], STDIN_FILENO); - fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + dup2(fd[0], STDIN_FILENO); - child_io = malloc(sizeof(ev_io)); - ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); - ev_io_start(main_loop, child_io); - - /* We must cleanup, if the child unexpectedly terminates */ - child_sig = malloc(sizeof(ev_io)); - ev_child_init(child_sig, &child_sig_cb, child_pid, 0); - ev_child_start(main_loop, child_sig); - - break; + break; + } } + + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + + child_io = malloc(sizeof(ev_io)); + ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); + ev_io_start(main_loop, child_io); + + /* We must cleanup, if the child unexpectedly terminates */ + child_sig = malloc(sizeof(ev_io)); + ev_child_init(child_sig, &child_sig_cb, child_pid, 0); + ev_child_start(main_loop, child_sig); + } void kill_child() { - kill(child_pid, SIGQUIT); + if (child_pid != 0) { + kill(child_pid, SIGQUIT); + } cleanup(); } diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 4b17a4bc..271cd339 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -47,12 +47,10 @@ void got_subscribe_reply(char *reply) { } void got_output_reply(char *reply) { - printf("Got Outputs-Data!\nDestroying Windows...\n"); - destroy_windows(); - printf("Parsing JSON...\n"); + printf("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); - printf("Creating_Windows...\n"); - create_windows(); + printf("Reconfiguring Windows...\n"); + reconfig_windows(); } handler_t reply_handlers[] = { diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 6ce7a38a..62f4974e 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -5,21 +5,73 @@ #include #include #include +#include #include "common.h" +char *i3_default_sock_path = "/home/mero/.i3/ipc.sock"; + int main(int argc, char **argv) { + int opt; + int option_index = 0; + char *socket_path = NULL; + char *command = NULL; + char *fontname = NULL; + + static struct option long_opt[] = { + { "socket", required_argument, 0, 's' }, + { "command", required_argument, 0, 'c' }, + { "font", required_argument, 0, 'f' }, + { "help", no_argument, 0, 'h' }, + { NULL, 0, 0, 0} + }; + + while ((opt = getopt_long(argc, argv, "s:c:f:h", long_opt, &option_index)) != -1) { + switch (opt) { + case 's': + socket_path = malloc(strlen(optarg)); + strcpy(socket_path, optarg); + break; + case 'c': + command = malloc(strlen(optarg)); + strcpy(command, optarg); + break; + case 'f': + fontname = malloc(strlen(optarg)); + strcpy(socket_path, optarg); + break; + default: + printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); + printf("-s : Connect to i3 via \n"); + printf("-c : Execute to get sdtin\n"); + printf("-f : Use X-Core-Font for display\n"); + printf("-h: Display this help-message and exit\n"); + exit(EXIT_SUCCESS); + break; + } + } + + if (fontname == NULL) { + fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; + } + + if (socket_path == NULL) { + printf("No Socket Path Specified, default to %s\n", i3_default_sock_path); + socket_path = i3_default_sock_path; + } + main_loop = ev_default_loop(0); - init_xcb(); - init_connection("/home/mero/.i3/ipc.sock"); + init_xcb(fontname); + init_outputs(); + init_connection(socket_path); subscribe_events(); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); - start_child("i3status"); + start_child(command); ev_loop(main_loop, 0); diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index dc61cb47..96f7d55f 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -11,6 +11,7 @@ struct outputs_json_params { i3_output *outputs_walk; char *cur_key; char *json; + bool init; }; static int outputs_null_cb(void *params_) { @@ -82,9 +83,11 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i return 0; } - params->outputs_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); - strncpy(params->outputs_walk->name, (const char*) val, len); - params->outputs_walk->name[len] = '\0'; + char *name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(name, (const char*) val, len); + name[len] = '\0'; + + params->outputs_walk->name = name; FREE(params->cur_key); @@ -105,9 +108,7 @@ static int outputs_start_map_cb(void *params_) { new_output->workspaces = malloc(sizeof(struct ws_head)); TAILQ_INIT(new_output->workspaces); - SLIST_INSERT_HEAD(params->outputs, new_output, slist); - - params->outputs_walk = SLIST_FIRST(params->outputs); + params->outputs_walk = new_output; return 1; } @@ -115,6 +116,20 @@ static int outputs_start_map_cb(void *params_) { return 1; } +static int outputs_end_map_cb(void *params_) { + struct outputs_json_params *params = (struct outputs_json_params*) params_; + + i3_output *target = get_output_by_name(params->outputs_walk->name); + + if (target == NULL) { + SLIST_INSERT_HEAD(outputs, params->outputs_walk, slist); + } else { + target->ws = params->outputs_walk->ws; + target->rect = params->outputs_walk->rect; + } + return 1; +} + static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); @@ -135,18 +150,18 @@ yajl_callbacks outputs_callbacks = { &outputs_string_cb, &outputs_start_map_cb, &outputs_map_key_cb, - NULL, + &outputs_end_map_cb, NULL, NULL }; +void init_outputs() { + outputs = malloc(sizeof(struct outputs_head)); + SLIST_INIT(outputs); +} + void parse_outputs_json(char *json) { - /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret - * JSON in chunks */ struct outputs_json_params params; - printf(json); - params.outputs = malloc(sizeof(struct outputs_head)); - SLIST_INIT(params.outputs); params.outputs_walk = NULL; params.cur_key = NULL; @@ -173,16 +188,13 @@ void parse_outputs_json(char *json) { } yajl_free(handle); - - if (outputs != NULL) { - FREE_SLIST(outputs, i3_output); - } - - outputs = params.outputs; } i3_output *get_output_by_name(char *name) { i3_output *walk; + if (name == NULL) { + return NULL; + } SLIST_FOREACH(walk, outputs, slist) { if (!strcmp(walk->name, name)) { break; diff --git a/i3bar/src/ucs2_to_utf8.c b/i3bar/src/ucs2_to_utf8.c new file mode 100644 index 00000000..8c79c3f9 --- /dev/null +++ b/i3bar/src/ucs2_to_utf8.c @@ -0,0 +1,103 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * © 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ +#include +#include +#include +#include +#include + +static iconv_t conversion_descriptor = 0; +static iconv_t conversion_descriptor2 = 0; + +/* + * Returns the input string, but converted from UCS-2 to UTF-8. Memory will be + * allocated, thus the caller has to free the output. + * + */ +char *convert_ucs_to_utf8(char *input) { + size_t input_size = 2; + /* UTF-8 may consume up to 4 byte */ + int buffer_size = 8; + + char *buffer = calloc(buffer_size, 1); + if (buffer == NULL) + err(EXIT_FAILURE, "malloc() failed\n"); + size_t output_size = buffer_size; + /* We need to use an additional pointer, because iconv() modifies it */ + char *output = buffer; + + /* We convert the input into UCS-2 big endian */ + if (conversion_descriptor == 0) { + conversion_descriptor = iconv_open("UTF-8", "UCS-2BE"); + if (conversion_descriptor == 0) { + fprintf(stderr, "error opening the conversion context\n"); + exit(1); + } + } + + /* Get the conversion descriptor back to original state */ + iconv(conversion_descriptor, NULL, NULL, NULL, NULL); + + /* Convert our text */ + int rc = iconv(conversion_descriptor, (void*)&input, &input_size, &output, &output_size); + if (rc == (size_t)-1) { + perror("Converting to UCS-2 failed"); + return NULL; + } + + return buffer; +} + +/* + * Converts the given string to UCS-2 big endian for use with + * xcb_image_text_16(). The amount of real glyphs is stored in real_strlen, + * a buffer containing the UCS-2 encoded string (16 bit per glyph) is + * returned. It has to be freed when done. + * + */ +char *convert_utf8_to_ucs2(char *input, int *real_strlen) { + size_t input_size = strlen(input) + 1; + /* UCS-2 consumes exactly two bytes for each glyph */ + int buffer_size = input_size * 2; + + char *buffer = malloc(buffer_size); + if (buffer == NULL) + err(EXIT_FAILURE, "malloc() failed\n"); + size_t output_size = buffer_size; + /* We need to use an additional pointer, because iconv() modifies it */ + char *output = buffer; + + /* We convert the input into UCS-2 big endian */ + if (conversion_descriptor2 == 0) { + conversion_descriptor2 = iconv_open("UCS-2BE", "UTF-8"); + if (conversion_descriptor2 == 0) { + fprintf(stderr, "error opening the conversion context\n"); + exit(1); + } + } + + /* Get the conversion descriptor back to original state */ + iconv(conversion_descriptor2, NULL, NULL, NULL, NULL); + + /* Convert our text */ + int rc = iconv(conversion_descriptor2, (void*)&input, &input_size, &output, &output_size); + if (rc == (size_t)-1) { + perror("Converting to UCS-2 failed"); + if (real_strlen != NULL) + *real_strlen = 0; + return NULL; + } + + if (real_strlen != NULL) + *real_strlen = ((buffer_size - output_size) / 2) - 1; + + return buffer; +} diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index abc3a572..f4df0444 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -94,32 +94,38 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne char *output_name; if (!strcmp(params->cur_key, "name")) { - params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); - strncpy(params->workspaces_walk->name, (const char*) val, len); - params->workspaces_walk->name[len] = '\0'; + params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(params->workspaces_walk->name, (const char*) val, len); + params->workspaces_walk->name[len] = '\0'; - params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->name); + int ucs2_len; + xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len); + params->workspaces_walk->ucs2_name = ucs2_name; + params->workspaces_walk->name_glyphs = ucs2_len; + params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->ucs2_name, + params->workspaces_walk->name_glyphs); - printf("Got Workspace %s, name_width: %d\n", - params->workspaces_walk->name, - params->workspaces_walk->name_width); - FREE(params->cur_key); + printf("Got Workspace %s, name_width: %d, glyphs: %d\n", + params->workspaces_walk->name, + params->workspaces_walk->name_width, + params->workspaces_walk->name_glyphs); + FREE(params->cur_key); - return 1; + return 1; } if (!strcmp(params->cur_key, "output")) { - output_name = malloc(sizeof(const unsigned char) * (len + 1)); - strncpy(output_name, (const char*) val, len); - output_name[len] = '\0'; - params->workspaces_walk->output = get_output_by_name(output_name); + output_name = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(output_name, (const char*) val, len); + output_name[len] = '\0'; + params->workspaces_walk->output = get_output_by_name(output_name); - TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, - params->workspaces_walk, - tailq); + TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, + params->workspaces_walk, + tailq); - free(output_name); - return 1; + FREE(output_name); + return 1; } return 0; @@ -128,7 +134,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne static int workspaces_start_map_cb(void *params_) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - i3_ws *new_workspace = NULL; + i3_ws *new_workspace = NULL; if (params->cur_key == NULL) { new_workspace = malloc(sizeof(i3_ws)); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 154af575..dc227355 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -26,6 +28,8 @@ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; +xcb_event_handlers_t xcb_event_handlers; + uint32_t get_colorpixel(const char *s) { char strings[3][3] = { { s[0], s[1], '\0'} , { s[2], s[3], '\0'} , @@ -128,14 +132,14 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * Prepare- and Check-Watchers */ } -int get_string_width(char *string) { +int get_string_width(xcb_char2b_t *string, int glyph_len) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; xcb_generic_error_t *error; int width; - cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t*) string); - if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { + cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); + if ((reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { printf("ERROR: Could not get text extents!"); return 7; } @@ -145,7 +149,7 @@ int get_string_width(char *string) { return width; } -void init_xcb() { +void init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); if (xcb_connection_has_error(xcb_connection)) { @@ -162,7 +166,6 @@ void init_xcb() { xcb_root = xcb_screens->root; xcb_font = xcb_generate_id(xcb_connection); - char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; xcb_open_font(xcb_connection, xcb_font, strlen(fontname), @@ -219,67 +222,80 @@ void get_atoms() { printf("Got Atoms\n"); } -void destroy_windows() { - i3_output *walk; - if (outputs == NULL) { +void destroy_window(i3_output *output) { + if (output == NULL) { return; } - SLIST_FOREACH(walk, outputs, slist) { - if (walk->bar == XCB_NONE) { - continue; - } - xcb_destroy_window(xcb_connection, walk->bar); - walk->bar = XCB_NONE; + if (output->bar == XCB_NONE) { + return; } + xcb_destroy_window(xcb_connection, output->bar); + output->bar = XCB_NONE; } -void create_windows() { +void reconfig_windows() { uint32_t mask; - uint32_t values[2]; + uint32_t values[4]; i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { + destroy_window(walk); continue; } - printf("Creating Window for output %s\n", walk->name); + if (walk->bar == XCB_NONE) { + printf("Creating Window for output %s\n", walk->name); - walk->bar = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - values[0] = xcb_screens->black_pixel; - values[1] = XCB_EVENT_MASK_EXPOSURE | - XCB_EVENT_MASK_BUTTON_PRESS; - xcb_create_window(xcb_connection, - xcb_screens->root_depth, + walk->bar = xcb_generate_id(xcb_connection); + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + values[0] = xcb_screens->black_pixel; + values[1] = XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_BUTTON_PRESS; + xcb_create_window(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + + walk->bargc = xcb_generate_id(xcb_connection); + mask = XCB_GC_FONT; + values[0] = xcb_font; + xcb_create_gc(xcb_connection, + walk->bargc, walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, mask, values); - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - - walk->bargc = xcb_generate_id(xcb_connection); - mask = XCB_GC_FONT; - values[0] = xcb_font; - xcb_create_gc(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); - - xcb_map_window(xcb_connection, walk->bar); + xcb_map_window(xcb_connection, walk->bar); + } else { + mask = XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT; + values[0] = walk->rect.x; + values[1] = walk->rect.y; + values[2] = walk->rect.w; + values[3] = walk->rect.h; + xcb_configure_window(xcb_connection, + walk->bar, + mask, + values); + } } xcb_flush(xcb_connection); } @@ -294,7 +310,7 @@ void draw_bars() { continue; } if (outputs_walk->bar == XCB_NONE) { - create_windows(); + reconfig_windows(); } uint32_t color = get_colorpixel("000000"); xcb_change_gc(xcb_connection, @@ -319,13 +335,23 @@ void draw_bars() { XCB_GC_FOREGROUND, &color); - xcb_image_text_8(xcb_connection, - strlen(statusline), - outputs_walk->bar, - outputs_walk->bargc, - outputs_walk->rect.w - get_string_width(statusline) - 4, - font_height + 1, - statusline); + int glyph_count; + xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); + + xcb_void_cookie_t cookie; + cookie = xcb_image_text_16(xcb_connection, + glyph_count, + outputs_walk->bar, + outputs_walk->bargc, + outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, + font_height + 1, + (xcb_char2b_t*) text); + + xcb_generic_error_t *err = xcb_request_check(xcb_connection, cookie); + + if (err != NULL) { + printf("XCB-Error: %d\n", err->error_code); + } } i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { @@ -357,12 +383,12 @@ void draw_bars() { outputs_walk->bargc, XCB_GC_FOREGROUND, &color); - xcb_image_text_8(xcb_connection, - strlen(ws_walk->name), - outputs_walk->bar, - outputs_walk->bargc, - i + 5, font_height + 1, - ws_walk->name); + xcb_image_text_16(xcb_connection, + ws_walk->name_glyphs, + outputs_walk->bar, + outputs_walk->bargc, + i + 5, font_height + 1, + ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } From fae997038d6ede3d24096c01b6eec2a6aaf1ad69 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 03:42:33 +0200 Subject: [PATCH 019/185] Remove superflous xcb_flush()es --- i3bar/src/xcb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index dc227355..1d359c0e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -297,7 +297,6 @@ void reconfig_windows() { values); } } - xcb_flush(xcb_connection); } void draw_bars() { @@ -394,5 +393,4 @@ void draw_bars() { i = 0; } - xcb_flush(xcb_connection); } From 36445f500f049d2aa1391d7dfda33aeaed8bcdb7 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 04:11:44 +0200 Subject: [PATCH 020/185] Use correct default-path for ipc-socket --- i3bar/src/main.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 62f4974e..4cb2fcb2 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -6,10 +6,26 @@ #include #include #include +#include #include "common.h" -char *i3_default_sock_path = "/home/mero/.i3/ipc.sock"; +char *i3_default_sock_path = "~/.i3/ipc.sock"; + +char *expand_path(char *path) { + static glob_t globbuf; + if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { + printf("glob() failed"); + exit(EXIT_FAILURE); + } + char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); + if (result == NULL) { + printf("malloc() failed"); + exit(EXIT_FAILURE); + } + globfree(&globbuf); + return result; +} int main(int argc, char **argv) { int opt; @@ -29,16 +45,13 @@ int main(int argc, char **argv) { while ((opt = getopt_long(argc, argv, "s:c:f:h", long_opt, &option_index)) != -1) { switch (opt) { case 's': - socket_path = malloc(strlen(optarg)); - strcpy(socket_path, optarg); + socket_path = expand_path(optarg); break; case 'c': - command = malloc(strlen(optarg)); - strcpy(command, optarg); + command = strdup(optarg); break; case 'f': - fontname = malloc(strlen(optarg)); - strcpy(socket_path, optarg); + fontname = strdup(optarg); break; default: printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); @@ -57,7 +70,7 @@ int main(int argc, char **argv) { if (socket_path == NULL) { printf("No Socket Path Specified, default to %s\n", i3_default_sock_path); - socket_path = i3_default_sock_path; + socket_path = expand_path(i3_default_sock_path); } main_loop = ev_default_loop(0); @@ -66,6 +79,8 @@ int main(int argc, char **argv) { init_outputs(); init_connection(socket_path); + FREE(socket_path); + subscribe_events(); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); From a4b1e0d01aa2663686b73503929b66e68e7bbc28 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 05:49:57 +0200 Subject: [PATCH 021/185] Modify the active-flag on parsing the output-list --- i3bar/src/outputs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 96f7d55f..5fcbd64d 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -124,6 +124,7 @@ static int outputs_end_map_cb(void *params_) { if (target == NULL) { SLIST_INSERT_HEAD(outputs, params->outputs_walk, slist); } else { + target->active = params->outputs_walk->active; target->ws = params->outputs_walk->ws; target->rect = params->outputs_walk->rect; } From 55047c1633736e44cc6538e03af77c87a15ebf42 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 05:52:01 +0200 Subject: [PATCH 022/185] Refresh the workspace-list on output-events --- i3bar/src/ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 271cd339..83ae4cec 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -68,6 +68,7 @@ void got_workspace_event(char *event) { void got_output_event(char *event) { printf("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } handler_t event_handlers[] = { From 660c77bdb8fc770aa21255e79036cc6656c33d31 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 6 Aug 2010 05:53:38 +0200 Subject: [PATCH 023/185] Reconfigure to the correct coordinates --- i3bar/src/xcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 1d359c0e..75011dac 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -240,6 +240,7 @@ void reconfig_windows() { i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { + printf("Destroying window for output %s\n", walk->name); destroy_window(walk); continue; } @@ -288,9 +289,10 @@ void reconfig_windows() { XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; values[0] = walk->rect.x; - values[1] = walk->rect.y; + values[1] = walk->rect.y + walk->rect.h - font_height - 6; values[2] = walk->rect.w; - values[3] = walk->rect.h; + values[3] = font_height + 6; + printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); xcb_configure_window(xcb_connection, walk->bar, mask, From b1a8ddd9d7518ba08f949efa50dfe192d547afb6 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 01:57:00 +0200 Subject: [PATCH 024/185] We don't need a callback for null-values --- i3bar/src/workspaces.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index f4df0444..e3efb445 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -12,18 +12,6 @@ struct workspaces_json_params { char *json; }; -static int workspaces_null_cb(void *params_) { - struct workspaces_json_params *params = (struct workspaces_json_params*) params_; - - if (strcmp(params->cur_key, "current_workspace")) { - return 0; - } - - FREE(params->cur_key); - - return 1; -} - static int workspaces_boolean_cb(void *params_, bool val) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -169,7 +157,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns } yajl_callbacks workspaces_callbacks = { - &workspaces_null_cb, + NULL, &workspaces_boolean_cb, &workspaces_integer_cb, NULL, From cee972280d46a27c1f6e5c004aa23f4809cfd9d0 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:10:05 +0200 Subject: [PATCH 025/185] Add comments --- i3bar/include/child.h | 12 ++++ i3bar/include/ipc.h | 16 ++++++ i3bar/include/outputs.h | 31 +++++++--- i3bar/include/workspaces.h | 31 ++++++---- i3bar/include/xcb.h | 39 ++++++++++++- i3bar/src/child.c | 52 ++++++++++++++--- i3bar/src/ipc.c | 54 +++++++++++++++++ i3bar/src/outputs.c | 46 +++++++++++++++ i3bar/src/workspaces.c | 35 +++++++++++ i3bar/src/xcb.c | 115 ++++++++++++++++++++++++++++++++----- 10 files changed, 389 insertions(+), 42 deletions(-) diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 3d3c28c9..5d945235 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -3,7 +3,19 @@ #define STDIN_CHUNK_SIZE 1024 +/* + * Start a child-process with the specified command and reroute stdin. + * We actually start a $SHELL to execute the command so we don't have to care + * about arguments and such + * + */ void start_child(char *command); + +/* + * kill()s the child-prozess (if existend) and closes and + * free()s the stdin- and sigchild-watchers + * + */ void kill_child(); #endif diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index b3760d2a..c9196044 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -3,8 +3,24 @@ #include +/* + * Initiate a connection to i3. + * socket-path must be a valid path to the ipc_socket of i3 + * + */ int init_connection(const char *socket_path); + +/* + * Sends a Message to i3. + * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) + * + */ int i3_send_msg(uint32_t type, const char* payload); + +/* + * Subscribe to all the i3-events, we need + * + */ void subscribe_events(); #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 64fa8563..8a12def4 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -10,23 +10,36 @@ typedef struct i3_output i3_output; SLIST_HEAD(outputs_head, i3_output); struct outputs_head *outputs; +/* + * Start parsing the received json-string + * + */ void parse_outputs_json(char* json); + +/* + * Initiate the output-list + * + */ void init_outputs(); -void free_outputs(); + +/* + * Returns the output with the given name + * + */ i3_output* get_output_by_name(char* name); struct i3_output { - char* name; - bool active; - int ws; - rect rect; + char* name; /* Name of the output */ + bool active; /* If the output is active */ + int ws; /* The number of the currently visible ws */ + rect rect; /* The rect (relative to the root-win) */ - xcb_window_t bar; - xcb_gcontext_t bargc; + xcb_window_t bar; /* The id of the bar of the output */ + xcb_gcontext_t bargc; /* The graphical context of the bar */ - struct ws_head *workspaces; + struct ws_head *workspaces; /* The workspaces on this output */ - SLIST_ENTRY(i3_output) slist; + SLIST_ENTRY(i3_output) slist; /* Pointer for the SLIST-Macro */ }; #endif diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index e32e7c21..1617d0f1 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -9,22 +9,31 @@ typedef struct i3_ws i3_ws; TAILQ_HEAD(ws_head, i3_ws); +/* + * Start parsing the received json-string + * + */ void parse_workspaces_json(); + +/* + * free() all workspace data-structures + * + */ void free_workspaces(); struct i3_ws { - int num; - char *name; - xcb_char2b_t *ucs2_name; - int name_glyphs; - int name_width; - bool visible; - bool focused; - bool urgent; - rect rect; - struct i3_output *output; + int num; /* The internal number of the ws */ + char *name; /* The name (in utf8) of the ws */ + xcb_char2b_t *ucs2_name; /* The name (in ucs2) of the ws */ + int name_glyphs; /* The length (in glyphs) of the name */ + int name_width; /* The rendered width of the name */ + bool visible; /* If the ws is currently visible on an output */ + bool focused; /* If the ws is currently focused */ + bool urgent; /* If the urgent-hint of the ws is set */ + rect rect; /* The rect of the ws (not used (yet)) */ + struct i3_output *output; /* The current output of the ws */ - TAILQ_ENTRY(i3_ws) tailq; + TAILQ_ENTRY(i3_ws) tailq; /* Pointer for the TAILQ-Macro */ }; #endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 7bc76e62..c22b1e43 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -3,12 +3,49 @@ int font_height; +/* + * Initialize xcb and use the specified fontname for text-rendering + * + */ void init_xcb(); + +/* + * Cleanup the xcb-stuff. + * Called once, before the program terminates. + * + */ void clean_xcb(); + +/* + * Get the earlier requested atoms and save them in the prepared data-structure + * + */ void get_atoms(); -void destroy_windows(); + +/* + * Destroy the bar of the specified output + * + */ +void destroy_window(i3_output *output); + +/* + * Reconfigure all bars and create new for newly activated outputs + * + */ void reconfig_windows(); + +/* + * Render the bars, with buttons and statusline + * + */ void draw_bars(); + +/* + * Calculate the rendered width of a string with the configured font. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in width) + * + */ int get_string_width(xcb_char2b_t *string, int glyph_len); #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 362a56d4..b14f873b 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -10,22 +10,33 @@ #include "common.h" -ev_io *child_io; +/* stdin- and sigchild-watchers */ +ev_io *stdin_io; ev_child *child_sig; +/* + * Stop and free() the stdin- and sigchild-watchers + * + */ void cleanup() { - ev_io_stop(main_loop, child_io); + ev_io_stop(main_loop, stdin_io); ev_child_stop(main_loop, child_sig); - FREE(child_io); + FREE(stdin_io); FREE(child_sig); FREE(statusline); } +/* + * Since we don't use colors and stuff, we strip the dzen-formatstrings + * + */ void strip_dzen_formats(char *buffer) { char *src = buffer; char *dest = buffer; while (*src != '\0') { + /* ^ starts a format-string, ) ends it */ if (*src == '^') { + /* We replace the seperators from i3status by pipe-symbols */ if (!strncmp(src, "^ro", strlen("^ro"))) { *(dest++) = ' '; *(dest++) = '|'; @@ -41,10 +52,16 @@ void strip_dzen_formats(char *buffer) { dest++; } } + /* The last character is \n, which xcb cannot display */ *(--dest) = '\0'; } -void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { +/* + * Callbalk for stdin. We read a line from stdin, strip dzen-formats and store + * the result in statusline + * + */ +void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int fd = watcher->fd; int n = 0; int rec = 0; @@ -85,11 +102,25 @@ void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { draw_bars(); } +/* + * We received a sigchild, meaning, that the child-process terminated. + * We simply free the respective data-structures and don't care for input + * anymore + * + */ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { - printf("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus); + printf("Child (pid: %d) unexpectedly exited with status %d\n", + child_pid, + watcher->rstatus); cleanup(); } +/* + * Start a child-process with the specified command and reroute stdin. + * We actually start a $SHELL to execute the command so we don't have to care + * about arguments and such + * + */ void start_child(char *command) { child_pid = 0; if (command != NULL) { @@ -123,9 +154,9 @@ void start_child(char *command) { fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); - child_io = malloc(sizeof(ev_io)); - ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); - ev_io_start(main_loop, child_io); + stdin_io = malloc(sizeof(ev_io)); + ev_io_init(stdin_io, &stdin_io_cb, STDIN_FILENO, EV_READ); + ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ child_sig = malloc(sizeof(ev_io)); @@ -134,6 +165,11 @@ void start_child(char *command) { } +/* + * kill()s the child-prozess (if existend) and closes and + * free()s the stdin- and sigchild-watchers + * + */ void kill_child() { if (child_pid != 0) { kill(child_pid, SIGQUIT); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 83ae4cec..86c61f86 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -13,6 +13,10 @@ ev_io *i3_connection; typedef void(*handler_t)(char*); +/* + * Get a connect to the IPC-interface of i3 and return a filedescriptor + * + */ int get_ipc_fd(const char *socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { @@ -31,21 +35,39 @@ int get_ipc_fd(const char *socket_path) { return sockfd; } +/* + * Called, when we get a reply to a command from i3. + * Since i3 does not give us much feedback on commands, we do not much + * + */ void got_command_reply(char *reply) { /* FIXME: Error handling for command-replies */ } +/* + * Called, when we get a reply with workspaces-data + * + */ void got_workspace_reply(char *reply) { printf("Got Workspace-Data!\n"); parse_workspaces_json(reply); draw_bars(); } +/* + * Called, when we get a reply for a subscription. + * Since i3 does not give us much feedback on commands, we do not much + * + */ void got_subscribe_reply(char *reply) { printf("Got Subscribe Reply: %s\n", reply); /* FIXME: Error handling for subscribe-commands */ } +/* + * Called, when we get a reply with outputs-data + * + */ void got_output_reply(char *reply) { printf("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); @@ -53,6 +75,7 @@ void got_output_reply(char *reply) { reconfig_windows(); } +/* Data-structure to easily call the reply-handlers later */ handler_t reply_handlers[] = { &got_command_reply, &got_workspace_reply, @@ -60,25 +83,40 @@ handler_t reply_handlers[] = { &got_output_reply, }; +/* + * Called, when a workspace-event arrives (i.e. the user changed the workspace) + * + */ void got_workspace_event(char *event) { printf("Got Workspace Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } +/* + * Called, when an output-event arrives (i.e. the screen-configuration changed) + * + */ void got_output_event(char *event) { printf("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } +/* Data-structure to easily call the reply-handlers later */ handler_t event_handlers[] = { &got_workspace_event, &got_output_event }; +/* + * Called, when we get a message from i3 + * + */ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { printf("Got data!\n"); int fd = watcher->fd; + + /* First we only read the header, because we know it's length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { @@ -108,6 +146,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } + /* Know we read the rest of the message */ char *walk = header + strlen(I3_IPC_MAGIC); uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); @@ -133,6 +172,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { } buffer[size] = '\0'; + /* And call the callback (indexed by the type) */ if (type & (1 << 31)) { type ^= 1 << 31; event_handlers[type](buffer); @@ -144,6 +184,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { FREE(buffer); } +/* + * Sends a Message to i3. + * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) + * + */ int i3_send_msg(uint32_t type, const char *payload) { uint32_t len = 0; if (payload != NULL) { @@ -186,6 +231,11 @@ int i3_send_msg(uint32_t type, const char *payload) { return 1; } +/* + * Initiate a connection to i3. + * socket-path must be a valid path to the ipc_socket of i3 + * + */ int init_connection(const char *socket_path) { int sockfd = get_ipc_fd(socket_path); @@ -196,6 +246,10 @@ int init_connection(const char *socket_path) { return 1; } +/* + * Subscribe to all the i3-events, we need + * + */ void subscribe_events() { i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 5fcbd64d..ada297a3 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -6,6 +6,7 @@ #include "common.h" +/* A datatype to pass through the callbacks to save the state */ struct outputs_json_params { struct outputs_head *outputs; i3_output *outputs_walk; @@ -14,10 +15,15 @@ struct outputs_json_params { bool init; }; +/* + * Parse a null-value (current_workspace) + * + */ static int outputs_null_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; if (strcmp(params->cur_key, "current_workspace")) { + /* FIXME: Is this the correct behavior? */ return 0; } @@ -26,6 +32,10 @@ static int outputs_null_cb(void *params_) { return 1; } +/* + * Parse a booleant-value (active) + * + */ static int outputs_boolean_cb(void *params_, bool val) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -40,6 +50,10 @@ static int outputs_boolean_cb(void *params_, bool val) { return 1; } +/* + * Parse an integer (current_workspace or the rect) + * + */ static int outputs_integer_cb(void *params_, long val) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -76,6 +90,10 @@ static int outputs_integer_cb(void *params_, long val) { return 0; } +/* + * Parse a string (name) + * + */ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -94,6 +112,10 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i return 1; } +/* + * We hit the start of a json-map (rect or a new output) + * + */ static int outputs_start_map_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; i3_output *new_output = NULL; @@ -116,8 +138,13 @@ static int outputs_start_map_cb(void *params_) { return 1; } +/* + * We hit the end of a map (rect or a new output) + * + */ static int outputs_end_map_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; + /* FIXME: What is at the end of a rect? */ i3_output *target = get_output_by_name(params->outputs_walk->name); @@ -131,6 +158,12 @@ static int outputs_end_map_cb(void *params_) { return 1; } +/* + * Parse a key. + * + * Essentially we just save it in the parsing-state + * + */ static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); @@ -142,6 +175,7 @@ static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsign return 1; } +/* A datastructure to pass all these callbacks to yajl */ yajl_callbacks outputs_callbacks = { &outputs_null_cb, &outputs_boolean_cb, @@ -156,11 +190,19 @@ yajl_callbacks outputs_callbacks = { NULL }; +/* + * Initiate the output-list + * + */ void init_outputs() { outputs = malloc(sizeof(struct outputs_head)); SLIST_INIT(outputs); } +/* + * Start parsing the received json-string + * + */ void parse_outputs_json(char *json) { struct outputs_json_params params; @@ -191,6 +233,10 @@ void parse_outputs_json(char *json) { yajl_free(handle); } +/* + * Returns the output with the given name + * + */ i3_output *get_output_by_name(char *name) { i3_output *walk; if (name == NULL) { diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index e3efb445..be8a2a41 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -5,6 +5,7 @@ #include "common.h" +/* A datatype to pass through the callbacks to save the state */ struct workspaces_json_params { struct ws_head *workspaces; i3_ws *workspaces_walk; @@ -12,6 +13,10 @@ struct workspaces_json_params { char *json; }; +/* + * Parse a booleant-value (visible, focused, urgent) + * + */ static int workspaces_boolean_cb(void *params_, bool val) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -38,6 +43,10 @@ static int workspaces_boolean_cb(void *params_, bool val) { return 0; } +/* + * Parse an integer (num or the rect) + * + */ static int workspaces_integer_cb(void *params_, long val) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -75,6 +84,10 @@ static int workspaces_integer_cb(void *params_, long val) { return 0; } +/* + * Parse a string (name, output) + * + */ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -82,10 +95,12 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne char *output_name; if (!strcmp(params->cur_key, "name")) { + /* Save the name */ params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(params->workspaces_walk->name, (const char*) val, len); params->workspaces_walk->name[len] = '\0'; + /* Convert the name to ucs2, save it's length in glyphs and calculate it'srendered width */ int ucs2_len; xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len); params->workspaces_walk->ucs2_name = ucs2_name; @@ -103,6 +118,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne } if (!strcmp(params->cur_key, "output")) { + /* We add the ws to the TAILQ of the output, it belongs to */ output_name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(output_name, (const char*) val, len); output_name[len] = '\0'; @@ -119,6 +135,10 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne return 0; } +/* + * We hit the start of a json-map (rect or a new output) + * + */ static int workspaces_start_map_cb(void *params_) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -141,6 +161,12 @@ static int workspaces_start_map_cb(void *params_) { return 1; } +/* + * Parse a key. + * + * Essentially we just save it in the parsing-state + * + */ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; FREE(params->cur_key); @@ -156,6 +182,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns return 1; } +/* A datastructure to pass all these callbacks to yajl */ yajl_callbacks workspaces_callbacks = { NULL, &workspaces_boolean_cb, @@ -170,6 +197,10 @@ yajl_callbacks workspaces_callbacks = { NULL }; +/* + * Start parsing the received json-string + * + */ void parse_workspaces_json(char *json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ @@ -206,6 +237,10 @@ void parse_workspaces_json(char *json) { FREE(params.cur_key); } +/* + * free() all workspace data-structures + * + */ void free_workspaces() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 75011dac..21d7df39 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -9,6 +9,7 @@ #include "common.h" +/* We save the Atoms in an easy to access array, indexed by an enum */ #define NUM_ATOMS 3 enum { @@ -19,17 +20,22 @@ enum { xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; xcb_atom_t atoms[NUM_ATOMS]; +/* Variables, that are the same for all functions at all times */ xcb_connection_t *xcb_connection; xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +/* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; -xcb_event_handlers_t xcb_event_handlers; - +/* + * Converts a colorstring to a colorpixel as expected from xcb_change_gc. + * s is assumed to be in the format "rrggbb" + * + */ uint32_t get_colorpixel(const char *s) { char strings[3][3] = { { s[0], s[1], '\0'} , { s[2], s[3], '\0'} , @@ -40,8 +46,16 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Handle a button-press-event (i.c. a mouse click on one of our bars). + * We determine, wether the click occured on a ws-button or if the scroll- + * wheel was used and change the workspace appropriately + * + */ void handle_button(xcb_button_press_event_t *event) { i3_ws *cur_ws; + + /* Determine, which bar was clicked */ i3_output *walk; xcb_window_t bar = event->event; SLIST_FOREACH(walk, outputs, slist) { @@ -55,6 +69,7 @@ void handle_button(xcb_button_press_event_t *event) { return; } + /* TODO: Move this to exern get_ws_for_output() */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { if (cur_ws->visible) { break; @@ -72,6 +87,8 @@ void handle_button(xcb_button_press_event_t *event) { switch (event->detail) { case 1: + /* Left Mousbutton. We determine, which button was clicked + * and set cur_ws accordingly */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { printf("x = %d\n", x); if (x < cur_ws->name_width + 10) { @@ -84,17 +101,19 @@ void handle_button(xcb_button_press_event_t *event) { } break; case 4: - if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { - cur_ws = TAILQ_FIRST(walk->workspaces); + /* Mouse wheel down. We select the next ws */ + if (cur_ws == TAILQ_FIRST(walk->workspaces, ws_head)) { + cur_ws = TAILQ_LAST(walk->workspaces); } else { - cur_ws = TAILQ_NEXT(cur_ws, tailq); + cur_ws = TAILQ_PREV(cur_ws, tailq); } break; case 5: - if (cur_ws == TAILQ_FIRST(walk->workspaces)) { - cur_ws = TAILQ_LAST(walk->workspaces, ws_head); + /* Mouse wheel up. We select the previos ws */ + if (cur_ws == TAILQ_LAST(walk->workspaces)) { + cur_ws = TAILQ_FIRST(walk->workspaces, ws_head); } else { - cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); + cur_ws = TAILQ_NEXT(cur_ws, ws_head, tailq); } break; } @@ -104,21 +123,42 @@ void handle_button(xcb_button_press_event_t *event) { i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); } +/* + * An X-Event occured, we determine, what kind and call the appropriate handler + * + * FIXME: Merge this in ev_chk_cb(), the additional call is superflous + * + */ void handle_xcb_event(xcb_generic_event_t *event) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: + /* Expose-events happen, when the window needs to be redrawn */ draw_bars(); break; case XCB_BUTTON_PRESS: + /* Button-press-events are mouse-buttons clicked on one of our bars */ handle_button((xcb_button_press_event_t*) event); break; } } +/* + * This function is called immediately bevor the main loop locks. We flush xcb + * then (and only then) + * + */ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { xcb_flush(xcb_connection); } +/* + * This function is called immediately after the main loop locks, so when one + * of the watchers registered an event. + * We check wether an X-Event arrived and handle it. + * + * FIXME: use a while-loop, to account for the xcb buffer + * + */ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { xcb_generic_event_t *event; if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { @@ -127,11 +167,20 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { FREE(event); } +/* + * Dummy Callback. We only need this, so that the Prepare- and Check-Watchers + * are triggered + * + */ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { - /* Dummy Callback. We only need this, so that xcb-events trigger - * Prepare- and Check-Watchers */ } +/* + * Calculate the rendered width of a string with the configured font. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in width) + * + */ int get_string_width(xcb_char2b_t *string, int glyph_len) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; @@ -139,7 +188,8 @@ int get_string_width(xcb_char2b_t *string, int glyph_len) { int width; cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); - if ((reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { + reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); + if (reply == NULL) { printf("ERROR: Could not get text extents!"); return 7; } @@ -149,6 +199,10 @@ int get_string_width(xcb_char2b_t *string, int glyph_len) { return width; } +/* + * Initialize xcb and use the specified fontname for text-rendering + * + */ void init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); @@ -160,30 +214,35 @@ void init_xcb(char *fontname) { /* We have to request the atoms we need */ #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); - #include "xcb_atoms.def" + #include "xcb_atoms.def" xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; xcb_root = xcb_screens->root; + /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); xcb_open_font(xcb_connection, xcb_font, strlen(fontname), fontname); + /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t cookie; cookie = xcb_list_fonts_with_info(xcb_connection, 1, strlen(fontname), fontname); + /* FIXME: push this to the end of init_xcb() */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, cookie, NULL); font_height = reply->font_ascent + reply->font_descent; FREE(reply); + printf("Calculated Font-height: %d\n", font_height); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); @@ -196,11 +255,17 @@ void init_xcb(char *fontname) { ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); - /* FIXME: Maybe we can push that further backwards */ + /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); } +/* + * Cleanup the xcb-stuff. + * Called once, before the program terminates. + * + */ void clean_xcb() { + /* FIXME: destroy() the bars first */ xcb_disconnect(xcb_connection); ev_check_stop(main_loop, xcb_chk); @@ -212,6 +277,10 @@ void clean_xcb() { FREE(xcb_io); } +/* + * Get the earlier requested atoms and save them in the prepared data-structure + * + */ void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ @@ -222,6 +291,10 @@ void get_atoms() { printf("Got Atoms\n"); } +/* + * Destroy the bar of the specified output + * + */ void destroy_window(i3_output *output) { if (output == NULL) { return; @@ -233,6 +306,10 @@ void destroy_window(i3_output *output) { output->bar = XCB_NONE; } +/* + * Reconfigure all bars and create new for newly activated outputs + * + */ void reconfig_windows() { uint32_t mask; uint32_t values[4]; @@ -240,6 +317,8 @@ void reconfig_windows() { i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { + /* If an output is not active, we destroy it's bar */ + /* FIXME: Maybe we rather want to unmap? */ printf("Destroying window for output %s\n", walk->name); destroy_window(walk); continue; @@ -249,7 +328,9 @@ void reconfig_windows() { walk->bar = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + /* Black background */ values[0] = xcb_screens->black_pixel; + /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; xcb_create_window(xcb_connection, @@ -264,6 +345,7 @@ void reconfig_windows() { mask, values); + /* We want dock-windows (for now) */ xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, walk->bar, @@ -273,6 +355,7 @@ void reconfig_windows() { 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; @@ -282,8 +365,10 @@ void reconfig_windows() { mask, values); + /* We finally map the bar (display it on screen) */ xcb_map_window(xcb_connection, walk->bar); } else { + /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | @@ -301,6 +386,10 @@ void reconfig_windows() { } } +/* + * Render the bars, with buttons and statusline + * + */ void draw_bars() { printf("Drawing Bars...\n"); int i = 0; From 188d4c18cc7070d98781ebb762a61e4f5b136b3d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:19:25 +0200 Subject: [PATCH 026/185] Merge handle_xcb_event() into xcb_chk_cb() --- i3bar/src/xcb.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 21d7df39..2b339412 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -123,25 +123,6 @@ void handle_button(xcb_button_press_event_t *event) { i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); } -/* - * An X-Event occured, we determine, what kind and call the appropriate handler - * - * FIXME: Merge this in ev_chk_cb(), the additional call is superflous - * - */ -void handle_xcb_event(xcb_generic_event_t *event) { - switch (event->response_type & ~0x80) { - case XCB_EXPOSE: - /* Expose-events happen, when the window needs to be redrawn */ - draw_bars(); - break; - case XCB_BUTTON_PRESS: - /* Button-press-events are mouse-buttons clicked on one of our bars */ - handle_button((xcb_button_press_event_t*) event); - break; - } -} - /* * This function is called immediately bevor the main loop locks. We flush xcb * then (and only then) @@ -161,8 +142,19 @@ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { */ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { xcb_generic_event_t *event; - if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { - handle_xcb_event(event); + if ((event = xcb_poll_for_event(xcb_connection)) == NULL) { + return; + } + + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: + /* Expose-events happen, when the window needs to be redrawn */ + draw_bars(); + break; + case XCB_BUTTON_PRESS: + /* Button-press-events are mouse-buttons clicked on one of our bars */ + handle_button((xcb_button_press_event_t*) event); + break; } FREE(event); } From 6780d87593a6fd443ad7799015e9af3c595db723 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:20:01 +0200 Subject: [PATCH 027/185] Use a while-loop in xcb_chk_cb() to account for the xcb-buffer --- i3bar/src/xcb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 2b339412..055775fb 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -137,12 +137,10 @@ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { * of the watchers registered an event. * We check wether an X-Event arrived and handle it. * - * FIXME: use a while-loop, to account for the xcb buffer - * */ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { xcb_generic_event_t *event; - if ((event = xcb_poll_for_event(xcb_connection)) == NULL) { + while ((event = xcb_poll_for_event(xcb_connection)) == NULL) { return; } From dcbf0c71d274e890fbc1ee8d9376eaf9b1d4e677 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:22:20 +0200 Subject: [PATCH 028/185] Move font-height-calculation to the end of init_xcb() --- i3bar/src/xcb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 055775fb..bdb1b5f5 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -222,15 +222,6 @@ void init_xcb(char *fontname) { 1, strlen(fontname), fontname); - /* FIXME: push this to the end of init_xcb() */ - xcb_list_fonts_with_info_reply_t *reply; - reply = xcb_list_fonts_with_info_reply(xcb_connection, - cookie, - NULL); - font_height = reply->font_ascent + reply->font_descent; - FREE(reply); - - printf("Calculated Font-height: %d\n", font_height); /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); @@ -247,6 +238,16 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); + + /* Now we calculate the font-height */ + xcb_list_fonts_with_info_reply_t *reply; + reply = xcb_list_fonts_with_info_reply(xcb_connection, + cookie, + NULL); + font_height = reply->font_ascent + reply->font_descent; + FREE(reply); + + printf("Calculated Font-height: %d\n", font_height); } /* From c03e8501716ea22f5735df02d8e45040e391f8fd Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:34:02 +0200 Subject: [PATCH 029/185] Correct the Macro-calls in src/xcb.c --- i3bar/src/xcb.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index bdb1b5f5..dd19feaf 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -102,18 +102,18 @@ void handle_button(xcb_button_press_event_t *event) { break; case 4: /* Mouse wheel down. We select the next ws */ - if (cur_ws == TAILQ_FIRST(walk->workspaces, ws_head)) { - cur_ws = TAILQ_LAST(walk->workspaces); + if (cur_ws == TAILQ_FIRST(walk->workspaces)) { + cur_ws = TAILQ_LAST(walk->workspaces, ws_head); } else { - cur_ws = TAILQ_PREV(cur_ws, tailq); + cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); } break; case 5: /* Mouse wheel up. We select the previos ws */ - if (cur_ws == TAILQ_LAST(walk->workspaces)) { - cur_ws = TAILQ_FIRST(walk->workspaces, ws_head); + if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { + cur_ws = TAILQ_FIRST(walk->workspaces); } else { - cur_ws = TAILQ_NEXT(cur_ws, ws_head, tailq); + cur_ws = TAILQ_NEXT(cur_ws, tailq); } break; } @@ -256,7 +256,12 @@ void init_xcb(char *fontname) { * */ void clean_xcb() { - /* FIXME: destroy() the bars first */ + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { + destroy_window(walk); + } + FREE_SLIST(outputs, i3_output); + xcb_disconnect(xcb_connection); ev_check_stop(main_loop, xcb_chk); From e7ba3183df602975f79eb04584327ad2b1887581 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:37:12 +0200 Subject: [PATCH 030/185] Correct behaviour of parsing null-values in src/outputs.c --- i3bar/src/outputs.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index ada297a3..0f035ac0 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -22,11 +22,6 @@ struct outputs_json_params { static int outputs_null_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; - if (strcmp(params->cur_key, "current_workspace")) { - /* FIXME: Is this the correct behavior? */ - return 0; - } - FREE(params->cur_key); return 1; From 04e2cd1dfea4c59924acbe4fa17d6c7da1c966e9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 03:50:22 +0200 Subject: [PATCH 031/185] Add version-option --- i3bar/Makefile | 7 +++++++ i3bar/common.mk | 19 +++++++++++++++++++ i3bar/src/main.c | 6 +++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index 172a442d..57af15e1 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -14,5 +14,12 @@ src/%.o: src/%.c ${HEADERS} echo "CC $<" $(CC) $(CFLAGS) -c -o $@ $< +install: all + echo "INSTALL" + $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin + $(INSTALL) -m 0755 i3bar $(DESTDIR)$(PREFIX)/bin + clean: rm src/*.o + +.PHONY: install clean diff --git a/i3bar/common.mk b/i3bar/common.mk index e2be3aab..65588314 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -1,9 +1,28 @@ +INSTALL=install +DEBUG=1 +PREFIX=/usr + +# The escaping is absurd, but we need to escape for shell, sed, make, define +GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1), branch $(shell [ -f .git/HEAD ] && sed 's/ref: refs\/heads\/\(.*\)/\\\\\\"\1\\\\\\"/g' .git/HEAD || echo 'unknown'))" + CFLAGS += -Wall CFLAGS += -pipe CFLAGS += -Iinclude CFLAGS += -g +CFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" + LDFLAGS += -lev LDFLAGS += -lyajl LDFLAGS += -lxcb LDFLAGS += -lxcb-atom +LDFLAGS += -L/usr/local/lib + +ifeq ($(DEBUG),1) +CFLAGS += -g3 +else +CFLAGS += -O2 +endif + .SILENT: + +.PHONY: install clean diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 4cb2fcb2..909106b3 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -39,10 +39,11 @@ int main(int argc, char **argv) { { "command", required_argument, 0, 'c' }, { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:f:h", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:f:hv", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -53,6 +54,9 @@ int main(int argc, char **argv) { case 'f': fontname = strdup(optarg); break; + case 'v': + printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); + exit(EXIT_SUCCESS); default: printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); printf("-s : Connect to i3 via \n"); From 60da522e13134c46d406fedad095e393f482d797 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 18:05:16 +0200 Subject: [PATCH 032/185] Add licensing information --- i3bar/LICENSE | 27 +++++++++++++++++++++++++++ i3bar/include/child.h | 8 ++++++++ i3bar/include/common.h | 8 ++++++++ i3bar/include/ipc.h | 8 ++++++++ i3bar/include/outputs.h | 8 ++++++++ i3bar/include/util.h | 8 ++++++++ i3bar/include/workspaces.h | 8 ++++++++ i3bar/include/xcb.h | 8 ++++++++ i3bar/src/child.c | 10 ++++++++++ i3bar/src/ipc.c | 10 ++++++++++ i3bar/src/main.c | 8 ++++++++ i3bar/src/outputs.c | 10 ++++++++++ i3bar/src/workspaces.c | 10 ++++++++++ i3bar/src/xcb.c | 10 ++++++++++ 14 files changed, 141 insertions(+) create mode 100644 i3bar/LICENSE diff --git a/i3bar/LICENSE b/i3bar/LICENSE new file mode 100644 index 00000000..4fe52a0c --- /dev/null +++ b/i3bar/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2010, Axel Wagner +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Axel Wagner nor the + names of contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY Axel Wagner ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Axel Wagner BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 5d945235..0405816d 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef CHILD_H_ #define CHILD_H_ diff --git a/i3bar/include/common.h b/i3bar/include/common.h index b77ac8ea..d6b63a7e 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef COMMON_H_ #define COMMON_H_ diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index c9196044..0eba64fa 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef IPC_H_ #define IPC_H_ diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 8a12def4..837aa50b 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef OUTPUTS_H_ #define OUTPUTS_H_ diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 08bdc335..0f5dd3e3 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef UTIL_H_ #define UTIL_H_ diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 1617d0f1..64da21a7 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef WORKSPACES_H_ #define WORKSPACES_H_ diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index c22b1e43..af2c8933 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #ifndef XCB_H_ #define XCB_H_ diff --git a/i3bar/src/child.c b/i3bar/src/child.c index b14f873b..2b0fb780 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -1,3 +1,13 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + * src/child.c: Getting Input for the statusline + * + */ #include #include #include diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 86c61f86..59563636 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -1,3 +1,13 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + * src/ipc.c: Communicating with i3 + * + */ #include #include #include diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 909106b3..45a4c0dc 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -1,3 +1,11 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + */ #include #include #include diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 0f035ac0..de905783 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -1,3 +1,13 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + * src/outputs.c: Maintaining the output-list + * + */ #include #include #include diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index be8a2a41..8ba79eec 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -1,3 +1,13 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + * src/workspaces.c: Maintaining the workspace-lists + * + */ #include #include #include diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index dd19feaf..ae1c8278 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1,3 +1,13 @@ +/* + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010 Axel Wagner and contributors + * + * See file LICNSE for license information + * + * src/xcb.c: Communicating with X + * + */ #include #include #include From ddf8bd63c7cb8fb59c8e3c50f3885ce02283bbf4 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 18 Aug 2010 03:58:32 +0200 Subject: [PATCH 033/185] Added some error handling for xcb --- i3bar/src/xcb.c | 109 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ae1c8278..a11a4e9a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -184,14 +184,14 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int get_string_width(xcb_char2b_t *string, int glyph_len) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; - xcb_generic_error_t *error; + xcb_generic_error_t *error = NULL; int width; cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); - if (reply == NULL) { - printf("ERROR: Could not get text extents!"); - return 7; + if (error != NULL) { + printf("ERROR: Could not get text extents! XCB-errorcode: %d\n", error->error_code); + exit(EXIT_FAILURE); } width = reply->overall_width; @@ -221,17 +221,26 @@ void init_xcb(char *fontname) { /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); - xcb_open_font(xcb_connection, - xcb_font, - strlen(fontname), - fontname); + xcb_void_cookie_t open_font_cookie; + open_font_cookie = xcb_open_font_checked(xcb_connection, + xcb_font, + strlen(fontname), + fontname); + + xcb_generic_error_t *err = xcb_request_check(xcb_connection, + open_font_cookie); + + if (err != NULL) { + printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We also need the fontheight to configure our bars accordingly */ - xcb_list_fonts_with_info_cookie_t cookie; - cookie = xcb_list_fonts_with_info(xcb_connection, - 1, - strlen(fontname), - fontname); + xcb_list_fonts_with_info_cookie_t font_info_cookie; + font_info_cookie = xcb_list_fonts_with_info(xcb_connection, + 1, + strlen(fontname), + fontname); /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); @@ -252,7 +261,7 @@ void init_xcb(char *fontname) { /* Now we calculate the font-height */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, - cookie, + font_info_cookie, NULL); font_height = reply->font_ascent + reply->font_descent; FREE(reply); @@ -290,6 +299,10 @@ void clean_xcb() { void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ + if (reply == NULL) { \ + printf("ERROR: Could not get atom %s\n", #name); \ + exit(EXIT_FAILURE); \ + } \ atoms[name] = reply->atom; \ free(reply); @@ -320,6 +333,9 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { @@ -339,17 +355,21 @@ void reconfig_windows() { /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - xcb_create_window(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); + cookie = xcb_create_window_checked(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We want dock-windows (for now) */ xcb_change_property(xcb_connection, @@ -360,19 +380,33 @@ void reconfig_windows() { 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; - xcb_create_gc(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We finally map the bar (display it on screen) */ - xcb_map_window(xcb_connection, walk->bar); + cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } else { /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | @@ -384,10 +418,15 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); - xcb_configure_window(xcb_connection, - walk->bar, - mask, - values); + cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } } } From 84d7da0acf39f4aeb79c2bd21683e5d5cf58a172 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 19 Aug 2010 22:13:40 +0200 Subject: [PATCH 034/185] Correct typo in usage-message --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 45a4c0dc..75f21382 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) { default: printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); printf("-s : Connect to i3 via \n"); - printf("-c : Execute to get sdtin\n"); + printf("-c : Execute to get stdin\n"); printf("-f : Use X-Core-Font for display\n"); printf("-h: Display this help-message and exit\n"); exit(EXIT_SUCCESS); From 5015cdc4d038cc09cde906b20879cec68c556842 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:09:34 +0200 Subject: [PATCH 035/185] Implement double-buffering to get rid of flickering --- i3bar/include/outputs.h | 1 + i3bar/src/xcb.c | 151 +++++++++++++++++++++++++--------------- 2 files changed, 96 insertions(+), 56 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 837aa50b..69a34a12 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -43,6 +43,7 @@ struct i3_output { rect rect; /* The rect (relative to the root-win) */ xcb_window_t bar; /* The id of the bar of the output */ + xcb_pixmap_t buffer; /* An extra pixmap for double-buffering */ xcb_gcontext_t bargc; /* The graphical context of the bar */ struct ws_head *workspaces; /* The workspaces on this output */ diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a11a4e9a..02e9d392 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -227,14 +227,6 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - xcb_generic_error_t *err = xcb_request_check(xcb_connection, - open_font_cookie); - - if (err != NULL) { - printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t font_info_cookie; font_info_cookie = xcb_list_fonts_with_info(xcb_connection, @@ -258,6 +250,14 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); + xcb_generic_error_t *err = xcb_request_check(xcb_connection, + open_font_cookie); + + if (err != NULL) { + printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + /* Now we calculate the font-height */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, @@ -333,7 +333,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; - xcb_void_cookie_t cookie; xcb_generic_error_t *err; i3_output *walk; @@ -349,61 +348,77 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); + walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - cookie = xcb_create_window_checked(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + + xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); /* We want dock-windows (for now) */ - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; - cookie = xcb_create_gc_checked(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + /* We finally map the bar (display it on screen) */ + xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, win_cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, prop_cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, gc_cookie)) != NULL) { printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } - /* We finally map the bar (display it on screen) */ - cookie = xcb_map_window_checked(xcb_connection, walk->bar); - - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + if ((err = xcb_request_check(xcb_connection, map_cookie)) != NULL) { printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } @@ -418,16 +433,31 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); - cookie = xcb_configure_window_checked(xcb_connection, - walk->bar, - mask, - values); + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + xcb_free_pixmap(xcb_connection, walk->buffer); + walk->buffer = xcb_generate_id(xcb_connection); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); + + if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } - } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + } } } @@ -454,7 +484,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -476,7 +506,7 @@ void draw_bars() { xcb_void_cookie_t cookie; cookie = xcb_image_text_16(xcb_connection, glyph_count, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, font_height + 1, @@ -509,7 +539,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -520,13 +550,22 @@ void draw_bars() { &color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, i + 5, font_height + 1, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } + xcb_copy_area(xcb_connection, + outputs_walk->buffer, + outputs_walk->bar, + outputs_walk->bargc, + 0, 0, + 0, 0, + outputs_walk->rect.w, + outputs_walk->rect.h); + i = 0; } } From fe24eb748c98c8dea36dc0da5948ea118771215b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:09:34 +0200 Subject: [PATCH 036/185] Implement double-buffering to get rid of flickering --- i3bar/include/outputs.h | 1 + i3bar/src/xcb.c | 150 ++++++++++++++++++++++++++++++---------- 2 files changed, 113 insertions(+), 38 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 837aa50b..69a34a12 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -43,6 +43,7 @@ struct i3_output { rect rect; /* The rect (relative to the root-win) */ xcb_window_t bar; /* The id of the bar of the output */ + xcb_pixmap_t buffer; /* An extra pixmap for double-buffering */ xcb_gcontext_t bargc; /* The graphical context of the bar */ struct ws_head *workspaces; /* The workspaces on this output */ diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ae1c8278..ed578700 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -221,10 +221,11 @@ void init_xcb(char *fontname) { /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); - xcb_open_font(xcb_connection, - xcb_font, - strlen(fontname), - fontname); + xcb_void_cookie_t open_font_cookie; + open_font_cookie = xcb_open_font_checked(xcb_connection, + xcb_font, + strlen(fontname), + fontname); /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t cookie; @@ -249,6 +250,14 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); + xcb_generic_error_t *err = xcb_request_check(xcb_connection, + open_font_cookie); + + if (err != NULL) { + printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + /* Now we calculate the font-height */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, @@ -333,46 +342,81 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); + walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - xcb_create_window(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); + + xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); /* We want dock-windows (for now) */ - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; - xcb_create_gc(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + + xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); /* We finally map the bar (display it on screen) */ - xcb_map_window(xcb_connection, walk->bar); + xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, win_cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, prop_cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, gc_cookie)) != NULL) { + printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, map_cookie)) != NULL) { + printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } else { /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | @@ -384,11 +428,32 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); - xcb_configure_window(xcb_connection, - walk->bar, - mask, - values); - } + + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); + + xcb_free_pixmap(xcb_connection, walk->buffer); + walk->buffer = xcb_generate_id(xcb_connection); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); + + if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { + printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + } } } @@ -415,7 +480,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -437,7 +502,7 @@ void draw_bars() { xcb_void_cookie_t cookie; cookie = xcb_image_text_16(xcb_connection, glyph_count, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, font_height + 1, @@ -470,7 +535,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -481,13 +546,22 @@ void draw_bars() { &color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, i + 5, font_height + 1, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } + xcb_copy_area(xcb_connection, + outputs_walk->buffer, + outputs_walk->bar, + outputs_walk->bargc, + 0, 0, + 0, 0, + outputs_walk->rect.w, + outputs_walk->rect.h); + i = 0; } } From 6ad922dbd5562903e28780bb1913683b36c1427a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:29:38 +0200 Subject: [PATCH 037/185] Add declaration, accidentally lost in last commit --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ed578700..7f6379e1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -329,6 +329,8 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; + xcb_generic_error_t *err; + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { From 14b885adf19be199a79c55bd30cbfcd8b569bc2a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 22 Aug 2010 10:24:32 +0200 Subject: [PATCH 038/185] Only copy the double-buffer on expose-events --- i3bar/include/xcb.h | 6 ++++++ i3bar/src/xcb.c | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index af2c8933..2e4b16a8 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -48,6 +48,12 @@ void reconfig_windows(); */ void draw_bars(); +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars(); + /* * Calculate the rendered width of a string with the configured font. * The string has to be encoded in ucs2 and glyph_len has to be the length diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 02e9d392..15e11faa 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -157,7 +157,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: /* Expose-events happen, when the window needs to be redrawn */ - draw_bars(); + redraw_bars(); break; case XCB_BUTTON_PRESS: /* Button-press-events are mouse-buttons clicked on one of our bars */ @@ -569,3 +569,22 @@ void draw_bars() { i = 0; } } + +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars() { + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + xcb_copy_area(xcb_connection, + outputs_walk->buffer, + outputs_walk->bar, + outputs_walk->bargc, + 0, 0, + 0, 0, + outputs_walk->rect.w, + outputs_walk->rect.h); + xcb_flush(xcb_connection); + } +} From bef80146e605b5d2c2d36641ff5fcd7b94087ee1 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 24 Aug 2010 14:01:48 +0200 Subject: [PATCH 039/185] Don't manually strip dzen-formats. Instead "output_format = none" should be used in the i3status-config --- i3bar/src/child.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..9b4e9aa0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -37,38 +37,8 @@ void cleanup() { } /* - * Since we don't use colors and stuff, we strip the dzen-formatstrings - * - */ -void strip_dzen_formats(char *buffer) { - char *src = buffer; - char *dest = buffer; - while (*src != '\0') { - /* ^ starts a format-string, ) ends it */ - if (*src == '^') { - /* We replace the seperators from i3status by pipe-symbols */ - if (!strncmp(src, "^ro", strlen("^ro"))) { - *(dest++) = ' '; - *(dest++) = '|'; - *(dest++) = ' '; - } - while (*src != ')') { - src++; - } - src++; - } else { - *dest = *src; - src++; - dest++; - } - } - /* The last character is \n, which xcb cannot display */ - *(--dest) = '\0'; -} - -/* - * Callbalk for stdin. We read a line from stdin, strip dzen-formats and store - * the result in statusline + * Callbalk for stdin. We read a line from stdin and store the result + * in statusline * */ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { @@ -105,7 +75,6 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { FREE(buffer); return; } - strip_dzen_formats(buffer); FREE(statusline); statusline = buffer; printf("%s\n", buffer); From 6034eee6474b3f906e28d16d117a149e42441bd5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 04:58:28 +0200 Subject: [PATCH 040/185] Remove trailing newline from stdin --- i3bar/src/child.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 9b4e9aa0..054c007f 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -52,6 +52,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { n = read(fd, buffer + rec, buffer_len - rec); if (n == -1) { if (errno == EAGAIN) { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; break; } printf("ERROR: read() failed!"); @@ -66,6 +68,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer_len += STDIN_CHUNK_SIZE; FREE(tmp); } else { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; break; } } From 53ec74a4ab6eff4958938bd9aea5ab5a3120ca96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 16:23:30 +0200 Subject: [PATCH 041/185] Implement hide-on-modifier --- i3bar/common.mk | 1 + i3bar/src/xcb.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/i3bar/common.mk b/i3bar/common.mk index 65588314..1df1f6fb 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -15,6 +15,7 @@ LDFLAGS += -lev LDFLAGS += -lyajl LDFLAGS += -lxcb LDFLAGS += -lxcb-atom +LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib ifeq ($(DEBUG),1) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a11a4e9a..45ed79cc 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -13,10 +13,16 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include + #include "common.h" /* We save the Atoms in an easy to access array, indexed by an enum */ @@ -36,10 +42,15 @@ xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +Display *xkb_dpy; +int xkb_event_base; +int mod_pressed; + /* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; +ev_io *xkb_io; /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. @@ -56,6 +67,54 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Hides all bars (unmaps them) + * + */ +void hide_bars() { + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { + xcb_unmap_window(xcb_connection, walk->bar); + } +} + +/* + * Unhides all bars (maps them) + * + */ +void unhide_bars() { + i3_output *walk; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + uint32_t mask; + uint32_t values[4]; + + SLIST_FOREACH(walk, outputs, slist) { + if (walk->bar == XCB_NONE) { + continue; + } + mask = XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT; + values[0] = walk->rect.x; + values[1] = walk->rect.y + walk->rect.h - font_height - 6; + values[2] = walk->rect.w; + values[3] = font_height + 6; + printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); + cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + xcb_map_window(xcb_connection, walk->bar); + } +} + /* * Handle a button-press-event (i.c. a mouse click on one of our bars). * We determine, wether the click occured on a ws-button or if the scroll- @@ -175,6 +234,45 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } +/* + * We need to bind to the modifier per XKB. Sadly, XCB does not implement this + * + */ +void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { + XkbEvent ev; + int modstate; + + printf("Got XKB-Event!\n"); + + while (XPending(xkb_dpy)) { + XNextEvent(xkb_dpy, (XEvent*)&ev); + + if (ev.type != xkb_event_base) { + printf("ERROR: No Xkb-Event!\n"); + continue; + } + + if (ev.any.xkb_type != XkbStateNotify) { + printf("ERROR: No State Notify!\n"); + continue; + } + + unsigned int mods = ev.state.mods; + modstate = mods & Mod4Mask; + } + + if (modstate != mod_pressed) { + if (modstate == 0) { + printf("Mod4 got released!\n"); + hide_bars(); + } else { + printf("Mod4 got pressed!\n"); + unhide_bars(); + } + mod_pressed = modstate; + } +} + /* * Calculate the rendered width of a string with the configured font. * The string has to be encoded in ucs2 and glyph_len has to be the length @@ -242,18 +340,55 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); + int xkb_major, xkb_minor, xkb_errbase, xkb_err; + xkb_major = XkbMajorVersion; + xkb_minor = XkbMinorVersion; + + xkb_dpy = XkbOpenDisplay(":0", + &xkb_event_base, + &xkb_errbase, + &xkb_major, + &xkb_minor, + &xkb_err); + + if (xkb_dpy == NULL) { + printf("ERROR: No XKB!\n"); + exit(EXIT_FAILURE); + } + + if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { + fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); + exit(EXIT_FAILURE); + } + + int i1; + if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { + printf("ERROR: XKB not supported by X-server!\n"); + exit(EXIT_FAILURE); + } + + if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { + printf("Could not grab Key!\n"); + exit(EXIT_FAILURE); + } + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); + xkb_io = malloc(sizeof(ev_io)); ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); ev_prepare_init(xcb_prep, &xcb_prep_cb); ev_check_init(xcb_chk, &xcb_chk_cb); + ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); ev_io_start(main_loop, xcb_io); ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); + ev_io_start(main_loop, xkb_io); + + XFlush(xkb_dpy); /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); From 3c1a6384ab024d33c089219c4384633bb78daed0 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 18:23:33 +0200 Subject: [PATCH 042/185] Define overrride-redirect The bars should not be in dockmode, when hide-on-mod is active --- i3bar/src/xcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 45ed79cc..9494b389 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -484,11 +484,13 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; + /* i3 is not supposed to manage our bar-windows */ + values[1] = 1; /* The events we want to receive */ - values[1] = XCB_EVENT_MASK_EXPOSURE | + values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; cookie = xcb_create_window_checked(xcb_connection, xcb_screens->root_depth, From a83e7699e75cad515019aa1ad5f7d59ee236a918 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 18:31:03 +0200 Subject: [PATCH 043/185] Send the child SIGSTOPs and SIGCONTs --- i3bar/include/child.h | 12 ++++++++++++ i3bar/src/child.c | 22 +++++++++++++++++++++- i3bar/src/xcb.c | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 0405816d..69cfc576 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -26,4 +26,16 @@ void start_child(char *command); */ void kill_child(); +/* + * Sends a SIGSTOP to the child-process (if existent) + * + */ +void stop_child(); + +/* + * Sends a SIGCONT to the child-process (if existent) + * + */ +void cont_child(); + #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..4be5d12d 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -176,7 +176,7 @@ void start_child(char *command) { } /* - * kill()s the child-prozess (if existend) and closes and + * kill()s the child-process (if existent) and closes and * free()s the stdin- and sigchild-watchers * */ @@ -186,3 +186,23 @@ void kill_child() { } cleanup(); } + +/* + * Sends a SIGSTOP to the child-process (if existent) + * + */ +void stop_child() { + if (child_pid != 0) { + kill(child_pid, SIGSTOP); + } +} + +/* + * Sends a SIGCONT to the child-process (if existent) + * + */ +void cont_child() { + if (child_pid != 0) { + kill(child_pid, SIGCONT); + } +} diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 9494b389..f5a50686 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -76,6 +76,7 @@ void hide_bars() { SLIST_FOREACH(walk, outputs, slist) { xcb_unmap_window(xcb_connection, walk->bar); } + stop_child(); } /* @@ -89,6 +90,8 @@ void unhide_bars() { uint32_t mask; uint32_t values[4]; + cont_child(); + SLIST_FOREACH(walk, outputs, slist) { if (walk->bar == XCB_NONE) { continue; From 701448c342b08b7517fb9700211cb4d53e307609 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 21:50:01 +0200 Subject: [PATCH 044/185] Unhide on urgent-hint --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f5a50686..a974ead9 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -638,6 +638,8 @@ void draw_bars() { if (ws_walk->urgent) { printf("WS %s is urgent!\n", ws_walk->name); color = get_colorpixel("002400"); + /* The urgent-hint should get noticed, so we unhide the bars shortly */ + unhide_bars(); } xcb_change_gc(xcb_connection, outputs_walk->bargc, From c2ad6167e99c3006f8c1148bca78ec76d8e599ec Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 23:36:25 +0200 Subject: [PATCH 045/185] Put the bars on top, when reconfiguring --- i3bar/src/xcb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a974ead9..7f479b4e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -88,7 +88,7 @@ void unhide_bars() { xcb_void_cookie_t cookie; xcb_generic_error_t *err; uint32_t mask; - uint32_t values[4]; + uint32_t values[5]; cont_child(); @@ -99,11 +99,13 @@ void unhide_bars() { mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | - XCB_CONFIG_WINDOW_HEIGHT; + XCB_CONFIG_WINDOW_HEIGHT | + XCB_CONFIG_WINDOW_STACK_MODE; values[0] = walk->rect.x; values[1] = walk->rect.y + walk->rect.h - font_height - 6; values[2] = walk->rect.w; values[3] = font_height + 6; + values[4] = XCB_STACK_MODE_ABOVE; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); cookie = xcb_configure_window_checked(xcb_connection, walk->bar, @@ -469,7 +471,7 @@ void destroy_window(i3_output *output) { */ void reconfig_windows() { uint32_t mask; - uint32_t values[4]; + uint32_t values[5]; xcb_void_cookie_t cookie; xcb_generic_error_t *err; @@ -552,11 +554,13 @@ void reconfig_windows() { mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | - XCB_CONFIG_WINDOW_HEIGHT; + XCB_CONFIG_WINDOW_HEIGHT | + XCB_CONFIG_WINDOW_STACK_MODE; values[0] = walk->rect.x; values[1] = walk->rect.y + walk->rect.h - font_height - 6; values[2] = walk->rect.w; values[3] = font_height + 6; + values[4] = XCB_STACK_MODE_ABOVE; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); cookie = xcb_configure_window_checked(xcb_connection, walk->bar, From 386abde4df1b1fee4c933a47989c986c30856df9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 26 Aug 2010 00:01:24 +0200 Subject: [PATCH 046/185] Put usage-message in own function --- i3bar/src/main.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 75f21382..63b60367 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -35,6 +35,17 @@ char *expand_path(char *path) { return result; } +void print_usage(char *elf_name) { + printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-h]\n", elf_name); + printf("-s \tConnect to i3 via \n"); + printf("-c \tExecute to get stdin\n"); + printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); + printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); + printf("\t\tand a SIGCONT on unhiding of the bars\n"); + printf("-f \tUse X-Core-Font for display\n"); + printf("-h\t\tDisplay this help-message and exit\n"); +} + int main(int argc, char **argv) { int opt; int option_index = 0; @@ -65,12 +76,9 @@ int main(int argc, char **argv) { case 'v': printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); + break; default: - printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); - printf("-s : Connect to i3 via \n"); - printf("-c : Execute to get stdin\n"); - printf("-f : Use X-Core-Font for display\n"); - printf("-h: Display this help-message and exit\n"); + print_usage(argv[0]); exit(EXIT_SUCCESS); break; } From c4c918cb0657a0296abbc10531f402b107831ab3 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 26 Aug 2010 00:02:35 +0200 Subject: [PATCH 047/185] Make hide_on_modifier configurable --- i3bar/include/common.h | 1 + i3bar/include/config.h | 10 ++++++ i3bar/src/main.c | 9 ++++- i3bar/src/xcb.c | 74 ++++++++++++++++++++++++------------------ 4 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 i3bar/include/config.h diff --git a/i3bar/include/common.h b/i3bar/include/common.h index d6b63a7e..dcb0bac3 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -25,6 +25,7 @@ struct rect_t { #include "queue.h" #include "child.h" +#include "config.h" #include "ipc.h" #include "outputs.h" #include "util.h" diff --git a/i3bar/include/config.h b/i3bar/include/config.h new file mode 100644 index 00000000..cbf158a6 --- /dev/null +++ b/i3bar/include/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H_ +#define CONFIL_H_ + +typedef struct config_t { + int hide_on_modifier; +} config_t; + +config_t config; + +#endif diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 63b60367..5afda241 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -53,16 +53,20 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; + /* Definition of the standard-config */ + config.hide_on_modifier = 0; + static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, { "command", required_argument, 0, 'c' }, + { "hide", no_argument, 0, 'm' }, { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:f:hv", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hv", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -70,6 +74,9 @@ int main(int argc, char **argv) { case 'c': command = strdup(optarg); break; + case 'm': + config.hide_on_modifier = 1; + break; case 'f': fontname = strdup(optarg); break; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 7f479b4e..d5a72ae3 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -72,6 +72,10 @@ uint32_t get_colorpixel(const char *s) { * */ void hide_bars() { + if (!config.hide_on_modifier) { + return; + } + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { xcb_unmap_window(xcb_connection, walk->bar); @@ -84,6 +88,10 @@ void hide_bars() { * */ void unhide_bars() { + if (!config.hide_on_modifier) { + return; + } + i3_output *walk; xcb_void_cookie_t cookie; xcb_generic_error_t *err; @@ -345,55 +353,57 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - int xkb_major, xkb_minor, xkb_errbase, xkb_err; - xkb_major = XkbMajorVersion; - xkb_minor = XkbMinorVersion; + if (config.hide_on_modifier) { + int xkb_major, xkb_minor, xkb_errbase, xkb_err; + xkb_major = XkbMajorVersion; + xkb_minor = XkbMinorVersion; - xkb_dpy = XkbOpenDisplay(":0", - &xkb_event_base, - &xkb_errbase, - &xkb_major, - &xkb_minor, - &xkb_err); + xkb_dpy = XkbOpenDisplay(":0", + &xkb_event_base, + &xkb_errbase, + &xkb_major, + &xkb_minor, + &xkb_err); - if (xkb_dpy == NULL) { - printf("ERROR: No XKB!\n"); - exit(EXIT_FAILURE); - } + if (xkb_dpy == NULL) { + printf("ERROR: No XKB!\n"); + exit(EXIT_FAILURE); + } - if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); - exit(EXIT_FAILURE); - } + if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { + fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); + exit(EXIT_FAILURE); + } - int i1; - if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { - printf("ERROR: XKB not supported by X-server!\n"); - exit(EXIT_FAILURE); - } + int i1; + if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { + printf("ERROR: XKB not supported by X-server!\n"); + exit(EXIT_FAILURE); + } - if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - printf("Could not grab Key!\n"); - exit(EXIT_FAILURE); + if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { + printf("Could not grab Key!\n"); + exit(EXIT_FAILURE); + } + + xkb_io = malloc(sizeof(ev_io)); + ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); + ev_io_start(main_loop, xkb_io); + XFlush(xkb_dpy); } /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); - xkb_io = malloc(sizeof(ev_io)); ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); ev_prepare_init(xcb_prep, &xcb_prep_cb); ev_check_init(xcb_chk, &xcb_chk_cb); - ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); ev_io_start(main_loop, xcb_io); ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); - ev_io_start(main_loop, xkb_io); - - XFlush(xkb_dpy); /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); @@ -492,8 +502,8 @@ void reconfig_windows() { mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; - /* i3 is not supposed to manage our bar-windows */ - values[1] = 1; + /* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */ + values[1] = config.hide_on_modifier; /* The events we want to receive */ values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; From 4e298d5a1d386da2f50c013de8fed3b666fb81c5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 4 Sep 2010 18:26:30 +0200 Subject: [PATCH 048/185] Reimplement double-buffering Due to a merge-fuckup, the double-buffer-code got lost. Know flickering should not happen anymore. --- i3bar/src/xcb.c | 132 ++++++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 49 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index d5a72ae3..42a49ced 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -229,7 +229,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: /* Expose-events happen, when the window needs to be redrawn */ - draw_bars(); + redraw_bars(); break; case XCB_BUTTON_PRESS: /* Button-press-events are mouse-buttons clicked on one of our bars */ @@ -483,7 +483,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[5]; - xcb_void_cookie_t cookie; xcb_generic_error_t *err; i3_output *walk; @@ -499,6 +498,7 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); + walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; @@ -507,55 +507,68 @@ void reconfig_windows() { /* The events we want to receive */ values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - cookie = xcb_create_window_checked(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); /* We want dock-windows (for now) */ - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - + xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; - cookie = xcb_create_gc_checked(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + /* We finally map the bar (display it on screen) */ + xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, win_cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, prop_cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, gc_cookie)) != NULL) { printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } - /* We finally map the bar (display it on screen) */ - cookie = xcb_map_window_checked(xcb_connection, walk->bar); - - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + if ((err = xcb_request_check(xcb_connection, map_cookie)) != NULL) { printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } @@ -572,12 +585,12 @@ void reconfig_windows() { values[3] = font_height + 6; values[4] = XCB_STACK_MODE_ABOVE; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); - cookie = xcb_configure_window_checked(xcb_connection, - walk->bar, - mask, - values); + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); exit(EXIT_FAILURE); } @@ -608,7 +621,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -630,7 +643,7 @@ void draw_bars() { xcb_void_cookie_t cookie; cookie = xcb_image_text_16(xcb_connection, glyph_count, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, font_height + 1, @@ -665,7 +678,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -676,13 +689,34 @@ void draw_bars() { &color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, i + 5, font_height + 1, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } + redraw_bars(); + i = 0; } } + +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars() { + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + xcb_copy_area(xcb_connection, + outputs_walk->buffer, + outputs_walk->bar, + outputs_walk->bargc, + 0, 0, + 0, 0, + outputs_walk->rect.w, + outputs_walk->rect.h); + xcb_flush(xcb_connection); + } +} From 17484d82f2b8a530badb8311341ef9e04df4f3ec Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 7 Sep 2010 17:28:15 +0200 Subject: [PATCH 049/185] Allocate the right amount of memory for ev_child --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..c0a56661 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -169,7 +169,7 @@ void start_child(char *command) { ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ - child_sig = malloc(sizeof(ev_io)); + child_sig = malloc(sizeof(ev_child)); ev_child_init(child_sig, &child_sig_cb, child_pid, 0); ev_child_start(main_loop, child_sig); From 4d38bf81ba6d66ce0124019082820f7bdec1659b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 7 Sep 2010 17:28:15 +0200 Subject: [PATCH 050/185] Allocate the right amount of memory for ev_child --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2ba839ec..97162cb4 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -142,7 +142,7 @@ void start_child(char *command) { ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ - child_sig = malloc(sizeof(ev_io)); + child_sig = malloc(sizeof(ev_child)); ev_child_init(child_sig, &child_sig_cb, child_pid, 0); ev_child_start(main_loop, child_sig); From 4ec3e7a61956a1b5ec81ac29fdadc4402226ad3b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:16:53 +0200 Subject: [PATCH 051/185] Define Macros MAX and MIN --- i3bar/include/util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 0f5dd3e3..7e638152 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -11,6 +11,10 @@ #include "queue.h" +/* Get the maximum/minimum of x and y */ +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + /* Securely free p */ #define FREE(p) do { \ if (p != NULL) { \ From 2ce9c4024f701d1e8b7d748bc99d06c904f5046c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:18:50 +0200 Subject: [PATCH 052/185] Draw the statusline to a seperate buffer-pixmap --- i3bar/src/xcb.c | 177 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 25 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 42a49ced..88f4be35 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -42,16 +42,67 @@ xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +/* We need to cache some data to speed up text-width-prediction */ +xcb_query_font_reply_t *font_info; +xcb_charinfo_t *font_table; + +/* These are only relevant for XKB, which we only need for grabbing modifiers */ Display *xkb_dpy; int xkb_event_base; int mod_pressed; +/* Because the statusline is the same on all outputs, we have + * global buffer to render it on */ +xcb_gcontext_t statusline_ctx; +xcb_pixmap_t statusline_pm; +uint32_t statusline_width; + /* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* + * Predicts the length of text based on cached data + * + */ +uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { + /* If we don't have per-character data, return the maximum width */ + if (font_table == NULL) { + return (font_info->max_bounds.character_width * length); + } + + uint32_t width = 0; + uint32_t i; + + for (i = 0; i < length; i++) { + xcb_charinfo_t *info; + int row = text[i].byte1; + int col = text[i].byte2; + + if (row < font_info->min_byte1 || row > font_info->max_byte1 || + col < font_info->min_char_or_byte2 || col > font_info->max_char_or_byte2) { + continue; + } + + /* Don't you ask me, how this one works… */ + info = &font_table[((row - font_info->min_byte1) * + (font_info->max_char_or_byte2 - font_info->min_char_or_byte2 + 1)) + + (col - font_info->min_char_or_byte2)]; + + if (info->character_width != 0 || + (info->right_side_bearing | + info->left_side_bearing | + info->ascent | + info->descent) != 0) { + width += info->character_width; + } + } + + return width; +} + /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. * s is assumed to be in the format "rrggbb" @@ -67,6 +118,52 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Redraws the statusline to the buffer + * + */ +void refresh_statusline() { + int glyph_count; + uint32_t root_width = xcb_screens->width_in_pixels; + if (statusline == NULL) { + return; + } + + xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); + statusline_width = predict_text_extents(text, glyph_count); + int crop_x = MIN(0, ((int32_t)root_width) - ((int32_t)statusline_width)); + printf("Cropping statusline with %d glyphs at x=%d\n", glyph_count, crop_x); + statusline_width = MIN((int32_t)statusline_width, (int32_t)root_width); + + xcb_free_pixmap(xcb_connection, statusline_pm); + statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + statusline_pm, + xcb_root, + statusline_width, + font_height); + + xcb_void_cookie_t text_cookie = xcb_image_text_16(xcb_connection, + glyph_count, + statusline_pm, + statusline_ctx, + 0, + font_height, + text); + + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { + printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, text_cookie)) != NULL) { + printf("ERROR: Could not draw text to buffer! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } +} + /* * Hides all bars (unmaps them) * @@ -353,6 +450,10 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); + xcb_query_font_cookie_t query_font_cookie; + query_font_cookie = xcb_query_font(xcb_connection, + xcb_font); + if (config.hide_on_modifier) { int xkb_major, xkb_minor, xkb_errbase, xkb_err; xkb_major = XkbMajorVersion; @@ -392,6 +493,22 @@ void init_xcb(char *fontname) { XFlush(xkb_dpy); } + /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and + * this way, we can choose to crop it */ + statusline_ctx = xcb_generate_id(xcb_connection); + uint32_t mask = XCB_GC_FOREGROUND | + XCB_GC_BACKGROUND | + XCB_GC_FONT; + uint32_t vals[3] = { xcb_screens->white_pixel, xcb_screens->black_pixel, xcb_font }; + + xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_ctx, + xcb_root, + mask, + vals); + + statusline_pm = xcb_generate_id(xcb_connection); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); @@ -416,7 +533,27 @@ void init_xcb(char *fontname) { font_height = reply->font_ascent + reply->font_descent; FREE(reply); + font_info = xcb_query_font_reply(xcb_connection, + query_font_cookie, + &err); + + if (err != NULL) { + printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if (xcb_query_font_char_infos_length(font_info) == 0) { + font_table = NULL; + } else { + font_table = xcb_query_font_char_infos(font_info); + } + printf("Calculated Font-height: %d\n", font_height); + + if((err = xcb_request_check(xcb_connection, sl_ctx_cookie)) != NULL) { + printf("ERROR: Could not create context for statusline! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } /* @@ -605,6 +742,9 @@ void reconfig_windows() { void draw_bars() { printf("Drawing Bars...\n"); int i = 0; + + refresh_statusline(); + i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { if (!outputs_walk->active) { @@ -627,34 +767,21 @@ void draw_bars() { &rect); if (statusline != NULL) { printf("Printing statusline!\n"); - xcb_change_gc(xcb_connection, + + xcb_void_cookie_t ca_cookie = xcb_copy_area(xcb_connection, + statusline_pm, + outputs_walk->buffer, outputs_walk->bargc, - XCB_GC_BACKGROUND, - &color); - color = get_colorpixel("FFFFFF"); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FOREGROUND, - &color); - - int glyph_count; - xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); - - xcb_void_cookie_t cookie; - cookie = xcb_image_text_16(xcb_connection, - glyph_count, - outputs_walk->buffer, - outputs_walk->bargc, - outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, - font_height + 1, - (xcb_char2b_t*) text); - - xcb_generic_error_t *err = xcb_request_check(xcb_connection, cookie); - - if (err != NULL) { - printf("XCB-Error: %d\n", err->error_code); + 0, 0, + MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1, + (uint16_t)outputs_walk->rect.w, font_height); + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) { + printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code); + free(err); } } + i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); From c5dc3d49aa42220bfef156fb9d559c677dfd7381 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:51:10 +0200 Subject: [PATCH 053/185] We don't need to crop at that point --- i3bar/src/xcb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 88f4be35..43ac8beb 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -124,16 +124,13 @@ uint32_t get_colorpixel(const char *s) { */ void refresh_statusline() { int glyph_count; - uint32_t root_width = xcb_screens->width_in_pixels; + if (statusline == NULL) { return; } xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - int crop_x = MIN(0, ((int32_t)root_width) - ((int32_t)statusline_width)); - printf("Cropping statusline with %d glyphs at x=%d\n", glyph_count, crop_x); - statusline_width = MIN((int32_t)statusline_width, (int32_t)root_width); xcb_free_pixmap(xcb_connection, statusline_pm); statusline_pm = xcb_generate_id(xcb_connection); From 0dc802c7b5a41f4e6205e2632eca8bee86276b2a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:52:04 +0200 Subject: [PATCH 054/185] Write a wrapper around xcb_image_text_16() xcb_image_text_16() can only process up to 255 glyphs, so we write a wrapper around it for arbitrary long strings --- i3bar/src/xcb.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 43ac8beb..e1495e66 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -103,6 +103,31 @@ uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { return width; } +/* + * Draws text given in UCS-2-encoding to a given drawable and position + * + */ +void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y, + xcb_char2b_t *text, uint32_t glyph_count) { + int offset = 0; + int16_t pos_x = x; + while (glyph_count > 0) { + uint8_t chunk_size = MIN(255, glyph_count); + uint32_t chunk_width = predict_text_extents(text + offset, chunk_size); + + xcb_image_text_16(xcb_connection, + chunk_size, + drawable, + ctx, + pos_x, y, + text + offset); + + offset += chunk_size; + pos_x += chunk_width; + glyph_count -= chunk_size; + } +} + /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. * s is assumed to be in the format "rrggbb" From 52120e3ed54000d03896d4d598760aeb28aa0f63 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:17:18 +0200 Subject: [PATCH 055/185] Use draw_text() to render text to the correct spot --- i3bar/src/xcb.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e1495e66..453d5f46 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -111,6 +111,8 @@ void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y xcb_char2b_t *text, uint32_t glyph_count) { int offset = 0; int16_t pos_x = x; + int16_t font_ascent = font_info->font_ascent; + while (glyph_count > 0) { uint8_t chunk_size = MIN(255, glyph_count); uint32_t chunk_width = predict_text_extents(text + offset, chunk_size); @@ -119,7 +121,7 @@ void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y chunk_size, drawable, ctx, - pos_x, y, + pos_x, y + font_ascent, text + offset); offset += chunk_size; @@ -166,24 +168,13 @@ void refresh_statusline() { statusline_width, font_height); - xcb_void_cookie_t text_cookie = xcb_image_text_16(xcb_connection, - glyph_count, - statusline_pm, - statusline_ctx, - 0, - font_height, - text); + draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); exit(EXIT_FAILURE); } - - if ((err = xcb_request_check(xcb_connection, text_cookie)) != NULL) { - printf("ERROR: Could not draw text to buffer! XCB-error: %d\n", err->error_code); - exit(EXIT_FAILURE); - } } /* @@ -790,18 +781,13 @@ void draw_bars() { if (statusline != NULL) { printf("Printing statusline!\n"); - xcb_void_cookie_t ca_cookie = xcb_copy_area(xcb_connection, + xcb_copy_area(xcb_connection, statusline_pm, outputs_walk->buffer, outputs_walk->bargc, - 0, 0, - MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1, - (uint16_t)outputs_walk->rect.w, font_height); - xcb_generic_error_t *err; - if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) { - printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code); - free(err); - } + MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0, + MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - 4)), 3, + MIN(outputs_walk->rect.w - 4, statusline_width), font_height); } i3_ws *ws_walk; From a702ced32249ecd9fc61339b63712fc00a0f6b14 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:21:09 +0200 Subject: [PATCH 056/185] Add CHANGELOG --- i3bar/CHANGELOG | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 i3bar/CHANGELOG diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG new file mode 100644 index 00000000..0106447e --- /dev/null +++ b/i3bar/CHANGELOG @@ -0,0 +1,9 @@ +- Bugfix: Correctly render long text +- Bugfix: Don't segfault on SIGCHILD +- Implement hide-on-modifier +- Use double-buffering + + +v0.5 +===== +- Initial release From d245d14765ef0676c85a346e3bea9cf25fe44a32 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:28:56 +0200 Subject: [PATCH 057/185] Use realloc instead of manually reallocating --- i3bar/src/child.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 97162cb4..a4c33bcd 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -61,12 +61,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } if (n == 0) { if (rec == buffer_len) { - char *tmp = buffer; - buffer = malloc(buffer_len + STDIN_CHUNK_SIZE); - memset(buffer, '\0', buffer_len); - strncpy(buffer, tmp, buffer_len); buffer_len += STDIN_CHUNK_SIZE; - FREE(tmp); + buffer = realloc(buffer, buffer_len); } else { /* remove trailing newline and finish up */ buffer[rec-1] = '\0'; From 0e4487e489ea173ae09cb31c6a48751d5287bf69 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:03:43 +0200 Subject: [PATCH 058/185] Move child_pid into child.c --- i3bar/include/common.h | 1 - i3bar/src/child.c | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index dcb0bac3..e885ddcd 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -13,7 +13,6 @@ typedef struct rect_t rect; typedef int bool; struct ev_loop* main_loop; -pid_t child_pid; char *statusline; struct rect_t { diff --git a/i3bar/src/child.c b/i3bar/src/child.c index a4c33bcd..1ed429c0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -20,6 +20,9 @@ #include "common.h" +/* Global variables for child_*() */ +pid_t child_pid; + /* stdin- and sigchild-watchers */ ev_io *stdin_io; ev_child *child_sig; From 5deb95de33a7f4665ff9a7f312babca3109b7c83 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:04:40 +0200 Subject: [PATCH 059/185] Make i3_default_sock_path a local variable --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 5afda241..07dcf5b9 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -18,7 +18,6 @@ #include "common.h" -char *i3_default_sock_path = "~/.i3/ipc.sock"; char *expand_path(char *path) { static glob_t globbuf; @@ -52,6 +51,7 @@ int main(int argc, char **argv) { char *socket_path = NULL; char *command = NULL; char *fontname = NULL; + char *i3_default_sock_path = "~/.i3/ipc.sock"; /* Definition of the standard-config */ config.hide_on_modifier = 0; From 7fda48aa9fd5c5b6174de7378fd6e6592187a065 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:11:49 +0200 Subject: [PATCH 060/185] We don't need get_string_width anymore --- i3bar/include/xcb.h | 6 +++--- i3bar/src/workspaces.c | 5 +++-- i3bar/src/xcb.c | 28 +++------------------------- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 2e4b16a8..82216f7f 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -55,11 +55,11 @@ void draw_bars(); void redraw_bars(); /* - * Calculate the rendered width of a string with the configured font. + * Predicts the length of text based on cached data. * The string has to be encoded in ucs2 and glyph_len has to be the length - * of the string (in width) + * of the string (in glyphs). * */ -int get_string_width(xcb_char2b_t *string, int glyph_len); +uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length); #endif diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 8ba79eec..71903fb0 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -115,8 +115,9 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len); params->workspaces_walk->ucs2_name = ucs2_name; params->workspaces_walk->name_glyphs = ucs2_len; - params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->ucs2_name, - params->workspaces_walk->name_glyphs); + params->workspaces_walk->name_width = + predict_text_extents(params->workspaces_walk->ucs2_name, + params->workspaces_walk->name_glyphs); printf("Got Workspace %s, name_width: %d, glyphs: %d\n", params->workspaces_walk->name, diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 453d5f46..e200c5e4 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,7 +64,9 @@ ev_io *xcb_io; ev_io *xkb_io; /* - * Predicts the length of text based on cached data + * Predicts the length of text based on cached data. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in glyphs). * */ uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { @@ -396,30 +398,6 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } } -/* - * Calculate the rendered width of a string with the configured font. - * The string has to be encoded in ucs2 and glyph_len has to be the length - * of the string (in width) - * - */ -int get_string_width(xcb_char2b_t *string, int glyph_len) { - xcb_query_text_extents_cookie_t cookie; - xcb_query_text_extents_reply_t *reply; - xcb_generic_error_t *error = NULL; - int width; - - cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); - reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); - if (error != NULL) { - printf("ERROR: Could not get text extents! XCB-errorcode: %d\n", error->error_code); - exit(EXIT_FAILURE); - } - - width = reply->overall_width; - free(reply); - return width; -} - /* * Initialize xcb and use the specified fontname for text-rendering * From c82556f0f2ac97bf2731f3f6aed008dca946cca9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:27:06 +0200 Subject: [PATCH 061/185] Use only xcb_query_font() --- i3bar/include/xcb.h | 2 -- i3bar/src/xcb.c | 18 ++++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 82216f7f..75402285 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -9,8 +9,6 @@ #ifndef XCB_H_ #define XCB_H_ -int font_height; - /* * Initialize xcb and use the specified fontname for text-rendering * diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e200c5e4..f4f064a1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -44,6 +44,7 @@ xcb_font_t xcb_font; /* We need to cache some data to speed up text-width-prediction */ xcb_query_font_reply_t *font_info; +int font_height; xcb_charinfo_t *font_table; /* These are only relevant for XKB, which we only need for grabbing modifiers */ @@ -434,13 +435,8 @@ void init_xcb(char *fontname) { exit(EXIT_FAILURE); } - /* We also need the fontheight to configure our bars accordingly */ - xcb_list_fonts_with_info_cookie_t font_info_cookie; - font_info_cookie = xcb_list_fonts_with_info(xcb_connection, - 1, - strlen(fontname), - fontname); - + /* We need to save info about the font, because we need the fonts height and + * information about the width of characters */ xcb_query_font_cookie_t query_font_cookie; query_font_cookie = xcb_query_font(xcb_connection, xcb_font); @@ -517,16 +513,10 @@ void init_xcb(char *fontname) { get_atoms(); /* Now we calculate the font-height */ - xcb_list_fonts_with_info_reply_t *reply; - reply = xcb_list_fonts_with_info_reply(xcb_connection, - font_info_cookie, - NULL); - font_height = reply->font_ascent + reply->font_descent; - FREE(reply); - font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, &err); + font_height = font_info->font_ascent + font_info->font_descent; if (err != NULL) { printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); From 93453c64f2db520416e381f2fb64cc0ca58fce79 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:26:31 +0200 Subject: [PATCH 062/185] Add some more comments --- i3bar/src/child.c | 3 +++ i3bar/src/ipc.c | 14 +++++++++++--- i3bar/src/main.c | 16 +++++++++++++++- i3bar/src/xcb.c | 21 ++++++++++++++++++--- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 1ed429c0..f57da9e1 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -114,6 +114,7 @@ void start_child(char *command) { printf("ERROR: Couldn't fork()"); exit(EXIT_FAILURE); case 0: + /* Child-process. Reroute stdout and start shell */ close(fd[0]); dup2(fd[1], STDOUT_FILENO); @@ -126,6 +127,7 @@ void start_child(char *command) { execl(shell, shell, "-c", command, (char*) NULL); return; default: + /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); @@ -134,6 +136,7 @@ void start_child(char *command) { } } + /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); stdin_io = malloc(sizeof(ev_io)); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 59563636..da9378f5 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -51,7 +51,7 @@ int get_ipc_fd(const char *socket_path) { * */ void got_command_reply(char *reply) { - /* FIXME: Error handling for command-replies */ + /* TODO: Error handling for command-replies */ } /* @@ -71,7 +71,7 @@ void got_workspace_reply(char *reply) { */ void got_subscribe_reply(char *reply) { printf("Got Subscribe Reply: %s\n", reply); - /* FIXME: Error handling for subscribe-commands */ + /* TODO: Error handling for subscribe-commands */ } /* @@ -134,6 +134,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } + /* We first parse the fixed-length IPC-header, to know, how much data + * we have to expect */ uint32_t rec = 0; while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); @@ -156,11 +158,13 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } - /* Know we read the rest of the message */ char *walk = header + strlen(I3_IPC_MAGIC); uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); uint32_t type = *((uint32_t*) walk); + + /* Now that we know, what to expect, we can start read()ing the rest + * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { printf("ERROR: Could not allocate memory!\n"); @@ -205,7 +209,11 @@ int i3_send_msg(uint32_t type, const char *payload) { len = strlen(payload); } + /* We are a wellbehaved client and send a proper header first */ uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; + /* TODO: I'm not entirely sure if this buffer really has to contain more + * than the pure header (why not just write() the payload from *payload?), + * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { printf("ERROR: Could not allocate memory\n"); diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 07dcf5b9..118c2947 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -18,7 +18,10 @@ #include "common.h" - +/* + * Glob path, i.e. expand ~ + * + */ char *expand_path(char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { @@ -92,6 +95,9 @@ int main(int argc, char **argv) { } if (fontname == NULL) { + /* This is a very restrictive default. More sensefull would be something like + * "-misc-*-*-*-*--*-*-*-*-*-*-*-*". But since that produces very ugly results + * on my machine, let's stick with this until we have a configfile */ fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; } @@ -108,13 +114,21 @@ int main(int argc, char **argv) { FREE(socket_path); + /* We subscribe to the i3-events we need */ subscribe_events(); + /* We initiate the main-function by requesting infos about the outputs and + * workspaces. Everything else (creating the bars, showing the right workspace- + * buttons and more) is taken care of by the event-driveniness of the code */ i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + /* The name of this function is actually misleading. Even if no -c is specified, + * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + /* From here on everything should run smooth for itself, just start listening for + * events. We stop simply stop the event-loop, when we are finished */ ev_loop(main_loop, 0); kill_child(); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f4f064a1..4939d6ab 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -441,6 +441,9 @@ void init_xcb(char *fontname) { query_font_cookie = xcb_query_font(xcb_connection, xcb_font); + /* To grab modifiers without blocking other applications from receiving key-events + * involving that modifier, we sadly have to use xkb which is not yet fully supported + * in xcb */ if (config.hide_on_modifier) { int xkb_major, xkb_minor, xkb_errbase, xkb_err; xkb_major = XkbMajorVersion; @@ -494,6 +497,8 @@ void init_xcb(char *fontname) { mask, vals); + /* We only generate an id for the pixmap, because the width of it is dependent on the + * input we get */ statusline_pm = xcb_generate_id(xcb_connection); /* The varios Watchers to communicate with xcb */ @@ -512,7 +517,7 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); - /* Now we calculate the font-height */ + /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, &err); @@ -637,6 +642,7 @@ void reconfig_windows() { mask, values); + /* The double-buffer we use to render stuff off-screen */ xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, xcb_screens->root_depth, walk->buffer, @@ -644,7 +650,8 @@ void reconfig_windows() { walk->rect.w, walk->rect.h); - /* We want dock-windows (for now) */ + /* We want dock-windows (for now). When override_redirect is set, i3 is ignoring + * this one */ xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, walk->bar, @@ -653,7 +660,9 @@ void reconfig_windows() { 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - /* We also want a graphics-context (the "canvas" on which we draw) */ + + /* We also want a graphics-context for the bars (it defines the properties + * with which we draw to them) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; @@ -733,8 +742,10 @@ void draw_bars() { continue; } if (outputs_walk->bar == XCB_NONE) { + /* Oh shit, an active output without an own bar. Create it now! */ reconfig_windows(); } + /* First things first: clear the backbuffer */ uint32_t color = get_colorpixel("000000"); xcb_change_gc(xcb_connection, outputs_walk->bargc, @@ -746,9 +757,13 @@ void draw_bars() { outputs_walk->bargc, 1, &rect); + if (statusline != NULL) { printf("Printing statusline!\n"); + /* Luckily we already prepared a seperate pixmap containing the rendered + * statusline, we just have to copy the relevant parts to the relevant + * position */ xcb_copy_area(xcb_connection, statusline_pm, outputs_walk->buffer, From a75cb6e785632f3baafbbb4af2d065e1c074abdc Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:28:22 +0200 Subject: [PATCH 063/185] Rename xcb_screens to xcb_screen, it's really just one --- i3bar/src/xcb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4939d6ab..cf1c8905 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -38,7 +38,7 @@ xcb_atom_t atoms[NUM_ATOMS]; /* Variables, that are the same for all functions at all times */ xcb_connection_t *xcb_connection; -xcb_screen_t *xcb_screens; +xcb_screen_t *xcb_screen; xcb_window_t xcb_root; xcb_font_t xcb_font; @@ -165,7 +165,7 @@ void refresh_statusline() { xcb_free_pixmap(xcb_connection, statusline_pm); statusline_pm = xcb_generate_id(xcb_connection); xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->root_depth, statusline_pm, xcb_root, statusline_width, @@ -416,8 +416,8 @@ void init_xcb(char *fontname) { #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); #include "xcb_atoms.def" - xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; - xcb_root = xcb_screens->root; + xcb_screen = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; + xcb_root = xcb_screen->root; /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); @@ -489,7 +489,7 @@ void init_xcb(char *fontname) { uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; - uint32_t vals[3] = { xcb_screens->white_pixel, xcb_screens->black_pixel, xcb_font }; + uint32_t vals[3] = { xcb_screen->white_pixel, xcb_screen->black_pixel, xcb_font }; xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, @@ -624,27 +624,27 @@ void reconfig_windows() { walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ - values[0] = xcb_screens->black_pixel; + values[0] = xcb_screen->black_pixel; /* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */ values[1] = config.hide_on_modifier; /* The events we want to receive */ values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->root_depth, walk->bar, xcb_root, walk->rect.x, walk->rect.y, walk->rect.w, font_height + 6, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, + xcb_screen->root_visual, mask, values); /* The double-buffer we use to render stuff off-screen */ xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->root_depth, walk->buffer, walk->bar, walk->rect.w, From 60bab3db28326206fb7c4725c64dc99c755f0e92 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:29:01 +0200 Subject: [PATCH 064/185] Use font_ascent instead of font_height, it's more elegant --- i3bar/src/xcb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index cf1c8905..4e116050 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -563,6 +563,7 @@ void clean_xcb() { FREE(xcb_chk); FREE(xcb_prep); FREE(xcb_io); + FREE(font_info); } /* @@ -809,7 +810,7 @@ void draw_bars() { ws_walk->name_glyphs, outputs_walk->buffer, outputs_walk->bargc, - i + 5, font_height + 1, + i + 5, font_info->font_ascent + 2, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } From ca1a2957147fafd0082d0088deb28b78f6c88c6f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:55:38 +0200 Subject: [PATCH 065/185] Clean the XCB-errorhandling a little bit up --- i3bar/src/xcb.c | 68 ++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4e116050..87829503 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,6 +64,17 @@ ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* We define xcb_request_failed as a macro to include the relevant line-number */ +#define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) +int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("%s:%d - %s. X Error Code: %d", __FILE__, line, err_msg, err->error_code); + return err->error_code; + } + return 0; +} + /* * Predicts the length of text based on cached data. * The string has to be encoded in ucs2 and glyph_len has to be the length @@ -173,9 +184,7 @@ void refresh_statusline() { draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); - xcb_generic_error_t *err; - if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { - printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { exit(EXIT_FAILURE); } } @@ -207,7 +216,6 @@ void unhide_bars() { i3_output *walk; xcb_void_cookie_t cookie; - xcb_generic_error_t *err; uint32_t mask; uint32_t values[5]; @@ -233,8 +241,7 @@ void unhide_bars() { mask, values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + if (xcb_request_failed(cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } xcb_map_window(xcb_connection, walk->bar); @@ -427,14 +434,6 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - xcb_generic_error_t *err = xcb_request_check(xcb_connection, - open_font_cookie); - - if (err != NULL) { - printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - /* We need to save info about the font, because we need the fonts height and * information about the width of characters */ xcb_query_font_cookie_t query_font_cookie; @@ -520,11 +519,10 @@ void init_xcb(char *fontname) { /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, - &err); + NULL); font_height = font_info->font_ascent + font_info->font_descent; - if (err != NULL) { - printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(open_font_cookie, "Could not open font")) { exit(EXIT_FAILURE); } @@ -536,8 +534,7 @@ void init_xcb(char *fontname) { printf("Calculated Font-height: %d\n", font_height); - if((err = xcb_request_check(xcb_connection, sl_ctx_cookie)) != NULL) { - printf("ERROR: Could not create context for statusline! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); } } @@ -607,8 +604,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[5]; - xcb_generic_error_t *err; - i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { @@ -676,28 +671,11 @@ void reconfig_windows() { /* We finally map the bar (display it on screen) */ xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); - if ((err = xcb_request_check(xcb_connection, win_cookie)) != NULL) { - printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - - if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { - printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - - if ((err = xcb_request_check(xcb_connection, prop_cookie)) != NULL) { - printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - - if ((err = xcb_request_check(xcb_connection, gc_cookie)) != NULL) { - printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - - if ((err = xcb_request_check(xcb_connection, map_cookie)) != NULL) { - printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); + if (xcb_request_failed(win_cookie, "Could not create window") || + xcb_request_failed(pm_cookie, "Could not create pixmap") || + xcb_request_failed(prop_cookie, "Could not set dock mode") || + xcb_request_failed(gc_cookie, "Could not create graphical context") || + xcb_request_failed(map_cookie, "Could not map window")) { exit(EXIT_FAILURE); } } else { @@ -717,9 +695,7 @@ void reconfig_windows() { walk->bar, mask, values); - - if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { - printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } } From 920721bb939a0aac67da24fd40ccd8893143034d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 06:49:28 +0200 Subject: [PATCH 066/185] Use DLOG/ELOG-macros, provide --verbose-option --- i3bar/include/config.h | 1 + i3bar/include/util.h | 11 ++++++++ i3bar/src/child.c | 8 +++--- i3bar/src/ipc.c | 42 +++++++++++++++--------------- i3bar/src/main.c | 15 +++++++---- i3bar/src/outputs.c | 2 +- i3bar/src/workspaces.c | 12 ++++----- i3bar/src/xcb.c | 58 +++++++++++++++++++++--------------------- 8 files changed, 83 insertions(+), 66 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index cbf158a6..0496f431 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -3,6 +3,7 @@ typedef struct config_t { int hide_on_modifier; + int verbose; } config_t; config_t config; diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 7e638152..1952b039 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -44,3 +44,14 @@ walk = TAILQ_FIRST(l); \ } \ } while (0) + +/* Use cool logging-macros */ +#define DLOG(fmt, ...) do { \ + if (config.verbose) { \ + printf("[%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ + } \ +} while(0) + +#define ELOG(fmt, ...) do { \ + fprintf(stderr, "[%s:%d] ERROR: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ +} while(0) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index f57da9e1..fa70f452 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -59,7 +59,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer[rec-1] = '\0'; break; } - printf("ERROR: read() failed!"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { @@ -80,7 +80,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } FREE(statusline); statusline = buffer; - printf("%s\n", buffer); + DLOG("%s\n", buffer); draw_bars(); } @@ -91,7 +91,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * */ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { - printf("Child (pid: %d) unexpectedly exited with status %d\n", + DLOG("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus); cleanup(); @@ -111,7 +111,7 @@ void start_child(char *command) { child_pid = fork(); switch (child_pid) { case -1: - printf("ERROR: Couldn't fork()"); + ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: /* Child-process. Reroute stdout and start shell */ diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index da9378f5..0ddccc25 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -30,7 +30,7 @@ typedef void(*handler_t)(char*); int get_ipc_fd(const char *socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { - printf("ERROR: Could not create Socket!\n"); + ELOG("Could not create Socket!\n"); exit(EXIT_FAILURE); } @@ -39,7 +39,7 @@ int get_ipc_fd(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, socket_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - printf("ERROR: Could not connct to i3\n"); + ELOG("Could not connct to i3!\n"); exit(EXIT_FAILURE); } return sockfd; @@ -59,7 +59,7 @@ void got_command_reply(char *reply) { * */ void got_workspace_reply(char *reply) { - printf("Got Workspace-Data!\n"); + DLOG("Got Workspace-Data!\n"); parse_workspaces_json(reply); draw_bars(); } @@ -70,7 +70,7 @@ void got_workspace_reply(char *reply) { * */ void got_subscribe_reply(char *reply) { - printf("Got Subscribe Reply: %s\n", reply); + DLOG("Got Subscribe Reply: %s\n", reply); /* TODO: Error handling for subscribe-commands */ } @@ -79,9 +79,9 @@ void got_subscribe_reply(char *reply) { * */ void got_output_reply(char *reply) { - printf("Parsing Outputs-JSON...\n"); + DLOG("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); - printf("Reconfiguring Windows...\n"); + DLOG("Reconfiguring Windows...\n"); reconfig_windows(); } @@ -98,7 +98,7 @@ handler_t reply_handlers[] = { * */ void got_workspace_event(char *event) { - printf("Got Workspace Event!\n"); + DLOG("Got Workspace Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } @@ -107,7 +107,7 @@ void got_workspace_event(char *event) { * */ void got_output_event(char *event) { - printf("Got Output Event!\n"); + DLOG("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } @@ -123,14 +123,14 @@ handler_t event_handlers[] = { * */ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { - printf("Got data!\n"); + DLOG("Got data!\n"); int fd = watcher->fd; /* First we only read the header, because we know it's length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } @@ -140,21 +140,21 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); if (n == -1) { - printf("ERROR: read() failed!\n"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: Nothing to read!\n"); + ELOG("Nothing to read!\n"); exit(EXIT_FAILURE); } rec += n; } if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { - printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", - (int) strlen(I3_IPC_MAGIC), - header, - I3_IPC_MAGIC); + ELOG("Wrong magic code: %.*s\n Expected: %s\n", + (int) strlen(I3_IPC_MAGIC), + header, + I3_IPC_MAGIC); exit(EXIT_FAILURE); } @@ -167,7 +167,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } rec = 0; @@ -175,11 +175,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < size) { int n = read(fd, buffer + rec, size - rec); if (n == -1) { - printf("ERROR: read() failed!\n"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: Nothing to read!\n"); + ELOG("Nothing to read!\n"); exit(EXIT_FAILURE); } rec += n; @@ -216,7 +216,7 @@ int i3_send_msg(uint32_t type, const char *payload) { * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { - printf("ERROR: Could not allocate memory\n"); + ELOG("Could not allocate memory\n"); exit(EXIT_FAILURE); } @@ -236,7 +236,7 @@ int i3_send_msg(uint32_t type, const char *payload) { while (to_write > 0) { int n = write(i3_connection->fd, buffer + written, to_write); if (n == -1) { - printf("ERROR: write() failed!\n"); + ELOG("write() failed!\n"); exit(EXIT_FAILURE); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 118c2947..5b6debc5 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -25,12 +25,12 @@ char *expand_path(char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { - printf("glob() failed"); + ELOG("glob() failed\n"); exit(EXIT_FAILURE); } char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); if (result == NULL) { - printf("malloc() failed"); + ELOG("malloc() failed\n"); exit(EXIT_FAILURE); } globfree(&globbuf); @@ -38,13 +38,14 @@ char *expand_path(char *path) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); printf("-c \tExecute to get stdin\n"); printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); printf("\t\tand a SIGCONT on unhiding of the bars\n"); printf("-f \tUse X-Core-Font for display\n"); + printf("-V\t\tBe (very) verbose with the debug-output\n"); printf("-h\t\tDisplay this help-message and exit\n"); } @@ -66,10 +67,11 @@ int main(int argc, char **argv) { { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, + { "verbose", no_argument, 0, 'V' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hv", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvV", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -87,6 +89,9 @@ int main(int argc, char **argv) { printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; + case 'V': + config.verbose = 1; + break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); @@ -102,7 +107,7 @@ int main(int argc, char **argv) { } if (socket_path == NULL) { - printf("No Socket Path Specified, default to %s\n", i3_default_sock_path); + ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); socket_path = expand_path(i3_default_sock_path); } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index de905783..3577d82b 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -230,7 +230,7 @@ void parse_outputs_json(char *json) { case yajl_status_client_canceled: case yajl_status_insufficient_data: case yajl_status_error: - printf("ERROR: Could not parse outputs-reply!\n"); + ELOG("Could not parse outputs-reply!\n"); exit(EXIT_FAILURE); break; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 71903fb0..9f8acc1b 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -119,10 +119,10 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne predict_text_extents(params->workspaces_walk->ucs2_name, params->workspaces_walk->name_glyphs); - printf("Got Workspace %s, name_width: %d, glyphs: %d\n", - params->workspaces_walk->name, - params->workspaces_walk->name_width, - params->workspaces_walk->name_glyphs); + DLOG("Got Workspace %s, name_width: %d, glyphs: %d\n", + params->workspaces_walk->name, + params->workspaces_walk->name_width, + params->workspaces_walk->name_glyphs); FREE(params->cur_key); return 1; @@ -184,7 +184,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); if (params->cur_key == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } strncpy(params->cur_key, (const char*) keyVal, keyLen); @@ -238,7 +238,7 @@ void parse_workspaces_json(char *json) { case yajl_status_client_canceled: case yajl_status_insufficient_data: case yajl_status_error: - printf("ERROR: Could not parse workspaces-reply!\n"); + ELOG("Could not parse workspaces-reply!\n"); exit(EXIT_FAILURE); break; } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 87829503..e1669061 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -69,7 +69,7 @@ ev_io *xkb_io; int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("%s:%d - %s. X Error Code: %d", __FILE__, line, err_msg, err->error_code); + ELOG("%s. X Error Code: %d\n", err_msg, err->error_code); return err->error_code; } return 0; @@ -235,7 +235,7 @@ void unhide_bars() { values[2] = walk->rect.w; values[3] = font_height + 6; values[4] = XCB_STACK_MODE_ABOVE; - printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); + DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); cookie = xcb_configure_window_checked(xcb_connection, walk->bar, mask, @@ -267,11 +267,11 @@ void handle_button(xcb_button_press_event_t *event) { } if (walk == NULL) { - printf("Unknown Bar klicked!\n"); + DLOG("Unknown Bar klicked!\n"); return; } - /* TODO: Move this to exern get_ws_for_output() */ + /* TODO: Move this to extern get_ws_for_output() */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { if (cur_ws->visible) { break; @@ -279,20 +279,20 @@ void handle_button(xcb_button_press_event_t *event) { } if (cur_ws == NULL) { - printf("No Workspace active?\n"); + DLOG("No Workspace active?\n"); return; } int32_t x = event->event_x; - printf("Got Button %d\n", event->detail); + DLOG("Got Button %d\n", event->detail); switch (event->detail) { case 1: /* Left Mousbutton. We determine, which button was clicked * and set cur_ws accordingly */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { - printf("x = %d\n", x); + DLOG("x = %d\n", x); if (x < cur_ws->name_width + 10) { break; } @@ -375,18 +375,18 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { XkbEvent ev; int modstate; - printf("Got XKB-Event!\n"); + DLOG("Got XKB-Event!\n"); while (XPending(xkb_dpy)) { XNextEvent(xkb_dpy, (XEvent*)&ev); if (ev.type != xkb_event_base) { - printf("ERROR: No Xkb-Event!\n"); + ELOG("No Xkb-Event!\n"); continue; } if (ev.any.xkb_type != XkbStateNotify) { - printf("ERROR: No State Notify!\n"); + ELOG("No State Notify!\n"); continue; } @@ -396,10 +396,10 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { if (modstate != mod_pressed) { if (modstate == 0) { - printf("Mod4 got released!\n"); + DLOG("Mod4 got released!\n"); hide_bars(); } else { - printf("Mod4 got pressed!\n"); + DLOG("Mod4 got pressed!\n"); unhide_bars(); } mod_pressed = modstate; @@ -414,10 +414,10 @@ void init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); if (xcb_connection_has_error(xcb_connection)) { - printf("Cannot open display\n"); + ELOG("Cannot open display\n"); exit(EXIT_FAILURE); } - printf("Connected to xcb\n"); + DLOG("Connected to xcb\n"); /* We have to request the atoms we need */ #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); @@ -456,23 +456,23 @@ void init_xcb(char *fontname) { &xkb_err); if (xkb_dpy == NULL) { - printf("ERROR: No XKB!\n"); + ELOG("No XKB!\n"); exit(EXIT_FAILURE); } if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); + ELOG("Could not set FD_CLOEXEC on xkbdpy\n"); exit(EXIT_FAILURE); } int i1; if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { - printf("ERROR: XKB not supported by X-server!\n"); + ELOG("XKB not supported by X-server!\n"); exit(EXIT_FAILURE); } if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - printf("Could not grab Key!\n"); + ELOG("Could not grab Key!\n"); exit(EXIT_FAILURE); } @@ -532,7 +532,7 @@ void init_xcb(char *fontname) { font_table = xcb_query_font_char_infos(font_info); } - printf("Calculated Font-height: %d\n", font_height); + DLOG("Calculated Font-height: %d\n", font_height); if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); @@ -571,14 +571,14 @@ void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ if (reply == NULL) { \ - printf("ERROR: Could not get atom %s\n", #name); \ + ELOG("Could not get atom %s\n", #name); \ exit(EXIT_FAILURE); \ } \ atoms[name] = reply->atom; \ free(reply); #include "xcb_atoms.def" - printf("Got Atoms\n"); + DLOG("Got Atoms\n"); } /* @@ -609,12 +609,12 @@ void reconfig_windows() { if (!walk->active) { /* If an output is not active, we destroy it's bar */ /* FIXME: Maybe we rather want to unmap? */ - printf("Destroying window for output %s\n", walk->name); + DLOG("Destroying window for output %s\n", walk->name); destroy_window(walk); continue; } if (walk->bar == XCB_NONE) { - printf("Creating Window for output %s\n", walk->name); + DLOG("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); walk->buffer = xcb_generate_id(xcb_connection); @@ -690,7 +690,7 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; values[4] = XCB_STACK_MODE_ABOVE; - printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); + DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, walk->bar, mask, @@ -707,7 +707,7 @@ void reconfig_windows() { * */ void draw_bars() { - printf("Drawing Bars...\n"); + DLOG("Drawing Bars...\n"); int i = 0; refresh_statusline(); @@ -715,7 +715,7 @@ void draw_bars() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { if (!outputs_walk->active) { - printf("Output %s inactive, skipping...\n", outputs_walk->name); + DLOG("Output %s inactive, skipping...\n", outputs_walk->name); continue; } if (outputs_walk->bar == XCB_NONE) { @@ -736,7 +736,7 @@ void draw_bars() { &rect); if (statusline != NULL) { - printf("Printing statusline!\n"); + DLOG("Printing statusline!\n"); /* Luckily we already prepared a seperate pixmap containing the rendered * statusline, we just have to copy the relevant parts to the relevant @@ -752,13 +752,13 @@ void draw_bars() { i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { - printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); + DLOG("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); uint32_t color = get_colorpixel("240000"); if (ws_walk->visible) { color = get_colorpixel("480000"); } if (ws_walk->urgent) { - printf("WS %s is urgent!\n", ws_walk->name); + DLOG("WS %s is urgent!\n", ws_walk->name); color = get_colorpixel("002400"); /* The urgent-hint should get noticed, so we unhide the bars shortly */ unhide_bars(); From 27fa078159f5c4301bb594686015a1964e525ae3 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 18:27:07 +0200 Subject: [PATCH 067/185] Adding a manpage --- i3bar/Makefile | 12 +++++++-- i3bar/doc/Makefile | 7 ++++++ i3bar/doc/i3bar.man | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 i3bar/doc/Makefile create mode 100644 i3bar/doc/i3bar.man diff --git a/i3bar/Makefile b/i3bar/Makefile index 57af15e1..8f124493 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -6,10 +6,17 @@ FILES:=$(wildcard src/*.c) FILES:=$(FILES:.c=.o) HEADERS:=$(wildcard include/*.h) -all: ${FILES} +all: i3bar doc + +i3bar: ${FILES} echo "LINK" $(CC) -o i3bar ${FILES} ${LDFLAGS} +doc: + echo "" + echo "SUBDIR doc" + $(MAKE) -C doc + src/%.o: src/%.c ${HEADERS} echo "CC $<" $(CC) $(CFLAGS) -c -o $@ $< @@ -21,5 +28,6 @@ install: all clean: rm src/*.o + make -C doc clean -.PHONY: install clean +.PHONY: install clean doc diff --git a/i3bar/doc/Makefile b/i3bar/doc/Makefile new file mode 100644 index 00000000..f363207c --- /dev/null +++ b/i3bar/doc/Makefile @@ -0,0 +1,7 @@ +all: i3bar.1 + +i3bar.1: i3bar.man + echo "A2X i3bar" + a2x -f manpage i3bar.man +clean: + rm -f i3bar.xml i3bar.1 i3bar.html diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man new file mode 100644 index 00000000..dc094ae6 --- /dev/null +++ b/i3bar/doc/i3bar.man @@ -0,0 +1,61 @@ +i3bar(1) +======== +Axel Wagner +v0.5, September 2010 + +== NAME + +i3bar - xcb-based status- and ws-bar + +== SYNOPSIS + +*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*] [*-f* 'font'] [*-V*] [*-h*] + +== OPTIONS + +*-s, --socket* 'sock_path':: +Specifies the 'socketpath', via which *i3bar* connects to *i3*(1). If *i3bar* can not connect to *i3*, it will exit. Defaults to '~/.i3/ipc.sock' + +*-c, --command* 'command':: +Execute '' to get 'stdin'. You can also simply pipe into 'stdin', but starting the coomand for itself, *i3bar* is able to send 'SIGCONT' and 'SIGSTOP', when combined with *-m* + +*-m, --hide*:: +Hide the bar, when 'mod4' is not pressed. With this, dockmode will not be set, and the bar is out of the way most of the time so you have more room. +If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars + +*-f, --font* 'font':: +Specifies a 'X-core-font' to use. You can choose one with *xfontsel*(1). Defaults to '-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1'. + +*-V, --verbose*:: +Be (very) verbose with the debug-output. If not set, only errors are reported to 'stderr' + +*-h, --help*:: +Display a short help-message and exit + +== DESCRIPTION + +*i3bar* is an xcb- and libev-based status- and ws-bar. It is best thought of as an replacement for the *i3-wsbar*(1) + *dzen2*(1)-combination. It creates a workspace-bar for every active output ("screen") and displays a piped in statusline rightaligned on every bar. + +It does not sample any status-information itself, so you still need a program like *i3status*(1) or *conky*(1) for that. + +i3bar does not support any color or other markups, so stdin should be plain utf8, one line at a time. If you use *i3status*(1), you therefore should specify 'output_format = none' in the general-section of it's configfile. + +Also, you should disable the internal workspace bar of *i3*(1), when using *i3bar* by specifying 'workspace_bar no' in your *i3*-configfile. + +== EXAMPLES + +To get a docked bar with some statusinformation, you use + +*i3status | i3bar* + +If you want it to hide when not needed, you should instead use + +*i3bar -c i3status -m* + +== SEE ALSO + ++i3(1)+, +i3-wsbar(1)+, +dzen2(1)+, +i3status(1)+ + +== AUTHORS + +Axel Wagner and contributors From cddda0c965e008670037b45de22828dc7ee0bcb9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 22 Oct 2010 00:30:09 +0200 Subject: [PATCH 068/185] Remove unnecessary dependencies --- i3bar/common.mk | 1 - i3bar/src/xcb.c | 1 - 2 files changed, 2 deletions(-) diff --git a/i3bar/common.mk b/i3bar/common.mk index 1df1f6fb..3d44b028 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -14,7 +14,6 @@ CFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" LDFLAGS += -lev LDFLAGS += -lyajl LDFLAGS += -lxcb -LDFLAGS += -lxcb-atom LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e1669061..9ae3873f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include From 4830288c7b416bbeebf4f1d53fffaafa239587fe Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 24 Oct 2010 22:56:08 +0200 Subject: [PATCH 069/185] Place bar at the bottom of the screen, when creating them --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 9ae3873f..31d9771c 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -629,7 +629,7 @@ void reconfig_windows() { xcb_screen->root_depth, walk->bar, xcb_root, - walk->rect.x, walk->rect.y, + walk->rect.x, walk->rect.y + walk->rect.h - font_height - 6, walk->rect.w, font_height + 6, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, From 80172c88c5515cfd9938dcea7f0fc3e031d8689e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 24 Oct 2010 23:03:44 +0200 Subject: [PATCH 070/185] Don't map bars on creation, if hide_on_modifier is enabled --- i3bar/src/xcb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 31d9771c..38ee5bd9 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -667,14 +667,17 @@ void reconfig_windows() { mask, values); - /* We finally map the bar (display it on screen) */ - xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + /* We finally map the bar (display it on screen), unless the modifier-switch is on */ + xcb_void_cookie_t map_cookie; + if (!config.hide_on_modifier) { + map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + } if (xcb_request_failed(win_cookie, "Could not create window") || xcb_request_failed(pm_cookie, "Could not create pixmap") || xcb_request_failed(prop_cookie, "Could not set dock mode") || xcb_request_failed(gc_cookie, "Could not create graphical context") || - xcb_request_failed(map_cookie, "Could not map window")) { + (!config.hide_on_modifier && xcb_request_failed(map_cookie, "Could not map window"))) { exit(EXIT_FAILURE); } } else { From 73728f519bd70a65aa10f73f31e22bb18f5c669e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 24 Oct 2010 01:29:54 -0200 Subject: [PATCH 071/185] Added a distclean target. --- i3bar/Makefile | 8 ++++++-- i3bar/doc/Makefile | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index 8f124493..d4cc59b9 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -27,7 +27,11 @@ install: all $(INSTALL) -m 0755 i3bar $(DESTDIR)$(PREFIX)/bin clean: - rm src/*.o + rm -f src/*.o make -C doc clean -.PHONY: install clean doc +distclean: clean + rm -f i3bar + make -C doc distclean + +.PHONY: install clean distclean doc diff --git a/i3bar/doc/Makefile b/i3bar/doc/Makefile index f363207c..a8144cd8 100644 --- a/i3bar/doc/Makefile +++ b/i3bar/doc/Makefile @@ -5,3 +5,5 @@ i3bar.1: i3bar.man a2x -f manpage i3bar.man clean: rm -f i3bar.xml i3bar.1 i3bar.html + +distclean: clean From 6376cf99d29aa8d2fa30a3f0e3c5deea0b94bf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 24 Oct 2010 01:24:51 -0200 Subject: [PATCH 072/185] Custom colors can be set from the command line. --- i3bar/include/xcb.h | 30 ++++++++++++++ i3bar/src/main.c | 98 ++++++++++++++++++++++++++++++++++++++++----- i3bar/src/xcb.c | 41 +++++++++++++++---- 3 files changed, 152 insertions(+), 17 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 75402285..83c65a55 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -9,12 +9,42 @@ #ifndef XCB_H_ #define XCB_H_ +#include + +struct colors_t { + char *bar_fg; + char *bar_bg; + char *active_ws_fg; + char *active_ws_bg; + char *inactive_ws_fg; + char *inactive_ws_bg; + char *urgent_ws_bg; + char *urgent_ws_fg; +}; + +struct parsed_colors_t { + uint32_t bar_fg; + uint32_t bar_bg; + uint32_t active_ws_fg; + uint32_t active_ws_bg; + uint32_t inactive_ws_fg; + uint32_t inactive_ws_bg; + uint32_t urgent_ws_bg; + uint32_t urgent_ws_fg; +}; + /* * Initialize xcb and use the specified fontname for text-rendering * */ void init_xcb(); +/* + * Initialize the colors + * + */ +void init_colors(const struct colors_t *colors); + /* * Cleanup the xcb-stuff. * Called once, before the program terminates. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 5b6debc5..e081d880 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -37,6 +37,49 @@ char *expand_path(char *path) { return result; } +static void read_color(char **color) +{ + int len = strlen(optarg); + if (len == 6 || (len == 7 && optarg[0] == '#')) { + int offset = len - 6; + int good = 1, i; + for (i = offset; good && i < 6 + offset; ++i) { + char c = optarg[i]; + if (!(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F') + && !(c >= '0' && c <= '9')) { + good = 0; + break; + } + } + if (good) { + *color = strdup(optarg + offset); + return; + } + } + + fprintf(stderr, "Bad color value \"%s\"\n", optarg); + exit(EXIT_FAILURE); +} + +static void free_colors(struct colors_t *colors) +{ +#define FREE_COLOR(x) \ + do { \ + if (colors->x) \ + free(colors->x); \ + } while (0) + FREE_COLOR(bar_fg); + FREE_COLOR(bar_bg); + FREE_COLOR(active_ws_fg); + FREE_COLOR(active_ws_bg); + FREE_COLOR(inactive_ws_fg); + FREE_COLOR(inactive_ws_bg); + FREE_COLOR(urgent_ws_fg); + FREE_COLOR(urgent_ws_bg); +#undef FREE_COLOR +} + void print_usage(char *elf_name) { printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); @@ -56,22 +99,31 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; + struct colors_t colors = {0,}; /* Definition of the standard-config */ config.hide_on_modifier = 0; static struct option long_opt[] = { - { "socket", required_argument, 0, 's' }, - { "command", required_argument, 0, 'c' }, - { "hide", no_argument, 0, 'm' }, - { "font", required_argument, 0, 'f' }, - { "help", no_argument, 0, 'h' }, - { "version", no_argument, 0, 'v' }, - { "verbose", no_argument, 0, 'V' }, - { NULL, 0, 0, 0} + { "socket", required_argument, 0, 's' }, + { "command", required_argument, 0, 'c' }, + { "hide", no_argument, 0, 'm' }, + { "font", required_argument, 0, 'f' }, + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { "verbose", no_argument, 0, 'V' }, + { "color-bar-fg", required_argument, 0, 'A' }, + { "color-bar-bg", required_argument, 0, 'B' }, + { "color-active-ws-fg", required_argument, 0, 'C' }, + { "color-active-ws-bg", required_argument, 0, 'D' }, + { "color-inactive-ws-fg", required_argument, 0, 'E' }, + { "color-inactive-ws-bg", required_argument, 0, 'F' }, + { "color-urgent-ws-bg", required_argument, 0, 'G' }, + { "color-urgent-ws-fg", required_argument, 0, 'H' }, + { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hvV", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvV:A:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -92,6 +144,30 @@ int main(int argc, char **argv) { case 'V': config.verbose = 1; break; + case 'A': + read_color(&colors.bar_fg); + break; + case 'B': + read_color(&colors.bar_bg); + break; + case 'C': + read_color(&colors.active_ws_fg); + break; + case 'D': + read_color(&colors.active_ws_bg); + break; + case 'E': + read_color(&colors.inactive_ws_fg); + break; + case 'F': + read_color(&colors.inactive_ws_bg); + break; + case 'G': + read_color(&colors.urgent_ws_fg); + break; + case 'H': + read_color(&colors.urgent_ws_bg); + break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); @@ -114,6 +190,10 @@ int main(int argc, char **argv) { main_loop = ev_default_loop(0); init_xcb(fontname); + + init_colors(&colors); + free_colors(&colors); + init_outputs(); init_connection(socket_path); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 38ee5bd9..41f221cf 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -63,6 +63,9 @@ ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* The parsed colors */ +struct parsed_colors_t colors; + /* We define xcb_request_failed as a macro to include the relevant line-number */ #define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { @@ -247,6 +250,26 @@ void unhide_bars() { } } +/* + * Parse the colors into a format that we can use + * + */ +void init_colors(const struct colors_t *new_colors) { +#define PARSE_COLOR(name, def) \ + do { \ + colors.name = get_colorpixel(new_colors->name ? new_colors->name : def); \ + } while (0) + PARSE_COLOR(bar_fg, "FFFFFF"); + PARSE_COLOR(bar_bg, "000000"); + PARSE_COLOR(active_ws_fg, "FFFFFF"); + PARSE_COLOR(active_ws_bg, "480000"); + PARSE_COLOR(inactive_ws_fg, "FFFFFF"); + PARSE_COLOR(inactive_ws_bg, "240000"); + PARSE_COLOR(urgent_ws_fg, "FFFFFF"); + PARSE_COLOR(urgent_ws_bg, "002400"); +#undef PARSE_COLOR +} + /* * Handle a button-press-event (i.c. a mouse click on one of our bars). * We determine, wether the click occured on a ws-button or if the scroll- @@ -725,7 +748,7 @@ void draw_bars() { reconfig_windows(); } /* First things first: clear the backbuffer */ - uint32_t color = get_colorpixel("000000"); + uint32_t color = colors.bar_bg; xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, @@ -755,35 +778,37 @@ void draw_bars() { i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { DLOG("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); - uint32_t color = get_colorpixel("240000"); + uint32_t fg_color = colors.inactive_ws_fg; + uint32_t bg_color = colors.inactive_ws_bg; if (ws_walk->visible) { - color = get_colorpixel("480000"); + fg_color = colors.active_ws_fg; + bg_color = colors.active_ws_bg; } if (ws_walk->urgent) { DLOG("WS %s is urgent!\n", ws_walk->name); - color = get_colorpixel("002400"); + fg_color = colors.urgent_ws_fg; + bg_color = colors.urgent_ws_bg; /* The urgent-hint should get noticed, so we unhide the bars shortly */ unhide_bars(); } xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, - &color); + &bg_color); xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_BACKGROUND, - &color); + &bg_color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, outputs_walk->buffer, outputs_walk->bargc, 1, &rect); - color = get_colorpixel("FFFFFF"); xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, - &color); + &fg_color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, outputs_walk->buffer, From 992612c89d33d82eaa118e7ca7faf24735ff4a6e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 12:27:10 +0100 Subject: [PATCH 073/185] Some stylechanges to previous commit --- i3bar/include/common.h | 2 +- i3bar/include/config.h | 9 ++++++--- i3bar/include/xcb.h | 16 ++++------------ i3bar/src/main.c | 8 +++----- i3bar/src/xcb.c | 14 ++++++++++++-- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index e885ddcd..4ad33703 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -24,12 +24,12 @@ struct rect_t { #include "queue.h" #include "child.h" -#include "config.h" #include "ipc.h" #include "outputs.h" #include "util.h" #include "workspaces.h" #include "xcb.h" #include "ucs2_to_utf8.h" +#include "config.h" #endif diff --git a/i3bar/include/config.h b/i3bar/include/config.h index 0496f431..2dd0f532 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -1,9 +1,12 @@ #ifndef CONFIG_H_ -#define CONFIL_H_ +#define CONFIG_H_ + +#include "common.h" typedef struct config_t { - int hide_on_modifier; - int verbose; + int hide_on_modifier; + int verbose; + xcb_colors_t *colors; } config_t; config_t config; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 83c65a55..5ace4f0b 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -10,8 +10,9 @@ #define XCB_H_ #include +//#include "outputs.h" -struct colors_t { +struct xcb_color_strings_t { char *bar_fg; char *bar_bg; char *active_ws_fg; @@ -22,16 +23,7 @@ struct colors_t { char *urgent_ws_fg; }; -struct parsed_colors_t { - uint32_t bar_fg; - uint32_t bar_bg; - uint32_t active_ws_fg; - uint32_t active_ws_bg; - uint32_t inactive_ws_fg; - uint32_t inactive_ws_bg; - uint32_t urgent_ws_bg; - uint32_t urgent_ws_fg; -}; +typedef struct xcb_colors_t xcb_colors_t; /* * Initialize xcb and use the specified fontname for text-rendering @@ -43,7 +35,7 @@ void init_xcb(); * Initialize the colors * */ -void init_colors(const struct colors_t *colors); +void init_colors(const struct xcb_color_strings_t *colors); /* * Cleanup the xcb-stuff. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index e081d880..e50bcc40 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -37,8 +37,7 @@ char *expand_path(char *path) { return result; } -static void read_color(char **color) -{ +static void read_color(char **color) { int len = strlen(optarg); if (len == 6 || (len == 7 && optarg[0] == '#')) { int offset = len - 6; @@ -62,8 +61,7 @@ static void read_color(char **color) exit(EXIT_FAILURE); } -static void free_colors(struct colors_t *colors) -{ +static void free_colors(struct xcb_color_strings_t *colors) { #define FREE_COLOR(x) \ do { \ if (colors->x) \ @@ -99,7 +97,7 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; - struct colors_t colors = {0,}; + struct xcb_color_strings_t colors = { NULL, }; /* Definition of the standard-config */ config.hide_on_modifier = 0; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 41f221cf..bf679b5d 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,7 +64,17 @@ ev_io *xcb_io; ev_io *xkb_io; /* The parsed colors */ -struct parsed_colors_t colors; +struct xcb_colors_t { + uint32_t bar_fg; + uint32_t bar_bg; + uint32_t active_ws_fg; + uint32_t active_ws_bg; + uint32_t inactive_ws_fg; + uint32_t inactive_ws_bg; + uint32_t urgent_ws_bg; + uint32_t urgent_ws_fg; +}; +struct xcb_colors_t colors; /* We define xcb_request_failed as a macro to include the relevant line-number */ #define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) @@ -254,7 +264,7 @@ void unhide_bars() { * Parse the colors into a format that we can use * */ -void init_colors(const struct colors_t *new_colors) { +void init_colors(const struct xcb_color_strings_t *new_colors) { #define PARSE_COLOR(name, def) \ do { \ colors.name = get_colorpixel(new_colors->name ? new_colors->name : def); \ From 214382a0307e2b2318d09d5be1c715eaf77d635b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 12:43:33 +0100 Subject: [PATCH 074/185] Mention the color-options in the manpage --- i3bar/.gitignore | 1 + i3bar/doc/i3bar.man | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/i3bar/.gitignore b/i3bar/.gitignore index 01e7ad61..6aad070b 100644 --- a/i3bar/.gitignore +++ b/i3bar/.gitignore @@ -1,3 +1,4 @@ i3bar *.o core +doc/i3bar.1 diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index dc094ae6..c41371b8 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -42,6 +42,18 @@ i3bar does not support any color or other markups, so stdin should be plain utf8 Also, you should disable the internal workspace bar of *i3*(1), when using *i3bar* by specifying 'workspace_bar no' in your *i3*-configfile. +== COLORS + +*i3bar* does not yet support formatting in the displayed statusline. However it does support setting colors for the bar, the workspace-buttons and the statusline. + +For now this happens with the following command-line-options: + +*--color-bar-fg, --color-bar-bg, --color-active-ws-fg, --color-active-ws-bg, --color-inactive-ws-fg, --color-inactive-ws-bg, color-urgent-ws-bg, color-urgent-ws-fg* + +For each specified option you need to give a HEX-colorcode. + +Be advised that this command-line-options are only temporary and are very likely to be removed, when we finally have a config-file. + == EXAMPLES To get a docked bar with some statusinformation, you use From 127c082e83e5622540905e56d9300cb0bf276208 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 13:46:33 +0100 Subject: [PATCH 075/185] Call init_colors() earlier --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index e50bcc40..9b6f9e12 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -187,9 +187,9 @@ int main(int argc, char **argv) { main_loop = ev_default_loop(0); + init_colors(&colors); init_xcb(fontname); - init_colors(&colors); free_colors(&colors); init_outputs(); From 23b62f621dc3f3ccfe57794f67fa16b530f3e694 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 13:46:50 +0100 Subject: [PATCH 076/185] Add support for bar_fg and bar_bg --- i3bar/src/xcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index bf679b5d..326ca2ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -520,7 +520,7 @@ void init_xcb(char *fontname) { uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; - uint32_t vals[3] = { xcb_screen->white_pixel, xcb_screen->black_pixel, xcb_font }; + uint32_t vals[3] = { colors.bar_fg, colors.bar_bg, xcb_font }; xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, @@ -652,7 +652,7 @@ void reconfig_windows() { walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ - values[0] = xcb_screen->black_pixel; + values[0] = colors.bar_bg; /* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */ values[1] = config.hide_on_modifier; /* The events we want to receive */ From eada4837658e60d9819480bcb49d5ad42cec5caa Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 10 Nov 2010 18:46:47 +0100 Subject: [PATCH 077/185] Double-fork() to avoid zombies --- i3bar/src/child.c | 51 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index fa70f452..3f927b45 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -100,41 +101,67 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { /* * Start a child-process with the specified command and reroute stdin. * We actually start a $SHELL to execute the command so we don't have to care - * about arguments and such + * about arguments and such. + * We also double-fork() to avoid zombies and pass the pid of the child through a + * temporary pipe back to i3bar * */ void start_child(char *command) { child_pid = 0; if (command != NULL) { - int fd[2]; + int fd[2], tmp[2]; + /* This pipe will be used to communicate between e.g. i3status and i3bar */ pipe(fd); - child_pid = fork(); - switch (child_pid) { + /* We also need this temporary pipe to get back the pid of i3status */ + pipe(tmp); + switch (fork()) { case -1: ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: - /* Child-process. Reroute stdout and start shell */ - close(fd[0]); + /* Double-fork(), so the child gets reparented to init */ + switch(child_pid = fork()) { + case -1: + ELOG("Couldn't fork() twice\n"); + exit(EXIT_FAILURE); + case 0: + /* Child-process. Reroute stdout and start shell */ + close(fd[0]); - dup2(fd[1], STDOUT_FILENO); + dup2(fd[1], STDOUT_FILENO); - static const char *shell = NULL; + static const char *shell = NULL; - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - execl(shell, shell, "-c", command, (char*) NULL); - return; + execl(shell, shell, "-c", command, (char*) NULL); + return; + default: + /* Temporary parent. We tell i3bar about the pid of i3status and exit */ + write(tmp[1], &child_pid, sizeof(int)); + close(tmp[0]); + close(tmp[1]); + exit(EXIT_SUCCESS); + } default: /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); + /* We also need to get the pid of i3status from the temporary pipe */ + size_t rec = 0; + while (rec < sizeof(int)) { + rec += read(tmp[0], &child_pid, sizeof(int) - rec); + } + /* The temporary pipe is no longer needed */ + close(tmp[0]); + close(tmp[1]); break; } } + wait(0); /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); From d5e3b58d479f73cbdec4e7cb8b19e9dbead7837f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:37:50 +0100 Subject: [PATCH 078/185] -V actually does not take an argument (yet) --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 9b6f9e12..22c85cc0 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -121,7 +121,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hvV:A:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvVA:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); From 33202881c4123084ba3eae98e33dc4378bd0fd5c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:47:30 +0100 Subject: [PATCH 079/185] Handle SIGTERM/-INT/-HUP --- i3bar/src/main.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 22c85cc0..6624f2ff 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -90,6 +90,26 @@ void print_usage(char *elf_name) { printf("-h\t\tDisplay this help-message and exit\n"); } +/* + * We watch various signals, that are there to make our application stop. + * If we get one of those, we ev_unloop() and invoke the cleanup-routines + * in main() with that + * + */ +void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { + switch (watcher->signum) { + case SIGTERM: + DLOG("Got a SIGTERM, stopping\n"); + break; + case SIGINT: + DLOG("Got a SIGINT, stopping\n"); + break; + case SIGHUP: + DLOG("Got a SIGHUP, stopping\n"); + } + ev_unloop(main_loop, EVUNLOOP_ALL); +} + int main(int argc, char **argv) { int opt; int option_index = 0; @@ -210,6 +230,19 @@ int main(int argc, char **argv) { * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. + * We only need those watchers on the stack, so putting them on the stack saves us + * some calls to free() */ + ev_signal sig_term, sig_quit, sig_int, sig_hup; + + ev_signal_init(&sig_term, &sig_cb, SIGTERM); + ev_signal_init(&sig_int, &sig_cb, SIGINT); + ev_signal_init(&sig_hup, &sig_cb, SIGHUP); + + ev_signal_start(main_loop, &sig_term); + ev_signal_start(main_loop, &sig_int); + ev_signal_start(main_loop, &sig_hup); + /* From here on everything should run smooth for itself, just start listening for * events. We stop simply stop the event-loop, when we are finished */ ev_loop(main_loop, 0); From 8301d3d9f3f00a13c38eb90f91c76bb8b3adf605 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:59:17 +0100 Subject: [PATCH 080/185] Send a SIGTERM instead of a SIGQUIT to exit the child --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 3f927b45..08d2bed9 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -184,7 +184,7 @@ void start_child(char *command) { */ void kill_child() { if (child_pid != 0) { - kill(child_pid, SIGQUIT); + kill(child_pid, SIGTERM); } cleanup(); } From a88f7fb392828493fd1c44adbeb76a07afa49ab5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 03:01:40 +0100 Subject: [PATCH 081/185] We don't need sig_quit --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 6624f2ff..35ea9210 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -233,7 +233,7 @@ int main(int argc, char **argv) { /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us * some calls to free() */ - ev_signal sig_term, sig_quit, sig_int, sig_hup; + ev_signal sig_term, sig_int, sig_hup; ev_signal_init(&sig_term, &sig_cb, SIGTERM); ev_signal_init(&sig_int, &sig_cb, SIGINT); From 3de12beef6ffacd252c5cc5d365969436311940d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 22 Nov 2010 00:07:52 +0100 Subject: [PATCH 082/185] make i3bar work with tree branch again (current_workspace is a string now) --- i3bar/src/outputs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 3577d82b..20ff8276 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,22 @@ static int outputs_integer_cb(void *params_, long val) { static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { struct outputs_json_params *params = (struct outputs_json_params*) params_; + if (!strcmp(params->cur_key, "current_workspace")) { + char *copy = malloc(sizeof(const unsigned char) * (len + 1)); + strncpy(copy, (const char*) val, len); + copy[len] = '\0'; + + char *end; + errno = 0; + long parsed_num = strtol(copy, &end, 10); + if (errno == 0 && + (end && *end == '\0')) + params->outputs_walk->ws = parsed_num; + free(copy); + FREE(params->cur_key); + return 1; + } + if (strcmp(params->cur_key, "name")) { return 0; } From a3e37b059fafc5c1179bd656780935a2dded25df Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 3 Dec 2010 17:59:16 +0100 Subject: [PATCH 083/185] Switch back ws_fg and ws_bg (Thanks julien) --- i3bar/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 35ea9210..ec85d324 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -181,10 +181,10 @@ int main(int argc, char **argv) { read_color(&colors.inactive_ws_bg); break; case 'G': - read_color(&colors.urgent_ws_fg); + read_color(&colors.urgent_ws_bg); break; case 'H': - read_color(&colors.urgent_ws_bg); + read_color(&colors.urgent_ws_fg); break; default: print_usage(argv[0]); From 537851b92952c060ebae153046dfbcd6a5177ff1 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 3 Dec 2010 17:59:16 +0100 Subject: [PATCH 084/185] Switch back ws_fg and ws_bg (Thanks julien) --- i3bar/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 35ea9210..ec85d324 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -181,10 +181,10 @@ int main(int argc, char **argv) { read_color(&colors.inactive_ws_bg); break; case 'G': - read_color(&colors.urgent_ws_fg); + read_color(&colors.urgent_ws_bg); break; case 'H': - read_color(&colors.urgent_ws_bg); + read_color(&colors.urgent_ws_fg); break; default: print_usage(argv[0]); From 9912d7fdbbf3cd68d836f4f22700eb583de5d5e2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 23 Dec 2010 16:38:22 +0100 Subject: [PATCH 085/185] Update changelog and manpage --- i3bar/CHANGELOG | 11 ++++++++--- i3bar/doc/i3bar.man | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index 0106447e..b8030e43 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,8 +1,13 @@ +v0.6 +===== +- Add manpage +- Implement hide-on-modifier +- Custom colors can be set from the commandline +- Use double-buffering - Bugfix: Correctly render long text - Bugfix: Don't segfault on SIGCHILD -- Implement hide-on-modifier -- Use double-buffering - +- Bugfix: Double-fork() to avoid zombies +- Some minor bugfixes v0.5 ===== diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index c41371b8..9ee7f7ce 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -1,7 +1,7 @@ i3bar(1) ======== Axel Wagner -v0.5, September 2010 +v0.6, September 2010 == NAME From d0077fb483dbb82d390c856c00b147eb8867a9fb Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 23 Dec 2010 16:38:22 +0100 Subject: [PATCH 086/185] Update changelog and manpage --- i3bar/CHANGELOG | 11 ++++++++--- i3bar/doc/i3bar.man | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index 0106447e..b8030e43 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,8 +1,13 @@ +v0.6 +===== +- Add manpage +- Implement hide-on-modifier +- Custom colors can be set from the commandline +- Use double-buffering - Bugfix: Correctly render long text - Bugfix: Don't segfault on SIGCHILD -- Implement hide-on-modifier -- Use double-buffering - +- Bugfix: Double-fork() to avoid zombies +- Some minor bugfixes v0.5 ===== diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index c41371b8..9ee7f7ce 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -1,7 +1,7 @@ i3bar(1) ======== Axel Wagner -v0.5, September 2010 +v0.6, September 2010 == NAME From a39db9ae8264b54fbb638fe358bbebcde3e4ce96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 23 Dec 2010 16:50:48 +0100 Subject: [PATCH 087/185] Remove unnecessary declaration --- i3bar/src/xcb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 300ac859..326ca2ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -636,8 +636,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[5]; - xcb_generic_error_t *err; - i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { From f539f76e5b0647146d115f8cec48fd354015bcfa Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:34:54 +0100 Subject: [PATCH 088/185] Revert "Double-fork() to avoid zombies" This reverts commit a4eafae108b63f5df76eea2958aee8cf95cb1ad6. --- i3bar/src/child.c | 51 +++++++++++------------------------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 08d2bed9..7cd364e0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -101,67 +100,41 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { /* * Start a child-process with the specified command and reroute stdin. * We actually start a $SHELL to execute the command so we don't have to care - * about arguments and such. - * We also double-fork() to avoid zombies and pass the pid of the child through a - * temporary pipe back to i3bar + * about arguments and such * */ void start_child(char *command) { child_pid = 0; if (command != NULL) { - int fd[2], tmp[2]; - /* This pipe will be used to communicate between e.g. i3status and i3bar */ + int fd[2]; pipe(fd); - /* We also need this temporary pipe to get back the pid of i3status */ - pipe(tmp); - switch (fork()) { + child_pid = fork(); + switch (child_pid) { case -1: ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: - /* Double-fork(), so the child gets reparented to init */ - switch(child_pid = fork()) { - case -1: - ELOG("Couldn't fork() twice\n"); - exit(EXIT_FAILURE); - case 0: - /* Child-process. Reroute stdout and start shell */ - close(fd[0]); + /* Child-process. Reroute stdout and start shell */ + close(fd[0]); - dup2(fd[1], STDOUT_FILENO); + dup2(fd[1], STDOUT_FILENO); - static const char *shell = NULL; + static const char *shell = NULL; - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - execl(shell, shell, "-c", command, (char*) NULL); - return; - default: - /* Temporary parent. We tell i3bar about the pid of i3status and exit */ - write(tmp[1], &child_pid, sizeof(int)); - close(tmp[0]); - close(tmp[1]); - exit(EXIT_SUCCESS); - } + execl(shell, shell, "-c", command, (char*) NULL); + return; default: /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); - /* We also need to get the pid of i3status from the temporary pipe */ - size_t rec = 0; - while (rec < sizeof(int)) { - rec += read(tmp[0], &child_pid, sizeof(int) - rec); - } - /* The temporary pipe is no longer needed */ - close(tmp[0]); - close(tmp[1]); break; } } - wait(0); /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); From 29aaced9008d107a8c20c14d66e4710b78468c76 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:45:31 +0100 Subject: [PATCH 089/185] Send child a SIGCONT, so it reacts to SIGTERM (no zombies \o/) --- i3bar/src/child.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 7cd364e0..3092d527 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -157,6 +157,7 @@ void start_child(char *command) { */ void kill_child() { if (child_pid != 0) { + kill(child_pid, SIGCONT); kill(child_pid, SIGTERM); } cleanup(); From cdf56f16bf4199379c976bcb204b65450b86808d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:34:54 +0100 Subject: [PATCH 090/185] Revert "Double-fork() to avoid zombies" This reverts commit a4eafae108b63f5df76eea2958aee8cf95cb1ad6. --- i3bar/src/child.c | 51 +++++++++++------------------------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 08d2bed9..7cd364e0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -101,67 +100,41 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { /* * Start a child-process with the specified command and reroute stdin. * We actually start a $SHELL to execute the command so we don't have to care - * about arguments and such. - * We also double-fork() to avoid zombies and pass the pid of the child through a - * temporary pipe back to i3bar + * about arguments and such * */ void start_child(char *command) { child_pid = 0; if (command != NULL) { - int fd[2], tmp[2]; - /* This pipe will be used to communicate between e.g. i3status and i3bar */ + int fd[2]; pipe(fd); - /* We also need this temporary pipe to get back the pid of i3status */ - pipe(tmp); - switch (fork()) { + child_pid = fork(); + switch (child_pid) { case -1: ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: - /* Double-fork(), so the child gets reparented to init */ - switch(child_pid = fork()) { - case -1: - ELOG("Couldn't fork() twice\n"); - exit(EXIT_FAILURE); - case 0: - /* Child-process. Reroute stdout and start shell */ - close(fd[0]); + /* Child-process. Reroute stdout and start shell */ + close(fd[0]); - dup2(fd[1], STDOUT_FILENO); + dup2(fd[1], STDOUT_FILENO); - static const char *shell = NULL; + static const char *shell = NULL; - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - execl(shell, shell, "-c", command, (char*) NULL); - return; - default: - /* Temporary parent. We tell i3bar about the pid of i3status and exit */ - write(tmp[1], &child_pid, sizeof(int)); - close(tmp[0]); - close(tmp[1]); - exit(EXIT_SUCCESS); - } + execl(shell, shell, "-c", command, (char*) NULL); + return; default: /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); - /* We also need to get the pid of i3status from the temporary pipe */ - size_t rec = 0; - while (rec < sizeof(int)) { - rec += read(tmp[0], &child_pid, sizeof(int) - rec); - } - /* The temporary pipe is no longer needed */ - close(tmp[0]); - close(tmp[1]); break; } } - wait(0); /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); From ff0522fe95f9ac35754ac4a73d9d78195ebe6d05 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:45:31 +0100 Subject: [PATCH 091/185] Bugfix: Send child a SIGCONT, so it reacts to SIGTERM (no zombies \o/) --- i3bar/src/child.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 7cd364e0..3092d527 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -157,6 +157,7 @@ void start_child(char *command) { */ void kill_child() { if (child_pid != 0) { + kill(child_pid, SIGCONT); kill(child_pid, SIGTERM); } cleanup(); From b3970b36a53ee51ce029fc24f60968e2f46790bc Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 19:29:57 +0100 Subject: [PATCH 092/185] Bugfix: Recover from closed socket --- i3bar/CHANGELOG | 2 + i3bar/include/ipc.h | 6 +++ i3bar/src/ipc.c | 89 ++++++++++++++++++++++++++++++++------------- i3bar/src/main.c | 4 +- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index b8030e43..cbacfb99 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,3 +1,5 @@ +- Bugfix: Recover from closed socket + v0.6 ===== - Add manpage diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index 0eba64fa..ee273a45 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -18,6 +18,12 @@ */ int init_connection(const char *socket_path); +/* + * Destroy the connection to i3. + * + */ +void destroy_connection(); + /* * Sends a Message to i3. * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 0ddccc25..bd7de75e 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -19,30 +19,40 @@ #include "common.h" -ev_io *i3_connection; +ev_io i3_connection; +ev_timer reconn; + +const char *sock_path; typedef void(*handler_t)(char*); /* - * Get a connect to the IPC-interface of i3 and return a filedescriptor + * Retry to connect. * */ -int get_ipc_fd(const char *socket_path) { - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) { - ELOG("Could not create Socket!\n"); - exit(EXIT_FAILURE); +void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { + static int retries = 8; + if (init_connection(sock_path) == 0) { + if (retries == 0) { + ELOG("Retried 8 times - connection failed!\n"); + exit(EXIT_FAILURE); + } + retries--; + return; } + retries = 8; + ev_timer_stop(loop, w); + subscribe_events(); + reconfig_windows(); +} - 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) { - ELOG("Could not connct to i3!\n"); - exit(EXIT_FAILURE); - } - return sockfd; +/* + * Schedule a reconnect + * + */ +void reconnect() { + ev_timer_init(&reconn, retry_connection, 0.25, 0.25); + ev_timer_start(main_loop, &reconn); } /* @@ -144,8 +154,12 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } if (n == 0) { - ELOG("Nothing to read!\n"); - exit(EXIT_FAILURE); + /* EOF received. We try to recover a few times, because most likely + * i3 just restarted */ + ELOG("EOF received, try to recover...\n"); + destroy_connection(); + reconnect(); + return; } rec += n; } @@ -167,8 +181,12 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { - ELOG("Could not allocate memory!\n"); - exit(EXIT_FAILURE); + /* EOF received. We try to recover a few times, because most likely + * i3 just restarted */ + ELOG("EOF received, try to recover...\n"); + destroy_connection(); + reconnect(); + return; } rec = 0; @@ -234,7 +252,7 @@ int i3_send_msg(uint32_t type, const char *payload) { uint32_t written = 0; while (to_write > 0) { - int n = write(i3_connection->fd, buffer + written, to_write); + int n = write(i3_connection.fd, buffer + written, to_write); if (n == -1) { ELOG("write() failed!\n"); exit(EXIT_FAILURE); @@ -255,15 +273,36 @@ int i3_send_msg(uint32_t type, const char *payload) { * */ int init_connection(const char *socket_path) { - int sockfd = get_ipc_fd(socket_path); + sock_path = socket_path; + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) { + ELOG("Could not create Socket!\n"); + exit(EXIT_FAILURE); + } - i3_connection = malloc(sizeof(ev_io)); - ev_io_init(i3_connection, &got_data, sockfd, EV_READ); - ev_io_start(main_loop, i3_connection); + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_LOCAL; + strcpy(addr.sun_path, sock_path); + if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { + ELOG("Could not connct to i3!\n"); + reconnect(); + return 0; + } + ev_io_init(&i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, &i3_connection); return 1; } +/* + * Destroy the connection to i3. + */ +void destroy_connection() { + close(i3_connection.fd); + ev_io_stop(main_loop, &i3_connection); +} + /* * Subscribe to all the i3-events, we need * diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ec85d324..7f27bdac 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -215,8 +215,6 @@ int main(int argc, char **argv) { init_outputs(); init_connection(socket_path); - FREE(socket_path); - /* We subscribe to the i3-events we need */ subscribe_events(); @@ -249,6 +247,8 @@ int main(int argc, char **argv) { kill_child(); + FREE(socket_path); + FREE(statusline); clean_xcb(); From 3daab599cad45cb6b5b6c4576dae7e8b221ae153 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 19:29:57 +0100 Subject: [PATCH 093/185] Bugfix: Recover from closed socket --- i3bar/CHANGELOG | 2 + i3bar/include/ipc.h | 6 +++ i3bar/src/ipc.c | 89 ++++++++++++++++++++++++++++++++------------- i3bar/src/main.c | 4 +- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index b8030e43..cbacfb99 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,3 +1,5 @@ +- Bugfix: Recover from closed socket + v0.6 ===== - Add manpage diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index 0eba64fa..ee273a45 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -18,6 +18,12 @@ */ int init_connection(const char *socket_path); +/* + * Destroy the connection to i3. + * + */ +void destroy_connection(); + /* * Sends a Message to i3. * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 0ddccc25..bd7de75e 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -19,30 +19,40 @@ #include "common.h" -ev_io *i3_connection; +ev_io i3_connection; +ev_timer reconn; + +const char *sock_path; typedef void(*handler_t)(char*); /* - * Get a connect to the IPC-interface of i3 and return a filedescriptor + * Retry to connect. * */ -int get_ipc_fd(const char *socket_path) { - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) { - ELOG("Could not create Socket!\n"); - exit(EXIT_FAILURE); +void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { + static int retries = 8; + if (init_connection(sock_path) == 0) { + if (retries == 0) { + ELOG("Retried 8 times - connection failed!\n"); + exit(EXIT_FAILURE); + } + retries--; + return; } + retries = 8; + ev_timer_stop(loop, w); + subscribe_events(); + reconfig_windows(); +} - 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) { - ELOG("Could not connct to i3!\n"); - exit(EXIT_FAILURE); - } - return sockfd; +/* + * Schedule a reconnect + * + */ +void reconnect() { + ev_timer_init(&reconn, retry_connection, 0.25, 0.25); + ev_timer_start(main_loop, &reconn); } /* @@ -144,8 +154,12 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } if (n == 0) { - ELOG("Nothing to read!\n"); - exit(EXIT_FAILURE); + /* EOF received. We try to recover a few times, because most likely + * i3 just restarted */ + ELOG("EOF received, try to recover...\n"); + destroy_connection(); + reconnect(); + return; } rec += n; } @@ -167,8 +181,12 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { - ELOG("Could not allocate memory!\n"); - exit(EXIT_FAILURE); + /* EOF received. We try to recover a few times, because most likely + * i3 just restarted */ + ELOG("EOF received, try to recover...\n"); + destroy_connection(); + reconnect(); + return; } rec = 0; @@ -234,7 +252,7 @@ int i3_send_msg(uint32_t type, const char *payload) { uint32_t written = 0; while (to_write > 0) { - int n = write(i3_connection->fd, buffer + written, to_write); + int n = write(i3_connection.fd, buffer + written, to_write); if (n == -1) { ELOG("write() failed!\n"); exit(EXIT_FAILURE); @@ -255,15 +273,36 @@ int i3_send_msg(uint32_t type, const char *payload) { * */ int init_connection(const char *socket_path) { - int sockfd = get_ipc_fd(socket_path); + sock_path = socket_path; + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) { + ELOG("Could not create Socket!\n"); + exit(EXIT_FAILURE); + } - i3_connection = malloc(sizeof(ev_io)); - ev_io_init(i3_connection, &got_data, sockfd, EV_READ); - ev_io_start(main_loop, i3_connection); + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_LOCAL; + strcpy(addr.sun_path, sock_path); + if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { + ELOG("Could not connct to i3!\n"); + reconnect(); + return 0; + } + ev_io_init(&i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, &i3_connection); return 1; } +/* + * Destroy the connection to i3. + */ +void destroy_connection() { + close(i3_connection.fd); + ev_io_stop(main_loop, &i3_connection); +} + /* * Subscribe to all the i3-events, we need * diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ec85d324..7f27bdac 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -215,8 +215,6 @@ int main(int argc, char **argv) { init_outputs(); init_connection(socket_path); - FREE(socket_path); - /* We subscribe to the i3-events we need */ subscribe_events(); @@ -249,6 +247,8 @@ int main(int argc, char **argv) { kill_child(); + FREE(socket_path); + FREE(statusline); clean_xcb(); From 64d8d40b25e10151ed9e4df162b40d31799cca39 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:07:28 +0100 Subject: [PATCH 094/185] Use "*buffer == '\0'" instead of "strlen(buffer) == 0" (thanks dothebart) --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 3092d527..0209e4cb 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -74,7 +74,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } rec += n; } - if (strlen(buffer) == 0) { + if (*buffer == '\0') { FREE(buffer); return; } From 600c4ae95c129ac005689b7d6cf3c783e23682f7 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:07:28 +0100 Subject: [PATCH 095/185] Use "*buffer == '\0'" instead of "strlen(buffer) == 0" (thanks dothebart) --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 3092d527..0209e4cb 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -74,7 +74,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } rec += n; } - if (strlen(buffer) == 0) { + if (*buffer == '\0') { FREE(buffer); return; } From 08a5a2fdb056a5bb9675042b93b1111ea7ee6afe Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:19:17 +0100 Subject: [PATCH 096/185] Only use font_info after we know, the request succeded --- i3bar/src/xcb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 326ca2ad..5361f411 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -552,12 +552,13 @@ void init_xcb(char *fontname) { font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, NULL); - font_height = font_info->font_ascent + font_info->font_descent; if (xcb_request_failed(open_font_cookie, "Could not open font")) { exit(EXIT_FAILURE); } + font_height = font_info->font_ascent + font_info->font_descent; + if (xcb_query_font_char_infos_length(font_info) == 0) { font_table = NULL; } else { From b40b92122891d8c725364f352d4c8513625133c2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:19:55 +0100 Subject: [PATCH 097/185] Fix typo (thx julien) --- i3bar/src/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index bd7de75e..08cc2fd7 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -285,7 +285,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connct to i3!\n"); + ELOG("Could not connect to i3!\n"); reconnect(); return 0; } From 8f0518c5c55e6a37312bae0a324c519694298451 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:19:17 +0100 Subject: [PATCH 098/185] Only use font_info after we know, the request succeded --- i3bar/src/xcb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 326ca2ad..5361f411 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -552,12 +552,13 @@ void init_xcb(char *fontname) { font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, NULL); - font_height = font_info->font_ascent + font_info->font_descent; if (xcb_request_failed(open_font_cookie, "Could not open font")) { exit(EXIT_FAILURE); } + font_height = font_info->font_ascent + font_info->font_descent; + if (xcb_query_font_char_infos_length(font_info) == 0) { font_table = NULL; } else { From 4c7f131fc55a78783cd44dd598395bd5b312d882 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 15:19:55 +0100 Subject: [PATCH 099/185] Fix typo (thx julien) --- i3bar/src/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index bd7de75e..08cc2fd7 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -285,7 +285,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connct to i3!\n"); + ELOG("Could not connect to i3!\n"); reconnect(); return 0; } From 2aeea30cc71d79a4a4581f1325a86483ecbdde7a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 16:48:30 +0100 Subject: [PATCH 100/185] Use strerror() for more usefull errormessages --- i3bar/src/child.c | 4 ++-- i3bar/src/ipc.c | 15 ++++++++------- i3bar/src/main.c | 2 +- i3bar/src/workspaces.c | 3 ++- i3bar/src/xcb.c | 3 ++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 0209e4cb..48541185 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -59,7 +59,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer[rec-1] = '\0'; break; } - ELOG("read() failed!\n"); + ELOG("read() failed!: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -111,7 +111,7 @@ void start_child(char *command) { child_pid = fork(); switch (child_pid) { case -1: - ELOG("Couldn't fork()\n"); + ELOG("Couldn't fork(): %s\n", strerror(errno)); exit(EXIT_FAILURE); case 0: /* Child-process. Reroute stdout and start shell */ diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 08cc2fd7..ce9f52cd 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -140,7 +141,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { - ELOG("Could not allocate memory!\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -150,7 +151,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); if (n == -1) { - ELOG("read() failed!\n"); + ELOG("read() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -193,7 +194,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < size) { int n = read(fd, buffer + rec, size - rec); if (n == -1) { - ELOG("read() failed!\n"); + ELOG("read() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -234,7 +235,7 @@ int i3_send_msg(uint32_t type, const char *payload) { * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { - ELOG("Could not allocate memory\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -254,7 +255,7 @@ int i3_send_msg(uint32_t type, const char *payload) { while (to_write > 0) { int n = write(i3_connection.fd, buffer + written, to_write); if (n == -1) { - ELOG("write() failed!\n"); + ELOG("write() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -276,7 +277,7 @@ int init_connection(const char *socket_path) { sock_path = socket_path; int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { - ELOG("Could not create Socket!\n"); + ELOG("Could not create Socket: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -285,7 +286,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connect to i3!\n"); + ELOG("Could not connect to i3: %s\n", strerror(errno)); reconnect(); return 0; } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 7f27bdac..c2cf53e2 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -30,7 +30,7 @@ char *expand_path(char *path) { } char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); if (result == NULL) { - ELOG("malloc() failed\n"); + ELOG("malloc() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } globfree(&globbuf); diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 9f8acc1b..1e47bb81 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "common.h" @@ -184,7 +185,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); if (params->cur_key == NULL) { - ELOG("Could not allocate memory!\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } strncpy(params->cur_key, (const char*) keyVal, keyLen); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 5361f411..6f023b4f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -493,7 +494,7 @@ void init_xcb(char *fontname) { } if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - ELOG("Could not set FD_CLOEXEC on xkbdpy\n"); + ELOG("Could not set FD_CLOEXEC on xkbdpy: %s\n", strerror(errno)); exit(EXIT_FAILURE); } From 497a091fbbce5c93e5d2db75ddeb46d2131748ab Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 1 Jan 2011 16:48:30 +0100 Subject: [PATCH 101/185] Use strerror() for more usefull errormessages --- i3bar/src/child.c | 4 ++-- i3bar/src/ipc.c | 15 ++++++++------- i3bar/src/main.c | 2 +- i3bar/src/workspaces.c | 3 ++- i3bar/src/xcb.c | 3 ++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 0209e4cb..48541185 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -59,7 +59,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer[rec-1] = '\0'; break; } - ELOG("read() failed!\n"); + ELOG("read() failed!: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -111,7 +111,7 @@ void start_child(char *command) { child_pid = fork(); switch (child_pid) { case -1: - ELOG("Couldn't fork()\n"); + ELOG("Couldn't fork(): %s\n", strerror(errno)); exit(EXIT_FAILURE); case 0: /* Child-process. Reroute stdout and start shell */ diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 08cc2fd7..ce9f52cd 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -140,7 +141,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { - ELOG("Could not allocate memory!\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -150,7 +151,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); if (n == -1) { - ELOG("read() failed!\n"); + ELOG("read() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -193,7 +194,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < size) { int n = read(fd, buffer + rec, size - rec); if (n == -1) { - ELOG("read() failed!\n"); + ELOG("read() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (n == 0) { @@ -234,7 +235,7 @@ int i3_send_msg(uint32_t type, const char *payload) { * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { - ELOG("Could not allocate memory\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -254,7 +255,7 @@ int i3_send_msg(uint32_t type, const char *payload) { while (to_write > 0) { int n = write(i3_connection.fd, buffer + written, to_write); if (n == -1) { - ELOG("write() failed!\n"); + ELOG("write() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -276,7 +277,7 @@ int init_connection(const char *socket_path) { sock_path = socket_path; int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { - ELOG("Could not create Socket!\n"); + ELOG("Could not create Socket: %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -285,7 +286,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connect to i3!\n"); + ELOG("Could not connect to i3: %s\n", strerror(errno)); reconnect(); return 0; } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 7f27bdac..c2cf53e2 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -30,7 +30,7 @@ char *expand_path(char *path) { } char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); if (result == NULL) { - ELOG("malloc() failed\n"); + ELOG("malloc() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } globfree(&globbuf); diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 9f8acc1b..1e47bb81 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "common.h" @@ -184,7 +185,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); if (params->cur_key == NULL) { - ELOG("Could not allocate memory!\n"); + ELOG("Could not allocate memory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } strncpy(params->cur_key, (const char*) keyVal, keyLen); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 5361f411..6f023b4f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -493,7 +494,7 @@ void init_xcb(char *fontname) { } if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - ELOG("Could not set FD_CLOEXEC on xkbdpy\n"); + ELOG("Could not set FD_CLOEXEC on xkbdpy: %s\n", strerror(errno)); exit(EXIT_FAILURE); } From 2183435da6eaf5f2d97ef946c6f0224df359c606 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 6 Jan 2011 17:28:21 +0100 Subject: [PATCH 102/185] Bugfix: Recreate double-buffers on reconfiguring (thx sECuRE) --- i3bar/src/xcb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6f023b4f..0cb1201a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -727,14 +727,30 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; values[4] = XCB_STACK_MODE_ABOVE; + + DLOG("Destroying buffer for output %s", walk->name); + xcb_free_pixmap(xcb_connection, walk->buffer); + DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, walk->bar, mask, values); + + DLOG("Recreating buffer for output %s", walk->name); + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); + if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } + if (xcb_request_failed(pm_cookie, "Could not create pixmap")) { + exit(EXIT_FAILURE); + } } } } From 34dd4bc89eef50ed4dd6cc65fce8cd4fe458833c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 6 Jan 2011 17:35:23 +0100 Subject: [PATCH 103/185] Bugfix: If hide-on-modifier is set, stop the child after starting --- i3bar/src/child.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 48541185..d7d55783 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -132,6 +132,10 @@ void start_child(char *command) { dup2(fd[0], STDIN_FILENO); + /* If hide-on-modifier is set, we start of by sending the + * child a SIGSTOP, because the bars aren't mapped at start */ + stop_child(); + break; } } From 5f32bfa6d8cc0c61f736a0e5f70ce960b3ac5dff Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 6 Jan 2011 17:28:21 +0100 Subject: [PATCH 104/185] Bugfix: Recreate double-buffers on reconfiguring (thx sECuRE) --- i3bar/src/xcb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6f023b4f..0cb1201a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -727,14 +727,30 @@ void reconfig_windows() { values[2] = walk->rect.w; values[3] = font_height + 6; values[4] = XCB_STACK_MODE_ABOVE; + + DLOG("Destroying buffer for output %s", walk->name); + xcb_free_pixmap(xcb_connection, walk->buffer); + DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, walk->bar, mask, values); + + DLOG("Recreating buffer for output %s", walk->name); + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); + if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } + if (xcb_request_failed(pm_cookie, "Could not create pixmap")) { + exit(EXIT_FAILURE); + } } } } From cd4b77ab724a9e608eb2943cc189239087d4d26e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 6 Jan 2011 17:35:23 +0100 Subject: [PATCH 105/185] Bugfix: If hide-on-modifier is set, stop the child after starting --- i3bar/src/child.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 48541185..d7d55783 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -132,6 +132,10 @@ void start_child(char *command) { dup2(fd[0], STDIN_FILENO); + /* If hide-on-modifier is set, we start of by sending the + * child a SIGSTOP, because the bars aren't mapped at start */ + stop_child(); + break; } } From 96e14d81032cb53c56664e88816f57efd24c415b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 2 Jan 2011 22:39:49 -0200 Subject: [PATCH 106/185] Separate the lines received in a single read. Fixes the case where multiple lines are read in a single read syscall (it could be better optimized in the future). Also fixes a memory corruption issue when rec == 0. --- i3bar/include/common.h | 1 + i3bar/src/child.c | 23 ++++++++++++++++------- i3bar/src/main.c | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 4ad33703..8b439ee0 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -14,6 +14,7 @@ typedef int bool; struct ev_loop* main_loop; char *statusline; +char *statusline_buffer; struct rect_t { int x; diff --git a/i3bar/src/child.c b/i3bar/src/child.c index d7d55783..1fae7593 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -27,6 +27,9 @@ pid_t child_pid; ev_io *stdin_io; ev_child *child_sig; +/* The buffer statusline points to */ +char *statusline_buffer = NULL; + /* * Stop and free() the stdin- and sigchild-watchers * @@ -36,7 +39,7 @@ void cleanup() { ev_child_stop(main_loop, child_sig); FREE(stdin_io); FREE(child_sig); - FREE(statusline); + FREE(statusline_buffer); } /* @@ -50,7 +53,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int rec = 0; int buffer_len = STDIN_CHUNK_SIZE; char *buffer = malloc(buffer_len); - memset(buffer, '\0', buffer_len); + buffer[0] = '\0'; while(1) { n = read(fd, buffer + rec, buffer_len - rec); if (n == -1) { @@ -67,8 +70,10 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer_len += STDIN_CHUNK_SIZE; buffer = realloc(buffer, buffer_len); } else { - /* remove trailing newline and finish up */ - buffer[rec-1] = '\0'; + if (rec != 0) { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; + } break; } } @@ -78,9 +83,13 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { FREE(buffer); return; } - FREE(statusline); - statusline = buffer; - DLOG("%s\n", buffer); + FREE(statusline_buffer); + statusline = statusline_buffer = buffer; + for (n = 0; buffer[n] != '\0'; ++n) { + if (buffer[n] == '\n') + statusline = &buffer[n + 1]; + } + DLOG("%s\n", statusline); draw_bars(); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index c2cf53e2..fce7fc29 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -249,7 +249,7 @@ int main(int argc, char **argv) { FREE(socket_path); - FREE(statusline); + FREE(statusline_buffer); clean_xcb(); ev_default_destroy(); From 29f153c6341c22ffb3ae83a5efcdbb518dd87171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 2 Jan 2011 22:39:49 -0200 Subject: [PATCH 107/185] Separate the lines received in a single read. Fixes the case where multiple lines are read in a single read syscall (it could be better optimized in the future). Also fixes a memory corruption issue when rec == 0. --- i3bar/include/common.h | 1 + i3bar/src/child.c | 23 ++++++++++++++++------- i3bar/src/main.c | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 4ad33703..8b439ee0 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -14,6 +14,7 @@ typedef int bool; struct ev_loop* main_loop; char *statusline; +char *statusline_buffer; struct rect_t { int x; diff --git a/i3bar/src/child.c b/i3bar/src/child.c index d7d55783..1fae7593 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -27,6 +27,9 @@ pid_t child_pid; ev_io *stdin_io; ev_child *child_sig; +/* The buffer statusline points to */ +char *statusline_buffer = NULL; + /* * Stop and free() the stdin- and sigchild-watchers * @@ -36,7 +39,7 @@ void cleanup() { ev_child_stop(main_loop, child_sig); FREE(stdin_io); FREE(child_sig); - FREE(statusline); + FREE(statusline_buffer); } /* @@ -50,7 +53,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int rec = 0; int buffer_len = STDIN_CHUNK_SIZE; char *buffer = malloc(buffer_len); - memset(buffer, '\0', buffer_len); + buffer[0] = '\0'; while(1) { n = read(fd, buffer + rec, buffer_len - rec); if (n == -1) { @@ -67,8 +70,10 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer_len += STDIN_CHUNK_SIZE; buffer = realloc(buffer, buffer_len); } else { - /* remove trailing newline and finish up */ - buffer[rec-1] = '\0'; + if (rec != 0) { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; + } break; } } @@ -78,9 +83,13 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { FREE(buffer); return; } - FREE(statusline); - statusline = buffer; - DLOG("%s\n", buffer); + FREE(statusline_buffer); + statusline = statusline_buffer = buffer; + for (n = 0; buffer[n] != '\0'; ++n) { + if (buffer[n] == '\n') + statusline = &buffer[n + 1]; + } + DLOG("%s\n", statusline); draw_bars(); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index c2cf53e2..fce7fc29 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -249,7 +249,7 @@ int main(int argc, char **argv) { FREE(socket_path); - FREE(statusline); + FREE(statusline_buffer); clean_xcb(); ev_default_destroy(); From 84b574167e26ab566be602e77c9f0b05b81ff114 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 11 Jan 2011 05:02:55 +0100 Subject: [PATCH 108/185] Use I3SOCK environment-variable --- i3bar/doc/i3bar.man | 8 ++++++++ i3bar/src/main.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 9ee7f7ce..d446143c 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -54,6 +54,14 @@ For each specified option you need to give a HEX-colorcode. Be advised that this command-line-options are only temporary and are very likely to be removed, when we finally have a config-file. +== ENVIRONMENT + +=== I3SOCK + +If no ipc-socket is specified on the commandline, this variable is used +to determine the path, at wich the unix domain socket is expected, on which +to connect to i3. + == EXAMPLES To get a docked bar with some statusinformation, you use diff --git a/i3bar/src/main.c b/i3bar/src/main.c index fce7fc29..c0e07a22 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -113,7 +113,7 @@ void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { int main(int argc, char **argv) { int opt; int option_index = 0; - char *socket_path = NULL; + char *socket_path = getenv("I3SOCK"); char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; @@ -247,8 +247,6 @@ int main(int argc, char **argv) { kill_child(); - FREE(socket_path); - FREE(statusline_buffer); clean_xcb(); From caca38b68e4bcfcdfae0a17694f2a4d087200053 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 11 Jan 2011 05:02:55 +0100 Subject: [PATCH 109/185] Use I3SOCK environment-variable --- i3bar/doc/i3bar.man | 8 ++++++++ i3bar/src/main.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 9ee7f7ce..d446143c 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -54,6 +54,14 @@ For each specified option you need to give a HEX-colorcode. Be advised that this command-line-options are only temporary and are very likely to be removed, when we finally have a config-file. +== ENVIRONMENT + +=== I3SOCK + +If no ipc-socket is specified on the commandline, this variable is used +to determine the path, at wich the unix domain socket is expected, on which +to connect to i3. + == EXAMPLES To get a docked bar with some statusinformation, you use diff --git a/i3bar/src/main.c b/i3bar/src/main.c index fce7fc29..c0e07a22 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -113,7 +113,7 @@ void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { int main(int argc, char **argv) { int opt; int option_index = 0; - char *socket_path = NULL; + char *socket_path = getenv("I3SOCK"); char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; @@ -247,8 +247,6 @@ int main(int argc, char **argv) { kill_child(); - FREE(socket_path); - FREE(statusline_buffer); clean_xcb(); From 4762152e1c281e5a58a38d3cb840dcfc285eec67 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 14 Jan 2011 17:33:40 +0100 Subject: [PATCH 110/185] Display socket-path in connection-error-message --- i3bar/src/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index ce9f52cd..206b1b72 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -286,7 +286,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connect to i3: %s\n", strerror(errno)); + ELOG("Could not connect to i3! %s: %s\n", sock_path, strerror(errno)); reconnect(); return 0; } From 2064df9e5d24750ba39e7855c78368ea42c9674d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 14 Jan 2011 17:33:40 +0100 Subject: [PATCH 111/185] Display socket-path in connection-error-message --- i3bar/src/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index ce9f52cd..206b1b72 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -286,7 +286,7 @@ int init_connection(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - ELOG("Could not connect to i3: %s\n", strerror(errno)); + ELOG("Could not connect to i3! %s: %s\n", sock_path, strerror(errno)); reconnect(); return 0; } From 1369e36d7c5238e56a14c393f654088b8f9293b9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 14 Jan 2011 19:16:52 +0100 Subject: [PATCH 112/185] Use tree-command for workspace-switching --- i3bar/src/xcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 0cb1201a..a6d667bc 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -353,8 +353,8 @@ void handle_button(xcb_button_press_event_t *event) { break; } - char buffer[50]; - snprintf(buffer, 50, "%d", cur_ws->num); + char buffer[strlen(cur_ws->name) + 11]; + snprintf(buffer, 50, "workspace %s", cur_ws->name); i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); } From c9ee3eb21ee6364a5f8bf09ee7c02007ae813e4c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 22 Jan 2011 17:41:24 +0100 Subject: [PATCH 113/185] Change default socketpath to /tmp/i3-ipc.sock --- i3bar/doc/i3bar.man | 2 +- i3bar/src/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index d446143c..f47108dd 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -14,7 +14,7 @@ i3bar - xcb-based status- and ws-bar == OPTIONS *-s, --socket* 'sock_path':: -Specifies the 'socketpath', via which *i3bar* connects to *i3*(1). If *i3bar* can not connect to *i3*, it will exit. Defaults to '~/.i3/ipc.sock' +Specifies the 'socketpath', via which *i3bar* connects to *i3*(1). If *i3bar* can not connect to *i3*, it will exit. Defaults to '/tmp/i3-ipc.sock' *-c, --command* 'command':: Execute '' to get 'stdin'. You can also simply pipe into 'stdin', but starting the coomand for itself, *i3bar* is able to send 'SIGCONT' and 'SIGSTOP', when combined with *-m* diff --git a/i3bar/src/main.c b/i3bar/src/main.c index c0e07a22..9c2a3181 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -116,7 +116,7 @@ int main(int argc, char **argv) { char *socket_path = getenv("I3SOCK"); char *command = NULL; char *fontname = NULL; - char *i3_default_sock_path = "~/.i3/ipc.sock"; + char *i3_default_sock_path = "/tmp/i3-ipc.sock"; struct xcb_color_strings_t colors = { NULL, }; /* Definition of the standard-config */ From 94ca5c73ccae65f8fe25b326fcf479eeed632bdd Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:21:36 +0100 Subject: [PATCH 114/185] Bugfix: Test for outputs == NULL --- i3bar/src/workspaces.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 1e47bb81..a28ed2be 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -255,6 +255,9 @@ void parse_workspaces_json(char *json) { */ void free_workspaces() { i3_output *outputs_walk; + if (outputs == NULL) { + return; + } SLIST_FOREACH(outputs_walk, outputs, slist) { if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { FREE_TAILQ(outputs_walk->workspaces, i3_ws); From cc71c773295bb6910fefc9e2c66f980ee3eb1b38 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:24:54 +0100 Subject: [PATCH 115/185] Bugfix: free() command-string, after it is not needed anymore --- i3bar/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 9c2a3181..41b0ea7b 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -227,6 +227,7 @@ int main(int argc, char **argv) { /* The name of this function is actually misleading. Even if no -c is specified, * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + FREE(command); /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us From da1b65dd867608ea08a7efacfb19ec83814cd744 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:34:15 +0100 Subject: [PATCH 116/185] Bugfix: free() workspace-names seperately (thx dothebart) --- i3bar/src/workspaces.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index a28ed2be..0393071e 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -258,8 +258,14 @@ void free_workspaces() { if (outputs == NULL) { return; } + i3_ws *ws_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { + TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { + FREE(ws_walk->name); + FREE(ws_walk->ucs2_name); + } FREE_TAILQ(outputs_walk->workspaces, i3_ws); } } From 7a7faff96d3ee7eb94babb1a0832ccf1a34117fb Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:54:35 +0100 Subject: [PATCH 117/185] Remove superflous FREE_SLIST --- i3bar/src/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 41b0ea7b..9771d2a3 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -254,7 +254,6 @@ int main(int argc, char **argv) { ev_default_destroy(); free_workspaces(); - FREE_SLIST(outputs, i3_output); return 0; } From 9d22b2916629330e4902dc9747da5a8b90c09d09 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:38:48 +0100 Subject: [PATCH 118/185] Bugfix: free() workspace-list of outputs seperately (thx dothebart) --- i3bar/src/xcb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a6d667bc..b48a6ad9 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -579,9 +579,10 @@ void init_xcb(char *fontname) { * */ void clean_xcb() { - i3_output *walk; - SLIST_FOREACH(walk, outputs, slist) { - destroy_window(walk); + i3_output *o_walk; + SLIST_FOREACH(o_walk, outputs, slist) { + destroy_window(o_walk); + FREE_TAILQ(o_walk->workspaces, i3_ws); } FREE_SLIST(outputs, i3_output); From d9f35859fa281a1239dc3bdd94e91020f90fcfca Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:55:15 +0100 Subject: [PATCH 119/185] Bugfix: free() text, after drawing it (thx dothebart) --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index b48a6ad9..1d7bcd3e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -197,6 +197,8 @@ void refresh_statusline() { draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); + FREE(text); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { exit(EXIT_FAILURE); } From dc7cfeaa4f09938366dad48e65a7241ba012a40c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:51:46 +0100 Subject: [PATCH 120/185] Bugfix: Also free() the head of slist/tailq (Thx dothebart) --- i3bar/src/workspaces.c | 2 +- i3bar/src/xcb.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 0393071e..89f7757d 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -250,7 +250,7 @@ void parse_workspaces_json(char *json) { } /* - * free() all workspace data-structures + * free() all workspace data-structures. Does not free() the heads of the tailqueues. * */ void free_workspaces() { diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 1d7bcd3e..10afa923 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -585,8 +585,10 @@ void clean_xcb() { SLIST_FOREACH(o_walk, outputs, slist) { destroy_window(o_walk); FREE_TAILQ(o_walk->workspaces, i3_ws); + FREE(o_walk->workspaces); } FREE_SLIST(outputs, i3_output); + FREE(outputs); xcb_disconnect(xcb_connection); From 18e6caf0a9ed01a9637b4fbc8245960f377676d9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:21:36 +0100 Subject: [PATCH 121/185] Bugfix: Test for outputs == NULL --- i3bar/src/workspaces.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 1e47bb81..a28ed2be 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -255,6 +255,9 @@ void parse_workspaces_json(char *json) { */ void free_workspaces() { i3_output *outputs_walk; + if (outputs == NULL) { + return; + } SLIST_FOREACH(outputs_walk, outputs, slist) { if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { FREE_TAILQ(outputs_walk->workspaces, i3_ws); From 9c7db9399339ab1ed6cc3472ab21f45338ff90f4 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:24:54 +0100 Subject: [PATCH 122/185] Bugfix: free() command-string, after it is not needed anymore --- i3bar/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index c0e07a22..4ac268d6 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -227,6 +227,7 @@ int main(int argc, char **argv) { /* The name of this function is actually misleading. Even if no -c is specified, * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + FREE(command); /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us From 31863efc043c3f1a66b861af402013f86d3d26c2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:34:15 +0100 Subject: [PATCH 123/185] Bugfix: free() workspace-names seperately (thx dothebart) --- i3bar/src/workspaces.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index a28ed2be..0393071e 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -258,8 +258,14 @@ void free_workspaces() { if (outputs == NULL) { return; } + i3_ws *ws_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { + TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { + FREE(ws_walk->name); + FREE(ws_walk->ucs2_name); + } FREE_TAILQ(outputs_walk->workspaces, i3_ws); } } From 17a795aba15733055c9650376f71b669fbb782b9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:54:35 +0100 Subject: [PATCH 124/185] Remove superflous FREE_SLIST --- i3bar/src/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 4ac268d6..dd3b9315 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -254,7 +254,6 @@ int main(int argc, char **argv) { ev_default_destroy(); free_workspaces(); - FREE_SLIST(outputs, i3_output); return 0; } From 51ffd4c3dd81e2eb123429104ff2f48c2e3b433a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:38:48 +0100 Subject: [PATCH 125/185] Bugfix: free() workspace-list of outputs seperately (thx dothebart) --- i3bar/src/xcb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 0cb1201a..2759f159 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -579,9 +579,10 @@ void init_xcb(char *fontname) { * */ void clean_xcb() { - i3_output *walk; - SLIST_FOREACH(walk, outputs, slist) { - destroy_window(walk); + i3_output *o_walk; + SLIST_FOREACH(o_walk, outputs, slist) { + destroy_window(o_walk); + FREE_TAILQ(o_walk->workspaces, i3_ws); } FREE_SLIST(outputs, i3_output); From e9ef6d186a15815795df955726a34b0d4c35a460 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 00:55:15 +0100 Subject: [PATCH 126/185] Bugfix: free() text, after drawing it (thx dothebart) --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 2759f159..f775aad3 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -197,6 +197,8 @@ void refresh_statusline() { draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); + FREE(text); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { exit(EXIT_FAILURE); } From 9bcc6216c81dafac809b3669b200565e600831b4 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 01:51:46 +0100 Subject: [PATCH 127/185] Bugfix: Also free() the head of slist/tailq (Thx dothebart) --- i3bar/src/workspaces.c | 2 +- i3bar/src/xcb.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 0393071e..89f7757d 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -250,7 +250,7 @@ void parse_workspaces_json(char *json) { } /* - * free() all workspace data-structures + * free() all workspace data-structures. Does not free() the heads of the tailqueues. * */ void free_workspaces() { diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f775aad3..e481e314 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -585,8 +585,10 @@ void clean_xcb() { SLIST_FOREACH(o_walk, outputs, slist) { destroy_window(o_walk); FREE_TAILQ(o_walk->workspaces, i3_ws); + FREE(o_walk->workspaces); } FREE_SLIST(outputs, i3_output); + FREE(outputs); xcb_disconnect(xcb_connection); From 8fa720d6b9729daa74c55ed9243391a63b57323e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 12:02:09 +0100 Subject: [PATCH 128/185] Bugfix: free() output-names seperately (thx dothebart) --- i3bar/src/xcb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 10afa923..af472638 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -586,6 +586,7 @@ void clean_xcb() { destroy_window(o_walk); FREE_TAILQ(o_walk->workspaces, i3_ws); FREE(o_walk->workspaces); + FREE(o_walk->name); } FREE_SLIST(outputs, i3_output); FREE(outputs); From ff925f58e886c2b510167624ffba1637ecbefc19 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 12:56:49 +0100 Subject: [PATCH 129/185] Bugfix: Use free-workspaces() in xcb-cleanup (thx dothebart) --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index af472638..0f0e2973 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -582,9 +582,9 @@ void init_xcb(char *fontname) { */ void clean_xcb() { i3_output *o_walk; + free_workspaces(); SLIST_FOREACH(o_walk, outputs, slist) { destroy_window(o_walk); - FREE_TAILQ(o_walk->workspaces, i3_ws); FREE(o_walk->workspaces); FREE(o_walk->name); } From 1cf054f2b4ad95c5f9e4d90752e004f95378f532 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 12:02:09 +0100 Subject: [PATCH 130/185] Bugfix: free() output-names seperately (thx dothebart) --- i3bar/src/xcb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e481e314..7e4e3d82 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -586,6 +586,7 @@ void clean_xcb() { destroy_window(o_walk); FREE_TAILQ(o_walk->workspaces, i3_ws); FREE(o_walk->workspaces); + FREE(o_walk->name); } FREE_SLIST(outputs, i3_output); FREE(outputs); From 4a10a2edbaa86c90b6706d2cf41acbfa785ea48c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 26 Jan 2011 12:56:49 +0100 Subject: [PATCH 131/185] Bugfix: Use free-workspaces() in xcb-cleanup (thx dothebart) --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 7e4e3d82..fb2564fb 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -582,9 +582,9 @@ void init_xcb(char *fontname) { */ void clean_xcb() { i3_output *o_walk; + free_workspaces(); SLIST_FOREACH(o_walk, outputs, slist) { destroy_window(o_walk); - FREE_TAILQ(o_walk->workspaces, i3_ws); FREE(o_walk->workspaces); FREE(o_walk->name); } From 29d03f917b5dfb3da9f32b187c5c64ee7bae64db Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 4 Feb 2011 10:04:54 +0100 Subject: [PATCH 132/185] Bugfix: _only_ stop child, if hide_on_modifier is set (thx cradle) --- i3bar/src/child.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 1fae7593..795a10d3 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -143,7 +143,9 @@ void start_child(char *command) { /* If hide-on-modifier is set, we start of by sending the * child a SIGSTOP, because the bars aren't mapped at start */ - stop_child(); + if (config.hide_on_modifier) { + stop_child(); + } break; } From 972be13dc5e4005fa6c3d44a4d1e1bb6b606e1ee Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 4 Feb 2011 10:04:54 +0100 Subject: [PATCH 133/185] Bugfix: _only_ stop child, if hide_on_modifier is set (thx cradle) --- i3bar/src/child.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 1fae7593..795a10d3 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -143,7 +143,9 @@ void start_child(char *command) { /* If hide-on-modifier is set, we start of by sending the * child a SIGSTOP, because the bars aren't mapped at start */ - stop_child(); + if (config.hide_on_modifier) { + stop_child(); + } break; } From acb52fc654634419e49324c5fb34a079569974a4 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 5 Feb 2011 15:20:40 +0100 Subject: [PATCH 134/185] Bugfix: Don't override DEBUG-env in Makefile --- i3bar/common.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/common.mk b/i3bar/common.mk index 3d44b028..db0e549d 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -1,5 +1,7 @@ INSTALL=install +ifndef DEBUG DEBUG=1 +endif PREFIX=/usr # The escaping is absurd, but we need to escape for shell, sed, make, define From 02480450672bb29c7c9f11bb87e76114105cd35b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 5 Feb 2011 15:20:40 +0100 Subject: [PATCH 135/185] Bugfix: Don't override DEBUG-env in Makefile --- i3bar/common.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/common.mk b/i3bar/common.mk index 3d44b028..db0e549d 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -1,5 +1,7 @@ INSTALL=install +ifndef DEBUG DEBUG=1 +endif PREFIX=/usr # The escaping is absurd, but we need to escape for shell, sed, make, define From 23a98140907341c8f04ffddb1de5701ac7f7bcc0 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 16 Feb 2011 19:53:42 +0100 Subject: [PATCH 136/185] Correct typo --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 0f0e2973..60b88fc8 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -365,7 +365,7 @@ void handle_button(xcb_button_press_event_t *event) { * then (and only then) * */ -void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { +void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) { xcb_flush(xcb_connection); } From 64f2a7561d885ab64905851626268d72051fe59f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 21 Feb 2011 15:47:58 +0100 Subject: [PATCH 137/185] Implement dock-positioning --- i3bar/CHANGELOG | 2 ++ i3bar/doc/i3bar.man | 19 +++++++++---- i3bar/include/config.h | 7 +++++ i3bar/include/xcb_atoms.def | 2 +- i3bar/src/main.c | 30 ++++++++++++++++++-- i3bar/src/xcb.c | 56 +++++++++++++++++++++++++++++++++---- 6 files changed, 102 insertions(+), 14 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index cbacfb99..0b6958d2 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,3 +1,5 @@ +- Implement different dock-positions +- Hide-on-modifier is now the default behavior - Bugfix: Recover from closed socket v0.6 diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index f47108dd..41a80bfa 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -9,7 +9,7 @@ i3bar - xcb-based status- and ws-bar == SYNOPSIS -*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*] [*-f* 'font'] [*-V*] [*-h*] +*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d*['pos']] [*-f* 'font'] [*-V*] [*-h*] == OPTIONS @@ -21,7 +21,12 @@ Execute '' to get 'stdin'. You can also simply pipe into 'stdin', but s *-m, --hide*:: Hide the bar, when 'mod4' is not pressed. With this, dockmode will not be set, and the bar is out of the way most of the time so you have more room. -If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars +If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars. +This is the default behavior of i3bar. + +*-d*['pos']*, --dock*[*=*'pos']:: +Put i3bar in dockmode. This will reserve some space for it, so it does not overlap other clients. +You can specify either *bottom* (default) or *top* as 'pos'. *-f, --font* 'font':: Specifies a 'X-core-font' to use. You can choose one with *xfontsel*(1). Defaults to '-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1'. @@ -66,11 +71,15 @@ to connect to i3. To get a docked bar with some statusinformation, you use -*i3status | i3bar* +*i3status | i3bar --dock* -If you want it to hide when not needed, you should instead use +If you rather have it displayed at the top of the screen, you use -*i3bar -c i3status -m* +*i3status | i3bar --dock=top* + +If you want it to hide when not needed, you should instead simply use + +*i3bar -c i3status* == SEE ALSO diff --git a/i3bar/include/config.h b/i3bar/include/config.h index 2dd0f532..d6abb45c 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -3,8 +3,15 @@ #include "common.h" +typedef enum { + DOCKPOS_NONE = 0, + DOCKPOS_TOP, + DOCKPOS_BOT +} dockpos_t; + typedef struct config_t { int hide_on_modifier; + dockpos_t dockpos; int verbose; xcb_colors_t *colors; } config_t; diff --git a/i3bar/include/xcb_atoms.def b/i3bar/include/xcb_atoms.def index 5084231c..2ac94acb 100644 --- a/i3bar/include/xcb_atoms.def +++ b/i3bar/include/xcb_atoms.def @@ -1,4 +1,4 @@ -ATOM_DO(ATOM) ATOM_DO(_NET_WM_WINDOW_TYPE) ATOM_DO(_NET_WM_WINDOW_TYPE_DOCK) +ATOM_DO(_NET_WM_STRUT_PARTIAL) #undef ATOM_DO diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 9771d2a3..d33ddb4f 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -79,10 +79,11 @@ static void free_colors(struct xcb_color_strings_t *colors) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-V] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-c command] [-m|-d[pos]] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); printf("-c \tExecute to get stdin\n"); printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); + printf("-d[]\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\n"); printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); printf("\t\tand a SIGCONT on unhiding of the bars\n"); printf("-f \tUse X-Core-Font for display\n"); @@ -121,11 +122,13 @@ int main(int argc, char **argv) { /* Definition of the standard-config */ config.hide_on_modifier = 0; + config.dockpos = DOCKPOS_NONE; static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, { "command", required_argument, 0, 'c' }, { "hide", no_argument, 0, 'm' }, + { "dock", optional_argument, 0, 'd' }, { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, @@ -141,7 +144,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hvVA:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:d::mf:hvVA:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -152,6 +155,20 @@ int main(int argc, char **argv) { case 'm': config.hide_on_modifier = 1; break; + case 'd': + if (optarg == NULL) { + config.dockpos = DOCKPOS_BOT; + break; + } + if (!strcmp(optarg, "top")) { + config.dockpos = DOCKPOS_TOP; + } else if (!strcmp(optarg, "bottom")) { + config.dockpos = DOCKPOS_BOT; + } else { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + break; case 'f': fontname = strdup(optarg); break; @@ -205,6 +222,15 @@ int main(int argc, char **argv) { socket_path = expand_path(i3_default_sock_path); } + if (config.dockpos != DOCKPOS_NONE) { + if (config.hide_on_modifier) { + ELOG("--dock and --hide are mutually exclusive!\n"); + exit(EXIT_FAILURE); + } + } else { + config.hide_on_modifier = 1; + } + main_loop = ev_default_loop(0); init_colors(&colors); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 60b88fc8..f33a69cd 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -10,6 +10,7 @@ */ #include #include +#include #include #include #include @@ -688,15 +689,57 @@ void reconfig_windows() { /* We want dock-windows (for now). When override_redirect is set, i3 is ignoring * this one */ - xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, + xcb_void_cookie_t dock_cookie = xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, walk->bar, atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], + XCB_ATOM_ATOM, 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + /* We need to tell i3, where to reserve space for i3bar */ + /* left, right, top, bottom, left_start_y, left_end_y, + * right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, + * bottom_end_x */ + /* A local struct to save the strut_partial property */ + struct { + uint32_t left; + uint32_t right; + uint32_t top; + uint32_t bottom; + uint32_t left_start_y; + uint32_t left_end_y; + uint32_t right_start_y; + uint32_t right_end_y; + uint32_t top_start_x; + uint32_t top_end_x; + uint32_t bottom_start_x; + uint32_t bottom_end_x; + } __attribute__((__packed__)) strut_partial = {0,}; + switch (config.dockpos) { + case DOCKPOS_NONE: + break; + case DOCKPOS_TOP: + strut_partial.top = font_height + 6; + strut_partial.top_start_x = walk->rect.x; + strut_partial.top_end_x = walk->rect.x + walk->rect.w; + break; + case DOCKPOS_BOT: + strut_partial.bottom = font_height + 6; + strut_partial.bottom_start_x = walk->rect.x; + strut_partial.bottom_end_x = walk->rect.x + walk->rect.w; + break; + } + xcb_void_cookie_t strut_cookie = xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_STRUT_PARTIAL], + XCB_ATOM_CARDINAL, + 32, + 12, + &strut_partial); + /* We also want a graphics-context for the bars (it defines the properties * with which we draw to them) */ walk->bargc = xcb_generate_id(xcb_connection); @@ -714,10 +757,11 @@ void reconfig_windows() { map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); } - if (xcb_request_failed(win_cookie, "Could not create window") || - xcb_request_failed(pm_cookie, "Could not create pixmap") || - xcb_request_failed(prop_cookie, "Could not set dock mode") || - xcb_request_failed(gc_cookie, "Could not create graphical context") || + if (xcb_request_failed(win_cookie, "Could not create window") || + xcb_request_failed(pm_cookie, "Could not create pixmap") || + xcb_request_failed(dock_cookie, "Could not set dock mode") || + xcb_request_failed(strut_cookie, "Could not set strut") || + xcb_request_failed(gc_cookie, "Could not create graphical context") || (!config.hide_on_modifier && xcb_request_failed(map_cookie, "Could not map window"))) { exit(EXIT_FAILURE); } From c8032d552d112bc950069e04b80b0677fe4d8eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Fri, 25 Feb 2011 21:45:52 -0300 Subject: [PATCH 138/185] Correct minor issues reported by the analyzer. Found with the Clang Static Analyzer. --- i3bar/src/ipc.c | 3 ++- i3bar/src/xcb.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 206b1b72..dc2255ea 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -248,7 +248,8 @@ int i3_send_msg(uint32_t type, const char *payload) { memcpy(walk, &type, sizeof(uint32_t)); walk += sizeof(uint32_t); - strncpy(walk, payload, len); + if (payload != NULL) + strncpy(walk, payload, len); uint32_t written = 0; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f33a69cd..8d4f60b5 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -51,7 +51,7 @@ xcb_charinfo_t *font_table; /* These are only relevant for XKB, which we only need for grabbing modifiers */ Display *xkb_dpy; int xkb_event_base; -int mod_pressed; +int mod_pressed = 0; /* Because the statusline is the same on all outputs, we have * global buffer to render it on */ @@ -409,7 +409,7 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { */ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { XkbEvent ev; - int modstate; + int modstate = 0; DLOG("Got XKB-Event!\n"); From 9bcdd2f614ae67e1304d1cc7cce0d207da11120b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Fri, 25 Feb 2011 21:45:52 -0300 Subject: [PATCH 139/185] Correct minor issues reported by the analyzer. Found with the Clang Static Analyzer. --- i3bar/src/ipc.c | 3 ++- i3bar/src/xcb.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 206b1b72..dc2255ea 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -248,7 +248,8 @@ int i3_send_msg(uint32_t type, const char *payload) { memcpy(walk, &type, sizeof(uint32_t)); walk += sizeof(uint32_t); - strncpy(walk, payload, len); + if (payload != NULL) + strncpy(walk, payload, len); uint32_t written = 0; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index fb2564fb..c6cda4ed 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -50,7 +50,7 @@ xcb_charinfo_t *font_table; /* These are only relevant for XKB, which we only need for grabbing modifiers */ Display *xkb_dpy; int xkb_event_base; -int mod_pressed; +int mod_pressed = 0; /* Because the statusline is the same on all outputs, we have * global buffer to render it on */ @@ -408,7 +408,7 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { */ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { XkbEvent ev; - int modstate; + int modstate = 0; DLOG("Got XKB-Event!\n"); From dfd566511e4d374807e3dfd4c69c506004c3af13 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 14 Mar 2011 09:17:06 +0100 Subject: [PATCH 140/185] Bugfix: Don't segfault, if child was killed --- i3bar/src/child.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 795a10d3..890dce29 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -35,11 +36,13 @@ char *statusline_buffer = NULL; * */ void cleanup() { - ev_io_stop(main_loop, stdin_io); - ev_child_stop(main_loop, child_sig); - FREE(stdin_io); - FREE(child_sig); - FREE(statusline_buffer); + if (stdin_io != NULL) { + ev_io_stop(main_loop, stdin_io); + ev_child_stop(main_loop, child_sig); + FREE(stdin_io); + FREE(child_sig); + FREE(statusline_buffer); + } } /* @@ -174,8 +177,11 @@ void kill_child() { if (child_pid != 0) { kill(child_pid, SIGCONT); kill(child_pid, SIGTERM); + int status; + waitpid(child_pid, &status, 0); + child_pid = 0; + cleanup(); } - cleanup(); } /* From 7fb6258fbd9246e6983f508c44d84d63aa7ce7d1 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 14 Mar 2011 09:20:16 +0100 Subject: [PATCH 141/185] Use DISPLAY in XKB-code --- i3bar/src/xcb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 8d4f60b5..a7f1e51b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -484,7 +484,11 @@ void init_xcb(char *fontname) { xkb_major = XkbMajorVersion; xkb_minor = XkbMinorVersion; - xkb_dpy = XkbOpenDisplay(":0", + char *dispname = getenv("DISPLAY"); + if (dispname == NULL) { + dispname = ":0"; + } + xkb_dpy = XkbOpenDisplay(dispname, &xkb_event_base, &xkb_errbase, &xkb_major, From 5219493ffe895ebbe4063e8d8367dd4c0a35877a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 14 Mar 2011 09:24:32 +0100 Subject: [PATCH 142/185] Bugfix: Don't SIGSTOP child in dockmode --- i3bar/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index d33ddb4f..8e632b7b 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -156,6 +156,7 @@ int main(int argc, char **argv) { config.hide_on_modifier = 1; break; case 'd': + config.hide_on_modifier = 0; if (optarg == NULL) { config.dockpos = DOCKPOS_BOT; break; From d993f8a3a1e278d7d32ca579415c4d0d4fb6600f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 20:58:05 +0100 Subject: [PATCH 143/185] Auto-update NUM_ATOMS by putting it into the enum (thx sECuRE) --- i3bar/src/xcb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a7f1e51b..5f4c58f7 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -27,11 +27,10 @@ #include "common.h" /* We save the Atoms in an easy to access array, indexed by an enum */ -#define NUM_ATOMS 3 - enum { #define ATOM_DO(name) name, #include "xcb_atoms.def" + NUM_ATOMS }; xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; From 2fd7449e2983de54504f0da55c6ea9ede246de69 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 22:06:08 +0100 Subject: [PATCH 144/185] Add support for I3_SOCKET_PATH-atom --- i3bar/include/xcb.h | 2 +- i3bar/include/xcb_atoms.def | 1 + i3bar/src/main.c | 16 ++++++++++------ i3bar/src/xcb.c | 25 ++++++++++++++++++++++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 5ace4f0b..0adb29ab 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -29,7 +29,7 @@ typedef struct xcb_colors_t xcb_colors_t; * Initialize xcb and use the specified fontname for text-rendering * */ -void init_xcb(); +char *init_xcb(); /* * Initialize the colors diff --git a/i3bar/include/xcb_atoms.def b/i3bar/include/xcb_atoms.def index 2ac94acb..5d168873 100644 --- a/i3bar/include/xcb_atoms.def +++ b/i3bar/include/xcb_atoms.def @@ -1,4 +1,5 @@ ATOM_DO(_NET_WM_WINDOW_TYPE) ATOM_DO(_NET_WM_WINDOW_TYPE_DOCK) ATOM_DO(_NET_WM_STRUT_PARTIAL) +ATOM_DO(I3_SOCKET_PATH) #undef ATOM_DO diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 8e632b7b..b09a220f 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -218,11 +218,6 @@ int main(int argc, char **argv) { fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; } - if (socket_path == NULL) { - ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); - socket_path = expand_path(i3_default_sock_path); - } - if (config.dockpos != DOCKPOS_NONE) { if (config.hide_on_modifier) { ELOG("--dock and --hide are mutually exclusive!\n"); @@ -235,7 +230,16 @@ int main(int argc, char **argv) { main_loop = ev_default_loop(0); init_colors(&colors); - init_xcb(fontname); + char *atom_sock_path = init_xcb(fontname); + + if (socket_path == NULL) { + socket_path = atom_sock_path; + } + + if (socket_path == NULL) { + ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); + socket_path = expand_path(i3_default_sock_path); + } free_colors(&colors); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 5f4c58f7..f9f3f79a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -445,7 +446,7 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * Initialize xcb and use the specified fontname for text-rendering * */ -void init_xcb(char *fontname) { +char *init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); if (xcb_connection_has_error(xcb_connection)) { @@ -555,6 +556,26 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); + xcb_get_property_cookie_t path_cookie; + path_cookie = xcb_get_property_unchecked(xcb_connection, + 0, + xcb_root, + atoms[I3_SOCKET_PATH], + XCB_GET_PROPERTY_TYPE_ANY, + 0, PATH_MAX); + + /* We check, if i3 set it's socket-path */ + xcb_get_property_reply_t *path_reply = xcb_get_property_reply(xcb_connection, + path_cookie, + NULL); + char *path = NULL; + if (path_reply) { + int len = xcb_get_property_value_length(path_reply); + if (len != 0) { + path = strndup(xcb_get_property_value(path_reply), len); + } + } + /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, @@ -577,6 +598,8 @@ void init_xcb(char *fontname) { if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); } + + return path; } /* From aaf60c632111463ccc34452fc09f29ba10e3e7c8 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 22:27:35 +0100 Subject: [PATCH 145/185] Don't reallocate the backbuffer on every refresh (thx sECuRE) --- i3bar/include/xcb.h | 6 ++++++ i3bar/src/ipc.c | 1 + i3bar/src/xcb.c | 46 ++++++++++++++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 0adb29ab..931e7643 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -56,6 +56,12 @@ void get_atoms(); */ void destroy_window(i3_output *output); +/* + * Reallocate the statusline-buffer + * + */ +void realloc_sl_buffer(); + /* * Reconfigure all bars and create new for newly activated outputs * diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index dc2255ea..d5c18033 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -93,6 +93,7 @@ void got_output_reply(char *reply) { DLOG("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); DLOG("Reconfiguring Windows...\n"); + realloc_sl_buffer(); reconfig_windows(); } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f9f3f79a..f717f487 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -187,22 +187,10 @@ void refresh_statusline() { xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - xcb_free_pixmap(xcb_connection, statusline_pm); - statusline_pm = xcb_generate_id(xcb_connection); - xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screen->root_depth, - statusline_pm, - xcb_root, - statusline_width, - font_height); - + xcb_clear_area(xcb_connection, 0, statusline_pm, 0, 0, xcb_screen->width_in_pixels, font_height); draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); FREE(text); - - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { - exit(EXIT_FAILURE); - } } /* @@ -536,9 +524,14 @@ char *init_xcb(char *fontname) { mask, vals); - /* We only generate an id for the pixmap, because the width of it is dependent on the - * input we get */ statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + statusline_pm, + xcb_root, + xcb_screen->width_in_pixels, + xcb_screen->height_in_pixels); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); @@ -595,6 +588,10 @@ char *init_xcb(char *fontname) { DLOG("Calculated Font-height: %d\n", font_height); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + exit(EXIT_FAILURE); + } + if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); } @@ -663,6 +660,25 @@ void destroy_window(i3_output *output) { output->bar = XCB_NONE; } +/* + * Reallocate the statusline-buffer + * + */ +void realloc_sl_buffer() { + xcb_free_pixmap(xcb_connection, statusline_pm); + statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + statusline_pm, + xcb_root, + xcb_screen->width_in_pixels, + xcb_screen->height_in_pixels); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + exit(EXIT_FAILURE); + } + +} + /* * Reconfigure all bars and create new for newly activated outputs * From a847454a42b4a54e9ebd8a56aa4c42e276d26f93 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 22:30:59 +0100 Subject: [PATCH 146/185] bugfix: Skip inactive outputs on redraw (thx sECuRE) --- i3bar/src/xcb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f717f487..6c89c64e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -951,6 +951,9 @@ void draw_bars() { void redraw_bars() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { + if (!outputs_walk->active) { + continue; + } xcb_copy_area(xcb_connection, outputs_walk->buffer, outputs_walk->bar, From fea94757cd6250ac123b713f0951cb07a9895e96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 22:27:35 +0100 Subject: [PATCH 147/185] Don't reallocate the backbuffer on every refresh (thx sECuRE) --- i3bar/include/xcb.h | 6 ++++++ i3bar/src/ipc.c | 1 + i3bar/src/xcb.c | 46 ++++++++++++++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 5ace4f0b..3817a320 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -56,6 +56,12 @@ void get_atoms(); */ void destroy_window(i3_output *output); +/* + * Reallocate the statusline-buffer + * + */ +void realloc_sl_buffer(); + /* * Reconfigure all bars and create new for newly activated outputs * diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index dc2255ea..d5c18033 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -93,6 +93,7 @@ void got_output_reply(char *reply) { DLOG("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); DLOG("Reconfiguring Windows...\n"); + realloc_sl_buffer(); reconfig_windows(); } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index c6cda4ed..c3ba149b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -186,22 +186,10 @@ void refresh_statusline() { xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - xcb_free_pixmap(xcb_connection, statusline_pm); - statusline_pm = xcb_generate_id(xcb_connection); - xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screen->root_depth, - statusline_pm, - xcb_root, - statusline_width, - font_height); - + xcb_clear_area(xcb_connection, 0, statusline_pm, 0, 0, xcb_screen->width_in_pixels, font_height); draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); FREE(text); - - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { - exit(EXIT_FAILURE); - } } /* @@ -531,9 +519,14 @@ void init_xcb(char *fontname) { mask, vals); - /* We only generate an id for the pixmap, because the width of it is dependent on the - * input we get */ statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + statusline_pm, + xcb_root, + xcb_screen->width_in_pixels, + xcb_screen->height_in_pixels); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); @@ -570,6 +563,10 @@ void init_xcb(char *fontname) { DLOG("Calculated Font-height: %d\n", font_height); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + exit(EXIT_FAILURE); + } + if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); } @@ -636,6 +633,25 @@ void destroy_window(i3_output *output) { output->bar = XCB_NONE; } +/* + * Reallocate the statusline-buffer + * + */ +void realloc_sl_buffer() { + xcb_free_pixmap(xcb_connection, statusline_pm); + statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screen->root_depth, + statusline_pm, + xcb_root, + xcb_screen->width_in_pixels, + xcb_screen->height_in_pixels); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + exit(EXIT_FAILURE); + } + +} + /* * Reconfigure all bars and create new for newly activated outputs * From 9f5b715bd6516d179207611f03089a348d10dcc8 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 22:30:59 +0100 Subject: [PATCH 148/185] bugfix: Skip inactive outputs on redraw (thx sECuRE) --- i3bar/src/xcb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index c3ba149b..24f20c34 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -881,6 +881,9 @@ void draw_bars() { void redraw_bars() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { + if (!outputs_walk->active) { + continue; + } xcb_copy_area(xcb_connection, outputs_walk->buffer, outputs_walk->bar, From 1b2002e1c8e2a56e7a4d456547b5c45aca91e1b3 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 23:04:09 +0100 Subject: [PATCH 149/185] XClearArea can't be used on pixmaps (thx sECuRE) --- i3bar/src/xcb.c | 56 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 6c89c64e..49bb0d09 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -56,6 +56,7 @@ int mod_pressed = 0; /* Because the statusline is the same on all outputs, we have * global buffer to render it on */ xcb_gcontext_t statusline_ctx; +xcb_gcontext_t statusline_clear; xcb_pixmap_t statusline_pm; uint32_t statusline_width; @@ -83,7 +84,7 @@ struct xcb_colors_t colors; int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - ELOG("%s. X Error Code: %d\n", err_msg, err->error_code); + fprintf(stderr, "[%s:%d] ERROR: %s. X Error Code: %d\n", __FILE__, line, err_msg, err->error_code); return err->error_code; } return 0; @@ -187,7 +188,8 @@ void refresh_statusline() { xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - xcb_clear_area(xcb_connection, 0, statusline_pm, 0, 0, xcb_screen->width_in_pixels, font_height); + xcb_rectangle_t rect = { 0, 0, xcb_screen->width_in_pixels, font_height }; + xcb_poly_fill_rectangle(xcb_connection, statusline_pm, statusline_clear, 1, &rect); draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); FREE(text); @@ -512,12 +514,19 @@ char *init_xcb(char *fontname) { /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and * this way, we can choose to crop it */ - statusline_ctx = xcb_generate_id(xcb_connection); - uint32_t mask = XCB_GC_FOREGROUND | - XCB_GC_BACKGROUND | - XCB_GC_FONT; - uint32_t vals[3] = { colors.bar_fg, colors.bar_bg, xcb_font }; + uint32_t mask = XCB_GC_FOREGROUND; + uint32_t vals[3] = { colors.bar_bg, colors.bar_bg, xcb_font }; + statusline_clear = xcb_generate_id(xcb_connection); + xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_clear, + xcb_root, + mask, + vals); + + mask |= XCB_GC_BACKGROUND | XCB_GC_FONT; + vals[0] = colors.bar_fg; + statusline_ctx = xcb_generate_id(xcb_connection); xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, xcb_root, @@ -588,11 +597,9 @@ char *init_xcb(char *fontname) { DLOG("Calculated Font-height: %d\n", font_height); - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { - exit(EXIT_FAILURE); - } - - if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || + xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || + xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { exit(EXIT_FAILURE); } @@ -673,7 +680,30 @@ void realloc_sl_buffer() { xcb_root, xcb_screen->width_in_pixels, xcb_screen->height_in_pixels); - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + + uint32_t mask = XCB_GC_FOREGROUND; + uint32_t vals[3] = { colors.bar_bg, colors.bar_bg, xcb_font }; + xcb_free_gc(xcb_connection, statusline_clear); + statusline_clear = xcb_generate_id(xcb_connection); + xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_clear, + xcb_root, + mask, + vals); + + mask |= XCB_GC_BACKGROUND | XCB_GC_FONT; + vals[0] = colors.bar_fg; + statusline_ctx = xcb_generate_id(xcb_connection); + xcb_free_gc(xcb_connection, statusline_ctx); + xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_ctx, + xcb_root, + mask, + vals); + + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || + xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || + xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { exit(EXIT_FAILURE); } From 49608121e010fff616df09ca6644cb67bda4f536 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 23:04:09 +0100 Subject: [PATCH 150/185] XClearArea can't be used on pixmaps (thx sECuRE) --- i3bar/src/xcb.c | 56 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 24f20c34..dbf681ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -55,6 +55,7 @@ int mod_pressed = 0; /* Because the statusline is the same on all outputs, we have * global buffer to render it on */ xcb_gcontext_t statusline_ctx; +xcb_gcontext_t statusline_clear; xcb_pixmap_t statusline_pm; uint32_t statusline_width; @@ -82,7 +83,7 @@ struct xcb_colors_t colors; int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - ELOG("%s. X Error Code: %d\n", err_msg, err->error_code); + fprintf(stderr, "[%s:%d] ERROR: %s. X Error Code: %d\n", __FILE__, line, err_msg, err->error_code); return err->error_code; } return 0; @@ -186,7 +187,8 @@ void refresh_statusline() { xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - xcb_clear_area(xcb_connection, 0, statusline_pm, 0, 0, xcb_screen->width_in_pixels, font_height); + xcb_rectangle_t rect = { 0, 0, xcb_screen->width_in_pixels, font_height }; + xcb_poly_fill_rectangle(xcb_connection, statusline_pm, statusline_clear, 1, &rect); draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); FREE(text); @@ -507,12 +509,19 @@ void init_xcb(char *fontname) { /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and * this way, we can choose to crop it */ - statusline_ctx = xcb_generate_id(xcb_connection); - uint32_t mask = XCB_GC_FOREGROUND | - XCB_GC_BACKGROUND | - XCB_GC_FONT; - uint32_t vals[3] = { colors.bar_fg, colors.bar_bg, xcb_font }; + uint32_t mask = XCB_GC_FOREGROUND; + uint32_t vals[3] = { colors.bar_bg, colors.bar_bg, xcb_font }; + statusline_clear = xcb_generate_id(xcb_connection); + xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_clear, + xcb_root, + mask, + vals); + + mask |= XCB_GC_BACKGROUND | XCB_GC_FONT; + vals[0] = colors.bar_fg; + statusline_ctx = xcb_generate_id(xcb_connection); xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, xcb_root, @@ -563,11 +572,9 @@ void init_xcb(char *fontname) { DLOG("Calculated Font-height: %d\n", font_height); - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { - exit(EXIT_FAILURE); - } - - if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || + xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || + xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { exit(EXIT_FAILURE); } } @@ -646,7 +653,30 @@ void realloc_sl_buffer() { xcb_root, xcb_screen->width_in_pixels, xcb_screen->height_in_pixels); - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { + + uint32_t mask = XCB_GC_FOREGROUND; + uint32_t vals[3] = { colors.bar_bg, colors.bar_bg, xcb_font }; + xcb_free_gc(xcb_connection, statusline_clear); + statusline_clear = xcb_generate_id(xcb_connection); + xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_clear, + xcb_root, + mask, + vals); + + mask |= XCB_GC_BACKGROUND | XCB_GC_FONT; + vals[0] = colors.bar_fg; + statusline_ctx = xcb_generate_id(xcb_connection); + xcb_free_gc(xcb_connection, statusline_ctx); + xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_ctx, + xcb_root, + mask, + vals); + + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || + xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || + xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { exit(EXIT_FAILURE); } From 682458f4d7c46557dfd1153579a9f84aef177729 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 23:27:50 +0100 Subject: [PATCH 151/185] Don't draw on backbuffer, when hiding (thx sECuRE) --- i3bar/src/xcb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 49bb0d09..b52160df 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -220,6 +220,8 @@ void unhide_bars() { return; } + draw_bars(); + i3_output *walk; xcb_void_cookie_t cookie; uint32_t mask; @@ -882,6 +884,9 @@ void reconfig_windows() { * */ void draw_bars() { + if (config.hide_on_modifier && !mod_pressed) { + return; + } DLOG("Drawing Bars...\n"); int i = 0; From 16f7574851255c75c9d3dc6f19ea4b355b8b5f8a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 23:28:10 +0100 Subject: [PATCH 152/185] Bugfix: Skip inactive outputs, when unmapping --- i3bar/src/xcb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index b52160df..9cb77f3f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -206,6 +206,9 @@ void hide_bars() { i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { + if (!walk->active) { + continue; + } xcb_unmap_window(xcb_connection, walk->bar); } stop_child(); From a5a9afcf2e9a7a93db0565ce83597673853d1d5c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 19 Mar 2011 23:28:10 +0100 Subject: [PATCH 153/185] Bugfix: Skip inactive outputs, when unmapping --- i3bar/src/xcb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index dbf681ad..66bcf93b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -205,6 +205,9 @@ void hide_bars() { i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { + if (!walk->active) { + continue; + } xcb_unmap_window(xcb_connection, walk->bar); } stop_child(); From 52e70c3802e4e4ceac54bb4d1e4e2870affaff41 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 20 Mar 2011 19:29:30 +0100 Subject: [PATCH 154/185] Add Color for focused ws (thx phnom) --- i3bar/doc/i3bar.man | 2 +- i3bar/include/xcb.h | 2 ++ i3bar/src/main.c | 12 +++++++++++- i3bar/src/xcb.c | 13 +++++++++++-- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 41a80bfa..44d5e8ac 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -53,7 +53,7 @@ Also, you should disable the internal workspace bar of *i3*(1), when using *i3ba For now this happens with the following command-line-options: -*--color-bar-fg, --color-bar-bg, --color-active-ws-fg, --color-active-ws-bg, --color-inactive-ws-fg, --color-inactive-ws-bg, color-urgent-ws-bg, color-urgent-ws-fg* +*--color-bar-fg, --color-bar-bg, --color-active-ws-fg, --color-active-ws-bg, --color-inactive-ws-fg, --color-inactive-ws-bg, --color-urgent-ws-bg, --color-urgent-ws-fg, --color-focus-ws-fg, --color-focus-ws-bg* For each specified option you need to give a HEX-colorcode. diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 931e7643..b1732905 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -19,6 +19,8 @@ struct xcb_color_strings_t { char *active_ws_bg; char *inactive_ws_fg; char *inactive_ws_bg; + char *focus_ws_bg; + char *focus_ws_fg; char *urgent_ws_bg; char *urgent_ws_fg; }; diff --git a/i3bar/src/main.c b/i3bar/src/main.c index b09a220f..ad8a9993 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -75,6 +75,8 @@ static void free_colors(struct xcb_color_strings_t *colors) { FREE_COLOR(inactive_ws_bg); FREE_COLOR(urgent_ws_fg); FREE_COLOR(urgent_ws_bg); + FREE_COLOR(focus_ws_fg); + FREE_COLOR(focus_ws_bg); #undef FREE_COLOR } @@ -141,10 +143,12 @@ int main(int argc, char **argv) { { "color-inactive-ws-bg", required_argument, 0, 'F' }, { "color-urgent-ws-bg", required_argument, 0, 'G' }, { "color-urgent-ws-fg", required_argument, 0, 'H' }, + { "color-focus-ws-bg", required_argument, 0, 'I' }, + { "color-focus-ws-fg", required_argument, 0, 'J' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:d::mf:hvVA:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:d::mf:hvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -204,6 +208,12 @@ int main(int argc, char **argv) { case 'H': read_color(&colors.urgent_ws_fg); break; + case 'I': + read_color(&colors.focus_ws_bg); + break; + case 'J': + read_color(&colors.focus_ws_fg); + break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 9cb77f3f..96dbe12e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -76,6 +76,8 @@ struct xcb_colors_t { uint32_t inactive_ws_bg; uint32_t urgent_ws_bg; uint32_t urgent_ws_fg; + uint32_t focus_ws_bg; + uint32_t focus_ws_fg; }; struct xcb_colors_t colors; @@ -276,6 +278,8 @@ void init_colors(const struct xcb_color_strings_t *new_colors) { PARSE_COLOR(inactive_ws_bg, "240000"); PARSE_COLOR(urgent_ws_fg, "FFFFFF"); PARSE_COLOR(urgent_ws_bg, "002400"); + PARSE_COLOR(focus_ws_fg, "FFFFFF"); + PARSE_COLOR(focus_ws_bg, "480000"); #undef PARSE_COLOR } @@ -939,8 +943,13 @@ void draw_bars() { uint32_t fg_color = colors.inactive_ws_fg; uint32_t bg_color = colors.inactive_ws_bg; if (ws_walk->visible) { - fg_color = colors.active_ws_fg; - bg_color = colors.active_ws_bg; + if (!ws_walk->focused) { + fg_color = colors.active_ws_fg; + bg_color = colors.active_ws_bg; + } else { + fg_color = colors.focus_ws_fg; + bg_color = colors.focus_ws_bg; + } } if (ws_walk->urgent) { DLOG("WS %s is urgent!\n", ws_walk->name); From ba748d72ff6c60b3eb0696151d083563807967ca Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 20 Mar 2011 19:49:59 +0100 Subject: [PATCH 155/185] Collapse two ChangeGC-calls (thx sECuRE) --- i3bar/src/xcb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 96dbe12e..87d0c85b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -958,14 +958,12 @@ void draw_bars() { /* The urgent-hint should get noticed, so we unhide the bars shortly */ unhide_bars(); } + uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND; + uint32_t vals[] = { bg_color, bg_color }; xcb_change_gc(xcb_connection, outputs_walk->bargc, - XCB_GC_FOREGROUND, - &bg_color); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_BACKGROUND, - &bg_color); + mask, + vals); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, outputs_walk->buffer, From edcc37307788cdcf72381e3d040001ac52aeafb6 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 20 Mar 2011 19:52:20 +0100 Subject: [PATCH 156/185] Fix typo in comment (thx sECuRE) --- i3bar/src/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index d5c18033..c6a85cf5 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -138,7 +138,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { DLOG("Got data!\n"); int fd = watcher->fd; - /* First we only read the header, because we know it's length */ + /* First we only read the header, because we know its length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { From 26993574f5599365dd70cdd81fd6d4adcfc931e5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Mon, 21 Mar 2011 17:29:11 +0100 Subject: [PATCH 157/185] Revert "Don't draw on backbuffer, when hiding (thx sECuRE)" This reverts commit f51ba2d7ecf3f560c8ce4d3ab8419ecf6265839c. This commit introduced a regression, which prevented i3bar to be redrawn at all in some circumstances. It will later be reintroduced in a bigger refactoring of event-dependencies --- i3bar/src/xcb.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 87d0c85b..2da2e6f7 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -225,8 +225,6 @@ void unhide_bars() { return; } - draw_bars(); - i3_output *walk; xcb_void_cookie_t cookie; uint32_t mask; @@ -891,9 +889,6 @@ void reconfig_windows() { * */ void draw_bars() { - if (config.hide_on_modifier && !mod_pressed) { - return; - } DLOG("Drawing Bars...\n"); int i = 0; From ed5ac7f41dd3b650026e13a2b9c0c77b7fbf07de Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 21 Apr 2011 20:24:02 +0200 Subject: [PATCH 158/185] =?UTF-8?q?Implement=20disabling=20the=20workspace?= =?UTF-8?q?=20buttons=20(=E2=80=9Ethx=E2=80=9C=20sECuRE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i3bar/include/config.h | 1 + i3bar/src/ipc.c | 10 ++++++++-- i3bar/src/main.c | 12 ++++++++++-- i3bar/src/xcb.c | 14 ++++++++++---- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index d6abb45c..b3473917 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -14,6 +14,7 @@ typedef struct config_t { dockpos_t dockpos; int verbose; xcb_colors_t *colors; + int disable_ws; } config_t; config_t config; diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index c6a85cf5..d06864c7 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -121,7 +121,9 @@ void got_workspace_event(char *event) { void got_output_event(char *event) { DLOG("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + if (!config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } } /* Data-structure to easily call the reply-handlers later */ @@ -311,5 +313,9 @@ void destroy_connection() { * */ void subscribe_events() { - i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); + if (config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\" ]"); + } else { + i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); + } } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ad8a9993..4a859254 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -89,6 +89,7 @@ void print_usage(char *elf_name) { printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); printf("\t\tand a SIGCONT on unhiding of the bars\n"); printf("-f \tUse X-Core-Font for display\n"); + printf("-w\t\tDisable workspace-buttons\n"); printf("-V\t\tBe (very) verbose with the debug-output\n"); printf("-h\t\tDisplay this help-message and exit\n"); } @@ -125,6 +126,7 @@ int main(int argc, char **argv) { /* Definition of the standard-config */ config.hide_on_modifier = 0; config.dockpos = DOCKPOS_NONE; + config.disable_ws = 0; static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, @@ -132,6 +134,7 @@ int main(int argc, char **argv) { { "hide", no_argument, 0, 'm' }, { "dock", optional_argument, 0, 'd' }, { "font", required_argument, 0, 'f' }, + { "nows", no_argument, 0, 'w' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { "verbose", no_argument, 0, 'V' }, @@ -148,7 +151,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:d::mf:hvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:d::mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -177,6 +180,9 @@ int main(int argc, char **argv) { case 'f': fontname = strdup(optarg); break; + case 'w': + config.disable_ws = 1; + break; case 'v': printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); @@ -263,7 +269,9 @@ int main(int argc, char **argv) { * workspaces. Everything else (creating the bars, showing the right workspace- * buttons and more) is taken care of by the event-driveniness of the code */ i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + if (!config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } /* The name of this function is actually misleading. Even if no -c is specified, * this function initiates the watchers to listen on stdin and react accordingly */ diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 2da2e6f7..e7c08060 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -744,8 +744,10 @@ void reconfig_windows() { /* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */ values[1] = config.hide_on_modifier; /* The events we want to receive */ - values[2] = XCB_EVENT_MASK_EXPOSURE | - XCB_EVENT_MASK_BUTTON_PRESS; + values[2] = XCB_EVENT_MASK_EXPOSURE; + if (!config.disable_ws) { + values[2] |= XCB_EVENT_MASK_BUTTON_PRESS; + } xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, xcb_screen->root_depth, walk->bar, @@ -932,6 +934,10 @@ void draw_bars() { MIN(outputs_walk->rect.w - 4, statusline_width), font_height); } + if (config.disable_ws) { + continue; + } + i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { DLOG("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); @@ -978,10 +984,10 @@ void draw_bars() { i += 10 + ws_walk->name_width; } - redraw_bars(); - i = 0; } + + redraw_bars(); } /* From bf078c673fc641baaa83fdd1d9c10a76d6f14552 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 22 Apr 2011 00:42:24 +0200 Subject: [PATCH 159/185] Allow space after space --- i3bar/doc/i3bar.man | 4 ++-- i3bar/src/main.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 44d5e8ac..2ff7494b 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -9,7 +9,7 @@ i3bar - xcb-based status- and ws-bar == SYNOPSIS -*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d*['pos']] [*-f* 'font'] [*-V*] [*-h*] +*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d* ['pos']] [*-f* 'font'] [*-V*] [*-h*] == OPTIONS @@ -24,7 +24,7 @@ Hide the bar, when 'mod4' is not pressed. With this, dockmode will not be set, a If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars. This is the default behavior of i3bar. -*-d*['pos']*, --dock*[*=*'pos']:: +*-d* \['pos']*, --dock*[*=*'pos']:: Put i3bar in dockmode. This will reserve some space for it, so it does not overlap other clients. You can specify either *bottom* (default) or *top* as 'pos'. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 4a859254..1c323643 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -81,11 +81,11 @@ static void free_colors(struct xcb_color_strings_t *colors) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m|-d[pos]] [-f font] [-V] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-c command] [-m|-d [pos]] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); printf("-c \tExecute to get stdin\n"); printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); - printf("-d[]\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\n"); + printf("-d []\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\n"); printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); printf("\t\tand a SIGCONT on unhiding of the bars\n"); printf("-f \tUse X-Core-Font for display\n"); @@ -151,7 +151,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:d::mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:d:mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); From d31384e9553a456c9a799396a5a6ba7e81536c27 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 22 Apr 2011 01:18:57 +0200 Subject: [PATCH 160/185] Revert "Allow space after space" This reverts commit c9334c922de120a08e66cb3a8c340fc1a453bf55. --- i3bar/doc/i3bar.man | 4 ++-- i3bar/src/main.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 2ff7494b..44d5e8ac 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -9,7 +9,7 @@ i3bar - xcb-based status- and ws-bar == SYNOPSIS -*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d* ['pos']] [*-f* 'font'] [*-V*] [*-h*] +*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d*['pos']] [*-f* 'font'] [*-V*] [*-h*] == OPTIONS @@ -24,7 +24,7 @@ Hide the bar, when 'mod4' is not pressed. With this, dockmode will not be set, a If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars. This is the default behavior of i3bar. -*-d* \['pos']*, --dock*[*=*'pos']:: +*-d*['pos']*, --dock*[*=*'pos']:: Put i3bar in dockmode. This will reserve some space for it, so it does not overlap other clients. You can specify either *bottom* (default) or *top* as 'pos'. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 1c323643..4a859254 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -81,11 +81,11 @@ static void free_colors(struct xcb_color_strings_t *colors) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m|-d [pos]] [-f font] [-V] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-c command] [-m|-d[pos]] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); printf("-c \tExecute to get stdin\n"); printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); - printf("-d []\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\n"); + printf("-d[]\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\n"); printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); printf("\t\tand a SIGCONT on unhiding of the bars\n"); printf("-f \tUse X-Core-Font for display\n"); @@ -151,7 +151,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:d:mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:d::mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); From e7c2b25ddd4d589ad58bb8f1931d9ebd34e9db78 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 19:54:31 +0200 Subject: [PATCH 161/185] Fix compiler-warnings from libev --- i3bar/src/ipc.c | 29 ++++++++++++++++++++--------- i3bar/src/main.c | 21 ++++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index d06864c7..f943b4f0 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -20,8 +20,8 @@ #include "common.h" -ev_io i3_connection; -ev_timer reconn; +ev_io *i3_connection; +ev_timer *reconn = NULL; const char *sock_path; @@ -52,8 +52,14 @@ void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { * */ void reconnect() { - ev_timer_init(&reconn, retry_connection, 0.25, 0.25); - ev_timer_start(main_loop, &reconn); + if (reconn == NULL) { + if ((reconn = malloc(sizeof(ev_timer))) == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + } + ev_timer_init(reconn, retry_connection, 0.25, 0.25); + ev_timer_start(main_loop, reconn); } /* @@ -257,7 +263,7 @@ int i3_send_msg(uint32_t type, const char *payload) { uint32_t written = 0; while (to_write > 0) { - int n = write(i3_connection.fd, buffer + written, to_write); + int n = write(i3_connection->fd, buffer + written, to_write); if (n == -1) { ELOG("write() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); @@ -295,8 +301,13 @@ int init_connection(const char *socket_path) { return 0; } - ev_io_init(&i3_connection, &got_data, sockfd, EV_READ); - ev_io_start(main_loop, &i3_connection); + i3_connection = malloc(sizeof(ev_io)); + if (i3_connection == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + ev_io_init(i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, i3_connection); return 1; } @@ -304,8 +315,8 @@ int init_connection(const char *socket_path) { * Destroy the connection to i3. */ void destroy_connection() { - close(i3_connection.fd); - ev_io_stop(main_loop, &i3_connection); + close(i3_connection->fd); + ev_io_stop(main_loop, i3_connection); } /* diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 4a859254..190b04a2 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -281,15 +281,22 @@ int main(int argc, char **argv) { /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us * some calls to free() */ - ev_signal sig_term, sig_int, sig_hup; + ev_signal *sig_term = malloc(sizeof(ev_signal)); + ev_signal *sig_int = malloc(sizeof(ev_signal)); + ev_signal *sig_hup = malloc(sizeof(ev_signal)); - ev_signal_init(&sig_term, &sig_cb, SIGTERM); - ev_signal_init(&sig_int, &sig_cb, SIGINT); - ev_signal_init(&sig_hup, &sig_cb, SIGHUP); + if (sig_term == NULL || sig_int == NULL || sig_hup == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } - ev_signal_start(main_loop, &sig_term); - ev_signal_start(main_loop, &sig_int); - ev_signal_start(main_loop, &sig_hup); + ev_signal_init(sig_term, &sig_cb, SIGTERM); + ev_signal_init(sig_int, &sig_cb, SIGINT); + ev_signal_init(sig_hup, &sig_cb, SIGHUP); + + ev_signal_start(main_loop, sig_term); + ev_signal_start(main_loop, sig_int); + ev_signal_start(main_loop, sig_hup); /* From here on everything should run smooth for itself, just start listening for * events. We stop simply stop the event-loop, when we are finished */ From b150ec1c47cc8e02acc0a309bda762615d0efa70 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 20:23:12 +0200 Subject: [PATCH 162/185] Apply ugly yajl-compatibility-fix (thx sECuRE) --- i3bar/common.mk | 4 ++++ i3bar/src/outputs.c | 23 +++++++++++++++++++++-- i3bar/src/workspaces.c | 22 ++++++++++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/i3bar/common.mk b/i3bar/common.mk index db0e549d..1db1558a 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -7,6 +7,10 @@ PREFIX=/usr # The escaping is absurd, but we need to escape for shell, sed, make, define GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1), branch $(shell [ -f .git/HEAD ] && sed 's/ref: refs\/heads\/\(.*\)/\\\\\\"\1\\\\\\"/g' .git/HEAD || echo 'unknown'))" +# Fallback for libyajl 1 which did not include yajl_version.h. We need +# YAJL_MAJOR from that file to decide which code path should be used. +CFLAGS += -idirafter yajl-fallback + CFLAGS += -Wall CFLAGS += -pipe CFLAGS += -Iinclude diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 20ff8276..0619d8b0 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "common.h" @@ -60,7 +61,11 @@ static int outputs_boolean_cb(void *params_, bool val) { * Parse an integer (current_workspace or the rect) * */ +#if YAJL_MAJOR >= 2 +static int outputs_integer_cb(void *params_, long long val) { +#else static int outputs_integer_cb(void *params_, long val) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; if (!strcmp(params->cur_key, "current_workspace")) { @@ -100,7 +105,11 @@ static int outputs_integer_cb(void *params_, long val) { * Parse a string (name) * */ +#if YAJL_MAJOR >= 2 +static int outputs_string_cb(void *params_, const unsigned char *val, size_t len) { +#else static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; if (!strcmp(params->cur_key, "current_workspace")) { @@ -186,7 +195,11 @@ static int outputs_end_map_cb(void *params_) { * Essentially we just save it in the parsing-state * */ -static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { +#if YAJL_MAJOR >= 2 +static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) { +#else +static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned keyLen) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); @@ -233,10 +246,14 @@ void parse_outputs_json(char *json) { params.json = json; yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; +#if YAJL_MAJOR < 2 + yajl_parser_config parse_conf = { 0, 0 }; handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); +#else + handle = yajl_alloc(&outputs_callbacks, NULL, (void*) ¶ms); +#endif state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -245,7 +262,9 @@ void parse_outputs_json(char *json) { case yajl_status_ok: break; case yajl_status_client_canceled: +#if YAJL_MAJOR < 2 case yajl_status_insufficient_data: +#endif case yajl_status_error: ELOG("Could not parse outputs-reply!\n"); exit(EXIT_FAILURE); diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 89f7757d..50f7f754 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "common.h" @@ -58,7 +59,11 @@ static int workspaces_boolean_cb(void *params_, bool val) { * Parse an integer (num or the rect) * */ +#if YAJL_MAJOR >= 2 +static int workspaces_integer_cb(void *params_, long long val) { +#else static int workspaces_integer_cb(void *params_, long val) { +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; if (!strcmp(params->cur_key, "num")) { @@ -99,8 +104,11 @@ static int workspaces_integer_cb(void *params_, long val) { * Parse a string (name, output) * */ +#if YAJL_MAJOR >= 2 +static int workspaces_string_cb(void *params_, const unsigned char *val, size_t len) { +#else static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) { - +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; char *output_name; @@ -179,7 +187,11 @@ static int workspaces_start_map_cb(void *params_) { * Essentially we just save it in the parsing-state * */ +#if YAJL_MAJOR >= 2 +static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) { +#else static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; FREE(params->cur_key); @@ -225,10 +237,14 @@ void parse_workspaces_json(char *json) { params.json = json; yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; +#if YAJL_MAJOR < 2 + yajl_parser_config parse_conf = { 0, 0 }; handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); +#else + handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) ¶ms); +#endif state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -237,7 +253,9 @@ void parse_workspaces_json(char *json) { case yajl_status_ok: break; case yajl_status_client_canceled: +#if YAJL_MAJOR < 2 case yajl_status_insufficient_data: +#endif case yajl_status_error: ELOG("Could not parse workspaces-reply!\n"); exit(EXIT_FAILURE); From 08d454b25e073e0a8f3b2d3fc1104ba24c3d64ac Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 20:23:12 +0200 Subject: [PATCH 163/185] Apply ugly yajl-compatibility-fix (thx sECuRE) --- i3bar/common.mk | 4 ++++ i3bar/src/outputs.c | 23 +++++++++++++++++++++-- i3bar/src/workspaces.c | 22 ++++++++++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/i3bar/common.mk b/i3bar/common.mk index db0e549d..1db1558a 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -7,6 +7,10 @@ PREFIX=/usr # The escaping is absurd, but we need to escape for shell, sed, make, define GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1), branch $(shell [ -f .git/HEAD ] && sed 's/ref: refs\/heads\/\(.*\)/\\\\\\"\1\\\\\\"/g' .git/HEAD || echo 'unknown'))" +# Fallback for libyajl 1 which did not include yajl_version.h. We need +# YAJL_MAJOR from that file to decide which code path should be used. +CFLAGS += -idirafter yajl-fallback + CFLAGS += -Wall CFLAGS += -pipe CFLAGS += -Iinclude diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 3577d82b..9ffe259e 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "common.h" @@ -59,7 +60,11 @@ static int outputs_boolean_cb(void *params_, bool val) { * Parse an integer (current_workspace or the rect) * */ +#if YAJL_MAJOR >= 2 +static int outputs_integer_cb(void *params_, long long val) { +#else static int outputs_integer_cb(void *params_, long val) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; if (!strcmp(params->cur_key, "current_workspace")) { @@ -99,7 +104,11 @@ static int outputs_integer_cb(void *params_, long val) { * Parse a string (name) * */ +#if YAJL_MAJOR >= 2 +static int outputs_string_cb(void *params_, const unsigned char *val, size_t len) { +#else static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; if (strcmp(params->cur_key, "name")) { @@ -169,7 +178,11 @@ static int outputs_end_map_cb(void *params_) { * Essentially we just save it in the parsing-state * */ -static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { +#if YAJL_MAJOR >= 2 +static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) { +#else +static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned keyLen) { +#endif struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); @@ -216,10 +229,14 @@ void parse_outputs_json(char *json) { params.json = json; yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; +#if YAJL_MAJOR < 2 + yajl_parser_config parse_conf = { 0, 0 }; handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); +#else + handle = yajl_alloc(&outputs_callbacks, NULL, (void*) ¶ms); +#endif state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -228,7 +245,9 @@ void parse_outputs_json(char *json) { case yajl_status_ok: break; case yajl_status_client_canceled: +#if YAJL_MAJOR < 2 case yajl_status_insufficient_data: +#endif case yajl_status_error: ELOG("Could not parse outputs-reply!\n"); exit(EXIT_FAILURE); diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 89f7757d..50f7f754 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "common.h" @@ -58,7 +59,11 @@ static int workspaces_boolean_cb(void *params_, bool val) { * Parse an integer (num or the rect) * */ +#if YAJL_MAJOR >= 2 +static int workspaces_integer_cb(void *params_, long long val) { +#else static int workspaces_integer_cb(void *params_, long val) { +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; if (!strcmp(params->cur_key, "num")) { @@ -99,8 +104,11 @@ static int workspaces_integer_cb(void *params_, long val) { * Parse a string (name, output) * */ +#if YAJL_MAJOR >= 2 +static int workspaces_string_cb(void *params_, const unsigned char *val, size_t len) { +#else static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) { - +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; char *output_name; @@ -179,7 +187,11 @@ static int workspaces_start_map_cb(void *params_) { * Essentially we just save it in the parsing-state * */ +#if YAJL_MAJOR >= 2 +static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) { +#else static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { +#endif struct workspaces_json_params *params = (struct workspaces_json_params*) params_; FREE(params->cur_key); @@ -225,10 +237,14 @@ void parse_workspaces_json(char *json) { params.json = json; yajl_handle handle; - yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; +#if YAJL_MAJOR < 2 + yajl_parser_config parse_conf = { 0, 0 }; handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); +#else + handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) ¶ms); +#endif state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -237,7 +253,9 @@ void parse_workspaces_json(char *json) { case yajl_status_ok: break; case yajl_status_client_canceled: +#if YAJL_MAJOR < 2 case yajl_status_insufficient_data: +#endif case yajl_status_error: ELOG("Could not parse workspaces-reply!\n"); exit(EXIT_FAILURE); From 31f661ec7390c7fde51f6483d59ef1cd22ddd9a2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 19:54:31 +0200 Subject: [PATCH 164/185] Fix compiler-warnings from libev --- i3bar/src/ipc.c | 29 ++++++++++++++++++++--------- i3bar/src/main.c | 21 ++++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index d5c18033..e7303bf8 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -20,8 +20,8 @@ #include "common.h" -ev_io i3_connection; -ev_timer reconn; +ev_io *i3_connection; +ev_timer *reconn = NULL; const char *sock_path; @@ -52,8 +52,14 @@ void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { * */ void reconnect() { - ev_timer_init(&reconn, retry_connection, 0.25, 0.25); - ev_timer_start(main_loop, &reconn); + if (reconn == NULL) { + if ((reconn = malloc(sizeof(ev_timer))) == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + } + ev_timer_init(reconn, retry_connection, 0.25, 0.25); + ev_timer_start(main_loop, reconn); } /* @@ -255,7 +261,7 @@ int i3_send_msg(uint32_t type, const char *payload) { uint32_t written = 0; while (to_write > 0) { - int n = write(i3_connection.fd, buffer + written, to_write); + int n = write(i3_connection->fd, buffer + written, to_write); if (n == -1) { ELOG("write() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); @@ -293,8 +299,13 @@ int init_connection(const char *socket_path) { return 0; } - ev_io_init(&i3_connection, &got_data, sockfd, EV_READ); - ev_io_start(main_loop, &i3_connection); + i3_connection = malloc(sizeof(ev_io)); + if (i3_connection == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + ev_io_init(i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, i3_connection); return 1; } @@ -302,8 +313,8 @@ int init_connection(const char *socket_path) { * Destroy the connection to i3. */ void destroy_connection() { - close(i3_connection.fd); - ev_io_stop(main_loop, &i3_connection); + close(i3_connection->fd); + ev_io_stop(main_loop, i3_connection); } /* diff --git a/i3bar/src/main.c b/i3bar/src/main.c index dd3b9315..14bd917d 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -232,15 +232,22 @@ int main(int argc, char **argv) { /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us * some calls to free() */ - ev_signal sig_term, sig_int, sig_hup; + ev_signal *sig_term = malloc(sizeof(ev_signal)); + ev_signal *sig_int = malloc(sizeof(ev_signal)); + ev_signal *sig_hup = malloc(sizeof(ev_signal)); - ev_signal_init(&sig_term, &sig_cb, SIGTERM); - ev_signal_init(&sig_int, &sig_cb, SIGINT); - ev_signal_init(&sig_hup, &sig_cb, SIGHUP); + if (sig_term == NULL || sig_int == NULL || sig_hup == NULL) { + ELOG("malloc() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } - ev_signal_start(main_loop, &sig_term); - ev_signal_start(main_loop, &sig_int); - ev_signal_start(main_loop, &sig_hup); + ev_signal_init(sig_term, &sig_cb, SIGTERM); + ev_signal_init(sig_int, &sig_cb, SIGINT); + ev_signal_init(sig_hup, &sig_cb, SIGHUP); + + ev_signal_start(main_loop, sig_term); + ev_signal_start(main_loop, sig_int); + ev_signal_start(main_loop, sig_hup); /* From here on everything should run smooth for itself, just start listening for * events. We stop simply stop the event-loop, when we are finished */ From cdc5e6527f4a8f9e513170267268b824330744b5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 20:55:40 +0200 Subject: [PATCH 165/185] yajl-compatibility: Forgot to git-add that one --- i3bar/yajl-fallback/yajl/yajl_version.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 i3bar/yajl-fallback/yajl/yajl_version.h diff --git a/i3bar/yajl-fallback/yajl/yajl_version.h b/i3bar/yajl-fallback/yajl/yajl_version.h new file mode 100644 index 00000000..c6da442e --- /dev/null +++ b/i3bar/yajl-fallback/yajl/yajl_version.h @@ -0,0 +1,7 @@ +#ifndef YAJL_VERSION_H_ +#define YAJL_VERSION_H_ +/* Fallback for libyajl 1 which does not provide yajl_version.h */ +#define YAJL_MAJOR 1 +#define YAJL_MINOR 0 +#define YAJL_MICRO 0 +#endif From ddddc82cbdf213871dafd423e53b843b9034692a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 28 Apr 2011 20:55:40 +0200 Subject: [PATCH 166/185] yajl-compatibility: Forgot to git-add that one --- i3bar/yajl-fallback/yajl/yajl_version.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 i3bar/yajl-fallback/yajl/yajl_version.h diff --git a/i3bar/yajl-fallback/yajl/yajl_version.h b/i3bar/yajl-fallback/yajl/yajl_version.h new file mode 100644 index 00000000..c6da442e --- /dev/null +++ b/i3bar/yajl-fallback/yajl/yajl_version.h @@ -0,0 +1,7 @@ +#ifndef YAJL_VERSION_H_ +#define YAJL_VERSION_H_ +/* Fallback for libyajl 1 which does not provide yajl_version.h */ +#define YAJL_MAJOR 1 +#define YAJL_MINOR 0 +#define YAJL_MICRO 0 +#endif From 778268c9bbd176f976ee0ea4c137d1f90a8bd229 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 3 May 2011 12:38:57 +0200 Subject: [PATCH 167/185] Fix unaligned memory access on sparc (Thanks David Coppa) --- i3bar/src/ipc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index f943b4f0..2f5d481c 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -183,9 +183,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { } char *walk = header + strlen(I3_IPC_MAGIC); - uint32_t size = *((uint32_t*) walk); + uint32_t size; + memcpy(&size, (uint32_t*)walk, sizeof(uint32_t)); walk += sizeof(uint32_t); - uint32_t type = *((uint32_t*) walk); + uint32_t type; + memcpy(&type, (uint32_t*)walk, sizeof(uint32_t)); /* Now that we know, what to expect, we can start read()ing the rest * of the message */ From 3b19edf148b57c018220984e279689439673747a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 3 May 2011 12:38:57 +0200 Subject: [PATCH 168/185] Fix unaligned memory access on sparc (Thanks David Coppa) --- i3bar/src/ipc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index e7303bf8..cff3ed38 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -181,9 +181,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { } char *walk = header + strlen(I3_IPC_MAGIC); - uint32_t size = *((uint32_t*) walk); + uint32_t size; + memcpy(&size, (uint32_t*)walk, sizeof(uint32_t)); walk += sizeof(uint32_t); - uint32_t type = *((uint32_t*) walk); + uint32_t type; + memcpy(&type, (uint32_t*)walk, sizeof(uint32_t)); /* Now that we know, what to expect, we can start read()ing the rest * of the message */ From 97827372af134b85154a90b51df790723374c5b7 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 8 Jul 2011 23:16:33 +0200 Subject: [PATCH 169/185] Bugfix: Correctly handle EOF on stdin (Thanks woddf2) --- i3bar/src/child.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 890dce29..a8de6fb9 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -38,8 +38,12 @@ char *statusline_buffer = NULL; void cleanup() { if (stdin_io != NULL) { ev_io_stop(main_loop, stdin_io); - ev_child_stop(main_loop, child_sig); FREE(stdin_io); + FREE(statusline_buffer); + } + + if (child_sig != NULL) { + ev_child_stop(main_loop, child_sig); FREE(child_sig); FREE(statusline_buffer); } @@ -69,18 +73,23 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { exit(EXIT_FAILURE); } if (n == 0) { - if (rec == buffer_len) { - buffer_len += STDIN_CHUNK_SIZE; - buffer = realloc(buffer, buffer_len); - } else { - if (rec != 0) { - /* remove trailing newline and finish up */ - buffer[rec-1] = '\0'; - } - break; + if (rec != 0) { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; } + + /* end of file, kill the watcher */ + DLOG("stdin: EOF\n"); + ev_io_stop(loop, watcher); + FREE(stdin_io); + break; } rec += n; + + if (rec == buffer_len) { + buffer_len += STDIN_CHUNK_SIZE; + buffer = realloc(buffer, buffer_len); + } } if (*buffer == '\0') { FREE(buffer); From 3d05fe7a52a7c50fb09b441c329cf93a79c44753 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 10 Jul 2011 04:34:18 +0200 Subject: [PATCH 170/185] Use cleanup() in child.c --- i3bar/src/child.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index a8de6fb9..982617ff 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -45,7 +45,6 @@ void cleanup() { if (child_sig != NULL) { ev_child_stop(main_loop, child_sig); FREE(child_sig); - FREE(statusline_buffer); } } @@ -80,8 +79,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { /* end of file, kill the watcher */ DLOG("stdin: EOF\n"); - ev_io_stop(loop, watcher); - FREE(stdin_io); + cleanup(); break; } rec += n; From 8734337fb5ae85de42db2feb3c5f97491fde04e2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 15 Jul 2011 01:31:02 +0200 Subject: [PATCH 171/185] Stop the reconn-timer before starting it again, else it's running twice --- i3bar/src/ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 2f5d481c..6bfbc3ec 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -57,6 +57,8 @@ void reconnect() { ELOG("malloc() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } + } else { + ev_timer_stop(main_loop, reconn); } ev_timer_init(reconn, retry_connection, 0.25, 0.25); ev_timer_start(main_loop, reconn); From a2a7de5e542d50be3d8fc0709461091131099156 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 19 Jul 2011 04:21:36 +0200 Subject: [PATCH 172/185] Respect and use CPPFLAGS --- i3bar/Makefile | 2 +- i3bar/common.mk | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index d4cc59b9..216e68cc 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -19,7 +19,7 @@ doc: src/%.o: src/%.c ${HEADERS} echo "CC $<" - $(CC) $(CFLAGS) -c -o $@ $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< install: all echo "INSTALL" diff --git a/i3bar/common.mk b/i3bar/common.mk index 1db1558a..ec633007 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -13,9 +13,10 @@ CFLAGS += -idirafter yajl-fallback CFLAGS += -Wall CFLAGS += -pipe -CFLAGS += -Iinclude CFLAGS += -g -CFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" + +CPPFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" +CPPFLAGS += -Iinclude LDFLAGS += -lev LDFLAGS += -lyajl From 8e275d85b5a64b2230193bb01a4abdc0c2f79b99 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 31 Jul 2011 15:58:14 +0200 Subject: [PATCH 173/185] Correct some minor mistakes in the manpage (thx sECuRE) --- i3bar/doc/i3bar.man | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 44d5e8ac..84e4c968 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -5,7 +5,7 @@ v0.6, September 2010 == NAME -i3bar - xcb-based status- and ws-bar +i3bar - xcb-based status- and workspace-bar == SYNOPSIS @@ -43,7 +43,7 @@ Display a short help-message and exit It does not sample any status-information itself, so you still need a program like *i3status*(1) or *conky*(1) for that. -i3bar does not support any color or other markups, so stdin should be plain utf8, one line at a time. If you use *i3status*(1), you therefore should specify 'output_format = none' in the general-section of it's configfile. +i3bar does not support any color or other markups, so stdin should be plain utf8, one line at a time. If you use *i3status*(1), you therefore should specify 'output_format = none' in the general section of its config file. Also, you should disable the internal workspace bar of *i3*(1), when using *i3bar* by specifying 'workspace_bar no' in your *i3*-configfile. From 8d09ed7bf53ebf39c8139146465c520e2edc0837 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 31 Jul 2011 16:16:17 +0200 Subject: [PATCH 174/185] Update changelog and copyright, bump version and more --- i3bar/CHANGELOG | 12 ++++++++++++ i3bar/LICENSE | 2 +- i3bar/doc/i3bar.man | 2 +- i3bar/include/child.h | 2 +- i3bar/include/common.h | 2 +- i3bar/include/ipc.h | 2 +- i3bar/include/outputs.h | 2 +- i3bar/include/util.h | 2 +- i3bar/include/workspaces.h | 2 +- i3bar/include/xcb.h | 2 +- i3bar/src/child.c | 2 +- i3bar/src/ipc.c | 2 +- i3bar/src/main.c | 4 ++-- i3bar/src/outputs.c | 2 +- i3bar/src/workspaces.c | 2 +- i3bar/src/xcb.c | 2 +- 16 files changed, 28 insertions(+), 16 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index 0b6958d2..32d880cd 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,6 +1,18 @@ +v0.7 +===== +- Make i3bar compatible with i3-4.0 +- Implement disabling the workspace buttons +- Add Color for focused ws +- Add support for I3_SOCKET_PATH-atom - Implement different dock-positions - Hide-on-modifier is now the default behavior +- Change default socketpath to /tmp/i3-ipc.sock +- Use I3SOCK environment-variable +- Bugfix: Stop the reconn-timer before starting it again, else it's running twice +- Bugfix: Don't SIGSTOP child in dockmode +- Bugfix: If hide-on-modifier is set, stop the child after starting - Bugfix: Recover from closed socket +- Some minor bugfixes v0.6 ===== diff --git a/i3bar/LICENSE b/i3bar/LICENSE index 4fe52a0c..6fe0f421 100644 --- a/i3bar/LICENSE +++ b/i3bar/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010, Axel Wagner +Copyright (c) 2010-2011, Axel Wagner All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index 84e4c968..5faa16c3 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -1,7 +1,7 @@ i3bar(1) ======== Axel Wagner -v0.6, September 2010 +v0.7, July 2011 == NAME diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 69cfc576..2622b3b0 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 8b439ee0..22e3ca43 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index ee273a45..35f2d0f7 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 69a34a12..f74048da 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 1952b039..60949320 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 64da21a7..2055d8b8 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index b1732905..a7924291 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 982617ff..3f59d060 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 6bfbc3ec..3d2cca58 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 190b04a2..d3107bfb 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * @@ -184,7 +184,7 @@ int main(int argc, char **argv) { config.disable_ws = 1; break; case 'v': - printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); + printf("i3bar version " I3BAR_VERSION " © 2010-2011 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; case 'V': diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 0619d8b0..8cfdaa98 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 50f7f754..db812673 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e7c08060..62160f40 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1,7 +1,7 @@ /* * i3bar - an xcb-based status- and ws-bar for i3 * - * © 2010 Axel Wagner and contributors + * © 2010-2011 Axel Wagner and contributors * * See file LICNSE for license information * From 3302b22f71d3d77b4183ab261e712ca2fee6268e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 31 Jul 2011 18:26:52 +0200 Subject: [PATCH 175/185] Bugfix: Delay event-subscription until reconnect (thx aniou) --- i3bar/src/ipc.c | 8 +++++++- i3bar/src/main.c | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 3d2cca58..85cd234f 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -44,7 +44,13 @@ void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { retries = 8; ev_timer_stop(loop, w); subscribe_events(); - reconfig_windows(); + + /* We get the current outputs and workspaces, to + * reconfigure all bars with the current configuration */ + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + if (!config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } } /* diff --git a/i3bar/src/main.c b/i3bar/src/main.c index d3107bfb..e91511ef 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -260,17 +260,17 @@ int main(int argc, char **argv) { free_colors(&colors); init_outputs(); - init_connection(socket_path); + if (init_connection(socket_path)) { + /* We subscribe to the i3-events we need */ + subscribe_events(); - /* We subscribe to the i3-events we need */ - subscribe_events(); - - /* We initiate the main-function by requesting infos about the outputs and - * workspaces. Everything else (creating the bars, showing the right workspace- - * buttons and more) is taken care of by the event-driveniness of the code */ - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - if (!config.disable_ws) { - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + /* We initiate the main-function by requesting infos about the outputs and + * workspaces. Everything else (creating the bars, showing the right workspace- + * buttons and more) is taken care of by the event-driveniness of the code */ + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + if (!config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } } /* The name of this function is actually misleading. Even if no -c is specified, From a0bb296f1bf599434eda7136e9b47c76ae8f6870 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 14:39:45 +0200 Subject: [PATCH 176/185] update debian packaging --- debian/control | 2 +- debian/rules | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 615a5181..7c5b462e 100644 --- a/debian/control +++ b/debian/control @@ -26,7 +26,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, x11-utils Provides: x-window-manager Suggests: rxvt-unicode | x-terminal-emulator Recommends: xfonts-base, libanyevent-i3-perl, libanyevent-perl, libipc-run-perl -Description: an improved dynamic tiling window manager +Description: improved dynamic tiling window manager Key features of i3 are correct implementation of Xinerama (workspaces are assigned to virtual screens, i3 does the right thing when attaching new monitors), XrandR support (not done yet), horizontal and vertical columns diff --git a/debian/rules b/debian/rules index d6393980..c392f715 100755 --- a/debian/rules +++ b/debian/rules @@ -13,11 +13,16 @@ config.status: configure dh_testdir touch $@ -build: +build: build-arch build-indep + +build-arch: build-stamp +build-indep: build-stamp + +build-stamp: dh_testdir # Add here commands to compile the package. - $(MAKE) + $(MAKE) TERM_EMU=x-terminal-emulator $(MAKE) -C man $(MAKE) -C docs @@ -45,6 +50,9 @@ install: build cp man/i3.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 cp man/i3-msg.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 cp man/i3-input.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 + cp man/i3-nagbar.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 + cp man/i3-config-wizard.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 + cp man/i3-migrate-config-to-v4.1 $(CURDIR)/debian/i3-wm/usr/share/man/man1 # Build architecture-independent files here. From 9fbf6e3992d37d9ce2b081d146558b3ccaf013b8 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 14:40:01 +0200 Subject: [PATCH 177/185] docs/userguide: use i3bar instead of dzen2 in the 'exec' example (Thanks ubitux) --- docs/userguide | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/userguide b/docs/userguide index 6941af91..70d0f7d4 100644 --- a/docs/userguide +++ b/docs/userguide @@ -523,7 +523,7 @@ exec_always command *Examples*: -------------------------------- -exec i3status | dzen2 -dock +exec i3status | i3bar -d exec_always ~/my_script.sh -------------------------------- From 9e4bd9a1577633b61abbb6abe301586fc0be6b90 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 14:42:21 +0200 Subject: [PATCH 178/185] docs/userguide: remove the bar.* color keys (Thanks aksr) --- docs/userguide | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/userguide b/docs/userguide index 70d0f7d4..e7a0459b 100644 --- a/docs/userguide +++ b/docs/userguide @@ -572,12 +572,6 @@ client.unfocused:: A client which is not the focused one of its container. client.urgent:: A client which has its urgency hint activated. -bar.focused:: - The current workspace in the bottom bar. -bar.unfocused:: - All other workspaces in the bottom bar. -bar.urgent:: - A workspace which has at least one client with an activated urgency hint. You can also specify the color to be used to paint the background of the client windows. This color will be used to paint the window on top of which the client From 339a7cb8c324377e1b2ead7daf02b7132e1ad58d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 16:13:19 +0200 Subject: [PATCH 179/185] =?UTF-8?q?make=20i3bar=20use=20i3=E2=80=99s=20com?= =?UTF-8?q?mon.mk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- common.mk | 2 +- i3bar/Makefile | 6 +++-- i3bar/common.mk | 35 ------------------------- i3bar/src/main.c | 2 +- i3bar/yajl-fallback/yajl/yajl_version.h | 7 ----- 6 files changed, 7 insertions(+), 47 deletions(-) delete mode 100644 i3bar/common.mk delete mode 100644 i3bar/yajl-fallback/yajl/yajl_version.h diff --git a/Makefile b/Makefile index 3bdffbb4..bbe08c0b 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ else UNUSED:=$(shell $(MAKE) loglevels.h) endif -SUBDIRS=i3-msg i3-input i3-nagbar i3-config-wizard +SUBDIRS=i3-msg i3-input i3-nagbar i3-config-wizard i3bar # Depend on the specific file (.c for each .o) and on all headers src/%.o: src/%.c ${HEADERS} diff --git a/common.mk b/common.mk index 0a695e7d..d7c0c5ac 100644 --- a/common.mk +++ b/common.mk @@ -93,7 +93,7 @@ endif # Fallback for libyajl 1 which did not include yajl_version.h. We need # YAJL_MAJOR from that file to decide which code path should be used. -CFLAGS += -idirafter yajl-fallback +CFLAGS += -idirafter $(TOPDIR)/yajl-fallback ifneq (,$(filter Linux GNU GNU/%, $(UNAME))) CPPFLAGS += -D_GNU_SOURCE diff --git a/i3bar/Makefile b/i3bar/Makefile index 216e68cc..643065df 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -1,4 +1,4 @@ -TOPDIR=$(shell pwd) +TOPDIR=.. include $(TOPDIR)/common.mk @@ -6,11 +6,13 @@ FILES:=$(wildcard src/*.c) FILES:=$(FILES:.c=.o) HEADERS:=$(wildcard include/*.h) +CPPFLAGS += -I$(TOPDIR)/include + all: i3bar doc i3bar: ${FILES} echo "LINK" - $(CC) -o i3bar ${FILES} ${LDFLAGS} + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) doc: echo "" diff --git a/i3bar/common.mk b/i3bar/common.mk deleted file mode 100644 index ec633007..00000000 --- a/i3bar/common.mk +++ /dev/null @@ -1,35 +0,0 @@ -INSTALL=install -ifndef DEBUG -DEBUG=1 -endif -PREFIX=/usr - -# The escaping is absurd, but we need to escape for shell, sed, make, define -GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1), branch $(shell [ -f .git/HEAD ] && sed 's/ref: refs\/heads\/\(.*\)/\\\\\\"\1\\\\\\"/g' .git/HEAD || echo 'unknown'))" - -# Fallback for libyajl 1 which did not include yajl_version.h. We need -# YAJL_MAJOR from that file to decide which code path should be used. -CFLAGS += -idirafter yajl-fallback - -CFLAGS += -Wall -CFLAGS += -pipe -CFLAGS += -g - -CPPFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" -CPPFLAGS += -Iinclude - -LDFLAGS += -lev -LDFLAGS += -lyajl -LDFLAGS += -lxcb -LDFLAGS += -lX11 -LDFLAGS += -L/usr/local/lib - -ifeq ($(DEBUG),1) -CFLAGS += -g3 -else -CFLAGS += -O2 -endif - -.SILENT: - -.PHONY: install clean diff --git a/i3bar/src/main.c b/i3bar/src/main.c index e91511ef..0def3057 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -184,7 +184,7 @@ int main(int argc, char **argv) { config.disable_ws = 1; break; case 'v': - printf("i3bar version " I3BAR_VERSION " © 2010-2011 Axel Wagner and contributors\n"); + printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; case 'V': diff --git a/i3bar/yajl-fallback/yajl/yajl_version.h b/i3bar/yajl-fallback/yajl/yajl_version.h deleted file mode 100644 index c6da442e..00000000 --- a/i3bar/yajl-fallback/yajl/yajl_version.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef YAJL_VERSION_H_ -#define YAJL_VERSION_H_ -/* Fallback for libyajl 1 which does not provide yajl_version.h */ -#define YAJL_MAJOR 1 -#define YAJL_MINOR 0 -#define YAJL_MICRO 0 -#endif From 3c68a9158c28625e5fd04781e4f14c598a56b720 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 16:13:38 +0200 Subject: [PATCH 180/185] LDFLAGS: add -Wl,--as-needed. reduces .so dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let’s see if that works on all systems :) --- common.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common.mk b/common.mk index d7c0c5ac..05b10611 100644 --- a/common.mk +++ b/common.mk @@ -71,6 +71,8 @@ LIBS += $(call ldflags_for_lib, x11, X11) LIBS += $(call ldflags_for_lib, yajl, yajl) LIBS += $(call ldflags_for_lib, libev, ev) +LDFLAGS += -Wl,--as-needed + ifeq ($(UNAME),NetBSD) # We need -idirafter instead of -I to prefer the system’s iconv over GNU libiconv CFLAGS += -idirafter /usr/pkg/include From fef5a69b0903704f5c20dcb8acbfc9f310060c8a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 16:17:59 +0200 Subject: [PATCH 181/185] Mac OS X fixes: include string.h, add strndup(), disable xmllint for the docs --- i3bar/doc/Makefile | 2 +- i3bar/src/ipc.c | 1 + i3bar/src/xcb.c | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/i3bar/doc/Makefile b/i3bar/doc/Makefile index a8144cd8..69566750 100644 --- a/i3bar/doc/Makefile +++ b/i3bar/doc/Makefile @@ -2,7 +2,7 @@ all: i3bar.1 i3bar.1: i3bar.man echo "A2X i3bar" - a2x -f manpage i3bar.man + a2x --no-xmllint -f manpage i3bar.man clean: rm -f i3bar.xml i3bar.1 i3bar.html diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 85cd234f..7769fdb1 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 62160f40..b8ab5ed2 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -27,6 +27,30 @@ #include "common.h" +#if defined(__APPLE__) + +/* + * Taken from FreeBSD + * Returns a pointer to a new string which is a duplicate of the + * string, but only copies at most n characters. + * + */ +char *strndup(const char *str, size_t n) { + size_t len; + char *copy; + + for (len = 0; len < n && str[len]; len++) + continue; + + if ((copy = malloc(len + 1)) == NULL) + return (NULL); + memcpy(copy, str, len); + copy[len] = '\0'; + return (copy); +} + +#endif + /* We save the Atoms in an easy to access array, indexed by an enum */ enum { #define ATOM_DO(name) name, From 29d579c4cc4252dbded1be7a9199c721ad64b6eb Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 17:12:04 +0200 Subject: [PATCH 182/185] makefile: redirect stderr of 'which' to /dev/null when checking for lcov --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bbe08c0b..99b5c4ef 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ dist: distclean clean: rm -f src/*.o src/*.gcno src/cfgparse.tab.{c,h} src/cfgparse.yy.c src/cfgparse.{output,dot} src/cmdparse.tab.{c,h} src/cmdparse.yy.c src/cmdparse.{output,dot} loglevels.tmp include/loglevels.h - (which lcov >/dev/null && lcov -d . --zerocounters) || true + (which lcov >/dev/null 2>&1 && lcov -d . --zerocounters) || true $(MAKE) -C docs clean $(MAKE) -C man clean for dir in $(SUBDIRS); do \ From 32ce533d54f3474f11d871fa754d621e0e820dd2 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 18:09:27 +0200 Subject: [PATCH 183/185] =?UTF-8?q?enable=20-Wl,--as-needed=20only=20on=20?= =?UTF-8?q?Linux=20(doesn=E2=80=99t=20work=20on=20Mac=20OS=20X)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common.mk b/common.mk index 05b10611..ce41f287 100644 --- a/common.mk +++ b/common.mk @@ -71,7 +71,11 @@ LIBS += $(call ldflags_for_lib, x11, X11) LIBS += $(call ldflags_for_lib, yajl, yajl) LIBS += $(call ldflags_for_lib, libev, ev) +# Please test if -Wl,--as-needed works on your platform and send me a patch. +# it is known not to work on Darwin (Mac OS X) +ifneq (,$(filter Linux GNU GNU/%, $(UNAME))) LDFLAGS += -Wl,--as-needed +endif ifeq ($(UNAME),NetBSD) # We need -idirafter instead of -I to prefer the system’s iconv over GNU libiconv From 49400a2c0f20f2b1730c214026efa5189f7d4a00 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 21:23:44 +0200 Subject: [PATCH 184/185] also start i3bar in the keycode config template --- i3.config.keycodes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3.config.keycodes b/i3.config.keycodes index f0170459..e986ffb3 100644 --- a/i3.config.keycodes +++ b/i3.config.keycodes @@ -145,3 +145,7 @@ mode "resize" { } bindcode $mod+27 mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +exec i3status | i3bar -d From 1f0b24df0cde52593c55a8200053824f67fa766e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Aug 2011 23:18:32 +0200 Subject: [PATCH 185/185] add release notes for 4.0.1 --- RELEASE-NOTES-4.0.1 | 145 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 RELEASE-NOTES-4.0.1 diff --git a/RELEASE-NOTES-4.0.1 b/RELEASE-NOTES-4.0.1 new file mode 100644 index 00000000..3d9d4087 --- /dev/null +++ b/RELEASE-NOTES-4.0.1 @@ -0,0 +1,145 @@ + + ┌─────────────────────────────┐ + │ Release notes for i3 v4.0.1 │ + └─────────────────────────────┘ + +This is the second release of the new major version of i3, v4.0.1. It has been +a long time since v3.ε was released (over one year). A lot has been happening +since then, we made 736 commits – compare that to the total number of 1664 +commits for i3. + +The reason for the high number of commits and long time for this release is the +big refactoring we have been doing. Instead of using several lists and a table +as data structures, we now use a single tree of containers. These containers +represent invisible entities like your X11 root window, your different monitors +and workspaces, but also visible entities like actual windows. + +Using a tree has made a lot of things cleaner and easier – in the code *and* in +the user interface. Admittedly though, you will probably need a day or two to +get used to a few more advanced movement commands if you are used to v3.ε right +now. + + ┌────────────────────────────┐ + │ New features in v4.0.1 │ + └────────────────────────────┘ + + • Fix the build process of i3bar + • Fix the build process on Mac OS X + • i3-config-wizard: also start i3bar in the keycode config template + • userguide: Remove the obsolete bar.* colors + • userguide: Use i3bar instead of dzen2 in the 'exec' example + + ┌────────────────────────────┐ + │ New features in v4.0 │ + └────────────────────────────┘ + + • In addition to the proper flex/bison based parser for the config file + introduced in 3.δ, we now also have a flex/bison parser for commands. What + this means is that we can have more human-readable, beautiful command names + instead of cryptic commands like 'f' for fullscreen or 'mh' for move left. + In fact, the commands for the aforementioned functions *are* 'fullscreen' + and 'move left'! + + • You can now chain commands using ';' (a semicolon). One example for that is + 'workspace 3 ; exec /usr/bin/urxvt' to switch to a new workspace and open a + terminal. + + • You can specify which windows should be affected by your command by using + different criteria. A good example is '[class="Firefox"] kill' to get rid + of all Firefox windows. + + • As the configuration file needs new commands (and a few options are + obsolete), you need to change it. To make this process a little bit easier + for you, this release comes with the script i3-migrate-config-to-v4. Just + run it on your current config file and it will spit out a v4 config file to + stdout. To make things even better, i3 automatically detects v3 config files + and calls that script, so you never end up with a non-working config :). + + • Similarly to the criteria when using commands, we now have a 'for_window' + configuration directive, which lets you automatically apply certain commands + to certain windows. Use it to set border styles per window, for example with + 'for_window [class="XTerm"] border 1pixel'. + + • Since dock clients (like dzen2) are now part of the layout tree (as opposed + to a custom data structure as before), it was easy to implement top and + bottom dock areas. Programs which properly specify the dock hint get placed + on the edge of the screen they request. i3bar has the -dtop and -dbottom + parameters, for example. + + • The internal workspace bar is obsolete. Use i3bar instead. + + • Resizing now works between all windows! + + • Fullscreen now works for everything! + + • Floating now works for everything! + + • Your layout is now preserved when doing an inplace restart. + + • When you have an error in your config file, a new program called i3-nagbar + will tell you so. It offers you two buttons: One to view the error in your + $PAGER and one to edit your config in your $EDITOR. + + • The default config used key symbols (like 'bind Mod1+f fullscreen') instead + of key codes. If you use a non-qwerty layout, the program i3-config-wizard + can create a key symbol based config file based on your current layout. You + can also chose between Windows (Mod4) and Alt (Mod1) as your default + modifier. i3-config-wizard will automatically be started as long as you + don’t have a configuration file for i3. + + • Custom X cursor themes are now supported. + + • The RandR backend now respects the primary output. + + • A wrong 'font' configuration in your config file will no longer make i3 + exit. Instead, it will fall back to a different font and tell you about the + error in its log. + + • The default split direction (whether a new window gets placed right next to + the current one or below the current one) is now automatically set to + horizontal if you have a monitor that is wider than high or vertical if you + a monitor which is higher than wide. This works great with rotated monitors. + + • Sockets and temporary files are now placed in XDG_RUNTIME_DIR, if set (this + is used on systemd based systems). + + • Tools like i3bar, i3-msg etc. use the I3_SOCKET_PATH property which is set + to the X11 root window, so you don’t have to configure your socket path + anywhere. + + • The kill command kills single windows by default now. To kill a whole + application, use 'kill client'. + + • IPC: Commands can now have custom replies. When the parser encounters an + error, a proper error reply is sent. + + • There is now an 'exec_always' configuration directive which works like + 'exec' but will also be run when restarting. + + ┌────────────────────────────┐ + │ Future features │ + └────────────────────────────┘ + +Our plans were big but our time and manpower is limited. Therefore, the +following features did not make it into this release. However, the foundation +is now in place and implementing them is possible, so stay tuned! + + • Saving/Restoring specific parts of your layout + + • Session saving + + • Sticky windows + + ┌────────────────────────────┐ + │ Thanks! │ + └────────────────────────────┘ + +Thanks for testing, bugfixes, discussions and everything I forgot go out to: + + aniou, artoj, badboy, cloud, cradle, David Coppa, dbp, dothebart, eeemsi, + eelvex, f8l, fernando, jan, jimdigriz, jon, julien, kacper, ktosiek, + lexszero, litemotiv, lourens, madroach, marcus, merovius, mike, mirko, mseed, + mxf, phnom, quaec, rogutes, sardemff7, smartass, thepub, tiago, tucos, + woddf2, xpt, ys + +-- Michael Stapelberg, 2011-08-01