/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1101 by astrand, Fri Mar 10 12:56:38 2006 UTC revision 1193 by ossman_, Wed Mar 22 16:20:55 2006 UTC
# Line 28  Line 28 
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31    /* We can't include Xproto.h because of conflicting defines for BOOL */
32    #define X_ConfigureWindow              12
33    
34  extern int g_width;  extern int g_width;
35  extern int g_height;  extern int g_height;
36  extern int g_xpos;  extern int g_xpos;
# Line 50  static Screen *g_screen; Line 53  static Screen *g_screen;
53  Window g_wnd;  Window g_wnd;
54    
55  /* SeamlessRDP support */  /* SeamlessRDP support */
56    typedef struct _seamless_group
57    {
58            Window wnd;
59            unsigned long id;
60            unsigned int refcnt;
61    } seamless_group;
62  typedef struct _seamless_window  typedef struct _seamless_window
63  {  {
64          Window wnd;          Window wnd;
65          unsigned long id;          unsigned long id;
66            unsigned long behind;
67            seamless_group *group;
68          int xoffset, yoffset;          int xoffset, yoffset;
69          int width, height;          int width, height;
70            int state;              /* normal/minimized/maximized. */
71            unsigned int desktop;
72            struct timeval *position_timer;
73    
74            BOOL outstanding_position;
75            unsigned int outpos_serial;
76            int outpos_xoffset, outpos_yoffset;
77            int outpos_width, outpos_height;
78    
79          struct _seamless_window *next;          struct _seamless_window *next;
80  } seamless_window;  } seamless_window;
81  static seamless_window *g_seamless_windows = NULL;  static seamless_window *g_seamless_windows = NULL;
82    static unsigned long g_seamless_focused = 0;
83    static BOOL g_seamless_started = False; /* Server end is up and running */
84    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
85    static BOOL g_seamless_hidden = False;  /* Desktop is hidden on server */
86  extern BOOL g_seamless_rdp;  extern BOOL g_seamless_rdp;
87    
88  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
# Line 83  static XModifierKeymap *g_mod_map; Line 107  static XModifierKeymap *g_mod_map;
107  static Cursor g_current_cursor;  static Cursor g_current_cursor;
108  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
109  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
110    extern Atom g_net_wm_state_atom;
111    extern Atom g_net_wm_desktop_atom;
112  static BOOL g_focused;  static BOOL g_focused;
113  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
114  /* Indicates that:  /* Indicates that:
# Line 255  static int rop2_map[] = { Line 281  static int rop2_map[] = {
281  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
282    
283  static seamless_window *  static seamless_window *
284  seamless_get_window_by_id(unsigned long id)  sw_get_window_by_id(unsigned long id)
285  {  {
286          seamless_window *sw;          seamless_window *sw;
287          for (sw = g_seamless_windows; sw; sw = sw->next)          for (sw = g_seamless_windows; sw; sw = sw->next)
# Line 268  seamless_get_window_by_id(unsigned long Line 294  seamless_get_window_by_id(unsigned long
294    
295    
296  static seamless_window *  static seamless_window *
297  seamless_get_window_by_wnd(Window wnd)  sw_get_window_by_wnd(Window wnd)
298  {  {
299          seamless_window *sw;          seamless_window *sw;
300          for (sw = g_seamless_windows; sw; sw = sw->next)          for (sw = g_seamless_windows; sw; sw = sw->next)
# Line 281  seamless_get_window_by_wnd(Window wnd) Line 307  seamless_get_window_by_wnd(Window wnd)
307    
308    
309  static void  static void
310  seamless_remove_window(seamless_window * win)  sw_remove_window(seamless_window * win)
311  {  {
312          seamless_window *sw, **prevnext = &g_seamless_windows;          seamless_window *sw, **prevnext = &g_seamless_windows;
313          for (sw = g_seamless_windows; sw; sw = sw->next)          for (sw = g_seamless_windows; sw; sw = sw->next)
# Line 289  seamless_remove_window(seamless_window * Line 315  seamless_remove_window(seamless_window *
315                  if (sw == win)                  if (sw == win)
316                  {                  {
317                          *prevnext = sw->next;                          *prevnext = sw->next;
318                            sw->group->refcnt--;
319                            if (sw->group->refcnt == 0)
320                            {
321                                    XDestroyWindow(g_display, sw->group->wnd);
322                                    xfree(sw->group);
323                            }
324                            xfree(sw->position_timer);
325                          xfree(sw);                          xfree(sw);
326                          return;                          return;
327                  }                  }
# Line 298  seamless_remove_window(seamless_window * Line 331  seamless_remove_window(seamless_window *
331  }  }
332    
333    
334    /* Move all windows except wnd to new desktop */
335    static void
336    sw_all_to_desktop(Window wnd, unsigned int desktop)
337    {
338            seamless_window *sw;
339            for (sw = g_seamless_windows; sw; sw = sw->next)
340            {
341                    if (sw->wnd == wnd)
342                            continue;
343                    if (sw->desktop != desktop)
344                    {
345                            ewmh_move_to_desktop(sw->wnd, desktop);
346                            sw->desktop = desktop;
347                    }
348            }
349    }
350    
351    
352    /* Send our position */
353    static void
354    sw_update_position(seamless_window * sw)
355    {
356            XWindowAttributes wa;
357            int x, y;
358            Window child_return;
359            unsigned int serial;
360    
361            XGetWindowAttributes(g_display, sw->wnd, &wa);
362            XTranslateCoordinates(g_display, sw->wnd, wa.root,
363                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
364    
365            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
366    
367            sw->outstanding_position = True;
368            sw->outpos_serial = serial;
369    
370            sw->outpos_xoffset = x;
371            sw->outpos_yoffset = y;
372            sw->outpos_width = wa.width;
373            sw->outpos_height = wa.height;
374    }
375    
376    
377    /* Check if it's time to send our position */
378    static void
379    sw_check_timers()
380    {
381            seamless_window *sw;
382            struct timeval now;
383    
384            gettimeofday(&now, NULL);
385            for (sw = g_seamless_windows; sw; sw = sw->next)
386            {
387                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
388                    {
389                            timerclear(sw->position_timer);
390                            sw_update_position(sw);
391                    }
392            }
393    }
394    
395    
396    static void
397    sw_restack_window(seamless_window * sw, unsigned long behind)
398    {
399            seamless_window *sw_above;
400    
401            /* Remove window from stack */
402            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
403            {
404                    if (sw_above->behind == sw->id)
405                            break;
406            }
407    
408            if (sw_above)
409                    sw_above->behind = sw->behind;
410    
411            /* And then add it at the new position */
412    
413            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
414            {
415                    if (sw_above->behind == behind)
416                            break;
417            }
418    
419            if (sw_above)
420                    sw_above->behind = sw->id;
421    
422            sw->behind = behind;
423    }
424    
425    
426    static void
427    sw_handle_restack(seamless_window * sw)
428    {
429            Status status;
430            Window root, parent, *children;
431            unsigned int nchildren, i;
432            seamless_window *sw_below;
433    
434            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
435                                &root, &parent, &children, &nchildren);
436            if (!status || !nchildren)
437                    return;
438    
439            sw_below = NULL;
440    
441            i = 0;
442            while (children[i] != sw->wnd)
443            {
444                    i++;
445                    if (i >= nchildren)
446                            goto end;
447            }
448    
449            for (i++; i < nchildren; i++)
450            {
451                    sw_below = sw_get_window_by_wnd(children[i]);
452                    if (sw_below)
453                            break;
454            }
455    
456            if (!sw_below && !sw->behind)
457                    goto end;
458            if (sw_below && (sw_below->id == sw->behind))
459                    goto end;
460    
461            if (sw_below)
462            {
463                    seamless_send_zchange(sw->id, sw_below->id, 0);
464                    sw_restack_window(sw, sw_below->id);
465            }
466            else
467            {
468                    seamless_send_zchange(sw->id, 0, 0);
469                    sw_restack_window(sw, 0);
470            }
471    
472          end:
473            XFree(children);
474    }
475    
476    
477    static seamless_group *
478    sw_find_group(unsigned long id, BOOL dont_create)
479    {
480            seamless_window *sw;
481            seamless_group *sg;
482            XSetWindowAttributes attribs;
483    
484            for (sw = g_seamless_windows; sw; sw = sw->next)
485            {
486                    if (sw->group->id == id)
487                            return sw->group;
488            }
489    
490            if (dont_create)
491                    return NULL;
492    
493            sg = xmalloc(sizeof(seamless_group));
494    
495            sg->wnd =
496                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
497                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
498    
499            sg->id = id;
500            sg->refcnt = 0;
501    
502            return sg;
503    }
504    
505    
506  static void  static void
507  mwm_hide_decorations(Window wnd)  mwm_hide_decorations(Window wnd)
508  {  {
# Line 1295  select_visual() Line 1500  select_visual()
1500          return True;          return True;
1501  }  }
1502    
1503    static XErrorHandler g_old_error_handler;
1504    
1505    static int
1506    error_handler(Display * dpy, XErrorEvent * eev)
1507    {
1508            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1509            {
1510                    fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1511                    fprintf(stderr,
1512                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1513                    return 0;
1514            }
1515    
1516            return g_old_error_handler(dpy, eev);
1517    }
1518    
1519  BOOL  BOOL
1520  ui_init(void)  ui_init(void)
1521  {  {
# Line 1312  ui_init(void) Line 1533  ui_init(void)
1533                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1534          }          }
1535    
1536            g_old_error_handler = XSetErrorHandler(error_handler);
1537    
1538          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1539          screen_num = DefaultScreen(g_display);          screen_num = DefaultScreen(g_display);
1540          g_x_socket = ConnectionNumber(g_display);          g_x_socket = ConnectionNumber(g_display);
# Line 1396  ui_init(void) Line 1619  ui_init(void)
1619                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1620    
1621          xclip_init();          xclip_init();
1622            ewmh_init();
1623          if (g_seamless_rdp)          if (g_seamless_rdp)
1624                  seamless_init();                  seamless_init();
1625    
# Line 1407  ui_init(void) Line 1631  ui_init(void)
1631  void  void
1632  ui_deinit(void)  ui_deinit(void)
1633  {  {
1634            while (g_seamless_windows)
1635            {
1636                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1637                    sw_remove_window(g_seamless_windows);
1638            }
1639    
1640          if (g_IM != NULL)          if (g_IM != NULL)
1641                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1642    
# Line 1541  ui_create_window(void) Line 1771  ui_create_window(void)
1771          }          }
1772    
1773          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
1774          if (!g_seamless_rdp)  
1775            XMapWindow(g_display, g_wnd);
1776            /* wait for VisibilityNotify */
1777            do
1778          {          {
1779                  XMapWindow(g_display, g_wnd);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
                 /* wait for VisibilityNotify */  
                 do  
                 {  
                         XMaskEvent(g_display, VisibilityChangeMask, &xevent);  
                 }  
                 while (xevent.type != VisibilityNotify);  
                 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;  
1780          }          }
1781            while (xevent.type != VisibilityNotify);
1782            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1783    
1784          g_focused = False;          g_focused = False;
1785          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 1615  xwin_toggle_fullscreen(void) Line 1843  xwin_toggle_fullscreen(void)
1843  {  {
1844          Pixmap contents = 0;          Pixmap contents = 0;
1845    
1846          if (g_seamless_rdp)          if (g_seamless_active)
1847                  /* Turn off SeamlessRDP mode */                  /* Turn off SeamlessRDP mode */
1848                  ui_seamless_toggle();                  ui_seamless_toggle();
1849    
# Line 1720  handle_button_event(XEvent xevent, BOOL Line 1948  handle_button_event(XEvent xevent, BOOL
1948          }          }
1949  }  }
1950    
1951    
1952  /* Process events in Xlib queue  /* Process events in Xlib queue
1953     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1954  static int  static int
# Line 1852  xwin_process_events(void) Line 2081  xwin_process_events(void)
2081                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2082                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2083                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2084    
2085                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2086                                    if (!sw)
2087                                            break;
2088    
2089                                    if (sw->id != g_seamless_focused)
2090                                    {
2091                                            seamless_send_focus(sw->id, 0);
2092                                            g_seamless_focused = sw->id;
2093                                    }
2094                                  break;                                  break;
2095    
2096                          case FocusOut:                          case FocusOut:
# Line 1894  xwin_process_events(void) Line 2133  xwin_process_events(void)
2133                                  }                                  }
2134                                  else                                  else
2135                                  {                                  {
2136                                          sw = seamless_get_window_by_wnd(xevent.xexpose.window);                                          sw = sw_get_window_by_wnd(xevent.xexpose.window);
2137                                          if (sw)                                          if (!sw)
2138                                                  XCopyArea(g_display, g_backstore,                                                  break;
2139                                                            xevent.xexpose.window, g_gc,                                          XCopyArea(g_display, g_backstore,
2140                                                            xevent.xexpose.x + sw->xoffset,                                                    xevent.xexpose.window, g_gc,
2141                                                            xevent.xexpose.y + sw->yoffset,                                                    xevent.xexpose.x + sw->xoffset,
2142                                                            xevent.xexpose.width,                                                    xevent.xexpose.y + sw->yoffset,
2143                                                            xevent.xexpose.height, xevent.xexpose.x,                                                    xevent.xexpose.width,
2144                                                            xevent.xexpose.y);                                                    xevent.xexpose.height, xevent.xexpose.x,
2145                                                      xevent.xexpose.y);
2146                                  }                                  }
2147    
2148                                  break;                                  break;
# Line 1933  xwin_process_events(void) Line 2173  xwin_process_events(void)
2173                                  break;                                  break;
2174                          case PropertyNotify:                          case PropertyNotify:
2175                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2176                                    if (xevent.xproperty.window == g_wnd)
2177                                            break;
2178                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2179                                            break;
2180    
2181                                    /* seamless */
2182                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2183                                    if (!sw)
2184                                            break;
2185    
2186                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2187                                        && (xevent.xproperty.state == PropertyNewValue))
2188                                    {
2189                                            sw->state = ewmh_get_window_state(sw->wnd);
2190                                            seamless_send_state(sw->id, sw->state, 0);
2191                                    }
2192    
2193                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2194                                        && (xevent.xproperty.state == PropertyNewValue))
2195                                    {
2196                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2197                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2198                                    }
2199    
2200                                  break;                                  break;
2201                          case MapNotify:                          case MapNotify:
2202                                  if (!g_seamless_rdp)                                  if (!g_seamless_active)
2203                                          rdp_send_client_window_status(1);                                          rdp_send_client_window_status(1);
2204                                  break;                                  break;
2205                          case UnmapNotify:                          case UnmapNotify:
2206                                  if (!g_seamless_rdp)                                  if (!g_seamless_active)
2207                                          rdp_send_client_window_status(0);                                          rdp_send_client_window_status(0);
2208                                  break;                                  break;
2209                            case ConfigureNotify:
2210                                    if (!g_seamless_active)
2211                                            break;
2212    
2213                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2214                                    if (!sw)
2215                                            break;
2216    
2217                                    gettimeofday(sw->position_timer, NULL);
2218                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2219                                        1000000)
2220                                    {
2221                                            sw->position_timer->tv_usec +=
2222                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2223                                            sw->position_timer->tv_sec += 1;
2224                                    }
2225                                    else
2226                                    {
2227                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2228                                    }
2229    
2230                                    sw_handle_restack(sw);
2231                                    break;
2232                  }                  }
2233          }          }
2234          /* Keep going */          /* Keep going */
# Line 1965  ui_select(int rdp_socket) Line 2252  ui_select(int rdp_socket)
2252                          /* User quit */                          /* User quit */
2253                          return 0;                          return 0;
2254    
2255                    if (g_seamless_active)
2256                            sw_check_timers();
2257    
2258                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2259                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2260                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1984  ui_select(int rdp_socket) Line 2274  ui_select(int rdp_socket)
2274    
2275                  /* add redirection handles */                  /* add redirection handles */
2276                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2277                    seamless_select_timeout(&tv);
2278    
2279                  n++;                  n++;
2280    
# Line 2952  ui_end_update(void) Line 3243  ui_end_update(void)
3243  {  {
3244  }  }
3245    
3246    
3247    void
3248    ui_seamless_begin(BOOL hidden)
3249    {
3250            if (!g_seamless_rdp)
3251                    return;
3252    
3253            if (g_seamless_started)
3254                    return;
3255    
3256            g_seamless_started = True;
3257            g_seamless_hidden = hidden;
3258    
3259            if (!hidden)
3260                    ui_seamless_toggle();
3261    }
3262    
3263    
3264    void
3265    ui_seamless_hide_desktop()
3266    {
3267            if (!g_seamless_rdp)
3268                    return;
3269    
3270            if (!g_seamless_started)
3271                    return;
3272    
3273            if (g_seamless_active)
3274                    ui_seamless_toggle();
3275    
3276            g_seamless_hidden = True;
3277    }
3278    
3279    
3280    void
3281    ui_seamless_unhide_desktop()
3282    {
3283            if (!g_seamless_rdp)
3284                    return;
3285    
3286            if (!g_seamless_started)
3287                    return;
3288    
3289            g_seamless_hidden = False;
3290    
3291            ui_seamless_toggle();
3292    }
3293    
3294    
3295  void  void
3296  ui_seamless_toggle()  ui_seamless_toggle()
3297  {  {
3298          if (g_seamless_rdp)          if (!g_seamless_rdp)
3299                    return;
3300    
3301            if (!g_seamless_started)
3302                    return;
3303    
3304            if (g_seamless_hidden)
3305                    return;
3306    
3307            if (g_seamless_active)
3308          {          {
3309                  /* Deactivate */                  /* Deactivate */
3310                  while (g_seamless_windows)                  while (g_seamless_windows)
3311                  {                  {
3312                          XDestroyWindow(g_display, g_seamless_windows->wnd);                          XDestroyWindow(g_display, g_seamless_windows->wnd);
3313                          seamless_remove_window(g_seamless_windows);                          sw_remove_window(g_seamless_windows);
3314                  }                  }
3315                  XMapWindow(g_display, g_wnd);                  XMapWindow(g_display, g_wnd);
3316          }          }
3317          else          else
3318          {          {
3319                  /* Activate */                  /* Activate */
                 if (g_win_button_size)  
                 {  
                         error("SeamlessRDP mode cannot be activated when using single application mode\n");  
                         return;  
                 }  
                 if (!g_using_full_workarea)  
                 {  
                         error("SeamlessRDP mode requires a session that covers the whole screen");  
                         return;  
                 }  
   
3320                  XUnmapWindow(g_display, g_wnd);                  XUnmapWindow(g_display, g_wnd);
3321                  seamless_send_sync();                  seamless_send_sync();
3322          }          }
3323    
3324          g_seamless_rdp = !g_seamless_rdp;          g_seamless_active = !g_seamless_active;
3325  }  }
3326    
3327    
3328  void  void
3329  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,
3330                              unsigned long flags)
3331  {  {
3332          Window wnd;          Window wnd;
3333          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
3334          XClassHint *classhints;          XClassHint *classhints;
3335            XSizeHints *sizehints;
3336            XWMHints *wmhints;
3337          long input_mask;          long input_mask;
3338          seamless_window *sw, *sw_parent;          seamless_window *sw, *sw_parent;
3339    
3340          get_window_attribs(&attribs);          if (!g_seamless_active)
3341                    return;
3342    
3343          attribs.override_redirect = False;          /* Ignore CREATEs for existing windows */
3344            sw = sw_get_window_by_id(id);
3345            if (sw)
3346                    return;
3347    
3348          /* FIXME: Do not assume that -1, -1 is outside screen Consider          get_window_attribs(&attribs);
3349             wait with showing the window until STATE and others have          wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
            been recieved. */  
         wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0,  
3350                              InputOutput, g_visual,                              InputOutput, g_visual,
3351                              CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |                              CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
                             CWBorderPixel, &attribs);  
3352    
3353          XStoreName(g_display, wnd, "rdesktop-seamless");          XStoreName(g_display, wnd, "SeamlessRDP");
3354            ewmh_set_wm_name(wnd, "SeamlessRDP");
3355    
3356          mwm_hide_decorations(wnd);          mwm_hide_decorations(wnd);
3357    
3358          classhints = XAllocClassHint();          classhints = XAllocClassHint();
3359          if (classhints != NULL)          if (classhints != NULL)
3360          {          {
3361                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = "rdesktop";
3362                    classhints->res_class = "SeamlessRDP";
3363                  XSetClassHint(g_display, wnd, classhints);                  XSetClassHint(g_display, wnd, classhints);
3364                  XFree(classhints);                  XFree(classhints);
3365          }          }
3366    
3367          /* Set WM_TRANSIENT_FOR, if necessary */          /* WM_NORMAL_HINTS */
3368          sw_parent = seamless_get_window_by_id(parent);          sizehints = XAllocSizeHints();
3369          if (sw_parent)          if (sizehints != NULL)
3370                  XSetTransientForHint(g_display, wnd, sw_parent->wnd);          {
3371          else                  sizehints->flags = USPosition;
3372                  warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);                  XSetWMNormalHints(g_display, wnd, sizehints);
3373                    XFree(sizehints);
3374            }
3375    
3376            /* Parent-less transient windows */
3377            if (parent == 0xFFFFFFFF)
3378            {
3379                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3380                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3381                       using some other hints. */
3382                    ewmh_set_window_popup(wnd);
3383            }
3384            /* Normal transient windows */
3385            else if (parent != 0x00000000)
3386            {
3387                    sw_parent = sw_get_window_by_id(parent);
3388                    if (sw_parent)
3389                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3390                    else
3391                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3392            }
3393    
3394            if (flags & SEAMLESSRDP_CREATE_MODAL)
3395            {
3396                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3397                       somewhat at least */
3398                    if (parent == 0x00000000)
3399                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3400                    ewmh_set_window_modal(wnd);
3401            }
3402    
3403          /* FIXME: Support for Input Context:s */          /* FIXME: Support for Input Context:s */
3404    
3405          get_input_mask(&input_mask);          get_input_mask(&input_mask);
3406            input_mask |= PropertyChangeMask;
3407    
3408          XSelectInput(g_display, wnd, input_mask);          XSelectInput(g_display, wnd, input_mask);
3409    
         XMapWindow(g_display, wnd);  
   
3410          /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a          /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3411             seamless window, we could try to close the window on the             seamless window, we could try to close the window on the
3412             serverside, instead of terminating rdesktop */             serverside, instead of terminating rdesktop */
3413          XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);          XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3414    
3415          sw = malloc(sizeof(seamless_window));          sw = xmalloc(sizeof(seamless_window));
3416          sw->wnd = wnd;          sw->wnd = wnd;
3417          sw->id = id;          sw->id = id;
3418            sw->behind = 0;
3419            sw->group = sw_find_group(group, False);
3420            sw->group->refcnt++;
3421          sw->xoffset = 0;          sw->xoffset = 0;
3422          sw->yoffset = 0;          sw->yoffset = 0;
3423          sw->width = 0;          sw->width = 0;
3424          sw->height = 0;          sw->height = 0;
3425            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3426            sw->desktop = 0;
3427            sw->position_timer = xmalloc(sizeof(struct timeval));
3428            timerclear(sw->position_timer);
3429    
3430            sw->outstanding_position = False;
3431            sw->outpos_serial = 0;
3432            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3433            sw->outpos_width = sw->outpos_height = 0;
3434    
3435          sw->next = g_seamless_windows;          sw->next = g_seamless_windows;
3436          g_seamless_windows = sw;          g_seamless_windows = sw;
3437    
3438            /* WM_HINTS */
3439            wmhints = XAllocWMHints();
3440            if (wmhints)
3441            {
3442                    wmhints->flags = WindowGroupHint;
3443                    wmhints->window_group = sw->group->wnd;
3444                    XSetWMHints(g_display, sw->wnd, wmhints);
3445                    XFree(wmhints);
3446            }
3447  }  }
3448    
3449    
# Line 3055  void Line 3451  void
3451  ui_seamless_destroy_window(unsigned long id, unsigned long flags)  ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3452  {  {
3453          seamless_window *sw;          seamless_window *sw;
         sw = seamless_get_window_by_id(id);  
3454    
3455            if (!g_seamless_active)
3456                    return;
3457    
3458            sw = sw_get_window_by_id(id);
3459          if (!sw)          if (!sw)
3460          {          {
3461                  warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);                  warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
# Line 3064  ui_seamless_destroy_window(unsigned long Line 3463  ui_seamless_destroy_window(unsigned long
3463          }          }
3464    
3465          XDestroyWindow(g_display, sw->wnd);          XDestroyWindow(g_display, sw->wnd);
3466          seamless_remove_window(sw);          sw_remove_window(sw);
3467  }  }
3468    
3469    
# Line 3073  ui_seamless_move_window(unsigned long id Line 3472  ui_seamless_move_window(unsigned long id
3472  {  {
3473          seamless_window *sw;          seamless_window *sw;
3474    
3475          sw = seamless_get_window_by_id(id);          if (!g_seamless_active)
3476                    return;
3477    
3478            sw = sw_get_window_by_id(id);
3479          if (!sw)          if (!sw)
3480          {          {
3481                  warning("ui_seamless_move_window: No information for window 0x%lx\n", id);                  warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3482                  return;                  return;
3483          }          }
3484    
3485            /* We ignore server updates until it has handled our request. */
3486            if (sw->outstanding_position)
3487                    return;
3488    
3489          if (!width || !height)          if (!width || !height)
3490                  /* X11 windows must be at least 1x1 */                  /* X11 windows must be at least 1x1 */
3491                  return;                  return;
3492    
3493          /* About MAX and MIN: Windows allows moving a window outside          sw->xoffset = x;
3494             the desktop. This happens, for example, when maximizing an          sw->yoffset = y;
3495             application. In this case, the position is set to something          sw->width = width;
3496             like -4,-4,1288,1032. Many WMs does not allow windows          sw->height = height;
3497             outside the desktop, however. Therefore, clip the window  
3498             ourselves. */          /* If we move the window in a maximized state, then KDE won't
3499          sw->xoffset = MAX(0, x);             accept restoration */
3500          sw->yoffset = MAX(0, y);          switch (sw->state)
3501          sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);          {
3502          sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);                  case SEAMLESSRDP_MINIMIZED:
3503                    case SEAMLESSRDP_MAXIMIZED:
3504                            return;
3505            }
3506    
3507          /* FIXME: Perhaps use ewmh_net_moveresize_window instead */          /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3508          XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);          XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
# Line 3102  ui_seamless_move_window(unsigned long id Line 3510  ui_seamless_move_window(unsigned long id
3510    
3511    
3512  void  void
3513    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3514    {
3515            seamless_window *sw;
3516    
3517            if (!g_seamless_active)
3518                    return;
3519    
3520            sw = sw_get_window_by_id(id);
3521            if (!sw)
3522            {
3523                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3524                    return;
3525            }
3526    
3527            if (behind)
3528            {
3529                    seamless_window *sw_behind;
3530                    Window wnds[2];
3531    
3532                    sw_behind = sw_get_window_by_id(behind);
3533                    if (!sw_behind)
3534                    {
3535                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3536                                    behind);
3537                            return;
3538                    }
3539    
3540                    wnds[1] = sw_behind->wnd;
3541                    wnds[0] = sw->wnd;
3542    
3543                    XRestackWindows(g_display, wnds, 2);
3544            }
3545            else
3546            {
3547                    XRaiseWindow(g_display, sw->wnd);
3548            }
3549    
3550            sw_restack_window(sw, behind);
3551    }
3552    
3553    
3554    void
3555  ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)  ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3556  {  {
3557          seamless_window *sw;          seamless_window *sw;
3558    
3559          sw = seamless_get_window_by_id(id);          if (!g_seamless_active)
3560                    return;
3561    
3562            sw = sw_get_window_by_id(id);
3563            if (!sw)
3564            {
3565                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3566                    return;
3567            }
3568    
3569            /* FIXME: Might want to convert the name for non-EWMH WMs */
3570          XStoreName(g_display, sw->wnd, title);          XStoreName(g_display, sw->wnd, title);
3571            ewmh_set_wm_name(sw->wnd, title);
3572  }  }
3573    
3574    
# Line 3117  ui_seamless_setstate(unsigned long id, u Line 3577  ui_seamless_setstate(unsigned long id, u
3577  {  {
3578          seamless_window *sw;          seamless_window *sw;
3579    
3580          sw = seamless_get_window_by_id(id);          if (!g_seamless_active)
3581                    return;
3582    
3583            sw = sw_get_window_by_id(id);
3584            if (!sw)
3585            {
3586                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3587                    return;
3588            }
3589    
3590          switch (state)          switch (state)
3591          {          {
3592                  case SEAMLESSRDP_NORMAL:                  case SEAMLESSRDP_NORMAL:
3593                  case SEAMLESSRDP_MAXIMIZED:                  case SEAMLESSRDP_MAXIMIZED:
3594                          /* FIXME */                          ewmh_change_state(sw->wnd, state);
3595                            XMapWindow(g_display, sw->wnd);
3596                          break;                          break;
3597                  case SEAMLESSRDP_MINIMIZED:                  case SEAMLESSRDP_MINIMIZED:
3598                          XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));                          /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3599                               the Window Manager should probably just ignore the request, since
3600                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3601                               such as minimization, rather than an independent state." Besides,
3602                               XIconifyWindow is easier. */
3603                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3604                            {
3605                                    XWMHints *hints;
3606                                    hints = XGetWMHints(g_display, sw->wnd);
3607                                    if (hints)
3608                                    {
3609                                            hints->flags |= StateHint;
3610                                            hints->initial_state = IconicState;
3611                                            XSetWMHints(g_display, sw->wnd, hints);
3612                                            XFree(hints);
3613                                    }
3614                                    XMapWindow(g_display, sw->wnd);
3615                            }
3616                            else
3617                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3618                          break;                          break;
3619                  default:                  default:
3620                          warning("SeamlessRDP: Invalid state %d\n", state);                          warning("SeamlessRDP: Invalid state %d\n", state);
3621                          break;                          break;
3622          }          }
3623    
3624            sw->state = state;
3625    }
3626    
3627    
3628    void
3629    ui_seamless_syncbegin(unsigned long flags)
3630    {
3631            if (!g_seamless_active)
3632                    return;
3633    
3634            /* Destroy all seamless windows */
3635            while (g_seamless_windows)
3636            {
3637                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3638                    sw_remove_window(g_seamless_windows);
3639            }
3640    }
3641    
3642    
3643    void
3644    ui_seamless_ack(unsigned int serial)
3645    {
3646            seamless_window *sw;
3647            for (sw = g_seamless_windows; sw; sw = sw->next)
3648            {
3649                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3650                    {
3651                            sw->xoffset = sw->outpos_xoffset;
3652                            sw->yoffset = sw->outpos_yoffset;
3653                            sw->width = sw->outpos_width;
3654                            sw->height = sw->outpos_height;
3655                            sw->outstanding_position = False;
3656    
3657                            /* Do a complete redraw of the window as part of the
3658                               completion of the move. This is to remove any
3659                               artifacts caused by our lack of synchronization. */
3660                            XCopyArea(g_display, g_backstore,
3661                                      sw->wnd, g_gc,
3662                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3663    
3664                            break;
3665                    }
3666            }
3667  }  }

Legend:
Removed from v.1101  
changed lines
  Added in v.1193

  ViewVC Help
Powered by ViewVC 1.1.26