コード例 #1
0
ファイル: recorder.py プロジェクト: kerryeon/test-macro
class Recorder:

    ID = {}
    QUEUE = {}

    def __init__(self, output: str, fps: float = 30.0):
        self._ewmh = EWMH()
        self._sct = None
        self._geometry = self._ewmh.getDesktopGeometry()
        self._writer = None
        self._output = output
        self._delay = 1.0 / fps
        self._fps = fps

        self._width = 0
        self._height = 0

        if not os.path.exists('recorded'):
            os.mkdir('recorded')

    async def record(self, wm_name: str):
        await self.__class__.wait(wm_name)
        asyncio.ensure_future(self._record(wm_name))

    @classmethod
    def fromCase(cls, case):
        return Recorder(cls.naming(case)).record

    @classmethod
    async def wait(cls, wm_name: str):
        # ID
        if wm_name not in cls.ID.keys():
            cls.ID[wm_name] = max([0, *cls.ID.values()])
        _id = cls.ID[wm_name]
        # wait by ID
        while (_id in cls.QUEUE.keys()) or (_id > len(cls.QUEUE)):
            await asyncio.sleep(0.1)
        cls.QUEUE[wm_name] = {
            'top': 0,
            'left': 0,
            'width': 0,
            'height': 0,
        }

    @classmethod
    async def signal(cls, wm_name: str):
        del cls.QUEUE[wm_name]

    @classmethod
    def naming(cls, case):
        def _shorten(name):
            # int
            if isinstance(name, float) and name % 1 == 0:
                return str(int(name))
            # maybe path
            if isinstance(name, str):
                return name.split('/')[-1]
            return str(name)

        return '_'.join(reversed([_shorten(c[1]) for c in case]))

    async def _record(self, wm_name: str):
        begin, tick = datetime.now(), 0
        tracking = False
        await asyncio.sleep(1)
        while True:
            ts_last = datetime.now()
            # retrieve
            try:
                frames = [
                    w for w in self._ewmh.getClientList()
                    if wm_name in (w.get_wm_name() or '')
                ]
                if len(frames) != 1:
                    if len(frames) > 1:
                        print(
                            '-' * 36 + '\n' +
                            f'!  {len(frames)} windows have been captured.\n' +
                            '.\n'.join(f'| {self._ewmh.getWmName(w).decode()}'
                                       for w in frames) + '\n' + ('-' * 36))
                        break
                    if tracking:
                        break
                    await asyncio.sleep(self._delay / 2)
                    continue
                # the only frame
                bbox = self._get_frame(frames[0]).get_geometry()
                monitor = {
                    'top': bbox.y,
                    'left': bbox.x,
                    'width': bbox.width,
                    'height': bbox.height
                }
            except Xlib.error.BadWindow:
                continue
            # move window
            if not tracking:
                tracking = True
                monitor = self._update_window(wm_name, monitor, frames[0])
                self._sct = mss.mss()
            if bbox.x + bbox.width > self._geometry[0]:
                monitor['width'] = self._geometry[0] - bbox.x
            if bbox.y + bbox.height > self._geometry[1]:
                monitor['height'] = self._geometry[1] - bbox.y
            img = np.array(self._sct.grab(monitor))
            img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
            self._write(img, wm_name)
            # end
            tick += 1
            ts = datetime.now()
            await asyncio.sleep(
                max(
                    0,
                    self._delay *
                    (tick - (ts - begin).total_seconds() * self._fps) * 0.9))
        # flush
        self.__close__()
        await self.__class__.signal(wm_name)

    def _write(self, img, wm_name):
        height, width = img.shape[:2]
        if self._writer is None or self._width != width or self._height != height:
            fourcc = cv2.VideoWriter_fourcc(*'FMP4')
            self._writer = cv2.VideoWriter(
                f'recorded/{self._output}-{"_".join(wm_name.lower().split(" "))}.avi',
                fourcc, self._fps, (width, height), False)
            self._width, self._height = width, height
        self._writer.write(img)

    def _get_frame(self, client):
        frame = client
        while frame.query_tree().parent != self._ewmh.root:
            frame = frame.query_tree().parent
        return frame

    def _update_window(self, wm_name, monitor, frame):
        width = sum(m['width'] for m in self.__class__.QUEUE.values())
        monitor['left'] = width
        monitor['top'] = 0
        if frame.get_wm_class() is None:
            w, h = monitor['width'], monitor['height']
        else:
            w, h = 0, None
        # TODO 2-d replacement
        self.__class__.QUEUE[wm_name] = monitor
        self._ewmh.setMoveResizeWindow(frame,
                                       x=monitor['left'],
                                       y=monitor['top'],
                                       w=w,
                                       h=h)
        self._ewmh.display.flush()
        return monitor

    def __close__(self):
        if hasattr(self, '_writer') and self._writer is not None:
            self._writer.release()
            self._writer = None
        if hasattr(self, '_sct') and self._sct is not None:
            self._sct.close()
            self._sct = None

    def __del__(self):
        self.__close__()
