/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
User interface services - X Window System
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB
Copyright 2002-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*/
/*
* Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Oracle 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"
#ifdef HAVE_XRANDR
#endif
extern int g_sizeopt;
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 RD_BOOL g_pending_resize;
extern char g_title[];
extern char g_seamless_spawn_cmd[];
/* 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;
unsigned int outpos_serial;
unsigned int icon_size;
unsigned int icon_offset;
static unsigned long g_seamless_focused = 0;
extern RD_BOOL g_seamless_rdp;
extern RD_BOOL g_seamless_persistent_mode;
extern uint32 g_embed_wnd;
/* 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;
/* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
to physical (1-based) indices. */
extern Atom g_net_wm_state_atom;
extern Atom g_net_wm_desktop_atom;
/* 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.
*/
/* 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 */
/* software backing store */
extern RD_BOOL g_ownbackstore;
/* Moving in single app mode */
static int g_move_x_offset = 0;
static int g_move_y_offset = 0;
#ifdef WITH_RDPSND
#endif
/* MWM decorations */
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) \
}
{ \
}
{ \
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 *
{
{
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
{
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; i > 0; i--)
{
{
found_behind = True;
}
{
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++)
{
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++)
{
do
{
}
}
}
{ \
}
{ \
} \
{ \
}
x = (x << 16) | (x >> 16); }
/* The following macros output the same octet sequences
on both BE and LE hosts: */
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)
{
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
{
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;
}
/* Check if the X11 window corresponding to a seamless window with
specified id exists. */
{
char *name;
if (!sw)
return False;
if (sts)
{
}
return sts;
}
static int
{
if (g_error_expected)
return 0;
}
/* Initialize the UI. This is done once per process. */
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");
}
xkeymap_init();
if (g_enable_compose)
xclip_init();
ewmh_init();
if (g_seamless_rdp)
{
}
return True;
}
/*
Initialize connection specific data, such as session size.
*/
void
ui_init_connection(void)
{
/*
* Determine desktop size
*/
if (g_fullscreen)
{
}
else if (g_sizeopt < 0)
{
/* Percent of screen */
if (-g_sizeopt >= 100)
}
else if (g_sizeopt == 1)
{
/* 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 */
}
void
ui_deinit(void)
{
xclip_deinit();
if (g_null_cursor != NULL)
}
static void
{
}
static void
{
if (g_sendmotion)
if (g_ownbackstore)
*input_mask |= ExposureMask;
if (g_fullscreen || g_grab_keyboard)
if (g_grab_keyboard)
}
ui_create_window(void)
{
/* 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)
{
}
{
}
#ifdef HAVE_XRANDR
#endif
/* 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)
{
g_wnd = 0;
if (g_backstore)
{
g_backstore = 0;
}
}
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;
}
}
}
/* Ignore mouse scroll button release event which will be handled as an additional
* scrolldown event on the Windows side.
*/
{
return;
}
{
}
else
{
/* SeamlessRDP */
}
}
/* Process events in Xlib queue
Returns 0 after user quit, 1 otherwise */
static int
xwin_process_events(void)
{
int events = 0;
{
if (!g_wnd)
/* Ignore events between ui_destroy_window and ui_create_window */
continue;
/* Also ignore root window events except ConfigureNotify */
continue;
{
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:
#ifdef HAVE_XRANDR
if ((g_sizeopt || g_fullscreen)
{
{
}
}
#endif
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
{
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 */
/* add ctrl slaves handles */
ctrl_add_fds(&n, &rfds);
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
{
}
/* convert next pixel to 32 bpp */
static int
{
int rv = 0;
switch (bpp)
{
case 1:
(*k) += 1;
break;
case 8:
/* should use colour map */
(*k) += 1;
break;
case 15:
(*k) += 1;
break;
case 16:
(*k) += 1;
break;
case 24:
(*k) += 3;
break;
case 32:
(*k) += 4;
break;
default:
break;
}
return rv;
}
{
int i, j, k;
k = 0;
if (bpp == 1)
{
offset = 0;
}
else
{
}
/* approximate AND and XOR masks with a monochrome X pointer */
for (i = 0; i < height; i++)
{
for (j = 0; j < scanline; j++)
{
{
{
}
else
{
}
}
andmask++;
pcursor++;
pmask++;
}
}
xcursor =
return (RD_HCURSOR) xcursor;
}
void
{
}
void
{
}
void
ui_set_null_cursor(void)
{
}
{
if (!g_owncolmap)
{
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
{
}
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++)
}
{
}
else
{
}
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++)
}
{
}
else
{
}
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++)
}
{
}
else
{
}
break;
default:
}
}
/* warning, this function only draws on wnd or backstore, not both */
void
{
}
{\
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)
if (g_seamless_spawn_cmd[0])
{
g_seamless_spawn_cmd[0] = 0;
}
}
void
{
/* Destroy all seamless windows */
while (g_seamless_windows)
{
}
}
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;
unsigned int value_mask;
if (!g_seamless_active)
return;
if (!sw)
{
return;
}
if (behind)
{
if (!sw_behind)
{
return;
}
/* Avoid that topmost windows references non-topmost
windows, and vice versa. */
{
{
/* Disallow, move to bottom of the
topmost stack. */
}
}
else
{
{
/* Move to top of non-topmost
stack. */
}
}
}
else
{
}
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
{
if (!g_seamless_active)
return;
/* Destroy all seamless windows */
while (g_seamless_windows)
{
}
}
void
{
{
{
/* 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;
}
}
}