/*
 * $Id: keyin.c,v 1.2 2001/06/14 18:16:13 ura Exp $
 */

/*
 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
 * This file is part of FreeWnn.
 * 
 * Copyright Kyoto University Research Institute for Mathematical Sciences
 *                 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright 1991, 1992 by Massachusetts Institute of Technology
 *
 * Author: OMRON SOFTWARE Co., Ltd. <freewnn@rd.kyoto.omronsoft.co.jp>
 *
 * 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, 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 GNU Emacs; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Commentary:
 *
 * Change log:
 *
 * Last modified date: 8,Feb.1999
 *
 * Code:
 *
 */
/*      Version 4.0
 */
#include <stdio.h>
#include "commonhd.h"
#include "sdefine.h"
#include "xjutil.h"
#include "sxheader.h"
#include "config.h"
#include "xext.h"

static XGCValues xgcv;
XPoint button;
Atom actual_type;
int actual_format;
unsigned long nitems;
unsigned long leftover;

extern Atom wm_id;
extern Atom wm_id1;

extern char xjutil_env_name[];

static void
change_fore ()
{
  xgcv.foreground = cur_root->fg;
  XChangeGC (dpy, cur_root->gc, GCForeground, &xgcv);
  xgcv.background = cur_root->fg;
  XChangeGC (dpy, cur_root->reversegc, GCBackground, &xgcv);
  xgcv.foreground = cur_root->fg;
  xgcv.plane_mask = XOR (cur_root->fg, cur_root->bg);
  XChangeGC (dpy, cur_root->invertgc, (GCForeground | GCPlaneMask), &xgcv);
}

static void
change_back ()
{
  xgcv.background = cur_root->bg;
  XChangeGC (dpy, cur_root->gc, GCBackground, &xgcv);
  xgcv.foreground = cur_root->bg;
  XChangeGC (dpy, cur_root->reversegc, GCForeground, &xgcv);
  xgcv.background = cur_root->bg;
  xgcv.plane_mask = XOR (cur_root->fg, cur_root->bg);
  XChangeGC (dpy, cur_root->invertgc, (GCBackground | GCPlaneMask), &xgcv);
}

static int
set_xjutil_bun (xjutil_env, p)
     Xjutil_envRec *xjutil_env;
     register char *p;
{
  XFontSet fs;
  XjutilFSRec *fsl;
  int i;
  WnnEnv *we;
#ifdef X11R5
  XLocale xlc;
#else
  XLCd xlc;
#endif /* X11R5 */
  extern XjutilFSRec *add_fontset_list (), *get_fontset_list ();
  extern XFontSet create_font_set ();

  if (!cur_root || cur_root->screen != xjutil_env->screen)
    {
      for (i = 0; i < xjutil->screen_count; i++)
        {
          if (xjutil->root_pointer[i]->screen == xjutil_env->screen)
            {
              cur_root = xjutil->root_pointer[i];
              break;
            }
        }
    }
  if (!cur_root)
    return (-1);
  if (strcmp (xjutil->lc_name, xjutil_env->lc_name))
    {
      xjutil->lc_name = alloc_and_copy (xjutil_env->lc_name);
      xjutil->cswidth_id = xjutil_env->cswidth_id;
      setlocale (LC_ALL, xjutil->lc_name);
#ifdef X11R5
      Free ((char *) xjutil->xlc);
      xlc = _XFallBackConvert ();
      xjutil->xlc = _XlcDupLocale (xlc);
#else
      xlc = _XlcCurrentLC ();
      xjutil->xlc = xlc;
#endif /* X11R5 */
      set_cswidth (xjutil->cswidth_id);
    }
  if ((fsl = get_fontset_list (xjutil_env->fs_id)) == NULL)
    {
      if ((xjutil_env->fn_len <= 0) || (p == NULL) || (*p == '\0'))
        {
          print_out ("XCreateFontSet failed");
          return (-1);
        }
      if ((fs = create_font_set (p)) == NULL)
        {
          return (-1);
        }
      cur_fs = add_fontset_list (fs, xjutil_env->fs_id);
    }
  else
    {
      cur_fs = fsl;
    }
  if (cur_root->fg != xjutil_env->fore_ground)
    {
      cur_root->fg = xjutil_env->fore_ground;
      change_fore ();
    }
  if (cur_root->bg != xjutil_env->back_ground)
    {
      cur_root->bg = xjutil_env->back_ground;
      change_back ();
    }
  for (i = 0, we = normal_env; we; i++, we = we->next)
    {
      if (we->env == NULL)
        continue;
      we->env->env_id = xjutil_env->env_id[i];
      if (xjutil_env->env_id[i] == xjutil_env->cur_env_id)
        cur_normal_env = we;
    }
  for (i = 0, we = reverse_env; we; i++, we = we->next)
    {
      if (we->env == NULL)
        continue;
      we->env->env_id = xjutil_env->env_reverse_id[i];
      if (xjutil_env->env_id[i] == xjutil_env->cur_env_id)
        cur_reverse_env = we;
    }
  env_is_reverse = xjutil_env->env_is_reverse;
  return (0);
}

