1 #include "qwindowcompositor.h"
6 #include <QtCompositor/waylandinput.h>
8 QWindowCompositor::QWindowCompositor(QOpenGLWindow *window)
9 : WaylandCompositor(window)
12 , m_renderScheduler(this)
14 , m_dragKeyIsPressed(false)
16 enableSubSurfaceExtension();
17 m_window->makeCurrent();
19 initializeGLFunctions();
21 m_textureCache = new QOpenGLTextureCache(m_window->context());
22 m_textureBlitter = new TextureBlitter();
23 m_backgroundImage = QImage(QLatin1String(":/background.jpg"));
24 m_renderScheduler.setSingleShot(true);
25 connect(&m_renderScheduler,SIGNAL(timeout()),this,SLOT(render()));
27 glGenFramebuffers(1,&m_surface_fbo);
29 window->installEventFilter(this);
31 setRetainedSelectionEnabled(true);
33 m_renderScheduler.start(0);
36 void QWindowCompositor::surfaceDestroyed(QObject *object)
38 WaylandSurface *surface = static_cast<WaylandSurface *>(object);
39 m_surfaces.removeOne(surface);
40 if (defaultInputDevice()->keyboardFocus() == surface || !defaultInputDevice()->keyboardFocus()) // typically reset to 0 already in Compositor::surfaceDestroyed()
41 defaultInputDevice()->setKeyboardFocus(m_surfaces.isEmpty() ? 0 : m_surfaces.last());
42 m_renderScheduler.start(0);
45 void QWindowCompositor::surfaceMapped()
47 WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
49 if (!m_surfaces.contains(surface)) {
52 if (!QCoreApplication::arguments().contains(QLatin1String("-stickytopleft"))) {
53 px = 1 + (qrand() % (m_window->width() - surface->size().width() - 2));
54 py = 1 + (qrand() % (m_window->height() - surface->size().height() - 2));
59 surface->setPos(window()->geometry().topLeft());
60 m_surfaces.removeOne(surface);
62 m_surfaces.append(surface);
63 defaultInputDevice()->setKeyboardFocus(surface);
64 m_renderScheduler.start(0);
67 void QWindowCompositor::surfaceDamaged(const QRect &rect)
69 WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
70 surfaceDamaged(surface, rect);
73 void QWindowCompositor::surfaceDamaged(WaylandSurface *surface, const QRect &rect)
77 m_renderScheduler.start(0);
80 void QWindowCompositor::surfaceCreated(WaylandSurface *surface)
82 connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
83 connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
84 connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
85 m_renderScheduler.start(0);
88 QPointF QWindowCompositor::toSurface(WaylandSurface *surface, const QPointF &pos) const
90 return pos - surface->pos();
93 void QWindowCompositor::changeCursor(const QImage &image, int hotspotX, int hotspotY)
95 QCursor cursor(QPixmap::fromImage(image),hotspotX,hotspotY);
96 static bool cursroIsSet = false;
98 QGuiApplication::changeOverrideCursor(cursor);
100 QGuiApplication::setOverrideCursor(cursor);
105 WaylandSurface *QWindowCompositor::surfaceAt(const QPoint &point, QPoint *local)
107 for (int i = m_surfaces.size() - 1; i >= 0; --i) {
108 WaylandSurface *surface = m_surfaces.at(i);
109 QRect geo(surface->pos().toPoint(),surface->size());
110 if (geo.contains(point)) {
112 *local = toSurface(surface, point).toPoint();
119 GLuint QWindowCompositor::composeSurface(WaylandSurface *surface)
123 glBindFramebuffer(GL_FRAMEBUFFER, m_surface_fbo);
125 if (surface->type() == WaylandSurface::Shm) {
126 texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image());
128 texture = surface->texture(QOpenGLContext::currentContext());
130 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
131 GL_TEXTURE_2D, texture, 0);
132 paintChildren(surface,surface);
133 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
136 glBindFramebuffer(GL_FRAMEBUFFER,0);
140 void QWindowCompositor::paintChildren(WaylandSurface *surface, WaylandSurface *window) {
142 if (surface->subSurfaces().size() == 0)
145 QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
146 while (i.hasNext()) {
147 WaylandSurface *subSurface = i.next();
148 QPointF p = subSurface->mapTo(window,QPointF(0,0));
149 if (subSurface->size().isValid()) {
151 if (subSurface->type() == WaylandSurface::Texture) {
152 texture = subSurface->texture(QOpenGLContext::currentContext());
153 } else if (surface->type() == WaylandSurface::Shm ) {
154 texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image());
156 QRect geo(p.toPoint(),subSurface->size());
157 m_textureBlitter->drawTexture(texture,geo,window->size(),0,window->isYInverted(),subSurface->isYInverted());
159 paintChildren(subSurface,window);
164 void QWindowCompositor::render()
166 m_window->makeCurrent();
167 m_backgroundTexture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),m_backgroundImage);
169 m_textureBlitter->bind();
170 //Draw the background Image texture
171 int w = m_window->width();
172 int h = m_window->height();
173 QSize imageSize = m_backgroundImage.size();
174 for (int y = 0; y < h; y += imageSize.height()) {
175 for (int x = 0; x < w; x += imageSize.width()) {
176 m_textureBlitter->drawTexture(m_backgroundTexture,QRect(QPoint(x, y),imageSize),window()->size(), 0,true,true);
180 foreach (WaylandSurface *surface, m_surfaces) {
181 GLuint texture = composeSurface(surface);
182 QRect geo(surface->pos().toPoint(),surface->size());
183 m_textureBlitter->drawTexture(texture,geo,m_window->size(),0,false,surface->isYInverted());
186 m_textureBlitter->release();
190 m_window->swapBuffers();
193 bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event)
198 WaylandInputDevice *input = defaultInputDevice();
200 switch (event->type()) {
202 m_renderScheduler.start(0);
204 case QEvent::MouseButtonPress: {
206 QMouseEvent *me = static_cast<QMouseEvent *>(event);
207 WaylandSurface *targetSurface = surfaceAt(me->pos(), &local);
209 if (m_dragKeyIsPressed) {
210 m_draggingWindow = targetSurface;
213 if (input->keyboardFocus() != targetSurface) {
214 input->setKeyboardFocus(targetSurface);
215 m_surfaces.removeOne(targetSurface);
216 m_surfaces.append(targetSurface);
217 m_renderScheduler.start(0);
219 input->sendMousePressEvent(me->button(),local,me->pos());
224 case QEvent::MouseButtonRelease: {
225 WaylandSurface *targetSurface = input->mouseFocus();
226 if (m_draggingWindow) {
227 m_draggingWindow = 0;
228 m_drag_diff = QPoint();
229 } else if (targetSurface) {
230 QMouseEvent *me = static_cast<QMouseEvent *>(event);
231 input->sendMouseReleaseEvent(me->button(),toSurface(targetSurface, me->pos()).toPoint(),me->pos());
235 case QEvent::MouseMove: {
236 QMouseEvent *me = static_cast<QMouseEvent *>(event);
237 if (m_draggingWindow) {
238 m_draggingWindow->setPos(me->posF() - m_drag_diff);
239 m_renderScheduler.start(0);
242 WaylandSurface *targetSurface = surfaceAt(me->pos(), &local);
243 input->sendMouseMoveEvent(targetSurface, local,me->pos());
247 case QEvent::KeyPress: {
248 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
249 if (ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Super_L) {
250 m_dragKeyIsPressed = true;
252 WaylandSurface *targetSurface = input->keyboardFocus();
254 input->sendKeyPressEvent(ke->nativeScanCode());
257 case QEvent::KeyRelease: {
258 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
259 if (ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Super_L) {
260 m_dragKeyIsPressed = false;
262 WaylandSurface *targetSurface = input->keyboardFocus();
264 input->sendKeyReleaseEvent(ke->nativeScanCode());
267 case QEvent::TouchBegin:
268 case QEvent::TouchUpdate:
269 case QEvent::TouchEnd:
271 WaylandSurface *targetSurface = 0;
272 QTouchEvent *te = static_cast<QTouchEvent *>(event);
273 QList<QTouchEvent::TouchPoint> points = te->touchPoints();
275 if (!points.isEmpty()) {
276 pointPos = points.at(0).pos().toPoint();
277 targetSurface = surfaceAt(pointPos);
279 if (targetSurface && targetSurface != input->mouseFocus())
280 input->setMouseFocus(targetSurface, pointPos, pointPos);
281 if (input->mouseFocus())
282 input->sendFullTouchEvent(te);