Beispiel #1
0
class MainWindow(QMainWindow):

    writeToPDFSignal = Signal(str, str)

    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)
        self.mainWindow = getUiFromFile(os.path.join(ROOT_DIR,"UI/mainwindow.ui"))
        self.setCentralWidget(self.mainWindow)


        # Visualization Part
        # accessing Motivo

        self.fileDialog = QFileDialog()

        self.userPreferencesDialog = UserPreferencesDialog()
        self.svgCache = ImageProvider(100)

        self.errorMessage = QMessageBox()

        self.csvFilePath = None

        self.writeToPDFThread = QThread(self)
        self.writeToPDF = ResultsExporter(self.svgCache)
        self.writeToPDF.moveToThread(self.writeToPDFThread)
        # TO DO: Creating a queue for motivo sessions

        # hide Layout

        self.mainWindow.writeToPdfProgressBar.hide()
        self.mainWindow.cancelWritingToPDFButton.hide()
        self.mainWindow.writeToPdfLabel.hide()

        # Creating the dialogs for menu bar actions

        self.basicDialog = BasicDialog()
        self.advancedDialog = AdvancedDialog()

        # Creating connections between menu bar actions and dialogs

        # File

        self.mainWindow.actionExit.triggered.connect(self.exit)

        # Motivo

        self.mainWindow.actionBasic.triggered.connect(self.openBasicDialog)
        self.mainWindow.actionAdvanced.triggered.connect(self.openAdvancedDialog)
        self.mainWindow.actionSaveAsPDF.triggered.connect(self.startWriteToPDFThread)
        self.mainWindow.actionOpenCSV.triggered.connect(self.openSelectCsv)

        self.writeToPDFSignal.connect(self.writeToPDF.setData)

        # Options
        self.mainWindow.actionUserPreferences.triggered.connect(self.openUserPreferencesDialog)

        # visualization

        self.basicDialog.outputReady.connect(self.visualizeFromBasicDialog)
        self.advancedDialog.outputReady.connect(self.visualizeFromAdvancedDialog)

        self.writeToPDF.progress.connect(self.updateWriteToPDFProgress)
        self.writeToPDF.finished.connect(self.writeToPdfComplete)
        self.mainWindow.cancelWritingToPDFButton.clicked.connect(self.cancelWritingToPDF)


    # functions called through menuBar actions

    def exit(self):
        self.close()

    def openBasicDialog(self):
        self.basicDialog.show()

    def openAdvancedDialog(self):
        self.advancedDialog.show()

    def openUserPreferencesDialog(self):
        self.userPreferencesDialog.show()

    def checkMotivoDirectory(self):
        if MotivoAccess.motivoDirectory == '':
            motivoDirError = QMessageBox()
            motivoDirError.critical(self.mainWindow, "motivo", "Motivo directory not found, please set the directory in User Preferences")

    def openSelectCsv(self):
        filePathAndName = self.fileDialog.getOpenFileName()[0]

        if filePathAndName[filePathAndName.rfind('.'):] == '.csv':
            self.csvFilePath = filePathAndName
            self.visualizeFromOpenCSV()
        elif filePathAndName != '':
            self.errorMessage.critical(self.mainWindow, "Visualize from a csv file", "Incorrect file format")

    def visualizeFromOpenCSV(self):
        self.updateMainGraphletWidget(self.csvFilePath)

    def visualizeFromBasicDialog(self):
        self.csvFilePath = self.basicDialog.getOutputFile() + '.csv'
        self.updateMainGraphletWidget(self.csvFilePath)

    def visualizeFromAdvancedDialog(self):
        self.csvFilePath = self.advancedDialog.getOutputFile() + '.csv'
        self.updateMainGraphletWidget(self.csvFilePath)


    def updateMainGraphletWidget(self,outputCsvFilePath):
        # Reset the widgets
        self.mainWindow.resultsView.clearSpans() 
        for i in reversed(range(self.mainWindow.plotLayout.count())): 
            self.mainWindow.plotLayout.itemAt(i).widget().setParent(None)
        try:  
            with open(outputCsvFilePath) as fh:
                csvreader = csv.reader(fh)
                headers = next(csvreader)
                headers.insert(1,"Graph")
                data = list(csvreader)
        except FileNotFoundError:
            print("Results file not found")
        results = ResultVisualizer(self.svgCache,data,headers,self.mainWindow.resultsView,self.mainWindow.plotLayout)
        results.visualizeMotif()
        results.visualizeChart()

    def startWriteToPDFThread(self):

        if self.csvFilePath == None:
            self.errorMessage.about(self.mainWindow, 'Save As PDF', 'Nothing to save')
            return

        pdfFileName = self.fileDialog.getSaveFileName()[0]

        if pdfFileName == '':
            return

        #self.writeToPDFThread.setTerminationEnabled(True)

        self.writeToPDFThread.start()

        self.mainWindow.writeToPdfProgressBar.setValue(0)
        self.showWriteToPdfProgressBar()

        self.writeToPDFSignal.emit(self.csvFilePath, pdfFileName)

    def updateWriteToPDFProgress(self, progress):
        self.mainWindow.writeToPdfProgressBar.setValue(progress)

    def writeToPdfComplete(self):
        self.mainWindow.writeToPdfProgressBar.setValue(100)

        self.hideWriteToPdfProgressBar()

        self.writeToPDFThread.quit()

    def showWriteToPdfProgressBar(self):
        self.mainWindow.writeToPdfProgressBar.show()
        self.mainWindow.cancelWritingToPDFButton.show()
        self.mainWindow.writeToPdfLabel.show()

    def hideWriteToPdfProgressBar(self):
        self.mainWindow.writeToPdfProgressBar.hide()
        self.mainWindow.cancelWritingToPDFButton.hide()
        self.mainWindow.writeToPdfLabel.hide()

    def cancelWritingToPDF(self):
        self.hideWriteToPdfProgressBar()
        self.writeToPDFThread.requestInterruption()
        self.writeToPDFThread.quit()
