diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2018-04-12 14:17:51 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2018-04-12 14:17:51 +0800 |
commit | 3d1888960d61461991f0542413964bcf8df42c40 (patch) | |
tree | 8752a833ae13d6b1cc5af4032e41d45490d688fa /im/imapi.c | |
download | fbterm-3d1888960d61461991f0542413964bcf8df42c40.tar.gz fbterm-3d1888960d61461991f0542413964bcf8df42c40.zip |
Initial commit
From fbterm 1.7.0, at https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/fbterm/fbterm-1.7.0.tar.gz
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'im/imapi.c')
-rw-r--r-- | im/imapi.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/im/imapi.c b/im/imapi.c new file mode 100644 index 0000000..0bbb127 --- /dev/null +++ b/im/imapi.c @@ -0,0 +1,279 @@ +/* + * Copyright © 2008-2010 dragchan <zgchan317@gmail.com> + * This file is part of FbTerm. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "imapi.h" + +#define OFFSET(TYPE, MEMBER) ((size_t)(&(((TYPE *)0)->MEMBER))) +#define MSG(a) ((Message *)(a)) + +static int imfd = -1; +static ImCallbacks cbs; +static char pending_msg_buf[10240]; +static unsigned pending_msg_buf_len = 0; +static int im_active = 0; + +static void wait_message(MessageType type); + +void register_im_callbacks(ImCallbacks callbacks) +{ + cbs = callbacks; +} + +int get_im_socket() +{ + static char init = 0; + if (!init) { + init = 1; + + char *val = getenv("FBTERM_IM_SOCKET"); + if (val) { + char *tail; + int fd = strtol(val, &tail, 0); + if (!*tail) imfd = fd; + } + } + + return imfd; +} + +void connect_fbterm(char raw) +{ + get_im_socket(); + if (imfd == -1) return; + + Message msg; + msg.type = Connect; + msg.len = sizeof(msg); + msg.raw = (raw ? 1 : 0); + int ret = write(imfd, (char *)&msg, sizeof(msg)); +} + +void put_im_text(const char *text, unsigned len) +{ + if (imfd == -1 || !im_active || !text || !len || (OFFSET(Message, texts) + len > UINT16_MAX)) return; + + char buf[OFFSET(Message, texts) + len]; + + MSG(buf)->type = PutText; + MSG(buf)->len = sizeof(buf); + memcpy(MSG(buf)->texts, text, len); + + int ret = write(imfd, buf, MSG(buf)->len); +} + +void set_im_window(unsigned id, Rectangle rect) +{ + if (imfd == -1 || !im_active || id >= NR_IM_WINS) return; + + Message msg; + msg.type = SetWin; + msg.len = sizeof(msg); + msg.win.winid = id; + msg.win.rect = rect; + + int ret = write(imfd, (char *)&msg, sizeof(msg)); + wait_message(AckWin); +} + +void fill_rect(Rectangle rect, unsigned char color) +{ + Message msg; + msg.type = FillRect; + msg.len = sizeof(msg); + + msg.fillRect.rect = rect; + msg.fillRect.color = color; + + int ret = write(imfd, (char *)&msg, sizeof(msg)); +} + +void draw_text(unsigned x, unsigned y, unsigned char fc, unsigned char bc, const char *text, unsigned len) +{ + if (!text || !len) return; + + char buf[OFFSET(Message, drawText.texts) + len]; + + MSG(buf)->type = DrawText; + MSG(buf)->len = sizeof(buf); + + MSG(buf)->drawText.x = x; + MSG(buf)->drawText.y = y; + MSG(buf)->drawText.fc = fc; + MSG(buf)->drawText.bc = bc; + memcpy(MSG(buf)->drawText.texts, text, len); + + int ret = write(imfd, buf, MSG(buf)->len); +} + +static int process_message(Message *msg) +{ + int exit = 0; + + switch (msg->type) { + case Disconnect: + close(imfd); + imfd = -1; + exit = 1; + break; + + case FbTermInfo: + if (cbs.fbterm_info) { + cbs.fbterm_info(&msg->info); + } + break; + + case Active: + im_active = 1; + if (cbs.active) { + cbs.active(); + } + break; + + case Deactive: + if (cbs.deactive) { + cbs.deactive(); + } + im_active = 0; + break; + + case ShowUI: + if (im_active && cbs.show_ui) { + cbs.show_ui(msg->winid); + } + break; + + case HideUI: { + if (im_active && cbs.hide_ui) { + cbs.hide_ui(); + } + + Message msg; + msg.type = AckHideUI; + msg.len = sizeof(msg); + int ret = write(imfd, (char *)&msg, sizeof(msg)); + break; + } + + case SendKey: + if (im_active && cbs.send_key) { + cbs.send_key(msg->keys, msg->len - OFFSET(Message, keys)); + } + break; + + case CursorPosition: + if (im_active && cbs.cursor_position) { + cbs.cursor_position(msg->cursor.x, msg->cursor.y); + } + break; + + case TermMode: + if (im_active && cbs.term_mode) { + cbs.term_mode(msg->term.crWithLf, msg->term.applicKeypad, msg->term.cursorEscO); + } + break; + + default: + break; + } + + return exit; +} + +static int process_messages(char *buf, int len) +{ + char *cur = buf, *end = cur + len; + int exit = 0; + + for (; cur < end && MSG(cur)->len <= (end - cur); cur += MSG(cur)->len) { + exit |= process_message(MSG(cur)); + } + + return exit; +} + +static void wait_message(MessageType type) +{ + int ack = 0; + while (!ack) { + char *cur = pending_msg_buf + pending_msg_buf_len; + int len = read(imfd, cur, sizeof(pending_msg_buf) - pending_msg_buf_len); + + if (len == -1 && (errno == EAGAIN || errno == EINTR)) continue; + else if (len <= 0) { + close(imfd); + imfd = -1; + return; + } + + pending_msg_buf_len += len; + + char *end = cur + len; + for (; cur < end && MSG(cur)->len <= (end - cur); cur += MSG(cur)->len) { + if (MSG(cur)->type == type) { + memcpy(cur, cur + MSG(cur)->len, end - cur - MSG(cur)->len); + pending_msg_buf_len -= MSG(cur)->len; + + ack = 1; + break; + } + } + } + + if (pending_msg_buf_len) { + Message msg; + msg.type = Ping; + msg.len = sizeof(msg); + int ret = write(imfd, (char *)&msg, sizeof(msg)); + } +} + +int check_im_message() +{ + if (imfd == -1) return 0; + + char buf[sizeof(pending_msg_buf)]; + int len, exit = 0; + + if (pending_msg_buf_len) { + len = pending_msg_buf_len; + pending_msg_buf_len = 0; + + memcpy(buf, pending_msg_buf, len); + exit |= process_messages(buf, len); + } + + len = read(imfd, buf, sizeof(buf)); + + if (len == -1 && (errno == EAGAIN || errno == EINTR)) return 1; + else if (len <= 0) { + close(imfd); + imfd = -1; + return 0; + } + + exit |= process_messages(buf, len); + + return !exit; +} |