Logo Search packages:      
Sourcecode: fbterm-ucimf version File versions  Download package

imapi.c

/*
 *   Copyright © 2008-2009 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;
}

Generated by  Doxygen 1.6.0   Back to index