コード例 #2
0
ファイル: api.py プロジェクト: mrhitman/poulpe
 def set_win_size(hwnd, x, y, width, height):
     ewmh = EWMH()
     ewmh.setMoveResizeWindow(hwnd, 0, x, y, width, height)
     ewmh.display.flush()
コード例 #3
0
ファイル: resize.py プロジェクト: pet1330/window-manager
class wn_resize():

    def __init__(self):

        self.mousePressed = False
        self.startX = -1
        self.startY = -1
        self.isOpen = True
        self.nBoxesW = 6
        self.nBoxesH = 6
        self.windowSpaceSizeW = 300
        self.windowSpaceSizeH = 300
        self.windowBoxSizeW = 20
        self.windowBoxSizeH = 20
        self.margin = 25
        self.windowSizeW = 220
        self.windowSizeH = 220
        self.mPosX = -self.windowBoxSizeW
        self.mPosY = -self.windowBoxSizeH

        self.ewmh = EWMH()
        self.activeWindow = self.ewmh.getActiveWindow()
        if self.activeWindow == self.ewmh.getClientListStacking()[0]:
            return
        
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        self.window.set_decorated(False)
        self.window.set_default_size(self.windowSizeW,self.windowSizeH)
        self.window.set_size_request(self.windowSizeW, self.windowSizeH)
        self.window.set_resizable(False)
        self.window.set_position(gtk.WIN_POS_CENTER)
        self.window.set_property("skip-taskbar-hint", True)
        self.window.connect("destroy", self.cb_destroy)
        self.window.connect("delete_event", self.cb_destroy)
        self.window.connect("focus_out_event", self.cb_destroy)

        self.box = gtk.EventBox()
        self.area = gtk.DrawingArea()
        self.area.connect("expose-event", self.expose_cairo)

        self.box.connect("button-press-event", self.cb_press)
        self.box.connect("button-release-event", self.cb_release)
        self.box.connect("motion_notify_event", self.cb_motion)
        
        self.box.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK)

        self.box.add(self.area)
        self.window.add(self.box)
        self.window.set_keep_above(True)

        self.window.show_all()

        gtk.idle_add(self.present)

    def present(self):

        self.window.present()

    def expose_cairo(self, widget=None, event=None):
        nMonitors = screen.get_n_monitors()
        self.cairoWidget = widget
        self.cr = widget.window.cairo_create()

        self.cr.set_source_rgb(1, 1, 1)
        self.cr.rectangle(0, 0, self.windowSizeW, self.windowSizeH)
        self.cr.fill()

        for i in xrange(0, self.nBoxesW):
            for j in xrange(0, self.nBoxesH):

                self.cr.set_source_rgb(0.6, 0.6, 0.6)
                self.cr.rectangle((self.windowSpaceSizeW * i) + self.margin, (self.windowSpaceSizeH * j) + self.margin, self.windowBoxSizeW, self.windowBoxSizeH)
                self.cr.fill()

        if not self.mousePressed:

            if (self.mPosX - self.margin) % self.windowSpaceSizeW < self.windowBoxSizeW and self.mPosX < self.windowSizeW - self.margin and self.mPosX > self.margin:
                if (self.mPosY - self.margin) % self.windowSpaceSizeH < self.windowBoxSizeH and self.mPosY < self.windowSizeH - self.margin and self.mPosY > self.margin:

                    self.cr.set_source_rgb(.3, .3, .3)
                    self.cr.rectangle(self.mPosX - ((self.mPosX - self.margin) % self.windowSpaceSizeW), self.mPosY - ((self.mPosY - self.margin) % self.windowSpaceSizeH), self.windowBoxSizeW, self.windowBoxSizeH)
                    self.cr.fill()

        else:

            x1 = self.startX
            y1 = self.startY
            x2 = ((self.mPosX - ((self.mPosX - self.margin) % self.windowSpaceSizeW)) - self.margin) / self.windowSpaceSizeW 
            y2 = ((self.mPosY - ((self.mPosY - self.margin) % self.windowSpaceSizeH)) - self.margin) / self.windowSpaceSizeH

            if x2 < 0:
                x2 = 0
            if y2 < 0:
                y2 = 0
            if x2 > self.nBoxesW - 1:
                x2 = self.nBoxesW - 1
            if y2 > self.nBoxesH - 1:
                y2 = self.nBoxesH - 1

            if x1 > x2:
                x1 = x2
                x2 = self.startX
            if y1 > y2:
                y1 = y2
                y2 = self.startY

            for i in xrange(int(x1), int(x2) + 1):
                for j in xrange(int(y1), int(y2) + 1):
                    self.cr.set_source_rgb(0.3, 0.3, 0.3)
                    self.cr.rectangle((i * self.windowSpaceSizeW) + self.margin, (j * self.windowSpaceSizeH) + self.margin, self.windowBoxSizeW, self.windowBoxSizeH)
                    self.cr.fill()
    def redraw(self):

        self.cairoWidget.queue_draw()

    def cb_destroy(self, widget=None, event=None):

        self.window.destroy()
        self.isOpen = False

    def cb_press(self, widget=None, event=None):

        self.mPosX = event.x
        self.mPosY = event.y

        if (self.mPosX - self.margin) % self.windowSpaceSizeW < self.windowBoxSizeW and self.mPosX < self.windowSizeW - self.margin and self.mPosX > self.margin:
            if (self.mPosY - self.margin) % self.windowSpaceSizeH < self.windowBoxSizeH and self.mPosY < self.windowSizeH - self.margin and self.mPosY > self.margin:

                self.mousePressed = True
                self.startX = int((self.mPosX - self.margin) / self.windowSpaceSizeW)
                self.startY = int((self.mPosY - self.margin) / self.windowSpaceSizeH)

    def cb_release(self, widget=None, event=None):

        x1 = self.startX
        y1 = self.startY

        if x1 < 0 or y1 < 0:
            return

        x2 = ((event.x - ((event.x - self.margin) % self.windowSpaceSizeW)) - self.margin) / self.windowSpaceSizeW 
        y2 = ((event.y - ((event.y - self.margin) % self.windowSpaceSizeH)) - self.margin) / self.windowSpaceSizeH

        if x2 < 0:
            x2 = 0
        if y2 < 0:
            y2 = 0

        if x2 > self.nBoxesW - 1:
            x2 = self.nBoxesW - 1
        if y2 > self.nBoxesH - 1:
            y2 = self.nBoxesH - 1
        if x1 > x2:
            x1 = x2
            x2 = self.startX
        if y1 > y2:
            y1 = y2
            y2 = self.startY

        self.resize(x1, y1, x2, y2)    

        self.cb_destroy()

    def getDesktopDimensions(self):

        window = gtk.Window()
        screen = window.get_screen()
        lMonitors = []
        self.offset = 0

        for i in xrange(0, screen.get_n_monitors()):
            lMonitors.append([screen.get_monitor_geometry(i).width, screen.get_monitor_geometry(i).height])

        currentMonitorIndex = screen.get_monitor_at_window(screen.get_active_window())

        if currentMonitorIndex != 0:
            for i in xrange(0, currentMonitorIndex):
                self.offset += lMonitors[i][0]

        return lMonitors[currentMonitorIndex][0], lMonitors[currentMonitorIndex][1]

    def resize(self, x1, y1, x2, y2):

        grav = 0

        screenDimensions = self.getDesktopDimensions()

        sectionSizeW = screenDimensions[0] / self.nBoxesW
        sectionSizeH = screenDimensions[1] / self.nBoxesH

        xPos = int(screenDimensions[0] / self.nBoxesW * x1)
        yPos = int(screenDimensions[1] / self.nBoxesH * y1)

        width = int(((x2 + 1) - x1) * (screenDimensions[0]) / self.nBoxesW)
        height = int(((y2 + 1) - y1) * (screenDimensions[1]) / self.nBoxesH)

        self.ewmh.setWmState(self.activeWindow, 0, '_NET_WM_STATE_MAXIMIZED_HORZ')
        self.ewmh.setWmState(self.activeWindow, 0, '_NET_WM_STATE_MAXIMIZED_VERT')

        self.ewmh.setMoveResizeWindow(self.activeWindow, grav, self.offset + xPos, yPos, width, height)
        self.ewmh.display.flush()

    def cb_motion(self, widget=None, event=None):

        if event.is_hint:

            x, y, state = event.window.get_pointer()

        else:

            x = event.x
            y = event.y
            state = event.state
        
        self.mPosX = x
        self.mPosY = y

        self.redraw()