Source code for dragonfly.windows.x11_monitor

#
# This file is part of Dragonfly.
# (c) Copyright 2007, 2008 by Christo Butcher
# Licensed under the LGPL.
#
#   Dragonfly is free software: you can redistribute it and/or modify it
#   under the terms of the GNU Lesser General Public License as published
#   by the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   Dragonfly is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#   Lesser General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public
#   License along with Dragonfly.  If not, see
#   <http://www.gnu.org/licenses/>.
#

import locale
from subprocess                     import Popen, PIPE

from six                            import string_types, binary_type

from dragonfly.windows.base_monitor import BaseMonitor
from dragonfly.windows.rectangle    import Rectangle


#===========================================================================
# Monitor class for storing info about a single display monitor.

[docs] class X11Monitor(BaseMonitor): """ The monitor class used on X11 (Linux). This implementation parses monitor information from ``xrandr``. """ #----------------------------------------------------------------------- # Methods for initialization and introspection. def __init__(self, name, rectangle): assert isinstance(name, string_types) self._name = name self._primary = False # Get a numeric value from the name that we can use as a handle. handle = hash(name) super(X11Monitor, self).__init__(handle, rectangle) def __repr__(self): return "%s(%s)" % (self.__class__.__name__, self._name) #----------------------------------------------------------------------- # Class methods to create new Monitor objects.
[docs] @classmethod def get_all_monitors(cls): # pylint: disable=R0912,R0914,R0915 # Suppress warnings about too many local variables. # Get updated monitor information from xrandr. try: p = Popen(["xrandr"], stdout=PIPE) stdout, _ = p.communicate() # Decode output if it is binary. encoding = locale.getpreferredencoding() if isinstance(stdout, binary_type): stdout = stdout.decode(encoding) # Handle non-zero return codes. if p.wait() > 0: print(stdout) raise RuntimeError("xrandr exited with non-zero return " "code %d" % p.returncode) except Exception as e: cls._log.error("Failed to execute command: %s. Is " "xrandr installed?", e) raise e # Parse output from xrandr. monitors = [] for line in stdout.split("\n")[1:]: # skip the first line # Skip disconnected monitors, output modes and empty lines. if not line or "disconnected" in line or line.startswith(" "): continue # Get the information we need. parts = line.split() name = parts.pop(0) primary = "primary" in parts if primary: # this monitor will be first in the list parts.remove("primary") # Find and remove info we don't need (e.g. 'connected' and # orientation info). i = 1 for i, part in enumerate(parts): if "(" in part: # e.g. '(normal' break parts = parts[1:i] # Skip disabled monitors (no reported mode info). if not parts: continue # Get resolution and position info. res_info = parts[0].split("+") dx, dy = res_info.pop(0).split("x") top_left_x, top_left_y = res_info # Convert values to integers and create a rectangle object # representing the monitor's dimensions and relative position. dx, dy = int(dx), int(dy) top_left_x, top_left_y = int(top_left_x), int(top_left_y) rectangle = Rectangle(top_left_x, top_left_y, dx, dy) # Get a new or updated monitor object and add it to the list. monitor = cls.get_monitor(name, rectangle) monitor.is_primary = primary # Ensure that the top_left monitor is the first in the list. if top_left_x == 0: monitors.insert(0, monitor) else: monitors.append(monitor) # Return the list of monitors. return monitors
#----------------------------------------------------------------------- # Methods that control attribute access. def _set_primary(self, value): self._primary = bool(value) is_primary = property(fget=lambda self: self._primary, fset=_set_primary, doc="Whether this is the " "primary display monitor.") def _set_name(self, name): assert isinstance(name, string_types) self._name = name # Also set the handle, as it is derived from the name. self._set_handle(hash(name)) name = property(fget=lambda self: self._name, fset=_set_name, doc="Protected access to name attribute.")