📄 xwin.c
字号:
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
User interface services - X Window System
Copyright (C) Matthew Chapman 1999-2005
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 <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <strings.h>
#include "rdesktop.h"
#include "xproto.h"
/* We can't include Xproto.h because of conflicting defines for BOOL */
#define X_ConfigureWindow 12
/* MWM decorations */
#define MWM_HINTS_DECORATIONS (1L << 1)
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
typedef struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
}
PropMotifWmHints;
typedef struct
{
uint32 red;
uint32 green;
uint32 blue;
}
PixelColour;
#define ON_ALL_SEAMLESS_WINDOWS(func, args) \
do { \
seamless_window *sw; \
XRectangle rect; \
if (!This->xwin.seamless_windows) break; \
for (sw = This->xwin.seamless_windows; sw; sw = sw->next) { \
rect.x = This->xwin.clip_rectangle.x - sw->xoffset; \
rect.y = This->xwin.clip_rectangle.y - sw->yoffset; \
rect.width = This->xwin.clip_rectangle.width; \
rect.height = This->xwin.clip_rectangle.height; \
XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &rect, 1, YXBanded); \
func args; \
} \
XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &This->xwin.clip_rectangle, 1, YXBanded); \
} while (0)
static void
seamless_XFillPolygon(RDPCLIENT * This, Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
{
points[0].x -= xoffset;
points[0].y -= yoffset;
XFillPolygon(This->display, d, This->xwin.gc, points, npoints, Complex, CoordModePrevious);
points[0].x += xoffset;
points[0].y += yoffset;
}
static void
seamless_XDrawLines(RDPCLIENT * This, Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
{
points[0].x -= xoffset;
points[0].y -= yoffset;
XDrawLines(This->display, d, This->xwin.gc, points, npoints, CoordModePrevious);
points[0].x += xoffset;
points[0].y += yoffset;
}
#define FILL_RECTANGLE(x,y,cx,cy)\
{ \
XFillRectangle(This->display, This->wnd, This->xwin.gc, x, y, cx, cy); \
ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
if (This->ownbackstore) \
XFillRectangle(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy); \
}
#define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
{ \
XFillRectangle(This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, This->xwin.gc, x, y, cx, cy); \
}
#define FILL_POLYGON(p,np)\
{ \
XFillPolygon(This->display, This->wnd, This->xwin.gc, p, np, Complex, CoordModePrevious); \
if (This->ownbackstore) \
XFillPolygon(This->display, This->xwin.backstore, This->xwin.gc, p, np, Complex, CoordModePrevious); \
ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (This, sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
}
#define DRAW_ELLIPSE(x,y,cx,cy,m)\
{ \
switch (m) \
{ \
case 0: /* Outline */ \
XDrawArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
if (This->ownbackstore) \
XDrawArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
break; \
case 1: /* Filled */ \
XFillArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, sw->wnd, This->xwin.gc, \
x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
if (This->ownbackstore) \
XFillArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
break; \
} \
}
#define TRANSLATE(col) ( This->server_depth != 8 ? translate_colour(This, col) : This->owncolmap ? col : This->xwin.colmap[col] )
#define SET_FOREGROUND(col) XSetForeground(This->display, This->xwin.gc, TRANSLATE(col));
#define SET_BACKGROUND(col) XSetBackground(This->display, This->xwin.gc, TRANSLATE(col));
static const 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(This->display, This->xwin.gc, rop2_map[rop2]); }
#define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(This->display, This->xwin.gc, GXcopy); }
static seamless_window *
sw_get_window_by_id(RDPCLIENT * This, unsigned long id)
{
seamless_window *sw;
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (sw->id == id)
return sw;
}
return NULL;
}
static seamless_window *
sw_get_window_by_wnd(RDPCLIENT * This, Window wnd)
{
seamless_window *sw;
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (sw->wnd == wnd)
return sw;
}
return NULL;
}
static void
sw_remove_window(RDPCLIENT * This, seamless_window * win)
{
seamless_window *sw, **prevnext = &This->xwin.seamless_windows;
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (sw == win)
{
*prevnext = sw->next;
sw->group->refcnt--;
if (sw->group->refcnt == 0)
{
XDestroyWindow(This->display, sw->group->wnd);
xfree(sw->group);
}
xfree(sw->position_timer);
xfree(sw);
return;
}
prevnext = &sw->next;
}
return;
}
/* Move all windows except wnd to new desktop */
static void
sw_all_to_desktop(RDPCLIENT * This, Window wnd, unsigned int desktop)
{
seamless_window *sw;
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (sw->wnd == wnd)
continue;
if (sw->desktop != desktop)
{
ewmh_move_to_desktop(This, sw->wnd, desktop);
sw->desktop = desktop;
}
}
}
/* Send our position */
static void
sw_update_position(RDPCLIENT * This, seamless_window * sw)
{
XWindowAttributes wa;
int x, y;
Window child_return;
unsigned int serial;
XGetWindowAttributes(This->display, sw->wnd, &wa);
XTranslateCoordinates(This->display, sw->wnd, wa.root,
-wa.border_width, -wa.border_width, &x, &y, &child_return);
serial = seamless_send_position(This, sw->id, x, y, wa.width, wa.height, 0);
sw->outstanding_position = True;
sw->outpos_serial = serial;
sw->outpos_xoffset = x;
sw->outpos_yoffset = y;
sw->outpos_width = wa.width;
sw->outpos_height = wa.height;
}
/* Check if it's time to send our position */
static void
sw_check_timers(RDPCLIENT * This)
{
seamless_window *sw;
struct timeval now;
gettimeofday(&now, NULL);
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
{
timerclear(sw->position_timer);
sw_update_position(This, sw);
}
}
}
static void
sw_restack_window(RDPCLIENT * This, seamless_window * sw, unsigned long behind)
{
seamless_window *sw_above;
/* Remove window from stack */
for (sw_above = This->xwin.seamless_windows; sw_above; sw_above = sw_above->next)
{
if (sw_above->behind == sw->id)
break;
}
if (sw_above)
sw_above->behind = sw->behind;
/* And then add it at the new position */
for (sw_above = This->xwin.seamless_windows; sw_above; sw_above = sw_above->next)
{
if (sw_above->behind == behind)
break;
}
if (sw_above)
sw_above->behind = sw->id;
sw->behind = behind;
}
static void
sw_handle_restack(RDPCLIENT * This, seamless_window * sw)
{
Status status;
Window root, parent, *children;
unsigned int nchildren, i;
seamless_window *sw_below;
status = XQueryTree(This->display, RootWindowOfScreen(This->xwin.screen),
&root, &parent, &children, &nchildren);
if (!status || !nchildren)
return;
sw_below = NULL;
i = 0;
while (children[i] != sw->wnd)
{
i++;
if (i >= nchildren)
goto end;
}
for (i++; i < nchildren; i++)
{
sw_below = sw_get_window_by_wnd(This, children[i]);
if (sw_below)
break;
}
if (!sw_below && !sw->behind)
goto end;
if (sw_below && (sw_below->id == sw->behind))
goto end;
if (sw_below)
{
seamless_send_zchange(This, sw->id, sw_below->id, 0);
sw_restack_window(This, sw, sw_below->id);
}
else
{
seamless_send_zchange(This, sw->id, 0, 0);
sw_restack_window(This, sw, 0);
}
end:
XFree(children);
}
static seamless_group *
sw_find_group(RDPCLIENT * This, unsigned long id, BOOL dont_create)
{
seamless_window *sw;
seamless_group *sg;
XSetWindowAttributes attribs;
for (sw = This->xwin.seamless_windows; sw; sw = sw->next)
{
if (sw->group->id == id)
return sw->group;
}
if (dont_create)
return NULL;
sg = xmalloc(sizeof(seamless_group));
sg->wnd =
XCreateWindow(This->display, RootWindowOfScreen(This->xwin.screen), -1, -1, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
sg->id = id;
sg->refcnt = 0;
return sg;
}
static void
mwm_hide_decorations(RDPCLIENT * This, Window wnd)
{
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(This->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(This->display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
}
#define SPLITCOLOUR15(colour, rv) \
{ \
rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
}
#define SPLITCOLOUR16(colour, rv) \
{ \
rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
} \
#define SPLITCOLOUR24(colour, rv) \
{ \
rv.blue = (colour & 0xff0000) >> 16; \
rv.green = (colour & 0x00ff00) >> 8; \
rv.red = (colour & 0x0000ff); \
}
#define MAKECOLOUR(pc) \
((pc.red >> This->xwin.red_shift_r) << This->xwin.red_shift_l) \
| ((pc.green >> This->xwin.green_shift_r) << This->xwin.green_shift_l) \
| ((pc.blue >> This->xwin.blue_shift_r) << This->xwin.blue_shift_l) \
#define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
#define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
#define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
x = (x << 16) | (x >> 16); }
/* The following macros output the same octet sequences
on both BE and LE hosts: */
#define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
#define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
#define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
#define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
#define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
#define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
static uint32
translate_colour(RDPCLIENT * This, uint32 colour)
{
PixelColour pc;
switch (This->server_depth)
{
case 15:
SPLITCOLOUR15(colour, pc);
break;
case 16:
SPLITCOLOUR16(colour, pc);
break;
case 24:
SPLITCOLOUR24(colour, pc);
break;
default:
/* Avoid warning */
pc.red = 0;
pc.green = 0;
pc.blue = 0;
break;
}
return MAKECOLOUR(pc);
}
/* indent is confused by UNROLL8 */
/* *INDENT-OFF* */
/* repeat and unroll, similar to bitmap.c */
/* potentialy any of the following translate */
/* functions can use repeat but just doing */
/* the most common ones */
#define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
/* 2 byte output repeat */
#define REPEAT2(stm) \
{ \
while (out <= end - 8 * 2) \
UNROLL8(stm) \
while (out < end) \
{ stm } \
}
/* 3 byte output repeat */
#define REPEAT3(stm) \
{ \
while (out <= end - 8 * 3) \
UNROLL8(stm) \
while (out < end) \
{ stm } \
}
/* 4 byte output repeat */
#define REPEAT4(stm) \
{ \
while (out <= end - 8 * 4) \
UNROLL8(stm) \
while (out < end) \
{ stm } \
}
/* *INDENT-ON* */
static void
translate8to8(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end)
{
while (out < end)
*(out++) = (uint8) This->xwin.colmap[*(data++)];
}
static void
translate8to16(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end)
{
uint16 value;
if (This->xwin.compatible_arch)
{
/* *INDENT-OFF* */
REPEAT2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -