/* pmterm.c -- xterm.c for the OS/2 Presentation Manager
   Copyright (C) 1993 Eberhard Mattes.

This file is part of GNU Emacs.

GNU Emacs 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.

GNU Emacs 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/process.h>
#include <sys/ioctl.h>

#include "config.h"
#include "lisp.h"
#include "blockinput.h"
#include "keyboard.h"
#include "window.h"
#include "frame.h"
#include "disptab.h"
#include "termhooks.h"
#include "termchar.h"
#include "dispextern.h"
#include "pmterm.h"
#include "pmemacs.h"

Lisp_Object Qpm_menu_bar_update;

extern struct face *intern_face (struct frame *f, struct face *face);

void x_make_frame_visible (struct frame *f);


/* This is the quit character, which is defined in keyboard.c.  It is
   used by the PM_set_terminal_modes function, which is assigned to
   set_terminal_modes_hook. */
extern int quit_char;

/* Dummy variable for simplifying changes to xfaces.c. */
Display *x_current_display;

int pm_session_started = 0;

static int curs_x;
static int curs_y;
static struct frame *updating_frame = 0;

static int outbound_pipe;
static int oob_handle;          /* Read-end of pipe for out-of-band data */

static char pm_send_buffer[4096];
static int pm_send_buffered = 0;

/* During an update, nonzero if chars output now should be highlighted.  */
static int highlight;

/* During an update, maximum vpos for ins/del line operations to affect.  */
static int flexlines;

/* Mouse position.  Valid only if mouse_moved is non-zero. */
static int mouse_x;
static int mouse_y;
static FRAME_PTR mouse_frame;


/* Dummy function for simplifying changes to xfaces.c. */

void XFreeGC (Display *dpy, GC gc)
{
}


/* Send a message to pmemacs.

   Note: This function should abort more gracefully on failure. */

void pm_send (const void *src, unsigned size)
{
  const char *s;
  int n;

  if (pm_send_buffered > 0)     /* Important! */
    pm_send_flush ();
  s = src;
  while (size != 0)
    {
      n = write (outbound_pipe, s, size);
      if (n == -1 || n == 0)
        fatal ("Cannot send message to PM Emacs.");
      size -= n;
      s += n;
    }
}


/* When sending many small requests, it's better to use this
   function.  We must not use this function if we want to receive data
   from pmemacs. */

void pm_send_collect (const void *src, unsigned size)
{
  if (pm_send_buffered + size > sizeof (pm_send_buffer))
    {
      if (size > sizeof (pm_send_buffer))
        {
          pm_send (src, size);
          return;
        }
      pm_send_flush ();
    }
  memcpy (pm_send_buffer + pm_send_buffered, src, size);
  pm_send_buffered += size;
}


/* Flush buffer filled by pm_send_collect. */

void pm_send_flush (void)
{
  int size;

  if (pm_send_buffered > 0)
    {
      size = pm_send_buffered;
      pm_send_buffered = 0;
      pm_send (pm_send_buffer, size);
    }
}


/* Receive data from pmemacs.
   Note: This should abort more gracefully on failure. */

static void receive (int fd, void *dst, size_t size)
{
  char *d;
  int n;

  d = dst;
  while (size != 0)
    {
      n = read (fd, d, size);
      if (n == -1 || n == 0)
        fatal ("Failed to receive data from PM Emacs.");
      size -= n;
      d += n;
    }
}


/* Receive out-of-band data from pmemacs. */

void pm_receive_oob (void *dst, unsigned size)
{
  receive (oob_handle, dst, size);
}


/* Turn mouse tracking on or off.  Tell pmemacs to start or stop
   sending PME_MOUSEMOVE events. */

void pm_mouse_tracking (int flag)
{
  pm_request pmr;

  pmr.track.header.type = PMR_TRACKMOUSE;
  pmr.track.header.frame = 0;
  pmr.track.flag = flag;
  pm_send (&pmr, sizeof (pmr));
}


/* Turn the cursor on or off. */

static void pm_display_cursor (struct frame *f, int on)
{
  pm_request pmr;

  if (!FRAME_VISIBLE_P (f))
    return;
  if (!on && f->phys_cursor_x < 0)
    return;
  if (f != updating_frame)
    {
      curs_x = FRAME_CURSOR_X (f);
      curs_y = FRAME_CURSOR_Y (f);
    }
  if (on && (f->phys_cursor_x != curs_x || f->phys_cursor_y != curs_y))
    {
      pmr.cursor.header.type = PMR_CURSOR;
      pmr.cursor.header.frame = (unsigned long)f;
      pmr.cursor.x = curs_x;
      pmr.cursor.y = curs_y;
      pmr.cursor.on = 1;
      pm_send (&pmr, sizeof (pmr));
      f->phys_cursor_x = curs_x;
      f->phys_cursor_y = curs_y;
    }
  if (!on)
    {
      pmr.cursor.header.type = PMR_CURSOR;
      pmr.cursor.header.frame = (unsigned long)f;
      pmr.cursor.x = 0;
      pmr.cursor.y = 0;
      pmr.cursor.on = 0;
      pm_send (&pmr, sizeof (pmr));
      f->phys_cursor_x = -1;
    }
}


/* ...to do: avoid PMR_CLREOL */

static void dump_glyphs (struct frame *f, GLYPH *gp, int enable, int used,
                         int x, int y, int cols, int hl)
{
  pm_request pmr, *pmrp;
  int n, clear;
  char *buf;
  int tlen = GLYPH_TABLE_LENGTH;
  Lisp_Object *tbase = GLYPH_TABLE_BASE;

  buf = alloca (sizeof (pmr) + cols);
  pmrp = (pm_request *)buf;
  buf += sizeof (pmr);
  if (enable)
    {
      n = used - x;
      if (n < 0) n = 0;
    }
  else
    n = 0;
  if (n > cols)
    n = cols;
  clear = cols - n;

  while (n > 0)
    {
      /* Get the face-code of the next GLYPH.  */
      int cf, len;
      int g = *gp;
      char *cp;

      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
      cf = GLYPH_FACE (g);
      /* Find the run of consecutive glyphs with the same face-code.
	 Extract their character codes into BUF.  */
      cp = buf;
      while (n > 0)
	{
	  g = *gp;
	  GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
	  if (GLYPH_FACE (g) != cf)
	    break;

	  *cp++ = GLYPH_CHAR (g);
	  --n;
	  ++gp;
	}

      /* LEN gets the length of the run.  */
      len = cp - buf;

      /* Now output this run of chars, with the font and pixel values
	 determined by the face code CF.  */
      {
	struct face *face = FRAME_DEFAULT_FACE (f);

	if (cf != 0)
	  {
	    /* The face codes on the glyphs must be valid indices into the
	       frame's face table.  */
	    if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f))
	      abort ();

	    if (cf == 1)
	      face = FRAME_MODE_LINE_FACE (f);
	    else
	      face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
	  }
	else if (hl == 1)
	  {
	    face = FRAME_MODE_LINE_FACE (f);
	  }
        pmrp->glyphs.header.type = PMR_GLYPHS;
        pmrp->glyphs.header.frame = (unsigned long)f;
        pmrp->glyphs.count = len;
        pmrp->glyphs.x = x;
        pmrp->glyphs.y = y;
        pmrp->glyphs.face = face->gc;
        pm_send_collect (pmrp, sizeof (pmr) + len);
      }

      x += len;
    }

  if (clear > 0)
    {
      pmr.clreol.header.type = PMR_CLREOL;
      pmr.clreol.header.frame = (unsigned long)f;
      pmr.clreol.y = y;
      pmr.clreol.x0 = x;
      pmr.clreol.x1 = x + clear; /* -1 ? */
      pm_send_collect (&pmr, sizeof (pmr));
    }
  pm_send_flush ();
}


static void dump_rectangle (FRAME_PTR f, int left, int top,
                            int right, int bottom)
{
  struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
  int cols, rows, y, cursor_flag, i;

  if (FRAME_GARBAGED_P (f))
    return;

  /* Clip the rectangle to what can be visible.  */
  if (left < 0)
    left = 0;
  if (top < 0)
    top = 0;
  if (right >= f->width)
    right = f->width - 1;
  if (bottom >= f->height)
    bottom = f->height - 1;

  /* Get size in chars of the rectangle.  */
  cols = 1 + right - left;
  rows = 1 + bottom - top;

  /* If rectangle has zero area, return.  */
  if (rows <= 0) return;
  if (cols <= 0) return;

  cursor_flag = (f->phys_cursor_x >= 0);
  pm_display_cursor (f, 0);

  /* Display the text in the rectangle, one text line at a time.  */

  for (y = top; y <= bottom; y++)
    dump_glyphs (f, &active_frame->glyphs[y][left],
                 active_frame->enable[y], active_frame->used[y],
                 left, y, cols, active_frame->highlight[y]);
  if (cursor_flag)
    pm_display_cursor (f, 1);
}


/* A menu of the PM menu bar has been selected.  Now we should update
   the menu.  A lisp function is called to do this -- this should be
   safe as we don't use SIGIO under emx. */

static void pm_menu_bar_update (FRAME_PTR f, int number)
{
  Lisp_Object oquit;
  Lisp_Object frame;

  XSET (frame, Lisp_Frame, f);
  oquit = Vinhibit_quit;
  Vinhibit_quit = Qt; 
  call2 (Qpm_menu_bar_update, frame, make_number (number));
  Vinhibit_quit = oquit;
}


int PM_read_socket (int sd, struct input_event *bufp, int numchars,
                    int waitp, int expected)
{
  int count = 0;
  pm_event pme;
  int nread;
  Lisp_Object tail, frame;
  FRAME_PTR f;

  if (interrupt_input_blocked)
    {
      interrupt_input_pending = 1;
      return -1;
    }
  interrupt_input_pending = 0;
  if (numchars <= 0)
    abort ();
  if (ioctl (0, FIONREAD, &nread) < 0 || nread < sizeof (pme))
    return 0;
  receive (0, &pme, sizeof (pme));
  f = (FRAME_PTR)pme.header.frame;
  switch (pme.header.type)
    {
    case PME_PAINT:

      /* A frame needs repainting. */

      dump_rectangle (f, pme.paint.x0, pme.paint.y0,
                      pme.paint.x1, pme.paint.y1);
      break;

    case PME_KEY:

      /* A key has been pressed. */

      switch (pme.key.type)
        {
        case PMK_ASCII:
          bufp->kind = ascii_keystroke;
          XSET (bufp->code, Lisp_Int, pme.key.code);
          break;
        case PMK_VIRTUAL:
          bufp->kind = non_ascii_keystroke;
          XSET (bufp->code, Lisp_Int, pme.key.code);
          break;
        case PMK_SYMBOL:
          bufp->kind = lispy_event;
          bufp->code = pme.key.code;
          break;
        default:
          abort ();
        }
      bufp->modifiers = pme.key.modifiers;
      bufp->timestamp = 0;
      XSET (bufp->frame_or_window, Lisp_Frame, f);
      ++count; ++bufp;
      break;

    case PME_BUTTON:
      bufp->kind = mouse_click;
      XSET (bufp->code, Lisp_Int, pme.button.button);
      XSET (bufp->frame_or_window, Lisp_Frame, f);
      XFASTINT (bufp->x) = pme.button.x;
      XFASTINT (bufp->y) = pme.button.y;
      bufp->modifiers = pme.button.modifiers;
      bufp->timestamp = pme.button.timestamp;
      ++count; ++bufp;
      break;

    case PME_SIZE:

      /* The size of the frame has been changed by the user.  Adjust
         frame and set new size. */

      change_frame_size (f, pme.size.height, pme.size.width, 0, 1);
      SET_FRAME_GARBAGED (f);
      Fredraw_display ();
      break;

    case PME_RESTORE:

      /* A frame window is being restored. */

      if (f->async_visible == 0)
        {
          f->async_visible = 1;
          f->async_iconified = 0;
          SET_FRAME_GARBAGED (f);
          x_make_frame_visible (f);
        }
      break;

    case PME_MINIMIZE:

      /* A frame window is being minimized. */

      if (!f->async_iconified)
        {
          XSET (frame, Lisp_Frame, f);
          Ficonify_frame (frame);
          FRAME_SAMPLE_VISIBILITY (f);
        }
      break;

    case PME_MENUBAR:
      pm_menu_bar_update (f, pme.menubar.number);
      break;

    case PME_MOUSEMOVE:
      mouse_frame = (FRAME_PTR)pme.mouse.header.frame;
      mouse_x = pme.mouse.x;
      mouse_y = pme.mouse.y;
      mouse_moved = 1;
      break;

    case PME_FRAMEMOVE:
      f->display.x->left_pos = pme.framemove.left;
      f->display.x->top_pos = pme.framemove.top;
      break;

    default:
      fatal ("Bad event type %d from PM Emacs.", pme.header.type);
    }
  return count;
}


