12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233 |
- diff --git a/src/client/configure.json b/src/client/configure.json
- index 2f424580..29222357 100644
- --- a/src/client/configure.json
- +++ b/src/client/configure.json
- @@ -149,8 +149,7 @@
- "#endif"
- ]
- },
- - "libs": "-ldrm",
- - "use": "egl"
- + "use": "drm egl"
- },
- "vulkan-server-buffer": {
- "label": "Vulkan Buffer Sharing",
- @@ -168,7 +167,8 @@
- "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
- "return 0;"
- ]
- - }
- + },
- + "use": "wayland-client"
- },
- "egl_1_5-wayland": {
- "label": "EGL 1.5 with Wayland Platform",
- @@ -183,7 +183,7 @@
- "eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, (struct wl_display *)(nullptr), nullptr);"
- ]
- },
- - "use": "egl"
- + "use": "egl wayland-client"
- }
- },
-
- diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
- index 966096a8..36609c08 100644
- --- a/src/client/global/qwaylandclientextension.cpp
- +++ b/src/client/global/qwaylandclientextension.cpp
- @@ -74,7 +74,10 @@ void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_regis
- void QWaylandClientExtension::addRegistryListener()
- {
- Q_D(QWaylandClientExtension);
- - d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
- + if (!d->registered) {
- + d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
- + d->registered = true;
- + }
- }
-
- QWaylandClientExtension::QWaylandClientExtension(const int ver)
- @@ -88,6 +91,13 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver)
- QMetaObject::invokeMethod(this, "addRegistryListener", Qt::QueuedConnection);
- }
-
- +QWaylandClientExtension::~QWaylandClientExtension()
- +{
- + Q_D(QWaylandClientExtension);
- + if (d->registered && !QCoreApplication::closingDown())
- + d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
- +}
- +
- QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const
- {
- Q_D(const QWaylandClientExtension);
- diff --git a/src/client/global/qwaylandclientextension.h b/src/client/global/qwaylandclientextension.h
- index 98272e57..5bd28398 100644
- --- a/src/client/global/qwaylandclientextension.h
- +++ b/src/client/global/qwaylandclientextension.h
- @@ -63,6 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtension : public QObject
- Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
- public:
- QWaylandClientExtension(const int version);
- + ~QWaylandClientExtension();
-
- QtWaylandClient::QWaylandIntegration *integration() const;
- int version() const;
- diff --git a/src/client/global/qwaylandclientextension_p.h b/src/client/global/qwaylandclientextension_p.h
- index 69cc46a0..9091efbe 100644
- --- a/src/client/global/qwaylandclientextension_p.h
- +++ b/src/client/global/qwaylandclientextension_p.h
- @@ -68,6 +68,7 @@ public:
- QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr;
- int version = -1;
- bool active = false;
- + bool registered = false;
- };
-
- class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate
- diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp
- index b628930d..d15a7f9f 100644
- --- a/src/client/qwaylandabstractdecoration.cpp
- +++ b/src/client/qwaylandabstractdecoration.cpp
- @@ -122,7 +122,7 @@ const QImage &QWaylandAbstractDecoration::contentImage()
- if (d->m_isDirty) {
- // Update the decoration backingstore
-
- - const int bufferScale = waylandWindow()->scale();
- + const qreal bufferScale = waylandWindow()->scale();
- const QSize imageSize = waylandWindow()->surfaceSize() * bufferScale;
- d->m_decorationContentImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
- // Only scale by buffer scale, not QT_SCALE_FACTOR etc.
- diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp
- index 81f48e05..14561c77 100644
- --- a/src/client/qwaylandclipboard.cpp
- +++ b/src/client/qwaylandclipboard.cpp
- @@ -54,10 +54,15 @@ namespace QtWaylandClient {
- QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
- : mDisplay(display)
- {
- + m_clientClipboard[QClipboard::Clipboard] = nullptr;
- + m_clientClipboard[QClipboard::Selection] = nullptr;
- }
-
- QWaylandClipboard::~QWaylandClipboard()
- {
- + if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
- + delete m_clientClipboard[QClipboard::Clipboard];
- + delete m_clientClipboard[QClipboard::Selection];
- }
-
- QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
- @@ -69,8 +74,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
- switch (mode) {
- case QClipboard::Clipboard:
- if (auto *dataDevice = seat->dataDevice()) {
- - if (auto *source = dataDevice->selectionSource())
- - return source->mimeData();
- + if (dataDevice->selectionSource())
- + return m_clientClipboard[QClipboard::Clipboard];
- if (auto *offer = dataDevice->selectionOffer())
- return offer->mimeData();
- }
- @@ -78,8 +83,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
- case QClipboard::Selection:
- #if QT_CONFIG(wayland_client_primary_selection)
- if (auto *selectionDevice = seat->primarySelectionDevice()) {
- - if (auto *source = selectionDevice->selectionSource())
- - return source->mimeData();
- + if (selectionDevice->selectionSource())
- + return m_clientClipboard[QClipboard::Selection];
- if (auto *offer = selectionDevice->selectionOffer())
- return offer->mimeData();
- }
- @@ -104,17 +109,27 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
- if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
- data->setData(utf8, data->data(plain));
-
- + if (m_clientClipboard[mode]) {
- + if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
- + delete m_clientClipboard[mode];
- + m_clientClipboard[mode] = nullptr;
- + }
- +
- + m_clientClipboard[mode] = data;
- +
- switch (mode) {
- case QClipboard::Clipboard:
- if (auto *dataDevice = seat->dataDevice()) {
- - dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
- + dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
- + m_clientClipboard[QClipboard::Clipboard]) : nullptr);
- emitChanged(mode);
- }
- break;
- case QClipboard::Selection:
- #if QT_CONFIG(wayland_client_primary_selection)
- if (auto *selectionDevice = seat->primarySelectionDevice()) {
- - selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr);
- + selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
- + m_clientClipboard[QClipboard::Selection]) : nullptr);
- emitChanged(mode);
- }
- #endif
- diff --git a/src/client/qwaylandclipboard_p.h b/src/client/qwaylandclipboard_p.h
- index ce14e124..bb52683d 100644
- --- a/src/client/qwaylandclipboard_p.h
- +++ b/src/client/qwaylandclipboard_p.h
- @@ -80,6 +80,7 @@ public:
- private:
- QWaylandDisplay *mDisplay = nullptr;
- QMimeData m_emptyData;
- + QMimeData *m_clientClipboard[2];
- };
-
- }
- diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp
- index e4eca9d4..ba76ba2d 100644
- --- a/src/client/qwaylandcursor.cpp
- +++ b/src/client/qwaylandcursor.cpp
- @@ -44,6 +44,7 @@
- #include "qwaylandshmbackingstore_p.h"
-
- #include <QtGui/QImageReader>
- +#include <QBitmap>
- #include <QDebug>
-
- #include <wayland-cursor.h>
- @@ -250,7 +251,27 @@ QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
- QSharedPointer<QWaylandBuffer> QWaylandCursor::cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor)
- {
- Q_ASSERT(cursor->shape() == Qt::BitmapCursor);
- - const QImage &img = cursor->pixmap().toImage();
- +
- + const QBitmap mask = cursor->mask(Qt::ReturnByValue);
- + QImage img;
- + if (cursor->pixmap().isNull())
- + img = cursor->bitmap(Qt::ReturnByValue).toImage();
- + else
- + img = cursor->pixmap().toImage();
- +
- + // convert to supported format if necessary
- + if (!display->shm()->formatSupported(img.format())) {
- + if (mask.isNull()) {
- + img.convertTo(QImage::Format_RGB32);
- + } else {
- + // preserve mask
- + img.convertTo(QImage::Format_ARGB32);
- + QPixmap pixmap = QPixmap::fromImage(img);
- + pixmap.setMask(mask);
- + img = pixmap.toImage();
- + }
- + }
- +
- QSharedPointer<QWaylandShmBuffer> buffer(new QWaylandShmBuffer(display, img.size(), img.format()));
- memcpy(buffer->image()->bits(), img.bits(), size_t(img.sizeInBytes()));
- return buffer;
- diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
- index 1e2db786..07b18ab0 100644
- --- a/src/client/qwaylanddatadevice.cpp
- +++ b/src/client/qwaylanddatadevice.cpp
- @@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl
-
- QWaylandDataDevice::~QWaylandDataDevice()
- {
- + if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
- + release();
- }
-
- QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
- @@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
- return m_dragOffer.data();
- }
-
- -bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
- +bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon)
- {
- auto *seat = m_display->currentInputDevice();
- auto *origin = seat->pointerFocus();
- @@ -122,8 +124,38 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
- return false;
- }
-
- + // dragging data without mimetypes is a legal operation in Qt terms
- + // but Wayland uses a mimetype to determine if a drag is accepted or not
- + // In this rare case, insert a placeholder
- + if (mimeData->formats().isEmpty())
- + mimeData->setData(QString::fromLatin1("application/x-qt-avoid-empty-placeholder"), QByteArray("1"));
- +
- m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
- +
- + if (wl_data_device_get_version(object()) >= 3)
- + m_dragSource->set_actions(dropActionsToWl(supportedActions));
- +
- connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
- + connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
- + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
- + if (!drag->currentDrag()) {
- + return;
- + }
- + // in old versions drop action is not set, so we guess
- + if (wl_data_source_get_version(m_dragSource->object()) < 3) {
- + drag->setResponse(accepted);
- + } else {
- + QPlatformDropQtResponse response(accepted, action);
- + drag->setResponse(response);
- + }
- + });
- + connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
- + QPlatformDropQtResponse response(accepted, action);
- + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
- + });
- + connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
- + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
- + });
-
- start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
- return true;
- @@ -152,7 +184,7 @@ void QWaylandDataDevice::data_device_drop()
- supportedActions = drag->supportedActions();
- } else if (m_dragOffer) {
- dragData = m_dragOffer->mimeData();
- - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
- + supportedActions = m_dragOffer->supportedActions();
- } else {
- return;
- }
- @@ -162,7 +194,11 @@ void QWaylandDataDevice::data_device_drop()
- QGuiApplication::keyboardModifiers());
-
- if (drag) {
- - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
- + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
- + drag->setDropResponse(response);
- + drag->finishDrag();
- + } else if (m_dragOffer) {
- + m_dragOffer->finish();
- }
- }
-
- @@ -186,7 +222,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
- supportedActions = drag->supportedActions();
- } else if (m_dragOffer) {
- dragData = m_dragOffer->mimeData();
- - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
- + supportedActions = m_dragOffer->supportedActions();
- }
-
- const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
- @@ -197,11 +233,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
- }
-
- - if (response.isAccepted()) {
- - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
- - } else {
- - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
- - }
- + sendResponse(supportedActions, response);
- }
-
- void QWaylandDataDevice::data_device_leave()
- @@ -235,10 +267,10 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
- supportedActions = drag->supportedActions();
- } else {
- dragData = m_dragOffer->mimeData();
- - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
- + supportedActions = m_dragOffer->supportedActions();
- }
-
- - QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
- + const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
- QGuiApplication::mouseButtons(),
- QGuiApplication::keyboardModifiers());
-
- @@ -246,11 +278,7 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
- }
-
- - if (response.isAccepted()) {
- - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
- - } else {
- - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
- - }
- + sendResponse(supportedActions, response);
- }
- #endif // QT_CONFIG(draganddrop)
-
- @@ -277,14 +305,10 @@ void QWaylandDataDevice::selectionSourceCancelled()
- #if QT_CONFIG(draganddrop)
- void QWaylandDataDevice::dragSourceCancelled()
- {
- + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
- m_dragSource.reset();
- }
-
- -void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType)
- -{
- - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType);
- -}
- -
- QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
- {
- QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y));
- @@ -297,6 +321,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con
- }
- return pnt;
- }
- +
- +void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response)
- +{
- + if (response.isAccepted()) {
- + if (wl_data_device_get_version(object()) >= 3)
- + m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction()));
- +
- + m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat());
- + } else {
- + m_dragOffer->accept(m_enterSerial, QString());
- + }
- +}
- +
- +int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions)
- +{
- +
- + int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- + if (actions & Qt::CopyAction)
- + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- + if (actions & (Qt::MoveAction | Qt::TargetMoveAction))
- + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- +
- + // wayland does not support LinkAction at the time of writing
- + return wlActions;
- +}
- +
- +
- #endif // QT_CONFIG(draganddrop)
-
- }
- diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h
- index 16c3ad28..801dcc2c 100644
- --- a/src/client/qwaylanddatadevice_p.h
- +++ b/src/client/qwaylanddatadevice_p.h
- @@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice);
- QT_BEGIN_NAMESPACE
-
- class QMimeData;
- +class QPlatformDragQtResponse;
- class QWindow;
-
- namespace QtWaylandClient {
- @@ -89,7 +90,7 @@ public:
-
- #if QT_CONFIG(draganddrop)
- QWaylandDataOffer *dragOffer() const;
- - bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
- + bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon);
- void cancelDrag();
- #endif
-
- @@ -109,13 +110,16 @@ private Q_SLOTS:
-
- #if QT_CONFIG(draganddrop)
- void dragSourceCancelled();
- - void dragSourceTargetChanged(const QString &mimeType);
- #endif
-
- private:
- #if QT_CONFIG(draganddrop)
- QPoint calculateDragPosition(int x, int y, QWindow *wnd) const;
- #endif
- + void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response);
- +
- + static int dropActionsToWl(Qt::DropActions dropActions);
- +
-
- QWaylandDisplay *m_display = nullptr;
- QWaylandInputDevice *m_inputDevice = nullptr;
- diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp
- index 35d67307..6dc4f77f 100644
- --- a/src/client/qwaylanddatadevicemanager.cpp
- +++ b/src/client/qwaylanddatadevicemanager.cpp
- @@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE
-
- namespace QtWaylandClient {
-
- -QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
- - : wl_data_device_manager(display->wl_registry(), id, 1)
- +QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id)
- + : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3))
- , m_display(display)
- {
- // Create transfer devices for all input devices.
- diff --git a/src/client/qwaylanddatadevicemanager_p.h b/src/client/qwaylanddatadevicemanager_p.h
- index bd05c0fb..510d9be4 100644
- --- a/src/client/qwaylanddatadevicemanager_p.h
- +++ b/src/client/qwaylanddatadevicemanager_p.h
- @@ -68,7 +68,7 @@ class QWaylandInputDevice;
- class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager
- {
- public:
- - QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id);
- + QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id);
- ~QWaylandDataDeviceManager() override;
-
- QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice);
- diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
- index 2297e8a1..fe0ea8c9 100644
- --- a/src/client/qwaylanddataoffer.cpp
- +++ b/src/client/qwaylanddataoffer.cpp
- @@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData()
- return m_mimeData.data();
- }
-
- +Qt::DropActions QWaylandDataOffer::supportedActions() const
- +{
- + if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) {
- + return Qt::MoveAction | Qt::CopyAction;
- + }
- +
- + return m_supportedActions;
- +}
- +
- void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
- {
- receive(mimeType, fd);
- @@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
- m_mimeData->appendFormat(mime_type);
- }
-
- +void QWaylandDataOffer::data_offer_action(uint32_t dnd_action)
- +{
- + Q_UNUSED(dnd_action);
- + // This is the compositor telling the drag target what action it should perform
- + // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
- +}
- +
- +void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions)
- +{
- + m_supportedActions = Qt::DropActions();
- + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
- + m_supportedActions |= Qt::MoveAction;
- + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
- + m_supportedActions |= Qt::CopyAction;
- +}
- +
- QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
- : m_dataOffer(dataOffer)
- {
- @@ -163,17 +188,18 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
-
- int QWaylandMimeData::readData(int fd, QByteArray &data) const
- {
- - fd_set readset;
- - FD_ZERO(&readset);
- - FD_SET(fd, &readset);
- - struct timeval timeout;
- + struct pollfd readset;
- + readset.fd = fd;
- + readset.events = POLLIN;
- + struct timespec timeout;
- timeout.tv_sec = 1;
- - timeout.tv_usec = 0;
- + timeout.tv_nsec = 0;
- +
-
- Q_FOREVER {
- - int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
- + int ready = qt_safe_poll(&readset, 1, &timeout);
- if (ready < 0) {
- - qWarning() << "QWaylandDataOffer: select() failed";
- + qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
- return -1;
- } else if (ready == 0) {
- qWarning("QWaylandDataOffer: timeout reading from pipe");
- diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h
- index 9cf1483c..6f667398 100644
- --- a/src/client/qwaylanddataoffer_p.h
- +++ b/src/client/qwaylanddataoffer_p.h
- @@ -82,6 +82,7 @@ public:
- explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
- ~QWaylandDataOffer() override;
- QMimeData *mimeData() override;
- + Qt::DropActions supportedActions() const;
-
- QString firstFormat() const;
-
- @@ -89,10 +90,13 @@ public:
-
- protected:
- void data_offer_offer(const QString &mime_type) override;
- + void data_offer_source_actions(uint32_t source_actions) override;
- + void data_offer_action(uint32_t dnd_action) override;
-
- private:
- QWaylandDisplay *m_display = nullptr;
- QScopedPointer<QWaylandMimeData> m_mimeData;
- + Qt::DropActions m_supportedActions;
- };
-
-
- diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
- index c2bc9dc4..321170a6 100644
- --- a/src/client/qwaylanddatasource.cpp
- +++ b/src/client/qwaylanddatasource.cpp
- @@ -72,11 +72,6 @@ QWaylandDataSource::~QWaylandDataSource()
- destroy();
- }
-
- -QMimeData * QWaylandDataSource::mimeData() const
- -{
- - return m_mime_data;
- -}
- -
- void QWaylandDataSource::data_source_cancelled()
- {
- Q_EMIT cancelled();
- @@ -110,7 +105,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
-
- void QWaylandDataSource::data_source_target(const QString &mime_type)
- {
- - Q_EMIT targetChanged(mime_type);
- + m_accepted = !mime_type.isEmpty();
- + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
- +}
- +
- +void QWaylandDataSource::data_source_action(uint32_t action)
- +{
- + Qt::DropAction qtAction = Qt::IgnoreAction;
- +
- + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
- + qtAction = Qt::MoveAction;
- + else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
- + qtAction = Qt::CopyAction;
- +
- + m_dropAction = qtAction;
- + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
- +}
- +
- +void QWaylandDataSource::data_source_dnd_finished()
- +{
- + Q_EMIT finished();
- +}
- +
- +void QWaylandDataSource::data_source_dnd_drop_performed()
- +{
- +
- + Q_EMIT dndDropped(m_accepted, m_dropAction);
- }
-
- }
- diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h
- index 3003da1b..089c5485 100644
- --- a/src/client/qwaylanddatasource_p.h
- +++ b/src/client/qwaylanddatasource_p.h
- @@ -74,19 +74,25 @@ public:
- QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData);
- ~QWaylandDataSource() override;
-
- - QMimeData *mimeData() const;
- -
- Q_SIGNALS:
- - void targetChanged(const QString &mime_type);
- void cancelled();
- + void finished();
- +
- + void dndResponseUpdated(bool accepted, Qt::DropAction action);
- + void dndDropped(bool accepted, Qt::DropAction action);
-
- protected:
- void data_source_cancelled() override;
- void data_source_send(const QString &mime_type, int32_t fd) override;
- void data_source_target(const QString &mime_type) override;
- + void data_source_dnd_drop_performed() override;
- + void data_source_dnd_finished() override;
- + void data_source_action(uint32_t action) override;
-
- private:
- QMimeData *m_mime_data = nullptr;
- + bool m_accepted = false;
- + Qt::DropAction m_dropAction = Qt::IgnoreAction;
- };
-
- }
- diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
- index 8a6d5db1..737b539d 100644
- --- a/src/client/qwaylanddisplay.cpp
- +++ b/src/client/qwaylanddisplay.cpp
- @@ -87,10 +87,203 @@
-
- #include <errno.h>
-
- +#include <tuple> // for std::tie
- +
- +static void checkWaylandError(struct wl_display *display)
- +{
- + int ecode = wl_display_get_error(display);
- + if ((ecode == EPIPE || ecode == ECONNRESET)) {
- + // special case this to provide a nicer error
- + qWarning("The Wayland connection broke. Did the Wayland compositor die?");
- + } else {
- + qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
- + }
- + _exit(1);
- +}
- +
- QT_BEGIN_NAMESPACE
-
- namespace QtWaylandClient {
-
- +class EventThread : public QThread
- +{
- + Q_OBJECT
- +public:
- + enum OperatingMode {
- + EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread.
- + SelfDispatch, // Dispatch the events inside this thread.
- + };
- +
- + EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue,
- + OperatingMode mode)
- + : m_fd(wl_display_get_fd(wl))
- + , m_pipefd{ -1, -1 }
- + , m_wldisplay(wl)
- + , m_wlevqueue(ev_queue)
- + , m_mode(mode)
- + , m_reading(true)
- + , m_quitting(false)
- + {
- + setObjectName(QStringLiteral("WaylandEventThread"));
- + }
- +
- + void readAndDispatchEvents()
- + {
- + /*
- + * Dispatch pending events and flush the requests at least once. If the event thread
- + * is not reading, try to call _prepare_read() to allow the event thread to poll().
- + * If that fails, re-try dispatch & flush again until _prepare_read() is successful.
- + *
- + * This allow any call to readAndDispatchEvents() to start event thread's polling,
- + * not only the one issued from event thread's waitForReading(), which means functions
- + * called from dispatch_pending() can safely spin an event loop.
- + */
- + for (;;) {
- + if (dispatchQueuePending() < 0) {
- + checkWaylandError(m_wldisplay);
- + return;
- + }
- +
- + wl_display_flush(m_wldisplay);
- +
- + // We have to check if event thread is reading every time we dispatch
- + // something, as that may recursively call this function.
- + if (m_reading.loadAcquire())
- + break;
- +
- + if (prepareReadQueue() == 0) {
- + QMutexLocker l(&m_mutex);
- + m_reading.storeRelease(true);
- + m_cond.wakeOne();
- + break;
- + }
- + }
- + }
- +
- + void stop()
- + {
- + // We have to both write to the pipe and set the flag, as the thread may be
- + // either in the poll() or waiting for _prepare_read().
- + if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1)
- + qWarning("Failed to write to the pipe: %s.", strerror(errno));
- +
- + {
- + QMutexLocker l(&m_mutex);
- + m_quitting = true;
- + m_cond.wakeOne();
- + }
- +
- + wait();
- + }
- +
- +Q_SIGNALS:
- + void needReadAndDispatch();
- +
- +protected:
- + void run() override
- + {
- + // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets
- + // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore.
- + struct Pipe
- + {
- + Pipe(int *fds)
- + : fds(fds)
- + {
- + if (qt_safe_pipe(fds) != 0)
- + qWarning("Pipe creation failed. Quitting may hang.");
- + }
- + ~Pipe()
- + {
- + if (fds[0] != -1) {
- + close(fds[0]);
- + close(fds[1]);
- + }
- + }
- +
- + int *fds;
- + } pipe(m_pipefd);
- +
- + // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the
- + // outbound ones. Wait until it's done before proceeding, unless we're told to quit.
- + while (waitForReading()) {
- + pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } };
- + poll(fds, 2, -1);
- +
- + if (fds[1].revents & POLLIN) {
- + // we don't really care to read the byte that was written here since we're closing down
- + wl_display_cancel_read(m_wldisplay);
- + break;
- + }
- +
- + if (fds[0].revents & POLLIN)
- + wl_display_read_events(m_wldisplay);
- + // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop
- + // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which
- + // case we don't care anymore about them.
- + else
- + wl_display_cancel_read(m_wldisplay);
- + }
- + }
- +
- +private:
- + bool waitForReading()
- + {
- + Q_ASSERT(QThread::currentThread() == this);
- +
- + m_reading.storeRelease(false);
- +
- + if (m_mode == SelfDispatch) {
- + readAndDispatchEvents();
- + } else {
- + Q_EMIT needReadAndDispatch();
- +
- + QMutexLocker lock(&m_mutex);
- + // m_reading might be set from our emit or some other invocation of
- + // readAndDispatchEvents().
- + while (!m_reading.loadRelaxed() && !m_quitting)
- + m_cond.wait(&m_mutex);
- + }
- +
- + return !m_quitting;
- + }
- +
- + int dispatchQueuePending()
- + {
- + if (m_wlevqueue)
- + return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue);
- + else
- + return wl_display_dispatch_pending(m_wldisplay);
- + }
- +
- + int prepareReadQueue()
- + {
- + if (m_wlevqueue)
- + return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue);
- + else
- + return wl_display_prepare_read(m_wldisplay);
- + }
- +
- + int m_fd;
- + int m_pipefd[2];
- + wl_display *m_wldisplay;
- + wl_event_queue *m_wlevqueue;
- + OperatingMode m_mode;
- +
- + /* Concurrency note when operating in EmitToDispatch mode:
- + * m_reading is set to false inside event thread's waitForReading(), and is
- + * set to true inside main thread's readAndDispatchEvents().
- + * The lock is not taken when setting m_reading to false, as the main thread
- + * is not actively waiting for it to turn false. However, the lock is taken
- + * inside readAndDispatchEvents() before setting m_reading to true,
- + * as the event thread is actively waiting for it under the wait condition.
- + */
- +
- + QAtomicInteger<bool> m_reading;
- + bool m_quitting;
- + QMutex m_mutex;
- + QWaitCondition m_cond;
- +};
- +
- Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging
-
- struct wl_surface *QWaylandDisplay::createSurface(void *handle)
- @@ -160,17 +353,16 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
- if (!mXkbContext)
- qCWarning(lcQpaWayland, "failed to create xkb context");
- #endif
- -
- - forceRoundTrip();
- -
- - if (!mWaitingScreens.isEmpty()) {
- - // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
- - forceRoundTrip();
- - }
- }
-
- QWaylandDisplay::~QWaylandDisplay(void)
- {
- + if (m_eventThread)
- + m_eventThread->stop();
- +
- + if (m_frameEventQueueThread)
- + m_frameEventQueueThread->stop();
- +
- if (mSyncCallback)
- wl_callback_destroy(mSyncCallback);
-
- @@ -187,10 +379,26 @@ QWaylandDisplay::~QWaylandDisplay(void)
- #if QT_CONFIG(cursor)
- qDeleteAll(mCursorThemes);
- #endif
- +
- + if (m_frameEventQueue)
- + wl_event_queue_destroy(m_frameEventQueue);
- +
- if (mDisplay)
- wl_display_disconnect(mDisplay);
- }
-
- +// Steps which is called just after constructor. This separates registry_global() out of the constructor
- +// so that factory functions in integration can be overridden.
- +void QWaylandDisplay::initialize()
- +{
- + forceRoundTrip();
- +
- + if (!mWaitingScreens.isEmpty()) {
- + // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
- + forceRoundTrip();
- + }
- +}
- +
- void QWaylandDisplay::ensureScreen()
- {
- if (!mScreens.empty() || mPlaceholderScreen)
- @@ -205,98 +413,37 @@ void QWaylandDisplay::ensureScreen()
-
- void QWaylandDisplay::checkError() const
- {
- - int ecode = wl_display_get_error(mDisplay);
- - if ((ecode == EPIPE || ecode == ECONNRESET)) {
- - // special case this to provide a nicer error
- - qWarning("The Wayland connection broke. Did the Wayland compositor die?");
- - } else {
- - qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
- - }
- - _exit(1);
- + checkWaylandError(mDisplay);
- }
-
- +// Called in main thread, either from queued signal or directly.
- void QWaylandDisplay::flushRequests()
- {
- - if (wl_display_prepare_read(mDisplay) == 0) {
- - wl_display_read_events(mDisplay);
- - }
- -
- - if (wl_display_dispatch_pending(mDisplay) < 0)
- - checkError();
- -
- - {
- - QReadLocker locker(&m_frameQueueLock);
- - for (const FrameQueue &q : mExternalQueues) {
- - QMutexLocker locker(q.mutex);
- - while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
- - wl_display_dispatch_queue_pending(mDisplay, q.queue);
- - wl_display_read_events(mDisplay);
- - wl_display_dispatch_queue_pending(mDisplay, q.queue);
- - }
- - }
- -
- - wl_display_flush(mDisplay);
- -}
- -
- -void QWaylandDisplay::blockingReadEvents()
- -{
- - if (wl_display_dispatch(mDisplay) < 0)
- - checkError();
- -}
- -
- -void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
- -{
- - QWriteLocker locker(&m_frameQueueLock);
- - auto it = std::find_if(mExternalQueues.begin(),
- - mExternalQueues.end(),
- - [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
- - Q_ASSERT(it != mExternalQueues.end());
- - mExternalQueues.erase(it);
- - if (q.queue != nullptr)
- - wl_event_queue_destroy(q.queue);
- - delete q.mutex;
- + m_eventThread->readAndDispatchEvents();
- }
-
- -QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
- +// We have to wait until we have an eventDispatcher before creating the eventThread,
- +// otherwise forceRoundTrip() may block inside _events_read() because eventThread is
- +// polling.
- +void QWaylandDisplay::initEventThread()
- {
- - QWriteLocker locker(&m_frameQueueLock);
- - FrameQueue q{createEventQueue()};
- - mExternalQueues.append(q);
- - return q;
- -}
- + m_eventThread.reset(
- + new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch));
- + connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this,
- + &QWaylandDisplay::flushRequests, Qt::QueuedConnection);
- + m_eventThread->start();
-
- -wl_event_queue *QWaylandDisplay::createEventQueue()
- -{
- - return wl_display_create_queue(mDisplay);
- + // wl_display_disconnect() free this.
- + m_frameEventQueue = wl_display_create_queue(mDisplay);
- + m_frameEventQueueThread.reset(
- + new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch));
- + m_frameEventQueueThread->start();
- }
-
- -void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
- +void QWaylandDisplay::blockingReadEvents()
- {
- - if (!condition())
- - return;
- -
- - QElapsedTimer timer;
- - timer.start();
- - struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
- - while (timeout == -1 || timer.elapsed() < timeout) {
- - while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
- - wl_display_dispatch_queue_pending(mDisplay, queue);
- -
- - wl_display_flush(mDisplay);
- -
- - const int remaining = qMax(timeout - timer.elapsed(), 0ll);
- - const int pollTimeout = timeout == -1 ? -1 : remaining;
- - if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
- - wl_display_read_events(mDisplay);
- - else
- - wl_display_cancel_read(mDisplay);
- -
- - if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0)
- - checkError();
- -
- - if (!condition())
- - break;
- - }
- + if (wl_display_dispatch(mDisplay) < 0)
- + checkWaylandError(mDisplay);
- }
-
- QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
- @@ -347,7 +494,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
- if (interface == QStringLiteral("wl_output")) {
- mWaitingScreens << new QWaylandScreen(this, version, id);
- } else if (interface == QStringLiteral("wl_compositor")) {
- - mCompositorVersion = qMin((int)version, 3);
- + mCompositorVersion = qMin((int)version, 4);
- mCompositor.init(registry, id, mCompositorVersion);
- } else if (interface == QStringLiteral("wl_shm")) {
- mShm.reset(new QWaylandShm(this, version, id));
- @@ -356,7 +503,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
- mInputDevices.append(inputDevice);
- #if QT_CONFIG(wayland_datadevice)
- } else if (interface == QStringLiteral("wl_data_device_manager")) {
- - mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
- + mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
- #endif
- } else if (interface == QStringLiteral("qt_surface_extension")) {
- mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
- @@ -373,6 +520,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
- #if QT_CONFIG(wayland_client_primary_selection)
- } else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
- mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
- + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
- + inputDevice->setPrimarySelectionDevice(mPrimarySelectionManager->createDevice(inputDevice));
- #endif
- } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
- mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
- @@ -431,6 +580,13 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
- inputDevice->setTextInput(nullptr);
- mWaylandIntegration->reconfigureInputContext();
- }
- +#if QT_CONFIG(wayland_client_primary_selection)
- + if (global.interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
- + mPrimarySelectionManager.reset();
- + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
- + inputDevice->setPrimarySelectionDevice(nullptr);
- + }
- +#endif
- mGlobals.removeAt(i);
- break;
- }
- @@ -456,9 +612,10 @@ void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
-
- void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
- {
- - std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
- + auto iter = std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
- return (l.listener == listener && l.data == data);
- });
- + mRegistryListeners.erase(iter, mRegistryListeners.end());
- }
-
- uint32_t QWaylandDisplay::currentTimeMillisec()
- @@ -471,50 +628,9 @@ uint32_t QWaylandDisplay::currentTimeMillisec()
- return 0;
- }
-
- -static void
- -sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
- -{
- - Q_UNUSED(serial)
- - bool *done = static_cast<bool *>(data);
- -
- - *done = true;
- -
- - // If the wl_callback done event is received after the condition check in the while loop in
- - // forceRoundTrip(), but before the call to processEvents, the call to processEvents may block
- - // forever if no more events are posted (eventhough the callback is handled in response to the
- - // aboutToBlock signal). Hence, we wake up the event dispatcher so forceRoundTrip may return.
- - // (QTBUG-64696)
- - if (auto *dispatcher = QThread::currentThread()->eventDispatcher())
- - dispatcher->wakeUp();
- -
- - wl_callback_destroy(callback);
- -}
- -
- -static const struct wl_callback_listener sync_listener = {
- - sync_callback
- -};
- -
- void QWaylandDisplay::forceRoundTrip()
- {
- - // wl_display_roundtrip() works on the main queue only,
- - // but we use a separate one, so basically reimplement it here
- - int ret = 0;
- - bool done = false;
- - wl_callback *callback = wl_display_sync(mDisplay);
- - wl_callback_add_listener(callback, &sync_listener, &done);
- - flushRequests();
- - if (QThread::currentThread()->eventDispatcher()) {
- - while (!done && ret >= 0) {
- - QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::WaitForMoreEvents);
- - ret = wl_display_dispatch_pending(mDisplay);
- - }
- - } else {
- - while (!done && ret >= 0)
- - ret = wl_display_dispatch(mDisplay);
- - }
- -
- - if (ret == -1 && !done)
- - wl_callback_destroy(callback);
- + wl_display_roundtrip(mDisplay);
- }
-
- bool QWaylandDisplay::supportsWindowDecoration() const
- @@ -578,14 +694,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
- if (mLastKeyboardFocus == keyboardFocus)
- return;
-
- - if (mWaylandIntegration->mShellIntegration) {
- - mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
- - } else {
- - if (keyboardFocus)
- - handleWindowActivated(keyboardFocus);
- - if (mLastKeyboardFocus)
- - handleWindowDeactivated(mLastKeyboardFocus);
- - }
- + if (keyboardFocus)
- + handleWindowActivated(keyboardFocus);
- + if (mLastKeyboardFocus)
- + handleWindowDeactivated(mLastKeyboardFocus);
-
- mLastKeyboardFocus = keyboardFocus;
- }
- @@ -604,6 +716,19 @@ void QWaylandDisplay::handleWaylandSync()
- QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
- if (activeWindow != QGuiApplication::focusWindow())
- QWindowSystemInterface::handleWindowActivated(activeWindow);
- +
- + if (!activeWindow) {
- + if (lastInputDevice()) {
- +#if QT_CONFIG(clipboard)
- + if (auto *dataDevice = lastInputDevice()->dataDevice())
- + dataDevice->invalidateSelectionOffer();
- +#endif
- +#if QT_CONFIG(wayland_client_primary_selection)
- + if (auto *device = lastInputDevice()->primarySelectionDevice())
- + device->invalidateSelectionOffer();
- +#endif
- + }
- + }
- }
-
- const wl_callback_listener QWaylandDisplay::syncCallbackListener = {
- @@ -630,6 +755,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
- return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
- }
-
- +bool QWaylandDisplay::isKeyboardAvailable() const
- +{
- + return std::any_of(
- + mInputDevices.constBegin(), mInputDevices.constEnd(),
- + [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
- +}
- +
- #if QT_CONFIG(cursor)
-
- QWaylandCursor *QWaylandDisplay::waylandCursor()
- @@ -656,6 +788,8 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
-
- } // namespace QtWaylandClient
-
- +#include "qwaylanddisplay.moc"
- +
- QT_END_NAMESPACE
-
- #include "moc_qwaylanddisplay_p.cpp"
- diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
- index 1bad8b67..cf91b924 100644
- --- a/src/client/qwaylanddisplay_p.h
- +++ b/src/client/qwaylanddisplay_p.h
- @@ -111,6 +111,7 @@ class QWaylandSurface;
- class QWaylandShellIntegration;
- class QWaylandCursor;
- class QWaylandCursorTheme;
- +class EventThread;
-
- typedef void (*RegistryListener)(void *data,
- struct wl_registry *registry,
- @@ -122,15 +123,11 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland
- Q_OBJECT
-
- public:
- - struct FrameQueue {
- - FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {}
- - wl_event_queue *queue;
- - QMutex *mutex;
- - };
- -
- QWaylandDisplay(QWaylandIntegration *waylandIntegration);
- ~QWaylandDisplay(void) override;
-
- + void initialize();
- +
- #if QT_CONFIG(xkbcommon)
- struct xkb_context *xkbContext() const { return mXkbContext.get(); }
- #endif
- @@ -214,11 +211,11 @@ public:
- void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
- void handleWindowDestroyed(QWaylandWindow *window);
-
- - wl_event_queue *createEventQueue();
- - FrameQueue createFrameQueue();
- - void destroyFrameQueue(const FrameQueue &q);
- - void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
- + wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
- +
- + bool isKeyboardAvailable() const;
-
- + void initEventThread();
- public slots:
- void blockingReadEvents();
- void flushRequests();
- @@ -241,6 +238,9 @@ private:
- };
-
- struct wl_display *mDisplay = nullptr;
- + QScopedPointer<EventThread> m_eventThread;
- + wl_event_queue *m_frameEventQueue = nullptr;
- + QScopedPointer<EventThread> m_frameEventQueueThread;
- QtWayland::wl_compositor mCompositor;
- QScopedPointer<QWaylandShm> mShm;
- QList<QWaylandScreen *> mWaitingScreens;
- @@ -279,11 +279,9 @@ private:
- QWaylandInputDevice *mLastInputDevice = nullptr;
- QPointer<QWaylandWindow> mLastInputWindow;
- QPointer<QWaylandWindow> mLastKeyboardFocus;
- - QVector<QWaylandWindow *> mActiveWindows;
- - QVector<FrameQueue> mExternalQueues;
- + QList<QWaylandWindow *> mActiveWindows;
- struct wl_callback *mSyncCallback = nullptr;
- static const wl_callback_listener syncCallbackListener;
- - QReadWriteLock m_frameQueueLock;
-
- bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
-
- diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
- index 6535aa16..7c53f5fa 100644
- --- a/src/client/qwaylanddnd.cpp
- +++ b/src/client/qwaylanddnd.cpp
- @@ -66,7 +66,7 @@ void QWaylandDrag::startDrag()
- {
- QBasicDrag::startDrag();
- QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
- - if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
- + if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) {
- icon->addAttachOffset(-drag()->hotSpot());
- } else {
- // Cancelling immediately does not work, since the event loop for QDrag::exec is started
- @@ -80,6 +80,9 @@ void QWaylandDrag::cancel()
- QBasicDrag::cancel();
-
- m_display->currentInputDevice()->dataDevice()->cancelDrag();
- +
- + if (drag())
- + drag()->deleteLater();
- }
-
- void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
- @@ -103,33 +106,41 @@ void QWaylandDrag::endDrag()
- m_display->currentInputDevice()->handleEndDrag();
- }
-
- -void QWaylandDrag::updateTarget(const QString &mimeType)
- +void QWaylandDrag::setResponse(bool accepted)
- {
- - setCanDrop(!mimeType.isEmpty());
- -
- - if (canDrop()) {
- - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
- - } else {
- - updateCursor(Qt::IgnoreAction);
- - }
- + // This method is used for old DataDevices where the drag action is not communicated
- + Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers());
- + setResponse(QPlatformDropQtResponse(accepted, action));
- }
-
- -void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response)
- +void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response)
- {
- setCanDrop(response.isAccepted());
-
- if (canDrop()) {
- - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
- + updateCursor(response.acceptedAction());
- } else {
- updateCursor(Qt::IgnoreAction);
- }
- }
-
- -void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response)
- +void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response)
- {
- setExecutedDropAction(response.acceptedAction());
- +}
- +
- +void QWaylandDrag::finishDrag()
- +{
- QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
- eventFilter(shapedPixmapWindow(), &event);
- +
- + if (drag())
- + drag()->deleteLater();
- +}
- +
- +bool QWaylandDrag::ownsDragObject() const
- +{
- + return true;
- }
-
- }
- diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
- index 474fe2ab..46f629ac 100644
- --- a/src/client/qwaylanddnd_p.h
- +++ b/src/client/qwaylanddnd_p.h
- @@ -71,9 +71,10 @@ public:
- QWaylandDrag(QWaylandDisplay *display);
- ~QWaylandDrag() override;
-
- - void updateTarget(const QString &mimeType);
- - void setResponse(const QPlatformDragQtResponse &response);
- - void finishDrag(const QPlatformDropQtResponse &response);
- + void setResponse(bool accepted);
- + void setResponse(const QPlatformDropQtResponse &response);
- + void setDropResponse(const QPlatformDropQtResponse &response);
- + void finishDrag();
-
- protected:
- void startDrag() override;
- @@ -82,6 +83,7 @@ protected:
- void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
- void endDrag() override;
-
- + bool ownsDragObject() const override;
-
- private:
- QWaylandDisplay *m_display = nullptr;
- diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp
- index 47696a6a..9435e961 100644
- --- a/src/client/qwaylandinputcontext.cpp
- +++ b/src/client/qwaylandinputcontext.cpp
- @@ -93,9 +93,14 @@ void QWaylandTextInput::reset()
- void QWaylandTextInput::commit()
- {
- if (QObject *o = QGuiApplication::focusObject()) {
- - QInputMethodEvent event;
- - event.setCommitString(m_preeditCommit);
- - QCoreApplication::sendEvent(o, &event);
- + if (!m_preeditCommit.isEmpty()) {
- +
- + QInputMethodEvent event;
- + event.setCommitString(m_preeditCommit);
- + m_preeditCommit = QString();
- +
- + QCoreApplication::sendEvent(o, &event);
- + }
- }
-
- reset();
- diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
- index b0e9692b..ab978d3f 100644
- --- a/src/client/qwaylandinputdevice.cpp
- +++ b/src/client/qwaylandinputdevice.cpp
- @@ -310,8 +310,7 @@ void QWaylandInputDevice::Pointer::updateCursor()
- auto shape = seat()->mCursor.shape;
-
- if (shape == Qt::BlankCursor) {
- - if (mCursor.surface)
- - mCursor.surface->hide();
- + getOrCreateCursorSurface()->hide();
- return;
- }
-
- @@ -846,7 +845,7 @@ void QWaylandInputDevice::Pointer::releaseButtons()
- mButtons = Qt::NoButton;
-
- if (auto *window = focusWindow()) {
- - MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
- + ReleaseEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, Qt::NoButton, mParent->modifiers());
- window->handleMouse(mParent, e);
- }
- }
- @@ -1304,14 +1303,6 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
- void QWaylandInputDevice::Keyboard::handleFocusLost()
- {
- mFocus = nullptr;
- -#if QT_CONFIG(clipboard)
- - if (auto *dataDevice = mParent->dataDevice())
- - dataDevice->invalidateSelectionOffer();
- -#endif
- -#if QT_CONFIG(wayland_client_primary_selection)
- - if (auto *device = mParent->primarySelectionDevice())
- - device->invalidateSelectionOffer();
- -#endif
- mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
- mRepeatTimer.stop();
- }
- @@ -1400,6 +1391,7 @@ void QWaylandInputDevice::Touch::touch_cancel()
- if (touchExt)
- touchExt->touchCanceled();
-
- + mFocus = nullptr;
- QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice);
- }
-
- diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
- index d257e2e3..54861600 100644
- --- a/src/client/qwaylandintegration.cpp
- +++ b/src/client/qwaylandintegration.cpp
- @@ -125,6 +125,9 @@ QWaylandIntegration::QWaylandIntegration()
- #endif
-
- reconfigureInputContext();
- +
- + QWaylandWindow::fixedToplevelPositions =
- + !qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
- }
-
- QWaylandIntegration::~QWaylandIntegration()
- @@ -192,14 +195,18 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
-
- void QWaylandIntegration::initialize()
- {
- + mDisplay->initEventThread();
- +
- + // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
- + mDisplay->initialize();
- +
- + // But the aboutToBlock() and awake() should be connected after initializePlatform().
- + // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait,
- + // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip().
- QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
- QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
- QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
-
- - int fd = wl_display_get_fd(mDisplay->wl_display());
- - QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
- - QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
- -
- // Qt does not support running with no screens
- mDisplay->ensureScreen();
- }
- @@ -262,6 +269,14 @@ QWaylandDisplay *QWaylandIntegration::display() const
- return mDisplay.data();
- }
-
- +Qt::KeyboardModifiers QWaylandIntegration::queryKeyboardModifiers() const
- +{
- + if (auto *seat = mDisplay->currentInputDevice()) {
- + return seat->modifiers();
- + }
- + return Qt::NoModifier;
- +}
- +
- QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const
- {
- if (auto *seat = mDisplay->currentInputDevice())
- diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h
- index ff70ae25..73b80658 100644
- --- a/src/client/qwaylandintegration_p.h
- +++ b/src/client/qwaylandintegration_p.h
- @@ -107,6 +107,8 @@ public:
-
- QWaylandDisplay *display() const;
-
- + Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- +
- QList<int> possibleKeys(const QKeyEvent *event) const override;
-
- QStringList themeNames() const override;
- diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp
- index bf54a1a0..9763c312 100644
- --- a/src/client/qwaylandnativeinterface.cpp
- +++ b/src/client/qwaylandnativeinterface.cpp
- @@ -139,7 +139,7 @@ void *QWaylandNativeInterface::nativeResourceForScreen(const QByteArray &resourc
- {
- QByteArray lowerCaseResource = resourceString.toLower();
-
- - if (lowerCaseResource == "output")
- + if (lowerCaseResource == "output" && !screen->handle()->isPlaceholder())
- return ((QWaylandScreen *) screen->handle())->output();
-
- return nullptr;
- diff --git a/src/client/qwaylandprimaryselectionv1.cpp b/src/client/qwaylandprimaryselectionv1.cpp
- index 7805dd73..dac532b2 100644
- --- a/src/client/qwaylandprimaryselectionv1.cpp
- +++ b/src/client/qwaylandprimaryselectionv1.cpp
- @@ -54,11 +54,6 @@ QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1
- : zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
- , m_display(display)
- {
- - // Create devices for all seats.
- - // This only works if we get the global before all devices
- - const auto seats = m_display->inputDevices();
- - for (auto *seat : seats)
- - seat->setPrimarySelectionDevice(createDevice(seat));
- }
-
- QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
- diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
- index 6cb337de..5537dafd 100644
- --- a/src/client/qwaylandscreen.cpp
- +++ b/src/client/qwaylandscreen.cpp
- @@ -60,7 +60,7 @@ QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandDisplay* display,
- }
-
- QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id)
- - : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 2))
- + : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 3))
- , m_outputId(id)
- , mWaylandDisplay(waylandDisplay)
- , mOutputName(QStringLiteral("Screen%1").arg(id))
- @@ -72,7 +72,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
- qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor,"
- << "QScreen may not work correctly";
- mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc.
- - mOutputDone = true; // Fake the done event
- + mProcessedEvents |= OutputDoneEvent; // Fake the done event
- maybeInitialize();
- }
- }
- @@ -81,16 +81,29 @@ QWaylandScreen::~QWaylandScreen()
- {
- if (zxdg_output_v1::isInitialized())
- zxdg_output_v1::destroy();
- + if (wl_output::isInitialized() && wl_output_get_version(wl_output::object()) >= WL_OUTPUT_RELEASE_SINCE_VERSION)
- + wl_output::release();
- +}
- +
- +uint QWaylandScreen::requiredEvents() const
- +{
- + uint ret = OutputDoneEvent;
- +
- + if (mWaylandDisplay->xdgOutputManager()) {
- + ret |= XdgOutputNameEvent;
- +
- + if (mWaylandDisplay->xdgOutputManager()->version() < 3)
- + ret |= XdgOutputDoneEvent;
- + }
- + return ret;
- }
-
- void QWaylandScreen::maybeInitialize()
- {
- Q_ASSERT(!mInitialized);
-
- - if (!mOutputDone)
- - return;
- -
- - if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone)
- + const uint requiredEvents = this->requiredEvents();
- + if ((mProcessedEvents & requiredEvents) != requiredEvents)
- return;
-
- mInitialized = true;
- @@ -276,9 +289,8 @@ void QWaylandScreen::output_scale(int32_t factor)
-
- void QWaylandScreen::output_done()
- {
- - mOutputDone = true;
- - if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3)
- - mXdgOutputDone = true;
- + mProcessedEvents |= OutputDoneEvent;
- +
- if (mInitialized) {
- updateOutputProperties();
- if (zxdg_output_v1::isInitialized())
- @@ -339,7 +351,7 @@ void QWaylandScreen::zxdg_output_v1_done()
- if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3))
- qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor";
-
- - mXdgOutputDone = true;
- + mProcessedEvents |= XdgOutputDoneEvent;
- if (mInitialized)
- updateXdgOutputProperties();
- else
- @@ -348,7 +360,11 @@ void QWaylandScreen::zxdg_output_v1_done()
-
- void QWaylandScreen::zxdg_output_v1_name(const QString &name)
- {
- + if (Q_UNLIKELY(mInitialized))
- + qWarning(lcQpaWayland) << "zxdg_output_v1.name received after output has been initialized, this is most likely a bug in the compositor";
- +
- mOutputName = name;
- + mProcessedEvents |= XdgOutputNameEvent;
- }
-
- void QWaylandScreen::updateXdgOutputProperties()
- diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
- index df1c94f2..050cfdc0 100644
- --- a/src/client/qwaylandscreen_p.h
- +++ b/src/client/qwaylandscreen_p.h
- @@ -116,6 +116,13 @@ public:
- static QWaylandScreen *fromWlOutput(::wl_output *output);
-
- private:
- + enum Event : uint {
- + XdgOutputDoneEvent = 0x1,
- + OutputDoneEvent = 0x2,
- + XdgOutputNameEvent = 0x4,
- + };
- + uint requiredEvents() const;
- +
- void output_mode(uint32_t flags, int width, int height, int refresh) override;
- void output_geometry(int32_t x, int32_t y,
- int32_t width, int32_t height,
- @@ -148,8 +155,7 @@ private:
- QSize mPhysicalSize;
- QString mOutputName;
- Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
- - bool mOutputDone = false;
- - bool mXdgOutputDone = false;
- + uint mProcessedEvents = 0;
- bool mInitialized = false;
-
- #if QT_CONFIG(cursor)
- diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
- index dc7ff670..145f933b 100644
- --- a/src/client/qwaylandshmbackingstore.cpp
- +++ b/src/client/qwaylandshmbackingstore.cpp
- @@ -52,6 +52,7 @@
-
- #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
-
- +#include <fcntl.h>
- #include <unistd.h>
- #include <sys/mman.h>
-
- @@ -61,6 +62,9 @@
- # ifndef MFD_CLOEXEC
- # define MFD_CLOEXEC 0x0001U
- # endif
- +# ifndef MFD_ALLOW_SEALING
- +# define MFD_ALLOW_SEALING 0x0002U
- +# endif
- #endif
-
- QT_BEGIN_NAMESPACE
- @@ -68,14 +72,16 @@ QT_BEGIN_NAMESPACE
- namespace QtWaylandClient {
-
- QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
- - const QSize &size, QImage::Format format, int scale)
- + const QSize &size, QImage::Format format, qreal scale)
- {
- int stride = size.width() * 4;
- int alloc = stride * size.height();
- int fd = -1;
-
- -#ifdef SYS_memfd_create
- - fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC);
- +#if defined(SYS_memfd_create) && defined(F_SEAL_SEAL)
- + fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- + if (fd >= 0)
- + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
- #endif
-
- QScopedPointer<QFile> filePointer;
- @@ -108,7 +114,7 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
- QWaylandShm* shm = display->shm();
- wl_shm_format wl_format = shm->formatFrom(format);
- mImage = QImage(data, size.width(), size.height(), stride, format);
- - mImage.setDevicePixelRatio(qreal(scale));
- + mImage.setDevicePixelRatio(scale);
-
- mShmPool = wl_shm_create_pool(shm->object(), fd, alloc);
- init(wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(),
- @@ -180,8 +186,6 @@ void QWaylandShmBackingStore::beginPaint(const QRegion ®ion)
- mPainting = true;
- ensureSize();
-
- - waylandWindow()->setCanResize(false);
- -
- if (mBackBuffer->image()->hasAlphaChannel()) {
- QPainter p(paintDevice());
- p.setCompositionMode(QPainter::CompositionMode_Source);
- @@ -196,7 +200,6 @@ void QWaylandShmBackingStore::endPaint()
- mPainting = false;
- if (mPendingFlush)
- flush(window(), mPendingRegion, QPoint());
- - waylandWindow()->setCanResize(true);
- }
-
- void QWaylandShmBackingStore::ensureSize()
- @@ -271,7 +274,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
- void QWaylandShmBackingStore::resize(const QSize &size)
- {
- QMargins margins = windowDecorationMargins();
- - int scale = waylandWindow()->scale();
- + qreal scale = waylandWindow()->scale();
- QSize sizeWithMargins = (size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom())) * scale;
-
- // We look for a free buffer to draw into. If the buffer is not the last buffer we used,
- diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h
- index e01632da..f3fae438 100644
- --- a/src/client/qwaylandshmbackingstore_p.h
- +++ b/src/client/qwaylandshmbackingstore_p.h
- @@ -71,7 +71,7 @@ class QWaylandWindow;
- class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer {
- public:
- QWaylandShmBuffer(QWaylandDisplay *display,
- - const QSize &size, QImage::Format format, int scale = 1);
- + const QSize &size, QImage::Format format, qreal scale = 1);
- ~QWaylandShmBuffer() override;
- QSize size() const override { return mImage.size(); }
- int scale() const override { return int(mImage.devicePixelRatio()); }
- diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
- index d57094a7..7a9bccc1 100644
- --- a/src/client/qwaylandwindow.cpp
- +++ b/src/client/qwaylandwindow.cpp
- @@ -76,7 +76,6 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
- QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
- : QPlatformWindow(window)
- , mDisplay(display)
- - , mFrameQueue(mDisplay->createFrameQueue())
- , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
- {
- {
- @@ -95,9 +94,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
-
- QWaylandWindow::~QWaylandWindow()
- {
- - mDisplay->destroyFrameQueue(mFrameQueue);
- - mDisplay->handleWindowDestroyed(this);
- -
- delete mWindowDecoration;
-
- if (mSurface)
- @@ -189,7 +185,7 @@ void QWaylandWindow::initWindow()
- // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
- // to inform the compositor that high-resolution buffers will be provided.
- if (mDisplay->compositorVersion() >= 3)
- - mSurface->set_buffer_scale(scale());
- + mSurface->set_buffer_scale(mScale);
-
- if (QScreen *s = window()->screen())
- setOrientationMask(s->orientationUpdateMask());
- @@ -204,6 +200,8 @@ void QWaylandWindow::initWindow()
- mShellSurface->requestWindowStates(window()->windowStates());
- handleContentOrientationChange(window()->contentOrientation());
- mFlags = window()->flags();
- +
- + mSurface->commit();
- }
-
- void QWaylandWindow::initializeWlSurface()
- @@ -243,6 +241,7 @@ bool QWaylandWindow::shouldCreateSubSurface() const
-
- void QWaylandWindow::reset()
- {
- + closeChildPopups();
- delete mShellSurface;
- mShellSurface = nullptr;
- delete mSubSurfaceWindow;
- @@ -255,17 +254,22 @@ void QWaylandWindow::reset()
- mSurface.reset();
- }
-
- - if (mFrameCallback) {
- - wl_callback_destroy(mFrameCallback);
- - mFrameCallback = nullptr;
- - }
- + {
- + QMutexLocker lock(&mFrameSyncMutex);
- + if (mFrameCallback) {
- + wl_callback_destroy(mFrameCallback);
- + mFrameCallback = nullptr;
- + }
-
- - mFrameCallbackElapsedTimer.invalidate();
- - mWaitingForFrameCallback = false;
- + mFrameCallbackElapsedTimer.invalidate();
- + mWaitingForFrameCallback = false;
- + }
- mFrameCallbackTimedOut = false;
-
- mMask = QRegion();
- mQueuedBuffer = nullptr;
- +
- + mDisplay->handleWindowDestroyed(this);
- }
-
- QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
- @@ -351,19 +355,25 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect)
- }
- }
-
- -void QWaylandWindow::setGeometry(const QRect &rect)
- +void QWaylandWindow::setGeometry(const QRect &r)
- {
- + auto rect = r;
- + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
- + && window()->type() != Qt::ToolTip) {
- + rect.moveTo(screen()->geometry().topLeft());
- + }
- setGeometry_helper(rect);
-
- if (window()->isVisible() && rect.isValid()) {
- if (mWindowDecoration)
- mWindowDecoration->update();
-
- - if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize)
- + if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize) {
- + QMutexLocker lock(&mResizeLock);
- mResizeDirty = true;
- - else
- + } else {
- QWindowSystemInterface::handleGeometryChange(window(), geometry());
- -
- + }
- mSentInitialResize = true;
- }
- QRect exposeGeometry(QPoint(), geometry().size());
- @@ -374,7 +384,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
- mShellSurface->setWindowGeometry(windowContentGeometry());
-
- if (isOpaque() && mMask.isEmpty())
- - setOpaqueArea(rect);
- + setOpaqueArea(QRect(QPoint(0, 0), rect.size()));
- }
-
- void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
- @@ -399,21 +409,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
- mLastExposeGeometry = rect;
- }
-
- -
- -static QVector<QPointer<QWaylandWindow>> activePopups;
- -
- -void QWaylandWindow::closePopups(QWaylandWindow *parent)
- -{
- - while (!activePopups.isEmpty()) {
- - auto popup = activePopups.takeLast();
- - if (popup.isNull())
- - continue;
- - if (popup.data() == parent)
- - return;
- - popup->reset();
- - }
- -}
- -
- QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
- {
- QReadLocker lock(&mSurfaceLock);
- @@ -433,10 +428,7 @@ void QWaylandWindow::setVisible(bool visible)
- lastVisible = visible;
-
- if (visible) {
- - if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
- - activePopups << this;
- initWindow();
- - mDisplay->flushRequests();
-
- setGeometry(windowGeometry());
- // Don't flush the events here, or else the newly visible window may start drawing, but since
- @@ -444,7 +436,6 @@ void QWaylandWindow::setVisible(bool visible)
- // QWaylandShmBackingStore::beginPaint().
- } else {
- sendExposeEvent(QRect());
- - closePopups(this);
- reset();
- }
- }
- @@ -487,8 +478,6 @@ void QWaylandWindow::setMask(const QRegion &mask)
- if (isOpaque())
- setOpaqueArea(mMask);
- }
- -
- - mSurface->commit();
- }
-
- void QWaylandWindow::applyConfigureWhenPossible()
- @@ -556,12 +545,12 @@ void QWaylandWindow::sendRecursiveExposeEvent()
-
- void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
- {
- - Q_ASSERT(!buffer->committed());
- QReadLocker locker(&mSurfaceLock);
- if (mSurface == nullptr)
- return;
-
- if (buffer) {
- + Q_ASSERT(!buffer->committed());
- handleUpdate();
- buffer->setBusy();
-
- @@ -583,7 +572,16 @@ void QWaylandWindow::damage(const QRect &rect)
- if (mSurface == nullptr)
- return;
-
- - mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
- + const qreal s = scale();
- + if (mDisplay->compositorVersion() >= 4) {
- + const QRect bufferRect =
- + QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
- + .toAlignedRect();
- + mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
- + bufferRect.height());
- + } else {
- + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
- + }
- }
-
- void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
- @@ -619,8 +617,19 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
- return;
-
- attachOffset(buffer);
- - for (const QRect &rect: damage)
- - mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
- + if (mDisplay->compositorVersion() >= 4) {
- + const qreal s = scale();
- + for (const QRect &rect : damage) {
- + const QRect bufferRect =
- + QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
- + .toAlignedRect();
- + mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
- + bufferRect.height());
- + }
- + } else {
- + for (const QRect &rect: damage)
- + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
- + }
- Q_ASSERT(!buffer->committed());
- buffer->setCommitted();
- mSurface->commit();
- @@ -635,42 +644,53 @@ void QWaylandWindow::commit()
-
- const wl_callback_listener QWaylandWindow::callbackListener = {
- [](void *data, wl_callback *callback, uint32_t time) {
- - Q_UNUSED(callback);
- Q_UNUSED(time);
- auto *window = static_cast<QWaylandWindow*>(data);
- - window->handleFrameCallback();
- + window->handleFrameCallback(callback);
- }
- };
-
- -void QWaylandWindow::handleFrameCallback()
- +void QWaylandWindow::handleFrameCallback(wl_callback* callback)
- {
- + QMutexLocker locker(&mFrameSyncMutex);
- + if (!mFrameCallback) {
- + // This means the callback is already unset by QWaylandWindow::reset.
- + // The wl_callback object will be destroyed there too.
- + return;
- + }
- + Q_ASSERT(callback == mFrameCallback);
- + wl_callback_destroy(callback);
- + mFrameCallback = nullptr;
- +
- mWaitingForFrameCallback = false;
- mFrameCallbackElapsedTimer.invalidate();
-
- // The rest can wait until we can run it on the correct thread
- - if (!mWaitingForUpdateDelivery) {
- - auto doHandleExpose = [this]() {
- - bool wasExposed = isExposed();
- - mFrameCallbackTimedOut = false;
- - if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
- - sendExposeEvent(QRect(QPoint(), geometry().size()));
- - if (wasExposed && hasPendingUpdateRequest())
- - deliverUpdateRequest();
- -
- - mWaitingForUpdateDelivery = false;
- - };
- + auto doHandleExpose = [this]() {
- + mWaitingForUpdateDelivery.storeRelease(false);
- + bool wasExposed = isExposed();
- + mFrameCallbackTimedOut = false;
- + if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
- + sendExposeEvent(QRect(QPoint(), geometry().size()));
- + if (wasExposed && hasPendingUpdateRequest())
- + deliverUpdateRequest();
- + };
-
- + if (mWaitingForUpdateDelivery.testAndSetAcquire(false, true)) {
- // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
- // in the single-threaded case.
- - mWaitingForUpdateDelivery = true;
- QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
- }
- +
- + mFrameSyncWait.notify_all();
- }
-
- bool QWaylandWindow::waitForFrameSync(int timeout)
- {
- - QMutexLocker locker(mFrameQueue.mutex);
- - mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout);
- + QMutexLocker locker(&mFrameSyncMutex);
- +
- + QDeadlineTimer deadline(timeout);
- + while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { }
-
- if (mWaitingForFrameCallback) {
- qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
- @@ -772,8 +792,6 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient
- Q_UNREACHABLE();
- }
- mSurface->set_buffer_transform(transform);
- - // set_buffer_transform is double buffered, we need to commit.
- - mSurface->commit();
- }
-
- void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
- @@ -1032,8 +1050,17 @@ void QWaylandWindow::handleScreensChanged()
- if (newScreen == mLastReportedScreen)
- return;
-
- + if (!newScreen->isPlaceholder() && !newScreen->QPlatformScreen::screen())
- + mDisplay->forceRoundTrip();
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
- mLastReportedScreen = newScreen;
- + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
- + && window()->type() != Qt::ToolTip
- + && geometry().topLeft() != newScreen->geometry().topLeft()) {
- + auto geometry = this->geometry();
- + geometry.moveTo(newScreen->geometry().topLeft());
- + setGeometry(geometry);
- + }
-
- int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
- if (scale != mScale) {
- @@ -1087,14 +1114,14 @@ bool QWaylandWindow::isActive() const
- return mDisplay->isWindowActivated(this);
- }
-
- -int QWaylandWindow::scale() const
- +qreal QWaylandWindow::scale() const
- {
- - return mScale;
- + return devicePixelRatio();
- }
-
- qreal QWaylandWindow::devicePixelRatio() const
- {
- - return mScale;
- + return qreal(mScale);
- }
-
- bool QWaylandWindow::setMouseGrabEnabled(bool grab)
- @@ -1108,10 +1135,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
- return true;
- }
-
- +Qt::WindowStates QWaylandWindow::windowStates() const
- +{
- + return mLastReportedWindowStates;
- +}
- +
- void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
- {
- createDecoration();
- - QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
- + Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
- + Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
- + QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
- + lastStatesWithoutActive);
- mLastReportedWindowStates = states;
- }
-
- @@ -1153,19 +1188,24 @@ void QWaylandWindow::timerEvent(QTimerEvent *event)
- if (event->timerId() != mFrameCallbackCheckIntervalTimerId)
- return;
-
- - bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
- - if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
- - killTimer(mFrameCallbackCheckIntervalTimerId);
- - mFrameCallbackCheckIntervalTimerId = -1;
- - }
- - if (mFrameCallbackElapsedTimer.isValid() && callbackTimerExpired) {
- - mFrameCallbackElapsedTimer.invalidate();
- + {
- + QMutexLocker lock(&mFrameSyncMutex);
-
- - qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
- - mFrameCallbackTimedOut = true;
- - mWaitingForUpdate = false;
- - sendExposeEvent(QRect());
- + bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
- + if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
- + killTimer(mFrameCallbackCheckIntervalTimerId);
- + mFrameCallbackCheckIntervalTimerId = -1;
- + }
- + if (!mFrameCallbackElapsedTimer.isValid() || !callbackTimerExpired) {
- + return;
- + }
- + mFrameCallbackElapsedTimer.invalidate();
- }
- +
- + qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
- + mFrameCallbackTimedOut = true;
- + mWaitingForUpdate = false;
- + sendExposeEvent(QRect());
- }
-
- void QWaylandWindow::requestUpdate()
- @@ -1174,8 +1214,11 @@ void QWaylandWindow::requestUpdate()
- Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
-
- // If we have a frame callback all is good and will be taken care of there
- - if (mWaitingForFrameCallback)
- - return;
- + {
- + QMutexLocker locker(&mFrameSyncMutex);
- + if (mWaitingForFrameCallback)
- + return;
- + }
-
- // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
- // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
- @@ -1188,7 +1231,12 @@ void QWaylandWindow::requestUpdate()
- // so use invokeMethod to delay the delivery a bit.
- QMetaObject::invokeMethod(this, [this] {
- // Things might have changed in the meantime
- - if (hasPendingUpdateRequest() && !mWaitingForFrameCallback)
- + {
- + QMutexLocker locker(&mFrameSyncMutex);
- + if (mWaitingForFrameCallback)
- + return;
- + }
- + if (hasPendingUpdateRequest())
- deliverUpdateRequest();
- }, Qt::QueuedConnection);
- }
- @@ -1199,19 +1247,18 @@ void QWaylandWindow::requestUpdate()
- void QWaylandWindow::handleUpdate()
- {
- qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
- +
- // TODO: Should sync subsurfaces avoid requesting frame callbacks?
- QReadLocker lock(&mSurfaceLock);
- if (!mSurface)
- return;
-
- - if (mFrameCallback) {
- - wl_callback_destroy(mFrameCallback);
- - mFrameCallback = nullptr;
- - }
- + QMutexLocker locker(&mFrameSyncMutex);
- + if (mWaitingForFrameCallback)
- + return;
-
- - QMutexLocker locker(mFrameQueue.mutex);
- struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
- - wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
- + wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue());
- mFrameCallback = wl_surface_frame(wrappedSurface);
- wl_proxy_wrapper_destroy(wrappedSurface);
- wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
- @@ -1221,6 +1268,8 @@ void QWaylandWindow::handleUpdate()
- // Start a timer for handling the case when the compositor stops sending frame callbacks.
- if (mFrameCallbackTimeout > 0) {
- QMetaObject::invokeMethod(this, [this] {
- + QMutexLocker locker(&mFrameSyncMutex);
- +
- if (mWaitingForFrameCallback) {
- if (mFrameCallbackCheckIntervalTimerId < 0)
- mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout);
- @@ -1281,6 +1330,20 @@ void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea)
- wl_region_destroy(region);
- }
-
- +void QWaylandWindow::addChildPopup(QWaylandWindow *surface) {
- + mChildPopups.append(surface);
- +}
- +
- +void QWaylandWindow::removeChildPopup(QWaylandWindow *surface) {
- + mChildPopups.removeAll(surface);
- +}
- +
- +void QWaylandWindow::closeChildPopups() {
- + while (!mChildPopups.isEmpty()) {
- + auto popup = mChildPopups.takeLast();
- + popup->reset();
- + }
- +}
- }
-
- QT_END_NAMESPACE
- diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
- index 01337cff..741f9e5c 100644
- --- a/src/client/qwaylandwindow_p.h
- +++ b/src/client/qwaylandwindow_p.h
- @@ -98,6 +98,9 @@ public:
- QWaylandWindow(QWindow *window, QWaylandDisplay *display);
- ~QWaylandWindow() override;
-
- + // Keep Toplevels position on the top left corner of their screen
- + static inline bool fixedToplevelPositions = true;
- +
- virtual WindowType windowType() const = 0;
- virtual void ensureSize();
- WId winId() const override;
- @@ -148,13 +151,14 @@ public:
- void setWindowState(Qt::WindowStates states) override;
- void setWindowFlags(Qt::WindowFlags flags) override;
- void handleWindowStatesChanged(Qt::WindowStates states);
- + Qt::WindowStates windowStates() const;
-
- void raise() override;
- void lower() override;
-
- void setMask(const QRegion ®ion) override;
-
- - int scale() const;
- + qreal scale() const;
- qreal devicePixelRatio() const override;
-
- void requestActivateWindow() override;
- @@ -206,6 +210,10 @@ public:
- void handleUpdate();
- void deliverUpdateRequest() override;
-
- + void addChildPopup(QWaylandWindow* child);
- + void removeChildPopup(QWaylandWindow* child);
- + void closeChildPopups();
- +
- public slots:
- void applyConfigure();
-
- @@ -215,7 +223,11 @@ signals:
-
- protected:
- QWaylandDisplay *mDisplay = nullptr;
- +
- + // mSurface can be written by the main thread. Other threads should claim a read lock for access
- + mutable QReadWriteLock mSurfaceLock;
- QScopedPointer<QWaylandSurface> mSurface;
- +
- QWaylandShellSurface *mShellSurface = nullptr;
- QWaylandSubSurface *mSubSurfaceWindow = nullptr;
- QVector<QWaylandSubSurface *> mChildren;
- @@ -225,13 +237,14 @@ protected:
- Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
-
- WId mWindowId;
- - bool mWaitingForFrameCallback = false;
- bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
- - bool mWaitingForUpdateDelivery = false;
- int mFrameCallbackCheckIntervalTimerId = -1;
- - QElapsedTimer mFrameCallbackElapsedTimer;
- - struct ::wl_callback *mFrameCallback = nullptr;
- - QWaylandDisplay::FrameQueue mFrameQueue;
- + QAtomicInt mWaitingForUpdateDelivery = false;
- +
- + bool mWaitingForFrameCallback = false; // Protected by mFrameSyncMutex
- + QElapsedTimer mFrameCallbackElapsedTimer; // Protected by mFrameSyncMutex
- + struct ::wl_callback *mFrameCallback = nullptr; // Protected by mFrameSyncMutex
- + QMutex mFrameSyncMutex;
- QWaitCondition mFrameSyncWait;
-
- // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
- @@ -261,6 +274,8 @@ protected:
- QWaylandBuffer *mQueuedBuffer = nullptr;
- QRegion mQueuedBufferDamage;
-
- + QList<QPointer<QWaylandWindow>> mChildPopups;
- +
- private:
- void setGeometry_helper(const QRect &rect);
- void initWindow();
- @@ -283,12 +298,10 @@ private:
- QRect mLastExposeGeometry;
-
- static const wl_callback_listener callbackListener;
- - void handleFrameCallback();
- + void handleFrameCallback(struct ::wl_callback* callback);
-
- static QWaylandWindow *mMouseGrab;
-
- - mutable QReadWriteLock mSurfaceLock;
- -
- friend class QWaylandSubSurface;
- };
-
- diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
- index ccad0048..4cc9b3b8 100644
- --- a/src/client/shellintegration/qwaylandshellintegration_p.h
- +++ b/src/client/shellintegration/qwaylandshellintegration_p.h
- @@ -73,11 +73,10 @@ public:
- return true;
- }
- virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
- + // kept for binary compat with layer-shell-qt
- virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
- - if (newFocus)
- - m_display->handleWindowActivated(newFocus);
- - if (oldFocus)
- - m_display->handleWindowDeactivated(oldFocus);
- + Q_UNUSED(newFocus);
- + Q_UNUSED(oldFocus);
- }
- virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
- Q_UNUSED(resource);
- diff --git a/src/compositor/configure.json b/src/compositor/configure.json
- index bcfd5215..da95d07b 100644
- --- a/src/compositor/configure.json
- +++ b/src/compositor/configure.json
- @@ -7,6 +7,31 @@
- "testDir": "../../config.tests",
-
- "libraries": {
- + "wayland-client": {
- + "label": "Wayland client library",
- + "headers": "wayland-version.h",
- + "test": {
- + "main": [
- + "#if WAYLAND_VERSION_MAJOR < 1",
- + "# error Wayland 1.8.0 or higher required",
- + "#endif",
- + "#if WAYLAND_VERSION_MAJOR == 1",
- + "# if WAYLAND_VERSION_MINOR < 8",
- + "# error Wayland 1.8.0 or higher required",
- + "# endif",
- + "# if WAYLAND_VERSION_MINOR == 8",
- + "# if WAYLAND_VERSION_MICRO < 0",
- + "# error Wayland 1.8.0 or higher required",
- + "# endif",
- + "# endif",
- + "#endif"
- + ]
- + },
- + "sources": [
- + { "type": "pkgConfig", "args": "wayland-client" },
- + "-lwayland-client"
- + ]
- + },
- "wayland-server": {
- "label": "wayland-server",
- "headers": "wayland-version.h",
- @@ -151,8 +176,7 @@
- "#endif"
- ]
- },
- - "libs": "-ldrm",
- - "use": "egl"
- + "use": "drm egl"
- },
- "dmabuf-client-buffer": {
- "label": "Linux Client dma-buf Buffer Sharing",
- @@ -176,8 +200,7 @@
- "return 0;"
- ]
- },
- - "libs": "-ldrm",
- - "use": "egl"
- + "use": "drm egl"
- },
- "vulkan-server-buffer": {
- "label": "Vulkan Buffer Sharing",
- @@ -195,7 +218,8 @@
- "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
- "return 0;"
- ]
- - }
- + },
- + "use": "wayland-client"
- }
- },
-
- diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
- index e00c28c3..dbe2845a 100644
- --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
- +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
- @@ -40,6 +40,7 @@
- #include "qwaylandeglwindow.h"
-
- #include <QtWaylandClient/private/qwaylandscreen_p.h>
- +#include <QtWaylandClient/private/qwaylandsurface_p.h>
- #include "qwaylandglcontext.h"
-
- #include <QtEglSupport/private/qeglconvenience_p.h>
- @@ -115,6 +116,7 @@ void QWaylandEglWindow::updateSurface(bool create)
- }
- mOffset = QPoint();
- } else {
- + QReadLocker locker(&mSurfaceLock);
- if (m_waylandEglWindow) {
- int current_width, current_height;
- static bool disableResizeCheck = qgetenv("QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
- @@ -122,14 +124,16 @@ void QWaylandEglWindow::updateSurface(bool create)
- if (!disableResizeCheck) {
- wl_egl_window_get_attached_size(m_waylandEglWindow, ¤t_width, ¤t_height);
- }
- - if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height())) {
- + if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
- wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y());
- + m_requestedSize = sizeWithMargins;
- mOffset = QPoint();
-
- m_resize = true;
- }
- - } else if (create && wlSurface()) {
- - m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
- + } else if (create && mSurface) {
- + m_waylandEglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
- + m_requestedSize = sizeWithMargins;
- }
-
- if (!m_eglSurface && m_waylandEglWindow && create) {
- diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
- index 2fccbcea..ad1e5ee9 100644
- --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
- +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
- @@ -85,6 +85,7 @@ private:
- mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
-
- QSurfaceFormat m_format;
- + QSize m_requestedSize;
- };
-
- }
- diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
- index c1f45fa6..bbc63444 100644
- --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
- +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
- @@ -195,7 +195,7 @@ public:
- QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
-
- QSize surfaceSize = window->surfaceSize();
- - int scale = window->scale() ;
- + qreal scale = window->scale() ;
- glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
-
- //Draw Decoration
- diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
- index 85d25e3c..60bdd491 100644
- --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
- +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
- @@ -47,18 +47,21 @@ QT_BEGIN_NAMESPACE
-
- namespace QtWaylandClient {
-
- -QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window)
- +QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window)
- : QWaylandShellSurface(window)
- , QtWayland::xdg_popup_v5(popup)
- + , m_parent(parent)
- , m_window(window)
- {
- if (window->display()->windowExtension())
- m_extendedWindow = new QWaylandExtendedSurface(window);
- + m_parent->addChildPopup(m_window);
- }
-
- QWaylandXdgPopupV5::~QWaylandXdgPopupV5()
- {
- xdg_popup_destroy(object());
- + m_parent->removeChildPopup(m_window);
- delete m_extendedWindow;
- }
-
- diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
- index 7494f6a6..d85f130b 100644
- --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
- +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
- @@ -70,7 +70,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopupV5 : public QWaylandShellSurface
- {
- Q_OBJECT
- public:
- - QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window);
- + QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window);
- ~QWaylandXdgPopupV5() override;
-
- protected:
- @@ -78,6 +78,7 @@ protected:
-
- private:
- QWaylandExtendedSurface *m_extendedWindow = nullptr;
- + QWaylandWindow *m_parent = nullptr;
- QWaylandWindow *m_window = nullptr;
- };
-
- diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
- index 7e242c4a..def8452a 100644
- --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
- +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
- @@ -84,7 +84,7 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, Q
- int x = position.x() + parentWindow->frameMargins().left();
- int y = position.y() + parentWindow->frameMargins().top();
-
- - auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), window);
- + auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), parentWindow, window);
- m_popups.append(window);
- QObject::connect(popup, &QWaylandXdgPopupV5::destroyed, [this, window](){
- m_popups.removeOne(window);
- diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
- index 4e25949f..cfc60939 100644
- --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
- +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
- @@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
- return m_xdgShell->createXdgSurface(window);
- }
-
- -void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
- - if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
- - m_display->handleWindowActivated(newFocus);
- - if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
- - m_display->handleWindowDeactivated(oldFocus);
- -}
- -
- }
-
- QT_END_NAMESPACE
- diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
- index ce6bdb9e..aed88670 100644
- --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
- +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
- @@ -67,7 +67,6 @@ public:
- QWaylandXdgShellV5Integration() {}
- bool initialize(QWaylandDisplay *display) override;
- QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
- - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
-
- private:
- QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
- diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
- index 8c371661..151c78e3 100644
- --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
- +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
- @@ -174,6 +174,7 @@ QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdg
- , m_xdgSurface(xdgSurface)
- , m_parent(parent)
- {
- + m_parent->window()->addChildPopup(m_xdgSurface->window());
- }
-
- QWaylandXdgSurfaceV6::Popup::~Popup()
- @@ -181,6 +182,8 @@ QWaylandXdgSurfaceV6::Popup::~Popup()
- if (isInitialized())
- destroy();
-
- + m_parent->window()->removeChildPopup(m_xdgSurface->window());
- +
- if (m_grabbing) {
- auto *shell = m_xdgSurface->m_shell;
- Q_ASSERT(shell->m_topmostGrabbingPopup == this);
- diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
- index 03164316..e8da8ba1 100644
- --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
- +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
- @@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
- return m_xdgShell->getXdgSurface(window);
- }
-
- -void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
- -{
- - if (newFocus) {
- - auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
- - if (xdgSurface && !xdgSurface->handlesActiveState())
- - m_display->handleWindowActivated(newFocus);
- - }
- - if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
- - auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
- - if (xdgSurface && !xdgSurface->handlesActiveState())
- - m_display->handleWindowDeactivated(oldFocus);
- - }
- -}
- -
- }
-
- QT_END_NAMESPACE
- diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
- index 261f8cbb..c1bcd5c6 100644
- --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
- +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
- @@ -65,7 +65,6 @@ public:
- QWaylandXdgShellV6Integration() {}
- bool initialize(QWaylandDisplay *display) override;
- QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
- - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
-
- private:
- QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
- diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
- index 94ea573e..9c6cbb81 100644
- --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
- +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
- @@ -44,6 +44,7 @@
- #include <QtWaylandClient/private/qwaylandwindow_p.h>
- #include <QtWaylandClient/private/qwaylandinputdevice_p.h>
- #include <QtWaylandClient/private/qwaylandscreen_p.h>
- +#include <QtWaylandClient/private/qwaylandcursor_p.h>
- #include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
-
- #include <QtGui/private/qwindow_p.h>
- @@ -67,11 +68,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
-
- QWaylandXdgSurface::Toplevel::~Toplevel()
- {
- - if (m_applied.states & Qt::WindowActive) {
- - QWaylandWindow *window = m_xdgSurface->window();
- - window->display()->handleWindowDeactivated(window);
- - }
- -
- // The protocol spec requires that the decoration object is deleted before xdg_toplevel.
- delete m_decoration;
- m_decoration = nullptr;
- @@ -85,16 +81,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
- if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
- m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
-
- - if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
- + if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
- + && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
- m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
-
- - if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
- + if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
- + && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
- m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
-
- - // TODO: none of the other plugins send WindowActive either, but is it on purpose?
- - Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
- -
- - m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
- + m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
-
- if (m_pending.size.isEmpty()) {
- // An empty size in the configure means it's up to the client to choose the size
- @@ -105,8 +100,6 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
- m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
- }
-
- - m_xdgSurface->setSizeHints();
- -
- m_applied = m_pending;
- qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
- }
- @@ -203,12 +196,17 @@ QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResi
- | ((edges & Qt::RightEdge) ? resize_edge_right : 0));
- }
-
- -QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent,
- +QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent,
- QtWayland::xdg_positioner *positioner)
- - : xdg_popup(xdgSurface->get_popup(parent->object(), positioner->object()))
- - , m_xdgSurface(xdgSurface)
- + : m_xdgSurface(xdgSurface)
- + , m_parentXdgSurface(qobject_cast<QWaylandXdgSurface *>(parent->shellSurface()))
- , m_parent(parent)
- {
- +
- + init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr, positioner->object()));
- + if (m_parent) {
- + m_parent->addChildPopup(m_xdgSurface->window());
- + }
- }
-
- QWaylandXdgSurface::Popup::~Popup()
- @@ -216,10 +214,14 @@ QWaylandXdgSurface::Popup::~Popup()
- if (isInitialized())
- destroy();
-
- + if (m_parent) {
- + m_parent->removeChildPopup(m_xdgSurface->window());
- + }
- +
- if (m_grabbing) {
- auto *shell = m_xdgSurface->m_shell;
- Q_ASSERT(shell->m_topmostGrabbingPopup == this);
- - shell->m_topmostGrabbingPopup = m_parent->m_popup;
- + shell->m_topmostGrabbingPopup = m_parentXdgSurface ? m_parentXdgSurface->m_popup : nullptr;
- m_grabbing = false;
-
- // Synthesize Qt enter/leave events for popup
- @@ -228,8 +230,10 @@ QWaylandXdgSurface::Popup::~Popup()
- leave = m_xdgSurface->window()->window();
- QWindowSystemInterface::handleLeaveEvent(leave);
-
- - if (QWindow *enter = QGuiApplication::topLevelAt(QCursor::pos()))
- - QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
- + if (QWindow *enter = QGuiApplication::topLevelAt(QCursor::pos())) {
- + const auto pos = m_xdgSurface->window()->display()->waylandCursor()->pos();
- + QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
- + }
- }
- }
-
- @@ -267,6 +271,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
- m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
- }
- }
- + setSizeHints();
- }
-
- QWaylandXdgSurface::~QWaylandXdgSurface()
- @@ -365,9 +370,6 @@ bool QWaylandXdgSurface::wantsDecorations() const
- void QWaylandXdgSurface::propagateSizeHints()
- {
- setSizeHints();
- -
- - if (m_toplevel && m_window)
- - m_window->commit();
- }
-
- void QWaylandXdgSurface::setWindowGeometry(const QRect &rect)
- @@ -382,10 +384,10 @@ void QWaylandXdgSurface::setSizeHints()
- const int minHeight = qMax(0, m_window->windowMinimumSize().height());
- m_toplevel->set_min_size(minWidth, minHeight);
-
- - int maxWidth = qMax(0, m_window->windowMaximumSize().width());
- + int maxWidth = qMax(minWidth, m_window->windowMaximumSize().width());
- if (maxWidth == QWINDOWSIZE_MAX)
- maxWidth = 0;
- - int maxHeight = qMax(0, m_window->windowMaximumSize().height());
- + int maxHeight = qMax(minHeight, m_window->windowMaximumSize().height());
- if (maxHeight == QWINDOWSIZE_MAX)
- maxHeight = 0;
- m_toplevel->set_max_size(maxWidth, maxHeight);
- @@ -410,8 +412,6 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
- {
- Q_ASSERT(!m_toplevel && !m_popup);
-
- - auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(parent->shellSurface());
- -
- auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner());
- // set_popup expects a position relative to the parent
- QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
- @@ -425,11 +425,10 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
- positioner->set_gravity(QtWayland::xdg_positioner::gravity_bottom_right);
- positioner->set_size(m_window->geometry().width(), m_window->geometry().height());
- positioner->set_constraint_adjustment(QtWayland::xdg_positioner::constraint_adjustment_slide_x
- - | QtWayland::xdg_positioner::constraint_adjustment_slide_y
- - | QtWayland::xdg_positioner::constraint_adjustment_flip_x
- - | QtWayland::xdg_positioner::constraint_adjustment_flip_y);
- - m_popup = new Popup(this, parentXdgSurface, positioner);
- + | QtWayland::xdg_positioner::constraint_adjustment_slide_y);
- + m_popup = new Popup(this, parent, positioner);
- positioner->destroy();
- +
- delete positioner;
- }
-
- @@ -466,8 +465,10 @@ void QWaylandXdgSurface::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevic
- if (m_popup && m_popup->m_xdgSurface && m_popup->m_xdgSurface->window())
- enter = m_popup->m_xdgSurface->window()->window();
-
- - if (enter)
- - QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
- + if (enter) {
- + const auto pos = m_popup->m_xdgSurface->window()->display()->waylandCursor()->pos();
- + QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
- + }
- }
-
- void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial)
- diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
- index 96785205..4b518f0a 100644
- --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
- +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
- @@ -131,14 +131,15 @@ private:
-
- class Popup : public QtWayland::xdg_popup {
- public:
- - Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent, QtWayland::xdg_positioner *positioner);
- + Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent, QtWayland::xdg_positioner *positioner);
- ~Popup() override;
-
- void grab(QWaylandInputDevice *seat, uint serial);
- void xdg_popup_popup_done() override;
-
- QWaylandXdgSurface *m_xdgSurface = nullptr;
- - QWaylandXdgSurface *m_parent = nullptr;
- + QWaylandXdgSurface *m_parentXdgSurface = nullptr;
- + QWaylandWindow *m_parent = nullptr;
- bool m_grabbing = false;
- };
-
- diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
- index 8769d971..da0dd6a7 100644
- --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
- +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
- @@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
- return m_xdgShell->getXdgSurface(window);
- }
-
- -void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
- -{
- - if (newFocus) {
- - auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
- - if (xdgSurface && !xdgSurface->handlesActiveState())
- - m_display->handleWindowActivated(newFocus);
- - }
- - if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
- - auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
- - if (xdgSurface && !xdgSurface->handlesActiveState())
- - m_display->handleWindowDeactivated(oldFocus);
- - }
- -}
- -
- }
-
- QT_END_NAMESPACE
- diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
- index b6caa6c9..2f929f98 100644
- --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
- +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
- @@ -65,7 +65,6 @@ public:
- QWaylandXdgShellIntegration() {}
- bool initialize(QWaylandDisplay *display) override;
- QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
- - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
-
- private:
- QScopedPointer<QWaylandXdgShell> m_xdgShell;
- diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp
- index c5266ab3..e2fe1928 100644
- --- a/src/shared/qwaylandmimehelper.cpp
- +++ b/src/shared/qwaylandmimehelper.cpp
- @@ -60,7 +60,7 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &
- buf.open(QIODevice::ReadWrite);
- QByteArray fmt = "BMP";
- if (mimeType.startsWith(QLatin1String("image/"))) {
- - QByteArray imgFmt = mimeType.mid(6).toUpper().toLatin1();
- + QByteArray imgFmt = mimeType.mid(6).toLower().toLatin1();
- if (QImageWriter::supportedImageFormats().contains(imgFmt))
- fmt = imgFmt;
- }
- diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
- index 1568b3b9..067410d0 100644
- --- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
- +++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
- @@ -35,7 +35,7 @@
-
- using namespace MockCompositor;
-
- -constexpr int dataDeviceVersion = 1;
- +constexpr int dataDeviceVersion = 3;
-
- class DataDeviceCompositor : public DefaultCompositor {
- public:
- diff --git a/tests/auto/client/seatv5/tst_seatv5.cpp b/tests/auto/client/seatv5/tst_seatv5.cpp
- index 9312c2e5..2ea382f1 100644
- --- a/tests/auto/client/seatv5/tst_seatv5.cpp
- +++ b/tests/auto/client/seatv5/tst_seatv5.cpp
- @@ -73,6 +73,7 @@ private slots:
- void multiTouch();
- void multiTouchUpAndMotionFrame();
- void tapAndMoveInSameFrame();
- + void cancelTouch();
- };
-
- void tst_seatv5::bindsToSeat()
- @@ -646,5 +647,34 @@ void tst_seatv5::tapAndMoveInSameFrame()
- QTRY_COMPARE(window.m_events.last().touchPoints.first().state(), Qt::TouchPointState::TouchPointReleased);
- }
-
- +void tst_seatv5::cancelTouch()
- +{
- + TouchWindow window;
- + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- +
- + exec([=] {
- + auto *t = touch();
- + auto *c = client();
- + t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
- + t->sendFrame(c);
- + t->sendCancel(c);
- + t->sendFrame(c);
- + });
- +
- + QTRY_VERIFY(!window.m_events.empty());
- + {
- + auto e = window.m_events.takeFirst();
- + QCOMPARE(e.type, QEvent::TouchBegin);
- + QCOMPARE(e.touchPointStates, Qt::TouchPointPressed);
- + QCOMPARE(e.touchPoints.length(), 1);
- + QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
- + }
- + {
- + auto e = window.m_events.takeFirst();
- + QCOMPARE(e.type, QEvent::TouchCancel);
- + QCOMPARE(e.touchPoints.length(), 0);
- + }
- +}
- +
- QCOMPOSITOR_TEST_MAIN(tst_seatv5)
- #include "tst_seatv5.moc"
- diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
- index 0d988521..53e12291 100644
- --- a/tests/auto/client/shared/coreprotocol.cpp
- +++ b/tests/auto/client/shared/coreprotocol.cpp
- @@ -185,6 +185,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource
-
- if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
- wl_output::send_done(resource->handle);
- +
- + Q_EMIT outputBound(resource);
- }
-
- // Seat stuff
- @@ -451,6 +453,13 @@ void Touch::sendFrame(wl_client *client)
- send_frame(r->handle);
- }
-
- +void Touch::sendCancel(wl_client *client)
- +{
- + const auto touchResources = resourceMap().values(client);
- + for (auto *r : touchResources)
- + send_cancel(r->handle);
- +}
- +
- uint Keyboard::sendEnter(Surface *surface)
- {
- auto serial = m_seat->m_compositor->nextSerial();
- diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
- index a1af137a..00c439e1 100644
- --- a/tests/auto/client/shared/coreprotocol.h
- +++ b/tests/auto/client/shared/coreprotocol.h
- @@ -158,7 +158,7 @@ class WlCompositor : public Global, public QtWaylandServer::wl_compositor
- {
- Q_OBJECT
- public:
- - explicit WlCompositor(CoreCompositor *compositor, int version = 3)
- + explicit WlCompositor(CoreCompositor *compositor, int version = 4)
- : QtWaylandServer::wl_compositor(compositor->m_display, version)
- , m_compositor(compositor)
- {}
- @@ -273,6 +273,9 @@ public:
- OutputData m_data;
- int m_version = 1; // TODO: remove on libwayland upgrade
-
- +Q_SIGNALS:
- + void outputBound(Resource *resource);
- +
- protected:
- void output_bind_resource(Resource *resource) override;
- };
- @@ -364,6 +367,7 @@ public:
- uint sendUp(wl_client *client, int id);
- void sendMotion(wl_client *client, const QPointF &position, int id);
- void sendFrame(wl_client *client);
- + void sendCancel(wl_client *client);
-
- Seat *m_seat = nullptr;
- };
- diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp
- index a415cbf5..b1d3d07d 100644
- --- a/tests/auto/client/shared_old/mockcompositor.cpp
- +++ b/tests/auto/client/shared_old/mockcompositor.cpp
- @@ -342,7 +342,7 @@ Compositor::Compositor(MockCompositor *mockCompositor)
- exit(EXIT_FAILURE);
- }
-
- - wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
- + wl_global_create(m_display, &wl_compositor_interface, 4, this, bindCompositor);
-
- m_data_device_manager.reset(new DataDeviceManager(this, m_display));
-
- diff --git a/tests/auto/client/shared_old/mocksurface.cpp b/tests/auto/client/shared_old/mocksurface.cpp
- index e9df5f90..c3246e4a 100644
- --- a/tests/auto/client/shared_old/mocksurface.cpp
- +++ b/tests/auto/client/shared_old/mocksurface.cpp
- @@ -125,6 +125,16 @@ void Surface::surface_damage(Resource *resource,
- Q_UNUSED(height);
- }
-
- +void Surface::surface_damage_buffer(Resource *resource,
- + int32_t x, int32_t y, int32_t width, int32_t height)
- +{
- + Q_UNUSED(resource);
- + Q_UNUSED(x);
- + Q_UNUSED(y);
- + Q_UNUSED(width);
- + Q_UNUSED(height);
- +}
- +
- void Surface::surface_frame(Resource *resource,
- uint32_t callback)
- {
- diff --git a/tests/auto/client/shared_old/mocksurface.h b/tests/auto/client/shared_old/mocksurface.h
- index 949dc23d..d176837e 100644
- --- a/tests/auto/client/shared_old/mocksurface.h
- +++ b/tests/auto/client/shared_old/mocksurface.h
- @@ -65,6 +65,8 @@ protected:
- struct wl_resource *buffer, int x, int y) override;
- void surface_damage(Resource *resource,
- int32_t x, int32_t y, int32_t width, int32_t height) override;
- + void surface_damage_buffer(Resource *resource,
- + int32_t x, int32_t y, int32_t width, int32_t height) override;
- void surface_frame(Resource *resource,
- uint32_t callback) override;
- void surface_commit(Resource *resource) override;
- diff --git a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
- index 80429608..68e8d77a 100644
- --- a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
- +++ b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
- @@ -55,6 +55,7 @@ private slots:
- void primaryScreen();
- void overrideGeometry();
- void changeGeometry();
- + void outputCreateEnterRace();
- };
-
- void tst_xdgoutput::cleanup()
- @@ -134,5 +135,39 @@ void tst_xdgoutput::changeGeometry()
- exec([=] { remove(output(1)); });
- }
-
- +void tst_xdgoutput::outputCreateEnterRace()
- +{
- + m_config.autoConfigure = true;
- + m_config.autoEnter = false;
- + QRasterWindow window;
- + QSignalSpy screenChanged(&window, &QWindow::screenChanged);
- + window.resize(400, 320);
- + window.show();
- + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- + exec([=] { xdgToplevel()->surface()->sendEnter(output(0));});
- +
- + QTRY_COMPARE(QGuiApplication::screens().size(), 1);
- + QScreen *primaryScreen = QGuiApplication::screens().first();
- + QCOMPARE(window.screen(), primaryScreen);
- +
- + auto *out = exec([=] {
- + return add<Output>();
- + });
- +
- + // In Compositor Thread
- + connect(out, &Output::outputBound, this, [this](QtWaylandServer::wl_output::Resource *resource){
- + auto surface = xdgToplevel()->surface();
- + surface->sendLeave(output(0));
- + surface->QtWaylandServer::wl_surface::send_enter(surface->resource()->handle, resource->handle);
- + }, Qt::DirectConnection);
- +
- + QTRY_COMPARE(QGuiApplication::screens().size(), 2);
- + QTRY_COMPARE(window.screen(), QGuiApplication::screens()[1]);
- +
- + exec([=] { remove(out); });
- + m_config.autoConfigure = false;
- + m_config.autoEnter = true;
- +}
- +
- QCOMPOSITOR_TEST_MAIN(tst_xdgoutput)
- #include "tst_xdgoutput.moc"
- diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
- index 2277bbb8..afbeef53 100644
- --- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
- +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
- @@ -31,6 +31,7 @@
- #include <QtGui/QOpenGLWindow>
- #include <QtGui/qpa/qplatformnativeinterface.h>
- #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
- +#include <QtWaylandClient/private/qwaylandwindow_p.h>
-
- using namespace MockCompositor;
-
- @@ -45,6 +46,7 @@ private slots:
- void configureStates();
- void popup();
- void tooltipOnPopup();
- + void tooltipAndSiblingPopup();
- void switchPopups();
- void hidePopupParent();
- void pongs();
- @@ -138,6 +140,7 @@ void tst_xdgshell::configureSize()
-
- void tst_xdgshell::configureStates()
- {
- + QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0"));
- QRasterWindow window;
- window.resize(64, 48);
- window.show();
- @@ -154,9 +157,12 @@ void tst_xdgshell::configureStates()
- // Toplevel windows don't know their position on xdg-shell
- // QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
-
- -// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
- -// QVERIFY(window.isActive());
- - QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
- + // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
- + // XDGShell this is internal to QtWayland so it is queried directly
- + auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
- + Q_ASSERT(waylandWindow);
- + QTRY_VERIFY(waylandWindow->windowStates().testFlag(
- + Qt::WindowActive)); // Just make sure it eventually get's set correctly
-
- const QSize screenSize(640, 480);
- const uint maximizedSerial = exec([=] {
- @@ -186,6 +192,7 @@ void tst_xdgshell::configureStates()
- QCOMPARE(window.windowStates(), Qt::WindowNoState);
- QCOMPARE(window.frameGeometry().size(), windowedSize);
- // QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
- + QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
- }
-
- void tst_xdgshell::popup()
- @@ -340,6 +347,92 @@ void tst_xdgshell::tooltipOnPopup()
- QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
- }
-
- +void tst_xdgshell::tooltipAndSiblingPopup()
- +{
- + class ToolTip : public QRasterWindow {
- + public:
- + explicit ToolTip(QWindow *parent) {
- + setTransientParent(parent);
- + setFlags(Qt::ToolTip);
- + resize(100, 100);
- + show();
- + }
- + void mousePressEvent(QMouseEvent *event) override {
- + QRasterWindow::mousePressEvent(event);
- + m_popup = new QRasterWindow;
- + m_popup->setTransientParent(transientParent());
- + m_popup->setFlags(Qt::Popup);
- + m_popup->resize(100, 100);
- + m_popup->show();
- + }
- +
- + QRasterWindow *m_popup = nullptr;
- + };
- +
- + class Window : public QRasterWindow {
- + public:
- + void mousePressEvent(QMouseEvent *event) override {
- + QRasterWindow::mousePressEvent(event);
- + m_tooltip = new ToolTip(this);
- + }
- + ToolTip *m_tooltip = nullptr;
- + };
- +
- + Window window;
- + window.resize(200, 200);
- + window.show();
- +
- + QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- + exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- +
- + exec([=] {
- + auto *surface = xdgToplevel()->surface();
- + auto *p = pointer();
- + auto *c = client();
- + p->sendEnter(surface, {100, 100});
- + p->sendFrame(c);
- + p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
- + p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
- + p->sendFrame(c);
- + p->sendLeave(surface);
- + p->sendFrame(c);
- + });
- +
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- + exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
- + QCOMPOSITOR_TRY_VERIFY(!xdgPopup()->m_grabbed);
- +
- + exec([=] {
- + auto *surface = xdgPopup()->surface();
- + auto *p = pointer();
- + auto *c = client();
- + p->sendEnter(surface, {100, 100});
- + p->sendFrame(c);
- + p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
- + p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
- + p->sendFrame(c);
- + });
- +
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
- + exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_grabbed);
- +
- + // Close the middle tooltip (it should not close the sibling popup)
- + window.m_tooltip->close();
- +
- + QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
- + // Verify the remaining xdg surface is a grab popup..
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup(0));
- + QCOMPOSITOR_TRY_VERIFY(xdgPopup(0)->m_grabbed);
- +
- + window.m_tooltip->m_popup->close();
- + QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
- + QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
- +}
- +
- // QTBUG-65680
- void tst_xdgshell::switchPopups()
- {
- @@ -505,15 +598,17 @@ void tst_xdgshell::minMaxSize()
- window.show();
- QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
-
- - exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- + // we don't roundtrip with our configuration the initial commit should be correct
-
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
-
- window.setMaximumSize(QSize(500, 400));
- + window.update();
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(500, 400));
-
- window.setMinimumSize(QSize(50, 40));
- + window.update();
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(50, 40));
- }
-
|