--- sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c 2006/03/10 14:09:16 1107 +++ sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c 2006/03/16 08:11:29 1142 @@ -54,8 +54,11 @@ { Window wnd; unsigned long id; + XWMHints *hints; int xoffset, yoffset; int width, height; + int state; /* normal/minimized/maximized. */ + unsigned int desktop; struct _seamless_window *next; } seamless_window; static seamless_window *g_seamless_windows = NULL; @@ -83,6 +86,8 @@ static Cursor g_current_cursor; static HCURSOR g_null_cursor = NULL; static Atom g_protocol_atom, g_kill_atom; +extern Atom g_net_wm_state_atom; +extern Atom g_net_wm_desktop_atom; static BOOL g_focused; static BOOL g_mouse_in_wnd; /* Indicates that: @@ -289,6 +294,7 @@ if (sw == win) { *prevnext = sw->next; + XFree(sw->hints); xfree(sw); return; } @@ -298,6 +304,24 @@ } +/* Move all windows except wnd to new desktop */ +static void +seamless_all_to_desktop(Window wnd, unsigned int desktop) +{ + seamless_window *sw; + for (sw = g_seamless_windows; sw; sw = sw->next) + { + if (sw->wnd == wnd) + continue; + if (sw->desktop != desktop) + { + ewmh_move_to_desktop(sw->wnd, desktop); + sw->desktop = desktop; + } + } +} + + static void mwm_hide_decorations(Window wnd) { @@ -1396,6 +1420,7 @@ g_IM = XOpenIM(g_display, NULL, NULL, NULL); xclip_init(); + ewmh_init(); if (g_seamless_rdp) seamless_init(); @@ -1938,6 +1963,30 @@ break; case PropertyNotify: xclip_handle_PropertyNotify(&xevent.xproperty); + if (xevent.xproperty.window == g_wnd) + break; + if (xevent.xproperty.window == DefaultRootWindow(g_display)) + break; + + /* seamless */ + sw = seamless_get_window_by_wnd(xevent.xproperty.window); + if (!sw) + break; + + if ((xevent.xproperty.atom == g_net_wm_state_atom) + && (xevent.xproperty.state == PropertyNewValue)) + { + sw->state = ewmh_get_window_state(sw->wnd); + seamless_send_state(sw->id, sw->state, 0); + } + + if ((xevent.xproperty.atom == g_net_wm_desktop_atom) + && (xevent.xproperty.state == PropertyNewValue)) + { + sw->desktop = ewmh_get_window_desktop(sw->wnd); + seamless_all_to_desktop(sw->wnd, sw->desktop); + } + break; case MapNotify: if (!g_seamless_rdp) @@ -2997,35 +3046,51 @@ Window wnd; XSetWindowAttributes attribs; XClassHint *classhints; + XSizeHints *sizehints; long input_mask; seamless_window *sw, *sw_parent; - get_window_attribs(&attribs); + /* Ignore CREATEs for existing windows */ + sw = seamless_get_window_by_id(id); + if (sw) + return; + get_window_attribs(&attribs); attribs.override_redirect = False; - /* FIXME: Do not assume that -1, -1 is outside screen Consider - wait with showing the window until STATE and others have - been recieved. */ - wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0, + wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth, InputOutput, g_visual, CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | CWBorderPixel, &attribs); - XStoreName(g_display, wnd, "rdesktop-seamless"); + XStoreName(g_display, wnd, "SeamlessRDP"); + ewmh_set_wm_name(wnd, "SeamlessRDP"); mwm_hide_decorations(wnd); classhints = XAllocClassHint(); if (classhints != NULL) { - classhints->res_name = classhints->res_class = "rdesktop"; + classhints->res_name = "rdesktop"; + classhints->res_class = "SeamlessRDP"; XSetClassHint(g_display, wnd, classhints); XFree(classhints); } + /* WM_NORMAL_HINTS */ + sizehints = XAllocSizeHints(); + if (sizehints != NULL) + { + sizehints->flags = USPosition; + XSetWMNormalHints(g_display, wnd, sizehints); + XFree(sizehints); + } + + /* Handle popups without parents through some ewm hints */ + if (parent == 0xFFFFFFFF) + ewmh_set_window_popup(wnd); /* Set WM_TRANSIENT_FOR, if necessary */ - if (parent) + else if (parent != 0x00000000) { sw_parent = seamless_get_window_by_id(parent); if (sw_parent) @@ -3034,14 +3099,14 @@ warning("ui_seamless_create_window: No parent window 0x%lx\n", parent); } + /* FIXME: Support for Input Context:s */ get_input_mask(&input_mask); + input_mask |= PropertyChangeMask; XSelectInput(g_display, wnd, input_mask); - XMapWindow(g_display, wnd); - /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a seamless window, we could try to close the window on the serverside, instead of terminating rdesktop */ @@ -3050,10 +3115,14 @@ sw = malloc(sizeof(seamless_window)); sw->wnd = wnd; sw->id = id; + sw->hints = XAllocWMHints(); + sw->hints->flags = 0; sw->xoffset = 0; sw->yoffset = 0; sw->width = 0; sw->height = 0; + sw->state = SEAMLESSRDP_NOTYETMAPPED; + sw->desktop = 0; sw->next = g_seamless_windows; g_seamless_windows = sw; } @@ -3103,6 +3172,15 @@ sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset); sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset); + /* If we move the window in a maximized state, then KDE won't + accept restoration */ + switch (sw->state) + { + case SEAMLESSRDP_MINIMIZED: + case SEAMLESSRDP_MAXIMIZED: + return; + } + /* FIXME: Perhaps use ewmh_net_moveresize_window instead */ XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height); } @@ -3120,7 +3198,9 @@ return; } + /* FIXME: Might want to convert the name for non-EWMH WMs */ XStoreName(g_display, sw->wnd, title); + ewmh_set_wm_name(sw->wnd, title); } @@ -3140,13 +3220,41 @@ { case SEAMLESSRDP_NORMAL: case SEAMLESSRDP_MAXIMIZED: + ewmh_change_state(sw->wnd, state); XMapWindow(g_display, sw->wnd); break; case SEAMLESSRDP_MINIMIZED: - XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display)); + /* 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 (sw->state == SEAMLESSRDP_NOTYETMAPPED) + { + sw->hints->flags |= StateHint; + sw->hints->initial_state = IconicState; + XSetWMHints(g_display, sw->wnd, sw->hints); + XMapWindow(g_display, sw->wnd); + } + else + XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display)); break; default: warning("SeamlessRDP: Invalid state %d\n", state); break; } + + sw->state = state; +} + + +void +ui_seamless_syncbegin(unsigned long flags) +{ + /* Destroy all seamless windows */ + while (g_seamless_windows) + { + XDestroyWindow(g_display, g_seamless_windows->wnd); + seamless_remove_window(g_seamless_windows); + } }