⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 srvevent.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2000 Greg Haerr <greg@censoft.com>
 * Copyright (c) 1991 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 * Graphics server event routines for windows.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "serv.h"

#ifndef __ECOS
/* readable error strings*/
char *nxErrorStrings[] = {
	GR_ERROR_STRINGS
};
#endif

#if NONETWORK
/* [copied from client.c]
 * The following is the user defined function for handling errors.
 * If this is not set, then the default action is to close the connection
 * to the server, describe the error, and then exit.  This error function
 * will only be called when the client asks for events.
 */
static GR_FNCALLBACKEVENT ErrorFunc = GrDefaultErrorHandler;

/* 
 * The default error handler which is called when the server
 * reports an error event and the client hasn't set a handler for error events.
 */
void 
GrDefaultErrorHandler(GR_EVENT *ep)
{
	if (ep->type == GR_EVENT_TYPE_ERROR) {
		EPRINTF("nxclient: Error (%s) ", ep->error.name);
		EPRINTF(nxErrorStrings[ep->error.code], ep->error.id);
		GrClose();
		exit(1);
	}
}

/*
 * Set an error handling routine, which will be called on any errors from
 * the server (when events are asked for by the client).  If zero is given,
 * then errors will be returned as regular events.  
 * Returns the previous error handler.
 */
GR_FNCALLBACKEVENT
GrSetErrorHandler(GR_FNCALLBACKEVENT fncb)
{
	GR_FNCALLBACKEVENT orig = ErrorFunc;

	ErrorFunc = fncb;
	return orig;
}
#endif /* NONETWORK*/

/*
 * Generate an error from a graphics function.
 * This creates a special event which describes the error.
 * Only one error event at a time can be saved for delivery to a client.
 * This is ok since there are usually lots of redundant errors generated
 * before the client can notice, errors occurs after the fact, and clients
 * can't do much about them except complain and die.  The error is saved
 * specially so that memory problems cannot occur.
 */
void GsError(GR_ERROR code, GR_ID id)
{
	GR_EVENT_ERROR	*ep;		/* event to describe error */

	EPRINTF("nano-X: GsError ");
	if(curfunc)
		EPRINTF("(%s) ", curfunc);
	EPRINTF(nxErrorStrings[code], id);

	/* if no clients, nothing to report*/
	if (!curclient)
		return;

	/* queue the error event regardless of GrSelectEvents*/
	ep = (GR_EVENT_ERROR *)GsAllocEvent(curclient);
	ep->type = GR_EVENT_TYPE_ERROR;
	ep->name[0] = 0;
	if(curfunc) {
		strncpy(ep->name, curfunc, sizeof(GR_FUNC_NAME));
		ep->name[sizeof(GR_FUNC_NAME)-1] = '\0';
	}
	ep->code = code;
	ep->id = id;
}

/*
 * Allocate an event to be passed back to the specified client.
 * The event is already chained onto the event queue, and only
 * needs filling out.  Returns NULL with an error generated if
 * the event cannot be allocated.
 */
GR_EVENT *GsAllocEvent(GR_CLIENT *client)
{
	GR_EVENT_LIST	*elp;		/* current element list */
	GR_CLIENT	*oldcurclient;	/* old current client */

	/*
	 * Get a new event structure from the free list, or else
	 * allocate it using malloc.
	 */
	elp = eventfree;
	if (elp)
		eventfree = elp->next;
	else {
		elp = (GR_EVENT_LIST *) malloc(sizeof(GR_EVENT_LIST));
		if (elp == NULL) {
			oldcurclient = curclient;
			curclient = client;
			GsError(GR_ERROR_MALLOC_FAILED, 0);
			curclient = oldcurclient;
			return NULL;
		}
	}

	/*
	 * Add the event to the end of the event list.
	 */
	if (client->eventhead)
		client->eventtail->next = elp;
	else
		client->eventhead = elp;
	client->eventtail = elp;
	elp->next = NULL;
	elp->event.type = GR_EVENT_TYPE_NONE;

	return &elp->event;
}

/*
 * Update mouse status and issue events on it if necessary.
 * This function doesn't block, but is normally only called when
 * there is known to be some data waiting to be read from the mouse.
 */
GR_BOOL GsCheckMouseEvent(void)
{
	GR_COORD	rootx;		/* latest mouse x position */
	GR_COORD	rooty;		/* latest mouse y position */
	int		newbuttons;	/* latest buttons */
	int		mousestatus;	/* latest mouse status */

	/* Read the latest mouse status: */
	mousestatus = GdReadMouse(&rootx, &rooty, &newbuttons);
	if(mousestatus < 0) {
		GsError(GR_ERROR_MOUSE_ERROR, 0);
		return FALSE;
	} else if(mousestatus) {	/* Deliver events as appropriate: */	
		GsHandleMouseStatus(rootx, rooty, newbuttons);

		/* possibly reset portrait mode based on mouse position*/
		if (autoportrait)
			GsSetPortraitModeFromXY(rootx, rooty);
		return TRUE;
	}
	return FALSE;
}

