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:
Pierre Ossman 2007-06-18 12:00:34 +00:00
parent fda4c63c95
commit 81a75745cb
6 changed files with 317 additions and 16 deletions

View File

@ -5,8 +5,6 @@ TODO
* Commands for changing z order and focus. * Commands for changing z order and focus.
* Command for transferring icon.
* Think about protocol version management * Think about protocol version management
* Try to assure that messages aren't repeated or are sent for hidden windows. * 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 has been restored. If the client has dropped all information about windows then
it can send a SYNC to re-enumerate them. 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 Client to Server Operations
=========================== ===========================

View File

@ -4,7 +4,8 @@
Support functions for Extended Window Manager Hints, Support functions for Extended Window Manager Hints,
http://www.freedesktop.org/wiki/Standards_2fwm_2dspec 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 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 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, 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_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; 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_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False);
g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", 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_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); g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
} }
@ -423,6 +426,113 @@ ewmh_set_window_modal(Window wnd)
return 0; 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 */ #endif /* MAKE_PROTO */

View File

@ -288,6 +288,9 @@ void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned l
unsigned long flags); unsigned long flags);
void ui_seamless_destroy_window(unsigned long id, 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_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, void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height,
unsigned long flags); unsigned long flags);
void ui_seamless_restack_window(unsigned long id, unsigned long behind, 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_zchange(unsigned long id, unsigned long below, unsigned long flags);
unsigned int seamless_send_focus(unsigned long id, unsigned long flags); unsigned int seamless_send_focus(unsigned long id, unsigned long flags);
/* scard.c */ /* 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_lock(int lock);
void scard_unlock(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* */ /* *INDENT-OFF* */
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1,7 +1,8 @@
/* -*- c-basic-offset: 8 -*- /* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client. rdesktop: A Remote Desktop Protocol client.
Seamless Windows support 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 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 it under the terms of the GNU General Public License as published by
@ -31,6 +32,7 @@
extern RD_BOOL g_seamless_rdp; extern RD_BOOL g_seamless_rdp;
static VCHANNEL *seamless_channel; static VCHANNEL *seamless_channel;
static unsigned int seamless_serial; static unsigned int seamless_serial;
static char icon_buf[1024];
static char * static char *
seamless_get_token(char **s) seamless_get_token(char **s)
@ -135,7 +137,65 @@ seamless_process_line(const char *line, void *data)
} }
else if (!strcmp("SETICON", tok1)) 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)) else if (!strcmp("POSITION", tok1))
{ {

View File

@ -9,3 +9,5 @@ int ewmh_get_window_desktop(Window wnd);
void ewmh_set_wm_name(Window wnd, const char *title); void ewmh_set_wm_name(Window wnd, const char *title);
int ewmh_set_window_popup(Window wnd); int ewmh_set_window_popup(Window wnd);
int ewmh_set_window_modal(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
View File

@ -2,6 +2,7 @@
rdesktop: A Remote Desktop Protocol client. rdesktop: A Remote Desktop Protocol client.
User interface services - X Window System User interface services - X Window System
Copyright (C) Matthew Chapman 1999-2007 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 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 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_xoffset, outpos_yoffset;
int outpos_width, outpos_height; int outpos_width, outpos_height;
unsigned int icon_size;
unsigned int icon_offset;
char icon_buffer[32 * 32 * 4];
struct _seamless_window *next; struct _seamless_window *next;
} seamless_window; } seamless_window;
static seamless_window *g_seamless_windows = NULL; 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); XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
sw = xmalloc(sizeof(seamless_window)); sw = xmalloc(sizeof(seamless_window));
memset(sw, 0, sizeof(seamless_window));
sw->wnd = wnd; sw->wnd = wnd;
sw->id = id; sw->id = id;
sw->behind = 0;
sw->group = sw_find_group(group, False); sw->group = sw_find_group(group, False);
sw->group->refcnt++; sw->group->refcnt++;
sw->xoffset = 0;
sw->yoffset = 0;
sw->width = 0;
sw->height = 0;
sw->state = SEAMLESSRDP_NOTYETMAPPED; sw->state = SEAMLESSRDP_NOTYETMAPPED;
sw->desktop = 0; sw->desktop = 0;
sw->position_timer = xmalloc(sizeof(struct timeval)); 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 void
ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags) ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
{ {