Milán Major

netscape-revival

1 branch
Code

sun-java/awt/x/awt_MToolkit.c

/*
 * @(#)awt_MToolkit.c	1.59 96/03/30 Sami Shaio
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */
#include "awt_p.h"
#include "color.h"
#include "canvas.h"
#include "interpreter.h"
#include <sys/time.h>
#include "sun_awt_motif_MToolkit.h"
#include "sun_awt_motif_InputThread.h"

#ifdef NEW_EVENT_MODEL
struct WidgetInfo {
    Widget widget;
    void   *peer;
    struct WidgetInfo *next;
};

static struct WidgetInfo *awt_winfo = (struct WidgetInfo *)0;
#endif

#if defined(AIX)
#include <sys/select.h>
#endif
#ifdef NETSCAPE
#include <signal.h>
extern int awt_init_xt;
#endif

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

void		*awt_lock;
XtAppContext	awt_appContext;
Display		*awt_display;
Pixel		awt_defaultBg;
Pixel		awt_defaultFg;
int		awt_whitepixel;
int		awt_blackpixel;
Visual		*awt_visual;
GC		awt_maskgc;
Window		awt_root;
long		awt_screen;
int		awt_depth;
XVisualInfo	awt_visInfo;
Colormap	awt_cmap;
int		awt_multiclick_time;
PRThread	*awt_thread;

static Colormap GetDefaultColormap(void) {
    return DefaultColormap(awt_display, awt_screen);
}

Colormap (*awt_GetDefaultColormap)(void) = GetDefaultColormap;

#ifdef DEBUG_AWT_LOCK

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

#endif

int inModalWait = 0;

/* list to associate a widget with a peer. It would have been
   preferable to use clientData but there seemed to be problems
   with that approach */
struct PeerList {
    Widget widget;
    void   *peer;
    struct PeerList *next;
};
struct PeerList *peers = NULL;

/*
 * error handlers
 */

static int
xerror_handler(Display *disp, XErrorEvent *err)
{
#ifdef DEBUG
    char msg[128];
    char buf[128];
    char *ev = getenv("NOISY_AWT");
    if (!ev || !ev[0]) return 0;
    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);
    }
    if (awt_lock) {
	/*SignalError(lockedee->lastpc, lockedee, "fp/ade/gui/GUIException", msg);*/
    }
    if (strcasecmp(ev, "abort") == 0) sysAbort();
#endif
    return 0;
}

static int
xtError() 
{
#ifdef DEBUG
    printf("Xt error\n");
    SignalError(0, JAVAPKG "NullPointerException", 0);
#endif
    return 0;
}

#if defined(NETSCAPE) && (defined(SCO) || defined(UNIXWARE))
/*
 * Prevent Motif warning messages from confusing Java apps
 */
static XtErrorMsgHandler
xtWarning(char *message)
{
#ifdef DEBUG
    extern FILE *real_stderr;

    if (message && *message)
       /* Is this safe to call? */
       (void)fprintf(real_stderr, "Java vs Motif: %s\n", message);
#endif
    return 0;
}
#endif

static int
xioerror_handler(Display *disp)
{
    if (awt_lock) {
	/*SignalError(lockedee->lastpc, lockedee, "fp/ade/gui/GUIException", "I/O error");*/
    }
    return 0;
}

Boolean scrollBugWorkAround;

