Support for window groups and modal windows.
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/branches/seamlessrdp-branch/rdesktop@1176 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
acec377e87
commit
8b98524485
@ -419,3 +419,5 @@ enum RDP_INPUT_DEVICE
|
||||
#define SEAMLESSRDP_MINIMIZED 1
|
||||
#define SEAMLESSRDP_MAXIMIZED 2
|
||||
#define SEAMLESSRDP_POSITION_TIMER 200000
|
||||
|
||||
#define SEAMLESSRDP_CREATE_MODAL 0x0001
|
||||
|
11
ewmhints.c
11
ewmhints.c
@ -34,7 +34,7 @@ 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_skip_taskbar_atom, g_net_wm_state_skip_pager_atom, g_net_wm_state_modal_atom;
|
||||
|
||||
Atom g_net_wm_state_atom, g_net_wm_desktop_atom;
|
||||
|
||||
@ -183,6 +183,7 @@ ewmh_init()
|
||||
g_net_wm_state_skip_taskbar_atom =
|
||||
XInternAtom(g_display, "_NET_WM_STATE_SKIP_TASKBAR", False);
|
||||
g_net_wm_state_skip_pager_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_PAGER", False);
|
||||
g_net_wm_state_modal_atom = XInternAtom(g_display, "_NET_WM_STATE_MODAL", 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_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False);
|
||||
@ -405,6 +406,14 @@ ewmh_set_window_popup(Window wnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ewmh_set_window_modal(Window wnd)
|
||||
{
|
||||
if (ewmh_modify_state(wnd, 1, g_net_wm_state_modal_atom, 0) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* MAKE_PROTO */
|
||||
|
||||
|
||||
|
3
proto.h
3
proto.h
@ -274,7 +274,8 @@ void ui_begin_update(void);
|
||||
void ui_end_update(void);
|
||||
void ui_seamless_begin(void);
|
||||
void ui_seamless_toggle(void);
|
||||
void ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags);
|
||||
void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
|
||||
unsigned long flags);
|
||||
void ui_seamless_destroy_window(unsigned long id, unsigned long flags);
|
||||
void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height,
|
||||
unsigned long flags);
|
||||
|
14
seamless.c
14
seamless.c
@ -82,23 +82,27 @@ seamless_process_line(const char *line, void *data)
|
||||
|
||||
if (!strcmp("CREATE", tok1))
|
||||
{
|
||||
unsigned long parent;
|
||||
if (!tok5)
|
||||
unsigned long group, parent;
|
||||
if (!tok6)
|
||||
return False;
|
||||
|
||||
id = strtoul(tok3, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
parent = strtoul(tok4, &endptr, 0);
|
||||
group = strtoul(tok4, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
flags = strtoul(tok5, &endptr, 0);
|
||||
parent = strtoul(tok5, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
ui_seamless_create_window(id, parent, flags);
|
||||
flags = strtoul(tok6, &endptr, 0);
|
||||
if (*endptr)
|
||||
return False;
|
||||
|
||||
ui_seamless_create_window(id, group, parent, flags);
|
||||
}
|
||||
else if (!strcmp("DESTROY", tok1))
|
||||
{
|
||||
|
1
xproto.h
1
xproto.h
@ -8,3 +8,4 @@ int ewmh_move_to_desktop(Window wnd, unsigned int desktop);
|
||||
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);
|
||||
|
103
xwin.c
103
xwin.c
@ -28,6 +28,9 @@
|
||||
#include "rdesktop.h"
|
||||
#include "xproto.h"
|
||||
|
||||
/* We can't include Xproto.h because of conflicting defines for BOOL */
|
||||
#define X_ConfigureWindow 12
|
||||
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
extern int g_xpos;
|
||||
@ -50,11 +53,18 @@ static Screen *g_screen;
|
||||
Window g_wnd;
|
||||
|
||||
/* SeamlessRDP support */
|
||||
typedef struct _seamless_group
|
||||
{
|
||||
Window wnd;
|
||||
unsigned long id;
|
||||
unsigned int refcnt;
|
||||
} seamless_group;
|
||||
typedef struct _seamless_window
|
||||
{
|
||||
Window wnd;
|
||||
unsigned long id;
|
||||
unsigned long behind;
|
||||
seamless_group *group;
|
||||
int xoffset, yoffset;
|
||||
int width, height;
|
||||
int state; /* normal/minimized/maximized. */
|
||||
@ -304,6 +314,12 @@ sw_remove_window(seamless_window * win)
|
||||
if (sw == win)
|
||||
{
|
||||
*prevnext = sw->next;
|
||||
sw->group->refcnt--;
|
||||
if (sw->group->refcnt == 0)
|
||||
{
|
||||
XDestroyWindow(g_display, sw->group->wnd);
|
||||
xfree(sw->group);
|
||||
}
|
||||
xfree(sw);
|
||||
return;
|
||||
}
|
||||
@ -453,6 +469,35 @@ sw_handle_restack(seamless_window * sw)
|
||||
}
|
||||
|
||||
|
||||
static seamless_group *
|
||||
sw_find_group(unsigned long id, BOOL dont_create)
|
||||
{
|
||||
seamless_window *sw;
|
||||
seamless_group *sg;
|
||||
XSetWindowAttributes attribs;
|
||||
|
||||
for (sw = g_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(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
|
||||
CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
|
||||
|
||||
sg->id = id;
|
||||
sg->refcnt = 0;
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mwm_hide_decorations(Window wnd)
|
||||
{
|
||||
@ -1450,6 +1495,22 @@ select_visual()
|
||||
return True;
|
||||
}
|
||||
|
||||
static XErrorHandler g_old_error_handler;
|
||||
|
||||
static int
|
||||
error_handler(Display * dpy, XErrorEvent * eev)
|
||||
{
|
||||
if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
|
||||
{
|
||||
fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
|
||||
fprintf(stderr,
|
||||
"This is most likely caused by a broken window manager (commonly KWin).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_old_error_handler(dpy, eev);
|
||||
}
|
||||
|
||||
BOOL
|
||||
ui_init(void)
|
||||
{
|
||||
@ -1467,6 +1528,8 @@ ui_init(void)
|
||||
g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
|
||||
}
|
||||
|
||||
g_old_error_handler = XSetErrorHandler(error_handler);
|
||||
|
||||
g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
|
||||
screen_num = DefaultScreen(g_display);
|
||||
g_x_socket = ConnectionNumber(g_display);
|
||||
@ -3222,12 +3285,14 @@ ui_seamless_toggle()
|
||||
|
||||
|
||||
void
|
||||
ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
|
||||
ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
|
||||
unsigned long flags)
|
||||
{
|
||||
Window wnd;
|
||||
XSetWindowAttributes attribs;
|
||||
XClassHint *classhints;
|
||||
XSizeHints *sizehints;
|
||||
XWMHints *wmhints;
|
||||
long input_mask;
|
||||
seamless_window *sw, *sw_parent;
|
||||
|
||||
@ -3267,10 +3332,15 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long
|
||||
XFree(sizehints);
|
||||
}
|
||||
|
||||
/* Handle popups without parents through some ewm hints */
|
||||
/* Parent-less transient windows */
|
||||
if (parent == 0xFFFFFFFF)
|
||||
{
|
||||
XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
|
||||
/* Some buggy wm:s (kwin) do not handle the above, so fake it
|
||||
using some other hints. */
|
||||
ewmh_set_window_popup(wnd);
|
||||
/* Set WM_TRANSIENT_FOR, if necessary */
|
||||
}
|
||||
/* Normal transient windows */
|
||||
else if (parent != 0x00000000)
|
||||
{
|
||||
sw_parent = sw_get_window_by_id(parent);
|
||||
@ -3280,6 +3350,14 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long
|
||||
warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
|
||||
}
|
||||
|
||||
if (flags & SEAMLESSRDP_CREATE_MODAL)
|
||||
{
|
||||
/* We do this to support buggy wm:s (*cough* metacity *cough*)
|
||||
somewhat at least */
|
||||
if (parent == 0x00000000)
|
||||
XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
|
||||
ewmh_set_window_modal(wnd);
|
||||
}
|
||||
|
||||
/* FIXME: Support for Input Context:s */
|
||||
|
||||
@ -3297,6 +3375,8 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long
|
||||
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;
|
||||
@ -3313,6 +3393,16 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long
|
||||
|
||||
sw->next = g_seamless_windows;
|
||||
g_seamless_windows = sw;
|
||||
|
||||
/* WM_HINTS */
|
||||
wmhints = XAllocWMHints();
|
||||
if (wmhints)
|
||||
{
|
||||
wmhints->flags = WindowGroupHint;
|
||||
wmhints->window_group = sw->group->wnd;
|
||||
XSetWMHints(g_display, sw->wnd, wmhints);
|
||||
XFree(wmhints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3472,11 +3562,14 @@ ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
|
||||
if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
|
||||
{
|
||||
XWMHints *hints;
|
||||
hints = XAllocWMHints();
|
||||
hints->flags = StateHint;
|
||||
hints = XGetWMHints(g_display, sw->wnd);
|
||||
if (hints)
|
||||
{
|
||||
hints->flags |= StateHint;
|
||||
hints->initial_state = IconicState;
|
||||
XSetWMHints(g_display, sw->wnd, hints);
|
||||
XFree(hints);
|
||||
}
|
||||
XMapWindow(g_display, sw->wnd);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user