/*
 * src/input.c - working set management
 *
 * Copyright (C) 1999, 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
 *
 * This 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 software 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 package; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.  
 */

#if HAVE_CONFIG_H
# include <config.h>
#endif 

#include <string.h>

#include <X11/keysym.h>

#include "display.h"
#include "input.h"
#include "wimpwm.h"
#include "screen.h"
#include "events.h"

#define INPUT_WINDOW_WIDTH  600
#define INPUT_WINDOW_HEIGHT 30

/*
 * The window for displaying the working set name after a switch.
 */
Window input_window = None;

/*
 * This is non-zero when INPUT_WINDOW above is active and acts
 * as a counter until the window will be deleted.
 */
static int input_window_active = 0;

static char input_buffer[1024];
static unsigned input_buffer_filled;

/*
 * Draw the contents of the woking set indicator window.
 */ 
void
draw_input_window (void)
{
  XPoint points0[3], points[5];
  int width, width1;

  if (input_window != None)
    {
      XClearWindow (display, input_window);

      XDrawString(display, input_window, active_gc,
		  4 * SPACE,
		  INPUT_WINDOW_HEIGHT / 2 + font->ascent / 2, 
		  "Execute:", sizeof ("Execute:") - 1);
      width1 = XTextWidth (font, "Execute:", sizeof ("Execute:") - 1);

      XDrawString(display, input_window, active_gc,
		  6 * SPACE + width1,
		  INPUT_WINDOW_HEIGHT / 2 + font->ascent / 2,
		  input_buffer, input_buffer_filled);

      width = XTextWidth (font, input_buffer, input_buffer_filled);

      points[0].x = 6 * SPACE + width1 + width;
      points[0].y = INPUT_WINDOW_HEIGHT / 2 + font->ascent / 2 + font->descent;
      points[1].x = 6 * SPACE + width1 + width;
      points[1].y = INPUT_WINDOW_HEIGHT / 2 - font->ascent / 2;
      points[2].x = 6 * SPACE + width1 + width + 6;
      points[2].y = INPUT_WINDOW_HEIGHT / 2 - font->ascent / 2;
      points[3].x = 6 * SPACE + width1 + width + 6;
      points[3].y = INPUT_WINDOW_HEIGHT / 2 + font->ascent / 2 + font->descent;
      points[4].x = 6 * SPACE + width1 + width;
      points[4].y = INPUT_WINDOW_HEIGHT / 2 + font->ascent / 2 + font->descent;
      XDrawLines(display, input_window,
		 active_gc, points, 5, CoordModeOrigin);
      points0[0].x = 0;
      points0[0].y = INPUT_WINDOW_HEIGHT - 1;
      points0[1].x = 0;
      points0[1].y = 0;
      points0[2].x = INPUT_WINDOW_WIDTH;
      points0[2].y = 0;
      XDrawLines(display, input_window,
		 highlight_gc, points0, 3, CoordModeOrigin);
      points0[0].x = INPUT_WINDOW_WIDTH;
      points0[0].y = 1;
      points0[1].x = INPUT_WINDOW_WIDTH;
      points0[1].y = INPUT_WINDOW_HEIGHT - 1;
      points0[2].x = 0;
      points0[2].y = INPUT_WINDOW_HEIGHT - 1;
      XDrawLines(display, input_window, shadow_gc,
		 points0, 3, CoordModeOrigin);
    }
}

void
input_hide_window (void)
{
  XUnmapWindow (display, input_window);
}

/*
 * Gets called every 10th of a second.  Delete the working set
 * indicator as soon as it times out.
 */
void
input_tick (void)
{
  if (input_window_active > 0)
    {
      input_window_active--;
      if (input_window_active == 0)
	{
	  input_hide_window ();
	}
    }
}

/*
 * Select the working set with number NUMBER as the current working
 * set.
 */
result_t
input_create (void)
{
  int width, height;

  input_buffer_filled = 0;
  width = INPUT_WINDOW_WIDTH;
  height = INPUT_WINDOW_HEIGHT;
  if (input_window == None)
    {
      input_window =
	XCreateSimpleWindow(display, root_window, 
			    DisplayWidth (display, default_screen) / 2
			    - width / 2,
			    DisplayHeight (display, default_screen) / 2
			    - height / 2,
			    width, 
			    height, 1,
			    BlackPixel(display, default_screen), 
			    background_color.pixel);
      if (!input_window) 
	{
	  error ("cannot create input window");
	  return RESULT_NOMEM;
	}

      XStoreName(display, input_window, "Working Set");
      XSetIconName(display, input_window, "Working Set");
      XSelectInput (display, input_window, ExposureMask | KeyPressMask |
		    EnterWindowMask);

    }
  else
    {
      XMoveResizeWindow (display, input_window,
			 DisplayWidth (display, default_screen) / 2
			 - width / 2,
			 DisplayHeight (display, default_screen) / 2
			 - height / 2,
			 width, 
			 height);
    }
  XMapRaised (display, input_window);
  
  draw_input_window ();

  input_window_active = 500;

  return RESULT_SUCCESS;
}

void
input_handle_key (XKeyEvent * event)
{
  KeySym sym;
  char buf[128];
  int len;
  XComposeStatus status;

  sym = XKeycodeToKeysym(display, event->keycode, 0);
  
  switch (sym)
    {
    case XK_Return:
      input_hide_window ();
      if (input_buffer_filled > 0)
	execute (input_buffer);
      return;
    case XK_Escape:
      input_hide_window ();
      return;
    case XK_BackSpace:
      if (input_buffer_filled > 0)
	input_buffer[--input_buffer_filled] = '\0';
      draw_input_window ();
      return;
    }
  len = XLookupString (event, buf, sizeof (buf), &sym, &status);
  if (len && input_buffer_filled < sizeof (input_buffer) - 1)
    {
      strncpy (input_buffer + input_buffer_filled,
	       buf,
	       sizeof (input_buffer) - input_buffer_filled);
      input_buffer[++input_buffer_filled] = '\0';
      draw_input_window ();
    }
}

