def do_make_screenshot_packet(self): log("grabbing screenshot") regions = [] OR_regions = [] for wid in reversed(sorted(self._id_to_window.keys())): window = self._id_to_window.get(wid) log("screenshot: window(%s)=%s", wid, window) if window is None or window.is_tray() or not window.is_managed(): continue pixmap = window.get_property("client-contents") log("screenshot: pixmap(%s)=%s", window, pixmap) if pixmap is None: continue if window.is_OR(): x, y = window.get_property("geometry")[:2] else: x, y = self._desktop_manager.window_geometry(window)[:2] log("screenshot: position(%s)=%s,%s", window, x, y) w, h = pixmap.get_size() log("screenshot: size(%s)=%sx%s", pixmap, w, h) item = (wid, x, y, w, h, pixmap) if window.is_OR(): OR_regions.append(item) elif self._has_focus==wid: #window with focus first (drawn last) regions.insert(0, item) else: regions.append(item) all_regions = OR_regions+regions if len(all_regions)==0: log("screenshot: no regions found, returning empty 0x0 image!") return ["screenshot", 0, 0, "png", -1, ""] log("screenshot: found regions=%s, OR_regions=%s", regions, OR_regions) minx = min([x for (_,x,_,_,_,_) in all_regions]) miny = min([y for (_,_,y,_,_,_) in all_regions]) maxx = max([(x+w) for (_,x,_,w,_,_) in all_regions]) maxy = max([(y+h) for (_,_,y,_,h,_) in all_regions]) width = maxx-minx height = maxy-miny log("screenshot: %sx%s, min x=%s y=%s", width, height, minx, miny) from PIL import Image image = Image.new("RGBA", (width, height)) for wid, x, y, w, h, pixmap in reversed(all_regions): _, _, wid, _, _, w, h, _, raw_data, rowstride, _, _ = get_rgb_rawdata(0, 0, wid, pixmap, 0, 0, w, h, "rgb24", -1, None, logger=log.debug) window_image = Image.fromstring("RGB", (w, h), raw_data, "raw", "RGB", rowstride) tx = x-minx ty = y-miny image.paste(window_image, (tx, ty)) buf = StringIO() image.save(buf, "png") data = buf.getvalue() buf.close() packet = ["screenshot", width, height, "png", rowstride, Compressed("png", data)] log("screenshot: %sx%s %s", packet[1], packet[2], packet[-1]) return packet
def process_damage_region(self, damage_time, window, x, y, w, h, coding, options): """ Called by 'damage' or 'send_delayed_regions' to process a damage region, we extract the rgb data from the pixmap and place it on the damage queue. This runs in the UI thread. """ if w == 0 or h == 0: return # It's important to acknowledge changes *before* we extract them, # to avoid a race condition. if not window.is_managed(): log.warn("the window %s is not composited!?", window) return window.acknowledge_changes() self._sequence += 1 sequence = self._sequence pixmap = window.get_property("client-contents") if self.is_cancelled(sequence): log("get_window_pixmap: dropping damage request with sequence=%s", sequence) return None if pixmap is None: log.error( "get_window_pixmap: wtf, pixmap is None for window %s, wid=%s", window, self.wid) return process_damage_time = time.time() data = get_rgb_rawdata(damage_time, process_damage_time, self.wid, pixmap, x, y, w, h, coding, sequence, options) if not data: return log( "process_damage_regions: adding pixel data %s to queue, elapsed time: %s ms", data[:6], dec1(1000 * (time.time() - damage_time))) def make_data_packet(*args): #NOTE: this function is called from the damage data thread! packet = self.make_data_packet(*data) if packet: self.queue_damage_packet(pixmap, packet, damage_time, process_damage_time) if self.encoding in ("png", "rgb24"): #primary encoding is lossless, no need for auto-refresh return #auto-refresh: if self.auto_refresh_delay > 0 and not self.is_cancelled( sequence): client_options = packet[ 10] #info about this packet from the encoder gobject.idle_add(self.schedule_auto_refresh, window, w, h, coding, options, client_options) self.queue_damage(make_data_packet)
def process_damage_region(self, damage_time, window, x, y, w, h, coding, options): """ Called by 'damage' or 'send_delayed_regions' to process a damage region, we extract the rgb data from the pixmap and place it on the damage queue. This runs in the UI thread. """ if w==0 or h==0: return # It's important to acknowledge changes *before* we extract them, # to avoid a race condition. if not window.is_managed(): log.warn("the window %s is not composited!?", window) return window.acknowledge_changes() self._sequence += 1 sequence = self._sequence pixmap = window.get_property("client-contents") if self.is_cancelled(sequence): log("get_window_pixmap: dropping damage request with sequence=%s", sequence) return None if pixmap is None: log.error("get_window_pixmap: wtf, pixmap is None for window %s, wid=%s", window, self.wid) return process_damage_time = time.time() data = get_rgb_rawdata(damage_time, process_damage_time, self.wid, pixmap, x, y, w, h, coding, sequence, options) if not data: return log("process_damage_regions: adding pixel data %s to queue, elapsed time: %s ms", data[:6], dec1(1000*(time.time()-damage_time))) def make_data_packet(*args): #NOTE: this function is called from the damage data thread! packet = self.make_data_packet(*data) if packet: self.queue_damage_packet(pixmap, packet, damage_time, process_damage_time) if self.encoding in ("png", "rgb24"): #primary encoding is lossless, no need for auto-refresh return #auto-refresh: if self.auto_refresh_delay>0 and not self.is_cancelled(sequence): client_options = packet[10] #info about this packet from the encoder gobject.idle_add(self.schedule_auto_refresh, window, w, h, coding, options, client_options) self.queue_damage(make_data_packet)
def process_damage_region(self, damage_time, pixmap, x, y, w, h, coding, sequence, options): """ Called by 'damage_now' or 'send_delayed_regions' to process a damage region, we extract the rgb data from the pixmap and place it on the damage queue. """ if w == 0 or h == 0: return process_damage_time = time.time() data = get_rgb_rawdata(damage_time, process_damage_time, self.wid, pixmap, x, y, w, h, coding, sequence, options) if data: log( "process_damage_regions: adding pixel data %s to queue, elapsed time: %s ms", data[:6], dec1(1000 * (time.time() - damage_time))) def make_data_packet(*args): #NOTE: this function is called from the damage data thread! packet = self.make_data_packet(*data) if packet: self.queue_damage_packet(packet, damage_time, process_damage_time) self.queue_damage(make_data_packet)
def do_make_screenshot_packet(self): log("grabbing screenshot") regions = [] OR_regions = [] for wid in reversed(sorted(self._id_to_window.keys())): window = self._id_to_window.get(wid) log("screenshot: window(%s)=%s", wid, window) if window is None or window.is_tray() or not window.is_managed(): continue pixmap = window.get_property("client-contents") log("screenshot: pixmap(%s)=%s", window, pixmap) if pixmap is None: continue if window.is_OR(): x, y = window.get_property("geometry")[:2] else: x, y = self._desktop_manager.window_geometry(window)[:2] log("screenshot: position(%s)=%s,%s", window, x, y) w, h = pixmap.get_size() log("screenshot: size(%s)=%sx%s", pixmap, w, h) item = (wid, x, y, w, h, pixmap) if window.is_OR(): OR_regions.append(item) elif self._has_focus == wid: #window with focus first (drawn last) regions.insert(0, item) else: regions.append(item) all_regions = OR_regions + regions if len(all_regions) == 0: log("screenshot: no regions found, returning empty 0x0 image!") return ["screenshot", 0, 0, "png", -1, ""] log("screenshot: found regions=%s, OR_regions=%s", regions, OR_regions) minx = min([x for (_, x, _, _, _, _) in all_regions]) miny = min([y for (_, _, y, _, _, _) in all_regions]) maxx = max([(x + w) for (_, x, _, w, _, _) in all_regions]) maxy = max([(y + h) for (_, _, y, _, h, _) in all_regions]) width = maxx - minx height = maxy - miny log("screenshot: %sx%s, min x=%s y=%s", width, height, minx, miny) from PIL import Image image = Image.new("RGBA", (width, height)) for wid, x, y, w, h, pixmap in reversed(all_regions): _, _, wid, _, _, w, h, _, raw_data, rowstride, _, _ = get_rgb_rawdata( 0, 0, wid, pixmap, 0, 0, w, h, "rgb24", -1, None, logger=log.debug) window_image = Image.fromstring("RGB", (w, h), raw_data, "raw", "RGB", rowstride) tx = x - minx ty = y - miny image.paste(window_image, (tx, ty)) buf = StringIO() image.save(buf, "png") data = buf.getvalue() buf.close() packet = [ "screenshot", width, height, "png", rowstride, Compressed("png", data) ] log("screenshot: %sx%s %s", packet[1], packet[2], packet[-1]) return packet