static PM_set_terminal_modes (void)
{
  pm_request pmr;

  pmr.quitchar.header.type = PMR_QUITCHAR;
  pmr.quitchar.header.frame = 0;
  pmr.quitchar.quitchar = quit_char;
  pm_send (&pmr, sizeof (pmr));
}


static int PM_cursor_to (int row, int col)
{
  curs_x = col;
  curs_y = row;
  if (updating_frame == 0)
    pm_display_cursor (selected_frame, 1);
}


static PM_write_glyphs (GLYPH *start, int len)
{
  pm_request pmr;
  struct frame *f;

  f = updating_frame;
  if (f == 0)
    {
      f = selected_frame;
      curs_x = f->cursor_x;
      curs_y = f->cursor_y;
    }
  dump_glyphs (f, start, 1, curs_x + len, curs_x, curs_y, len, highlight);
  if (updating_frame == 0)
    {
      f->cursor_x += len;
      pm_display_cursor (f, 1);
      f->cursor_x -= len;
    }
  else
    curs_x += len;
}


static PM_set_terminal_window (int n)
{
  if (updating_frame == 0)
    abort ();
  if (n <= 0 || n > updating_frame->height)
    flexlines = updating_frame->height;
  else
    flexlines = n;
}


static PM_ins_del_lines (int vpos, int n)
{
  pm_request pmr;

  if (updating_frame == 0)
    abort ();
  if (vpos >= flexlines)
    return;
  pmr.lines.header.type = PMR_LINES;
  pmr.lines.header.frame = (unsigned long)updating_frame;
  pmr.lines.y = vpos;
  pmr.lines.max_y = flexlines;
  pmr.lines.count = n;
  pm_send (&pmr, sizeof (pmr));
}


static PM_update_begin (FRAME_PTR f)
{
  pm_request pmr;

  if (f == 0)
    abort ();
  updating_frame = f;
  flexlines = f->height;
  highlight = 0;
  pm_display_cursor (f, 0);
}


static PM_update_end (struct frame *f)
{
  if (updating_frame == 0 || updating_frame != f)
    abort ();
  pm_display_cursor (f, 1);
  updating_frame = 0;
}


static PM_clear_frame ()
{
  pm_request pmr;
  struct frame *f;

  f = updating_frame;
  if (f == 0)
    f = selected_frame;
  f->phys_cursor_x = -1;
  curs_x = 0;
  curs_y = 0;
  pmr.header.type = PMR_CLEAR;
  pmr.header.frame = (unsigned long)f;
  pm_send (&pmr, sizeof (pmr));
}

static PM_clear_end_of_line (int first_unused)
{
  pm_request pmr;
  struct frame *f = updating_frame;

  if (f == 0)
    abort ();

  if (curs_y < 0 || curs_y >= f->height)
    return;
  if (first_unused <= 0)
    return;
  if (first_unused >= f->width)
    first_unused = f->width;

  pmr.clreol.header.type = PMR_CLREOL;
  pmr.clreol.header.frame = (unsigned long)f;
  pmr.clreol.y = curs_y;
  pmr.clreol.x0 = curs_x;
  pmr.clreol.x1 = first_unused;
  pm_send (&pmr, sizeof (pmr));
}



static PM_reassert_line_highlight (int new, int vpos)
{
  highlight = new;
}


