/*
 * $Id: xscribble.c,v 1.1.1.1 2000/06/12 22:20:12 jg Exp $
 *
 * Copyright © 1999 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/keysym.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
#include "Scribble.h"

Widget  toplevel;
Widget  scribble;
Widget	pane1;
Widget	state;
Widget	symbol;

static int	    shift_keycode, control_keycode;

static void
SetLabel (Widget w, char *label)
{
    Arg	arg[1];

    XtSetArg (arg[0], XtNlabel, label);
    XtSetValues (w, arg, 1);
}

static void
ModeCB (Widget w, XtPointer clientData, XtPointer callData)
{
    ScribbleModeDataPtr	    md = callData;
    char		    *mode;

    if (md->controlShift)
	mode = "^C";
    else if (md->puncShift)
	mode = "#&^";
    else if (md->num)
	mode = "123";
    else if (md->capsLock)
	mode = "ABC";
    else if (md->shift)
	mode = "Abc";
    else
	mode = "abc";
    
    SetLabel (state, mode);
}

static void
SendKey (Display    *dpy,
	 int	    keycode,
	 Boolean    press)
{
    XTestFakeKeyEvent (dpy, keycode, press, 0);
}

static Boolean
FindKey (Display    *dpy,
	 KeySym	    keysym,
	 int	    *code_ret,
	 int	    *col_ret)
{
    int	    col;
    int	    keycode;
    KeySym  k;
    int	    min_keycode, max_keycode;

    XDisplayKeycodes (dpy, &min_keycode, &max_keycode);

    for (keycode = min_keycode; keycode <= max_keycode; keycode++)
    {
	for (col = 0; (k = XKeycodeToKeysym (dpy, keycode, col)) != NoSymbol; col++)
	    if (k == keysym)
	    {
		*code_ret = keycode;
		if (col_ret)
		    *col_ret = col;
		return TRUE;
	    }
    }
    return FALSE;
}

static void
KeysymCB (Widget w, XtPointer clientData, XtPointer callData)
{
    ScribbleKeysymDataPtr   kd = callData;
    Display		    *dpy = XtDisplay (w);
    int			    keycode, col;
    char		    *keyname;
    char		    buf[128];

    if (!FindKey (dpy, kd->keysym, &keycode, &col))
	return;
    keyname = XKeysymToString (kd->keysym);
    if (kd->control)
    {
	strcpy (buf, "^");
	strcat (buf, keyname);
	keyname = buf;
	SendKey (dpy, control_keycode, TRUE);
    }
    SetLabel (symbol, keyname);
    if (col & 1)
	SendKey (dpy, shift_keycode, TRUE);
    SendKey (dpy, keycode, TRUE);
    SendKey (dpy, keycode, FALSE);
    if (col & 1)
	SendKey (dpy, shift_keycode, FALSE);
    if (kd->control)
	SendKey (dpy, control_keycode, FALSE);
}

static void
InitKeymap (Display *dpy)
{
    FindKey (dpy, XK_Shift_L, &shift_keycode, 0);
    FindKey (dpy, XK_Control_L, &control_keycode, 0);
}

static void			/* ARGSUSED */
CloseAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
    exit (0);
}

static XtActionsRec actions_table[] = {
    { "close", CloseAP},
};

XrmOptionDescRec options[] = {
{"-fg",		"*Foreground",		XrmoptionSepArg,	NULL},
{"-bg",		"*Background",		XrmoptionSepArg,	NULL},
{"-foreground",	"*Foreground",		XrmoptionSepArg,	NULL},
{"-background",	"*Background",		XrmoptionSepArg,	NULL},
{"-thickness",	"*thickness",		XrmoptionSepArg,	NULL},
};

main (int argc, char **argv)
{
    Arg		    args[2];
    XtAppContext    app_context;
    Atom	    wm_delete_window;

    XtSetArg (args[0], XtNinput, FALSE);
    toplevel = XtAppInitialize (&app_context, "Scribble", 
				options, XtNumber (options),
				&argc, argv, 
				0,
				args, 1);

    pane1 = XtCreateManagedWidget ("pane1", panedWidgetClass, toplevel, args, 1);
    
    XtSetArg (args[0], XtNshowGrip, FALSE);
    XtSetArg (args[1], XtNlabel, "abc");
    state = XtCreateManagedWidget ("state", labelWidgetClass, pane1, args, 2);
    
    XtSetArg (args[0], XtNshowGrip, FALSE);
    XtSetArg (args[1], XtNlabel, "");
    symbol = XtCreateManagedWidget ("symbol", labelWidgetClass, pane1, args, 2);
    
    scribble = XtCreateManagedWidget ("scribble", scribbleWidgetClass, pane1, args, 1);
    XtAddCallback (scribble, XtNmodeCallback, ModeCB, (XtPointer) NULL);
    XtAddCallback (scribble, XtNkeysymCallback, KeysymCB, (XtPointer) NULL);
    
    InitKeymap (XtDisplay (toplevel));

    XtAppAddActions(app_context, actions_table, XtNumber(actions_table));
    XtOverrideTranslations (toplevel,
			    XtParseTranslationTable ("<Message>WM_PROTOCOLS: close()"));
    
    XtRealizeWidget (toplevel);
    
    wm_delete_window = XInternAtom(XtDisplay (toplevel), "WM_DELETE_WINDOW", False);
    (void) XSetWMProtocols (XtDisplay (toplevel), XtWindow(toplevel), &wm_delete_window, 1);
    
    XtAppMainLoop (app_context);
}
