Implement support for icons in SeamlessRDP.
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@1412 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
fda4c63c95
commit
81a75745cb
@ -5,8 +5,6 @@ TODO
|
||||
|
||||
* Commands for changing z order and focus.
|
||||
|
||||
* Command for transferring icon.
|
||||
|
||||
* Think about protocol version management
|
||||
|
||||
* Try to assure that messages aren't repeated or are sent for hidden windows.
|
||||
@ -237,6 +235,49 @@ This message is sent some time after a HIDE, indicating that the windowed view
|
||||
has been restored. If the client has dropped all information about windows then
|
||||
it can send a SYNC to re-enumerate them.
|
||||
|
||||
SETICON
|
||||
-------
|
||||
|
||||
Sets an icon for a window.
|
||||
|
||||
Syntax:
|
||||
SETICON,<SERIAL>,<ID>,<CHUNK>,<FORMAT>,<WIDTH>,<HEIGHT>,<DATA>
|
||||
|
||||
This message is sent when a window is initially created and at any time when
|
||||
the application modifies its icon.
|
||||
|
||||
A window can have multiple icons, but only one of a given format and size. A
|
||||
SETICON received for an already existing format and size is expected to over-
|
||||
write that icon.
|
||||
|
||||
Since icons can potentially be very large, it can easily overflow the line
|
||||
limitation in the protocol. To handle this, multiple SETICON will be issued
|
||||
with an ever increasing chunk number.
|
||||
|
||||
The initial chunk is 0 (zero) and all chunks must be sent in order. Multiple
|
||||
SETICON sets for the same window may not interleave. SETICON sets for
|
||||
different windows may interleave though.
|
||||
|
||||
Formats:
|
||||
RGBA : Four bytes of data per pixel, representing red, green, blue and
|
||||
alpha, in that order.
|
||||
|
||||
Data is the raw icon data written in hex (e.g. 3fab32...). Chunks must be
|
||||
divided on a whole byte boundary. Case is not specified.
|
||||
|
||||
DELICON
|
||||
-------
|
||||
|
||||
Removes an icon for a window.
|
||||
|
||||
Syntax:
|
||||
DELICON,<SERIAL>,<ID>,<FORMAT>,<WIDTH>,<HEIGHT>
|
||||
|
||||
Removes the icon of a window matching the given format and size, previously
|
||||
set with SETICON.
|
||||
|
||||
This command may not be interleaved with a SETICON set.
|
||||
|
||||
Client to Server Operations
|
||||
===========================
|
||||
|
||||
|
114
ewmhints.c
114
ewmhints.c
@ -4,7 +4,8 @@
|
||||
Support functions for Extended Window Manager Hints,
|
||||
http://www.freedesktop.org/wiki/Standards_2fwm_2dspec
|
||||
|
||||
Copyright (C) Peter Astrand <astrand@cendio.se> 2005
|
||||
Copyright 2005 Peter Astrand <astrand@cendio.se> for Cendio AB
|
||||
Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
|
||||
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
|
||||
@ -34,7 +35,8 @@ extern Display *g_display;
|
||||
|
||||
static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom,
|
||||
g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom,
|
||||
g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom, g_net_wm_state_modal_atom;
|
||||
g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom,
|
||||
g_net_wm_state_modal_atom, g_net_wm_icon_atom;
|
||||
|
||||
Atom g_net_wm_state_atom, g_net_wm_desktop_atom;
|
||||
|
||||
@ -187,6 +189,7 @@ ewmh_init()
|
||||
g_net_wm_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False);
|
||||
g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False);
|
||||
g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False);
|
||||
g_net_wm_icon_atom = XInternAtom(g_display, "_NET_WM_ICON", False);
|
||||
g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
|
||||
}
|
||||
|
||||
@ -423,6 +426,113 @@ ewmh_set_window_modal(Window wnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data)
|
||||
{
|
||||
unsigned long nitems, i;
|
||||
unsigned char *props;
|
||||
uint32 *cur_set, *new_set;
|
||||
uint32 *icon;
|
||||
|
||||
cur_set = NULL;
|
||||
new_set = NULL;
|
||||
|
||||
if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) >= 0)
|
||||
{
|
||||
cur_set = (uint32 *) props;
|
||||
|
||||
for (i = 0; i < nitems;)
|
||||
{
|
||||
if (cur_set[i] == width && cur_set[i + 1] == height)
|
||||
break;
|
||||
|
||||
i += 2 + cur_set[i] * cur_set[i + 1];
|
||||
}
|
||||
|
||||
if (i != nitems)
|
||||
icon = cur_set + i;
|
||||
else
|
||||
{
|
||||
new_set = xmalloc((nitems + width * height + 2) * 4);
|
||||
memcpy(new_set, cur_set, nitems * 4);
|
||||
icon = new_set + nitems;
|
||||
nitems += width * height + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_set = xmalloc((width * height + 2) * 4);
|
||||
icon = new_set;
|
||||
nitems = width * height + 2;
|
||||
}
|
||||
|
||||
icon[0] = width;
|
||||
icon[1] = height;
|
||||
|
||||
/* Convert RGBA -> ARGB */
|
||||
for (i = 0; i < width * height; i++)
|
||||
{
|
||||
icon[i + 2] =
|
||||
rgba_data[i * 4 + 3] << 24 |
|
||||
((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
|
||||
((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
|
||||
((rgba_data[i * 4 + 2] << 0) & 0x000000FF);
|
||||
}
|
||||
|
||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char *) (new_set ? new_set : cur_set), nitems);
|
||||
|
||||
if (cur_set)
|
||||
XFree(cur_set);
|
||||
if (new_set)
|
||||
xfree(new_set);
|
||||
}
|
||||
|
||||
void
|
||||
ewmh_del_icon(Window wnd, int width, int height)
|
||||
{
|
||||
unsigned long nitems, i, icon_size;
|
||||
unsigned char *props;
|
||||
uint32 *cur_set, *new_set;
|
||||
|
||||
cur_set = NULL;
|
||||
new_set = NULL;
|
||||
|
||||
if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) < 0)
|
||||
return;
|
||||
|
||||
cur_set = (uint32 *) props;
|
||||
|
||||
for (i = 0; i < nitems;)
|
||||
{
|
||||
if (cur_set[i] == width && cur_set[i + 1] == height)
|
||||
break;
|
||||
|
||||
i += 2 + cur_set[i] * cur_set[i + 1];
|
||||
}
|
||||
|
||||
if (i == nitems)
|
||||
goto out;
|
||||
|
||||
icon_size = width * height + 2;
|
||||
new_set = xmalloc((nitems - icon_size) * 4);
|
||||
|
||||
if (i != 0)
|
||||
memcpy(new_set, cur_set, i * 4);
|
||||
if (i != nitems - icon_size)
|
||||
memcpy(new_set + i * 4, cur_set + i * 4 + icon_size, nitems - icon_size);
|
||||
|
||||
nitems -= icon_size;
|
||||
|
||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char *) new_set, nitems);
|
||||
|
||||
xfree(new_set);
|
||||
|
||||
out:
|
||||
XFree(cur_set);
|
||||
}
|
||||
|
||||
#endif /* MAKE_PROTO */
|
||||
|
||||
|
||||
|
8
proto.h
8
proto.h
@ -288,6 +288,9 @@ void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned l
|
||||
unsigned long flags);
|
||||
void ui_seamless_destroy_window(unsigned long id, unsigned long flags);
|
||||
void ui_seamless_destroy_group(unsigned long id, unsigned long flags);
|
||||
void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
|
||||
const char *data, int chunk_len);
|
||||
void ui_seamless_delicon(unsigned long id, const char *format, int width, int height);
|
||||
void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height,
|
||||
unsigned long flags);
|
||||
void ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags);
|
||||
@ -307,13 +310,8 @@ void seamless_select_timeout(struct timeval *tv);
|
||||
unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags);
|
||||
unsigned int seamless_send_focus(unsigned long id, unsigned long flags);
|
||||
/* scard.c */
|
||||
void scardSetInfo(uint32 device, uint32 id, uint32 bytes_out);
|
||||
int scard_enum_devices(uint32 * id, char *optarg);
|
||||
void scard_lock(int lock);
|
||||
void scard_unlock(int lock);
|
||||
STREAM scard_tcp_init(void);
|
||||
void scard_tcp_connect(void);
|
||||
void scard_tcp_reset_state(void);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
|
64
seamless.c
64
seamless.c
@ -1,7 +1,8 @@
|
||||
/* -*- c-basic-offset: 8 -*-
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
Seamless Windows support
|
||||
Copyright (C) Peter Astrand <astrand@cendio.se> 2005-2007
|
||||
Copyright 2005-2007 Peter Astrand <astrand@cendio.se> for Cendio AB
|
||||
Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
|
||||
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
|
||||
@ -31,6 +32,7 @@
|
||||
extern RD_BOOL g_seamless_rdp;
|
||||
static VCHANNEL *seamless_channel;
|
||||
static unsigned int seamless_serial;
|
||||
static char icon_buf[1024];
|
||||
|
||||
static char *
|
||||
seamless_get_token(char **s)
|
||||
@ -135,7 +137,65 @@ seamless_process_line(const char *line, void *data)
|
||||
}
|
||||
else if (!strcmp("SETICON", tok1))
|
||||
{
|
||||
unimpl("SeamlessRDP SETICON1\n");
|
||||
int chunk, width, height, len;
|
||||
char byte[3];
|
||||
|
||||
if (!tok8)
|
||||
return False;
|
||||
|
||||
id = strtoul(tok3, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
chunk = strtoul(tok4, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
width = strtoul(tok6, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
height = strtoul(tok7, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
byte[2] = '\0';
|
||||
len = 0;
|
||||
while (*tok8 != '\0')
|
||||
{
|
||||
byte[0] = *tok8;
|
||||
tok8++;
|
||||
if (*tok8 == '\0')
|
||||
return False;
|
||||
byte[1] = *tok8;
|
||||
tok8++;
|
||||
|
||||
icon_buf[len] = strtol(byte, NULL, 16);
|
||||
len++;
|
||||
}
|
||||
|
||||
ui_seamless_seticon(id, tok5, width, height, chunk, icon_buf, len);
|
||||
}
|
||||
else if (!strcmp("DELICON", tok1))
|
||||
{
|
||||
int width, height;
|
||||
|
||||
if (!tok6)
|
||||
return False;
|
||||
|
||||
id = strtoul(tok3, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
width = strtoul(tok5, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
height = strtoul(tok6, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
ui_seamless_delicon(id, tok4, width, height);
|
||||
}
|
||||
else if (!strcmp("POSITION", tok1))
|
||||
{
|
||||
|
2
xproto.h
2
xproto.h
@ -9,3 +9,5 @@ int ewmh_get_window_desktop(Window wnd);
|
||||
void ewmh_set_wm_name(Window wnd, const char *title);
|
||||
int ewmh_set_window_popup(Window wnd);
|
||||
int ewmh_set_window_modal(Window wnd);
|
||||
void ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data);
|
||||
void ewmh_del_icon(Window wnd, int width, int height);
|
||||
|
100
xwin.c
100
xwin.c
@ -2,6 +2,7 @@
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
User interface services - X Window System
|
||||
Copyright (C) Matthew Chapman 1999-2007
|
||||
Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
|
||||
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
|
||||
@ -74,6 +75,10 @@ typedef struct _seamless_window
|
||||
int outpos_xoffset, outpos_yoffset;
|
||||
int outpos_width, outpos_height;
|
||||
|
||||
unsigned int icon_size;
|
||||
unsigned int icon_offset;
|
||||
char icon_buffer[32 * 32 * 4];
|
||||
|
||||
struct _seamless_window *next;
|
||||
} seamless_window;
|
||||
static seamless_window *g_seamless_windows = NULL;
|
||||
@ -3452,15 +3457,13 @@ ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long p
|
||||
XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
|
||||
|
||||
sw = xmalloc(sizeof(seamless_window));
|
||||
|
||||
memset(sw, 0, sizeof(seamless_window));
|
||||
|
||||
sw->wnd = wnd;
|
||||
sw->id = id;
|
||||
sw->behind = 0;
|
||||
sw->group = sw_find_group(group, False);
|
||||
sw->group->refcnt++;
|
||||
sw->xoffset = 0;
|
||||
sw->yoffset = 0;
|
||||
sw->width = 0;
|
||||
sw->height = 0;
|
||||
sw->state = SEAMLESSRDP_NOTYETMAPPED;
|
||||
sw->desktop = 0;
|
||||
sw->position_timer = xmalloc(sizeof(struct timeval));
|
||||
@ -3527,6 +3530,93 @@ ui_seamless_destroy_group(unsigned long id, unsigned long flags)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
|
||||
const char *data, int chunk_len)
|
||||
{
|
||||
seamless_window *sw;
|
||||
|
||||
if (!g_seamless_active)
|
||||
return;
|
||||
|
||||
sw = sw_get_window_by_id(id);
|
||||
if (!sw)
|
||||
{
|
||||
warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk == 0)
|
||||
{
|
||||
if (sw->icon_size)
|
||||
warning("ui_seamless_seticon: New icon started before previous completed\n");
|
||||
|
||||
if (strcmp(format, "RGBA") != 0)
|
||||
{
|
||||
warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
|
||||
return;
|
||||
}
|
||||
|
||||
sw->icon_size = width * height * 4;
|
||||
if (sw->icon_size > 32 * 32 * 4)
|
||||
{
|
||||
warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
|
||||
sw->icon_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sw->icon_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sw->icon_size)
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk_len > (sw->icon_size - sw->icon_offset))
|
||||
{
|
||||
warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
|
||||
chunk_len, sw->icon_size - sw->icon_offset);
|
||||
sw->icon_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
|
||||
sw->icon_offset += chunk_len;
|
||||
|
||||
if (sw->icon_offset == sw->icon_size)
|
||||
{
|
||||
ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
|
||||
sw->icon_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
|
||||
{
|
||||
seamless_window *sw;
|
||||
|
||||
if (!g_seamless_active)
|
||||
return;
|
||||
|
||||
sw = sw_get_window_by_id(id);
|
||||
if (!sw)
|
||||
{
|
||||
warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(format, "RGBA") != 0)
|
||||
{
|
||||
warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
|
||||
return;
|
||||
}
|
||||
|
||||
ewmh_del_icon(sw->wnd, width, height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user