rdesktop/xwin.c
Matt Chapman cd9b5a8761 Major commit of work from laptop - done in various free moments.
Implemented encryption layer and some basic licensing negotiation.
Reorganised code somewhat. While this is not quite as clean, it is
a lot faster - our parser speed was becoming a bottle-neck.


git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@9 423420c4-83ab-492f-b58f-81f9feb106b5
2000-08-15 10:23:24 +00:00

554 lines
12 KiB
C

/*
rdesktop: A Remote Desktop Protocol client.
User interface services - X-Windows
Copyright (C) Matthew Chapman 1999-2000
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 <time.h>
#include "rdesktop.h"
extern int width;
extern int height;
extern BOOL motion;
static Display *display;
static Window wnd;
static GC gc;
static Visual *visual;
static XIM IM;
BOOL ui_create_window(char *title)
{
Screen *screen;
XSetWindowAttributes attribs;
unsigned long input_mask;
int i;
display = XOpenDisplay(NULL);
if (display == NULL)
return False;
/* Check the screen supports 8-bit depth. */
screen = DefaultScreenOfDisplay(display);
for (i = 0; i < screen->ndepths; i++)
if (screen->depths[i].depth == 8)
break;
if (i >= screen->ndepths)
{
ERROR("8-bit depth required (in this version).\n");
XCloseDisplay(display);
return False;
}
visual = DefaultVisual(display, DefaultScreen(display));
attribs.background_pixel = BlackPixel(display, DefaultScreen(display));
attribs.backing_store = Always;
wnd = XCreateWindow(display, DefaultRootWindow(display),
0, 0, width, height, 0, 8, InputOutput, visual,
CWBackingStore | CWBackPixel, &attribs);
XStoreName(display, wnd, title);
XMapWindow(display, wnd);
input_mask = KeyPressMask | KeyReleaseMask;
input_mask |= ButtonPressMask | ButtonReleaseMask;
if (motion)
input_mask |= PointerMotionMask;
XSelectInput(display, wnd, input_mask);
gc = XCreateGC(display, wnd, 0, NULL);
IM = XOpenIM(display, NULL, NULL, NULL);
return True;
}
void ui_destroy_window()
{
XCloseIM(IM);
XFreeGC(display, gc);
XDestroyWindow(display, wnd);
XCloseDisplay(display);
}
static uint8 xwin_translate_key(unsigned long key)
{
DEBUG("KEY(code=0x%lx)\n", key);
if ((key > 8) && (key <= 0x60))
return (key - 8);
switch (key)
{
case 0x62: /* left arrow */
return 0x48;
case 0x64: /* up arrow */
return 0x4b;
case 0x66: /* down arrow */
return 0x4d;
case 0x68: /* right arrow */
return 0x50;
case 0x73: /* Windows key */
DEBUG("CHECKPOINT\n");
}
return 0;
}
static uint16 xwin_translate_mouse(unsigned long button)
{
switch (button)
{
case Button1: /* left */
return MOUSE_FLAG_BUTTON1;
case Button2: /* middle */
return MOUSE_FLAG_BUTTON3;
case Button3: /* right */
return MOUSE_FLAG_BUTTON2;
}
return 0;
}
void ui_process_events()
{
XEvent event;
uint8 scancode;
uint16 button;
uint32 ev_time;
if (display == NULL)
return;
while (XCheckWindowEvent(display, wnd, 0xffffffff, &event))
{
ev_time = time(NULL);
switch (event.type)
{
case KeyPress:
scancode = xwin_translate_key(event.xkey.keycode);
if (scancode == 0)
break;
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0,
scancode, 0);
break;
case KeyRelease:
scancode = xwin_translate_key(event.xkey.keycode);
if (scancode == 0)
break;
rdp_send_input(ev_time, RDP_INPUT_SCANCODE,
KBD_FLAG_DOWN | KBD_FLAG_UP,
scancode, 0);
break;
case ButtonPress:
button = xwin_translate_mouse(event.xbutton.button);
if (button == 0)
break;
rdp_send_input(ev_time, RDP_INPUT_MOUSE,
button | MOUSE_FLAG_DOWN,
event.xbutton.x,
event.xbutton.y);
break;
case ButtonRelease:
button = xwin_translate_mouse(event.xbutton.button);
if (button == 0)
break;
rdp_send_input(ev_time, RDP_INPUT_MOUSE,
button,
event.xbutton.x,
event.xbutton.y);
break;
case MotionNotify:
rdp_send_input(ev_time, RDP_INPUT_MOUSE,
MOUSE_FLAG_MOVE,
event.xmotion.x,
event.xmotion.y);
}
}
}
void ui_move_pointer(int x, int y)
{
XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);
}
HBITMAP ui_create_bitmap(int width, int height, uint8 *data)
{
XImage *image;
Pixmap bitmap;
bitmap = XCreatePixmap(display, wnd, width, height, 8);
image = XCreateImage(display, visual, 8, ZPixmap, 0,
data, width, height, 8, width);
XSetFunction(display, gc, GXcopy);
XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
XFree(image);
return (HBITMAP)bitmap;
}
void ui_paint_bitmap(int x, int y, int cx, int cy,
int width, int height, uint8 *data)
{
XImage *image;
image = XCreateImage(display, visual, 8, ZPixmap, 0,
data, width, height, 8, width);
XSetFunction(display, gc, GXcopy);
XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
XFree(image);
}
void ui_destroy_bitmap(HBITMAP bmp)
{
XFreePixmap(display, (Pixmap)bmp);
}
HGLYPH ui_create_glyph(int width, int height, uint8 *data)
{
XImage *image;
Pixmap bitmap;
int scanline;
GC gc;
scanline = (width + 7) / 8;
bitmap = XCreatePixmap(display, wnd, width, height, 1);
gc = XCreateGC(display, bitmap, 0, NULL);
image = XCreateImage(display, visual, 1, ZPixmap, 0,
data, width, height, 8, scanline);
XSetFunction(display, gc, GXcopy);
XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
XFree(image);
XFreeGC(display, gc);
return (HGLYPH)bitmap;
}
void ui_destroy_glyph(HGLYPH glyph)
{
XFreePixmap(display, (Pixmap)glyph);
}
HCOLOURMAP ui_create_colourmap(COLOURMAP *colours)
{
COLOURENTRY *entry;
XColor *xcolours, *xentry;
Colormap map;
int i, ncolours = colours->ncolours;
xcolours = xmalloc(sizeof(XColor) * ncolours);
for (i = 0; i < ncolours; i++)
{
entry = &colours->colours[i];
xentry = &xcolours[i];
xentry->pixel = i;
xentry->red = entry->red << 8;
xentry->blue = entry->blue << 8;
xentry->green = entry->green << 8;
xentry->flags = DoRed | DoBlue | DoGreen;
}
map = XCreateColormap(display, wnd, visual, AllocAll);
XStoreColors(display, map, xcolours, ncolours);
xfree(xcolours);
return (HCOLOURMAP)map;
}
void ui_destroy_colourmap(HCOLOURMAP map)
{
XFreeColormap(display, (Colormap)map);
}
void ui_set_colourmap(HCOLOURMAP map)
{
XSetWindowColormap(display, wnd, (Colormap)map);
}
void ui_set_clip(int x, int y, int cx, int cy)
{
XRectangle rect;
rect.x = x;
rect.y = y;
rect.width = cx;
rect.height = cy;
XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
}
void ui_reset_clip()
{
XRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
}
void ui_bell()
{
XBell(display, 0);
}
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 */
};
static void xwin_set_function(uint8 rop2)
{
XSetFunction(display, gc, rop2_map[rop2]);
}
void ui_destblt(uint8 opcode,
/* dest */ int x, int y, int cx, int cy)
{
xwin_set_function(opcode);
XFillRectangle(display, wnd, gc, x, y, cx, cy);
}
void ui_patblt(uint8 opcode,
/* dest */ int x, int y, int cx, int cy,
/* brush */ BRUSH *brush, int bgcolour, int fgcolour)
{
Display *dpy = display;
Pixmap fill;
xwin_set_function(opcode);
switch (brush->style)
{
case 0: /* Solid */
XSetForeground(dpy, gc, fgcolour);
XFillRectangle(dpy, wnd, gc, x, y, cx, cy);
break;
case 3: /* Pattern */
fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);
XSetForeground(dpy, gc, fgcolour);
XSetBackground(dpy, gc, bgcolour);
XSetFillStyle(dpy, gc, FillOpaqueStippled);
XSetStipple(dpy, gc, fill);
XFillRectangle(dpy, wnd, gc, x, y, cx, cy);
XSetFillStyle(dpy, gc, FillSolid);
ui_destroy_glyph((HGLYPH)fill);
break;
default:
NOTIMP("brush %d\n", brush->style);
}
}
void ui_screenblt(uint8 opcode,
/* dest */ int x, int y, int cx, int cy,
/* src */ int srcx, int srcy)
{
xwin_set_function(opcode);
XCopyArea(display, wnd, wnd, gc, srcx, srcy,
cx, cy, x, y);
}
void ui_memblt(uint8 opcode,
/* dest */ int x, int y, int cx, int cy,
/* src */ HBITMAP src, int srcx, int srcy)
{
xwin_set_function(opcode);
XCopyArea(display, (Pixmap)src, wnd, gc, srcx, srcy,
cx, cy, x, y);
}
void ui_triblt(uint8 opcode,
/* dest */ int x, int y, int cx, int cy,
/* src */ HBITMAP src, int srcx, int srcy,
/* brush */ BRUSH *brush, int bgcolour, int fgcolour)
{
/* This is potentially difficult to do in general. Until someone
comes up with a more efficient way of doing it I am using cases. */
switch (opcode)
{
case 0xb8: /* PSDPxax */
ui_patblt(ROP2_XOR, x, y, cx, cy,
brush, bgcolour, fgcolour);
ui_memblt(ROP2_AND, x, y, cx, cy,
src, srcx, srcy);
ui_patblt(ROP2_XOR, x, y, cx, cy,
brush, bgcolour, fgcolour);
break;
default:
NOTIMP("triblt 0x%x\n", opcode);
ui_memblt(ROP2_COPY, x, y, cx, cy,
brush, bgcolour, fgcolour);
}
}
void ui_line(uint8 opcode,
/* dest */ int startx, int starty, int endx, int endy,
/* pen */ PEN *pen)
{
xwin_set_function(opcode);
XSetForeground(display, gc, pen->colour);
XDrawLine(display, wnd, gc, startx, starty, endx, endy);
}
void ui_rect(
/* dest */ int x, int y, int cx, int cy,
/* brush */ int colour)
{
xwin_set_function(ROP2_COPY);
XSetForeground(display, gc, colour);
XFillRectangle(display, wnd, gc, x, y, cx, cy);
}
void ui_draw_glyph(int mixmode,
/* dest */ int x, int y, int cx, int cy,
/* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour)
{
Pixmap pixmap = (Pixmap)glyph;
xwin_set_function(ROP2_COPY);
XSetForeground(display, gc, fgcolour);
switch (mixmode)
{
case MIX_TRANSPARENT:
XSetStipple(display, gc, pixmap);
XSetFillStyle(display, gc, FillStippled);
XSetTSOrigin(display, gc, x, y);
XFillRectangle(display, wnd, gc,
x, y, cx, cy);
XSetFillStyle(display, gc, FillSolid);
break;
case MIX_OPAQUE:
XSetBackground(display, gc, bgcolour);
XCopyPlane(display, pixmap, wnd, gc,
srcx, srcy, cx, cy, x, y, 1);
break;
default:
NOTIMP("mix %d\n", mixmode);
}
}
void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x,
int y, int boxx, int boxy, int boxcx, int boxcy,
int bgcolour, int fgcolour, uint8 *text, uint8 length)
{
FONTGLYPH *glyph;
int i;
if (boxcx > 1)
{
ui_rect(boxx, boxy, boxcx, boxcy, bgcolour);
}
/* Paint text, character by character */
for (i = 0; i < length; i++)
{
glyph = cache_get_font(font, text[i]);
if (glyph != NULL)
{
ui_draw_glyph(mixmode, x,
y + (short)glyph->baseline,
glyph->width, glyph->height,
glyph->pixmap, 0, 0,
bgcolour, fgcolour);
if (flags & TEXT2_IMPLICIT_X)
x += glyph->width;
else
x += text[++i];
}
}
}
void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
{
XImage *image;
int scanline;
scanline = (cx + 3) & ~3;
STATUS("XGetImage(%p,%x,%d,%d,%d,%d,%x,%d)\n", display, wnd, x, y,
cx, cy, 0xffffffff, ZPixmap);
image = XGetImage(display, wnd, x, y, cx, cy, 0xffffffff, ZPixmap);
cache_put_desktop(offset, scanline*cy, image->data);
XFree(image->data);
XFree(image);
}
void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
{
XImage *image;
int scanline;
uint8 *data;
scanline = (cx + 3) & ~3;
data = cache_get_desktop(offset, scanline*cy);
if (data == NULL)
return;
image = XCreateImage(display, visual, 8, ZPixmap, 0,
data, cx, cy, 32, scanline);
XSetFunction(display, gc, GXcopy);
XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
XFree(image);
}