/*
 * Update keyboard status and issue events on it if necessary.
 * This function doesn't block, but is normally only called when
 * there is known to be some data waiting to be read from the keyboard.
 */
GR_BOOL GsCheckKeyboardEvent(void)
{
	MWKEY	 	mwkey;		/* latest character */
	MWKEYMOD 	modifiers;	/* latest modifiers */
	MWSCANCODE	scancode;
	int	 	keystatus;	/* latest keyboard status */

	/* Read the latest keyboard status: */
	keystatus = GdReadKeyboard(&mwkey, &modifiers, &scancode);

	if(keystatus < 0) {
		if(keystatus == -2)	/* special case return code*/
			GsTerminate();
		GsError(GR_ERROR_KEYBOARD_ERROR, 0);
		return FALSE;
	} else if(keystatus) {		/* Deliver events as appropriate: */	
		switch (mwkey) {
		case MWKEY_QUIT:
			GsTerminate();
			/* no return*/
		case MWKEY_REDRAW:
			GsRedrawScreen();
			break;
		case MWKEY_PRINT:
			if (keystatus == 1)
				GdCaptureScreen("screen.bmp");
			break;
		}
		GsDeliverKeyboardEvent(0,
			(keystatus==1?
			GR_EVENT_TYPE_KEY_DOWN: GR_EVENT_TYPE_KEY_UP),
			mwkey, modifiers, scancode);
		return TRUE;
	}
	return FALSE;
}

/*
 * Handle all mouse events.  These are mouse enter, mouse exit, mouse
 * motion, mouse position, button down, and button up.  This also moves
 * the cursor to the new mouse position and changes it shape if needed.
 */
void GsHandleMouseStatus(GR_COORD newx, GR_COORD newy, int newbuttons)
{
	int	 changebuttons;	/* buttons that have changed */
	MWKEYMOD modifiers;	/* latest modifiers */

	GdGetModifierInfo(NULL, &modifiers); /* Read kbd modifiers */

	/*
	 * First, if the mouse has moved, then position the cursor to the
	 * new location, which will send mouse enter, mouse exit, focus in,
	 * and focus out events if needed.  Check here for mouse motion and
	 * mouse position events.  Flush the device queue to make sure the
	 * new cursor location is quickly seen by the user.
	 */
	if ((newx != cursorx) || (newy != cursory)) {
		GsResetScreenSaver();
		GrMoveCursor(newx, newy);
		GsDeliverMotionEvent(GR_EVENT_TYPE_MOUSE_MOTION,
			newbuttons, modifiers);
		GsDeliverMotionEvent(GR_EVENT_TYPE_MOUSE_POSITION,
			newbuttons, modifiers);
	}

	/*
	 * Next, generate a button up event if any buttons have been released.
	 */
	changebuttons = (curbuttons & ~newbuttons);
	if (changebuttons) {
		GsResetScreenSaver();
		GsDeliverButtonEvent(GR_EVENT_TYPE_BUTTON_UP,
			newbuttons, changebuttons, modifiers);
	}

	/*
	 * Finally, generate a button down event if any buttons have been
	 * pressed.
	 */
	changebuttons = (~curbuttons & newbuttons);
	if (changebuttons) {
		GsResetScreenSaver();
		GsDeliverButtonEvent(GR_EVENT_TYPE_BUTTON_DOWN,
			newbuttons, changebuttons, modifiers);
	}

	curbuttons = newbuttons;
}

/*
 * Deliver a mouse button event to the clients which have selected for it.
 * Each client can only be delivered one instance of the event.  The window
 * the event is delivered for is either the smallest one containing the
 * mouse coordinates, or else one of its direct ancestors.  The lowest
 * window in that tree which has enabled for the event gets it.  This scan
 * is done independently for each client.  If a window with the correct
 * noprop mask is reached, or if no window selects for the event, then the
 * event is discarded for that client.  Special case: for the first client
 * that is enabled for both button down and button up events in a window,
 * then the pointer is implicitly grabbed by that window when a button is
 * pressed down in that window.  The grabbing remains until all buttons are
 * released.  While the pointer is grabbed, no other clients or windows can
 * receive button down or up events.
 */
