Beispiel #1
0
    def __init__(self,
                 parent=None,
                 url='',
                 width=None,
                 height=None,
                 isDialog=False):
        super(Window, self).__init__(parent if isDialog else None)
        self.assets = assets
        assets.windows.append(self)
        if width is None:
            width = assets.manifest['width']
        if height is None:
            height = assets.manifest['height']
        windowFlags = Qt.WindowTitleHint | \
            Qt.WindowSystemMenuHint | \
            Qt.WindowMinimizeButtonHint | \
            Qt.WindowMaximizeButtonHint | \
            Qt.WindowCloseButtonHint
        if isDialog:
            windowFlags |= Qt.Dialog
        else:
            windowFlags |= Qt.CustomizeWindowHint
        self.dragParams = {
            'type': 0,
            'x': self.shadowWidth,
            'y': self.shadowWidth,
            'size': 5,
            'draging': False
        }
        self.api = API(self)
        self.parent = parent
        self.resize(width, height)
        self.setMouseTracking(True)
        self.setWindowFlags(windowFlags)
        self.setAttribute(Qt.WA_QuitOnClose, True)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)

        self.setWindowTitle(assets.manifest['name'])
        self.setResizable(assets.manifest['resizable'])
        self.setFrameless(assets.manifest['frameless'])
        self.setWindowIcon(QIcon(assets.manifest['icon']))

        self._win_id = self.winId().__int__()

        self.webView = WebView(self, url)
        self.verticalLayout.addWidget(self.webView)

        if assets.manifest['debug']:
            shortcut = QShortcut(self)
            shortcut.setKey(Qt.Key_F12)
            shortcut.activated.connect(self.showInspector)

        self._old_window_state = self.windowState()
        self._is_max_to_min = False
        self._maximizable = True

        self.setClosable(True)
    def __init__(self, parent = None, url = '', width = None, height = None, isDialog = False):
        super(Window, self).__init__(parent if isDialog else None)
        self.assets = assets
        assets.windows.append(self)
        if width is None:
            width = assets.manifest['width']
        if height is None:
            height = assets.manifest['height']
        windowFlags = Qt.WindowTitleHint | \
            Qt.WindowSystemMenuHint | \
            Qt.WindowMinimizeButtonHint | \
            Qt.WindowMaximizeButtonHint | \
            Qt.WindowCloseButtonHint
        if isDialog:
            windowFlags |= Qt.Dialog
        else:
            windowFlags |= Qt.CustomizeWindowHint
        self.dragParams = {'type': 0, 'x': self.shadowWidth, 'y': self.shadowWidth, 'size': 5, 'draging': False}
        self.api = API(self)
        self.parent = parent
        self.resize(width, height)
        self.setMouseTracking(True)
        self.setWindowFlags(windowFlags)
        self.setAttribute(Qt.WA_QuitOnClose, True)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)

        self.setWindowTitle(assets.manifest['name'])
        self.setResizable(assets.manifest['resizable'])
        self.setFrameless(assets.manifest['frameless'])
        self.setWindowIcon(QIcon(assets.manifest['icon']))

        self._win_id = self.winId().__int__()

        self.webView = WebView(self, url)
        self.verticalLayout.addWidget(self.webView)

        if assets.manifest['debug']:
            shortcut = QShortcut(self)
            shortcut.setKey(Qt.Key_F12)
            shortcut.activated.connect(self.showInspector)

        self._old_window_state = self.windowState()
        self._is_max_to_min = False
        self._maximizable = True

        self.setClosable(True)