Beispiel #2
0
class X11GameManager(GameManager):
    connection: xcffib.Connection

    _instances: Dict[int, X11GameInstance]
    _atom: Dict[bytes, int]
    _shm: List[Tuple[int, sysv_ipc.SharedMemory]]

    def __init__(self, **kwargs):
        super().__init__(*kwargs)
        self._instances = {}
        self._atom = {}
        self._shm = []

        self.logger = logging.getLogger(__name__ + "." + self.__class__.__name__)
        self.connection = xcffib.Connection()
        self.screen = self.connection.get_screen_pointers()[self.connection.pref_screen]
        self.xcomposite = self.connection(xcffib.composite.key)
        self.xshm = self.connection(xcffib.shm.key)
        self.xinput = self.connection(xcffib.xinput.key)
        self._setup_composite()
        self._setup_overlay()

        self.event_thread = QThread(self)

        self.event_worker = X11EventWorker(self)
        self.event_worker.moveToThread(self.event_thread)
        self.event_thread.started.connect(self.event_worker.run)
        self.event_thread.finished.connect(self.event_worker.deleteLater)
        self.event_worker.create_signal.connect(self.on_game_opened)
        self.event_worker.destroy_signal.connect(self.on_game_closed)

        self.event_thread.start()

        self.get_instances()

    def stop(self):
        self.event_thread.requestInterruption()
        self.event_thread.quit()
        self.event_thread.wait()

    def get_instances(self) -> List[GameInstance]:
        def visit(wid: int):
            if self.is_game(wid):
                if wid not in self._instances:
                    self.logger.info("Found game instance %d", wid)
                    instance = X11GameInstance(self, wid, parent=self)
                    self._instances[wid] = instance

            try:
                query = self.connection.core.QueryTree(wid).reply()
                for child in query.children:
                    visit(child)
            except xcffib.xproto.WindowError:
                return

        visit(self.screen.root)

        return list(self._instances.values())

    def get_active_instance(self) -> Union[GameInstance, None]:
        for instance in self._instances.values():
            if instance.is_focused():
                return instance

        return None

    def is_game(self, wid: int) -> bool:
        geom_req = self.connection.core.GetGeometry(wid)
        try:
            wm_class = self.get_property(wid, xcffib.xproto.Atom.WM_CLASS)
        except xcffib.xproto.WindowError:
            geom_req.discard_reply()
            return False

        geom = geom_req.reply()
        if geom.width == 32 and geom.height == 32:
            # OpenGL test window
            return False

        if not wm_class:
            return False

        instance_name, app_name = wm_class.split("\00")
        return app_name == WM_APP_NAME

    def get_active_window(self) -> int:
        return self.get_property(self.screen.root, "_NET_ACTIVE_WINDOW")

    def _setup_overlay(self):
        self.overlay = DesktopWideOverlay()
        self.overlay.show()
        self.overlay.check_compatibility()

    def _setup_composite(self):
        self.xcomposite.QueryVersion(0, 4, is_checked=True)

    def get_property(
        self,
        wid: int,
        name: str,
        type_=xcffib.xproto.GetPropertyType.Any,
        index=0,
        max_values=1000,
    ):
        reply = self.connection.core.GetProperty(
            False,
            wid,
            self.get_atom(name),
            type_,
            index,
            max_values,
        ).reply()

        if reply.type == xcffib.xproto.Atom.STRING:
            return reply.value.to_string()[:-1]
        elif reply.type in (xcffib.xproto.Atom.WINDOW, xcffib.xproto.Atom.CARDINAL):
            return struct.unpack("=I", reply.value.buf()[:4])[0]

        return reply.value

    def get_atom(self, atom: str) -> int:
        if isinstance(atom, int):
            return atom

        if hasattr(xcffib.xproto.Atom, atom):
            return getattr(xcffib.xproto.Atom, atom)

        atom = atom.encode("ascii")

        if atom in self._atom:
            return self._atom[atom]

        out = self.connection.core.InternAtom(False, len(atom), atom).reply().atom
        self._atom[atom] = out

        return out

    def get_shm(self, size: int) -> Tuple[int, sysv_ipc.SharedMemory]:
        for item in self._shm:
            if item[1].size >= size:
                self._shm.remove(item)
                return item

        shm = sysv_ipc.SharedMemory(None, flags=sysv_ipc.IPC_CREX, size=size)
        xid = self.connection.generate_id()
        self.xshm.Attach(xid, shm.id, False, is_checked=True)
        return xid, shm

    def free_shm(self, shm: Tuple[int, sysv_ipc.SharedMemory]):
        self._shm.append(shm)
        self.gc_shm()

    def gc_shm(self):
        while len(self._shm) > MAX_SHM:
            xid, shm = self._shm.pop(0)
            self.xshm.Detach(xid)
            shm.detach()
            shm.remove()

    @Slot(xcffib.Event)
    def on_game_opened(self, evt: xcffib.xproto.CreateNotifyEvent):
        self.logger.info("New game window opened %d", evt.window)
        self._instances[evt.window] = X11GameInstance(self, evt.window, parent=self)

    @Slot(int)
    def on_game_closed(self, wid: int):
        if wid not in self._instances:
            return

        self.logger.info("Game window %d closed", wid)
        instance = self._instances[wid]
        del self._instances[wid]
        self.instance_removed.emit(instance)
        self.instance_changed.emit()
