📄 srvfunc.c
字号:
/*
* Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
* Copyright (c) 2000 Alex Holden <alex@linuxhacker.org>
* Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MWINCLUDECOLORS
#include "serv.h"
static int nextid = GR_ROOT_WINDOW_ID + 1;
static void CheckNextEvent(GR_EVENT *ep, GR_BOOL doSelect);
/*
* Return information about the screen for clients to use.
*/
void
GrGetScreenInfo(GR_SCREEN_INFO *sip)
{
GdGetScreenInfo(rootwp->psd, sip);
/* virtual/workspace screen sizing*/
#if 0
/* force small screen for emulation purposes*/
sip->vs_width = 240; /* PDA*/
sip->vs_height = 320;
sip->ws_width = 240;
sip->ws_height = 298;
#else
/* set workspace equal to screen area minus 22 pixel taskbar*/
sip->vs_width = sip->cols;
sip->vs_height = sip->rows;
sip->ws_width = sip->cols;
sip->ws_height = sip->rows - 22;
#endif
}
/*
* Return the size of a text string for the font in a graphics context.
* This is the width of the string, the height of the string,
* and the height above the bottom of the font of the baseline for the font.
*/
void
GrGetGCTextSize(GR_GC_ID gc, void *str, int count, int flags,
GR_SIZE *retwidth, GR_SIZE *retheight, GR_SIZE *retbase)
{
GR_GC *gcp;
GR_FONT *fontp;
PMWFONT pf;
gcp = GsFindGC(gc);
if (gcp == NULL)
fontp = NULL;
else
fontp = GsFindFont(gcp->fontid);
pf = fontp? fontp->pfont: stdfont;
GdGetTextSize(pf, str, count, retwidth, retheight, retbase, flags);
}
#if NONETWORK
/*
* Return the next waiting event for a client, or wait for one if there
* is none yet. The event is copied into the specified structure, and
* then is moved from the event queue to the free event queue. If there
* is an error event waiting, it is delivered before any other events.
*/
void
GrGetNextEvent(GR_EVENT *ep)
{
GrGetNextEventTimeout(ep, 0L);
}
/*
* Return the next event from the event queue, or
* wait for a new one if one is not ready. If timeout
* is nonzero, return timeout event if time elapsed.
*/
void
GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout)
{
/* If no event ready, wait for one*/
/* Note: won't work for multiple clients*/
/* This is OK, since only static linked apps call this function*/
while(curclient->eventhead == NULL)
GsSelect(timeout);
CheckNextEvent(ep, GR_FALSE);
}
/*
* Wait until an event is available for a client, and then peek at it.
*/
void
GrPeekWaitEvent(GR_EVENT *ep)
{
while(curclient->eventhead == NULL)
GsSelect(0L);
GrPeekEvent(ep);
}
#endif
/*
* Return the next event from the event queue if one is ready.
* If one is not ready, then the type GR_EVENT_TYPE_NONE is returned.
* If it is an error event, then a user-specified routine is called
* if it was defined, otherwise we clean up and exit.
*/
void
GrCheckNextEvent(GR_EVENT *ep)
{
CheckNextEvent(ep, GR_TRUE);
}
static void
CheckNextEvent(GR_EVENT *ep, GR_BOOL doSelect)
{
GR_EVENT_LIST * elp;
#if NONETWORK
/* Since we're bound to server, select() is only called
* thru here
*/
if(doSelect)
GsSelect(0L);
#endif
/* Copy first event if any*/
if(!GrPeekEvent(ep))
return;
/* Get first event again*/
elp = curclient->eventhead;
/* Remove first event from queue*/
curclient->eventhead = elp->next;
if (curclient->eventtail == elp)
curclient->eventtail = NULL;
elp->next = eventfree;
eventfree = elp;
}
/*
* Peek at the event queue for the current client to see if there are any
* outstanding events. Returns the event at the head of the queue, or
* else a null event type. The event is still left in the queue, however.
*/
int
GrPeekEvent(GR_EVENT *ep)
{
GR_EVENT_LIST * elp;
elp = curclient->eventhead;
if(elp == NULL) {
ep->type = GR_EVENT_TYPE_NONE;
return 0;
}
/* copy event out*/
*ep = elp->event;
return 1;
}
/*
* Return information about a window id.
*/
void
GrGetWindowInfo(GR_WINDOW_ID wid, GR_WINDOW_INFO *infoptr)
{
GR_WINDOW *wp; /* window structure */
GR_PIXMAP *pp;
GR_EVENT_CLIENT *evp; /* event-client structure */
/* first check window list*/
wp = GsFindWindow(wid);
if (wp) {
infoptr->wid = wid;
/* report parent-relative x,y coordinates*/
infoptr->x = wp->x - (wp->parent ? wp->parent->x : 0);
infoptr->y = wp->y - (wp->parent ? wp->parent->y : 0);
infoptr->width = wp->width;
infoptr->height = wp->height;
infoptr->parent = wp->parent? wp->parent->id: 0;
infoptr->child = wp->children? wp->children->id: 0;
infoptr->sibling = wp->siblings? wp->siblings->id: 0;
infoptr->mapped = wp->mapped;
infoptr->unmapcount = wp->unmapcount;
infoptr->inputonly = !wp->output;
infoptr->bordersize = wp->bordersize;
infoptr->bordercolor = wp->bordercolor;
infoptr->background = wp->background;
infoptr->props = wp->props;
infoptr->cursor = wp->cursorid;
infoptr->processid = wp->owner? wp->owner->processid: 0;
infoptr->eventmask = 0;
for (evp = wp->eventclients; evp; evp = evp->next) {
if (evp->client == curclient)
infoptr->eventmask = evp->eventmask;
}
return;
}
/* then pixmap list*/
pp = GsFindPixmap(wid);
if (pp) {
infoptr->wid = wid;
infoptr->x = pp->x;
infoptr->y = pp->y;
infoptr->width = pp->width;
infoptr->height = pp->height;
infoptr->parent = 0;
infoptr->child = 0;
infoptr->sibling = 0;
infoptr->mapped = GR_FALSE;
infoptr->unmapcount = 0;
infoptr->inputonly = GR_FALSE;
infoptr->bordersize = 0;
infoptr->bordercolor = 0;
infoptr->background = 0;
infoptr->eventmask = 0;
infoptr->cursor = 0;
infoptr->processid = pp->owner? pp->owner->processid: 0;
return;
}
/* No error if window id is invalid.*/
memset(infoptr, 0, sizeof(GR_WINDOW_INFO));
}
/*
* Destroy an existing window and all of its children.
* Also used to destroy a pixmap.
*/
void
GrDestroyWindow(GR_WINDOW_ID wid)
{
GR_WINDOW *wp; /* window structure */
GR_PIXMAP *pp;
GR_PIXMAP *prevpp;
PSD psd;
wp = GsFindWindow(wid);
if (wp) {
GsWpDestroyWindow(wp);
} else {
pp = GsFindPixmap(wid);
if (pp) {
psd = pp->psd;
/* deallocate pixmap memory*/
if (psd->flags & PSF_ADDRMALLOC)
free(psd->addr);
/* deallocate mem gc*/
psd->FreeMemGC(psd);
/*
* Remove this pixmap from the complete list of pixmaps.
*/
prevpp = listpp;
if (prevpp == pp)
listpp = pp->next;
else {
while (prevpp->next != pp)
prevpp = prevpp->next;
prevpp->next = pp->next;
}
/*
* Forget various information if they related to this
* pixmap. Then finally free the structure.
*/
if (pp == cachepp) {
cachepixmapid = 0;
cachepp = NULL;
}
free(pp);
}
}
}
/*
* Raise a window to the highest level among its siblings.
*/
void
GrRaiseWindow(GR_WINDOW_ID wid)
{
GR_WINDOW *wp; /* window structure */
GR_WINDOW *prevwp; /* previous window pointer */
GR_BOOL overlap; /* TRUE if there was overlap */
wp = GsFindWindow(wid);
if ((wp == NULL) || (wp == rootwp))
return;
/*
* If this is already the highest window then we are done.
*/
prevwp = wp->parent->children;
if (prevwp == wp)
return;
/*
* Find the sibling just before this window so we can unlink it.
* Also, determine if any sibling ahead of us overlaps the window.
* Remember that for exposure events.
*/
overlap = GR_FALSE;
while (prevwp->siblings != wp) {
overlap |= GsCheckOverlap(prevwp, wp);
prevwp = prevwp->siblings;
}
overlap |= GsCheckOverlap(prevwp, wp);
/*
* Now unlink the window and relink it in at the front of the
* sibling chain.
*/
prevwp->siblings = wp->siblings;
wp->siblings = wp->parent->children;
wp->parent->children = wp;
/*
* Finally redraw the window if necessary.
*/
if (overlap) {
GsDrawBorder(wp);
GsExposeArea(wp, wp->x, wp->y, wp->width, wp->height, NULL);
}
}
/*
* Lower a window to the lowest level among its siblings.
*/
void GrLowerWindow(GR_WINDOW_ID wid)
{
GR_WINDOW *wp; /* window structure */
GR_WINDOW *prevwp; /* previous window pointer */
GR_WINDOW *sibwp; /* sibling window */
GR_WINDOW *expwp; /* siblings being exposed */
wp = GsFindWindow(wid);
if ((wp == NULL) || (wp == rootwp))
return;
if (wp->siblings == NULL)
return;
/*
* Find the sibling just before this window so we can unlink us.
*/
prevwp = wp->parent->children;
if (prevwp != wp) {
while (prevwp->siblings != wp)
prevwp = prevwp->siblings;
}
/*
* Remember the first sibling that is after us, so we can
* generate exposure events for the remaining siblings. Then
* walk down the sibling chain looking for the last sibling.
*/
expwp = wp->siblings;
sibwp = wp;
while (sibwp->siblings)
sibwp = sibwp->siblings;
/*
* Now unlink the window and relink it in at the end of the
* sibling chain.
*/
if (prevwp == wp)
wp->parent->children = wp->siblings;
else
prevwp->siblings = wp->siblings;
sibwp->siblings = wp;
wp->siblings = NULL;
/*
* Finally redraw the sibling windows which this window covered
* if they overlapped our window.
*/
while (expwp && (expwp != wp)) {
if (GsCheckOverlap(wp, expwp)) {
GsExposeArea(expwp, wp->x - wp->bordersize,
wp->y - wp->bordersize,
wp->width + wp->bordersize * 2,
wp->height + wp->bordersize * 2, NULL);
}
expwp = expwp->siblings;
}
}
/* Offset a window position and all children by offx,offy*/
static void
OffsetWindow(GR_WINDOW *wp, GR_COORD offx, GR_COORD offy)
{
GR_WINDOW *cp;
wp->x += offx;
wp->y += offy;
for(cp=wp->children; cp; cp=cp->siblings)
OffsetWindow(cp, offx, offy);
}
/* deliver an update move event to window and all children*/
static void
DeliverUpdateMoveEventAndChildren(GR_WINDOW *wp)
{
GR_WINDOW * childwp;
GsDeliverUpdateEvent(wp, GR_UPDATE_MOVE, wp->x, wp->y,
wp->width, wp->height);
for (childwp = wp->children; childwp; childwp = childwp->siblings)
DeliverUpdateMoveEventAndChildren(childwp);
}
/*
* Move the window to the specified position relative to its parent.
*/
void
GrMoveWindow(GR_WINDOW_ID wid, GR_COORD x, GR_COORD y)
{
GR_WINDOW *wp; /* window structure */
GR_COORD offx, offy;
wp = GsFindWindow(wid);
if (wp == NULL)
return;
if (wp == rootwp) {
GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid);
return;
}
x += wp->parent->x;
y += wp->parent->y;
offx = x - wp->x;
offy = y - wp->y;
if (wp->x == x && wp->y == y)
return;
/*** move algorithms not requiring unmap/map ***/
#if 1
/* perform screen blit if topmost and mapped - no flicker!*/
if (wp->mapped && wp == wp->parent->children
&& wp->parent->id == GR_ROOT_WINDOW_ID
/* temp don't blit in portrait mode, still buggy*/
&& !(wp->psd->portrait & (MWPORTRAIT_LEFT|MWPORTRAIT_RIGHT))
) {
int oldx = wp->x;
int oldy = wp->y;
GR_WINDOW_ID pixid = GrNewPixmap(wp->width, wp->height,NULL);
GR_GC_ID gc = GrNewGC();
GR_WINDOW * stopwp = wp;
int X, Y, W, H;
/* must hide cursor first or GdFixCursor() will show it*/
GdHideCursor(rootwp->psd);
/* turn off clipping of root's children*/
GrSetGCMode(gc, GR_MODE_COPY|GR_MODE_EXCLUDECHILDREN);
/* copy topmost window contents offscreen*/
GrCopyArea(pixid, gc, 0, 0, wp->width, wp->height,
GR_ROOT_WINDOW_ID, oldx, oldy, MWROP_COPY);
/* calc new window offsets*/
OffsetWindow(wp, offx, offy);
/* force recalc of clip region*/
clipwp = NULL;
/* copy window bits to new location*/
GrCopyArea(GR_ROOT_WINDOW_ID, gc, wp->x, wp->y, wp->width,
wp->height, pixid, 0, 0, MWROP_COPY);
/*
* If any portion of the window was offscreen
* and is coming onscreen, must send expose events
* to this window as well.
*/
if ((oldx < 0 && wp->x > oldx) ||
(oldy < 0 && wp->y > oldy) ||
(oldx+wp->width > rootwp->width && wp->x < oldx) ||
(oldy+wp->height > rootwp->height && wp->y < oldy))
stopwp = NULL;
/*
* Calculate bounded exposed area and
* redraw anything lower than stopwp window.
*/
X = MWMIN(oldx, wp->x);
Y = MWMIN(oldy, wp->y);
W = MWMAX(oldx, wp->x) + wp->width - X;
H = MWMAX(oldy, wp->y) + wp->height - Y;
GsExposeArea(rootwp, X, Y, W, H, stopwp);
GdShowCursor(rootwp->psd);
GrDestroyGC(gc);
GrDestroyWindow(pixid);
DeliverUpdateMoveEventAndChildren(wp);
return;
}
#endif
#if 0
/* perform quick move and expose if topmost and mapped - no blit*/
if (wp->mapped && wp == wp->parent->children) {
int oldx = wp->x;
int oldy = wp->y;
int X, Y, W, H;
OffsetWindow(wp, offx, offy);
/* force recalc of clip region*/
clipwp = NULL;
X = MWMIN(oldx, wp->x);
Y = MWMIN(oldy, wp->y);
W = MWMAX(oldx, wp->x) + wp->width - X;
H = MWMAX(oldy, wp->y) + wp->height - Y;
GsExposeArea(rootwp, X, Y, W, H, NULL);
DeliverUpdateMoveEventAndChildren(wp);
return;
}
#endif
/*
* This method will redraw the window entirely,
* resulting in considerable flicker.
*/
GsWpUnmapWindow(wp, GR_TRUE);
OffsetWindow(wp, offx, offy);
GsWpMapWindow(wp, GR_FALSE);
DeliverUpdateMoveEventAndChildren(wp);
}
/*
* Resize the window to be the specified size.
*/
void
GrResizeWindow(GR_WINDOW_ID wid, GR_SIZE width, GR_SIZE height)
{
GR_WINDOW *wp; /* window structure */
wp = GsFindWindow(wid);
if (wp == NULL)
return;
if (wp == rootwp) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -