xwin.c revision d65680efa46fa49e8bf14e67b29b782510ff934c
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
User interface services - X Window System
Copyright (C) Matthew Chapman 1999-2008
Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
*/
/*
* Sun GPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any software where
* a choice of GPL license versions is made available with the language indicating
* that GPLv2 or any later version may be used, or where a choice of which version
* of the GPL is applied is otherwise unspecified.
*/
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <strings.h>
#include "rdesktop.h"
#include "xproto.h"
extern int g_width;
extern int g_height;
extern int g_xpos;
extern int g_ypos;
extern int g_pos;
extern RD_BOOL g_sendmotion;
extern RD_BOOL g_fullscreen;
extern RD_BOOL g_grab_keyboard;
extern RD_BOOL g_hide_decorations;
extern char g_title[];
/* Color depth of the RDP session.
As of RDP 5.1, it may be 8, 15, 16 or 24. */
extern int g_server_depth;
extern int g_win_button_size;
static int g_x_socket;
/* SeamlessRDP support */
typedef struct _seamless_group
{
unsigned long id;
unsigned int refcnt;
typedef struct _seamless_window
{
unsigned long id;
unsigned long behind;
unsigned int desktop;
struct timeval *position_timer;
unsigned int outpos_serial;
int outpos_xoffset, outpos_yoffset;
int outpos_width, outpos_height;
unsigned int icon_size;
unsigned int icon_offset;
struct _seamless_window *next;
static unsigned long g_seamless_focused = 0;
extern RD_BOOL g_seamless_rdp;
extern uint32 g_embed_wnd;
static XRectangle g_clip_rectangle;
/* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
as far as we're concerned. */
static int g_depth;
/* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
This may be larger than g_depth, in which case some of the bits would
be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
static int g_bpp;
static XModifierKeymap *g_mod_map;
/* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
to physical (1-based) indices. */
static unsigned char g_pointer_log_to_phys_map[32];
static Cursor g_current_cursor;
extern Atom g_net_wm_state_atom;
extern Atom g_net_wm_desktop_atom;
static RD_BOOL g_mouse_in_wnd;
/* Indicates that:
1) visual has 15, 16 or 24 depth and the same color channel masks
as its RDP equivalent (implies X server is LE),
2) host is LE
This will trigger an optimization whose real value is questionable.
*/
static RD_BOOL g_compatible_arch;
/* Indicates whether RDP's bitmaps and our XImages have the same
binary format. If so, we can avoid an expensive translation.
Note that this can be true when g_compatible_arch is false,
e.g.:
RDP(LE) <-> host(BE) <-> X-Server(LE)
('host' is the machine running rdesktop; the host simply memcpy's
so its endianess doesn't matter)
*/
/* endianness */
static RD_BOOL g_xserver_be;
/* software backing store */
extern RD_BOOL g_ownbackstore;
static Pixmap g_backstore = 0;
/* Moving in single app mode */
static RD_BOOL g_moving_wnd;
static int g_move_x_offset = 0;
static int g_move_y_offset = 0;
#ifdef WITH_RDPSND
#endif
/* MWM decorations */
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
typedef struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
}
typedef struct
{
}
do { \
seamless_window *sw; \
XRectangle rect; \
if (!g_seamless_windows) break; \
} \
} while (0)
static void
{
}
static void
{
}
{ \
ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
if (g_ownbackstore) \
}
{ \
}
#define FILL_POLYGON(p,np)\
{ \
if (g_ownbackstore) \
}
{ \
switch (m) \
{ \
case 0: /* Outline */ \
ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
if (g_ownbackstore) \
break; \
case 1: /* Filled */ \
ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
if (g_ownbackstore) \
break; \
} \
}
/* colour maps */
extern RD_BOOL g_owncolmap;
#define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[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(g_display, g_gc, rop2_map[rop2]); }
static seamless_window *
sw_get_window_by_id(unsigned long id)
{
{
return sw;
}
return NULL;
}
static seamless_window *
{
{
return sw;
}
return NULL;
}
static void
{
{
{
{
}
return;
}
}
return;
}
/* Move all windows except wnd to new desktop */
static void
{
{
continue;
{
}
}
}
/* Send our position */
static void
{
int x, y;
unsigned int serial;
sw->outpos_xoffset = x;
sw->outpos_yoffset = y;
}
/* Check if it's time to send our position */
static void
{
{
{
}
}
}
static void
{
/* Remove window from stack */
{
break;
}
if (sw_above)
/* And then add it at the new position */
{
break;
}
if (sw_above)
}
static void
{
unsigned int nchildren, i;
return;
i = 0;
{
i++;
if (i >= nchildren)
goto end;
}
for (i++; i < nchildren; i++)
{
if (sw_below)
break;
}
goto end;
goto end;
if (sw_below)
{
}
else
{
sw_restack_window(sw, 0);
}
end:
}
static seamless_group *
{
{
}
if (dont_create)
return NULL;
return sg;
}
static void
{
/* setup the property */
motif_hints.decorations = 0;
/* get the atom for the property */
if (!hintsatom)
{
warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
return;
}
(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
}
typedef struct _sw_configurenotify_context
{
unsigned long serial;
/* Predicate procedure for sw_wait_configurenotify */
static Bool
{
return True;
return False;
}
/* Wait for a ConfigureNotify, with a equal or larger serial, on the
specified window. The event will be removed from the queue. We
could use XMaskEvent(StructureNotifyMask), but we would then risk
throwing away crucial events like DestroyNotify.
After a ConfigureWindow, according to ICCCM section 4.1.5, we
should recieve a ConfigureNotify, either a real or synthetic
one. This indicates that the configure has been "completed".
However, some WMs such as several versions of Metacity fails to
send synthetic events. See bug
http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
timeout to avoid a hang. Tk uses the same approach. */
static void
{
struct timeval nextsecond;
do
{
{
break;
}
usleep(100000);
}
if (!got)
{
warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
}
}
/* Get the toplevel window, in case of reparenting */
static Window
{
unsigned int num_children;
while (1)
{
{
break;
}
else if (!parent)
{
warning("Internal error: sw_get_toplevel called with root window\n");
}
}
return wnd;
}
/* Check if wnd is already behind a window wrt stacking order */
static RD_BOOL
{
unsigned int num_children;
unsigned int i;
&num_children);
for (i = num_children - 1; i >= 0; i--)
{
if (child_list[i] == behind)
{
found_behind = True;
}
else if (child_list[i] == wnd)
{
break;
}
}
if (child_list)
if (!found_wnd)
{
if (!found_behind)
{
warning("sw_window_is_behind: Unable to find behind window 0x%lx\n",
behind);
}
}
return found_behind;
}
/* Test if the window manager correctly handles window restacking. In
particular, we are testing if it's possible to place a window
between two other windows. Many WMs such as Metacity can only stack
windows on the top or bottom. The window creation should mostly
match ui_seamless_create_window. */
static void
{
/* The goal is to have the middle window between top and
bottom. The middle window is initially at the top,
though. */
int i;
unsigned long restack_serial;
for (i = 0; i < 3; i++)
{
char name[64];
wnds[i] =
0, 0, 0);
/* Hide decorations. Often this means that no
reparenting will be done, which makes the restack
easier. Besides, we want to mimic our other
seamless windows as much as possible. We must still
handle the case with reparenting, though. */
mwm_hide_decorations(wnds[i]);
/* Prevent windows from appearing in task bar */
/* We need to catch MapNotify/ConfigureNotify */
}
/* Map Windows. Currently, we assume that XMapRaised places
the window on the top of the stack. Should be fairly safe;
the window is configured before it's mapped. */
do
{
}
do
{
}
do
{
}
/* The stacking order should now be 1 - 0 - 2 */
{
/* Ok, technically a WM is allowed to stack windows arbitrarily, but... */
warning("Broken Window Manager: Unable to test window restacking\n");
for (i = 0; i < 3; i++)
return;
}
/* Restack, using XReconfigureWMWindow, which should correctly
handle reparented windows as well as nonreparenting WMs. */
&values);
/* Now verify that middle is behind top but not behind
bottom */
{
warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n");
}
{
warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n");
}
/* Destroy windows */
for (i = 0; i < 3; i++)
}
{ \
}
{ \
} \
{ \
}
#define MAKECOLOUR(pc) \
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 LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
static uint32
{
switch (g_server_depth)
{
case 15:
break;
case 16:
break;
case 24:
case 32:
break;
default:
/* Avoid warning */
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 */
/* 2 byte output repeat */
{ \
{ stm } \
}
/* 3 byte output repeat */
{ \
{ stm } \
}
/* 4 byte output repeat */
{ \
{ stm } \
}
/* *INDENT-ON* */
static void
{
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
out += 2;
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
{
}
}
else
{
{
}
}
}
/* little endian - conversion happens when colourmap is built */
static void
{
if (g_compatible_arch)
{
{
}
}
else
{
{
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
out += 4;
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
{
}
}
else
{
{
}
}
}
static void
{
if (g_xserver_be)
{
{
if (g_host_be)
{
}
}
}
else
{
{
if (g_host_be)
{
}
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
{
if (g_host_be)
{
}
}
}
else
{
{
if (g_host_be)
{
}
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
*(out++) = 0;
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
{
if (g_host_be)
{
}
}
}
else
{
{
if (g_host_be)
{
}
}
}
}
static void
{
if (g_xserver_be)
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
else
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
else
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
(
*(out++) = 0;
)
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
else
{
if (g_host_be)
{
{
}
}
else
{
{
}
}
}
}
static void
{
{
if (g_xserver_be)
{
}
else
{
}
}
}
static void
{
if (g_xserver_be)
{
{
}
}
else
{
{
}
}
}
static void
{
if (g_compatible_arch)
{
/* *INDENT-OFF* */
#ifdef NEED_ALIGN
(
*(out++) = 0;
)
#else
(
/* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
out += 4;
data += 3;
)
#endif
/* *INDENT-ON* */
}
else if (g_xserver_be)
{
{
}
}
else
{
{
}
}
}
static uint8 *
{
int size;
/*
If RDP depth and X Visual depths match,
and arch(endian) matches, no need to translate:
just return data.
Note: select_visual should've already ensured g_no_translate
is only set for compatible depths, but the RDP depth might've
changed during connection negotiations.
*/
/* todo */
{
return data;
}
if (g_no_translate_image)
{
return data;
}
switch (g_server_depth)
{
case 24:
switch (g_bpp)
{
case 32:
break;
case 24:
break;
case 16:
break;
}
break;
case 16:
switch (g_bpp)
{
case 32:
break;
case 24:
break;
case 16:
break;
}
break;
case 15:
switch (g_bpp)
{
case 32:
break;
case 24:
break;
case 16:
break;
}
break;
case 8:
switch (g_bpp)
{
case 8:
break;
case 16:
break;
case 24:
break;
case 32:
break;
}
break;
}
return out;
}
static void
xwin_refresh_pointer_map(void)
{
unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
int i, pointer_buttons;
if (pointer_buttons > sizeof(phys_to_log_map))
pointer_buttons = sizeof(phys_to_log_map);
/* if multiple physical buttons map to the same logical button, then
* use the lower numbered physical one */
for (i = pointer_buttons - 1; i >= 0; i--)
{
/* a user could specify arbitrary values for the logical button
* number, ignore any that are abnormally large */
if (phys_to_log_map[i] > sizeof(g_pointer_log_to_phys_map))
continue;
}
}
{
int offset;
return False;
{
{
}
}
}
static void
{
}
/* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
calculates the bits-per-pixel of this channel (a.k.a. colour weight).
*/
static unsigned
{
unsigned weight = 0;
do
{
}
while (mask >>= 1);
return weight;
}
static RD_BOOL
select_visual(int screen_num)
{
int i;
if (g_server_depth == -1)
{
}
{
error("Unable to get list of pixmap formats from display.\n");
return False;
}
/* Search for best TrueColor visual */
vmatches =
{
for (i = 0; i < visuals_count; ++i)
{
int j;
/* Try to find a no-translation visual that'll
allow us to use RDP bitmaps directly as ZPixmaps. */
/* R5G5B5 */
/* R5G6B5 */
/* R8G8B8 */
{
if (g_no_translate_image)
/* We found the best visual */
break;
}
else
{
}
{
/* Avoid 32-bit visuals and likes like the plague.
They're either untested or proven to work bad
(e.g. nvidia's Composite 32-bit visual).
Most implementation offer a 24-bit visual anyway. */
continue;
}
/* Only care for visuals, for whose BPPs (not depths!)
we have a translateXtoY function. */
for (j = 0; j < pixmap_formats_count; ++j)
{
{
{
}
break;
}
}
/* Prefer formats which have the most colour depth.
We're being truly aristocratic here, minding each
weight on its own. */
if (can_translate_to_bpp)
{
unsigned vis_red_weight =
unsigned vis_green_weight =
unsigned vis_blue_weight =
if ((vis_red_weight >= red_weight)
&& (vis_green_weight >= green_weight)
&& (vis_blue_weight >= blue_weight))
{
}
}
}
}
{
g_owncolmap = False;
}
else
{
vmatches =
&template, &visuals_count);
{
error("No usable TrueColor or PseudoColor visuals on this display.\n");
return False;
}
/* we use a colourmap, so the default visual should do */
g_owncolmap = True;
}
g_bpp = 0;
for (i = 0; i < pixmap_formats_count; ++i)
{
{
if (g_no_translate_image)
{
switch (g_server_depth)
{
case 15:
case 16:
if (g_bpp != 16)
break;
case 24:
/* Yes, this will force image translation
on most modern servers which use 32 bits
for R8G8B8. */
if (g_bpp != 24)
break;
default:
break;
}
}
/* Pixmap formats list is a depth-to-bpp mapping --
there's just a single entry for every depth,
so we can safely break here */
break;
}
}
return True;
}
static XErrorHandler g_old_error_handler;
/* Check if the X11 window corresponding to a seamless window with
specified id exists. */
sw_window_exists(unsigned long id)
{
char *name;
if (!sw)
return False;
if (sts)
{
}
return sts;
}
static int
{
if (g_error_expected)
return 0;
}
ui_init(void)
{
int screen_num;
{
return False;
}
{
}
if (!select_visual(screen_num))
return False;
if (g_no_translate_image)
{
DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
}
if (g_server_depth > g_bpp)
{
warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
}
DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
if (!g_owncolmap)
{
if (g_depth <= 8)
warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
}
{
warning("External BackingStore not available. Using internal.\n");
}
/*
* Determine desktop size
*/
if (g_fullscreen)
{
}
else if (g_width < 0)
{
/* Percent of screen */
if (-g_width >= 100)
}
else if (g_width == 0)
{
/* Fetch geometry from _NET_WORKAREA */
{
}
else
{
warning("Failed to get workarea: probably your window manager does not support extended hints\n");
}
}
/* make sure width is a multiple of 4 */
xkeymap_init();
if (g_enable_compose)
xclip_init();
ewmh_init();
if (g_seamless_rdp)
{
}
return True;
}
void
ui_deinit(void)
{
while (g_seamless_windows)
{
}
xclip_deinit();
if (g_null_cursor != NULL)
if (g_ownbackstore)
}
static void
{
}
static void
get_input_mask(long *input_mask)
{
if (g_sendmotion)
if (g_ownbackstore)
*input_mask |= ExposureMask;
if (g_fullscreen || g_grab_keyboard)
if (g_grab_keyboard)
}
ui_create_window(void)
{
long input_mask, ic_input_mask;
/* Handle -x-y portion of geometry string */
CWBorderPixel, &attribs);
{
}
if (g_create_bitmap_gc == NULL)
if ((g_ownbackstore) && (g_backstore == 0))
{
/* clear to prevent rubbish being exposed at startup */
}
if (g_hide_decorations)
if (classhints != NULL)
{
}
sizehints = XAllocSizeHints();
if (sizehints)
{
if (g_pos)
}
if (g_embed_wnd)
{
}
{
}
/* wait for VisibilityNotify */
do
{
}
/* handle the WM_DELETE_WINDOW protocol */
/* create invisible 1x1 cursor to be used as null cursor */
if (g_null_cursor == NULL)
if (g_seamless_rdp)
{
}
return True;
}
void
{
sizehints = XAllocSizeHints();
if (sizehints)
{
}
if (!(g_fullscreen || g_embed_wnd))
{
}
/* create new backstore pixmap */
if (g_backstore != 0)
{
g_backstore = bs;
}
}
void
ui_destroy_window(void)
{
}
void
xwin_toggle_fullscreen(void)
{
if (g_seamless_active)
/* Turn off SeamlessRDP mode */
if (!g_ownbackstore)
{
/* need to save contents of window */
}
if (!g_ownbackstore)
{
}
}
static void
{
/* Reverse the pointer button mapping, e.g. in the case of
"left-handed mouse mode"; the RDP session expects to
receive physical buttons (true in mstsc as well) and
logical button behavior depends on the remote desktop's own
mouse settings */
if (button == 0)
return;
if (down)
/* Stop moving window when button is released, regardless of cursor position */
/* If win_button_size is nonzero, enable single app mode */
{
/* Check from right to left: */
{
/* The close button, continue */
;
}
{
server. It might be a good idea to change the
cursor or give some other visible indication
that rdesktop inhibited this click */
return;
}
{
/* The minimize button. Iconify window. */
{
/* Release the mouse button outside the minimize button, to prevent the
actual minimazation to happen */
return;
}
}
{
/* The system menu. Ignore. */
return;
}
else
{
/* The title bar. */
{
{
g_moving_wnd = True;
}
return;
}
}
}
{
}
else
{
/* SeamlessRDP */
}
}
/* Process events in Xlib queue
Returns 0 after user quit, 1 otherwise */
static int
xwin_process_events(void)
{
char str[256];
int events = 0;
{
{
DEBUG_KBD(("Filtering event\n"));
continue;
}
{
case VisibilityNotify:
break;
case ClientMessage:
/* the window manager told us to quit */
{
/* When killing a seamless window, close the window on the
serverside instead of terminating rdesktop */
if (!sw)
/* Otherwise, quit */
return 0;
/* send seamless destroy process message */
}
break;
case KeyPress:
/* Multi_key compatible version */
{
&status);
{
error("XmbLookupString failed with status 0x%x\n",
status);
break;
}
}
else
{
/* Plain old XLookupString */
DEBUG_KBD(("\nNo input context, using XLookupString\n"));
}
get_ksname(keysym)));
break;
break;
case KeyRelease:
get_ksname(keysym)));
break;
break;
case ButtonPress:
break;
case ButtonRelease:
break;
case MotionNotify:
if (g_moving_wnd)
{
break;
}
if (g_fullscreen && !g_focused)
{
}
else
{
/* SeamlessRDP */
}
break;
case FocusIn:
break;
if (g_grab_keyboard && g_mouse_in_wnd)
if (!sw)
break;
/* Menu windows are real X11 windows,
with focus. When such a window is
destroyed, focus is reverted to the
main application window, which
would cause us to send FOCUS. This
breaks window switching in, say,
Seamonkey. We shouldn't need to
send FOCUS: Windows should also
revert focus to some other window
when the menu window is
destroyed. So, we only send FOCUS
if the previous focus window still
exists. */
{
}
break;
case FocusOut:
break;
break;
case EnterNotify:
/* we only register for this event when in fullscreen mode */
/* or grab_keyboard */
if (g_fullscreen)
{
break;
}
if (g_focused)
break;
case LeaveNotify:
/* we only register for this event when grab_keyboard */
/* VirtualBox code begin */
if (g_fullscreen)
{
/* If mouse pointer is outside the fullscreen client window,
* release it to let the client on the other screen to continue
* with the mouse processing.
*/
}
/* VirtualBox code end */
break;
case Expose:
{
g_gc,
}
else
{
if (!sw)
break;
}
break;
case MappingNotify:
/* Refresh keyboard mapping if it has changed. This is important for
Xvnc, since it allocates keycodes dynamically */
{
}
{
}
break;
/* clipboard stuff */
case SelectionNotify:
break;
case SelectionRequest:
break;
case SelectionClear:
break;
case PropertyNotify:
break;
break;
/* seamless */
if (!sw)
break;
{
}
{
}
break;
case MapNotify:
if (!g_seamless_active)
break;
case UnmapNotify:
if (!g_seamless_active)
break;
case ConfigureNotify:
if (!g_seamless_active)
break;
if (!sw)
break;
1000000)
{
SEAMLESSRDP_POSITION_TIMER - 1000000;
}
else
{
}
break;
}
}
/* Keep going */
return 1;
}
/* Returns 0 after user quit, 1 otherwise */
int
ui_select(int rdp_socket)
{
int n;
while (True)
{
/* Process any events already waiting */
if (!xwin_process_events())
/* User quit */
return 0;
if (g_seamless_active)
/* default timeout */
#ifdef WITH_RDPSND
#endif
#ifdef WITH_RDPUSB
#endif
/* add redirection handles */
n++;
{
case -1:
case 0:
#ifdef WITH_RDPSND
#endif
/* Abort serial read calls */
if (s_timeout)
continue;
}
#ifdef WITH_RDPUSB
#endif
#ifdef WITH_RDPSND
#endif
return 1;
}
}
void
ui_move_pointer(int x, int y)
{
}
{
int bitmap_pad;
if (g_server_depth == 8)
{
bitmap_pad = 8;
}
else
{
bitmap_pad = g_bpp;
if (g_bpp == 24)
bitmap_pad = 32;
}
return (RD_HBITMAP) bitmap;
}
void
{
int bitmap_pad;
if (g_server_depth == 8)
{
bitmap_pad = 8;
}
else
{
bitmap_pad = g_bpp;
if (g_bpp == 24)
bitmap_pad = 32;
}
if (g_ownbackstore)
{
}
else
{
}
}
void
{
}
{
int scanline;
if (g_create_glyph_gc == 0)
}
void
{
}
{
int i, j;
/* approximate AND and XOR masks with a monochrome X pointer */
for (i = 0; i < height; i++)
{
for (j = 0; j < scanline; j++)
{
{
{
}
else
{
}
xormask += 3;
}
andmask++;
pcursor++;
pmask++;
}
}
xcursor =
return (RD_HCURSOR) xcursor;
}
void
{
}
void
{
}
void
ui_set_null_cursor(void)
{
}
#define MAKE_XCOLOR(xc,c) \
{
if (!g_owncolmap)
{
int colLookup = 256;
for (i = 0; i < ncolours; i++)
{
{
/* Allocation failed, find closest match. */
int j = 256;
/* only get the colors once */
while (colLookup--)
{
}
colLookup = 0;
/* approximate the pixel */
while (j--)
{
{
}
{
}
}
}
/* update our cache */
{
}
}
return map;
}
else
{
for (i = 0; i < ncolours; i++)
{
}
return (RD_HCOLOURMAP) map;
}
}
void
{
if (!g_owncolmap)
else
}
void
{
if (!g_owncolmap)
{
if (g_colmap)
}
else
{
}
}
void
{
g_clip_rectangle.x = x;
g_clip_rectangle.y = y;
}
void
ui_reset_clip(void)
{
g_clip_rectangle.x = 0;
g_clip_rectangle.y = 0;
}
void
ui_bell(void)
{
}
void
{
}
static uint8 hatch_patterns[] = {
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
};
void
{
{
case 0: /* Solid */
break;
case 2: /* Hatch */
break;
case 3: /* Pattern */
for (i = 0; i != 8; i++)
break;
default:
}
if (g_ownbackstore)
}
void
{
if (g_ownbackstore)
{
}
else
{
}
}
void
{
if (g_ownbackstore)
}
void
{
/* 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 0x69: /* PDSxxn */
break;
case 0xb8: /* PSDPxax */
break;
case 0xc0: /* PSa */
break;
default:
}
}
void
{
if (g_ownbackstore)
}
void
/* brush */ int colour)
{
}
void
{
switch (fillmode)
{
case ALTERNATE:
break;
case WINDING:
break;
default:
}
if (brush)
else
style = 0;
switch (style)
{
case 0: /* Solid */
break;
case 2: /* Hatch */
break;
case 3: /* Pattern */
for (i = 0; i != 8; i++)
break;
default:
}
}
void
{
/* TODO: set join style */
if (g_ownbackstore)
}
void
{
if (brush)
else
style = 0;
switch (style)
{
case 0: /* Solid */
break;
case 2: /* Hatch */
break;
case 3: /* Pattern */
for (i = 0; i != 8; i++)
break;
default:
}
}
/* warning, this function only draws on wnd or backstore, not both */
void
ui_draw_glyph(int mixmode,
{
}
{\
if (!(flags & TEXT2_IMPLICIT_X))\
{\
if ((xyoffset & 0x80))\
{\
if (flags & TEXT2_VERTICAL)\
else\
idx += 2;\
}\
else\
{\
if (flags & TEXT2_VERTICAL)\
y += xyoffset;\
else\
x += xyoffset;\
}\
}\
{\
if (flags & TEXT2_IMPLICIT_X)\
}\
}
void
{
/* TODO: use brush appropriately */
/* Sometimes, the boxcx value is something really large, like
32691. This makes XCopyArea fail with Xvnc. The code below
is a quick fix. */
if (boxcx > 1)
{
}
else if (mixmode == MIX_OPAQUE)
{
}
/* Paint text, character by character */
for (i = 0; i < length;)
{
switch (text[i])
{
case 0xff:
/* At least two bytes needs to follow */
if (i + 3 > length)
{
warning("Skipping short 0xff command:");
for (j = 0; j < length; j++)
i = length = 0;
break;
}
i += 3;
length -= i;
/* this will move pointer from start to first character after FF command */
i = 0;
break;
case 0xfe:
/* At least one byte needs to follow */
if (i + 2 > length)
{
warning("Skipping short 0xfe command:");
for (j = 0; j < length; j++)
i = length = 0;
break;
}
{
{
if (flags & TEXT2_VERTICAL)
y += text[i + 2];
else
x += text[i + 2];
}
}
if (i + 2 < length)
i += 3;
else
i += 2;
length -= i;
/* this will move pointer from start to first character after FE command */
i = 0;
break;
default:
i++;
break;
}
}
if (g_ownbackstore)
{
if (boxcx > 1)
{
}
else
{
}
}
}
void
{
if (g_ownbackstore)
{
}
else
{
}
}
void
{
return;
if (g_ownbackstore)
{
}
else
{
}
}
/* these do nothing here but are used in uiports */
void
ui_begin_update(void)
{
}
void
ui_end_update(void)
{
}
void
{
if (!g_seamless_rdp)
return;
if (g_seamless_started)
return;
if (!hidden)
}
void
{
if (!g_seamless_rdp)
return;
if (!g_seamless_started)
return;
if (g_seamless_active)
}
void
{
if (!g_seamless_rdp)
return;
if (!g_seamless_started)
return;
}
void
{
if (!g_seamless_rdp)
return;
if (!g_seamless_started)
return;
if (g_seamless_hidden)
return;
if (g_seamless_active)
{
/* Deactivate */
while (g_seamless_windows)
{
}
}
else
{
/* Activate */
}
}
void
unsigned long flags)
{
long input_mask;
if (!g_seamless_active)
return;
/* Ignore CREATEs for existing windows */
if (sw)
return;
if (classhints != NULL)
{
}
/* WM_NORMAL_HINTS */
sizehints = XAllocSizeHints();
{
}
/* Parent-less transient windows */
if (parent == 0xFFFFFFFF)
{
/* Some buggy wm:s (kwin) do not handle the above, so fake it
using some other hints. */
}
/* Normal transient windows */
else if (parent != 0x00000000)
{
if (sw_parent)
else
}
if (flags & SEAMLESSRDP_CREATE_MODAL)
{
/* We do this to support buggy wm:s (*cough* metacity *cough*)
somewhat at least */
if (parent == 0x00000000)
}
if (flags & SEAMLESSRDP_CREATE_TOPMOST)
{
/* Make window always-on-top */
}
/* FIXME: Support for Input Context:s */
/* handle the WM_DELETE_WINDOW protocol. */
sw->outpos_serial = 0;
/* WM_HINTS */
wmhints = XAllocWMHints();
if (wmhints)
{
}
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
}
void
{
if (!g_seamless_active)
return;
{
{
}
}
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
if (chunk == 0)
{
warning("ui_seamless_seticon: New icon started before previous completed\n");
{
return;
}
{
return;
}
sw->icon_offset = 0;
}
else
{
return;
}
{
warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
return;
}
{
}
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
{
return;
}
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
/* We ignore server updates until it has handled our request. */
if (sw->outstanding_position)
return;
/* X11 windows must be at least 1x1 */
return;
/* If we move the window in a maximized state, then KDE won't
accept restoration */
{
case SEAMLESSRDP_MINIMIZED:
case SEAMLESSRDP_MAXIMIZED:
return;
}
/* FIXME: Perhaps use ewmh_net_moveresize_window instead */
}
void
{
unsigned long restack_serial;
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
if (behind)
{
if (!sw_behind)
{
return;
}
{
}
}
else
{
&values);
}
if (flags & SEAMLESSRDP_CREATE_TOPMOST)
{
/* Make window always-on-top */
}
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
/* FIXME: Might want to convert the name for non-EWMH WMs */
}
void
{
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
switch (state)
{
case SEAMLESSRDP_NORMAL:
case SEAMLESSRDP_MAXIMIZED:
break;
case SEAMLESSRDP_MINIMIZED:
/* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
the Window Manager should probably just ignore the request, since
_NET_WM_STATE_HIDDEN is a function of some other aspect of the window
such as minimization, rather than an independent state." Besides,
XIconifyWindow is easier. */
{
if (hints)
{
}
}
else
break;
default:
break;
}
}
void
ui_seamless_syncbegin(unsigned long flags)
{
if (!g_seamless_active)
return;
/* Destroy all seamless windows */
while (g_seamless_windows)
{
}
}
void
ui_seamless_ack(unsigned int serial)
{
{
{
/* Do a complete redraw of the window as part of the
completion of the move. This is to remove any
artifacts caused by our lack of synchronization. */
break;
}
}
}