int
get_env ()
{
  Atom atom_env;
  unsigned char *data;
  Xjutil_envRec xjutil_env;

  if ((atom_env = XInternAtom (dpy, xjutil_env_name, True)) == (Atom) NULL)
    {
      return (-1);
    }
  XGetWindowProperty (dpy, xjutil->root_pointer[xjutil->default_screen]->root_window, atom_env, 0L, 1000000L, False, XA_STRING, &actual_type, &actual_format, &nitems, &leftover, &data);
  bcopy (data, &xjutil_env, sizeof (Xjutil_envRec));
  if (set_xjutil_bun (&xjutil_env, (data + sizeof (Xjutil_envRec))) == -1)
    {
      XFree ((char *) data);
      return (-1);
    }
  XFree ((char *) data);
  return (0);
}

int
get_touroku_data (buffer)
     w_char *buffer;
{
  Atom atom_env;
  unsigned char *data, *data_sv;
  int ret;
  Xjutil_envRec xjutil_env;

  if ((atom_env = XInternAtom (dpy, xjutil_env_name, True)) == (Atom) NULL)
    {
      return (-1);
    }
  XGetWindowProperty (dpy, xjutil->root_pointer[xjutil->default_screen]->root_window, atom_env, 0L, 1000000L, False, XA_STRING, &actual_type, &actual_format, &nitems, &leftover, &data);
  data_sv = data;
  bcopy (data, &xjutil_env, sizeof (Xjutil_envRec));
  if (set_xjutil_bun (&xjutil_env, (data += sizeof (Xjutil_envRec))) == -1)
    {
      XFree (data_sv);
      return (-1);
    }
  data += xjutil_env.fn_len;
  bcopy (data, &ret, sizeof (int));
  data += sizeof (int);
  bcopy (data, buffer, (nitems - (data - data_sv)));
  buffer[(nitems - (data - data_sv)) / 2] = 0;
  XFree (data_sv);
  return (ret);
}

static void
keyboard_mapping (ev)
     XMappingEvent *ev;
{
  XRefreshKeyboardMapping (ev);
}

static int
wm_event (ev)
     XClientMessageEvent *ev;
{
  if (ev->window == cur_root->ichi->w || ev->window == cur_root->jutil->w)
    {
      xjutil->sel_ret = -2;
      return (0);
    }
  return (1);
}

static void
check_map (w)
     Window w;
{
  if (w == cur_root->ichi->w)
    {
      cur_root->ichi->map = 1;
      return;
    }
  else if (w == cur_root->ichi->keytable->w)
    {
      cur_root->ichi->keytable->map = 1;
      return;
    }
  else if (w == cur_root->yes_no->w)
    {
      cur_root->yes_no->map = 1;
      return;
    }
  return;
}

static XComposeStatus compose_status = { NULL, 0 };
static int work = 0;

