diff --git a/constants.h b/constants.h index 5958d35..41b38b9 100644 --- a/constants.h +++ b/constants.h @@ -418,3 +418,4 @@ enum RDP_INPUT_DEVICE #define SEAMLESSRDP_NORMAL 0 #define SEAMLESSRDP_MINIMIZED 1 #define SEAMLESSRDP_MAXIMIZED 2 +#define SEAMLESSRDP_POSITION_TIMER 200000 diff --git a/proto.h b/proto.h index 6ac2416..da65a94 100644 --- a/proto.h +++ b/proto.h @@ -288,6 +288,9 @@ BOOL lspci_init(void); BOOL seamless_init(void); void seamless_send_sync(void); void seamless_send_state(unsigned long id, unsigned int state, unsigned long flags); +void seamless_send_position(unsigned long id, int x, int y, int width, int height, + unsigned long flags); +void seamless_select_timeout(struct timeval *tv); void seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags); void seamless_send_focus(unsigned long id, unsigned long flags); diff --git a/rdesktop.h b/rdesktop.h index 768d798..a91cee3 100644 --- a/rdesktop.h +++ b/rdesktop.h @@ -67,6 +67,22 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif +/* timeval macros */ +#ifndef timerisset +#define timerisset(tvp)\ + ((tvp)->tv_sec || (tvp)->tv_usec) +#endif +#ifndef timercmp +#define timercmp(tvp, uvp, cmp)\ + ((tvp)->tv_sec cmp (uvp)->tv_sec ||\ + (tvp)->tv_sec == (uvp)->tv_sec &&\ + (tvp)->tv_usec cmp (uvp)->tv_usec) +#endif +#ifndef timerclear +#define timerclear(tvp)\ + ((tvp)->tv_sec = (tvp)->tv_usec = 0) +#endif + /* If configure does not define the endianess, try to find it out */ #if !defined(L_ENDIAN) && !defined(B_ENDIAN) diff --git a/seamless.c b/seamless.c index b407f54..0319eb7 100644 --- a/seamless.c +++ b/seamless.c @@ -339,6 +339,30 @@ seamless_send_state(unsigned long id, unsigned int state, unsigned long flags) } +void +seamless_send_position(unsigned long id, int x, int y, int width, int height, unsigned long flags) +{ + seamless_send("POSITION,0x%08lx,%d,%d,%d,%d,0x%lx\n", id, x, y, width, height, flags); +} + + +/* Update select timeout */ +void +seamless_select_timeout(struct timeval *tv) +{ + struct timeval ourtimeout = { 0, SEAMLESSRDP_POSITION_TIMER }; + + if (g_seamless_rdp) + { + if (timercmp(&ourtimeout, tv, <)) + { + tv->tv_sec = ourtimeout.tv_sec; + tv->tv_usec = ourtimeout.tv_usec; + } + } +} + + void seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags) { diff --git a/xwin.c b/xwin.c index 498e782..c587f54 100644 --- a/xwin.c +++ b/xwin.c @@ -60,6 +60,7 @@ typedef struct _seamless_window int width, height; int state; /* normal/minimized/maximized. */ unsigned int desktop; + struct timeval *position_timer; struct _seamless_window *next; } seamless_window; static seamless_window *g_seamless_windows = NULL; @@ -325,6 +326,45 @@ seamless_all_to_desktop(Window wnd, unsigned int desktop) } +/* Send our position */ +static void +seamless_update_position(seamless_window * sw) +{ + XWindowAttributes wa; + int x, y; + Window child_return; + + XGetWindowAttributes(g_display, sw->wnd, &wa); + XTranslateCoordinates(g_display, sw->wnd, wa.root, + -wa.border_width, -wa.border_width, &x, &y, &child_return); + + seamless_send_position(sw->id, x, y, wa.width, wa.height, 0); + sw->xoffset = x; + sw->yoffset = y; + sw->width = wa.width; + sw->height = wa.height; +} + + +/* Check if it's time to send our position */ +static void +seamless_check_timers() +{ + seamless_window *sw; + struct timeval now; + + gettimeofday(&now, NULL); + for (sw = g_seamless_windows; sw; sw = sw->next) + { + if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <)) + { + timerclear(sw->position_timer); + seamless_update_position(sw); + } + } +} + + static void seamless_restack_window(seamless_window * sw, unsigned long behind) { @@ -2085,12 +2125,31 @@ xwin_process_events(void) rdp_send_client_window_status(0); break; case ConfigureNotify: - /* seamless */ - sw = seamless_get_window_by_wnd(xevent.xconfigure.window); - if (!sw) + if (!g_seamless_active) break; + sw = seamless_get_window_by_wnd(xevent.xconfigure.window); + if (!sw) + { + error("ConfigureNotify for unknown window 0x%lx\n", + xevent.xconfigure.window); + } + + gettimeofday(sw->position_timer, NULL); + if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >= + 1000000) + { + sw->position_timer->tv_usec += + SEAMLESSRDP_POSITION_TIMER - 1000000; + sw->position_timer->tv_sec += 1; + } + else + { + sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER; + } + ui_seamless_handle_restack(sw); + break; } } /* Keep going */ @@ -2114,6 +2173,9 @@ ui_select(int rdp_socket) /* User quit */ return 0; + if (g_seamless_active) + seamless_check_timers(); + FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(rdp_socket, &rfds); @@ -2133,6 +2195,7 @@ ui_select(int rdp_socket) /* add redirection handles */ rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); + seamless_select_timeout(&tv); n++; @@ -3216,7 +3279,7 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long serverside, instead of terminating rdesktop */ XSetWMProtocols(g_display, wnd, &g_kill_atom, 1); - sw = malloc(sizeof(seamless_window)); + sw = xmalloc(sizeof(seamless_window)); sw->wnd = wnd; sw->id = id; sw->parent = parent; @@ -3227,6 +3290,8 @@ ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long sw->height = 0; sw->state = SEAMLESSRDP_NOTYETMAPPED; sw->desktop = 0; + sw->position_timer = xmalloc(sizeof(struct timeval)); + timerclear(sw->position_timer); sw->next = g_seamless_windows; g_seamless_windows = sw; } @@ -3271,16 +3336,10 @@ ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, u /* X11 windows must be at least 1x1 */ return; - /* About MAX and MIN: Windows allows moving a window outside - the desktop. This happens, for example, when maximizing an - application. In this case, the position is set to something - like -4,-4,1288,1032. Many WMs does not allow windows - outside the desktop, however. Therefore, clip the window - ourselves. */ - sw->xoffset = MAX(0, x); - sw->yoffset = MAX(0, y); - sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset); - sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset); + sw->xoffset = x; + sw->yoffset = y; + sw->width = width; + sw->height = height; /* If we move the window in a maximized state, then KDE won't accept restoration */