xwin.c

来自「LinuxTools一书随书源代码」· C语言 代码 · 共 1,365 行 · 第 1/2 页

C
1,365
字号
/*   rdesktop: A Remote Desktop Protocol client.   User interface services - X Window System   Copyright (C) Matthew Chapman 1999-2002   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <X11/Xlib.h>#include <X11/Xutil.h>#include <time.h>#include <errno.h>#include "rdesktop.h"extern int width;extern int height;extern BOOL sendmotion;extern BOOL fullscreen;extern BOOL grab_keyboard;extern BOOL hide_decorations;extern char title[];BOOL enable_compose = False;BOOL focused;BOOL mouse_in_wnd;Display *display;static int x_socket;static Screen *screen;static Window wnd;static GC gc;static Visual *visual;static int depth;static int bpp;static XIM IM;static XIC IC;static XModifierKeymap *mod_map;static Cursor current_cursor;static Atom protocol_atom, kill_atom;/* endianness */static BOOL host_be;static BOOL xserver_be;/* software backing store */static BOOL ownbackstore;static Pixmap backstore;/* MWM decorations */#define MWM_HINTS_DECORATIONS   (1L << 1)#define PROP_MOTIF_WM_HINTS_ELEMENTS    5typedef struct{	uint32 flags;	uint32 functions;	uint32 decorations;	sint32 inputMode;	uint32 status;}PropMotifWmHints;#define FILL_RECTANGLE(x,y,cx,cy)\{ \	XFillRectangle(display, wnd, gc, x, y, cx, cy); \	if (ownbackstore) \		XFillRectangle(display, backstore, gc, x, y, cx, cy); \}#define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\{ \	XFillRectangle(display, ownbackstore ? backstore : wnd, gc, x, y, cx, cy); \}/* colour maps */BOOL owncolmap = False;static Colormap xcolmap;static uint32 *colmap;#define TRANSLATE(col)		( owncolmap ? col : translate_colour(colmap[col]) )#define SET_FOREGROUND(col)	XSetForeground(display, gc, TRANSLATE(col));#define SET_BACKGROUND(col)	XSetBackground(display, gc, TRANSLATE(col));static int rop2_map[] = {	GXclear,		/* 0 */	GXnor,			/* DPon */	GXandInverted,		/* DPna */	GXcopyInverted,		/* Pn */	GXandReverse,		/* PDna */	GXinvert,		/* Dn */	GXxor,			/* DPx */	GXnand,			/* DPan */	GXand,			/* DPa */	GXequiv,		/* DPxn */	GXnoop,			/* D */	GXorInverted,		/* DPno */	GXcopy,			/* P */	GXorReverse,		/* PDno */	GXor,			/* DPo */	GXset			/* 1 */};#define SET_FUNCTION(rop2)	{ if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); }#define RESET_FUNCTION(rop2)	{ if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }voidmwm_hide_decorations(void){	PropMotifWmHints motif_hints;	Atom hintsatom;	/* setup the property */	motif_hints.flags = MWM_HINTS_DECORATIONS;	motif_hints.decorations = 0;	/* get the atom for the property */	hintsatom = XInternAtom(display, "_MOTIF_WM_HINTS", False);	if (!hintsatom)	{		warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");		return;	}	XChangeProperty(display, wnd, hintsatom, hintsatom, 32, PropModeReplace,			(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);}static voidtranslate8(uint8 * data, uint8 * out, uint8 * end){	while (out < end)		*(out++) = (uint8) colmap[*(data++)];}static voidtranslate16(uint8 * data, uint16 * out, uint16 * end){	while (out < end)		*(out++) = (uint16) colmap[*(data++)];}/* little endian - conversion happens when colourmap is built */static voidtranslate24(uint8 * data, uint8 * out, uint8 * end){	uint32 value;	while (out < end)	{		value = colmap[*(data++)];		*(out++) = value;		*(out++) = value >> 8;		*(out++) = value >> 16;	}}static voidtranslate32(uint8 * data, uint32 * out, uint32 * end){	while (out < end)		*(out++) = colmap[*(data++)];}static uint8 *translate_image(int width, int height, uint8 * data){	int size = width * height * bpp / 8;	uint8 *out = xmalloc(size);	uint8 *end = out + size;	switch (bpp)	{		case 8:			translate8(data, out, end);			break;		case 16:			translate16(data, (uint16 *) out, (uint16 *) end);			break;		case 24:			translate24(data, out, end);			break;		case 32:			translate32(data, (uint32 *) out, (uint32 *) end);			break;	}	return out;}#define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }#define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }#define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \			x = (x << 16) | (x >> 16); }static uint32translate_colour(uint32 colour){	switch (bpp)	{		case 16:			if (host_be != xserver_be)				BSWAP16(colour);			break;		case 24:			if (xserver_be)				BSWAP24(colour);			break;		case 32:			if (host_be != xserver_be)				BSWAP32(colour);			break;	}	return colour;}BOOLget_key_state(unsigned int state, uint32 keysym){	int modifierpos, key, keysymMask = 0;	int offset;	KeyCode keycode = XKeysymToKeycode(display, keysym);	if (keycode == NoSymbol)		return False;	for (modifierpos = 0; modifierpos < 8; modifierpos++)	{		offset = mod_map->max_keypermod * modifierpos;		for (key = 0; key < mod_map->max_keypermod; key++)		{			if (mod_map->modifiermap[offset + key] == keycode)				keysymMask |= 1 << modifierpos;		}	}	return (state & keysymMask) ? True : False;}BOOLui_init(void){	XPixmapFormatValues *pfm;	uint16 test;	int i;	display = XOpenDisplay(NULL);	if (display == NULL)	{		error("Failed to open display: %s\n", XDisplayName(NULL));		return False;	}	x_socket = ConnectionNumber(display);	screen = DefaultScreenOfDisplay(display);	visual = DefaultVisualOfScreen(screen);	depth = DefaultDepthOfScreen(screen);	pfm = XListPixmapFormats(display, &i);	if (pfm != NULL)	{		/* Use maximum bpp for this depth - this is generally		   desirable, e.g. 24 bits->32 bits. */		while (i--)		{			if ((pfm[i].depth == depth) && (pfm[i].bits_per_pixel > bpp))			{				bpp = pfm[i].bits_per_pixel;			}		}		XFree(pfm);	}	if (bpp < 8)	{		error("Less than 8 bpp not currently supported.\n");		XCloseDisplay(display);		return False;	}	if (owncolmap != True)	{		xcolmap = DefaultColormapOfScreen(screen);		if (depth <= 8)			warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");	}	gc = XCreateGC(display, RootWindowOfScreen(screen), 0, NULL);	if (DoesBackingStore(screen) != Always)		ownbackstore = True;	test = 1;	host_be = !(BOOL) (*(uint8 *) (&test));	xserver_be = (ImageByteOrder(display) == MSBFirst);	if ((width == 0) || (height == 0))	{		/* Fetch geometry from _NET_WORKAREA */		uint32 x, y, cx, cy;		if (get_current_workarea(&x, &y, &cx, &cy) == 0)		{			width = cx;			height = cy;		}		else		{			warning("Failed to get workarea: probably your window manager does not support extended hints\n");			width = 800;			height = 600;		}	}	if (fullscreen)	{		width = WidthOfScreen(screen);		height = HeightOfScreen(screen);	}	/* make sure width is a multiple of 4 */	width = (width + 3) & ~3;	if (ownbackstore)	{		backstore =			XCreatePixmap(display, RootWindowOfScreen(screen), width, height, depth);		/* clear to prevent rubbish being exposed at startup */		XSetForeground(display, gc, BlackPixelOfScreen(screen));		XFillRectangle(display, backstore, gc, 0, 0, width, height);	}	mod_map = XGetModifierMapping(display);	if (enable_compose)		IM = XOpenIM(display, NULL, NULL, NULL);	xkeymap_init();	return True;}voidui_deinit(void){	if (IM != NULL)		XCloseIM(IM);	XFreeModifiermap(mod_map);	if (ownbackstore)		XFreePixmap(display, backstore);	XFreeGC(display, gc);	XCloseDisplay(display);	display = NULL;}BOOLui_create_window(void){	XSetWindowAttributes attribs;	XClassHint *classhints;	XSizeHints *sizehints;	int wndwidth, wndheight;	long input_mask, ic_input_mask;	XEvent xevent;	wndwidth = fullscreen ? WidthOfScreen(screen) : width;	wndheight = fullscreen ? HeightOfScreen(screen) : height;	attribs.background_pixel = BlackPixelOfScreen(screen);	attribs.backing_store = ownbackstore ? NotUseful : Always;	attribs.override_redirect = fullscreen;	wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, wndwidth, wndheight,			    0, CopyFromParent, InputOutput, CopyFromParent,			    CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);	XStoreName(display, wnd, title);	if (hide_decorations)		mwm_hide_decorations();	classhints = XAllocClassHint();	if (classhints != NULL)	{		classhints->res_name = classhints->res_class = "rdesktop";		XSetClassHint(display, wnd, classhints);		XFree(classhints);	}	sizehints = XAllocSizeHints();	if (sizehints)	{		sizehints->flags = PMinSize | PMaxSize;		sizehints->min_width = sizehints->max_width = width;		sizehints->min_height = sizehints->max_height = height;		XSetWMNormalHints(display, wnd, sizehints);		XFree(sizehints);	}	input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |		VisibilityChangeMask | FocusChangeMask;	if (sendmotion)		input_mask |= PointerMotionMask;	if (ownbackstore)		input_mask |= ExposureMask;	if (fullscreen || grab_keyboard)		input_mask |= EnterWindowMask;	if (grab_keyboard)		input_mask |= LeaveWindowMask;	if (IM != NULL)	{		IC = XCreateIC(IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),			       XNClientWindow, wnd, XNFocusWindow, wnd, NULL);		if ((IC != NULL)		    && (XGetICValues(IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))			input_mask |= ic_input_mask;	}	XSelectInput(display, wnd, input_mask);	XMapWindow(display, wnd);	/* wait for VisibilityNotify */	do	{		XMaskEvent(display, VisibilityChangeMask, &xevent);	}	while (xevent.type != VisibilityNotify);	focused = False;	mouse_in_wnd = False;	/* handle the WM_DELETE_WINDOW protocol */	protocol_atom = XInternAtom(display, "WM_PROTOCOLS", True);	kill_atom = XInternAtom(display, "WM_DELETE_WINDOW", True);	XSetWMProtocols(display, wnd, &kill_atom, 1);	return True;}voidui_destroy_window(void){	if (IC != NULL)		XDestroyIC(IC);	XDestroyWindow(display, wnd);}voidxwin_toggle_fullscreen(void){	Pixmap contents = 0;	if (!ownbackstore)	{		/* need to save contents of window */		contents = XCreatePixmap(display, wnd, width, height, depth);		XCopyArea(display, wnd, contents, gc, 0, 0, width, height, 0, 0);	}	ui_destroy_window();	fullscreen = !fullscreen;	ui_create_window();	XDefineCursor(display, wnd, current_cursor);	if (!ownbackstore)	{		XCopyArea(display, contents, wnd, gc, 0, 0, width, height, 0, 0);		XFreePixmap(display, contents);	}}/* Process all events in Xlib queue    Returns 0 after user quit, 1 otherwise */static intxwin_process_events(void){	XEvent xevent;	KeySym keysym;	uint16 button, flags;	uint32 ev_time;	key_translation tr;	char str[256];	Status status;	unsigned int state;	Window wdummy;	int dummy;	while (XPending(display) > 0)	{		XNextEvent(display, &xevent);		if ((IC != NULL) && (XFilterEvent(&xevent, None) == True))		{			DEBUG_KBD(("Filtering event\n"));			continue;		}		flags = 0;		switch (xevent.type)		{			case ClientMessage:				/* the window manager told us to quit */				if ((xevent.xclient.message_type == protocol_atom)				    && (xevent.xclient.data.l[0] == kill_atom))					/* Quit */					return 0;				break;			case KeyPress:				if (IC != NULL)					/* Multi_key compatible version */				{					XmbLookupString(IC,							(XKeyPressedEvent *) &							xevent, str, sizeof(str), &keysym, &status);					if (!((status == XLookupKeySym) || (status == XLookupBoth)))					{						error("XmbLookupString failed with status 0x%x\n",						      status);						break;					}				}				else				{					/* Plain old XLookupString */					DEBUG_KBD(("\nNo input context, using XLookupString\n"));					XLookupString((XKeyEvent *) & xevent,						      str, sizeof(str), &keysym, NULL);				}				DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,					   get_ksname(keysym)));				ev_time = time(NULL);				if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))					break;				tr = xkeymap_translate_key(keysym,							   xevent.xkey.keycode, xevent.xkey.state);				if (tr.scancode == 0)					break;				ensure_remote_modifiers(ev_time, tr);				rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);				break;			case KeyRelease:				XLookupString((XKeyEvent *) & xevent, str,					      sizeof(str), &keysym, NULL);				DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,					   get_ksname(keysym)));				ev_time = time(NULL);				if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))					break;				tr = xkeymap_translate_key(keysym,							   xevent.xkey.keycode, xevent.xkey.state);				if (tr.scancode == 0)					break;				rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);				break;			case ButtonPress:				flags = MOUSE_FLAG_DOWN;				/* fall through */			case ButtonRelease:				button = xkeymap_translate_button(xevent.xbutton.button);				if (button == 0)					break;				rdp_send_input(time(NULL), RDP_INPUT_MOUSE,					       flags | button, xevent.xbutton.x, xevent.xbutton.y);				break;			case MotionNotify:				if (fullscreen && !focused)					XSetInputFocus(display, wnd, RevertToPointerRoot,						       CurrentTime);				rdp_send_input(time(NULL), RDP_INPUT_MOUSE,					       MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);				break;			case FocusIn:				if (xevent.xfocus.mode == NotifyGrab)					break;				focused = True;				XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy,					      &dummy, &dummy, &state);				reset_modifier_keys(state);				if (grab_keyboard && mouse_in_wnd)					XGrabKeyboard(display, wnd, True,						      GrabModeAsync, GrabModeAsync, CurrentTime);				break;			case FocusOut:				if (xevent.xfocus.mode == NotifyUngrab)					break;				focused = False;				if (xevent.xfocus.mode == NotifyWhileGrabbed)					XUngrabKeyboard(display, CurrentTime);				break;			case EnterNotify:				/* we only register for this event when in fullscreen mode */				/* or grab_keyboard */				mouse_in_wnd = True;				if (fullscreen)				{					XSetInputFocus(display, wnd, RevertToPointerRoot,						       CurrentTime);					break;				}				if (focused)					XGrabKeyboard(display, wnd, True,						      GrabModeAsync, GrabModeAsync, CurrentTime);				break;			case LeaveNotify:				/* we only register for this event when grab_keyboard */				mouse_in_wnd = False;				XUngrabKeyboard(display, CurrentTime);				break;			case Expose:				XCopyArea(display, backstore, wnd, gc,					  xevent.xexpose.x, xevent.xexpose.y,					  xevent.xexpose.width,					  xevent.xexpose.height,					  xevent.xexpose.x, xevent.xexpose.y);				break;			case MappingNotify:				/* Refresh keyboard mapping if it has changed. This is important for				   Xvnc, since it allocates keycodes dynamically */				if (xevent.xmapping.request == MappingKeyboard				    || xevent.xmapping.request == MappingModifier)					XRefreshKeyboardMapping(&xevent.xmapping);				if (xevent.xmapping.request == MappingModifier)				{					XFreeModifiermap(mod_map);					mod_map = XGetModifierMapping(display);				}				break;		}	}	/* Keep going */	return 1;

⌨️ 快捷键说明

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