Milán Major

netscape-revival

1 branch
Code

sun-java/awt/tinyx/tiny_Toolkit.c

#include <X11/keysym.h>
#include <ctype.h>
/*#include "thread.h"*/
#include "tiny.h"
#include "java_awt_Event.h"
#include "sun_awt_tiny_TinyToolkit.h"
#include "sun_awt_tiny_TinyWindow.h"
#include "sun_awt_tiny_TinyEventThread.h"
#include "sun_awt_tiny_TinyInputThread.h"

#define bzero(a,b) memset(a, 0, b)

void		*awt_lock;
Display 	*awt_display;
long 		awt_screen;
Window 		awt_root;
int		awt_depth;
XVisualInfo	awt_visInfo;
Colormap	awt_cmap;
Visual		*awt_visual;
int		awt_whitepixel;
int		awt_blackpixel;
GC		awt_maskgc;
static int	awt_flush;

#ifdef DEBUG_AWT_LOCK

int awt_locked = 0;
char *lastF = "";
int lastL = -1;

#endif

#define MAXWINDOWS 512
TinyWindow *windows[MAXWINDOWS];

void
tiny_register(TinyWindow *win)
{
    int i;

    for (i = 0 ; i < MAXWINDOWS ; i++) {
	if (!windows[i]) {
	    windows[i] = win;
	    return;
	}
    }
}

void
tiny_unregister(TinyWindow *win)
{
    int i;

    for (i = 0 ; i < MAXWINDOWS ; i++) {
	if (windows[i] == win) {
	    windows[i] = 0;
	    return;
	}
    }
}

static TinyWindow *
tiny_find(Window win)
{
    long xid = (long)win;
    int i;

    for (i = 0 ; i < MAXWINDOWS ; i++) {
	if (windows[i] && (unhand(windows[i])->xid == xid)) {
	    return windows[i];
	}
    }
    return 0;
}

static int
getModifiers(unsigned int state)
{
    int modifiers = 0;

    if (state & ShiftMask) {
	modifiers |= java_awt_Event_SHIFT_MASK;
    }
    if (state & ControlMask) {
	modifiers |= java_awt_Event_CTRL_MASK;
    }
    if (state & Mod1Mask) {
	modifiers |= java_awt_Event_META_MASK;
    }
    if (state & Mod4Mask) {
	modifiers |= java_awt_Event_ALT_MASK;
    }
    if ((state&Button2Mask) != 0) {
	modifiers |= java_awt_Event_ALT_MASK;
    }
    if (state & Button3Mask) {
	modifiers |= java_awt_Event_META_MASK;
    }

    return modifiers;
}

static int
xerror_handler(Display *disp, XErrorEvent *err)
{
    char msg[128];
    char buf[128];
    XGetErrorText(disp, err->error_code, msg, sizeof(msg));
    fprintf(stderr, "Xerror %s\n", msg);
    jio_snprintf(buf, sizeof(buf), "%d", err->request_code);
    XGetErrorDatabaseText(disp, "XRequest", buf, "Unknown", msg, sizeof(msg));
    fprintf(stderr, "Major opcode %d (%s)\n", err->request_code, msg);
    if (err->request_code > 128) {
	fprintf(stderr, "Minor opcode %d\n", err->minor_code);
    }
    return 0;
}

static int
xioerror_handler(Display *disp)
{
    fprintf(stderr, "X I/O Error\n");
    return 0;
}

static void
handleKeyEvent(char *javaMethod,
	       char *actionKeyMethod,
	       XEvent *event,
	       TinyWindow *win)
{
    char buf[64];
    int len = sizeof(buf);
    int modifiers = getModifiers(event->xkey.state);
    KeySym keysym = 0;
    int key = -1;

    len = XLookupString(&event->xkey, buf, len - 1, &keysym, NULL);
    buf[len - 1] = '\0';

    if (keysym < 256) {
	if ((event->xkey.state & ControlMask)) {
	    switch (keysym) {
	      case '[':
	      case ']':
	      case '\\':
	      case '_':
		keysym -= 64;
		break;
	      default:
		if (isalpha(keysym)) {
		    keysym = tolower(keysym) - 'a' + 1;
		}
		break;
	    }
	}
	JAVA_UPCALL((EE(),
		     (HObject*)win,
		     javaMethod,"(JIIII)V",
		     int2ll(event->xkey.time),
		     event->xkey.x, event->xkey.y,
		     keysym, modifiers));
    } else {
	switch (keysym) {
	  case XK_BackSpace:
	    key = '\010';
	    break;
	  case XK_Delete:
	  case XK_KP_Delete:
	    key = '\177';
	    break;
	  case XK_Tab:
	    key = '\t';
	    break;
	  case XK_Return:
	  case XK_Linefeed:
	  case XK_KP_Enter:
	    key = '\n';
	    break;
	  case XK_F27:
	  case XK_Home:
	    /* Home */
	    key = java_awt_Event_HOME;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F1:
	    key = java_awt_Event_F1;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F2:
	    key = java_awt_Event_F2;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F3:
	    key = java_awt_Event_F3;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F4:
	    key = java_awt_Event_F4;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F5:
	    key = java_awt_Event_F5;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F6:
	    key = java_awt_Event_F6;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F7:
	    key = java_awt_Event_F7;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F8:
	    key = java_awt_Event_F8;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F9:
	    key = java_awt_Event_F9;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F10:
	    key = java_awt_Event_F10;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F11:
	    key = java_awt_Event_F11;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F12:
	    key = java_awt_Event_F12;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_R13:
	  case XK_End:
	    /* End */
	    key = java_awt_Event_END;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F29:
	  case XK_Page_Up:
	    /* PgUp */
	    key = java_awt_Event_PGUP;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_F35:
	  case XK_Page_Down:
	    /* PgDn */
	    key = java_awt_Event_PGDN;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_Up:
	    /* Up */
	    key = java_awt_Event_UP;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_Down:
	    /* Down */
	    key = java_awt_Event_DOWN;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_Left:
	    /* Left */
	    key = java_awt_Event_LEFT;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_Right:
	    /* Right */
	    key = java_awt_Event_RIGHT;
	    javaMethod = actionKeyMethod;
	    break;
	  case XK_Escape:
	    key = 27;
	    break;
	  case XK_KP_Decimal:
	    key = '.';
	    break;
	  case XK_KP_Add:
	    key = '+';
	    break;
	  case XK_KP_Subtract:
	    key = '-';
	    break;
	  case XK_KP_Divide:
	    key = '/';
	    break;
	  case XK_KP_Multiply:
	    key = '*';
	    break;
	  case XK_KP_0:
	    key = '0';
	    break;
	  case XK_KP_1:
	    key = '1';
	    break;
	  case XK_KP_2:
	    key = '2';
	    break;
	  case XK_KP_3:
	    key = '3';
	    break;
	  case XK_KP_4:
	    key = '4';
	    break;
	  case XK_KP_5:
	    key = '5';
	    break;
	  case XK_KP_6:
	    key = '6';
	    break;
	  case XK_KP_7:
	    key = '7';
	    break;
	  case XK_KP_8:
	    key = '8';
	    break;
	  case XK_KP_9:
	    key = '9';
	    break;
	  default:
	    break;
	}
	if (key != -1) {
	    JAVA_UPCALL((EE(),
			 (HObject*)win,
			 javaMethod,"(JIIII)V",
			 int2ll(event->xkey.time),
			 event->xkey.x,
			 event->xkey.y,
			 key,
			 modifiers));
	}

    }
}