void GsDeliverButtonEvent(GR_EVENT_TYPE type, int buttons, int changebuttons,
			int modifiers)
{
	GR_EVENT_BUTTON	*ep;		/* mouse button event */
	GR_WINDOW	*wp;		/* current window */
	GR_EVENT_CLIENT	*ecp;		/* current event client */
	GR_CLIENT	*client;	/* current client */
	GR_WINDOW_ID	subwid;		/* subwindow id event is for */
	GR_EVENT_MASK	eventmask;	/* event mask */
	GR_EVENT_MASK	tempmask;	/* to get around compiler bug */

	eventmask = GR_EVENTMASK(type);
	if (eventmask == 0)
		return;

	/*
	 * If the pointer is implicitly grabbed, then the only window
	 * which can receive button events is that window.  Otherwise
	 * the window the pointer is in gets the events.  Determine the
	 * subwindow by seeing if it is a child of the grabbed button.
	 */
	wp = mousewp;
	subwid = wp->id;

	if (grabbuttonwp) {
		while ((wp != rootwp) && (wp != grabbuttonwp))
			wp = wp->parent;
#if 0
		if (wp != grabbuttonwp)
			subwid = grabbuttonwp->id;
#endif
		wp = grabbuttonwp;
	}

	for (;;) {
		for (ecp = wp->eventclients; ecp; ecp = ecp->next) {
			if ((ecp->eventmask & eventmask) == 0)
				continue;

			client = ecp->client;

			/*
			 * If this is a button down, the buttons are not
			 * yet grabbed, and this client is enabled for both
			 * button down and button up events, then implicitly
			 * grab the window for him.
			 */
			if ((type == GR_EVENT_TYPE_BUTTON_DOWN)
				&& (grabbuttonwp == NULL))
			{
				tempmask = GR_EVENT_MASK_BUTTON_UP;
				if (ecp->eventmask & tempmask) {
/*DPRINTF("nano-X: implicit grab on window %d\n", wp->id);*/
					grabbuttonwp = wp;
				}
			}

			ep = (GR_EVENT_BUTTON *) GsAllocEvent(client);
			if (ep == NULL)
				continue;

			ep->type = type;
			ep->wid = wp->id;
			ep->subwid = subwid;
			ep->rootx = cursorx;
			ep->rooty = cursory;
			ep->x = cursorx - wp->x;
			ep->y = cursory - wp->y;
			ep->buttons = buttons;
			ep->changebuttons = changebuttons;
			ep->modifiers = modifiers;
			ep->time = GsGetTickCount();
		}

		/*
		 * Events do not propagate if the window was grabbed.
		 * Also release the grab if the buttons are now all released,
		 * which can cause various events.
		 */
		if (grabbuttonwp) {
			if (buttons == 0) {
				grabbuttonwp = NULL;
				GrMoveCursor(cursorx, cursory);
			}
			return;
		}

		if ((wp == rootwp) || (wp->nopropmask & eventmask))
			return;

		wp = wp->parent;
	}
}

/*
 * Deliver a mouse motion event to the clients which have selected for it.
 * Each client can only be delivered one instance of the event.  The window
 * the event is delivered for is either the smallest one containing the
 * mouse coordinates, or else one of its direct ancestors.  The lowest
 * window in that tree which has enabled for the event gets it.  This scan
 * is done independently for each client.  If a window with the correct
 * noprop mask is reached, or if no window selects for the event, then the
 * event is discarded for that client.  Special case: If the event type is
 * GR_EVENT_TYPE_MOUSE_POSITION, then only the last such event is queued for
 * any single client to reduce events.  If the mouse is implicitly grabbed,
 * then only the grabbing window receives the events, and continues to do
 * so even if the mouse is currently outside of the grabbing window.
 */
void GsDeliverMotionEvent(GR_EVENT_TYPE type, int buttons, MWKEYMOD modifiers)
{
	GR_EVENT_MOUSE	*ep;		/* mouse motion event */
	GR_WINDOW	*wp;		/* current window */
	GR_EVENT_CLIENT	*ecp;		/* current event client */
	GR_CLIENT	*client;	/* current client */
	GR_WINDOW_ID	subwid;		/* subwindow id event is for */
	GR_EVENT_MASK	eventmask;	/* event mask */

	eventmask = GR_EVENTMASK(type);
	if (eventmask == 0)
		return;

	wp = mousewp;
	subwid = wp->id;

	if (grabbuttonwp) {
		while ((wp != rootwp) && (wp != grabbuttonwp))
			wp = wp->parent;
#if 0
		if (wp != grabbuttonwp)
			subwid = grabbuttonwp->id;
#endif
		wp = grabbuttonwp;
	}

	for (;;) {
		for (ecp = wp->eventclients; ecp; ecp = ecp->next) {
			if ((ecp->eventmask & eventmask) == 0)
				continue;

			client = ecp->client;

			/*
			 * If the event is for just the latest position,
			 * then search the event queue for an existing
			 * event of this type (if any), and free it.
			 */
			if (type == GR_EVENT_TYPE_MOUSE_POSITION) 
				GsFreePositionEvent(client, wp->id, subwid);

			ep = (GR_EVENT_MOUSE *) GsAllocEvent(client);
			if (ep == NULL)
				continue;

			ep->type = type;
			ep->wid = wp->id;
			ep->subwid = subwid;
			ep->rootx = cursorx;
			ep->rooty = cursory;
			ep->x = cursorx - wp->x;
			ep->y = cursory - wp->y;
			ep->buttons = buttons;
			ep->modifiers = modifiers;
		}

		if ((wp == rootwp) || grabbuttonwp ||
			(wp->nopropmask & eventmask))
				return;

		wp = wp->parent;
	}
}

/*
 * Deliver a keyboard event to one of the clients which have selected for it.
 * Only the first client found gets the event (no duplicates are sent).  The
 * window the event is delivered to is either the smallest one containing
 * the mouse coordinates, or else one of its direct ancestors (if such a

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -