Esempio n. 1
0
 def do_xpra_client_message_event(self, event):
     if event.message_type == "_NET_SYSTEM_TRAY_OPCODE" and event.window == self.tray_window and event.format == 32:
         opcode = event.data[1]
         SYSTEM_TRAY_REQUEST_DOCK = 0
         SYSTEM_TRAY_BEGIN_MESSAGE = 1
         SYSTEM_TRAY_CANCEL_MESSAGE = 2
         if opcode == SYSTEM_TRAY_REQUEST_DOCK:
             xid = event.data[2]
             log("tray docking request from %#x", xid)
             trap.call_synced(self.dock_tray, xid)
         elif opcode == SYSTEM_TRAY_BEGIN_MESSAGE:
             timeout = event.data[2]
             mlen = event.data[3]
             mid = event.data[4]
             log.info(
                 "tray begin message timeout=%s, mlen=%s, mid=%s - not handled yet!",
                 timeout, mlen, mid)
         elif opcode == SYSTEM_TRAY_CANCEL_MESSAGE:
             mid = event.data[2]
             log.info("tray cancel message for mid=%s - not handled yet!",
                      mid)
     elif event.message_type == "_NET_SYSTEM_TRAY_MESSAGE_DATA":
         assert event.format == 8
         log.info("tray message data - not handled yet!")
     elif event.message_type in IGNORED_MESSAGE_TYPES:
         log(
             "do_xpra_client_message_event(%s) in ignored message type list",
             event)
     else:
         log.info("do_xpra_client_message_event(%s)", event)
Esempio n. 2
0
 def do_xpra_client_message_event(self, event):
     if event.message_type=="_NET_SYSTEM_TRAY_OPCODE" and event.window==self.tray_window and event.format==32:
         opcode = event.data[1]
         SYSTEM_TRAY_REQUEST_DOCK = 0
         SYSTEM_TRAY_BEGIN_MESSAGE = 1
         SYSTEM_TRAY_CANCEL_MESSAGE = 2
         if opcode==SYSTEM_TRAY_REQUEST_DOCK:
             xid = event.data[2]
             log("tray docking request from %#x", xid)
             trap.call_synced(self.dock_tray, xid)
         elif opcode==SYSTEM_TRAY_BEGIN_MESSAGE:
             timeout = event.data[2]
             mlen = event.data[3]
             mid = event.data[4]
             log.info("tray begin message timeout=%s, mlen=%s, mid=%s - not handled yet!", timeout, mlen, mid)
         elif opcode==SYSTEM_TRAY_CANCEL_MESSAGE:
             mid = event.data[2]
             log.info("tray cancel message for mid=%s - not handled yet!", mid)
     elif event.message_type=="_NET_SYSTEM_TRAY_MESSAGE_DATA":
         assert event.format==8
         log.info("tray message data - not handled yet!")
     elif event.message_type in IGNORED_MESSAGE_TYPES:
         log("do_xpra_client_message_event(%s) in ignored message type list", event)
     else:
         log.info("do_xpra_client_message_event(%s)", event)
Esempio n. 3
0
    def X11_ungrab(self):
        grablog("X11_ungrab")

        def do_X11_ungrab():
            X11Core.UngrabKeyboard()
            X11Core.UngrabPointer()

        trap.call_synced(do_X11_ungrab)
Esempio n. 4
0
 def initiate_moveresize(self, x_root, y_root, direction, button, source_indication):
     log("initiate_moveresize%s", (x_root, y_root, direction, button, source_indication))
     assert HAS_X11_BINDINGS, "cannot handle initiate-moveresize without X11 bindings"
     event_mask = SubstructureNotifyMask | SubstructureRedirectMask
     def wm_moveresize():
         from xpra.gtk_common.gobject_compat import get_xid
         root = self.get_window().get_screen().get_root_window()
         root_xid = get_xid(root)
         xwin = get_xid(self.get_window())
         X11Core.UngrabPointer()
         X11Window.sendClientMessage(root_xid, xwin, False, event_mask, "_NET_WM_MOVERESIZE",
               x_root, y_root, direction, button, source_indication)
     trap.call_synced(wm_moveresize)
Esempio n. 5
0
 def _process_button_action(self, proto, packet):
     ss = self._server_sources.get(proto)
     if ss is None:
         return
     wid, button, pressed, pointer, modifiers = packet[1:6]
     self._process_mouse_common(proto, wid, pointer, modifiers)
     ss.user_event()
     try:
         trap.call_synced(X11Keyboard.xtest_fake_button, button, pressed)
     except XError:
         err = "Failed to pass on (un)press of mouse button %s" % button
         if button >= 4:
             err += " (perhaps your Xvfb does not support mousewheels?)"
         log.warn(err)
Esempio n. 6
0
 def _process_button_action(self, proto, packet):
     ss = self._server_sources.get(proto)
     if ss is None:
         return
     wid, button, pressed, pointer, modifiers = packet[1:6]
     self._process_mouse_common(proto, wid, pointer, modifiers)
     ss.user_event()
     try:
         trap.call_synced(X11Keyboard.xtest_fake_button, button, pressed)
     except XError:
         err = "Failed to pass on (un)press of mouse button %s" % button
         if button>=4:
             err += " (perhaps your Xvfb does not support mousewheels?)"
         log.warn(err)
Esempio n. 7
0
 def cleanup(self):
     #this must be called from the UI thread!
     remove_event_receiver(self._root, self)
     self._root.set_events(self._saved_event_mask)
     if self._own_x11_filter:
         #only remove the x11 filter if we initialized it (ie: when running in client)
         try:
             trap.call_synced(cleanup_x11_filter)
         except Exception, e:
             log.error("failed to remove x11 event filter: %s", e)
         try:
             trap.call_synced(cleanup_all_event_receivers)
         except Exception, e:
             log.error("failed to remove event receivers: %s", e)
Esempio n. 8
0
 def cleanup(self):
     #this must be called from the UI thread!
     remove_event_receiver(self._root, self)
     self._root.set_events(self._saved_event_mask)
     if self._own_x11_filter:
         #only remove the x11 filter if we initialized it (ie: when running in client)
         try:
             trap.call_synced(cleanup_x11_filter)
         except Exception, e:
             log.error("failed to remove x11 event filter: %s", e)
         try:
             trap.call_synced(cleanup_all_event_receivers)
         except Exception, e:
             log.error("failed to remove event receivers: %s", e)
Esempio n. 9
0
def prop_get(target, key, etype, ignore_errors=False, raise_xerrors=False):
    if isinstance(etype, list):
        scalar_type = etype[0]
    else:
        scalar_type = etype
    (_, atom, _, _, _, _) = _prop_types[scalar_type]
    try:
        data = trap.call_synced(X11Window.XGetWindowProperty, get_xwindow(target), key, atom, etype)
        if data is None:
            if not ignore_errors:
                log("Missing property %s (%s)", key, etype)
            return None
    except XError:
        if raise_xerrors:
            raise
        log.info("Missing window %s or wrong property type %s (%s)", target, key, etype, exc_info=True)
        return None
    except PropertyError:
        if not ignore_errors:
            log.info("Missing property or wrong property type %s (%s)", key, etype, exc_info=True)
        return None
    try:
        return _prop_decode(target, etype, data)
    except:
        if not ignore_errors:
            log.warn("Error parsing property %s (type %s); this may be a"
                     + " misbehaving application, or bug in Xpra\n"
                     + "  Data: %r[...?]",
                     key, etype, data[:160], exc_info=True)
        raise
Esempio n. 10
0
    def initiate_moveresize(self, x_root, y_root, direction, button,
                            source_indication):
        log("initiate_moveresize%s",
            (x_root, y_root, direction, button, source_indication))
        assert HAS_X11_BINDINGS, "cannot handle initiate-moveresize without X11 bindings"
        event_mask = SubstructureNotifyMask | SubstructureRedirectMask

        def wm_moveresize():
            from xpra.gtk_common.gobject_compat import get_xid
            root = self.get_window().get_screen().get_root_window()
            root_xid = get_xid(root)
            xwin = get_xid(self.get_window())
            X11Core.UngrabPointer()
            X11Window.sendClientMessage(root_xid, xwin, False, event_mask,
                                        "_NET_WM_MOVERESIZE", x_root, y_root,
                                        direction, button, source_indication)

        trap.call_synced(wm_moveresize)
Esempio n. 11
0
    def set_workspace(self):
        if not self._can_set_workspace:
            return -1
        root = self.gdk_window().get_screen().get_root_window()
        ndesktops = self.get_workspace_count()
        workspacelog("%s.set_workspace() workspace=%s ndesktops=%s", self, self._window_workspace, ndesktops)
        if ndesktops is None or ndesktops<=1 or self._window_workspace<0:
            return  -1
        workspace = max(0, min(ndesktops-1, self._window_workspace))
        event_mask = SubstructureNotifyMask | SubstructureRedirectMask

        def send():
            from xpra.gtk_common.gobject_compat import get_xid
            root_xid = get_xid(root)
            xwin = get_xid(self.gdk_window())
            X11Window.sendClientMessage(root_xid, xwin, False, event_mask, "_NET_WM_DESKTOP",
                  workspace, CurrentTime, 0, 0, 0)
        trap.call_synced(send)
        return workspace
Esempio n. 12
0
 def get_settings(self):
     owner = self.xsettings_owner()
     log("Fetching current XSettings data, owner=%s", owner)
     if owner is None:
         return None
     try:
         return trap.call_synced(prop_get, owner, XSETTINGS, XSETTINGS_TYPE)
     except XError:
         log("X error while fetching XSettings data; ignored")
         return None
Esempio n. 13
0
 def get_settings(self):
     owner = self.xsettings_owner()
     log("Fetching current XSettings data, owner=%s", owner)
     if owner is None:
         return None
     try:
         return trap.call_synced(prop_get, owner, XSETTINGS, XSETTINGS_TYPE)
     except XError:
         log("X error while fetching XSettings data; ignored")
         return None
Esempio n. 14
0
 def xsettings_owner(self):
     owner_x = X11Window.XGetSelectionOwner(self._selection)
     log("XGetSelectionOwner(%s)=%s", self._selection, owner_x)
     if owner_x == XNone:
         return None
     try:
         return trap.call_synced(get_pywindow, self._clipboard, owner_x)
     except XError:
         log("X error while fetching owner of XSettings data; ignored")
         return None
Esempio n. 15
0
def apply_xmodmap(instructions):
    try:
        unset = trap.call_synced(X11Keyboard.set_xmodmap, instructions)
    except:
        log.error("apply_xmodmap", exc_info=True)
        unset = instructions
    if unset is None:
        #None means an X11 error occurred, re-do all:
        unset = instructions
    return unset
Esempio n. 16
0
 def xsettings_owner(self):
     owner_x = X11Window.XGetSelectionOwner(self._selection)
     log("XGetSelectionOwner(%s)=%s", self._selection, owner_x)
     if owner_x == XNone:
         return None
     try:
         return trap.call_synced(get_pywindow, self._clipboard, owner_x)
     except XError:
         log("X error while fetching owner of XSettings data; ignored")
         return None
Esempio n. 17
0
    def set_workspace(self):
        if not self._can_set_workspace:
            return -1
        root = self.gdk_window().get_screen().get_root_window()
        ndesktops = self.get_workspace_count()
        workspacelog("%s.set_workspace() workspace=%s ndesktops=%s", self,
                     self._window_workspace, ndesktops)
        if ndesktops is None or ndesktops <= 1 or self._window_workspace < 0:
            return -1
        workspace = max(0, min(ndesktops - 1, self._window_workspace))
        event_mask = SubstructureNotifyMask | SubstructureRedirectMask

        def send():
            from xpra.gtk_common.gobject_compat import get_xid
            root_xid = get_xid(root)
            xwin = get_xid(self.gdk_window())
            X11Window.sendClientMessage(root_xid, xwin, False, event_mask,
                                        "_NET_WM_DESKTOP", workspace,
                                        CurrentTime, 0, 0, 0)

        trap.call_synced(send)
        return workspace
Esempio n. 18
0
def prop_get(target, key, etype, ignore_errors=False, raise_xerrors=False):
    if isinstance(etype, list):
        scalar_type = etype[0]
    else:
        scalar_type = etype
    (_, atom, _, _, _, _) = _prop_types[scalar_type]
    try:
        data = trap.call_synced(X11Window.XGetWindowProperty,
                                get_xwindow(target), key, atom, etype)
        if data is None:
            if not ignore_errors:
                log("Missing property %s (%s)", key, etype)
            return None
    except XError:
        if raise_xerrors:
            raise
        log.info("Missing window %s or wrong property type %s (%s)",
                 target,
                 key,
                 etype,
                 exc_info=True)
        return None
    except PropertyError:
        if not ignore_errors:
            log.info("Missing property or wrong property type %s (%s)",
                     key,
                     etype,
                     exc_info=True)
        return None
    try:
        return _prop_decode(target, etype, data)
    except:
        if not ignore_errors:
            log.warn("Error parsing property %s (type %s); this may be a" +
                     " misbehaving application, or bug in Xpra\n" +
                     "  Data: %r[...?]",
                     key,
                     etype,
                     data[:160],
                     exc_info=True)
        raise
Esempio n. 19
0
 def X11_ungrab(self):
     grablog("X11_ungrab")
     def do_X11_ungrab():
         X11Core.UngrabKeyboard()
         X11Core.UngrabPointer()
     trap.call_synced(do_X11_ungrab)
Esempio n. 20
0
def prop_set(target, key, etype, value):
    trap.call_synced(X11Window.XChangeProperty, get_xwindow(target), key,
                       _prop_encode(target, etype, value))
Esempio n. 21
0
    def acquire(self, when):
        old_owner = self._owner()
        if when is self.IF_UNOWNED and old_owner != XNone:
            raise AlreadyOwned

        self.clipboard.set_with_data([("VERSION", 0, 0)],
                                     self._get,
                                     self._clear,
                                     None)

        # Having acquired the selection, we have to announce our existence
        # (ICCCM 2.8, still).  The details here probably don't matter too
        # much; I've never heard of an app that cares about these messages,
        # and metacity actually gets the format wrong in several ways (no
        # MANAGER or owner_window atoms).  But might as well get it as right
        # as possible.

        # To announce our existence, we need:
        #   -- the timestamp we arrived at
        #   -- the manager selection atom
        #   -- the window that registered the selection
        # Of course, because Gtk is doing so much magic for us, we have to do
        # some weird tricks to get at these.

        # Ask ourselves when we acquired the selection:
        ts_data = self.clipboard.wait_for_contents("TIMESTAMP").data
        #data is a timestamp, X11 datatype is Time which is CARD32,
        #(which is 64 bits on 64-bit systems!)
        Lsize = calcsize("@L")
        if len(ts_data)==Lsize:
            ts_num = unpack("@L", ts_data[:Lsize])[0]
        else:
            ts_num = 0      #CurrentTime
            log.warn("invalid data for 'TIMESTAMP': %s", ([hex(ord(x)) for x in ts_data]))
        # Calculate the X atom for this selection:
        selection_xatom = get_xatom(self.atom)
        # Ask X what window we used:
        self._xwindow = X11Window.XGetSelectionOwner(self.atom)

        root = self.clipboard.get_display().get_default_screen().get_root_window()
        X11Window.sendClientMessage(root.xid, root.xid, False, StructureNotifyMask,
                          "MANAGER",
                          ts_num, selection_xatom, self._xwindow, 0, 0)

        if old_owner != XNone and when is self.FORCE:
            # Block in a recursive mainloop until the previous owner has
            # cleared out.
            def getwin():
                window = get_pywindow(self.clipboard, old_owner)
                window.set_events(window.get_events() | gtk.gdk.STRUCTURE_MASK)
                return window
            try:
                window = trap.call_synced(getwin)
                log("got window")
            except XError:
                log("Previous owner is already gone, not blocking")
            else:
                log("Waiting for previous owner to exit...")
                add_event_receiver(window, self)
                gtk.main()
                log("...they did.")
        window = get_pywindow(self.clipboard, self._xwindow)
        window.set_title("Xpra-ManagerSelection")
Esempio n. 22
0
 def fake_key(self, keycode, press):
     keylog("fake_key(%s, %s)", keycode, press)
     trap.call_synced(X11Keyboard.xtest_fake_key, keycode, press)
Esempio n. 23
0
 def _manage_client(self, gdkwindow):
     try:
         if gdkwindow not in self._windows:
             trap.call_synced(self.do_manage_client, gdkwindow)
     except Exception, e:
         log("failed to manage client %s: %s", gdkwindow, e)
Esempio n. 24
0
    def set_screen_size(self, desired_w, desired_h):
        root_w, root_h = gtk.gdk.get_default_root_window().get_size()
        if desired_w == root_w and desired_h == root_h and not self.fake_xinerama:
            return root_w, root_h  #unlikely: perfect match already!
        #find the "physical" screen dimensions, so we can calculate the required dpi
        #(and do this before changing the resolution)
        wmm, hmm = 0, 0
        client_w, client_h = 0, 0
        sss = self._server_sources.values()
        for ss in sss:
            for s in ss.screen_sizes:
                if len(s) >= 10:
                    #display_name, width, height, width_mm, height_mm, monitors, work_x, work_y, work_width, work_height
                    client_w = max(client_w, s[1])
                    client_h = max(client_h, s[2])
                    wmm = max(wmm, s[3])
                    hmm = max(hmm, s[4])
        xdpi = self.default_dpi or self.dpi or 96
        ydpi = self.default_dpi or self.dpi or 96
        if wmm > 0 and hmm > 0 and client_w > 0 and client_h > 0:
            #calculate "real" dpi using integer calculations:
            xdpi = client_w * 254 / wmm / 10
            ydpi = client_h * 254 / hmm / 10
        log("calculated DPI: %s x %s (from w: %s / %s, h: %s / %s)", xdpi,
            ydpi, client_w, wmm, client_h, hmm)
        self.set_dpi(xdpi, ydpi)

        #try to find the best screen size to resize to:
        new_size = None
        for w, h in RandR.get_screen_sizes():
            if w < desired_w or h < desired_h:
                continue  #size is too small for client
            if new_size:
                ew, eh = new_size
                if ew * eh < w * h:
                    continue  #we found a better (smaller) candidate already
            new_size = w, h
        if not new_size:
            log.warn("resolution not found for %sx%s", desired_w, desired_h)
            return root_w, root_h
        log("best resolution for client(%sx%s) is: %s", desired_w, desired_h,
            new_size)
        #now actually apply the new settings:
        w, h = new_size
        xinerama_changed = self.save_fakexinerama_config()
        #we can only keep things unchanged if xinerama was also unchanged
        #(many apps will only query xinerama again if they get a randr notification)
        if (w == root_w and h == root_h) and not xinerama_changed:
            log.info("best resolution matching %sx%s is unchanged: %sx%s",
                     desired_w, desired_h, w, h)
            return root_w, root_h
        try:
            if (w == root_w and h == root_h) and xinerama_changed:
                #xinerama was changed, but the RandR resolution will not be...
                #and we need a RandR change to force applications to re-query it
                #so we temporarily switch to another resolution to force
                #the change! (ugly! but this works)
                temp = {}
                for tw, th in RandR.get_screen_sizes():
                    if tw != w or th != h:
                        #use the number of extra pixels as key:
                        #(so we can choose the closest resolution)
                        temp[abs((tw * th) - (w * h))] = (tw, th)
                if len(temp) == 0:
                    log.warn(
                        "cannot find a temporary resolution for Xinerama workaround!"
                    )
                else:
                    k = sorted(temp.keys())[0]
                    tw, th = temp[k]
                    log.info(
                        "temporarily switching to %sx%s as a Xinerama workaround",
                        tw, th)
                    RandR.set_screen_size(tw, th)
            log.debug("calling RandR.set_screen_size(%s, %s)", w, h)
            trap.call_synced(RandR.set_screen_size, w, h)
            log.debug("calling RandR.get_screen_size()")
            root_w, root_h = RandR.get_screen_size()
            log.debug("RandR.get_screen_size()=%s,%s", root_w, root_h)
            if root_w != w or root_h != h:
                log.error(
                    "odd, failed to set the new resolution, "
                    "tried to set it to %sx%s and ended up with %sx%s", w, h,
                    root_w, root_h)
            else:
                msg = "server virtual display now set to %sx%s" % (root_w,
                                                                   root_h)
                if desired_w != root_w or desired_h != root_h:
                    msg += " (best match for %sx%s)" % (desired_w, desired_h)
                log.info(msg)

            def show_dpi():
                sizes_mm = RandR.get_screen_sizes_mm()  #ie: [(1280, 1024)]
                assert len(sizes_mm) > 0
                wmm = sum([x[0] for x in sizes_mm]) / len(sizes_mm)
                hmm = sum([x[1] for x in sizes_mm]) / len(sizes_mm)
                actual_xdpi = int(root_w * 25.4 / wmm + 0.5)
                actual_ydpi = int(root_h * 25.4 / hmm + 0.5)
                if actual_xdpi == xdpi and actual_ydpi == ydpi:
                    log.info("DPI set to %s x %s", xdpi, ydpi)
                else:
                    #should this be a warning:
                    l = log.info
                    maxdelta = max(abs(actual_xdpi - xdpi),
                                   abs(actual_ydpi - ydpi))
                    if maxdelta >= 10:
                        l = log.warn
                    l("DPI set to %s x %s (wanted %s x %s)", actual_xdpi,
                      actual_ydpi, xdpi, ydpi)
                    if maxdelta >= 10:
                        l(" you may experience scaling problems, such as huge or small fonts, etc"
                          )
                        l(" to fix this issue, try the dpi switch, or use a patched Xdummy driver"
                          )

            #show dpi via idle_add so server has time to change the screen size (mm)
            self.idle_add(show_dpi)
        except Exception, e:
            log.error("ouch, failed to set new resolution: %s",
                      e,
                      exc_info=True)
Esempio n. 25
0
    def acquire(self, when):
        old_owner = self._owner()
        if when is self.IF_UNOWNED and old_owner != XNone:
            raise AlreadyOwned

        self.clipboard.set_with_data([("VERSION", 0, 0)], self._get,
                                     self._clear, None)

        # Having acquired the selection, we have to announce our existence
        # (ICCCM 2.8, still).  The details here probably don't matter too
        # much; I've never heard of an app that cares about these messages,
        # and metacity actually gets the format wrong in several ways (no
        # MANAGER or owner_window atoms).  But might as well get it as right
        # as possible.

        # To announce our existence, we need:
        #   -- the timestamp we arrived at
        #   -- the manager selection atom
        #   -- the window that registered the selection
        # Of course, because Gtk is doing so much magic for us, we have to do
        # some weird tricks to get at these.

        # Ask ourselves when we acquired the selection:
        ts_data = self.clipboard.wait_for_contents("TIMESTAMP").data
        #data is a timestamp, X11 datatype is Time which is CARD32,
        #(which is 64 bits on 64-bit systems!)
        Lsize = calcsize("@L")
        if len(ts_data) == Lsize:
            ts_num = unpack("@L", ts_data[:Lsize])[0]
        else:
            ts_num = 0  #CurrentTime
            log.warn("invalid data for 'TIMESTAMP': %s",
                     ([hex(ord(x)) for x in ts_data]))
        # Calculate the X atom for this selection:
        selection_xatom = get_xatom(self.atom)
        # Ask X what window we used:
        self._xwindow = X11Window.XGetSelectionOwner(self.atom)

        root = self.clipboard.get_display().get_default_screen(
        ).get_root_window()
        X11Window.sendClientMessage(root.xid, root.xid, False,
                                    StructureNotifyMask, "MANAGER", ts_num,
                                    selection_xatom, self._xwindow, 0, 0)

        if old_owner != XNone and when is self.FORCE:
            # Block in a recursive mainloop until the previous owner has
            # cleared out.
            def getwin():
                window = get_pywindow(self.clipboard, old_owner)
                window.set_events(window.get_events() | gtk.gdk.STRUCTURE_MASK)
                return window

            try:
                window = trap.call_synced(getwin)
                log("got window")
            except XError:
                log("Previous owner is already gone, not blocking")
            else:
                log("Waiting for previous owner to exit...")
                add_event_receiver(window, self)
                gtk.main()
                log("...they did.")
        window = get_pywindow(self.clipboard, self._xwindow)
        window.set_title("Xpra-ManagerSelection")