void 
sun_awt_tiny_TinyToolkit_init(TinyToolkit *this)
{
    XColor color;
    XVisualInfo viTmp, *pVI;
    int numvi;
    char *dstr = getenv("DISPLAY");

    awt_lock = this;

    AWT_LOCK();
    awt_display = XOpenDisplay(dstr ? dstr : ":0.0");

    if (awt_display == 0) {
	SignalError(0, JAVAPKG "InternalError", "Can't connect to X server");
	AWT_UNLOCK();
	return;
    }

    XSetErrorHandler(xerror_handler);
    XSetIOErrorHandler(xioerror_handler);

    awt_screen = DefaultScreen(awt_display);
    awt_root = RootWindow(awt_display, awt_screen);
    if (!getenv("FORCEDEFVIS") && XMatchVisualInfo(awt_display, awt_screen,
						   24, TrueColor,
						   &awt_visInfo))
    {
	awt_visual = awt_visInfo.visual;
	awt_depth = awt_visInfo.depth;
	if (awt_visual == DefaultVisual(awt_display, awt_screen)) {
	    awt_cmap = DefaultColormap(awt_display, awt_screen);
	} else {
	    awt_cmap = XCreateColormap(awt_display, awt_root, awt_visual,
					  AllocNone);
	}
	color.flags = DoRed | DoGreen | DoBlue;
	color.red = color.green = color.blue = 0x0000;
	XAllocColor(awt_display, awt_cmap, &color);
	awt_blackpixel = color.pixel;
	color.flags = DoRed | DoGreen | DoBlue;
	color.red = color.green = color.blue = 0xffff;
	XAllocColor(awt_display, awt_cmap, &color);
	awt_whitepixel = color.pixel;
    } else {
	awt_visual = DefaultVisual(awt_display, awt_screen);
	awt_depth = DefaultDepth(awt_display, awt_screen);
	awt_cmap = DefaultColormap(awt_display, awt_screen);
	viTmp.visualid = XVisualIDFromVisual(awt_visual);
	viTmp.depth = awt_depth;
	pVI = XGetVisualInfo(awt_display, VisualIDMask | VisualDepthMask,
			     &viTmp, &numvi);
	if (!pVI) {
	    /* This should never happen. */
	    SignalError(0, JAVAPKG "InternalError",
			"Can't find default visual information");
	    AWT_UNLOCK();
	    return;
	}
	awt_visInfo = *pVI;
	XFree(pVI);
	awt_blackpixel = BlackPixel(awt_display, awt_screen);
	awt_whitepixel = WhitePixel(awt_display, awt_screen);
    }
    awt_allocate_colors();

    {
	Pixmap one_bit;
	XGCValues xgcv;
	xgcv.background = 0;
	xgcv.foreground = 1;
	one_bit = XCreatePixmap(awt_display, awt_root, 1, 1, 1);
	awt_maskgc = XCreateGC(awt_display, one_bit,
				  GCForeground | GCBackground, &xgcv);
	XFreePixmap(awt_display, one_bit);
    }
    AWT_UNLOCK();
}

void
tiny_flush() 
{
    if (!awt_flush++) {
	AWT_NOTIFY();
    }
}

void 
sun_awt_tiny_TinyInputThread_run(TinyInputThread *this)
{
    AWT_LOCK();

    while (1) {
	fd_set rdset;

	FD_ZERO(&rdset);
	FD_SET(ConnectionNumber(awt_display), &rdset);
	AWT_UNLOCK();
	select(ConnectionNumber(awt_display)+1, &rdset, 0,  0, 0);
	AWT_LOCK();

	tiny_flush();
	while (awt_flush > 0) {
	    AWT_WAIT(TIMEOUT_INFINITY);
	}
    }
    /* NOT REACHED */
}

static void FlushMotionEvent(XEvent *evt) {
    TinyWindow *win;
    int modifiers;

    if ((win = tiny_find(evt->xexpose.window)) == 0) {
	return;
    }

    modifiers = getModifiers(evt->xmotion.state);
    if (evt->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) {
	INVOKE((EE(), (HObject *)win,
		"handleMouseDrag","(JIII)V",
		int2ll(evt->xmotion.time),
		evt->xmotion.x,
		evt->xmotion.y,
		modifiers));
    } else {
	INVOKE((EE(), (HObject *)win,
		"handleMouseMove","(JIII)V",
		int2ll(evt->xmotion.time),
		evt->xmotion.x,
		evt->xmotion.y,
		modifiers));
    }
}

void 
sun_awt_tiny_TinyEventThread_run(TinyEventThread *this)
{
    TinyWindow *win;
    int modifiers;
    XEvent evt;
    TinyWindow *exposeWin = 0;
    int x1, y1, x2, y2;
#ifdef MOTION_COMPRESSION
    XEvent lastMotionEvent;
    int haveMotionEvent;
#endif

    AWT_LOCK();
    
    while (1) {
	/* flush */
	if (--awt_flush > 0) {
	    XFlush(awt_display);
	    awt_flush = 0;
	    AWT_NOTIFY();
	}

	AWT_WAIT(TIMEOUT_INFINITY);
	awt_flush++;
#ifdef MOTION_COMPRESSION
	haveMotionEvent = 0;
#endif

	/* process events */
	while (XPending(awt_display)) {
	    XNextEvent(awt_display, &evt);
#ifdef MOTION_COMPRESSION
	    if (haveMotionEvent &&
		((evt.type != MotionNotify) ||
		 (evt.xmotion.window != lastMotionEvent.xmotion.window) ||
		 (evt.xmotion.state != lastMotionEvent.xmotion.state))) {
		FlushMotionEvent(&lastMotionEvent);
	    }
#endif

	    switch (evt.type) {
	    case Expose:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		if (exposeWin == win) {
		    x1 = MIN(x1, evt.xexpose.x);
		    y1 = MIN(y1, evt.xexpose.y);
		    x2 = MAX(x2, evt.xexpose.x + evt.xexpose.width);
		    y2 = MAX(y2, evt.xexpose.y + evt.xexpose.height);
		} else {
		    if (exposeWin != 0) {
			INVOKE((EE(), (HObject *)exposeWin, "handleExpose","(IIII)V",
				x1, y1, x2 - x1, y2 - y1));
		    }
		    exposeWin = win;
		    x1 = evt.xexpose.x;
		    y1 = evt.xexpose.y;
		    x2 = x1 + evt.xexpose.width;
		    y2 = y1 + evt.xexpose.height;
		}
		if (evt.xexpose.count == 0) {
		    INVOKE((EE(), (HObject *)exposeWin, "handleExpose","(IIII)V",
			    x1, y1, x2 - x1, y2 - y1));
		    exposeWin = 0;
		}
		break;

	    case GraphicsExpose:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		INVOKE((EE(), (HObject *)win, "handleExpose","(IIII)V",
			evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height));
		break;

	    case ButtonPress:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		switch (evt.xbutton.button) {
		case 2:
		    evt.xbutton.state |= Button2Mask;
		    break;
		case 3:
		    evt.xbutton.state |= Button3Mask;
		    break;
		}
		modifiers = getModifiers(evt.xbutton.state);
		INVOKE((EE(), (HObject *)win,
			"handleMouseDown","(JIII)V",
			int2ll(evt.xbutton.time),
			evt.xbutton.x, evt.xbutton.y,
			modifiers));
		    break;

	    case ButtonRelease:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		modifiers = getModifiers(evt.xbutton.state);
		INVOKE((EE(), (HObject *)win,
			"handleMouseUp","(JIII)V",
			int2ll(evt.xbutton.time),
			evt.xbutton.x,
			evt.xbutton.y,
			modifiers));
		break;

	    case MotionNotify:
#ifdef MOTION_COMPRESSION
	        lastMotionEvent = evt;
		haveMotionEvent = 1;
#else
		FlushMotionEvent(&evt);
#endif
		break;

	    case EnterNotify:
	    case LeaveNotify:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}

		switch (evt.type) {
		case EnterNotify:
		    INVOKE((EE(), (HObject *)win,
				 "handleMouseEnter","(JII)V",
				 int2ll(evt.xcrossing.time),
				 evt.xcrossing.x,
				 evt.xcrossing.y));
		    break;
		case LeaveNotify:
		    INVOKE((EE(), (HObject *)win,
			    "handleMouseExit","(JII)V",
			    int2ll(evt.xcrossing.time),
			    evt.xcrossing.x,
			    evt.xcrossing.y));
		    break;
		}
		break;

	    case KeyPress:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		handleKeyEvent("handleKeyPress",
			       "handleActionKey",
			       &evt, win);
		break;
	    case KeyRelease:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		handleKeyEvent("handleKeyRelease",
			       "handleActionKeyRelease",
			       &evt, win);
		break;

	    case FocusIn:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		INVOKE((EE(), (HObject *)win, "handleFocusIn","()V"));
		break;

	    case FocusOut:
		if ((win = tiny_find(evt.xexpose.window)) == 0) {
		    break;
		}
		INVOKE((EE(), (HObject *)win, "handleFocusOut","()V"));
		break;

	    default:
		/*printf("got event 0x%d\n", evt.type);*/
		break;
	    }
	}
#ifdef MOTION_COMPRESSION
	if (haveMotionEvent) {
	    FlushMotionEvent(&lastMotionEvent);
	}
#endif
    }

    /* NOT REACHED */
}

long
sun_awt_tiny_TinyToolkit_getScreenWidth(TinyToolkit *this)
{
    return DisplayWidth(awt_display, awt_screen);
}

long
sun_awt_tiny_TinyToolkit_getScreenHeight(TinyToolkit *this)
{
    return DisplayHeight(awt_display, awt_screen);
}

long
sun_awt_tiny_TinyToolkit_getScreenResolution(TinyToolkit *this)
{
    return (int)((DisplayWidth(awt_display, awt_screen) * 25.4) / 
		 DisplayWidthMM(awt_display, awt_screen));
}

struct Hjava_awt_image_ColorModel *
sun_awt_tiny_TinyToolkit_makeColorModel(TinyToolkit *this)
{
    return awt_getColorModel();
}

void
sun_awt_tiny_TinyToolkit_sync(TinyToolkit *this)
{
    XSync(awt_display, False);
}