int
xw_read (buff)
     register int *buff;
{
  XEvent event;
  unsigned char strbuf[32];
  KeySym keycode;
  int nbytes;
  int ck;
  int i;

  for (;;)
    {
      XNextEvent (dpy, &event);
      if (event.type != ClientMessage && !cur_root)
        continue;
      switch (event.type)
        {
        case KeyPress:
          xjutil->sel_button = 0;
          nbytes = XLookupString ((XKeyEvent *) & event, strbuf, 32, &keycode, &compose_status);
          if ((ck = cvt_key_fun (keycode, event.xkey.state)) >= 0)
            {
              *buff++ = ck;
              return (1);
            }
          if ((keycode & 0xff00) == 0xff00)
            {                   /* ファンクションキー */
              if (nbytes > 0)
                {
                  for (i = 0; i < nbytes; i++)
                    {
                      *buff++ = (int) strbuf[i];
                    }
                  return (nbytes);
                }
              else
                {
                  break;
                }
            }
          if (event.xkey.state & ControlMask)
            {                   /* コントロールキー */
              if (*strbuf >= 0x20)
                {
                  break;
                }
              else if (*strbuf == 0x0)
                {
                  *buff++ = (int) *strbuf;
                  return (1);
                }
              else if (*strbuf <= 0x1f)
                {
                  *buff++ = (int) *strbuf;
                  return (1);
                }
            }
          if ((keycode >= 0x4a0) && (keycode <= 0x4df))
            {                   /* 仮名キー */
              *buff++ = (int) ((SS2 << 8) | (keycode & 0xff));
              return (1);
            }
          else if ((keycode < 0x100) && (keycode > 0))
            {
              for (i = 0; i < nbytes; i++)
                {
                  *buff++ = (int) strbuf[i];
                }
              return (nbytes);
            }
          break;

        case ClientMessage:     /* 日本語ツールキットからの要求 */
/* MOTIF */
          if (wm_id && event.xclient.message_type == wm_id && event.xclient.data.l[0] == wm_id1)
            {
              if (wm_event (&event) == 0)
                {
                  *buff = (int) 0xd;
                  return (1);
                }
              break;
            }
/* MOTIF */
          if (event.xclient.data.l[0] == DIC_KILL)
            terminate_handler ();
          if (work)
            break;
          xjutil->sel_button = 0;
          switch (event.xclient.data.l[0])
            {
            case DIC_ADD:
              work = 1;
              jishoadd ();
              send_end_work ();
              work = 0;
              break;
            case DIC_KENSAKU:
              work = 1;
              kensaku ();
              send_end_work ();
              work = 0;
              break;
            case DIC_ICHIRAN:
              work = 1;
              select_one_dict9 ();
              send_end_work ();
              work = 0;
              break;
            case DIC_PARAM:
              work = 1;
              paramchg ();
              send_end_work ();
              work = 0;
              break;
            case DIC_INFO:
              work = 1;
              dicinfoout ();
              send_end_work ();
              work = 0;
              break;
            case DIC_FZK:
              work = 1;
              fuzoku_set ();
              send_end_work ();
              work = 0;
              break;
            case DIC_TOUROKU:
              work = 1;
              touroku ();
              send_end_work ();
              work = 0;
              break;
            default:
              break;
            }

        case Expose:
          xw_expose (&event);
          return (-1);
          break;
        case ButtonRelease:
          button.x = event.xbutton.x_root;
          button.y = event.xbutton.y_root;
          xjutil->sel_button = 1;
          if (xw_buttonpress (&event) == True)
            {
              *buff = (int) 0xd;
              return (1);
            }
          break;
        case DestroyNotify:
          terminate_handler ();
          break;
        case MotionNotify:
          xw_mousemove (&event);
          break;
        case EnterNotify:
          xw_enterleave (&event, (char) 1);
          break;
        case LeaveNotify:
          xw_enterleave (&event, (char) 0);
          break;
        case ReparentNotify:
          read_wm_id ();
          break;
        case MapNotify:
          check_map (event.xmap.window);
          break;
        case MappingNotify:
          keyboard_mapping (&event);
          break;
        default:
          break;

        }
    }
}
