from PyQt5.QtCore import pyqtProperty, QObject, Qt
from PyQt5.QtGui import QColor
from PyQt5.QtQuick import QQuickWindow, QQuickItem

from OpenGL import GL
from OpenGL.GL.GREMEDY.string_marker import *

from Cura.Math.Vector import Vector
from Cura.Qt.QtMouseDevice import QtMouseDevice


##  QQuickWindow subclass that provides the main window.
class MainWindow(QQuickWindow):
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)

        self._app = None
        self._backgroundColor = QColor(204, 204, 204, 255)

        self.setClearBeforeRendering(False)
        self.beforeRendering.connect(self._render, type=Qt.DirectConnection)

        self._mouseDevice = QtMouseDevice()
        self._keyboardDevice = None

    def getApplication(self):
        return self._app

    def setApplication(self, app):
        if app == self._app:
            return

        if self._app:
            self._app.getController().removeInputDevice("Mouse")
            self._app.getController().getScene().sceneChanged.disconnect(self.update)

        self._app = app
        if self._app:
            self._app.getController().addInputDevice("Mouse", self._mouseDevice)
            self._app.getController().getScene().sceneChanged.connect(self._onSceneChanged)

    application = pyqtProperty(QObject, fget=getApplication, fset=setApplication)

    def getBackgroundColor(self):
        return self._backgroundColor

    def setBackgroundColor(self, color):
        self._backgroundColor = color

    backgroundColor = pyqtProperty(QColor, fget=getBackgroundColor, fset=setBackgroundColor)

    def event(self, event):
        super().event(event)

        if event.isAccepted():
           return True

        e = None
        if self._mouseDevice:
            e = self._mouseDevice.handleEvent(event)

        if not e and self._keyboardDevice:
            e = self._keyboardDevice.handleEvent(event)

        if e:
            self._app.getController().event(e)
            return True
        else:
            return False

    def _render(self):
        if bool(glStringMarkerGREMEDY):
            msg = b"Begin Rendering Background"
            glStringMarkerGREMEDY(len(msg), msg)

        GL.glClearColor(self._backgroundColor.redF(), self._backgroundColor.greenF(), self._backgroundColor.blueF(), self._backgroundColor.alphaF())
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        if self._app:
            self._app.getController().getActiveView().render()

        if bool(glStringMarkerGREMEDY):
            msg = "End Rendering Background"
            glStringMarkerGREMEDY(len(msg), msg)

    def _onSceneChanged(self, object):
        self.update()

@@ -1615,52 +1615,239 @@
 r)%0A%0A
+#
    
- def event(self, event):%0A 
+Warning! Never reimplemented this as a QExposeEvent can cause a deadlock with QSGThreadedRender due to both trying%0A#   to claim the Python GIL.%0A#   def event(self, event):%0A%0A    def mousePressEvent(self, event):%0A
        
+ 
 super().
 even
@@ -1838,25 +1838,35 @@
     super().
-e
+mousePressE
 vent(event)%0A
@@ -1857,33 +1857,32 @@
 essEvent(event)%0A
-%0A
         if event
@@ -1907,27 +1907,23 @@
         
+ 
 return
- True
 %0A%0A      
@@ -1928,324 +1928,734 @@
     
-e = None%0A        if self._mouseDevice:%0A            e = self._mouseDevice.handleEvent(event)%0A%0A        if not e and self._keyboardDevice:%0A            e = self._keyboardDevice.handleEvent(event)%0A%0A        if e:%0A            self._app.getController().event(e)%0A            return True%0A        else:%0A            return False
+self._mouseDevice.handleEvent(event)%0A%0A    def mouseMoveEvent(self, event):%0A        super().mouseMoveEvent(event)%0A        if event.isAccepted():%0A            return%0A%0A        self._mouseDevice.handleEvent(event)%0A%0A    def mouseReleaseEvent(self, event):%0A        super().mouseReleaseEvent(event)%0A        if event.isAccepted():%0A            return%0A%0A        self._mouseDevice.handleEvent(event)%0A%0A    def keyPressEvent(self, event):%0A        super().keyPressEvent(event)%0A        if event.isAccepted():%0A            return%0A%0A        self._keyDevice.handleEvent(event)%0A%0A    def keyReleaseEvent(self, event):%0A        super().keyReleaseEvent(event)%0A        if event.isAccepted():%0A            return%0A%0A        self._keyDevice.handleEvent(event)
 %0A%0A  

Fix Qt event handling to avoid a deadlock on ExposeEvent