def main(): window = Window() display = Display() display.connect() print("connected to display") registry = display.get_registry() registry.dispatcher["global"] = registry_global_handler registry.dispatcher["global_remove"] = registry_global_remover registry.user_data = window display.dispatch(block=True) display.roundtrip() if window.compositor is None: raise RuntimeError("no compositor found") elif window.shell is None: raise RuntimeError("no shell found") elif window.shm is None: raise RuntimeError("no shm found") window.surface = window.compositor.create_surface() shell_surface = window.shell.get_shell_surface(window.surface) shell_surface.set_toplevel() shell_surface.dispatcher["ping"] = shell_surface_ping_handler frame_callback = window.surface.frame() frame_callback.dispatcher["done"] = redraw frame_callback.user_data = window create_window(window) redraw(frame_callback, 0, destroy_callback=False) while display.dispatch(block=True) != -1: pass import time time.sleep(1) display.disconnect()
def _run_client(): global got_compositor c = ClientDisplay() start = time.time() while time.time() < start + 10: try: c.connect() except Exception: time.sleep(0.1) continue break reg = c.get_registry() reg.dispatcher['global'] = _get_registry_callback c.roundtrip() c.disconnect()
def shell_surface_ping_handler(shell_surface, serial): shell_surface.pong(serial) window = {'compositor': None, 'shell': None, 'shm': None} display = Display() display.connect() registry = display.get_registry() registry.dispatcher['global'] = registry_global_handler registry.dispatcher['global_remove'] = registry_global_remover registry.user_data = window display.dispatch() display.roundtrip() assert window['compositor'] assert window['shell'] assert window['shm'] surface = window['compositor'].create_surface() shell_surface = window['shell'].get_shell_surface(surface) shell_surface.set_toplevel() shell_surface.dispatcher['ping'] = shell_surface_ping_handler region = window['compositor'].create_region() region.add(0, 0, WIDTH, HEIGHT) surface.set_opaque_region(region) # ----------
class WaylandClient(object): """High level interface for wayland client.""" preferred_formats = (WlShm.format.argb8888, WlShm.format.xrgb8888, WlShm.format.rgb565) def __init__(self): self.display = Display() self.connected = False self.formats = set() # initialize these to None self.compositor = None self.shell = None self.registry = None self.connect() def ensure_connected(self): if not self.connected: raise RuntimeError("Not connected") def connect(self): assert not self.connected self.width_mm = None self.height_mm = None self.display.connect() print("connected to display") registry = self.display.get_registry() registry.dispatcher["global"] = self.handler self.display.dispatch(block=True) self.display.roundtrip() if self.compositor is None: raise RuntimeError("no compositor found") elif self.shell is None: raise RuntimeError("no shell found") elif self.shm is None: raise RuntimeError("no shm found") while self.width_mm is None: self.display.dispatch(block=True) self.display.roundtrip() self.connected = True def create_window(self, width, height, on_paint): self.ensure_connected() return Window(self, width, height, on_paint) def handler(self, registry, id_, interface, version): if interface == "wl_compositor": self.compositor = registry.bind(id_, WlCompositor, version) elif interface == "wl_shell": self.shell = registry.bind(id_, WlShell, version) elif interface == "wl_shm": self.shm = registry.bind(id_, WlShm, version) self.shm.dispatcher["format"] = self.shm_format_handler elif interface == "wl_output": self.output = registry.bind(id_, WlOutput, version) self.output.dispatcher["geometry"] = self.geometry_handler self.output.dispatcher["mode"] = self.mode_handler else: print("Unhandled proxy:", interface) def run(self): self.ensure_connected() while self.display.dispatch(block=True) != -1: pass time.sleep(1) display.disconnect() def shm_format_handler(self, unused, format_): self.formats.add(WlShm.format(format_)) def geometry_handler(self, unused, x, y, width, height, *wtf): self.width_mm = width self.height_mm = height print(wtf) def mode_handler(self, unused, flags, width, height, refresh): # XXX: magic number should be the "current flag", i.e. ignore other modes. if flags & 0x01: self.mode_flags = flags self.width_pixels = width self.height_pixels = height self.refresh_mhz = refresh print("Output Mode: {}x{}@{} ({})".format(width, height, refresh, flags)) def create_buffer(self, width, height): stride = stride_for_format(width, client.best_format()) size = stride * height with AnonymousFile(size) as fd: shm_data = mmap.mmap(fd, size, prot=mmap.PROT_READ | mmap.PROT_WRITE, flags=mmap.MAP_SHARED) pool = client.shm.create_pool(fd, size) buff = pool.create_buffer(0, width, height, stride, WlShm.format.argb8888.value) pool.destroy() return shm_data, buff def best_format(self): for f in self.preferred_formats: if f in self.formats: return f raise ValueError("No supported formats!")
class Client(QObject): disconnected = Signal() def __init__(self, display: Union[str, int], qml_view: QUrl, gl_context: QOpenGLContext): super().__init__() self.qml_view = qml_view self.display = display self.wl_display = Display(display) self.wl_compositor = None self.wl_shm = None self.wl_embedder = None self.views = {} self.fd_notifier = None self.engine = Engine() self.component = None self.qml_view = qml_view self.connected = False self.gl_context = gl_context assert gl_context.isOpenGLES() surface = QOffscreenSurface() surface.setFormat(gl_context.format()) surface.create() gl_context.makeCurrent(surface) def __del__(self): print("Disconnecting from", self.display) if self.connected: self.stop() def start(self) -> None: assert not self.connected print("Connecting to", self.display) self.wl_display.connect() self.connected = True self.component = Component(self.engine, self.qml_view) self.component.load() self.component.relatedCreated.connect(self.on_related_created) registry = self.wl_display.get_registry() registry.dispatcher["global"] = self.on_global_object_added registry.dispatcher["global_remove"] = self.on_global_object_removed self.wl_display.dispatch(block=True) self.wl_display.roundtrip() self.fd_notifier = QSocketNotifier(self.wl_display.get_fd(), QSocketNotifier.Read) self.fd_notifier.activated.connect(self.on_can_read_wl_data) self.wl_display.dispatch() def stop(self) -> None: assert self.connected self.connected = False self.component.relatedCreated.disconnect(self.on_related_created) self.fd_notifier.activated.disconnect(self.on_can_read_wl_data) registry = self.wl_display.get_registry() registry.dispatcher["global"] = None registry.dispatcher["global_remove"] = None if self.wl_shm: self.wl_shm.dispatcher["format"] = None if self.wl_embedder: self.wl_embedder.dispatcher["ping"] = None self.wl_embedder.dispatcher["view_requested"] = None self.wl_compositor = None self.wl_shm = None self.wl_embedder = None self.wl_display.disconnect() self.disconnected.emit() # TODO: clear views self.fd_notifier = None self.component = None self.engine = None @Slot() def on_can_read_wl_data(self, *args): try: self.wl_display.read() self.wl_display.dispatch() self.wl_display.flush() except RuntimeError: self.stop() def on_global_object_added(self, registry, object_id, interface, version): print("Global object added:", registry, object_id, interface, version) if interface == "wl_compositor": print("got compositor") self.wl_compositor = registry.bind(object_id, WlCompositor, version) elif interface == "wl_shm": print("got shm") self.wl_shm = registry.bind(object_id, WlShm, version) self.wl_shm.dispatcher["format"] = self.on_shm_format elif interface == "dodo_proto_embedder": print("got embeder") self.wl_embedder = registry.bind(object_id, DodoProtoEmbedder, version) self.wl_embedder.dispatcher["ping"] = self.on_ping self.wl_embedder.dispatcher[ "view_requested"] = self.on_view_requested def on_global_object_removed(self, registry, object_id): print("Global object removed:", registry, object_id) def on_shm_format(self, shm, shm_format): print("Possible shmem format: {}".format( SHM_FORMAT.get(shm_format, shm_format))) def on_ping(self, embeder, serial): embeder.pong(serial) self.wl_display.flush() def create_view(self, serial: int, width: int, height: int, scale: int, rootItem): surface = self.wl_compositor.create_surface() wl_view = self.wl_embedder.create_view(serial, surface, width, height, scale) self.views[wl_view] = View(self.wl_display, self.gl_context, self.wl_shm, rootItem, wl_view, surface, width, height, scale) self.wl_display.flush() def on_view_requested(self, embedder, serial, width, height, scale, url): print("Request new view", serial, width, height, scale) item = self.component.create() if url: item.setProperty("url", url) self.create_view(serial, width, height, scale, item) @Slot() def on_related_created(self, view, item): self.create_view(0, view.width, view.height, view.scale, item)