void
sun_awt_motif_MToolkit_init(struct Hsun_awt_motif_MToolkit *this)
{
    int	argc = 0;
    char *argv[1];
    Display *dpy;
    XColor color;
    XVisualInfo viTmp, *pVI;
    int numvi;
#ifdef NETSCAPE
    sigset_t alarm_set, oldset;
#endif

    awt_lock = this;
    AWT_LOCK();

#ifdef NETSCAPE
    if (awt_init_xt) {
	XtToolkitInitialize();
    }
#else
    XtToolkitInitialize();
#endif

    argv[0] = 0;
#ifdef NETSCAPE
    /* Disable interrupts during XtOpenDisplay to avoid bugs in unix os select
       code: some unix systems don't implement SA_RESTART properly and
       because of this, select returns with EINTR. Most implementations of
       gethostbyname don't cope with EINTR properly and as a result we get
       stuck (forever) in the gethostbyname code
       */
    sigemptyset(&alarm_set);
    sigaddset(&alarm_set, SIGALRM);
    sigprocmask(SIG_BLOCK, &alarm_set, &oldset);
#endif
    awt_appContext = XtCreateApplicationContext();
#if defined(NETSCAPE) && (defined(SCO) || defined(UNIXWARE))
    XtAppSetWarningHandler(awt_appContext, &xtWarning);
#endif
    dpy = awt_display = XtOpenDisplay(awt_appContext,
				      (getenv("DISPLAY") == 0) ? ":0.0" : NULL,
				      "MToolkit app",
				      "XApplication",
				      NULL,
				      0,
				      &argc,
				      argv);
#ifdef NETSCAPE
    sigprocmask(SIG_SETMASK, &oldset, 0);
#endif

    XtAppSetErrorHandler(awt_appContext, (XtErrorHandler)xtError);
    if (!dpy) {
	char *errmsg = (char *)sysMalloc(1024);

	if (!errmsg) {
	    errmsg = "Can't connect to X11 window server";
	} else {
	    jio_snprintf(errmsg,
			 1024,
			 "Can't connect to X11 window server using '%s' as the value of the DISPLAY variable.",
			 (getenv("DISPLAY") == 0) ? ":0.0" : getenv("DISPLAY"));
	}
	SignalError(0, JAVAPKG "InternalError", errmsg);
	AWT_UNLOCK();
	return;
    }

    awt_multiclick_time = XtGetMultiClickTime(awt_display);
/*
    scrollBugWorkAround = 
	(strcmp(XServerVendor(dpy), "Sun Microsystems, Inc.") == 0
	 && XVendorRelease(dpy) == 3400);
*/
    scrollBugWorkAround = TRUE;

    XSetErrorHandler(xerror_handler);
    XSetIOErrorHandler(xioerror_handler);

    awt_screen = DefaultScreen(awt_display);
    awt_root = RootWindow(awt_display, awt_screen);
    if (!getenv("FORCEDEFVIS") && XMatchVisualInfo(dpy, 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(dpy, awt_root, awt_visual,
					  AllocNone);
	}
	color.flags = DoRed | DoGreen | DoBlue;
	color.red = color.green = color.blue = 0x0000;
	XAllocColor(dpy, awt_cmap, &color);
	awt_blackpixel = color.pixel;
	color.flags = DoRed | DoGreen | DoBlue;
	color.red = color.green = color.blue = 0xffff;
	XAllocColor(dpy, awt_cmap, &color);
	awt_whitepixel = color.pixel;
    } else {
	awt_visual = DefaultVisual(awt_display, awt_screen);
	awt_depth = DefaultDepth(awt_display, awt_screen);
#ifdef NETSCAPE
	awt_cmap = (*awt_GetDefaultColormap)();
#else
	awt_cmap = DefaultColormap(awt_display, awt_screen);
#endif /* NETSCAPE */
	viTmp.visualid = XVisualIDFromVisual(awt_visual);
	viTmp.depth = awt_depth;
	pVI = XGetVisualInfo(dpy, 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);
    }

    (void)awt_allocate_colors();
    awt_defaultBg = awtImage->ColorMatch(200, 200, 200);
    awt_defaultFg = awt_blackpixel;
    argc = 0;
    {
	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();
}

#ifdef NEW_EVENT_MODEL

void
awt_addWidget(Widget w, void *peer)
{
     if (!XtIsSubclass(w, xmFileSelectionBoxWidgetClass) &&
	 !XtIsSubclass(w, xmDrawingAreaWidgetClass)) {
	struct WidgetInfo *nw = (struct WidgetInfo *)sysMalloc(sizeof(struct WidgetInfo));
	if (nw) {
	    nw->widget = w;
	    nw->peer = peer;
	    nw->next = awt_winfo;
	    awt_winfo = nw;
	} else {
	    SignalError(0, JAVAPKG "OutOfMemoryError", 0);	    
	}
    }
}

void
awt_delWidget(Widget w)
{
    struct WidgetInfo	*cw;

    if (awt_winfo != NULL) {
	if (awt_winfo->widget == w) {
	    cw = awt_winfo;
	    awt_winfo = awt_winfo->next;
	    sysFree((void *)cw);
	} else {
	    struct WidgetInfo *pw;

	    for (pw = awt_winfo, cw = awt_winfo->next;
		 cw != NULL;
		 pw = cw, cw = cw->next) {
		if (cw->widget == w) {
		    pw->next = cw->next;
		    sysFree((void *)cw);
		    break;
		}
	    }
	}
    }
}

static void *
findPeer(Widget widget)
{
    struct WidgetInfo	*cw;

    for (cw = awt_winfo; cw != NULL; cw = cw->next) {
	if (cw->widget == widget) {
	    return cw->peer;
	}
    }
    return NULL;
}


#define KEYBOARD_ONLY_EVENTS

static int
dispatchToWidget(XEvent *xev)
{
    Window	win;
    Widget	widget = 0;
    void	*peer = NULL;
    Boolean	cont = FALSE;

#ifdef KEYBOARD_ONLY_EVENTS
    switch (xev->type) {
      case KeyPress:
      case KeyRelease:
	win = xev->xkey.window;
	break;
      default:
	return 0;
    }
#endif				/* KEYBOARD_ONLY_EVENTS */

    widget = XtWindowToWidget(awt_display, win);

    peer = NULL;

    /* If it's a keyboard event, we need to find the peer associated */
    /* with the widget that has the focus rather than the widget */
    /* associated with the window in the X event. */

    switch (xev->type) {
      case KeyPress:
      case KeyRelease:
	{
	    Widget focusWidget = XmGetFocusWidget(widget);

	    if (focusWidget != 0 && focusWidget != widget &&
		(peer = findPeer(focusWidget)) != NULL) {
		widget = focusWidget;
	    }
	}
	break;
      default:
	break;
    }

    /* If we found a widget and a suitable peer (either the focus
       peer above or the one associated with the widget then we
       dispatch to it. */
    if (widget != NULL &&
	(peer!=NULL || (peer = findPeer(widget)))) {
	awt_canvas_handleEvent(widget, peer, xev, &cont, TRUE);
	if (cont == TRUE) {
	    return 0;
	}
	return 1;
    } else {
	return 0;
    }
}

#endif				/* NEW_EVENT_MODEL */

#include "prmon.h"
#include "prclist.h"

typedef struct ModalWorkItemStr {
    PRCList links;
    int (*terminateFn)(void *data);
    void *data;
} ModalWorkItem;

static PRCList workQ = PR_INIT_STATIC_CLIST(&workQ);

#define MODAL_WORK_ITEM_PTR(_qp) \
    ((ModalWorkItem*) ((char*) (_qp) - offsetof(ModalWorkItem,links)))

void awt_MToolkit_loop(void)
{
    XtInputMask	iMask;
    XEvent xev;
    PRCList *qp;
    fd_set rdset;

    /*
    ** Wait for something to show up for this connection. The awt-thread
    ** is the only thread that does this.
    */
    AWT_UNLOCK();
    FD_ZERO(&rdset);
    FD_SET(ConnectionNumber(awt_display), &rdset);
    select(ConnectionNumber(awt_display)+1, &rdset, 0,  0, 0);
    AWT_LOCK();

    for (;;) {
	iMask = XtAppPending(awt_appContext);
	if (iMask == 0)
	    break;
#ifdef NEW_EVENT_MODEL	
	if (iMask & XtIMXEvent) {
	    XtAppNextEvent(awt_appContext, &xev);
	    if (dispatchToWidget(&xev) == 0) {
		XtDispatchEvent(&xev);
	    }
	} else if (iMask & XtIMTimer) {
	    XtAppProcessEvent(awt_appContext, XtIMTimer);
	} else {
	    XtAppProcessEvent(awt_appContext, iMask);
	}
#else
	XtAppProcessEvent(awt_appContext, iMask);
#endif				/* NEW_EVENT_MODEL */
    }

    /* Scan work Q looking for modal operations that finished */
    qp = workQ.next;
    while (qp != &workQ) {
	ModalWorkItem *m = MODAL_WORK_ITEM_PTR(qp);
	if ((*m->terminateFn)(m->data)) {
	    /* All done */
	    PR_REMOVE_LINK(&m->links);
	    PR_CEnterMonitor(m);
	    PR_CNotify(m);
	    PR_CExitMonitor(m);
	}
	qp = qp->next;
    }
}

void
sun_awt_motif_MToolkit_run(struct Hsun_awt_motif_MToolkit *this)
{
    sysAssert(this == awt_lock);
    awt_thread = PR_CurrentThread();
    AWT_LOCK();
    for (;;) {
	(void) awt_MToolkit_loop();
    }
}

void
sun_awt_motif_MToolkit_sync(struct Hsun_awt_motif_MToolkit *this)
{
    AWT_LOCK();
    XSync(awt_display, False);
    AWT_UNLOCK();
}


void
awt_MToolkit_modalWait(int (*terminateFn)(void *data), void *data)
{
    ModalWorkItem e;

    if (PR_CurrentThread() == awt_thread) {
	/*
	** This is going to cause a deadlock. For some reason a modal
	** wait is being done by the awt thread (probably because
	** somebody's paint method brought up a modal dialog?).
	*/
	SignalError(0, "java/awt/AWTError", "modal deadlock");
	return;
    }

    /*
    ** Enter monitor before we append this modal wait to the queue so
    ** that we don't lose the notify
    */
    PR_CEnterMonitor(&e);

    /* Add this modal work item to the queue */
    AWT_LOCK();
    e.terminateFn = terminateFn;
    e.data = data;
    PR_APPEND_LINK(&e.links, &workQ);
    AWT_UNLOCK();

    /* Wait forever for modal operation to terminate */
    PR_CWait(&e, LL_MAXINT);
    PR_CExitMonitor(&e);
}

long
sun_awt_motif_MToolkit_getScreenWidth(struct Hsun_awt_motif_MToolkit *this)
{
    return DisplayWidth(awt_display, awt_screen);
}

long
sun_awt_motif_MToolkit_getScreenHeight(struct Hsun_awt_motif_MToolkit *this)
{
    return DisplayHeight(awt_display, awt_screen);
}

long
sun_awt_motif_MToolkit_getScreenResolution(struct Hsun_awt_motif_MToolkit *this)
{
    return (int)((DisplayWidth(awt_display, awt_screen) * 25.4) / 
		   DisplayWidthMM(awt_display, awt_screen));
}

struct Hjava_awt_image_ColorModel *
sun_awt_motif_MToolkit_makeColorModel(struct Hsun_awt_motif_MToolkit *this)
{
    extern struct Hjava_awt_image_ColorModel *awt_getColorModel(void);
    return awt_getColorModel();
}