Beispiel #3
0
class Window(ShadowWindow):

    Move = 0b0000
    ResizeTop = 0b0001
    ResizeRight = 0b0010
    ResizeBottom = 0b0100
    ResizeLeft = 0b1000

    onshow = pyqtSignal()
    onhide = pyqtSignal()
    onfocus = pyqtSignal()
    onblur = pyqtSignal()
    onclose = pyqtSignal()
    onmove = pyqtSignal(int, int, int, int)
    onresize = pyqtSignal(int, int, int, int)
    onstatechange = pyqtSignal()
    onmouseenter = pyqtSignal()
    onmouseleave = pyqtSignal()

    windowLevel = LEVEL0


    def __init__(self, parent = None, url = '', width = None, height = None, isDialog = False):
        super(Window, self).__init__(parent if isDialog else None)

        self.assets = assets
        assets.windows.append(self)
        if width is None:
            width = assets.manifest['width']
        if height is None:
            height = assets.manifest['height']
        windowFlags = Qt.WindowTitleHint | \
            Qt.WindowSystemMenuHint | \
            Qt.WindowMinimizeButtonHint | \
            Qt.WindowMaximizeButtonHint | \
            Qt.WindowCloseButtonHint
        if isDialog:
            windowFlags |= Qt.Dialog
        else:
            windowFlags |= Qt.CustomizeWindowHint
        self.dragParams = {'type': 0, 'x': self.shadowWidth, 'y': self.shadowWidth, 'size': 5, 'draging': False}
        self.api = API(self)
        self.parent = parent
        self.resize(width, height)
        self.setMouseTracking(True)
        self.setWindowFlags(windowFlags)
        self.setAttribute(Qt.WA_QuitOnClose, True)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)

        self.setWindowTitle(assets.manifest['name'])
        self.setResizable(assets.manifest['resizable'])
        self.setFrameless(assets.manifest['frameless'])
        self.setWindowIcon(QIcon(assets.manifest['icon']))

        self._win_id = self.winId().__int__()

        self.webView = WebView(self, url)
        self.verticalLayout.addWidget(self.webView)

        if assets.manifest['debug']:
            shortcut = QShortcut(self)
            shortcut.setKey(Qt.Key_F12)
            shortcut.activated.connect(self.showInspector)

        self._old_window_state = self.windowState()
        self._is_max_to_min = False
        self._maximizable = True

        self.setClosable(True)

    def getXWindow(self):
        return xutils.get_xwindow(int(self.winId()))

    def hasWindowFlags(self, windowFlags):
        return int(self.windowFlags() & windowFlags) != 0

    def addWindowFlags(self, windowFlags):
        if not self.hasWindowFlags(windowFlags):
            flags = self.windowFlags()
            flags |= windowFlags
            self.setWindowFlags(flags)

    def removeWindowFlags(self, windowFlags):
        if self.hasWindowFlags(windowFlags):
            flags = self.windowFlags()
            flags = flags &~ windowFlags
            self.setWindowFlags(flags)

    def getCursorType(self, x, y):
        width = self.width()
        height = self.height()
        size = self.dragParams['size']
        margin = self.shadowWidth
        isResizableX = self.isResizableX()
        isResizableY = self.isResizableY()
        cursorType = Window.Move
        if x >= margin and x <= width - margin and y >= margin and y <= height - margin:
            if y <= size + margin and isResizableY:
                cursorType |= Window.ResizeTop
            elif y >= height - margin - size and isResizableY:
                cursorType |= Window.ResizeBottom
            if x <= size + margin and isResizableX:
                cursorType |= Window.ResizeLeft
            elif x >= width - margin - size and isResizableX:
                cursorType |= Window.ResizeRight
        return cursorType

    # Slots

    # 获取父窗口
    @pyqtSlot(result = QObject)
    def opener(self):
        return self.parent

    # 任务栏闪烁
    @pyqtSlot()
    @pyqtSlot(int)
    def alert(self, msec = 0):
        QApplication.alert(self, msec)

    # 执行简单的JS
    @pyqtSlot(str, result = QObject)
    def eval(self, javaScript):
        obj = QObject(self)
        obj.setObjectName('evalResult')
        obj.setProperty('result', self.webView.eval(javaScript))
        return obj

    # 截图
    @pyqtSlot(result = str)
    @pyqtSlot(bool, result = str)
    @pyqtSlot(bool, str, result = bool)
    def capture(self, fullScreen = False, filename = ''):
        if fullScreen:
            image = QApplication.primaryScreen().grabWindow(0)
        else:
            image = QImage(self.webView.mainFrame.contentsSize(), QImage.Format_ARGB32)
            painter = QPainter(image)
            self.webView.mainFrame.render(painter)
            painter.end()
        if filename:
            return image.save(filename)
        else:
            data = QByteArray()
            buffer = QBuffer(data)
            buffer.open(QBuffer.WriteOnly)
            image.save(buffer, 'PNG')
            return bytes(data.toBase64()).decode()

    # 打开开发者工具
    @pyqtSlot()
    def showInspector(self):
        self.webView.page().showInspector()

    # 关闭开发者工具
    @pyqtSlot()
    def hideInspector(self):
        self.webView.page().hideInspector()

    # 搜索文本
    @pyqtSlot(str, result = bool)
    def findText(self, text):
        return self.webView.page().findText(text)

    # 设置窗口图标
    @pyqtSlot(str)
    def setIcon(self, icon):
        if isinstance(icon, str):
            icon = QIcon(self.api.normUrl(icon))
        self.setWindowIcon(icon)

    # 设置内容是否已被修改(标题中需要有[*]标志)
    @pyqtSlot(bool)
    def setModified(self, modified):
        self.setWindowModified(modified)

    # 获取内容是否已被修改
    @pyqtSlot(result = bool)
    def isModified(self):
        return self.isWindowModified()

    # 设置是否模态
    @pyqtSlot(bool)
    def setModal(self, modal):
        super(Window, self).setModal(modal)

    # 获取是否模态
    @pyqtSlot(result = bool)
    def isModal(self):
        return super(Window, self).isModal()

    # 设置是否在任务栏中显示
    @pyqtSlot(bool)
    def setShowInTaskbar(self, showInTaskbar):
        if showInTaskbar:
            self.setWindowFlags(self.windowFlags() & ~ Qt.Tool)
        else:
            self.setWindowFlags(self.windowFlags() | Qt.Tool)

    # 获取是否在任务栏中显示
    @pyqtSlot(result = bool)
    def isShowInTaskbar(self):
        return self.hasWindowFlags(Qt.Tool)

    # 设置窗口是否置顶
    @pyqtSlot(bool)
    def setStaysOnTop(self, staysOnTop):
        if staysOnTop:
            xutils.do_stay_on_top(self.getXWindow())
        else:
            xutils.undo_stay_on_top(self.getXWindow())

    # 获取窗口是否置顶
    @pyqtSlot(result = bool)
    def isStaysOnTop(self):
        return xutils.is_stay_on_top(self.getXWindow())

    # 设置是否显示系统边框
    @pyqtSlot(bool)
    def setFrameless(self, frameless):
        if frameless:
            self.setWindowFlags(Qt.FramelessWindowHint)
        else:
            self.addWindowFlags(Qt.WindowMaximizeButtonHint)
            self.addWindowFlags(Qt.WindowMinMaxButtonsHint)
            self.addWindowFlags(Qt.WindowSystemMenuHint)
            self.removeWindowFlags(Qt.FramelessWindowHint)

    # 获取是否显示系统边框
    @pyqtSlot(result = bool)
    def isFrameless(self):
        return self.hasWindowFlags(Qt.FramelessWindowHint)

    # 设置是否背景透明
    @pyqtSlot(bool)
    def setTransBackground(self, transBackground):
        palette = self.palette()
        if transBackground:
            palette.setBrush(QPalette.Base, Qt.transparent)
        else:
            palette.setBrush(QPalette.Base, Qt.white)
        self.setPalette(palette)

    # 获取是否背景透明
    @pyqtSlot(result = bool)
    def isTransBackground(self):
        palette = self.palette()
        return palette.brush(QPalette.Base) == Qt.transparent

    # 设置是否鼠标事件穿透
    @pyqtSlot(bool)
    def setTransMouseEvent(self, transMouseEvent):
        self.setAttribute(Qt.WA_TransparentForMouseEvents, transMouseEvent)
        self.setWindowFlags(self.windowFlags() | Qt.WindowTitleHint)

    # 获取是否是否鼠标事件穿透
    @pyqtSlot(result = bool)
    def isTransMouseEvent(self):
        return self.testAttribute(Qt.WA_TransparentForMouseEvents)

    # 设置窗口不透明度
    @pyqtSlot(float)
    def setOpacity(self, opacity):
        self.setWindowOpacity(opacity)

    # 获取窗口不透明度
    @pyqtSlot(result = float)
    def getOpacity(self):
        return self.windowOpacity()

    # 设置尺寸是否可调整
    @pyqtSlot(bool)
    def setResizable(self, resizable):
        if resizable:
            self.setMinimumSize(5, 5)
            self.setMaximumSize(0xFFFFFF, 0xFFFFFF)
        else:
            self.setFixedSize(self.width(), self.height())

    # 获取尺寸是否可调整
    @pyqtSlot(result = bool)
    def isResizable(self):
        return self.minimumSize() != self.maximumSize()

    # 设置宽度是否可调整
    @pyqtSlot(bool)
    def setResizableX(self, resizableX):
        if resizableX:
            self.setMinimumWidth(5)
            self.setMaximumWidth(0xFFFFFF)
        else:
            self.setFixedWidth(self.width())

    # 获取宽度是否可调整
    @pyqtSlot(result = bool)
    def isResizableX(self):
        return self.minimumWidth() != self.maximumWidth()

    # 设置高度是否可调整
    @pyqtSlot(bool)
    def setResizableY(self, resizableY):
        if resizableY:
            self.setMinimumHeight(5)
            self.setMaximumHeight(0xFFFFFF)
        else:
            self.setFixedHeight(self.height())

    # 获取高度是否可调整
    @pyqtSlot(result = bool)
    def isResizableY(self):
        return self.minimumHeight() != self.maximumHeight()

    # 设置是否可最小化
    @pyqtSlot(bool)
    def setMinimizable(self, minimizable):
        if minimizable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMinimizeButtonHint)

    # 获取是否可最小化
    @pyqtSlot(result = bool)
    def isMinimizable(self):
        return True

    # 设置是否可最大化
    @pyqtSlot(bool)
    def setMaximizable(self, maximizable):
        if maximizable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMaximizeButtonHint)

    # 获取是否可最大化
    @pyqtSlot(result = bool)
    def isMaximizable(self):
        return self._maximizable

    # 设置是否可关闭
    @pyqtSlot(bool)
    def setClosable(self, closable):
        if closable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowCloseButtonHint)

    # 获取是否可关闭
    @pyqtSlot(result = bool)
    def isClosable(self):
        return self.hasWindowFlags(Qt.WindowCloseButtonHint)

    # 获取是否已最小化
    @pyqtSlot(result = bool)
    def isMinimized(self):
        return super(Window, self).isMinimized()

    # 获取是否已最大化
    @pyqtSlot(result = bool)
    def isMaximized(self):
        return super(Window, self).isMaximized()

    # 获取是否已最大化
    @pyqtSlot(result = bool)
    def isFullScreen(self):
        return super(Window, self).isFullScreen()

    # 最小化
    @pyqtSlot()
    def minimize(self):
        if self.isMinimizable():
            self.showMinimized()

    # 还原
    @pyqtSlot()
    def normalize(self):
        self.showNormal()

    # 最大化
    @pyqtSlot()
    def maximize(self):
        if self.isMaximizable():
            self.showMaximized()

    # 全屏
    @pyqtSlot()
    def showFullScreen(self):
        super(Window, self).showFullScreen()

    # 设置窗口坐标
    @pyqtSlot(int, int)
    def setPos(self, x, y):
        self.move(x, y)

    # 设置窗口尺寸
    @pyqtSlot(int, int)
    def setSize(self, width, height):
        self.resize(width, height)

    # 设置窗口最小尺寸
    @pyqtSlot(int, int)
    def setMinSize(self, width, height):
        self.setMinimumSize(width, height)

    # 设置窗口最大尺寸
    @pyqtSlot(int, int)
    def setMaxSize(self, width, height):
        self.setMaximumSize(width, height)

    # 设置尺寸控制大小
    @pyqtSlot(int)
    def setResizerSize(self, size):
        self.dragParams['size'] = size

    # 获取尺寸控制大小
    @pyqtSlot(result = int)
    def getResizerSize(self):
        return self.dragParams['size']

    # 是否正在拖动
    @pyqtSlot(result = bool)
    def isDraging(self):
        return self.dragParams['draging']

    # 开始拖动
    @pyqtSlot()
    def dragStart(self):
        self.dragParams['draging'] = True

    # 结束拖动
    @pyqtSlot()
    def dragStop(self):
        self.dragParams['type'] = Window.Move
        self.dragParams['draging'] = False

    # 窗口获取焦点
    @pyqtSlot()
    def activate(self):
        self.activateWindow()

    # 窗口是否已获得焦点
    @pyqtSlot(result = bool)
    def isActive(self):
        return self.isActiveWindow()

    # 设置窗口可用状态
    @pyqtSlot(bool)
    def setEnabled(self, enabled):
        super(Window, self).setEnabled(enabled)

    # 窗口是否可用
    @pyqtSlot(result = bool)
    def isEnabled(self):
        return super(Window, self).isEnabled()

    # 设置窗口可见状态
    @pyqtSlot(result = bool)
    def setVisible(self, visible):
        super(Window, self).setVisible(visible)

    # 窗口是否显示
    @pyqtSlot(result = bool)
    def isVisible(self):
        return super(Window, self).isVisible()

    # 关闭窗口
    @pyqtSlot()
    def close(self):
        super(Window, self).close()

    @pyqtSlot()
    def quit(self):
        for win in assets.windows:
            win.close()
        qApp.quit()

    # Events
    def keyPressEvent(self, event):
        if(event.key() == Qt.Key_Escape):
            event.ignore()

    # 被webview调用
    def mousePressEvent(self, event):
        self.dragParams['x'] = event.x()
        self.dragParams['y'] = event.y()
        self.dragParams['globalX'] = event.globalX()
        self.dragParams['globalY'] = event.globalY()
        self.dragParams['width'] = self.width()
        self.dragParams['height'] = self.height()
        if self.dragParams['type'] != Window.Move \
            and self.isFrameless() \
            and not self.isMaximized() \
            and not self.isFullScreen():
                self.dragStart()

    def mouseReleaseEvent(self, event):
        self.dragStop()

    def mouseMoveEvent(self, event):
        if self.isFrameless() and not self.isMaximized() and not self.isFullScreen():
            # 判断鼠标类型
            cursorType = self.dragParams['type']
            if not self.dragParams['draging']:
                cursorType = self.dragParams['type'] = self.getCursorType(event.x(), event.y())

            # 设置鼠标形状
            if cursorType in (Window.ResizeTop, Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeVerCursor)
            elif cursorType in (Window.ResizeLeft, Window.ResizeRight):
                self.webView.setCursor(Qt.SizeHorCursor)
            elif cursorType in (Window.ResizeTop | Window.ResizeRight, Window.ResizeLeft | Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeBDiagCursor)
            elif cursorType in (Window.ResizeTop | Window.ResizeLeft, Window.ResizeRight | Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeFDiagCursor)
            elif self.dragParams['draging']:
                self.webView.setCursor(Qt.ArrowCursor)
            else:
                self.webView.unsetCursor()

        # 判断窗口拖动
        dragType = self.dragParams['type']
        if self.dragParams['draging'] and not self.isMaximized() and not self.isFullScreen():
            x = self.x()
            y = self.y()
            width = self.width()
            height = self.height()
            if dragType == Window.Move:
                x = event.globalX() - self.dragParams['x']
                y = event.globalY() - self.dragParams['y']
            elif self.isFrameless():
                if dragType & Window.ResizeTop == Window.ResizeTop:
                    y = event.globalY() - self.shadowWidth
                    height = self.dragParams['height'] + self.dragParams['globalY'] - event.globalY()
                elif dragType & Window.ResizeBottom == Window.ResizeBottom:
                    height = self.dragParams['height'] - self.dragParams['globalY'] + event.globalY()
                if dragType & Window.ResizeLeft == Window.ResizeLeft:
                    x = event.globalX() - self.shadowWidth
                    width = self.dragParams['width'] + self.dragParams['globalX'] - event.globalX()
                elif dragType & Window.ResizeRight == Window.ResizeRight:
                    width = self.dragParams['width'] - self.dragParams['globalX'] + event.globalX()
            else:
                return

            if width < self.minimumWidth():
                width = self.minimumWidth()
            elif width > self.maximumWidth():
                width = self.maximumWidth()
            if height < self.minimumHeight():
                height = self.minimumHeight()
            elif height > self.maximumHeight():
                height = self.maximumHeight()

            xutils.set_geometry(self.getXWindow(), x, y, width, height)

    def changeEvent(self, event):
        if event.type() == QEvent.ActivationChange:
            if self.isActiveWindow():
                self.onfocus.emit()
            else:
                self.onblur.emit()
        elif event.type() == QEvent.WindowStateChange:
            new_window_state = self.windowState()
            if new_window_state == Qt.WindowMaximized or \
                    new_window_state == Qt.WindowFullScreen:
                self.setShadowWidth(0)
            else:
                self.setShadowWidth(10)
            self.onstatechange.emit()

            self._old_window_state = new_window_state

    def resizeEvent(self, event):
        self.onresize.emit(
                event.oldSize().width(), event.oldSize().height(),
                event.size().width(), event.size().height()
                )

        # workround: it can't be set Antialiasing in setRoundedCorners method
        # use `self.radius - 1` to workround the problem
        if self.radius > 1:
            self.webView.setRoundedCorners(self.webView.rect(), self.radius - 1)

    def moveEvent(self, event):
        pos = event.pos()
        oldPos = event.oldPos()
        self.onmove.emit(pos.x(), pos.y(), oldPos.x(), oldPos.y())

    def enterEvent(self, event):
        self.onmouseenter.emit()

    def leaveEvent(self, event):
        self.onmouseleave.emit()

    def showEvent(self, event):
        self.onshow.emit()

    def hideEvent(self, event):
        self.onhide.emit()

    def closeEvent(self, event):
        self.onclose.emit()
        if self.isClosable():
            self.webView.close()
            assets.windows = [i for i in assets.windows if i != self]
            event.accept()
        else:
            event.ignore()

    def event(self, event):
        if event.type() == QEvent.WindowStateChange:
            if int(self.windowState()) == 3 and \
               event.oldState() == Qt.WindowMaximized:
               self.windowLevel = LEVEL1
            # 3 -> minimized
            # minimized -> normal
            elif self.windowLevel == LEVEL1:
               self.windowLevel = LEVEL2
            # normal -> minimized
            elif self.windowLevel == LEVEL2:
               self.windowLevel = LEVEL3
            # minimized -> normal -> maximized
            elif self.windowLevel == LEVEL3:
               self.maximize()
               self.windowLevel = LEVEL0
        return super(Window, self).event(event)

    @pyqtSlot()
    def showCenter(self):
        screen = qApp.primaryScreen()
        geometry = screen.availableGeometry()
        x = geometry.x() + (geometry.width() - self.width())/2
        y = geometry.y() + (geometry.height() - self.height())/2
        self.move(x, y)
        self.show()

    @pyqtSlot()
    def showCurrentScreenCenter(self):
        screen = qApp.desktop()
        geometry = screen.screenGeometry(screen.screenNumber(QCursor.pos()))
        x = geometry.x() + (geometry.width() - self.width())/2
        y = geometry.y() + (geometry.height() - self.height())/2
        self.move(x, y)
        self.show()