Beispiel #3
0
class X11GameManager(GameManager):
    connection: xcffib.Connection

    _instances: Dict[int, X11GameInstance]
    _atom: Dict[bytes, int]
    _shm: List[Tuple[int, sysv_ipc.SharedMemory]]

    def __init__(self, **kwargs):
        super().__init__(*kwargs)
        self._instances = {}
        self._atom = {}
        self._shm = []

        self.connection = xcffib.Connection()
        self.screen = self.connection.get_screen_pointers()[self.connection.pref_screen]
        self.xcomposite = self.connection(xcffib.composite.key)
        self.xshm = self.connection(xcffib.shm.key)
        self.xinput = self.connection(xcffib.xinput.key)
        self._setup_composite()
        self._setup_overlay()

        self.event_thread = QThread(self)

        self.event_worker = X11EventWorker(self)
        self.event_worker.moveToThread(self.event_thread)
        self.event_thread.started.connect(self.event_worker.run)
        self.event_thread.finished.connect(self.event_worker.deleteLater)

        self.event_thread.start()

    def stop(self):
        self.event_thread.requestInterruption()
        self.event_thread.quit()
        self.event_thread.wait()

    def get_instances(self) -> List[GameInstance]:
        def visit(wid: int):
            wm_class = self.get_property(wid, xcffib.xproto.Atom.WM_CLASS)

            if wm_class:
                instance_name, app_name = wm_class.split("\00")
                if app_name == WM_APP_NAME:
                    if wid not in self._instances:
                        instance = X11GameInstance(self, wid, parent=self)
                        self._instances[wid] = instance

            query = self.connection.core.QueryTree(wid).reply()
            for child in query.children:
                visit(child)

        visit(self.screen.root)

        return list(self._instances.values())

    def get_active_window(self) -> int:
        return self.get_property(self.screen.root, "_NET_ACTIVE_WINDOW")

    def _setup_overlay(self):
        self.overlay = DesktopWideOverlay()
        self.overlay.show()

    def _setup_composite(self):
        self.xcomposite.QueryVersion(0, 4, is_checked=True)

    def get_property(
        self,
        wid: int,
        name: str,
        type_=xcffib.xproto.GetPropertyType.Any,
        index=0,
        max_values=1000,
    ):
        reply = self.connection.core.GetProperty(
            False,
            wid,
            self.get_atom(name),
            type_,
            index,
            max_values,
        ).reply()

        if reply.type == xcffib.xproto.Atom.STRING:
            return reply.value.to_string()[:-1]
        elif reply.type in (xcffib.xproto.Atom.WINDOW, xcffib.xproto.Atom.CARDINAL):
            return struct.unpack("=I", reply.value.buf()[:4])[0]

        return reply.value

    def get_atom(self, atom: str) -> int:
        if isinstance(atom, int):
            return atom

        if hasattr(xcffib.xproto.Atom, atom):
            return getattr(xcffib.xproto.Atom, atom)

        atom = atom.encode("ascii")

        if atom in self._atom:
            return self._atom[atom]

        out = self.connection.core.InternAtom(False, len(atom), atom).reply().atom
        self._atom[atom] = out

        return out

    def get_shm(self, size: int) -> Tuple[int, sysv_ipc.SharedMemory]:
        for item in self._shm:
            if item[1].size >= size:
                self._shm.remove(item)
                return item

        shm = sysv_ipc.SharedMemory(None, flags=sysv_ipc.IPC_CREX, size=size)
        xid = self.connection.generate_id()
        self.xshm.Attach(xid, shm.id, False, is_checked=True)
        return xid, shm

    def free_shm(self, shm: Tuple[int, sysv_ipc.SharedMemory]):
        self._shm.append(shm)
        self.gc_shm()

    def gc_shm(self):
        while len(self._shm) > MAX_SHM:
            xid, shm = self._shm.pop(0)
            self.xshm.Detach(xid)
            shm.detach()
            shm.remove()