static PM_change_line_highlight (int new_highlight, int vpos,
                                 int first_unused_hpos)
{
  highlight = new_highlight;
  PM_cursor_to (vpos, 0);
  PM_clear_end_of_line (updating_frame->width);
}


/* Let pmemacs ring the bell. */

PM_ring_bell ()
{
  pm_request pmr;

  pmr.header.type = PMR_BELL;
  pmr.header.frame = -1;
  pm_send (&pmr, sizeof (pmr));
}


/* Return the current mouse position. */

static void PM_mouse_position (FRAME_PTR *f, Lisp_Object *bar_window,
                               enum scroll_bar_part *part,
                               Lisp_Object *x, Lisp_Object *y,
                               unsigned long *time)
{
  if (mouse_moved)
    {
      *f = mouse_frame;
      XSET (*x, Lisp_Int, mouse_x);
      XSET (*y, Lisp_Int, mouse_y);
      mouse_moved = 0;
    }
  else
    {
      /* Probably we don't need this -- is PM_mouse_position ever
         called when mouse_moved is zero? */
      pmd_mousepos result;
      pm_request pmr;

      pmr.header.type = PMR_MOUSEPOS;
      pmr.header.frame = -1;
      pm_send (&pmr, sizeof (pmr));
      pm_receive_oob (&result, sizeof (result));
      if (result.frame == 0)
        {
          *f = NULL;
          *x = Qnil;
          *y = Qnil;
        }
      else
        {
          *f = (FRAME_PTR)result.frame;
          XSET (*x, Lisp_Int, result.x);
          XSET (*y, Lisp_Int, result.y);
        }
    }
  *bar_window = Qnil;
  *time = 0;
}


void x_destroy_window (struct frame *f)
{
  pm_request pmr;

  pmr.header.type = PMR_DESTROY;
  pmr.header.frame = (unsigned long)f;
  pm_send (&pmr, sizeof (pmr));
  free_frame_faces (f);
  free_pm_menu_bar (f->pm_menu_bar_items);
  f->pm_menu_bar_items = 0;
}


void x_set_mouse_position (struct frame *f, int x, int y)
{
}


static void PM_frame_raise_lower (struct frame *f, int raise)
{
  pm_request pmr;

  pmr.header.type = (raise ? PMR_RAISE : PMR_LOWER);
  pmr.header.frame = (unsigned long)f;
  pm_send (&pmr, sizeof (pmr));
}


void x_make_frame_visible (struct frame *f)
{
  pm_request pmr;

  if (!FRAME_VISIBLE_P (f))
    {
      pmr.visible.header.type = PMR_VISIBLE;
      pmr.visible.header.frame = (unsigned long)f;
      pmr.visible.visible = 1;
      pm_send (&pmr, sizeof (pmr));
      f->async_visible = 1;
      f->async_iconified = 0;
    }
}


void x_make_frame_invisible (struct frame *f)
{
  pm_request pmr;

  if (!f->async_visible)
    return;
  f->async_visible = 0;
  pmr.visible.header.type = PMR_VISIBLE;
  pmr.visible.header.frame = (unsigned long)f;
  pmr.visible.visible = 0;
  pm_send (&pmr, sizeof (pmr));
}


void x_iconify_frame (struct frame *f)
{
  pm_request pmr;

  f->async_visible = 0;
  f->async_iconified = 1;
  pmr.header.type = PMR_ICONIFY;
  pmr.header.frame = (unsigned long)f;
  pm_send (&pmr, sizeof (pmr));
}


void x_set_window_size (struct frame *f, int cols, int rows)
{
  pm_request pmr;

  check_frame_size (f, &rows, &cols);
  change_frame_size (f, rows, cols, 0, 0);
  pmr.size.header.type = PMR_SIZE;
  pmr.size.header.frame = (unsigned long)f;
  pmr.size.width = cols;
  pmr.size.height = rows;
  pm_send (&pmr, sizeof (pmr));
  SET_FRAME_GARBAGED (f);
}


void x_set_offset (struct frame *f, int xoff, int yoff)
{
  pm_request pmr;

  pmr.setpos.header.type = PMR_SETPOS;
  pmr.setpos.header.frame = (unsigned long)f;
  pmr.setpos.left = xoff;
  pmr.setpos.top = yoff;
  pm_send (&pmr, sizeof (pmr));
}