class Window(ShadowWindow):

    Move = 0b0000
    ResizeTop = 0b0001
    ResizeRight = 0b0010
    ResizeBottom = 0b0100
    ResizeLeft = 0b1000

    onshow = pyqtSignal()
    onhide = pyqtSignal()
    onfocus = pyqtSignal()
    onblur = pyqtSignal()
    onclose = pyqtSignal()
    onmove = pyqtSignal(int, int, int, int)
    onresize = pyqtSignal(int, int, int, int)
    onstatechange = pyqtSignal()
    onmouseenter = pyqtSignal()
    onmouseleave = pyqtSignal()

    def __init__(self, parent = None, url = '', width = None, height = None, isDialog = False):
        super(Window, self).__init__(parent if isDialog else None)
        self.assets = assets
        assets.windows.append(self)
        if width is None:
            width = assets.manifest['width']
        if height is None:
            height = assets.manifest['height']
        windowFlags = Qt.WindowTitleHint | \
            Qt.WindowSystemMenuHint | \
            Qt.WindowMinimizeButtonHint | \
            Qt.WindowMaximizeButtonHint | \
            Qt.WindowCloseButtonHint
        if isDialog:
            windowFlags |= Qt.Dialog
        else:
            windowFlags |= Qt.CustomizeWindowHint
        self.dragParams = {'type': 0, 'x': self.shadowWidth, 'y': self.shadowWidth, 'size': 5, 'draging': False}
        self.api = API(self)
        self.parent = parent
        self.resize(width, height)
        self.setMouseTracking(True)
        self.setWindowFlags(windowFlags)
        self.setAttribute(Qt.WA_QuitOnClose, True)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)

        self.setWindowTitle(assets.manifest['name'])
        self.setResizable(assets.manifest['resizable'])
        self.setFrameless(assets.manifest['frameless'])
        self.setWindowIcon(QIcon(assets.manifest['icon']))

        self._win_id = self.winId().__int__()

        self.webView = WebView(self, url)
        self.verticalLayout.addWidget(self.webView)

        if assets.manifest['debug']:
            shortcut = QShortcut(self)
            shortcut.setKey(Qt.Key_F12)
            shortcut.activated.connect(self.showInspector)

        self._old_window_state = self.windowState()
        self._is_max_to_min = False
        self._maximizable = True

        self.setClosable(True)

    def getXWindow(self):
        return xutils.get_xwindow(int(self.winId()))

    def hasWindowFlags(self, windowFlags):
        return int(self.windowFlags() & windowFlags) != 0

    def addWindowFlags(self, windowFlags):
        if not self.hasWindowFlags(windowFlags):
            flags = self.windowFlags()
            flags |= windowFlags
            self.setWindowFlags(flags)

    def removeWindowFlags(self, windowFlags):
        if self.hasWindowFlags(windowFlags):
            flags = self.windowFlags()
            flags = flags &~ windowFlags
            self.setWindowFlags(flags)

    def getCursorType(self, x, y):
        width = self.width()
        height = self.height()
        size = self.dragParams['size']
        margin = self.shadowWidth
        isResizableX = self.isResizableX()
        isResizableY = self.isResizableY()
        cursorType = Window.Move
        if x >= margin and x <= width - margin and y >= margin and y <= height - margin:
            if y <= size + margin and isResizableY:
                cursorType |= Window.ResizeTop
            elif y >= height - margin - size and isResizableY:
                cursorType |= Window.ResizeBottom
            if x <= size + margin and isResizableX:
                cursorType |= Window.ResizeLeft
            elif x >= width - margin - size and isResizableX:
                cursorType |= Window.ResizeRight
        return cursorType

    # Slots

    # 获取父窗口
    @pyqtSlot(result = QObject)
    def opener(self):
        return self.parent

    # 任务栏闪烁
    @pyqtSlot()
    @pyqtSlot(int)
    def alert(self, msec = 0):
        QApplication.alert(self, msec)

    # 执行简单的JS
    @pyqtSlot(str, result = QObject)
    def eval(self, javaScript):
        obj = QObject(self)
        obj.setObjectName('evalResult')
        obj.setProperty('result', self.webView.eval(javaScript))
        return obj

    # 截图
    @pyqtSlot(result = str)
    @pyqtSlot(bool, result = str)
    @pyqtSlot(bool, str, result = bool)
    def capture(self, fullScreen = False, filename = ''):
        if fullScreen:
            image = QApplication.primaryScreen().grabWindow(0)
        else:
            image = QImage(self.webView.mainFrame.contentsSize(), QImage.Format_ARGB32)
            painter = QPainter(image)
            self.webView.mainFrame.render(painter)
            painter.end()
        if filename:
            return image.save(filename)
        else:
            data = QByteArray()
            buffer = QBuffer(data)
            buffer.open(QBuffer.WriteOnly)
            image.save(buffer, 'PNG')
            return bytes(data.toBase64()).decode()

    # 打开开发者工具
    @pyqtSlot()
    def showInspector(self):
        self.webView.page().showInspector()

    # 关闭开发者工具
    @pyqtSlot()
    def hideInspector(self):
        self.webView.page().hideInspector()

    # 搜索文本
    @pyqtSlot(str, result = bool)
    def findText(self, text):
        return self.webView.page().findText(text)

    # 设置窗口图标
    @pyqtSlot(str)
    def setIcon(self, icon):
        if isinstance(icon, str):
            icon = QIcon(self.api.normUrl(icon))
        self.setWindowIcon(icon)

    # 设置内容是否已被修改(标题中需要有[*]标志)
    @pyqtSlot(bool)
    def setModified(self, modified):
        self.setWindowModified(modified)

    # 获取内容是否已被修改
    @pyqtSlot(result = bool)
    def isModified(self):
        return self.isWindowModified()

    # 设置是否模态
    @pyqtSlot(bool)
    def setModal(self, modal):
        super(Window, self).setModal(modal)

    # 获取是否模态
    @pyqtSlot(result = bool)
    def isModal(self):
        return super(Window, self).isModal()

    # 设置是否在任务栏中显示
    @pyqtSlot(bool)
    def setShowInTaskbar(self, showInTaskbar):
        if showInTaskbar:
            self.setWindowFlags(self.windowFlags() & ~ Qt.Tool)
        else:
            self.setWindowFlags(self.windowFlags() | Qt.Tool)

    # 获取是否在任务栏中显示
    @pyqtSlot(result = bool)
    def isShowInTaskbar(self):
        return self.hasWindowFlags(Qt.Tool)

    # 设置窗口是否置顶
    @pyqtSlot(bool)
    def setStaysOnTop(self, staysOnTop):
        if staysOnTop:
            xutils.do_stay_on_top(self.getXWindow())
        else:
            xutils.undo_stay_on_top(self.getXWindow())

    # 获取窗口是否置顶
    @pyqtSlot(result = bool)
    def isStaysOnTop(self):
        return xutils.is_stay_on_top(self.getXWindow())

    # 设置是否显示系统边框
    @pyqtSlot(bool)
    def setFrameless(self, frameless):
        if frameless:
            self.setWindowFlags(Qt.FramelessWindowHint)
        else:
            self.addWindowFlags(Qt.WindowMaximizeButtonHint)
            self.addWindowFlags(Qt.WindowMinMaxButtonsHint)
            self.addWindowFlags(Qt.WindowSystemMenuHint)
            self.removeWindowFlags(Qt.FramelessWindowHint)

    # 获取是否显示系统边框
    @pyqtSlot(result = bool)
    def isFrameless(self):
        return self.hasWindowFlags(Qt.FramelessWindowHint)

    # 设置是否背景透明
    @pyqtSlot(bool)
    def setTransBackground(self, transBackground):
        palette = self.palette()
        if transBackground:
            palette.setBrush(QPalette.Base, Qt.transparent)
        else:
            palette.setBrush(QPalette.Base, Qt.white)
        self.setPalette(palette)

    # 获取是否背景透明
    @pyqtSlot(result = bool)
    def isTransBackground(self):
        palette = self.palette()
        return palette.brush(QPalette.Base) == Qt.transparent

    # 设置是否鼠标事件穿透
    @pyqtSlot(bool)
    def setTransMouseEvent(self, transMouseEvent):
        self.setAttribute(Qt.WA_TransparentForMouseEvents, transMouseEvent)
        self.setWindowFlags(self.windowFlags() | Qt.WindowTitleHint)

    # 获取是否是否鼠标事件穿透
    @pyqtSlot(result = bool)
    def isTransMouseEvent(self):
        return self.testAttribute(Qt.WA_TransparentForMouseEvents)

    # 设置窗口不透明度
    @pyqtSlot(float)
    def setOpacity(self, opacity):
        self.setWindowOpacity(opacity)

    # 获取窗口不透明度
    @pyqtSlot(result = float)
    def getOpacity(self):
        return self.windowOpacity()

    # 设置尺寸是否可调整
    @pyqtSlot(bool)
    def setResizable(self, resizable):
        if resizable:
            self.setMinimumSize(5, 5)
            self.setMaximumSize(0xFFFFFF, 0xFFFFFF)
        else:
            self.setFixedSize(self.width(), self.height())

    # 获取尺寸是否可调整
    @pyqtSlot(result = bool)
    def isResizable(self):
        return self.minimumSize() != self.maximumSize()

    # 设置宽度是否可调整
    @pyqtSlot(bool)
    def setResizableX(self, resizableX):
        if resizableX:
            self.setMinimumWidth(5)
            self.setMaximumWidth(0xFFFFFF)
        else:
            self.setFixedWidth(self.width())

    # 获取宽度是否可调整
    @pyqtSlot(result = bool)
    def isResizableX(self):
        return self.minimumWidth() != self.maximumWidth()

    # 设置高度是否可调整
    @pyqtSlot(bool)
    def setResizableY(self, resizableY):
        if resizableY:
            self.setMinimumHeight(5)
            self.setMaximumHeight(0xFFFFFF)
        else:
            self.setFixedHeight(self.height())

    # 获取高度是否可调整
    @pyqtSlot(result = bool)
    def isResizableY(self):
        return self.minimumHeight() != self.maximumHeight()

    # 设置是否可最小化
    @pyqtSlot(bool)
    def setMinimizable(self, minimizable):
        if minimizable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMinimizeButtonHint)

    # 获取是否可最小化
    @pyqtSlot(result = bool)
    def isMinimizable(self):
        return True

    # 设置是否可最大化
    @pyqtSlot(bool)
    def setMaximizable(self, maximizable):
        if maximizable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMaximizeButtonHint)

    # 获取是否可最大化
    @pyqtSlot(result = bool)
    def isMaximizable(self):
        return self._maximizable

    # 设置是否可关闭
    @pyqtSlot(bool)
    def setClosable(self, closable):
        if closable:
            self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~ Qt.WindowCloseButtonHint)

    # 获取是否可关闭
    @pyqtSlot(result = bool)
    def isClosable(self):
        return self.hasWindowFlags(Qt.WindowCloseButtonHint)

    # 获取是否已最小化
    @pyqtSlot(result = bool)
    def isMinimized(self):
        return super(Window, self).isMinimized()

    # 获取是否已最大化
    @pyqtSlot(result = bool)
    def isMaximized(self):
        return super(Window, self).isMaximized()

    # 获取是否已最大化
    @pyqtSlot(result = bool)
    def isFullScreen(self):
        return super(Window, self).isFullScreen()

    # 最小化
    @pyqtSlot()
    def minimize(self):
        if self.isMinimizable():
            ## NOTE: This is bug of Qt5 that showMinimized() just can work once after restore window.
            ## I change window state before set it as WindowMinimized to fixed this bug!

            ## Do minimized.
            self.setWindowState(Qt.WindowMinimized)
            self.setVisible(True)

    # 还原
    @pyqtSlot()
    def normalize(self):
        self.showNormal()

    # 最大化
    @pyqtSlot()
    def maximize(self):
        if self.isMaximizable():
            xutils.do_maximize(self.getXWindow())

    # 全屏
    @pyqtSlot()
    def showFullScreen(self):
        super(Window, self).showFullScreen()

    # 设置窗口坐标
    @pyqtSlot(int, int)
    def setPos(self, x, y):
        self.move(x, y)

    # 设置窗口尺寸
    @pyqtSlot(int, int)
    def setSize(self, width, height):
        self.resize(width, height)

    # 设置窗口最小尺寸
    @pyqtSlot(int, int)
    def setMinSize(self, width, height):
        self.setMinimumSize(width, height)

    # 设置窗口最大尺寸
    @pyqtSlot(int, int)
    def setMaxSize(self, width, height):
        self.setMaximumSize(width, height)

    # 设置尺寸控制大小
    @pyqtSlot(int)
    def setResizerSize(self, size):
        self.dragParams['size'] = size

    # 获取尺寸控制大小
    @pyqtSlot(result = int)
    def getResizerSize(self):
        return self.dragParams['size']

    # 是否正在拖动
    @pyqtSlot(result = bool)
    def isDraging(self):
        return self.dragParams['draging']

    # 开始拖动
    @pyqtSlot()
    def dragStart(self):
        self.dragParams['draging'] = True

    # 结束拖动
    @pyqtSlot()
    def dragStop(self):
        self.dragParams['type'] = Window.Move
        self.dragParams['draging'] = False

    # 窗口获取焦点
    @pyqtSlot()
    def activate(self):
        self.activateWindow()

    # 窗口是否已获得焦点
    @pyqtSlot(result = bool)
    def isActive(self):
        return self.isActiveWindow()

    # 设置窗口可用状态
    @pyqtSlot(bool)
    def setEnabled(self, enabled):
        super(Window, self).setEnabled(enabled)

    # 窗口是否可用
    @pyqtSlot(result = bool)
    def isEnabled(self):
        return super(Window, self).isEnabled()

    # 设置窗口可见状态
    @pyqtSlot(result = bool)
    def setVisible(self, visible):
        super(Window, self).setVisible(visible)

    # 窗口是否显示
    @pyqtSlot(result = bool)
    def isVisible(self):
        return super(Window, self).isVisible()

    # 关闭窗口
    @pyqtSlot()
    def close(self):
        super(Window, self).close()

    @pyqtSlot()
    def quit(self):
        for win in assets.windows:
            win.close()
        qApp.quit()

    # Events
    def keyPressEvent(self, event):
        if(event.key() == Qt.Key_Escape):
            event.ignore()

    # 被webview调用
    def mousePressEvent(self, event):
        self.dragParams['x'] = event.x()
        self.dragParams['y'] = event.y()
        self.dragParams['globalX'] = event.globalX()
        self.dragParams['globalY'] = event.globalY()
        self.dragParams['width'] = self.width()
        self.dragParams['height'] = self.height()
        if self.dragParams['type'] != Window.Move and self.isFrameless() and not self.isMaximized() and not self.isFullScreen():
            self.dragStart()

    def mouseReleaseEvent(self, event):
        self.dragStop()

    def mouseMoveEvent(self, event):
        if self.isFrameless() and not self.isMaximized() and not self.isFullScreen():
            # 判断鼠标类型
            cursorType = self.dragParams['type']
            if not self.dragParams['draging']:
                cursorType = self.dragParams['type'] = self.getCursorType(event.x(), event.y())

            # 设置鼠标形状
            if cursorType in (Window.ResizeTop, Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeVerCursor)
            elif cursorType in (Window.ResizeLeft, Window.ResizeRight):
                self.webView.setCursor(Qt.SizeHorCursor)
            elif cursorType in (Window.ResizeTop | Window.ResizeRight, Window.ResizeLeft | Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeBDiagCursor)
            elif cursorType in (Window.ResizeTop | Window.ResizeLeft, Window.ResizeRight | Window.ResizeBottom):
                self.webView.setCursor(Qt.SizeFDiagCursor)
            elif self.dragParams['draging']:
                self.webView.setCursor(Qt.ArrowCursor)

        # 判断窗口拖动
        dragType = self.dragParams['type']
        if self.dragParams['draging'] and not self.isMaximized() and not self.isFullScreen():
            x = self.x()
            y = self.y()
            width = self.width()
            height = self.height()
            if dragType == Window.Move:
                x = event.globalX() - self.dragParams['x']
                y = event.globalY() - self.dragParams['y']
            elif self.isFrameless():
                if dragType & Window.ResizeTop == Window.ResizeTop:
                    y = event.globalY() - self.shadowWidth
                    height = self.dragParams['height'] + self.dragParams['globalY'] - event.globalY()
                elif dragType & Window.ResizeBottom == Window.ResizeBottom:
                    height = self.dragParams['height'] - self.dragParams['globalY'] + event.globalY()
                if dragType & Window.ResizeLeft == Window.ResizeLeft:
                    x = event.globalX() - self.shadowWidth
                    width = self.dragParams['width'] + self.dragParams['globalX'] - event.globalX()
                elif dragType & Window.ResizeRight == Window.ResizeRight:
                    width = self.dragParams['width'] - self.dragParams['globalX'] + event.globalX()
            else:
                return

            if width < self.minimumWidth():
                width = self.minimumWidth()
            elif width > self.maximumWidth():
                width = self.maximumWidth()
            if height < self.minimumHeight():
                height = self.minimumHeight()
            elif height > self.maximumHeight():
                height = self.maximumHeight()

            xutils.set_geometry(self.getXWindow(), x, y, width, height)

    def changeEvent(self, event):
        if event.type() == QEvent.ActivationChange:
            if self.isActiveWindow():
                self.onfocus.emit()
            else:
                self.onblur.emit()
        elif event.type() == QEvent.WindowStateChange:
            new_window_state = self.windowState()
            if new_window_state == Qt.WindowMaximized or \
                    new_window_state == Qt.WindowFullScreen:
                self.setShadowWidth(0)
            else:
                self.setShadowWidth(10)
            self.onstatechange.emit()

            self._old_window_state = new_window_state

    def resizeEvent(self, event):
        self.onresize.emit(
                event.oldSize().width(), event.oldSize().height(),
                event.size().width(), event.size().height()
                )

    def moveEvent(self, event):
        pos = event.pos()
        oldPos = event.oldPos()
        self.onmove.emit(pos.x(), pos.y(), oldPos.x(), oldPos.y())

    def enterEvent(self, event):
        self.onmouseenter.emit()

    def leaveEvent(self, event):
        self.onmouseleave.emit()

    def showEvent(self, event):
        self.onshow.emit()

    def hideEvent(self, event):
        self.onhide.emit()

    def closeEvent(self, event):
        self.onclose.emit()
        if self.isClosable():
            self.webView.close()
            assets.windows = [i for i in assets.windows if i != self]
            event.accept()
        else:
            event.ignore()

    @pyqtSlot()
    def showCenter(self):
        screen = qApp.primaryScreen()
        geometry = screen.availableGeometry()
        x = geometry.x() + (geometry.width() - self.width())/2
        y = geometry.y() + (geometry.height() - self.height())/2
        self.move(x, y)
        self.show()