diff options
author | Deron <dj@dj-laptop.(none)> | 2007-06-04 20:10:38 -0700 |
---|---|---|
committer | Deron <dj@dj-laptop.(none)> | 2007-06-04 20:10:38 -0700 |
commit | fe201a8f9a4cd8390a84660f68b78d2e4de622dd (patch) | |
tree | 8756e3cd469921802a7d49833cc999ffa8dd7e0b | |
parent | 9789f35cc5ca147c6c4b4bfc810d44fdbdbe5705 (diff) |
Add more files to branch.
-rw-r--r-- | hw/vfb/protocol.h | 615 | ||||
-rw-r--r-- | hw/vfb/remwin.h | 190 | ||||
-rw-r--r-- | hw/vfb/rle.c | 235 | ||||
-rw-r--r-- | hw/vfb/rwcomm.h | 98 | ||||
-rw-r--r-- | hw/vfb/rwcommsock.c | 457 | ||||
-rw-r--r-- | hw/vfb/rwcommsock.h | 55 | ||||
-rw-r--r-- | hw/vfb/rwin.c | 1029 | ||||
-rw-r--r-- | hw/vfb/takecontrol.c | 275 |
8 files changed, 2954 insertions, 0 deletions
diff --git a/hw/vfb/protocol.h b/hw/vfb/protocol.h new file mode 100644 index 000000000..122fb7657 --- /dev/null +++ b/hw/vfb/protocol.h @@ -0,0 +1,615 @@ + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +/* +** Client-to-Server Messages +*/ + +#define CLIENT_MESSAGE_TYPE_INVALID 0 +#define CLIENT_MESSAGE_TYPE_KEY 1 +#define CLIENT_MESSAGE_TYPE_POINTER 2 +#define CLIENT_MESSAGE_TYPE_TAKE_CONTROL 3 +#define CLIENT_MESSAGE_TYPE_SET_WINDOW_TITLES 4 +#define CLIENT_MESSAGE_TYPE_MOVE_WINDOW 5 +#define CLIENT_MESSAGE_TYPE_RESIZE_WINDOW 6 +#define CLIENT_MESSAGE_TYPE_DESTROY_WINDOW 7 +#define CLIENT_MESSAGE_TYPE_HELLO 8 + +typedef struct keyeventmessage_struct { + CARD8 msgType; + CARD8 isPressed; + CARD16 pad; + CARD32 keysym; + CARD32 clientId; +} KeyEventMessage; + +#define KEY_EVENT_MESSAGE_SIZE sizeof(KeyEventMessage) + +#define KEY_EVENT_MESSAGE_GET_ISPRESSED(pBuf) \ + ((KeyEventMessage*)(pBuf))->isPressed + +#define KEY_EVENT_MESSAGE_GET_KEYSYM(pBuf) \ + ((KeyEventMessage*)(pBuf))->keysym + +#define KEY_EVENT_MESSAGE_GET_CLIENTID(pBuf) \ + ((KeyEventMessage*)(pBuf))->clientId + +typedef struct pointereventmessage_struct { + CARD8 msgType; + CARD8 mask; + CARD16 x; + CARD16 y; + CARD16 pad; + CARD32 wid; + CARD32 clientId; +} PointerEventMessage; + +#define POINTER_EVENT_MESSAGE_SIZE sizeof(PointerEventMessage) + +#define POINTER_EVENT_MESSAGE_GET_MASK(pBuf) \ + ((PointerEventMessage *)(pBuf))->mask + +#define POINTER_EVENT_MESSAGE_GET_X(pBuf) \ + ((PointerEventMessage*)(pBuf))->x + +#define POINTER_EVENT_MESSAGE_GET_Y(pBuf) \ + ((PointerEventMessage*)(pBuf))->y + +#define POINTER_EVENT_MESSAGE_GET_WID(pBuf) \ + ((PointerEventMessage*)(pBuf))->wid + +#define POINTER_EVENT_MESSAGE_GET_CLIENTID(pBuf) \ + ((PointerEventMessage*)(pBuf))->clientId + +typedef struct takecontrolmessage_struct { + CARD8 msgType; + CARD8 steal; + CARD16 pad; + CARD32 clientId; +} TakeControlMessage; + +#define TAKE_CONTROL_MESSAGE_SIZE sizeof(TakeControlMessage) + +#define TAKE_CONTROL_MESSAGE_GET_STEAL(pBuf) \ + ((((TakeControlMessage*)(pBuf))->steal == 1) ? TRUE : FALSE) + +#define TAKE_CONTROL_MESSAGE_GET_CLIENTID(pBuf) \ + ((TakeControlMessage*)(pBuf))->clientId + +/* Same structure used for both server and client messages */ + +typedef struct setwindowtitlesmessage_struct { + CARD8 msgType; + CARD8 pad; + CARD16 strLen; + /* Followed by strLen bytes */ +} SetWindowTitlesMessage; + +#define SET_WINDOW_TITLES_MESSAGE_SIZE sizeof(SetWindowTitlesMessage) + +#define SET_WINDOW_TITLES_MESSAGE_SET_TYPE(pBuf, mType) \ + ((SetWindowTitlesMessage *)(pBuf))->msgType = (mType) + +#define SET_WINDOW_TITLES_MESSAGE_GET_STRLEN(pBuf) \ + ((((SetWindowTitlesMessage*)(pBuf))->strLen)) + +#define SET_WINDOW_TITLES_MESSAGE_SET_STRLEN(pBuf, len) \ + ((SetWindowTitlesMessage *)(pBuf))->strLen = (len) + +/* Same structure used for both server and client messages */ + +typedef struct movewindowmessage_struct { + CARD8 msgType; + CARD8 pad; + CARD16 x; + CARD32 clientId; + CARD32 wid; + CARD16 y; +} MoveWindowMessage; + +#define MOVE_WINDOW_MESSAGE_SIZE sizeof(MoveWindowMessage) + +#define MOVE_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((MoveWindowMessage *)(pBuf))->msgType = (mType) + +#define MOVE_WINDOW_MESSAGE_GET_X(pBuf) \ + ((((MoveWindowMessage*)(pBuf))->x)) + +#define MOVE_WINDOW_MESSAGE_SET_X(pBuf, xval) \ + ((MoveWindowMessage *)(pBuf))->x = (xval) + +#define MOVE_WINDOW_MESSAGE_GET_CLIENT_ID(pBuf) \ + ((((MoveWindowMessage*)(pBuf))->clientId)) + +#define MOVE_WINDOW_MESSAGE_SET_CLIENT_ID(pBuf, cid) \ + ((MoveWindowMessage *)(pBuf))->clientId = (cid) + +#define MOVE_WINDOW_MESSAGE_GET_WID(pBuf) \ + ((((MoveWindowMessage*)(pBuf))->wid)) + +#define MOVE_WINDOW_MESSAGE_SET_WID(pBuf, widval) \ + ((MoveWindowMessage *)(pBuf))->wid = (widval) + +#define MOVE_WINDOW_MESSAGE_GET_Y(pBuf) \ + ((((MoveWindowMessage*)(pBuf))->y)) + +#define MOVE_WINDOW_MESSAGE_SET_Y(pBuf, yval) \ + ((MoveWindowMessage *)(pBuf))->y = (yval) + +/* Same structure used for both server and client messages */ + +typedef struct resizewindowmessage_struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 clientId; + CARD32 wid; + CARD32 width; + CARD32 height; +} ResizeWindowMessage; + +#define RESIZE_WINDOW_MESSAGE_SIZE sizeof(ResizeWindowMessage) + +#define RESIZE_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((ResizeWindowMessage *)(pBuf))->msgType = (mType) + +#define RESIZE_WINDOW_MESSAGE_GET_CLIENT_ID(pBuf) \ + ((((ResizeWindowMessage*)(pBuf))->clientId)) + +#define RESIZE_WINDOW_MESSAGE_SET_CLIENT_ID(pBuf, cid) \ + ((ResizeWindowMessage *)(pBuf))->CLIENT_ID = (cid) + +#define RESIZE_WINDOW_MESSAGE_GET_WID(pBuf) \ + ((((ResizeWindowMessage*)(pBuf))->wid)) + +#define RESIZE_WINDOW_MESSAGE_SET_WID(pBuf, widval) \ + ((ResizeWindowMessage *)(pBuf))->wid = (widval) + +#define RESIZE_WINDOW_MESSAGE_GET_WIDTH(pBuf) \ + ((((ResizeWindowMessage*)(pBuf))->width)) + +#define RESIZE_WINDOW_MESSAGE_SET_WIDTH(pBuf, w) \ + ((ResizeWindowMessage *)(pBuf))->width = (w) + +#define RESIZE_WINDOW_MESSAGE_GET_HEIGHT(pBuf) \ + ((((ResizeWindowMessage*)(pBuf))->height)) + +#define RESIZE_WINDOW_MESSAGE_SET_HEIGHT(pBuf, h) \ + ((ResizeWindowMessage *)(pBuf))->height = (h) + +typedef struct hellomessage_struct { + CARD8 msgType; +} HelloMessage; + +#define MOVE_WINDOW_MESSAGE_SIZE sizeof(MoveWindowMessage) + +/* +** Server to Client Messages +*/ + +#define SERVER_MESSAGE_TYPE_CREATE_WINDOW 0 +#define SERVER_MESSAGE_TYPE_DESTROY_WINDOW 1 +#define SERVER_MESSAGE_TYPE_SHOW_WINDOW 2 +#define SERVER_MESSAGE_TYPE_CONFIGURE_WINDOW 3 +#define SERVER_MESSAGE_TYPE_POSITION_WINDOW 4 +#define SERVER_MESSAGE_TYPE_WINDOW_SET_DECORATED 5 +#define SERVER_MESSAGE_TYPE_WINDOW_SET_BORDER_WIDTH 6 +#define SERVER_MESSAGE_TYPE_BEEP 7 +#define SERVER_MESSAGE_TYPE_DISPLAY_PIXELS 8 +#define SERVER_MESSAGE_TYPE_COPY_AREA 9 +#define SERVER_MESSAGE_TYPE_CONTROLLER_STATUS 10 +#define SERVER_MESSAGE_TYPE_DISPLAY_CURSOR 11 +#define SERVER_MESSAGE_TYPE_MOVE_CURSOR 12 +#define SERVER_MESSAGE_TYPE_SHOW_CURSOR 13 +#define SERVER_MESSAGE_TYPE_SET_WINDOW_TITLES 14 +#define SERVER_MESSAGE_TYPE_WELCOME 15 +#define SERVER_MESSAGE_TYPE_PING 16 + +typedef struct { + CARD8 msgType; + CARD8 decorated; + CARD16 borderWidth; + CARD32 wid; + CARD16 x; + CARD16 y; + CARD32 wAndBorder; /* Includes 2 * bw */ + CARD32 hAndBorder; /* Includes 2 * bw */ +} CreateWindowMessage; + +#define CREATE_WINDOW_MESSAGE_SIZE sizeof(CreateWindowMessage) + +#define CREATE_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((CreateWindowMessage *)(pBuf))->msgType = (mType) + +#define CREATE_WINDOW_MESSAGE_SET_DECORATED(pBuf, decor) \ + ((CreateWindowMessage *)(pBuf))->decorated = (decor) + +#define CREATE_WINDOW_MESSAGE_SET_BORDER_WIDTH(pBuf, bw) \ + ((CreateWindowMessage *)(pBuf))->borderWidth = (bw) + +#define CREATE_WINDOW_MESSAGE_SET_WID(pBuf, windowId) \ + ((CreateWindowMessage *)(pBuf))->wid = (windowId) + +#define CREATE_WINDOW_MESSAGE_SET_X(pBuf, xval) \ + ((CreateWindowMessage *)(pBuf))->x = (xval) + +#define CREATE_WINDOW_MESSAGE_SET_Y(pBuf, yval) \ + ((CreateWindowMessage *)(pBuf))->y = (yval) + +#define CREATE_WINDOW_MESSAGE_SET_WANDBORDER(pBuf, wandb) \ + ((CreateWindowMessage *)(pBuf))->wAndBorder = (wandb) + +#define CREATE_WINDOW_MESSAGE_SET_HANDBORDER(pBuf, handb) \ + ((CreateWindowMessage *)(pBuf))->hAndBorder = (handb) + +/* Same structure used for both server and client messages */ + +typedef struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 wid; +} DestroyWindowMessage; + +#define DESTROY_WINDOW_MESSAGE_SIZE sizeof(DestroyWindowMessage) + +#define DESTROY_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((DestroyWindowMessage *)(pBuf))->msgType = (mType) + +#define DESTROY_WINDOW_MESSAGE_GET_WID(pBuf) \ + ((((DestroyWindowMessage*)(pBuf))->wid)) + +#define DESTROY_WINDOW_MESSAGE_SET_WID(pBuf, windowId) \ + ((DestroyWindowMessage *)(pBuf))->wid = (windowId) + +typedef struct { + CARD8 msgType; + CARD8 show; + CARD16 pad; + CARD32 wid; +} ShowWindowMessage; + +#define SHOW_WINDOW_MESSAGE_SIZE sizeof(ShowWindowMessage) + +#define SHOW_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((ShowWindowMessage *)(pBuf))->msgType = (mType) + +#define SHOW_WINDOW_MESSAGE_SET_WID(pBuf, windowId) \ + ((ShowWindowMessage *)(pBuf))->wid = (windowId) + +#define SHOW_WINDOW_MESSAGE_SET_SHOW(pBuf, showit) \ + ((ShowWindowMessage *)(pBuf))->show = (showit) + +typedef struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 clientId; + CARD32 wid; + CARD16 x; + CARD16 y; + CARD32 wAndBorder; /* Includes 2 * bw */ + CARD32 hAndBorder; /* Includes 2 * bw */ + CARD32 sibid; +} ConfigureWindowMessage; + +#define CONFIGURE_WINDOW_MESSAGE_SIZE sizeof(ConfigureWindowMessage) + +#define CONFIGURE_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((ConfigureWindowMessage *)(pBuf))->msgType = (mType) + +#define CONFIGURE_WINDOW_MESSAGE_SET_CLIENT_ID(pBuf, cid) \ + ((ConfigureWindowMessage *)(pBuf))->clientId = (clientId) + +#define CONFIGURE_WINDOW_MESSAGE_SET_WID(pBuf, windowId) \ + ((ConfigureWindowMessage *)(pBuf))->wid = (windowId) + +#define CONFIGURE_WINDOW_MESSAGE_SET_X(pBuf, xval) \ + ((ConfigureWindowMessage *)(pBuf))->x = (xval) + +#define CONFIGURE_WINDOW_MESSAGE_SET_Y(pBuf, yval) \ + ((ConfigureWindowMessage *)(pBuf))->y = (yval) + +#define CONFIGURE_WINDOW_MESSAGE_SET_WANDBORDER(pBuf, wandb) \ + ((ConfigureWindowMessage *)(pBuf))->wAndBorder = (wandb) + +#define CONFIGURE_WINDOW_MESSAGE_SET_HANDBORDER(pBuf, handb) \ + ((ConfigureWindowMessage *)(pBuf))->hAndBorder = (handb) + +#define CONFIGURE_WINDOW_MESSAGE_SET_SIBID(pBuf, siblingId) \ + ((ConfigureWindowMessage *)(pBuf))->sibid = (siblingId) + +typedef struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 clientId; + CARD32 wid; + CARD16 x; + CARD16 y; +} PositionWindowMessage; + +#define POSITION_WINDOW_MESSAGE_SIZE sizeof(PositionWindowMessage) + +#define POSITION_WINDOW_MESSAGE_SET_TYPE(pBuf, mType) \ + ((PositionWindowMessage *)(pBuf))->msgType = (mType) + +#define POSITION_WINDOW_MESSAGE_SET_CLIENT_ID(pBuf, cid) \ + ((PositionWindowMessage *)(pBuf))->clientId = (clientId) + +#define POSITION_WINDOW_MESSAGE_SET_WID(pBuf, windowId) \ + ((PositionWindowMessage *)(pBuf))->wid = (windowId) + +#define POSITION_WINDOW_MESSAGE_SET_X(pBuf, xval) \ + ((PositionWindowMessage *)(pBuf))->x = (xval) + +#define POSITION_WINDOW_MESSAGE_SET_Y(pBuf, yval) \ + ((PositionWindowMessage *)(pBuf))->y = (yval) + +typedef struct { + CARD8 msgType; + CARD8 decorated; + CARD16 pad; + CARD32 wid; +} WindowSetDecoratedMessage; + +#define WINDOW_SET_DECORATED_MESSAGE_SIZE sizeof(WindowSetDecoratedMessage) + +#define WINDOW_SET_DECORATED_MESSAGE_SET_TYPE(pBuf, mType) \ + ((WindowSetDecoratedMessage *)(pBuf))->msgType = (mType) + +#define WINDOW_SET_DECORATED_MESSAGE_SET_DECORATED(pBuf, decor) \ + ((WindowSetDecoratedMessage *)(pBuf))->decorated = (decor) + +#define WINDOW_SET_DECORATED_MESSAGE_SET_WID(pBuf, windowId) \ + ((WindowSetDecoratedMessage *)(pBuf))->wid = (windowId) + +typedef struct { + CARD8 msgType; + CARD8 pad; + CARD16 borderWidth; + CARD32 wid; +} WindowSetBorderWidthMessage; + +#define WINDOW_SET_BORDER_WIDTH_MESSAGE_SIZE sizeof(WindowSetBorderWidthMessage) + +#define WINDOW_SET_BORDER_WIDTH_MESSAGE_SET_TYPE(pBuf, mType) \ + ((WindowSetBorderWidthMessage *)(pBuf))->msgType = (mType) + +#define WINDOW_SET_BORDER_WIDTH_MESSAGE_SET_BORDER_WIDTH(pBuf, bw) \ + ((WindowSetBorderWidthMessage *)(pBuf))->borderWidth = (bw) + +#define WINDOW_SET_BORDER_WIDTH_MESSAGE_SET_WID(pBuf, windowId) \ + ((WindowSetBorderWidthMessage *)(pBuf))->wid = (windowId) + +typedef struct { + CARD8 msgType; +} BeepMessage; + +#define BEEP_MESSAGE_SIZE sizeof(BeepMessage) + +#define BEEP_MESSAGE_SET_TYPE(pBuf, mType) \ + ((BeepMessage *)(pBuf))->msgType = (mType) + +#define DISPLAY_PIXELS_ENCODING_UNCODED 0 +#define DISPLAY_PIXELS_ENCODING_RLE24 1 + +/* +** Note: Don't use xRectangle because x and y are constrained +** to fit in shorts because they are clipped to the screen. +*/ + +typedef struct { + CARD16 x; + CARD16 y; + CARD16 width; + CARD16 height; + + /* How pixels which follow are encoded */ + CARD32 encodingType; + +} DirtyAreaRectRec, *DirtyAreaRectPtr; + +#define DIRTY_AREA_RECT_SIZE sizeof(DirtyAreaRectRec) + +typedef struct { + CARD8 msgType; + CARD8 pad; + CARD16 numDirty; + CARD32 wid; +} DisplayPixelsMessage; + +#define DISPLAY_PIXELS_MESSAGE_SIZE sizeof(DisplayPixelsMessage) + +#define DISPLAY_PIXELS_MESSAGE_SET_TYPE(pBuf, mType) \ + ((DisplayPixelsMessage *)(pBuf))->msgType = (mType) + +#define DISPLAY_PIXELS_MESSAGE_SET_NUM_DIRTY(pBuf, n) \ + ((DisplayPixelsMessage *)(pBuf))->numDirty = (n) + +#define DISPLAY_PIXELS_MESSAGE_SET_WID(pBuf, windowId) \ + ((DisplayPixelsMessage *)(pBuf))->wid = (windowId) + +typedef struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 wid; + CARD32 srcx; + CARD32 srcy; + CARD32 width; + CARD32 height; + CARD32 dstx; + CARD32 dsty; +} CopyAreaMessage; + +#define COPY_AREA_MESSAGE_SIZE sizeof(CopyAreaMessage) + +#define COPY_AREA_MESSAGE_SET_TYPE(pBuf, mType) \ + ((CopyAreaMessage *)(pBuf))->msgType = (mType) + +#define COPY_AREA_MESSAGE_SET_WID(pBuf, windowId) \ + ((CopyAreaMessage *)(pBuf))->wid = (windowId) + +#define COPY_AREA_MESSAGE_SET_SRCX(pBuf, sx) \ + ((CopyAreaMessage *)(pBuf))->srcx = (sx) + +#define COPY_AREA_MESSAGE_SET_SRCY(pBuf, sy) \ + ((CopyAreaMessage *)(pBuf))->srcy = (sy) + +#define COPY_AREA_MESSAGE_SET_WIDTH(pBuf, w) \ + ((CopyAreaMessage *)(pBuf))->width = (w) + +#define COPY_AREA_MESSAGE_SET_HEIGHT(pBuf, h) \ + ((CopyAreaMessage *)(pBuf))->height = (h) + +#define COPY_AREA_MESSAGE_SET_DSTX(pBuf, dx) \ + ((CopyAreaMessage *)(pBuf))->dstx = (dx) + +#define COPY_AREA_MESSAGE_SET_DSTY(pBuf, dy) \ + ((CopyAreaMessage *)(pBuf))->dsty = (dy) + +typedef struct controllerstatusmessage_struct { + CARD8 msgType; + CARD8 status; + CARD16 pad; + CARD32 clientId; +} ControllerStatusMessage; + +/* The attempt of the specified client to take control has been refused */ +#define CONTROLLER_STATUS_REFUSED 0 + +/* The specified client has lost control */ +#define CONTROLLER_STATUS_LOST 1 + +/* The specified client has gained control */ +#define CONTROLLER_STATUS_GAINED 2 + +#define CONTROLLER_STATUS_MESSAGE_SIZE sizeof(ControllerStatusMessage) + +#define CONTROLLER_STATUS_MESSAGE_SET_TYPE(pBuf, mType) \ + ((ControllerStatusMessage *)(pBuf))->msgType = (mType) + +#define CONTROLLER_STATUS_MESSAGE_SET_STATUS(pBuf, stat) \ + ((ControllerStatusMessage*)(pBuf))->status = (stat) + +#define CONTROLLER_STATUS_MESSAGE_SET_CLIENTID(pBuf, cid) \ + ((ControllerStatusMessage*)(pBuf))->clientId = (cid) + +typedef struct displaycursormessage_struct { + + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD16 width; + CARD16 height; + CARD16 xhot; + CARD16 yhot; + + /* Followed by (width * height) 32-bit pixels */ + +} DisplayCursorMessage; + +#define DISPLAY_CURSOR_MESSAGE_SIZE sizeof(DisplayCursorMessage) + +#define DISPLAY_CURSOR_MESSAGE_SET_TYPE(pBuf, mType) \ + ((DisplayCursorMessage *)(pBuf))->msgType = (mType) + +#define DISPLAY_CURSOR_MESSAGE_SET_WIDTH(pBuf, w) \ + ((DisplayCursorMessage *)(pBuf))->width = (w) + +#define DISPLAY_CURSOR_MESSAGE_SET_HEIGHT(pBuf, h) \ + ((DisplayCursorMessage *)(pBuf))->height = (h) + +#define DISPLAY_CURSOR_MESSAGE_SET_XHOT(pBuf, xh) \ + ((DisplayCursorMessage *)(pBuf))->xhot = (xh) + +#define DISPLAY_CURSOR_MESSAGE_SET_YHOT(pBuf, yh) \ + ((DisplayCursorMessage *)(pBuf))->yhot = (yh) + +typedef struct movecursormessage_struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 wid; + CARD32 x; + CARD32 y; +} MoveCursorMessage; + +#define MOVE_CURSOR_MESSAGE_SIZE sizeof(MoveCursorMessage) + +#define MOVE_CURSOR_MESSAGE_SET_TYPE(pBuf, mType) \ + ((MoveCursorMessage *)(pBuf))->msgType = (mType) + +#define MOVE_CURSOR_MESSAGE_SET_WID(pBuf, windowId) \ + ((MoveCursorMessage *)(pBuf))->wid = (windowId) + +#define MOVE_CURSOR_MESSAGE_SET_X(pBuf, cx) \ + ((MoveCursorMessage *)(pBuf))->x = (cx) + +#define MOVE_CURSOR_MESSAGE_SET_Y(pBuf, cy) \ + ((MoveCursorMessage *)(pBuf))->y = (cy) + +typedef struct showcursormessage_struct { + CARD8 msgType; + CARD8 show; +} ShowCursorMessage; + +#define SHOW_CURSOR_MESSAGE_SIZE sizeof(ShowCursorMessage) + +#define SHOW_CURSOR_MESSAGE_SET_TYPE(pBuf, mType) \ + ((ShowCursorMessage *)(pBuf))->msgType = (mType) + +#define SHOW_CURSOR_MESSAGE_SET_SHOW(pBuf, showit) \ + ((ShowCursorMessage *)(pBuf))->show = (showit) + +typedef struct welcomessage_struct { + CARD8 msgType; + CARD8 pad1; + CARD16 pad2; + CARD32 clientId; +} WelcomeMessage; + +#define WELCOME_MESSAGE_SIZE sizeof(WelcomeMessage) + +#define WELCOME_MESSAGE_SET_TYPE(pBuf, mType) \ + ((WelcomeMessage *)(pBuf))->msgType = (mType) + +#define WELCOME_MESSAGE_SET_CLIENT_ID(pBuf, cid) \ + ((WelcomeMessage *)(pBuf))->clientId = (cid) + +#endif /* PROTOCOL_H */ diff --git a/hw/vfb/remwin.h b/hw/vfb/remwin.h new file mode 100644 index 000000000..f545d25f5 --- /dev/null +++ b/hw/vfb/remwin.h @@ -0,0 +1,190 @@ + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#ifndef REMWIN_H +#define REMWIN_H + +#include "scrnintstr.h" +#include "regionstr.h" +#include "rwcomm.h" +#include "gcstruct.h" + +/* Don't send any pixel buffers larger than 16KB */ +#define PIXEL_BUF_MAX_NUM_BYTES (1024*16) +#define PIXEL_BUF_MAX_NUM_PIXELS (PIXEL_BUF_MAX_NUM_BYTES/4) + +/* +** The RLE algorithm used never creates more pixels than +** is in the original buffer, so the max number of pixels +** provides an upper bound on the maximum number of runs. +*/ +#define RLE_BUF_MAX_NUM_BYTES PIXEL_BUF_MAX_NUM_BYTES +#define RLE_BUF_MAX_NUM_PIXELS (RLE_BUF_MAX_NUM_BYTES/4) + +typedef struct remwin_scr_priv_rec { + RwcommPtr pComm; + OsTimerPtr outputTimer; + CloseScreenProcPtr CloseScreen; + ScreenWakeupHandlerProcPtr WakeupHandler; + CreateWindowProcPtr CreateWindow; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + DestroyWindowProcPtr DestroyWindow; + PositionWindowProcPtr PositionWindow; + ResizeWindowProcPtr ResizeWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + CreateGCProcPtr CreateGC; + DisplayCursorProcPtr DisplayCursor; + SetCursorPositionProcPtr SetCursorPosition; + + unsigned char *pPixelBuf; + unsigned char *pRleBuf; + + /* List of managed o(top-level, drawable) windows */ + WindowPtr pManagedWindows; + + /* + ** Which client currently has interactive control. + ** -1 indicates no one has control. + */ + int controller; + + /* Which pointer buttons the controller has pressed */ + int controllerButtonMask; + + /* The currently displayed cursor */ + CursorPtr pCursor; + + /* + ** The managed window the cursor is in. + ** NULL if cursor isn't shown + */ + WindowPtr pCursorWin; + + /* The cursor position (relative to pCursorWin) */ + int cursorX; + int cursorY; + + /* The window manager client */ + ClientPtr pWmClient; + + /* + ** When this is -1 window moves and resizes are programmatic. + ** (i.e. invoked by the application). When this is not -1 + ** window moves and resizes are being made by the user. + */ + int configuringClient; + + /* True when any windows may have unsent dirty pixels */ + Bool windowsAreDirty; + +} RemwinScreenPrivRec, *RemwinScreenPrivPtr; + +#define REMWIN_GET_SCRPRIV(pScreen) \ + ((RemwinScreenPrivPtr)((pScreen)->devPrivates[remwinScreenIndex].ptr)) + +#define REMWIN_GET_WINPRIV(pWin) \ + ((RemwinWindowPrivPtr)(pWin)->devPrivates[remwinWinIndex].ptr); + +/* DELETE: no longer used +#define REMWIN_SET_WINPRIV(pWin, pWinPriv) \ + (pWin)->devPrivates[remwinWinIndex].ptr = (pointer)pWinPriv; +*/ + +typedef struct remwin_window_priv_rec *RemwinWindowPrivPtr; + +typedef struct remwin_window_priv_rec { + + /* + ** The window has been dirtied. That is, there are updates to send + ** to the client. (One or both of the regions has been updated). + */ + Bool dirty; + + /* Whether the window has been mapped */ + Bool mapped; + + /* The area of the window that has been dirtied */ + RegionRec dirtyReg; + + /* The link to the next window (not winpriv!) */ + WindowPtr pWinNext; + +} RemwinWindowPrivRec; + +#define REMWIN_GET_GCPRIV(pGC) \ + ((RemwinGCPrivPtr)(pGC)->devPrivates[remwinGCIndex].ptr); + +/* DELETE: no longer used +#define REMWIN_SET_GCPRIV(pGC, pGCPriv) \ + (pWin)->devPrivates[remwinGCIndex].ptr = (pointer)pGCPriv; +*/ + +typedef struct remwin_gc_priv_rec *RemwinGCPrivPtr; + +typedef struct remwin_gc_priv_rec { + GCOps *wrapOps; /* wrapped ops */ + GCFuncs *wrapFuncs; /* wrapped funcs */ +} RemwinGCPrivRec; + +extern RemwinScreenPrivRec remwinScreenPriv; + +extern void rwoutTimerCreate (ScreenPtr pScreen); +extern void rwoutTimerDestroy (ScreenPtr pScreen); + +extern void rwinHandler (ScreenPtr pScreen); + +/* Maximum pixel output rate is 30 fps */ +#define MAX_OUTPUT_RATE 30.0 +#define TIMER_MS ((int)((1/MAX_OUTPUT_RATE) * 1000.0)) + +extern Bool rwoutInitScreen (ScreenPtr pScreen); + +extern void rwTakeControlInit (ScreenPtr pScreen); +extern void rwTakeControl (ScreenPtr pScreen, int clientId, Bool steal); + +extern int remwinScreenIndex; + +extern Bool rwoutSetWindowTitlesWrite (ScreenPtr pScreen, int strLen, char *buf); + +extern void rwoutBeep (int percent, DeviceIntPtr pDevice, + pointer ctrl, int unused); + +extern void rwoutSyncClientOnConnect (ScreenPtr pScreen, RwcommClientPtr pCommClient); + +extern Bool rlePixelsWrite (ScreenPtr pScreen, WindowPtr pWin, int x, int y, int w, int h); + +extern Bool vfbRemoteWindow; + +#endif /* REMWIN_H */ diff --git a/hw/vfb/rle.c b/hw/vfb/rle.c new file mode 100644 index 000000000..e8c81a0fb --- /dev/null +++ b/hw/vfb/rle.c @@ -0,0 +1,235 @@ +#undef VERBOSE + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +/* TODO: prune these */ +#include <unistd.h> +#include "regionstr.h" +#include "damage.h" +#include "windowstr.h" +#include "remwin.h" +#include "rwcomm.h" +#include "misc.h" +#include "protocol.h" +#include "cursorstr.h" +#include "servermd.h" +#include "rwcommsock.h" + +extern Bool rwRleVerifyPixels; + +#define RGB_MASK 0x00ffffff + +#define ROUNDUP(fval) (int)((fval)+1) + +#define MIN(a, b) (((a)>(b))?(b):(a)) + +#define MAX_COUNT 255 + +#define NEXT_PIXEL(pixel) { \ + if (linesLeftInChunk <= 0) { \ + /* End of chunk */ \ + (pixel) = -1; \ + /*ErrorF("y,x,ll at end of chunk = %d, %d, %d\n", y, x, linesLeftInChunk);*/ \ + } else {\ + (pixel) = *(pPixel++) & RGB_MASK; \ + /* Advance pointers */ \ + if (++x >= xLimit) { \ + y++; \ + linesLeftInChunk--; \ + pLine += w; \ + pPixel = pLine; \ + x = xStart;\ + } \ + } \ +} + +#ifdef VERBOSE + +static int maxVerboseRuns = 120; +static int numRunsOutput = 0; + +#define OUTPUT_PIXEL(count, pixel) { \ + /* \ + if (numRunsOutput++ < maxVerboseRuns) { \ + ErrorF("numRuns = %d, count = %d, pixel = 0x%x\n", numRunsOutput, count, pixel); \ + } \ + */ \ + if (pDst >= pDstLimit) { \ + FatalError("Buffer overflow, pDst = 0x%x, 0x%x\n", (int)pDst, (int)pDstLimit); \ + } \ + *pDst++ = ((count) << 24) | (pixel); \ + bytesInChunk += 4; \ +} +#else +#define OUTPUT_PIXEL(count, pixel) { \ + *pDst++ = ((count) << 24) | (pixel); \ + bytesInChunk += 4; \ +} +#endif /* VERBOSE */ + +Bool +rlePixelsWrite (ScreenPtr pScreen, WindowPtr pWin, int x, int y, int w, int h) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommPtr pComm = pScrPriv->pComm; + char buf[DIRTY_AREA_RECT_SIZE]; + DirtyAreaRectPtr pDirty = (DirtyAreaRectPtr) &buf[0]; + int *pSrc, *pDst, *pLine, *pPixel, *pChunkHeight, *pNumOutBytes; + int linesLeft, xStart, xLimit, chunkHeight; + int numChunks, linesLeftInChunk; + int count, a, b; + int bytesInChunk; + int i, n; + + /* TODO: for debug */ + int *pDstLimit; + + chunkHeight = RLE_BUF_MAX_NUM_PIXELS / w; + numChunks = ROUNDUP((float)h / chunkHeight); +#ifdef VERBOSE + ErrorF("chunkHeight = %d\n", chunkHeight); + ErrorF("numChunks = %d\n", numChunks); +#endif /* VERBOSE */ + + /* Prepare rectangle description */ + pDirty->x = x; + pDirty->y = y; + pDirty->width = w; + /* TODO: HACK: notify the client of verification via negative numChunks */ + if (rwRleVerifyPixels) { + pDirty->height = -numChunks; + } else { + pDirty->height = numChunks; + } + pDirty->encodingType = DISPLAY_PIXELS_ENCODING_RLE24; +#ifdef VERBOSE + ErrorF("x = %d\n", x); + ErrorF("y = %d\n", y); + ErrorF("y = %d\n", h); + ErrorF("w = %d\n", w); +#endif /* VERBOSE */ + + swaps(&pDirty->x, n); + swaps(&pDirty->y, n); + swaps(&pDirty->width, n); + swaps(&pDirty->height, n); + swapl(&pDirty->encodingType, a); + + /* Send it off */ + if (!RWCOMM_BUFFER_WRITE(pComm, buf, DIRTY_AREA_RECT_SIZE)) { + return FALSE; + } + + /* Lazy allocation of pixel buffer*/ + if (pScrPriv->pPixelBuf == NULL) { + pScrPriv->pPixelBuf = (unsigned char *) + xalloc(PIXEL_BUF_MAX_NUM_BYTES); + } + pSrc = (int *) pScrPriv->pPixelBuf; + + /* Lazy allocation of rle output buffer*/ + if (pScrPriv->pRleBuf == NULL) { + pScrPriv->pRleBuf = (unsigned char *) + xalloc(RLE_BUF_MAX_NUM_BYTES + 10); + } + + linesLeft = h; + xStart = x; + xLimit = x + w; + + pChunkHeight = (int *) buf; + for (i = 0; i < numChunks; i++) { + + /* ErrorF("Filling chunk %d\n", i); */ + + /* This is a fresh chunk; start at the beginning of the buffer */ + pDst = (int *) pScrPriv->pRleBuf; + pDstLimit = (int *) ((char *)pDst + RLE_BUF_MAX_NUM_BYTES + 10); + + /* Clamp chunk height and send it */ + chunkHeight = MIN(linesLeft, chunkHeight); + *pChunkHeight = chunkHeight; + swapl(pChunkHeight, n); + if (!RWCOMM_BUFFER_WRITE(pComm, buf, 4)) { + return FALSE; + } + + /* Fetch chunk from frame buffer */ + (*pScreen->GetImage)((DrawablePtr)pWin, x, y, w, chunkHeight, + ZPixmap, ~0, (char *) pSrc); + pLine = pSrc; + pPixel = pLine; + + linesLeftInChunk = chunkHeight; + bytesInChunk = 0; + count = 1; + NEXT_PIXEL(a); + NEXT_PIXEL(b); + + while (b >= 0) { + if (a == b) { + if (count == MAX_COUNT) { + OUTPUT_PIXEL(count, a); + count = 1; + } else { + count++; + } + } else { + OUTPUT_PIXEL(count, a); + a = b; + count = 1; + } + NEXT_PIXEL(b); + } + OUTPUT_PIXEL(count, a); + + /* + ** Now send the number of bytes in the chunk followed by + ** the chunk data. + */ + pNumOutBytes = (int *) buf; + *pNumOutBytes = bytesInChunk; + swapl(pNumOutBytes, n); + if (!RWCOMM_BUFFER_WRITE(pComm, buf, 4)) { + return FALSE; + } + if (!RWCOMM_BUFFER_WRITE(pComm, (char *)pScrPriv->pRleBuf, bytesInChunk)) { + return FALSE; + } + + linesLeft -= chunkHeight; + } + + return TRUE; +} diff --git a/hw/vfb/rwcomm.h b/hw/vfb/rwcomm.h new file mode 100644 index 000000000..f65c84f3b --- /dev/null +++ b/hw/vfb/rwcomm.h @@ -0,0 +1,98 @@ + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#ifndef RWCOMM_H +#define RWCOMM_H + +#define RWCOMM_DESTROY(pComm) \ + (pComm)->funcs.destroy(pComm) + +#define RWCOMM_CONNECT(pComm) \ + (pComm)->funcs.connect(pComm) + +#define RWCOMM_DISCONNECT(pComm) \ + (pComm)->funcs.disconnect(pComm) + +#define RWCOMM_IS_CONNECTED(pComm) \ + (pComm)->funcs.isConnected(pComm) + +#define RWCOMM_BUFFER_WRITE(pComm, pBuf, bufLen) \ + (pComm)->funcs.bufferWrite((pComm), (pBuf), (bufLen)) + +#define RWCOMM_BUFFER_WRITE_TO_CLIENT(pComm, clientId, pBuf, bufLen) \ + (pComm)->funcs.bufferWriteToClient((pComm), (clientId), (pBuf), (bufLen)) + +#define RWCOMM_NEXT_MESSAGE_TYPE_READ(pComm) \ + (pComm)->funcs.nextMessageTypeRead(pComm) + +#define RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf, readLen) \ + (pComm)->funcs.nextMessageBufferRead((pComm), (buf), (readLen)) + +#define RWCOMM_CLIENT_MESSAGE_POLL(pComm, pReadMask) \ + (pComm)->funcs.clientMessagePoll((pComm), (pReadmask)) + +typedef struct rwcomm_rec *RwcommPtr; + +typedef void (*RwcommFuncPtrDestroy)(RwcommPtr pComm); +typedef void (*RwcommFuncPtrConnect)(RwcommPtr pComm); +typedef void (*RwcommFuncPtrDisconnect)(RwcommPtr pComm); +typedef Bool (*RwcommFuncPtrIsConnected)(RwcommPtr pComm); +typedef Bool (*RwcommFuncPtrBufferWrite)(RwcommPtr pComm, + char *buf, int bufLen); +typedef Bool (*RwcommFuncPtrBufferWriteToClient)(RwcommPtr pComm, + int clientId, char *buf, int bufLen); +typedef int (*RwcommFuncPtrNextMessageTypeRead)(RwcommPtr pComm); +typedef int (*RwcommFuncPtrNextMessageBufferRead)(RwcommPtr pComm, + char *buf, int readLen); +typedef void (*RwcommFuncPtrClientMessagePoll)(RwcommPtr pComm, fd_set *pReadMask); + +typedef struct rwcomm_funcptr_rec { + RwcommFuncPtrDestroy destroy; + RwcommFuncPtrConnect connect; + RwcommFuncPtrDisconnect disconnect; + RwcommFuncPtrIsConnected isConnected; + RwcommFuncPtrBufferWrite bufferWrite; + RwcommFuncPtrBufferWriteToClient bufferWriteToClient; + RwcommFuncPtrNextMessageTypeRead nextMessageTypeRead; + RwcommFuncPtrNextMessageBufferRead nextMessageBufferRead; + RwcommFuncPtrClientMessagePoll clientMessagePoll; +} RwcommFuncPtrRec, *RwcommFuncPtrPtr; + +typedef struct rwcomm_rec { + RwcommFuncPtrRec funcs; +} RwcommRec; + +typedef pointer RwcommClientPtr; + +#endif /* RWCOMM_H */ diff --git a/hw/vfb/rwcommsock.c b/hw/vfb/rwcommsock.c new file mode 100644 index 000000000..dacb10702 --- /dev/null +++ b/hw/vfb/rwcommsock.c @@ -0,0 +1,457 @@ +#undef VERBOSE + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#include <unistd.h> +#include <errno.h> +#include <X11/Xproto.h> +#include "dix-config.h" +#include "remwin.h" +#include "rwcomm.h" +#include "rwcommsock.h" +#include "protocol.h" +#include "opaque.h" +#include <arpa/inet.h> +#include <fcntl.h> + +static void rwcommsockDisconnect (RwcommPtr pComm); +static int WriteFully (int sock, char *pbuf, int bufLen); +static int ReadFully (int sock, char *pbuf, int bufLen); + +/* +** Disconnect all activate connections and free the comm module. +*/ + +static void +rwcommsockDestroy (RwcommPtr pComm) +{ + rwcommsockDisconnect(pComm); + xfree(pComm); +} + +/* TODO: notyet +static Bool firstClient = TRUE; +*/ + +/* +** Called when a new client connection is received. +*/ + +static void +rwcommsockConnect (RwcommPtr pComm) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + ScreenPtr pScreen = pCommsock->pScreen; + + pCommsock->isConnected = TRUE; + + rwoutTimerCreate(pScreen); + + rwTakeControlInit(pScreen); + + // TODO: DS: clientptr is an opaque handle to the client's sessionid + rwoutSyncClientOnConnect(pScreen, NULL); + + /* TODO: notyet + if (firstClient) { + // By this time we know that composite has been enabled and + // it is safe to discard frame buffer memory + ErrorF("Discarding fb memory"); + ddxGiveUp(); + firstClient = FALSE; + } + */ +} + +/* +** Disconnect all connections. +*/ + +static void +rwcommsockDisconnect (RwcommPtr pComm) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + + FD_CLR(pCommsock->socket, &pCommsock->fdSetPoll); + RemoveEnabledDevice(pCommsock->socket); + close(pCommsock->socket); + + if (pCommsock->sockServer > 0) { + if (close(pCommsock->sockServer)) { + ErrorF("rwcommsockDisconnect failed\n"); + return; + } + } + + pCommsock->isConnected = FALSE; + rwoutTimerDestroy(pCommsock->pScreen); + + ErrorF("Client disconnected\n"); +} + +static Bool +rwcommsockIsConnected (RwcommPtr pComm) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + return pCommsock->isConnected; +} + +/* +** Broadcast buffer to all clients +*/ + +static Bool +rwcommsockBufferWrite (RwcommPtr pComm, char *pbuf, int bufLen) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + int ret; + + ret = WriteFully(pCommsock->socket, pbuf, bufLen); + if (ret < 0) { + ErrorF("rwcommsockBufferWrite: IO error\n"); + rwcommsockDestroy((RwcommPtr)pCommsock); + return FALSE; + } + +#ifdef VERBOSE + { int i; + + bufLen = (bufLen > 50) ? 50 : bufLen; + + ErrorF("Broadcast: "); + for (i = 0; i < bufLen; i++) { + ErrorF("0x%x ", ((int)buf[i]) & 0xff); + } + ErrorF("\n"); + } +#endif /* VERBOSE */ + + return TRUE; +} + +/* +** Unicast buffer to specified client. +*/ + +static Bool +rwcommsockBufferWriteToClient (RwcommPtr pComm, int clientId, char *buf, int bufLen) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + int ret; + + /* + ** Note: we can't do unicast in the socket implementation. We can + ** only do broadcast. So clients will need to ignore this if necessary. + */ + ret = WriteFully(pCommsock->socket, buf, bufLen); + if (ret <= 0) { + ErrorF("rwcommsockBufferWriteToClient: IO error\n"); + rwcommsockDestroy((RwcommPtr)pCommsock); + return FALSE; + } + +#ifdef VERBOSE + { int i; + + bufLen = (bufLen > 50) ? 50 : bufLen; + + ErrorF("Unicast to client %d: ", clientId); + for (i = 0; i < bufLen; i++) { + ErrorF("0x%x ", ((int)buf[i]) & 0xff); + } + ErrorF("\n"); + } +#endif /* VERBOSE */ + + return TRUE; +} + +static int +rwcommsockNextMessageTypeRead (RwcommPtr pComm) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + char msgType; + int ret; + + ret = ReadFully(pCommsock->socket, &msgType, 1); + if (ret <= 0) { + if (ret != 0) { + ErrorF("rwcommsockNextMessageTypeRead: IO error\n"); + } + rwcommsockDestroy((RwcommPtr)pCommsock); + return CLIENT_MESSAGE_TYPE_INVALID; + } + + return (int) msgType; +} + +static Bool +rwcommsockNextMessageBufferRead (RwcommPtr pComm, char *pbuf, int readLen) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + int ret; + + ret = ReadFully(pCommsock->socket, pbuf, readLen); + if (ret <= 0) { + if (ret != 0) { + ErrorF("rwcommsockNextMessageBufferRead: IO error\n"); + } + rwcommsockDestroy((RwcommPtr)pCommsock); + return FALSE; + } + + return TRUE; +} + +static void +rwcommsockClientMessagePoll (RwcommPtr pComm, fd_set *pReadMask) +{ + RwcommsockPtr pCommsock = (RwcommsockPtr) pComm; + int numFdsSet; + fd_set tempFds; + struct timeval waittime; + + memcpy((char *)&tempFds, (char *)&pCommsock->fdSetPoll, sizeof(fd_set)); + waittime.tv_usec = 0; + waittime.tv_sec = 0; + numFdsSet = select(pCommsock->fdMax + 1, &tempFds, NULL, NULL, &waittime); + if (numFdsSet <= 0) { + if (numFdsSet == 0) return; + if (errno != EINTR) { + ErrorF("rwcommsockClientMessagePoll: select error\n"); + } + return; + } + + /* + ** We only listen for a single connection. Only accept a new connection + ** if we aren't already connected. + */ + if (!pCommsock->isConnected && + pCommsock->sockServer != -1 && + FD_ISSET(pCommsock->sockServer, pReadMask)) { + + int newSocket; + struct sockaddr_in addrDummy; + socklen_t lenDummy = sizeof(struct sockaddr_in); + + if ((newSocket = accept(pCommsock->sockServer, + (struct sockaddr *)&addrDummy, &lenDummy)) < 0) { + perror("rwcommsockClientMessagePoll: accept"); + return; + } + + /* + if (fcntl(newSocket, F_SETFL, O_NONBLOCK) < 0) { + perror("rwcommsockClientMessagePoll: fcntl"); + close(newSocket); + return; + } + */ + + pCommsock->fdMax = (newSocket > pCommsock->fdMax) ? newSocket :pCommsock->fdMax; + FD_SET(newSocket, &pCommsock->fdSetPoll); + AddEnabledDevice(newSocket); + + pCommsock->socket = newSocket; + RWCOMM_CONNECT((RwcommPtr)pCommsock); + + ErrorF("New client connected\n"); + + numFdsSet--; + if (numFdsSet == 0) { + return; + } + } + + /* Call input handler when the socket has data */ + if (FD_ISSET(pCommsock->socket, pReadMask) && + FD_ISSET(pCommsock->socket, &pCommsock->fdSetPoll)) { + rwinHandler(pCommsock->pScreen); + } +} + +/* +** Create the comm module and accept connections. +*/ + +RwcommPtr +rwcommsockCreate (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommsockPtr pCommsock; + struct sockaddr_in sockAddr; + int val = 1; + + pCommsock = (RwcommsockPtr) xalloc(sizeof(RwcommsockRec)); + if (pCommsock == NULL) { + return NULL; + } + + pCommsock->pScreen = pScreen; + pCommsock->sockServer = -1; + pCommsock->isConnected = FALSE; + + pCommsock->funcs.destroy = rwcommsockDestroy; + pCommsock->funcs.connect = rwcommsockConnect; + pCommsock->funcs.disconnect = rwcommsockDisconnect; + pCommsock->funcs.isConnected = rwcommsockIsConnected; + pCommsock->funcs.bufferWrite = rwcommsockBufferWrite; + pCommsock->funcs.bufferWriteToClient = rwcommsockBufferWriteToClient; + pCommsock->funcs.nextMessageTypeRead = rwcommsockNextMessageTypeRead; + pCommsock->funcs.nextMessageBufferRead = rwcommsockNextMessageBufferRead; + pCommsock->funcs.clientMessagePoll = rwcommsockClientMessagePoll; + + pScrPriv->pComm = (RwcommPtr) pCommsock; + + memset(&sockAddr, 0, sizeof(sockAddr)); + sockAddr.sin_family = AF_INET; + sockAddr.sin_port = htons(RWCOMMSOCK_SERVER_PORT + atoi(display)); + sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + pCommsock->sockServer = socket(AF_INET, SOCK_STREAM, 0); + if (pCommsock->sockServer < 0) { + xfree(pCommsock); + return NULL; + } + + if (setsockopt(pCommsock->sockServer, SOL_SOCKET, SO_REUSEADDR, (char *)&val, 4) < 0) { + close(pCommsock->sockServer); + xfree(pCommsock); + return NULL; + } + + if (bind(pCommsock->sockServer, + (struct sockaddr *)&sockAddr, sizeof(struct sockaddr_in)) < 0) { + close(pCommsock->sockServer); + xfree(pCommsock); + return NULL; + } + + if (listen(pCommsock->sockServer, 1) < 0) { + close(pCommsock->sockServer); + xfree(pCommsock); + return NULL; + } + + FD_ZERO(&pCommsock->fdSetPoll); + FD_SET(pCommsock->sockServer, &pCommsock->fdSetPoll); + pCommsock->fdMax = pCommsock->sockServer; + AddEnabledDevice(pCommsock->sockServer); + + return (RwcommPtr)pCommsock; +} + +static int +ReadFully (int sock, char *pbuf, int bufLen) +{ + int bytes_read; + + errno = 0; + + bytes_read = read(sock, pbuf, bufLen); + while (bytes_read != bufLen) { + if (bytes_read > 0) { + bufLen -= bytes_read; + pbuf += bytes_read; + } else if (bytes_read == 0) { + /* Read failed because of end of file! */ + errno = EPIPE; + return -1; + } else if (errno == EWOULDBLOCK || + errno == EAGAIN) { + int ret; + fd_set r_mask; + + FD_ZERO(&r_mask); + for (;;) { + FD_SET(sock, &r_mask); + ret = select(sock + 1, &r_mask, NULL, NULL, NULL); + if (ret == -1 && + errno != EINTR) { + return -1; + } + if (ret <= 0) { + continue; + } + if (FD_ISSET(sock, &r_mask)) { + break; + } + } + errno = 0; + } else { + if (errno != EINTR) { + return -1; + } + } + bytes_read = read(sock, pbuf, bufLen); + } + + return bufLen; +} + +static int +WriteFully (int sock, char *pbuf, int bufLen) +{ + int todo = bufLen; + int ret; + + while (bufLen != 0) { + ret = write(sock, pbuf, todo); + if (ret >= 0) { + pbuf += ret; + bufLen -= ret; + todo = bufLen; + } else if (errno == EWOULDBLOCK || + errno == EAGAIN) { + int nfound; + fd_set w_mask; + + FD_ZERO(&w_mask); + for (;;) { + FD_SET(sock, &w_mask); + do { + nfound = select(sock + 1, NULL, &w_mask, NULL, NULL); + if (nfound < 0 && errno != EINTR) { + return -1; + } + } while (nfound <= 0); + } + } else if (errno != EINTR) { + return -1; + } + } + + return bufLen; +} diff --git a/hw/vfb/rwcommsock.h b/hw/vfb/rwcommsock.h new file mode 100644 index 000000000..0b89afa7c --- /dev/null +++ b/hw/vfb/rwcommsock.h @@ -0,0 +1,55 @@ + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#ifndef RWCOMMSOCK_H +#define RWCOMMSOCK_H + +/* TODO: rewrite: change this */ +#define RWCOMMSOCK_SERVER_PORT 5900 + +typedef struct rwcommsock_rec { + RwcommFuncPtrRec funcs; + ScreenPtr pScreen; + Bool isConnected; + fd_set fdSetPoll; + int fdMax; + int sockServer; + int socket; +} RwcommsockRec, *RwcommsockPtr; + +extern RwcommPtr rwcommsockCreate (ScreenPtr pScreen); +extern int ReadExact(int sock, char *buf, int len); +extern int WriteExact(int sock, char *buf, int len); + +#endif /* RWCOMMSOCK_H */ diff --git a/hw/vfb/rwin.c b/hw/vfb/rwin.c new file mode 100644 index 000000000..e946bba92 --- /dev/null +++ b/hw/vfb/rwin.c @@ -0,0 +1,1029 @@ +#undef VERBOSE + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +Copyright 1985, 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +******************************************************************/ + +#include "inputstr.h" +#define XK_MISCELLANY +#define XK_LATIN1 +#define XK_LATIN2 +#define XK_LATIN3 +#define XK_LATIN4 +#define XK_LATIN8 +#define XK_LATIN9 +#define XK_CYRILLIC +#define XK_GREEK +#define XK_ARMENIAN +#define XK_CAUCASUS +#define XK_VIETNAMESE +#define XK_XKB_KEYS +#include <X11/keysym.h> +#include "windowstr.h" +#include "remwin.h" +#include "protocol.h" +#include "lk201kbd.h" + +/* +** Accept the event if its client has been assigned control +** or if nobody has control. +*/ + +#define ACCEPT_EVENT(pScrPriv, clientId) \ + ((pScrPriv)->controller == clientId || \ + (pScrPriv)->controller == -1) + +/************************************************************************ +** Begin derived from libX11/KeyBind.c +*/ + +static void +UCSConvertCase(register unsigned code, + KeySym *lower, + KeySym *upper ) +{ + /* Case conversion for UCS, as in Unicode Data version 4.0.0 */ + /* NB: Only converts simple one-to-one mappings. */ + + /* Tables are used where they take less space than */ + /* the code to work out the mappings. Zero values mean */ + /* undefined code points. */ + + static unsigned short const IPAExt_upper_mapping[] = { /* part only */ + 0x0181, 0x0186, 0x0255, 0x0189, 0x018A, + 0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F, + 0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C, + 0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, + 0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287, + 0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F, + 0x0290, 0x0291, 0x01B7 + }; + + static unsigned short const LatinExtB_upper_mapping[] = { /* first part only */ + 0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187, + 0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F, + 0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197, + 0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x0220, 0x019F, + 0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7, + 0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF, + 0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7, + 0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7, + 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7, + 0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA + }; + + static unsigned short const LatinExtB_lower_mapping[] = { /* first part only */ + 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, + 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259, + 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, + 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275, + 0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x0280, 0x01A8, + 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0, + 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, + 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF, + 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, + 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC + }; + + static unsigned short const Greek_upper_mapping[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000, + 0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x0386, 0x0387, + 0x0388, 0x0389, 0x038A, 0x0000, 0x038C, 0x0000, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A, + 0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x0000, + 0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03D7, + 0x03D8, 0x03D8, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE, + 0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6, + 0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE, + 0x039A, 0x03A1, 0x03F9, 0x03F3, 0x03F4, 0x0395, 0x03F6, 0x03F7, + 0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x0000, 0x0000, 0x0000, 0x0000 + }; + + static unsigned short const Greek_lower_mapping[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000, + 0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x03AC, 0x0387, + 0x03AD, 0x03AE, 0x03AF, 0x0000, 0x03CC, 0x0000, 0x03CD, 0x03CE, + 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x0000, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000, + 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, + 0x03D9, 0x03D9, 0x03DB, 0x03DB, 0x03DD, 0x03DD, 0x03DF, 0x03DF, + 0x03E1, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, + 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF, + 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03B8, 0x03F5, 0x03F6, 0x03F8, + 0x03F8, 0x03F2, 0x03FB, 0x03FB, 0x0000, 0x0000, 0x0000, 0x0000 + }; + + static unsigned short const GreekExt_lower_mapping[] = { + 0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07, + 0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07, + 0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000, + 0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000, + 0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27, + 0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27, + 0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37, + 0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37, + 0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000, + 0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000, + 0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57, + 0x0000, 0x1F51, 0x0000, 0x1F53, 0x0000, 0x1F55, 0x0000, 0x1F57, + 0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67, + 0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67, + 0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77, + 0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x0000, 0x0000, + 0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87, + 0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87, + 0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97, + 0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97, + 0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7, + 0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7, + 0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7, + 0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FB3, 0x1FBD, 0x1FBE, 0x1FBF, + 0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7, + 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FC3, 0x1FCD, 0x1FCE, 0x1FCF, + 0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7, + 0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF, + 0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7, + 0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF, + 0x0000, 0x0000, 0x1FF2, 0x1FF3, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7, + 0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FF3, 0x1FFD, 0x1FFE, 0x0000 + }; + + static unsigned short const GreekExt_upper_mapping[] = { + 0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F, + 0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F, + 0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000, + 0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000, + 0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F, + 0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F, + 0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F, + 0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F, + 0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000, + 0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000, + 0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F, + 0x0000, 0x1F59, 0x0000, 0x1F5B, 0x0000, 0x1F5D, 0x0000, 0x1F5F, + 0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F, + 0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F, + 0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB, + 0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x0000, 0x0000, + 0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F, + 0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F, + 0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F, + 0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F, + 0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF, + 0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF, + 0x1FB8, 0x1FB9, 0x1FB2, 0x1FBC, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7, + 0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x0399, 0x1FBF, + 0x1FC0, 0x1FC1, 0x1FC2, 0x1FCC, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7, + 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF, + 0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7, + 0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF, + 0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7, + 0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF, + 0x0000, 0x0000, 0x1FF2, 0x1FFC, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7, + 0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x0000 + }; + + *lower = code; + *upper = code; + + /* Basic Latin and Latin-1 Supplement, U+0000 to U+00FF */ + if (code <= 0x00ff) { + if (code >= 0x0041 && code <= 0x005a) /* A-Z */ + *lower += 0x20; + else if (code >= 0x0061 && code <= 0x007a) /* a-z */ + *upper -= 0x20; + else if ( (code >= 0x00c0 && code <= 0x00d6) || + (code >= 0x00d8 && code <= 0x00de) ) + *lower += 0x20; + else if ( (code >= 0x00e0 && code <= 0x00f6) || + (code >= 0x00f8 && code <= 0x00fe) ) + *upper -= 0x20; + else if (code == 0x00ff) /* y with diaeresis */ + *upper = 0x0178; + else if (code == 0x00b5) /* micro sign */ + *upper = 0x039c; + return; + } + + /* Latin Extended-A, U+0100 to U+017F */ + if (code >= 0x0100 && code <= 0x017f) { + if ( (code >= 0x0100 && code <= 0x012f) || + (code >= 0x0132 && code <= 0x0137) || + (code >= 0x014a && code <= 0x0177) ) { + *upper = code & ~1; + *lower = code | 1; + } + else if ( (code >= 0x0139 && code <= 0x0148) || + (code >= 0x0179 && code <= 0x017e) ) { + if (code & 1) + *lower += 1; + else + *upper -= 1; + } + else if (code == 0x0130) + *lower = 0x0069; + else if (code == 0x0131) + *upper = 0x0049; + else if (code == 0x0178) + *lower = 0x00ff; + else if (code == 0x017f) + *upper = 0x0053; + return; + } + + /* Latin Extended-B, U+0180 to U+024F */ + if (code >= 0x0180 && code <= 0x024f) { + if (code >= 0x01cd && code <= 0x01dc) { + if (code & 1) + *lower += 1; + else + *upper -= 1; + } + else if ( (code >= 0x01de && code <= 0x01ef) || + (code >= 0x01f4 && code <= 0x01f5) || + (code >= 0x01f8 && code <= 0x021f) || + (code >= 0x0222 && code <= 0x0233) ) { + *lower |= 1; + *upper &= ~1; + } + else if (code >= 0x0180 && code <= 0x01cc) { + *lower = LatinExtB_lower_mapping[code - 0x0180]; + *upper = LatinExtB_upper_mapping[code - 0x0180]; + } + else if (code == 0x01dd) + *upper = 0x018e; + else if (code == 0x01f1 || code == 0x01f2) { + *lower = 0x01f3; + *upper = 0x01f1; + } + else if (code == 0x01f3) + *upper = 0x01f1; + else if (code == 0x01f6) + *lower = 0x0195; + else if (code == 0x01f7) + *lower = 0x01bf; + else if (code == 0x0220) + *lower = 0x019e; + return; + } + + /* IPA Extensions, U+0250 to U+02AF */ + if (code >= 0x0253 && code <= 0x0292) { + *upper = IPAExt_upper_mapping[code - 0x0253]; + } + + /* Combining Diacritical Marks, U+0300 to U+036F */ + if (code == 0x0345) { + *upper = 0x0399; + } + + /* Greek and Coptic, U+0370 to U+03FF */ + if (code >= 0x0370 && code <= 0x03ff) { + *lower = Greek_lower_mapping[code - 0x0370]; + *upper = Greek_upper_mapping[code - 0x0370]; + if (*upper == 0) + *upper = code; + if (*lower == 0) + *lower = code; + } + + /* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */ + if ( (code >= 0x0400 && code <= 0x04ff) || + (code >= 0x0500 && code <= 0x052f) ) { + if (code >= 0x0400 && code <= 0x040f) + *lower += 0x50; + else if (code >= 0x0410 && code <= 0x042f) + *lower += 0x20; + else if (code >= 0x0430 && code <= 0x044f) + *upper -= 0x20; + else if (code >= 0x0450 && code <= 0x045f) + *upper -= 0x50; + else if ( (code >= 0x0460 && code <= 0x0481) || + (code >= 0x048a && code <= 0x04bf) || + (code >= 0x04d0 && code <= 0x04f5) || + (code >= 0x04f8 && code <= 0x04f9) || + (code >= 0x0500 && code <= 0x050f) ) { + *upper &= ~1; + *lower |= 1; + } + else if (code >= 0x04c1 && code <= 0x04ce) { + if (code & 1) + *lower += 1; + else + *upper -= 1; + } + } + + /* Armenian, U+0530 to U+058F */ + if (code >= 0x0530 && code <= 0x058f) { + if (code >= 0x0531 && code <= 0x0556) + *lower += 0x30; + else if (code >=0x0561 && code <= 0x0586) + *upper -= 0x30; + } + + /* Latin Extended Additional, U+1E00 to U+1EFF */ + if (code >= 0x1e00 && code <= 0x1eff) { + if ( (code >= 0x1e00 && code <= 0x1e95) || + (code >= 0x1ea0 && code <= 0x1ef9) ) { + *upper &= ~1; + *lower |= 1; + } + else if (code == 0x1e9b) + *upper = 0x1e60; + } + + /* Greek Extended, U+1F00 to U+1FFF */ + if (code >= 0x1f00 && code <= 0x1fff) { + *lower = GreekExt_lower_mapping[code - 0x1f00]; + *upper = GreekExt_upper_mapping[code - 0x1f00]; + if (*upper == 0) + *upper = code; + if (*lower == 0) + *lower = code; + } + + /* Letterlike Symbols, U+2100 to U+214F */ + if (code >= 0x2100 && code <= 0x214f) { + switch (code) { + case 0x2126: *lower = 0x03c9; break; + case 0x212a: *lower = 0x006b; break; + case 0x212b: *lower = 0x00e5; break; + } + } + /* Number Forms, U+2150 to U+218F */ + else if (code >= 0x2160 && code <= 0x216f) + *lower += 0x10; + else if (code >= 0x2170 && code <= 0x217f) + *upper -= 0x10; + /* Enclosed Alphanumerics, U+2460 to U+24FF */ + else if (code >= 0x24b6 && code <= 0x24cf) + *lower += 0x1a; + else if (code >= 0x24d0 && code <= 0x24e9) + *upper -= 0x1a; + /* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */ + else if (code >= 0xff21 && code <= 0xff3a) + *lower += 0x20; + else if (code >= 0xff41 && code <= 0xff5a) + *upper -= 0x20; + /* Deseret, U+10400 to U+104FF */ + else if (code >= 0x10400 && code <= 0x10427) + *lower += 0x28; + else if (code >= 0x10428 && code <= 0x1044f) + *upper -= 0x28; +} + +static void +ConvertCase(KeySym sym, KeySym *lower, KeySym *upper) +{ + /* Latin 1 keysym */ + if (sym < 0x100) { + UCSConvertCase(sym, lower, upper); + return; + } + + /* Unicode keysym */ + if ((sym & 0xff000000) == 0x01000000) { + UCSConvertCase((sym & 0x00ffffff), lower, upper); + *upper |= 0x01000000; + *lower |= 0x01000000; + return; + } + + /* Legacy keysym */ + + *lower = sym; + *upper = sym; + + switch(sym >> 8) { + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + case 0x13: /* Latin 9 */ + if (sym == XK_OE) + *lower = XK_oe; + else if (sym == XK_oe) + *upper = XK_OE; + else if (sym == XK_Ydiaeresis) + *lower = XK_ydiaeresis; + break; + } +} + +static KeySym +KeyCodeToKeySym (KeyCode keycode, int col) +{ + KeySymsPtr pks = &inputInfo.keyboard->key->curKeySyms; + register int per = pks->mapWidth; + register KeySym *syms; + KeySym lsym, usym; + + if ((col < 0) || ((col >= per) && (col > 3)) || + ((int)keycode < pks->minKeyCode) || ((int)keycode > pks->maxKeyCode)) + return NoSymbol; + + syms = &pks->map[(keycode - pks->minKeyCode) * per]; + if (col < 4) { + if (col > 1) { + while ((per > 2) && (syms[per - 1] == NoSymbol)) + per--; + if (per < 3) + col -= 2; + } + if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { + ConvertCase(syms[col&~1], &lsym, &usym); + if (!(col & 1)) + return lsym; + else if (usym == lsym) + return NoSymbol; + else + return usym; + } + } + return syms[col]; +} + +static KeyCode +KeysymToKeycode (KeySym ks) +{ + KeySymsPtr pks = &inputInfo.keyboard->key->curKeySyms; + register int i, j; + + for (j = 0; j < pks->mapWidth; j++) { + for (i = pks->minKeyCode; i <= pks->maxKeyCode; i++) { + if (KeyCodeToKeySym((KeyCode) i, j) == ks) + return i; + } + } + return 0; +} + +/* +** End derived from libX11/KeyBind.c +************************************************************************/ + +static void +injectKeyEvent (ScreenPtr pScreen, Bool isPressed, KeySym keySym) +{ + DeviceIntPtr pKeyboard = inputInfo.keyboard; + xEvent event; + + event.u.u.detail = KeysymToKeycode(keySym); + + if (isPressed) { + event.u.u.type = KeyPress; + } else { + event.u.u.type = KeyRelease; + } + event.u.keyButtonPointer.time = GetTimeInMillis(); + event.u.keyButtonPointer.state = 0; + + (*pKeyboard->public.processInputProc)(&event, pKeyboard, 1); +} + +static void +injectPointerEvent (ScreenPtr pScreen, int wid, int mask, int x, int y) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + DeviceIntPtr pPointer = inputInfo.pointer; + unsigned long when = GetTimeInMillis(); + xEvent event; + int button; + + /* + ** TODO: for now, absolutize event here. This isn't actually correct (because it + ** doesn't take into account window position changing after this point but before + ** picking, but it will suffice for now. + */ + { + WindowPtr pWin = LookupIDByType(wid, RT_WINDOW); + if (pWin == NULL) { + ErrorF("WARNING: cannot find pointer event window %d\n", wid); + return; + } + + /* + ErrorF("Pointer event on window %d, winrel coord xy = %d, %d\n", wid, x, y); + */ + + x += pWin->drawable.x; + y += pWin->drawable.y; + + /* + ErrorF("Pointer event on window %d, scrabs coord xy = %d, %d\n", wid, x, y); + */ + } + + + event.u.u.type = MotionNotify; + event.u.keyButtonPointer.rootX = x; + event.u.keyButtonPointer.rootY = y; + event.u.keyButtonPointer.time = when;; + (*inputInfo.pointer->public.processInputProc)(&event, inputInfo.pointer, 1); + + for (button = 0; button < 5; button++) { + int buttonMask = 1 << button; + int changeMask = mask ^ pScrPriv->controllerButtonMask; + if (changeMask & buttonMask) { + if (mask & buttonMask) { + event.u.u.type = ButtonPress; + event.u.keyButtonPointer.time = when; + event.u.u.detail = button + 1; + } else { + event.u.u.type = ButtonRelease; + event.u.keyButtonPointer.time = when; + event.u.u.detail = button + 1; + } + (*pPointer->public.processInputProc)(&event, pPointer, 1); + } + } + + pScrPriv->controllerButtonMask = mask; +} + +/* +** The window manager client is the client which has set +** SubstructureRedirect on the root window. We know this +** because the Appshare window manager does this. +*/ + +static ClientPtr +findWindowManagerClient (ScreenPtr pScreen) +{ + WindowPtr pRootWin = WindowTable[pScreen->myNum]; + OtherClients *pOthClient = wOtherClients(pRootWin); + + while (pOthClient != NULL) { + if ((pOthClient->mask & SubstructureRedirectMask)) { + return clients[CLIENT_ID(pOthClient->resource)]; + } + } + + FatalError("Remote Window: Cannot find window manager client"); +} + + +static void +moveWindow (WindowPtr pWin, int clientId, short x, short y) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + int vlist[2]; + int ret; + + if (pScrPriv->pWmClient == NULL) { + pScrPriv->pWmClient = findWindowManagerClient(pScreen); + } + + /* Inform clients that an interactive move is occuring */ + pScrPriv->configuringClient = clientId; + + vlist[0] = x; + vlist[1] = y; + ret = ConfigureWindow(pWin, (CWX | CWY), (XID *) vlist, pScrPriv->pWmClient); + if (ret != Success) { + ErrorF("Move window failed, error = %d\n", ret); + return; + } + + pScrPriv->configuringClient = -1; +} + +static void +resizeWindow (WindowPtr pWin, int clientId, int w, int h) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + int vlist[2]; + int ret; + + if (pScrPriv->pWmClient == NULL) { + pScrPriv->pWmClient = findWindowManagerClient(pScreen); + } + + /* Inform clients that an interactive resize is occuring */ + pScrPriv->configuringClient = clientId; + + vlist[0] = w; + vlist[1] = h; + ret = ConfigureWindow(pWin, (CWWidth | CWHeight), (XID *) vlist, pScrPriv->pWmClient); + if (ret != Success) { + ErrorF("Resize window failed, error = %d\n", ret); + return; + } + + pScrPriv->configuringClient = -1; +} + +static void +destroyWindow (WindowPtr pWin) +{ + if (pWin->parent != NULL) { + FreeResource(pWin->drawable.id, RT_NONE); + } +} + +/* +** Handle client input messages. +*/ + +void +rwinHandler (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommPtr pComm = pScrPriv->pComm; + int msgType; + int n; + + msgType = RWCOMM_NEXT_MESSAGE_TYPE_READ(pComm); + /*ErrorF("msgType = %d\n", msgType);*/ + + switch (msgType) { + + case CLIENT_MESSAGE_TYPE_KEY: { + char buf[KEY_EVENT_MESSAGE_SIZE]; + Bool isPressed; + KeySym keySym; + int clientId; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + KEY_EVENT_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + isPressed = KEY_EVENT_MESSAGE_GET_ISPRESSED(buf); + keySym = KEY_EVENT_MESSAGE_GET_KEYSYM(buf); + clientId = KEY_EVENT_MESSAGE_GET_CLIENTID(buf); + + swapl(&keySym, n); + swapl(&clientId, n); + +#ifdef VERBOSE + ErrorF("KeyEvent: isPressed = %d, keySym = %d, clientId = %d\n", + isPressed, (int)keySym, clientId); +#endif + + if (ACCEPT_EVENT(pScrPriv, clientId)) { + injectKeyEvent(pScreen, isPressed, keySym); + } + + break; + } + + case CLIENT_MESSAGE_TYPE_POINTER: { + char buf[POINTER_EVENT_MESSAGE_SIZE]; + int mask; + short x, y; + int wid; + int clientId; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + POINTER_EVENT_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + mask = POINTER_EVENT_MESSAGE_GET_MASK(buf); + x = POINTER_EVENT_MESSAGE_GET_X(buf); + y = POINTER_EVENT_MESSAGE_GET_Y(buf); + wid = POINTER_EVENT_MESSAGE_GET_WID(buf); + clientId = POINTER_EVENT_MESSAGE_GET_CLIENTID(buf); + + swaps(&x, n); + swaps(&y, n); + swapl(&wid, n); + swapl(&clientId, n); + +#ifdef VERBOSE + ErrorF("PointerEvent: mask = 0x%x, x,y = %d, %d, wid = %d, clientId = %d\n", + mask, x, y, wid, clientId); +#endif + + if (ACCEPT_EVENT(pScrPriv, clientId)) { + injectPointerEvent(pScreen, wid, mask, x, y); + } + + break; + } + + case CLIENT_MESSAGE_TYPE_TAKE_CONTROL: { + char buf[TAKE_CONTROL_MESSAGE_SIZE]; + int clientId; + Bool steal; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + TAKE_CONTROL_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + clientId = TAKE_CONTROL_MESSAGE_GET_CLIENTID(buf); + steal = TAKE_CONTROL_MESSAGE_GET_STEAL(buf); + + swapl(&clientId, n); + +#ifdef VERBOSE + ErrorF("TakeControl: clientId = %d, steal = %d\n", + clientId, steal); +#endif + + rwTakeControl(pScreen, clientId, steal); + + break; + } + + case CLIENT_MESSAGE_TYPE_SET_WINDOW_TITLES: { + char hdrBuf[SET_WINDOW_TITLES_MESSAGE_SIZE]; + char *buf; + short strLen; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, hdrBuf + 1, + SET_WINDOW_TITLES_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + strLen = SET_WINDOW_TITLES_MESSAGE_GET_STRLEN(hdrBuf); + + swaps(&strLen, n); + +#ifdef VERBOSE + ErrorF("SetWindowTitles: strLen = %d\n", strLen); +#endif + + buf = xalloc(strLen); + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf, strLen)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + if (!rwoutSetWindowTitlesWrite(pScreen, strLen, buf)) { + ErrorF("Could not send SetWindowTitles message\n"); + return; + } + + xfree(buf); + + break; + } + + case CLIENT_MESSAGE_TYPE_MOVE_WINDOW: { + char buf[MOVE_WINDOW_MESSAGE_SIZE]; + int clientId; + int wid; + int x, y; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + MOVE_WINDOW_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + clientId = MOVE_WINDOW_MESSAGE_GET_CLIENT_ID(buf); + wid = MOVE_WINDOW_MESSAGE_GET_WID(buf); + x = MOVE_WINDOW_MESSAGE_GET_X(buf); + y = MOVE_WINDOW_MESSAGE_GET_Y(buf); + + swapl(&clientId, n); + swapl(&wid, n); + swaps(&x, n); + swaps(&y, n); + +#ifdef VERBOSE + ErrorF("MoveWindow: clientId = %d, wid = %d, xy = %d, %d\n", + clientId, wid, x, y); +#endif + + WindowPtr pWin = LookupIDByType(wid, RT_WINDOW); + if (pWin == NULL) { + ErrorF("Could not find window to move, wid = %d\n", wid); + return; + } + + moveWindow(pWin, clientId, x, y); + break; + } + + case CLIENT_MESSAGE_TYPE_RESIZE_WINDOW: { + char buf[RESIZE_WINDOW_MESSAGE_SIZE]; + int clientId; + int wid; + int w, h; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + RESIZE_WINDOW_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + clientId = RESIZE_WINDOW_MESSAGE_GET_CLIENT_ID(buf); + wid = RESIZE_WINDOW_MESSAGE_GET_WID(buf); + w = RESIZE_WINDOW_MESSAGE_GET_WIDTH(buf); + h = RESIZE_WINDOW_MESSAGE_GET_HEIGHT(buf); + + swapl(&clientId, n); + swapl(&wid, n); + swaps(&w, n); + swaps(&h, n); + +#ifdef VERBOSE + ErrorF("ResizeWindow: clientId = %d, wid = %d, wh = %d, %d\n", + clientId, wid, w, h); +#endif + + WindowPtr pWin = LookupIDByType(wid, RT_WINDOW); + if (pWin == NULL) { + ErrorF("Could not find window to resize, wid = %d\n", wid); + return; + } + + resizeWindow(pWin, clientId, w, h); + break; + } + + case CLIENT_MESSAGE_TYPE_DESTROY_WINDOW: { + char buf[DESTROY_WINDOW_MESSAGE_SIZE]; + int wid; + + if (!RWCOMM_NEXT_MESSAGE_BUFFER_READ(pComm, buf + 1, + DESTROY_WINDOW_MESSAGE_SIZE -1)) { + ErrorF("Error reading next message buffer\n"); + return; + } + + wid = DESTROY_WINDOW_MESSAGE_GET_WID(buf); + swapl(&wid, n); + +#ifdef VERBOSE + ErrorF("DestroyWindow: wid = %d\n", wid); +#endif + + WindowPtr pWin = LookupIDByType(wid, RT_WINDOW); + if (pWin == NULL) { + ErrorF("Could not find window to destroy, wid = %d\n", wid); + return; + } + + destroyWindow(pWin); + break; + } + + /* TODO */ + case CLIENT_MESSAGE_TYPE_HELLO: + FatalError("rwinHandler: client message hello is not yet implemented\n"); + + case CLIENT_MESSAGE_TYPE_INVALID: + // Client has disconnected + ErrorF("Exitting.\n"); + exit(0); + break; + + default: + FatalError("rwinHandler: unknown message type %d\n", msgType); + + } +} + diff --git a/hw/vfb/takecontrol.c b/hw/vfb/takecontrol.c new file mode 100644 index 000000000..adbc5c999 --- /dev/null +++ b/hw/vfb/takecontrol.c @@ -0,0 +1,275 @@ + +/***************************************************************** + +Copyright 2007 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +Copyright 1985, 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +******************************************************************/ + +#include "inputstr.h" +#include "remwin.h" +#include "protocol.h" + +/* +** Each time we grant control to a new controller, we need +** to make sure that if control was granted while the previous +** controller had any keys or buttons down that we start out the +** keyboard state and button state with a clean state. + +*/ + +static void +initKeyboardState (ScreenPtr pScreen) +{ + DeviceIntPtr pKeyboard = inputInfo.keyboard; + unsigned long when = GetTimeInMillis(); + xEvent event; + int i, k; + + for (i = 0; i < DOWN_LENGTH; i++) { + if (pKeyboard->key->down[i] == 0) { + continue; + } + for (k = 0; k < 8; k++) { + int mask = 1 << k; + if (pKeyboard->key->down[i] & mask) { + event.u.u.type = KeyRelease; + event.u.u.detail = (i << 3) | k; + event.u.keyButtonPointer.time = when; + (*pKeyboard->public.processInputProc)(&event, pKeyboard, 1); + } + } + } +} + +static void +initPointerState (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + DeviceIntPtr pPointer = inputInfo.pointer; + xEvent event; + int button; + + for (button = 0; button < 5; button++) { + int mask = 1 << button; + if (pScrPriv->controllerButtonMask & mask) { + event.u.u.type = ButtonRelease; + event.u.u.detail = button + 1; + event.u.keyButtonPointer.time = GetTimeInMillis(); + (*pPointer->public.processInputProc)(&event, pPointer, 1); + } + } +} + +static void +rwGrantControl (ScreenPtr pScreen, int clientId) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + + /* Are we granting to someone who already has control? */ + if (pScrPriv->controller == clientId) { + return; + } + + pScrPriv->controller = clientId; + + initKeyboardState(pScreen); + initPointerState(pScreen); + + /* TODO: what else? */ +} + +/* +** Notify everyone that the current controller has lost control +*/ + +static Bool +notifyControlLost (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommPtr pComm = pScrPriv->pComm; + char buf[CONTROLLER_STATUS_MESSAGE_SIZE]; + int losingClient; + int n; + + if (!RWCOMM_IS_CONNECTED(pComm)) { + ErrorF("Connection lost.\n"); + return FALSE; + } + + losingClient = pScrPriv->controller; + swapl(&losingClient, n); + + CONTROLLER_STATUS_MESSAGE_SET_TYPE(buf, SERVER_MESSAGE_TYPE_CONTROLLER_STATUS); + CONTROLLER_STATUS_MESSAGE_SET_STATUS(buf, CONTROLLER_STATUS_LOST); + CONTROLLER_STATUS_MESSAGE_SET_CLIENTID(buf, losingClient); + + if (!RWCOMM_BUFFER_WRITE(pComm, buf, CONTROLLER_STATUS_MESSAGE_SIZE)) { + ErrorF("Write to connection failed.\n"); + return FALSE; + } + + return TRUE; +} + +/* +** Notify everyone that the current controller has gained control +*/ + +static Bool +notifyControlGained (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommPtr pComm = pScrPriv->pComm; + char buf[CONTROLLER_STATUS_MESSAGE_SIZE]; + int gainingClient; + int n; + + if (!RWCOMM_IS_CONNECTED(pComm)) { + ErrorF("Connection lost.\n"); + return FALSE; + } + + gainingClient = pScrPriv->controller; + swapl(&gainingClient, n); + + CONTROLLER_STATUS_MESSAGE_SET_TYPE(buf, SERVER_MESSAGE_TYPE_CONTROLLER_STATUS); + CONTROLLER_STATUS_MESSAGE_SET_STATUS(buf, CONTROLLER_STATUS_GAINED); + CONTROLLER_STATUS_MESSAGE_SET_CLIENTID(buf, gainingClient); + + if (!RWCOMM_BUFFER_WRITE(pComm, buf, CONTROLLER_STATUS_MESSAGE_SIZE)) { + ErrorF("Write to connection failed.\n"); + return FALSE; + } + + return TRUE; +} + + +/* +** Notify the given client that its request for control is refused. +*/ + +static Bool +notifyControlRefused (ScreenPtr pScreen, int clientId) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + RwcommPtr pComm = pScrPriv->pComm; + char buf[CONTROLLER_STATUS_MESSAGE_SIZE]; + int refusedClient; + int n; + + if (!RWCOMM_IS_CONNECTED(pComm)) { + ErrorF("Connection lost.\n"); + return FALSE; + } + + refusedClient = pScrPriv->controller; + swapl(&refusedClient, n); + + CONTROLLER_STATUS_MESSAGE_SET_TYPE(buf, SERVER_MESSAGE_TYPE_CONTROLLER_STATUS); + CONTROLLER_STATUS_MESSAGE_SET_STATUS(buf, CONTROLLER_STATUS_REFUSED); + CONTROLLER_STATUS_MESSAGE_SET_CLIENTID(buf, refusedClient); + + if (!RWCOMM_BUFFER_WRITE_TO_CLIENT(pComm, clientId, + buf, CONTROLLER_STATUS_MESSAGE_SIZE)) { + ErrorF("Write to connection failed.\n"); + return FALSE; + } + + return TRUE; +} + +void +rwTakeControl (ScreenPtr pScreen, int clientId, Bool steal) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + + /* If client already has control do nothing */ + if (pScrPriv->controller == clientId) { + return; + } + + if (pScrPriv->controller == -1 || steal) { + + /* Nobody has control or client is stealing -- Grant control */ + + if (!notifyControlLost(pScreen)) { + ErrorF("Cannot notify clients that control is lost.\n"); + return; + } + + rwGrantControl(pScreen, clientId); + + if (!notifyControlGained(pScreen)) { + ErrorF("Cannot notify clients that control is gained.\n"); + return; + } + + } else { + if (!notifyControlRefused(pScreen, clientId)) { + ErrorF("Cannot notify client %d that control is refused.\n", + clientId); + return; + } + } +} + +void +rwTakeControlInit (ScreenPtr pScreen) +{ + RemwinScreenPrivPtr pScrPriv = REMWIN_GET_SCRPRIV(pScreen); + + pScrPriv->controller = -1; + pScrPriv->controllerButtonMask = 0; + pScrPriv->configuringClient = -1; +} + |