void x_focus_on_frame (struct frame *f)
{
  pm_request pmr;

  pmr.header.type = PMR_FOCUS;
  pmr.header.frame = (unsigned long)f;
  pm_send (&pmr, sizeof (pmr));
}


void pm_init (void)
{
  int i, pipe_in[2], pipe_out[2], pipe_oob[2];
  char arg1[12], arg2[12], arg3[12], arg4[12];

  for (i = 0; i < 64; i++)
    fcntl (i, F_SETFD, 1);

  sprintf (arg1, "%d", getpid ());

  if (pipe (pipe_out) != 0)
    fatal ("Cannot open pipe for PM Emacs.");
  fcntl (pipe_out[1], F_SETFD, 1); /* Don't pass write end to child */
  outbound_pipe = pipe_out[1];
  setmode (outbound_pipe, O_BINARY);
  sprintf (arg2, "%d", pipe_out[0]);

  if (pipe (pipe_in) != 0)
    fatal ("Cannot open pipe for PM Emacs.");
  dup2 (pipe_in[0], 0);         /* Replace stdin with pipe */
  close (pipe_in[0]);
  fcntl (0, F_SETFD, 1);        /* Don't pass read end to child */
  setmode (0, O_BINARY);
  sprintf (arg3, "%d", pipe_in[1]);

  if (pipe (pipe_oob) != 0)
    fatal ("Cannot open pipe for PM Emacs.");
  oob_handle = pipe_oob[0];
  fcntl (oob_handle, F_SETFD, 1); /* Don't pass read end to child */
  setmode (oob_handle, O_BINARY);
  sprintf (arg4, "%d", pipe_oob[1]);

  if (spawnlp (P_PM, "pmemacs.exe", "pmemacs.exe", arg1, arg2, arg3, arg4, 0)
      == -1)
    fatal ("Cannot start PM Emacs.");
  close (pipe_out[0]);
  close (pipe_in[1]);
  close (pipe_oob[1]);
  pm_session_started = 1;

  clear_frame_hook = PM_clear_frame;
  clear_end_of_line_hook = PM_clear_end_of_line;
  ins_del_lines_hook = PM_ins_del_lines;
  set_terminal_window_hook = PM_set_terminal_window;
#if 0
  insert_glyphs_hook = PM_insert_glyphs;
  delete_glyphs_hook = PM_delete_glyphs;
#endif
  frame_raise_lower_hook = PM_frame_raise_lower;
  change_line_highlight_hook = PM_change_line_highlight;
  reassert_line_highlight_hook = PM_reassert_line_highlight;
  mouse_position_hook = PM_mouse_position;
  write_glyphs_hook = PM_write_glyphs;
  ring_bell_hook = PM_ring_bell;
  set_terminal_modes_hook = PM_set_terminal_modes;
  update_begin_hook = PM_update_begin;
  update_end_hook = PM_update_end;
  read_socket_hook = PM_read_socket;
  cursor_to_hook = PM_cursor_to;

  scroll_region_ok = 0;		/* we won't scroll partial frames */
  char_ins_del_ok = 0;		/* just as fast to write the line */
  line_ins_del_ok = 1;		/* use GpiBitBlt */
  fast_clear_end_of_line = 1;	/* PM does this well */
  memory_below_frame = 0;	/* we don't remember what scrolls 
				   off the bottom */
  baud_rate = 19200;
  remove_switch_entry ();
}


void pm_exit (void)
{
  pm_request pmr;

  pmr.header.type = PMR_CLOSE;
  pmr.header.frame = 0;
  pm_send (&pmr, sizeof (pmr));
  pm_session_started = 0;
  close (outbound_pipe);
  close (oob_handle);
  close (0);
}


syms_of_xterm ()
{
  Qpm_menu_bar_update = intern ("pm-menu-bar-update");
  staticpro (&Qpm_menu_bar_update);
}


void x_handle_selection_request (struct input_event *event)
{
}

void x_handle_selection_clear (struct input_event *event)
{
}

