Added Unicode-Support

This commit is contained in:
Axel Wagner 2010-08-06 03:32:05 +02:00
parent 7d7867acce
commit 1daa395a77
12 changed files with 352 additions and 141 deletions

View File

@ -22,5 +22,6 @@ struct rect_t {
#include "util.h" #include "util.h"
#include "workspaces.h" #include "workspaces.h"
#include "xcb.h" #include "xcb.h"
#include "ucs2_to_utf8.h"
#endif #endif

View File

@ -11,6 +11,7 @@ SLIST_HEAD(outputs_head, i3_output);
struct outputs_head *outputs; struct outputs_head *outputs;
void parse_outputs_json(char* json); void parse_outputs_json(char* json);
void init_outputs();
void free_outputs(); void free_outputs();
i3_output* get_output_by_name(char* name); i3_output* get_output_by_name(char* name);

View File

@ -0,0 +1 @@
char *convert_utf8_to_ucs2(char *input, int *real_strlen);

View File

@ -1,6 +1,8 @@
#ifndef WORKSPACES_H_ #ifndef WORKSPACES_H_
#define WORKSPACES_H_ #define WORKSPACES_H_
#include <xcb/xproto.h>
#include "common.h" #include "common.h"
typedef struct i3_ws i3_ws; typedef struct i3_ws i3_ws;
@ -13,6 +15,8 @@ void free_workspaces();
struct i3_ws { struct i3_ws {
int num; int num;
char *name; char *name;
xcb_char2b_t *ucs2_name;
int name_glyphs;
int name_width; int name_width;
bool visible; bool visible;
bool focused; bool focused;

View File

@ -7,8 +7,8 @@ void init_xcb();
void clean_xcb(); void clean_xcb();
void get_atoms(); void get_atoms();
void destroy_windows(); void destroy_windows();
void create_windows(); void reconfig_windows();
void draw_bars(); void draw_bars();
int get_string_width(char *string); int get_string_width(xcb_char2b_t *string, int glyph_len);
#endif #endif

View File

@ -81,7 +81,7 @@ void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
strip_dzen_formats(buffer); strip_dzen_formats(buffer);
FREE(statusline); FREE(statusline);
statusline = buffer; statusline = buffer;
printf("%s", buffer); printf("%s\n", buffer);
draw_bars(); draw_bars();
} }
@ -91,6 +91,8 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
} }
void start_child(char *command) { void start_child(char *command) {
child_pid = 0;
if (command != NULL) {
int fd[2]; int fd[2];
pipe(fd); pipe(fd);
child_pid = fork(); child_pid = fork();
@ -109,11 +111,16 @@ void start_child(char *command) {
shell = "/bin/sh"; shell = "/bin/sh";
execl(shell, shell, "-c", command, (char*) NULL); execl(shell, shell, "-c", command, (char*) NULL);
break; return;
default: default:
close(fd[1]); close(fd[1]);
dup2(fd[0], STDIN_FILENO); dup2(fd[0], STDIN_FILENO);
break;
}
}
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
child_io = malloc(sizeof(ev_io)); child_io = malloc(sizeof(ev_io));
@ -125,11 +132,11 @@ void start_child(char *command) {
ev_child_init(child_sig, &child_sig_cb, child_pid, 0); ev_child_init(child_sig, &child_sig_cb, child_pid, 0);
ev_child_start(main_loop, child_sig); ev_child_start(main_loop, child_sig);
break;
}
} }
void kill_child() { void kill_child() {
if (child_pid != 0) {
kill(child_pid, SIGQUIT); kill(child_pid, SIGQUIT);
}
cleanup(); cleanup();
} }

View File

@ -47,12 +47,10 @@ void got_subscribe_reply(char *reply) {
} }
void got_output_reply(char *reply) { void got_output_reply(char *reply) {
printf("Got Outputs-Data!\nDestroying Windows...\n"); printf("Parsing Outputs-JSON...\n");
destroy_windows();
printf("Parsing JSON...\n");
parse_outputs_json(reply); parse_outputs_json(reply);
printf("Creating_Windows...\n"); printf("Reconfiguring Windows...\n");
create_windows(); reconfig_windows();
} }
handler_t reply_handlers[] = { handler_t reply_handlers[] = {

View File

@ -5,21 +5,73 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <ev.h> #include <ev.h>
#include <getopt.h>
#include "common.h" #include "common.h"
char *i3_default_sock_path = "/home/mero/.i3/ipc.sock";
int main(int argc, char **argv) { 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 <socket_path>: Connect to i3 via <socket_path>\n");
printf("-c <command>: Execute <command> to get sdtin\n");
printf("-f <font>: Use X-Core-Font <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); main_loop = ev_default_loop(0);
init_xcb(); init_xcb(fontname);
init_connection("/home/mero/.i3/ipc.sock"); init_outputs();
init_connection(socket_path);
subscribe_events(); subscribe_events();
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); 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_WORKSPACES, NULL);
start_child("i3status"); start_child(command);
ev_loop(main_loop, 0); ev_loop(main_loop, 0);

View File

@ -11,6 +11,7 @@ struct outputs_json_params {
i3_output *outputs_walk; i3_output *outputs_walk;
char *cur_key; char *cur_key;
char *json; char *json;
bool init;
}; };
static int outputs_null_cb(void *params_) { 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; return 0;
} }
params->outputs_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); char *name = malloc(sizeof(const unsigned char) * (len + 1));
strncpy(params->outputs_walk->name, (const char*) val, len); strncpy(name, (const char*) val, len);
params->outputs_walk->name[len] = '\0'; name[len] = '\0';
params->outputs_walk->name = name;
FREE(params->cur_key); FREE(params->cur_key);
@ -105,9 +108,7 @@ static int outputs_start_map_cb(void *params_) {
new_output->workspaces = malloc(sizeof(struct ws_head)); new_output->workspaces = malloc(sizeof(struct ws_head));
TAILQ_INIT(new_output->workspaces); TAILQ_INIT(new_output->workspaces);
SLIST_INSERT_HEAD(params->outputs, new_output, slist); params->outputs_walk = new_output;
params->outputs_walk = SLIST_FIRST(params->outputs);
return 1; return 1;
} }
@ -115,6 +116,20 @@ static int outputs_start_map_cb(void *params_) {
return 1; 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) { 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_; struct outputs_json_params *params = (struct outputs_json_params*) params_;
FREE(params->cur_key); FREE(params->cur_key);
@ -135,18 +150,18 @@ yajl_callbacks outputs_callbacks = {
&outputs_string_cb, &outputs_string_cb,
&outputs_start_map_cb, &outputs_start_map_cb,
&outputs_map_key_cb, &outputs_map_key_cb,
NULL, &outputs_end_map_cb,
NULL, NULL,
NULL NULL
}; };
void init_outputs() {
outputs = malloc(sizeof(struct outputs_head));
SLIST_INIT(outputs);
}
void parse_outputs_json(char *json) { 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;
printf(json);
params.outputs = malloc(sizeof(struct outputs_head));
SLIST_INIT(params.outputs);
params.outputs_walk = NULL; params.outputs_walk = NULL;
params.cur_key = NULL; params.cur_key = NULL;
@ -173,16 +188,13 @@ void parse_outputs_json(char *json) {
} }
yajl_free(handle); yajl_free(handle);
if (outputs != NULL) {
FREE_SLIST(outputs, i3_output);
}
outputs = params.outputs;
} }
i3_output *get_output_by_name(char *name) { i3_output *get_output_by_name(char *name) {
i3_output *walk; i3_output *walk;
if (name == NULL) {
return NULL;
}
SLIST_FOREACH(walk, outputs, slist) { SLIST_FOREACH(walk, outputs, slist) {
if (!strcmp(walk->name, name)) { if (!strcmp(walk->name, name)) {
break; break;

103
i3bar/src/ucs2_to_utf8.c Normal file
View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <iconv.h>
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;
}

View File

@ -98,11 +98,17 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne
strncpy(params->workspaces_walk->name, (const char*) val, len); 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); 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", printf("Got Workspace %s, name_width: %d, glyphs: %d\n",
params->workspaces_walk->name, params->workspaces_walk->name,
params->workspaces_walk->name_width); params->workspaces_walk->name_width,
params->workspaces_walk->name_glyphs);
FREE(params->cur_key); FREE(params->cur_key);
return 1; return 1;
@ -118,7 +124,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne
params->workspaces_walk, params->workspaces_walk,
tailq); tailq);
free(output_name); FREE(output_name);
return 1; return 1;
} }

View File

@ -1,4 +1,6 @@
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <xcb/xcb_event.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -26,6 +28,8 @@ ev_prepare *xcb_prep;
ev_check *xcb_chk; ev_check *xcb_chk;
ev_io *xcb_io; ev_io *xcb_io;
xcb_event_handlers_t xcb_event_handlers;
uint32_t get_colorpixel(const char *s) { uint32_t get_colorpixel(const char *s) {
char strings[3][3] = { { s[0], s[1], '\0'} , char strings[3][3] = { { s[0], s[1], '\0'} ,
{ s[2], s[3], '\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 */ * 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_cookie_t cookie;
xcb_query_text_extents_reply_t *reply; xcb_query_text_extents_reply_t *reply;
xcb_generic_error_t *error; xcb_generic_error_t *error;
int width; int width;
cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t*) string); cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string);
if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { if ((reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) {
printf("ERROR: Could not get text extents!"); printf("ERROR: Could not get text extents!");
return 7; return 7;
} }
@ -145,7 +149,7 @@ int get_string_width(char *string) {
return width; return width;
} }
void init_xcb() { void init_xcb(char *fontname) {
/* FIXME: xcb_connect leaks Memory */ /* FIXME: xcb_connect leaks Memory */
xcb_connection = xcb_connect(NULL, NULL); xcb_connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(xcb_connection)) { if (xcb_connection_has_error(xcb_connection)) {
@ -162,7 +166,6 @@ void init_xcb() {
xcb_root = xcb_screens->root; xcb_root = xcb_screens->root;
xcb_font = xcb_generate_id(xcb_connection); 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_open_font(xcb_connection,
xcb_font, xcb_font,
strlen(fontname), strlen(fontname),
@ -219,29 +222,28 @@ void get_atoms() {
printf("Got Atoms\n"); printf("Got Atoms\n");
} }
void destroy_windows() { void destroy_window(i3_output *output) {
i3_output *walk; if (output == NULL) {
if (outputs == NULL) {
return; return;
} }
SLIST_FOREACH(walk, outputs, slist) { if (output->bar == XCB_NONE) {
if (walk->bar == XCB_NONE) { return;
continue;
}
xcb_destroy_window(xcb_connection, walk->bar);
walk->bar = XCB_NONE;
} }
xcb_destroy_window(xcb_connection, output->bar);
output->bar = XCB_NONE;
} }
void create_windows() { void reconfig_windows() {
uint32_t mask; uint32_t mask;
uint32_t values[2]; uint32_t values[4];
i3_output *walk; i3_output *walk;
SLIST_FOREACH(walk, outputs, slist) { SLIST_FOREACH(walk, outputs, slist) {
if (!walk->active) { if (!walk->active) {
destroy_window(walk);
continue; continue;
} }
if (walk->bar == XCB_NONE) {
printf("Creating Window for output %s\n", walk->name); printf("Creating Window for output %s\n", walk->name);
walk->bar = xcb_generate_id(xcb_connection); walk->bar = xcb_generate_id(xcb_connection);
@ -280,6 +282,20 @@ void create_windows() {
values); 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); xcb_flush(xcb_connection);
} }
@ -294,7 +310,7 @@ void draw_bars() {
continue; continue;
} }
if (outputs_walk->bar == XCB_NONE) { if (outputs_walk->bar == XCB_NONE) {
create_windows(); reconfig_windows();
} }
uint32_t color = get_colorpixel("000000"); uint32_t color = get_colorpixel("000000");
xcb_change_gc(xcb_connection, xcb_change_gc(xcb_connection,
@ -319,13 +335,23 @@ void draw_bars() {
XCB_GC_FOREGROUND, XCB_GC_FOREGROUND,
&color); &color);
xcb_image_text_8(xcb_connection, int glyph_count;
strlen(statusline), 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->bar,
outputs_walk->bargc, outputs_walk->bargc,
outputs_walk->rect.w - get_string_width(statusline) - 4, outputs_walk->rect.w - get_string_width(text, glyph_count) - 4,
font_height + 1, font_height + 1,
statusline); (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; i3_ws *ws_walk;
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
@ -357,12 +383,12 @@ void draw_bars() {
outputs_walk->bargc, outputs_walk->bargc,
XCB_GC_FOREGROUND, XCB_GC_FOREGROUND,
&color); &color);
xcb_image_text_8(xcb_connection, xcb_image_text_16(xcb_connection,
strlen(ws_walk->name), ws_walk->name_glyphs,
outputs_walk->bar, outputs_walk->bar,
outputs_walk->bargc, outputs_walk->bargc,
i + 5, font_height + 1, i + 5, font_height + 1,
ws_walk->name); ws_walk->ucs2_name);
i += 10 + ws_walk->name_width; i += 10 + ws_walk->name_width;
} }