Esempio n. 26
0
    def set_screen_size(self, desired_w, desired_h):
        root_w, root_h = gtk.gdk.get_default_root_window().get_size()
        if desired_w==root_w and desired_h==root_h and not self.fake_xinerama:
            return    root_w,root_h    #unlikely: perfect match already!
        #find the "physical" screen dimensions, so we can calculate the required dpi
        #(and do this before changing the resolution)
        wmm, hmm = 0, 0
        client_w, client_h = 0, 0
        sss = self._server_sources.values()
        for ss in sss:
            for s in ss.screen_sizes:
                if len(s)>=10:
                    #display_name, width, height, width_mm, height_mm, monitors, work_x, work_y, work_width, work_height
                    client_w = max(client_w, s[1])
                    client_h = max(client_h, s[2])
                    wmm = max(wmm, s[3])
                    hmm = max(hmm, s[4])
        xdpi = self.default_dpi or self.dpi or 96
        ydpi = self.default_dpi or self.dpi or 96
        if wmm>0 and hmm>0 and client_w>0 and client_h>0:
            #calculate "real" dpi using integer calculations:
            xdpi = client_w * 254 / wmm / 10
            ydpi = client_h * 254 / hmm / 10
        log("calculated DPI: %s x %s (from w: %s / %s, h: %s / %s)", xdpi, ydpi, client_w, wmm, client_h, hmm)
        self.set_dpi(xdpi, ydpi)

        #try to find the best screen size to resize to:
        new_size = None
        for w,h in RandR.get_screen_sizes():
            if w<desired_w or h<desired_h:
                continue            #size is too small for client
            if new_size:
                ew,eh = new_size
                if ew*eh<w*h:
                    continue        #we found a better (smaller) candidate already
            new_size = w,h
        if not new_size:
            log.warn("resolution not found for %sx%s", desired_w, desired_h)
            return  root_w, root_h
        log("best resolution for client(%sx%s) is: %s", desired_w, desired_h, new_size)
        #now actually apply the new settings:
        w, h = new_size
        xinerama_changed = self.save_fakexinerama_config()
        #we can only keep things unchanged if xinerama was also unchanged
        #(many apps will only query xinerama again if they get a randr notification)
        if (w==root_w and h==root_h) and not xinerama_changed:
            log.info("best resolution matching %sx%s is unchanged: %sx%s", desired_w, desired_h, w, h)
            return  root_w, root_h
        try:
            if (w==root_w and h==root_h) and xinerama_changed:
                #xinerama was changed, but the RandR resolution will not be...
                #and we need a RandR change to force applications to re-query it
                #so we temporarily switch to another resolution to force
                #the change! (ugly! but this works)
                temp = {}
                for tw,th in RandR.get_screen_sizes():
                    if tw!=w or th!=h:
                        #use the number of extra pixels as key:
                        #(so we can choose the closest resolution)
                        temp[abs((tw*th) - (w*h))] = (tw, th)
                if len(temp)==0:
                    log.warn("cannot find a temporary resolution for Xinerama workaround!")
                else:
                    k = sorted(temp.keys())[0]
                    tw, th = temp[k]
                    log.info("temporarily switching to %sx%s as a Xinerama workaround", tw, th)
                    RandR.set_screen_size(tw, th)
            log.debug("calling RandR.set_screen_size(%s, %s)", w, h)
            trap.call_synced(RandR.set_screen_size, w, h)
            log.debug("calling RandR.get_screen_size()")
            root_w, root_h = RandR.get_screen_size()
            log.debug("RandR.get_screen_size()=%s,%s", root_w, root_h)
            if root_w!=w or root_h!=h:
                log.error("odd, failed to set the new resolution, "
                          "tried to set it to %sx%s and ended up with %sx%s", w, h, root_w, root_h)
            else:
                msg = "server virtual display now set to %sx%s" % (root_w, root_h)
                if desired_w!=root_w or desired_h!=root_h:
                    msg += " (best match for %sx%s)" % (desired_w, desired_h)
                log.info(msg)
            def show_dpi():
                sizes_mm = RandR.get_screen_sizes_mm()      #ie: [(1280, 1024)]
                assert len(sizes_mm)>0
                wmm = sum([x[0] for x in sizes_mm]) / len(sizes_mm)
                hmm = sum([x[1] for x in sizes_mm]) / len(sizes_mm)
                actual_xdpi = int(root_w * 25.4 / wmm + 0.5)
                actual_ydpi = int(root_h * 25.4 / hmm + 0.5)
                if actual_xdpi==xdpi and actual_ydpi==ydpi:
                    log.info("DPI set to %s x %s", xdpi, ydpi)
                else:
                    log.info("DPI set to %s x %s (wanted %s x %s)", actual_xdpi, actual_ydpi, xdpi, ydpi)
            #show dpi via idle_add so server has time to change the screen size (mm)
            self.idle_add(show_dpi)
        except Exception, e:
            log.error("ouch, failed to set new resolution: %s", e, exc_info=True)
Esempio n. 27
0
 def fake_key(self, keycode, press):
     keylog("fake_key(%s, %s)", keycode, press)
     trap.call_synced(X11Keyboard.xtest_fake_key, keycode, press)
Esempio n. 28
0
 def _manage_client(self, gdkwindow):
     try:
         if gdkwindow not in self._windows:
             trap.call_synced(self.do_manage_client, gdkwindow)
     except Exception, e:
         log("failed to manage client %s: %s", gdkwindow, e)
Esempio n. 29
0
def prop_set(target, key, etype, value):
    trap.call_synced(X11Window.XChangeProperty, get_xwindow(target), key,
                     _prop_encode(target, etype, value))