qt_kde.patch 124 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233
  1. diff --git a/src/client/configure.json b/src/client/configure.json
  2. index 2f424580..29222357 100644
  3. --- a/src/client/configure.json
  4. +++ b/src/client/configure.json
  5. @@ -149,8 +149,7 @@
  6. "#endif"
  7. ]
  8. },
  9. - "libs": "-ldrm",
  10. - "use": "egl"
  11. + "use": "drm egl"
  12. },
  13. "vulkan-server-buffer": {
  14. "label": "Vulkan Buffer Sharing",
  15. @@ -168,7 +167,8 @@
  16. "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
  17. "return 0;"
  18. ]
  19. - }
  20. + },
  21. + "use": "wayland-client"
  22. },
  23. "egl_1_5-wayland": {
  24. "label": "EGL 1.5 with Wayland Platform",
  25. @@ -183,7 +183,7 @@
  26. "eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, (struct wl_display *)(nullptr), nullptr);"
  27. ]
  28. },
  29. - "use": "egl"
  30. + "use": "egl wayland-client"
  31. }
  32. },
  33. diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
  34. index 966096a8..36609c08 100644
  35. --- a/src/client/global/qwaylandclientextension.cpp
  36. +++ b/src/client/global/qwaylandclientextension.cpp
  37. @@ -74,7 +74,10 @@ void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_regis
  38. void QWaylandClientExtension::addRegistryListener()
  39. {
  40. Q_D(QWaylandClientExtension);
  41. - d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
  42. + if (!d->registered) {
  43. + d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
  44. + d->registered = true;
  45. + }
  46. }
  47. QWaylandClientExtension::QWaylandClientExtension(const int ver)
  48. @@ -88,6 +91,13 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver)
  49. QMetaObject::invokeMethod(this, "addRegistryListener", Qt::QueuedConnection);
  50. }
  51. +QWaylandClientExtension::~QWaylandClientExtension()
  52. +{
  53. + Q_D(QWaylandClientExtension);
  54. + if (d->registered && !QCoreApplication::closingDown())
  55. + d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
  56. +}
  57. +
  58. QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const
  59. {
  60. Q_D(const QWaylandClientExtension);
  61. diff --git a/src/client/global/qwaylandclientextension.h b/src/client/global/qwaylandclientextension.h
  62. index 98272e57..5bd28398 100644
  63. --- a/src/client/global/qwaylandclientextension.h
  64. +++ b/src/client/global/qwaylandclientextension.h
  65. @@ -63,6 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtension : public QObject
  66. Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
  67. public:
  68. QWaylandClientExtension(const int version);
  69. + ~QWaylandClientExtension();
  70. QtWaylandClient::QWaylandIntegration *integration() const;
  71. int version() const;
  72. diff --git a/src/client/global/qwaylandclientextension_p.h b/src/client/global/qwaylandclientextension_p.h
  73. index 69cc46a0..9091efbe 100644
  74. --- a/src/client/global/qwaylandclientextension_p.h
  75. +++ b/src/client/global/qwaylandclientextension_p.h
  76. @@ -68,6 +68,7 @@ public:
  77. QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr;
  78. int version = -1;
  79. bool active = false;
  80. + bool registered = false;
  81. };
  82. class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate
  83. diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp
  84. index b628930d..d15a7f9f 100644
  85. --- a/src/client/qwaylandabstractdecoration.cpp
  86. +++ b/src/client/qwaylandabstractdecoration.cpp
  87. @@ -122,7 +122,7 @@ const QImage &QWaylandAbstractDecoration::contentImage()
  88. if (d->m_isDirty) {
  89. // Update the decoration backingstore
  90. - const int bufferScale = waylandWindow()->scale();
  91. + const qreal bufferScale = waylandWindow()->scale();
  92. const QSize imageSize = waylandWindow()->surfaceSize() * bufferScale;
  93. d->m_decorationContentImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
  94. // Only scale by buffer scale, not QT_SCALE_FACTOR etc.
  95. diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp
  96. index 81f48e05..14561c77 100644
  97. --- a/src/client/qwaylandclipboard.cpp
  98. +++ b/src/client/qwaylandclipboard.cpp
  99. @@ -54,10 +54,15 @@ namespace QtWaylandClient {
  100. QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
  101. : mDisplay(display)
  102. {
  103. + m_clientClipboard[QClipboard::Clipboard] = nullptr;
  104. + m_clientClipboard[QClipboard::Selection] = nullptr;
  105. }
  106. QWaylandClipboard::~QWaylandClipboard()
  107. {
  108. + if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
  109. + delete m_clientClipboard[QClipboard::Clipboard];
  110. + delete m_clientClipboard[QClipboard::Selection];
  111. }
  112. QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
  113. @@ -69,8 +74,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
  114. switch (mode) {
  115. case QClipboard::Clipboard:
  116. if (auto *dataDevice = seat->dataDevice()) {
  117. - if (auto *source = dataDevice->selectionSource())
  118. - return source->mimeData();
  119. + if (dataDevice->selectionSource())
  120. + return m_clientClipboard[QClipboard::Clipboard];
  121. if (auto *offer = dataDevice->selectionOffer())
  122. return offer->mimeData();
  123. }
  124. @@ -78,8 +83,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
  125. case QClipboard::Selection:
  126. #if QT_CONFIG(wayland_client_primary_selection)
  127. if (auto *selectionDevice = seat->primarySelectionDevice()) {
  128. - if (auto *source = selectionDevice->selectionSource())
  129. - return source->mimeData();
  130. + if (selectionDevice->selectionSource())
  131. + return m_clientClipboard[QClipboard::Selection];
  132. if (auto *offer = selectionDevice->selectionOffer())
  133. return offer->mimeData();
  134. }
  135. @@ -104,17 +109,27 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
  136. if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
  137. data->setData(utf8, data->data(plain));
  138. + if (m_clientClipboard[mode]) {
  139. + if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
  140. + delete m_clientClipboard[mode];
  141. + m_clientClipboard[mode] = nullptr;
  142. + }
  143. +
  144. + m_clientClipboard[mode] = data;
  145. +
  146. switch (mode) {
  147. case QClipboard::Clipboard:
  148. if (auto *dataDevice = seat->dataDevice()) {
  149. - dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
  150. + dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
  151. + m_clientClipboard[QClipboard::Clipboard]) : nullptr);
  152. emitChanged(mode);
  153. }
  154. break;
  155. case QClipboard::Selection:
  156. #if QT_CONFIG(wayland_client_primary_selection)
  157. if (auto *selectionDevice = seat->primarySelectionDevice()) {
  158. - selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr);
  159. + selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
  160. + m_clientClipboard[QClipboard::Selection]) : nullptr);
  161. emitChanged(mode);
  162. }
  163. #endif
  164. diff --git a/src/client/qwaylandclipboard_p.h b/src/client/qwaylandclipboard_p.h
  165. index ce14e124..bb52683d 100644
  166. --- a/src/client/qwaylandclipboard_p.h
  167. +++ b/src/client/qwaylandclipboard_p.h
  168. @@ -80,6 +80,7 @@ public:
  169. private:
  170. QWaylandDisplay *mDisplay = nullptr;
  171. QMimeData m_emptyData;
  172. + QMimeData *m_clientClipboard[2];
  173. };
  174. }
  175. diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp
  176. index e4eca9d4..ba76ba2d 100644
  177. --- a/src/client/qwaylandcursor.cpp
  178. +++ b/src/client/qwaylandcursor.cpp
  179. @@ -44,6 +44,7 @@
  180. #include "qwaylandshmbackingstore_p.h"
  181. #include <QtGui/QImageReader>
  182. +#include <QBitmap>
  183. #include <QDebug>
  184. #include <wayland-cursor.h>
  185. @@ -250,7 +251,27 @@ QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
  186. QSharedPointer<QWaylandBuffer> QWaylandCursor::cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor)
  187. {
  188. Q_ASSERT(cursor->shape() == Qt::BitmapCursor);
  189. - const QImage &img = cursor->pixmap().toImage();
  190. +
  191. + const QBitmap mask = cursor->mask(Qt::ReturnByValue);
  192. + QImage img;
  193. + if (cursor->pixmap().isNull())
  194. + img = cursor->bitmap(Qt::ReturnByValue).toImage();
  195. + else
  196. + img = cursor->pixmap().toImage();
  197. +
  198. + // convert to supported format if necessary
  199. + if (!display->shm()->formatSupported(img.format())) {
  200. + if (mask.isNull()) {
  201. + img.convertTo(QImage::Format_RGB32);
  202. + } else {
  203. + // preserve mask
  204. + img.convertTo(QImage::Format_ARGB32);
  205. + QPixmap pixmap = QPixmap::fromImage(img);
  206. + pixmap.setMask(mask);
  207. + img = pixmap.toImage();
  208. + }
  209. + }
  210. +
  211. QSharedPointer<QWaylandShmBuffer> buffer(new QWaylandShmBuffer(display, img.size(), img.format()));
  212. memcpy(buffer->image()->bits(), img.bits(), size_t(img.sizeInBytes()));
  213. return buffer;
  214. diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
  215. index 1e2db786..07b18ab0 100644
  216. --- a/src/client/qwaylanddatadevice.cpp
  217. +++ b/src/client/qwaylanddatadevice.cpp
  218. @@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl
  219. QWaylandDataDevice::~QWaylandDataDevice()
  220. {
  221. + if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
  222. + release();
  223. }
  224. QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
  225. @@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
  226. return m_dragOffer.data();
  227. }
  228. -bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
  229. +bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon)
  230. {
  231. auto *seat = m_display->currentInputDevice();
  232. auto *origin = seat->pointerFocus();
  233. @@ -122,8 +124,38 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
  234. return false;
  235. }
  236. + // dragging data without mimetypes is a legal operation in Qt terms
  237. + // but Wayland uses a mimetype to determine if a drag is accepted or not
  238. + // In this rare case, insert a placeholder
  239. + if (mimeData->formats().isEmpty())
  240. + mimeData->setData(QString::fromLatin1("application/x-qt-avoid-empty-placeholder"), QByteArray("1"));
  241. +
  242. m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
  243. +
  244. + if (wl_data_device_get_version(object()) >= 3)
  245. + m_dragSource->set_actions(dropActionsToWl(supportedActions));
  246. +
  247. connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
  248. + connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
  249. + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
  250. + if (!drag->currentDrag()) {
  251. + return;
  252. + }
  253. + // in old versions drop action is not set, so we guess
  254. + if (wl_data_source_get_version(m_dragSource->object()) < 3) {
  255. + drag->setResponse(accepted);
  256. + } else {
  257. + QPlatformDropQtResponse response(accepted, action);
  258. + drag->setResponse(response);
  259. + }
  260. + });
  261. + connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
  262. + QPlatformDropQtResponse response(accepted, action);
  263. + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
  264. + });
  265. + connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
  266. + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
  267. + });
  268. start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
  269. return true;
  270. @@ -152,7 +184,7 @@ void QWaylandDataDevice::data_device_drop()
  271. supportedActions = drag->supportedActions();
  272. } else if (m_dragOffer) {
  273. dragData = m_dragOffer->mimeData();
  274. - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
  275. + supportedActions = m_dragOffer->supportedActions();
  276. } else {
  277. return;
  278. }
  279. @@ -162,7 +194,11 @@ void QWaylandDataDevice::data_device_drop()
  280. QGuiApplication::keyboardModifiers());
  281. if (drag) {
  282. - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
  283. + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
  284. + drag->setDropResponse(response);
  285. + drag->finishDrag();
  286. + } else if (m_dragOffer) {
  287. + m_dragOffer->finish();
  288. }
  289. }
  290. @@ -186,7 +222,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
  291. supportedActions = drag->supportedActions();
  292. } else if (m_dragOffer) {
  293. dragData = m_dragOffer->mimeData();
  294. - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
  295. + supportedActions = m_dragOffer->supportedActions();
  296. }
  297. const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
  298. @@ -197,11 +233,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
  299. static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
  300. }
  301. - if (response.isAccepted()) {
  302. - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
  303. - } else {
  304. - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
  305. - }
  306. + sendResponse(supportedActions, response);
  307. }
  308. void QWaylandDataDevice::data_device_leave()
  309. @@ -235,10 +267,10 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
  310. supportedActions = drag->supportedActions();
  311. } else {
  312. dragData = m_dragOffer->mimeData();
  313. - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
  314. + supportedActions = m_dragOffer->supportedActions();
  315. }
  316. - QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
  317. + const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
  318. QGuiApplication::mouseButtons(),
  319. QGuiApplication::keyboardModifiers());
  320. @@ -246,11 +278,7 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
  321. static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
  322. }
  323. - if (response.isAccepted()) {
  324. - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
  325. - } else {
  326. - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
  327. - }
  328. + sendResponse(supportedActions, response);
  329. }
  330. #endif // QT_CONFIG(draganddrop)
  331. @@ -277,14 +305,10 @@ void QWaylandDataDevice::selectionSourceCancelled()
  332. #if QT_CONFIG(draganddrop)
  333. void QWaylandDataDevice::dragSourceCancelled()
  334. {
  335. + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
  336. m_dragSource.reset();
  337. }
  338. -void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType)
  339. -{
  340. - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType);
  341. -}
  342. -
  343. QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
  344. {
  345. QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y));
  346. @@ -297,6 +321,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con
  347. }
  348. return pnt;
  349. }
  350. +
  351. +void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response)
  352. +{
  353. + if (response.isAccepted()) {
  354. + if (wl_data_device_get_version(object()) >= 3)
  355. + m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction()));
  356. +
  357. + m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat());
  358. + } else {
  359. + m_dragOffer->accept(m_enterSerial, QString());
  360. + }
  361. +}
  362. +
  363. +int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions)
  364. +{
  365. +
  366. + int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
  367. + if (actions & Qt::CopyAction)
  368. + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
  369. + if (actions & (Qt::MoveAction | Qt::TargetMoveAction))
  370. + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
  371. +
  372. + // wayland does not support LinkAction at the time of writing
  373. + return wlActions;
  374. +}
  375. +
  376. +
  377. #endif // QT_CONFIG(draganddrop)
  378. }
  379. diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h
  380. index 16c3ad28..801dcc2c 100644
  381. --- a/src/client/qwaylanddatadevice_p.h
  382. +++ b/src/client/qwaylanddatadevice_p.h
  383. @@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice);
  384. QT_BEGIN_NAMESPACE
  385. class QMimeData;
  386. +class QPlatformDragQtResponse;
  387. class QWindow;
  388. namespace QtWaylandClient {
  389. @@ -89,7 +90,7 @@ public:
  390. #if QT_CONFIG(draganddrop)
  391. QWaylandDataOffer *dragOffer() const;
  392. - bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
  393. + bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon);
  394. void cancelDrag();
  395. #endif
  396. @@ -109,13 +110,16 @@ private Q_SLOTS:
  397. #if QT_CONFIG(draganddrop)
  398. void dragSourceCancelled();
  399. - void dragSourceTargetChanged(const QString &mimeType);
  400. #endif
  401. private:
  402. #if QT_CONFIG(draganddrop)
  403. QPoint calculateDragPosition(int x, int y, QWindow *wnd) const;
  404. #endif
  405. + void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response);
  406. +
  407. + static int dropActionsToWl(Qt::DropActions dropActions);
  408. +
  409. QWaylandDisplay *m_display = nullptr;
  410. QWaylandInputDevice *m_inputDevice = nullptr;
  411. diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp
  412. index 35d67307..6dc4f77f 100644
  413. --- a/src/client/qwaylanddatadevicemanager.cpp
  414. +++ b/src/client/qwaylanddatadevicemanager.cpp
  415. @@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE
  416. namespace QtWaylandClient {
  417. -QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
  418. - : wl_data_device_manager(display->wl_registry(), id, 1)
  419. +QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id)
  420. + : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3))
  421. , m_display(display)
  422. {
  423. // Create transfer devices for all input devices.
  424. diff --git a/src/client/qwaylanddatadevicemanager_p.h b/src/client/qwaylanddatadevicemanager_p.h
  425. index bd05c0fb..510d9be4 100644
  426. --- a/src/client/qwaylanddatadevicemanager_p.h
  427. +++ b/src/client/qwaylanddatadevicemanager_p.h
  428. @@ -68,7 +68,7 @@ class QWaylandInputDevice;
  429. class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager
  430. {
  431. public:
  432. - QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id);
  433. + QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id);
  434. ~QWaylandDataDeviceManager() override;
  435. QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice);
  436. diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
  437. index 2297e8a1..fe0ea8c9 100644
  438. --- a/src/client/qwaylanddataoffer.cpp
  439. +++ b/src/client/qwaylanddataoffer.cpp
  440. @@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData()
  441. return m_mimeData.data();
  442. }
  443. +Qt::DropActions QWaylandDataOffer::supportedActions() const
  444. +{
  445. + if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) {
  446. + return Qt::MoveAction | Qt::CopyAction;
  447. + }
  448. +
  449. + return m_supportedActions;
  450. +}
  451. +
  452. void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
  453. {
  454. receive(mimeType, fd);
  455. @@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
  456. m_mimeData->appendFormat(mime_type);
  457. }
  458. +void QWaylandDataOffer::data_offer_action(uint32_t dnd_action)
  459. +{
  460. + Q_UNUSED(dnd_action);
  461. + // This is the compositor telling the drag target what action it should perform
  462. + // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
  463. +}
  464. +
  465. +void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions)
  466. +{
  467. + m_supportedActions = Qt::DropActions();
  468. + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
  469. + m_supportedActions |= Qt::MoveAction;
  470. + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
  471. + m_supportedActions |= Qt::CopyAction;
  472. +}
  473. +
  474. QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
  475. : m_dataOffer(dataOffer)
  476. {
  477. @@ -163,17 +188,18 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
  478. int QWaylandMimeData::readData(int fd, QByteArray &data) const
  479. {
  480. - fd_set readset;
  481. - FD_ZERO(&readset);
  482. - FD_SET(fd, &readset);
  483. - struct timeval timeout;
  484. + struct pollfd readset;
  485. + readset.fd = fd;
  486. + readset.events = POLLIN;
  487. + struct timespec timeout;
  488. timeout.tv_sec = 1;
  489. - timeout.tv_usec = 0;
  490. + timeout.tv_nsec = 0;
  491. +
  492. Q_FOREVER {
  493. - int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
  494. + int ready = qt_safe_poll(&readset, 1, &timeout);
  495. if (ready < 0) {
  496. - qWarning() << "QWaylandDataOffer: select() failed";
  497. + qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
  498. return -1;
  499. } else if (ready == 0) {
  500. qWarning("QWaylandDataOffer: timeout reading from pipe");
  501. diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h
  502. index 9cf1483c..6f667398 100644
  503. --- a/src/client/qwaylanddataoffer_p.h
  504. +++ b/src/client/qwaylanddataoffer_p.h
  505. @@ -82,6 +82,7 @@ public:
  506. explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
  507. ~QWaylandDataOffer() override;
  508. QMimeData *mimeData() override;
  509. + Qt::DropActions supportedActions() const;
  510. QString firstFormat() const;
  511. @@ -89,10 +90,13 @@ public:
  512. protected:
  513. void data_offer_offer(const QString &mime_type) override;
  514. + void data_offer_source_actions(uint32_t source_actions) override;
  515. + void data_offer_action(uint32_t dnd_action) override;
  516. private:
  517. QWaylandDisplay *m_display = nullptr;
  518. QScopedPointer<QWaylandMimeData> m_mimeData;
  519. + Qt::DropActions m_supportedActions;
  520. };
  521. diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
  522. index c2bc9dc4..321170a6 100644
  523. --- a/src/client/qwaylanddatasource.cpp
  524. +++ b/src/client/qwaylanddatasource.cpp
  525. @@ -72,11 +72,6 @@ QWaylandDataSource::~QWaylandDataSource()
  526. destroy();
  527. }
  528. -QMimeData * QWaylandDataSource::mimeData() const
  529. -{
  530. - return m_mime_data;
  531. -}
  532. -
  533. void QWaylandDataSource::data_source_cancelled()
  534. {
  535. Q_EMIT cancelled();
  536. @@ -110,7 +105,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
  537. void QWaylandDataSource::data_source_target(const QString &mime_type)
  538. {
  539. - Q_EMIT targetChanged(mime_type);
  540. + m_accepted = !mime_type.isEmpty();
  541. + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
  542. +}
  543. +
  544. +void QWaylandDataSource::data_source_action(uint32_t action)
  545. +{
  546. + Qt::DropAction qtAction = Qt::IgnoreAction;
  547. +
  548. + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
  549. + qtAction = Qt::MoveAction;
  550. + else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
  551. + qtAction = Qt::CopyAction;
  552. +
  553. + m_dropAction = qtAction;
  554. + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
  555. +}
  556. +
  557. +void QWaylandDataSource::data_source_dnd_finished()
  558. +{
  559. + Q_EMIT finished();
  560. +}
  561. +
  562. +void QWaylandDataSource::data_source_dnd_drop_performed()
  563. +{
  564. +
  565. + Q_EMIT dndDropped(m_accepted, m_dropAction);
  566. }
  567. }
  568. diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h
  569. index 3003da1b..089c5485 100644
  570. --- a/src/client/qwaylanddatasource_p.h
  571. +++ b/src/client/qwaylanddatasource_p.h
  572. @@ -74,19 +74,25 @@ public:
  573. QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData);
  574. ~QWaylandDataSource() override;
  575. - QMimeData *mimeData() const;
  576. -
  577. Q_SIGNALS:
  578. - void targetChanged(const QString &mime_type);
  579. void cancelled();
  580. + void finished();
  581. +
  582. + void dndResponseUpdated(bool accepted, Qt::DropAction action);
  583. + void dndDropped(bool accepted, Qt::DropAction action);
  584. protected:
  585. void data_source_cancelled() override;
  586. void data_source_send(const QString &mime_type, int32_t fd) override;
  587. void data_source_target(const QString &mime_type) override;
  588. + void data_source_dnd_drop_performed() override;
  589. + void data_source_dnd_finished() override;
  590. + void data_source_action(uint32_t action) override;
  591. private:
  592. QMimeData *m_mime_data = nullptr;
  593. + bool m_accepted = false;
  594. + Qt::DropAction m_dropAction = Qt::IgnoreAction;
  595. };
  596. }
  597. diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
  598. index 8a6d5db1..737b539d 100644
  599. --- a/src/client/qwaylanddisplay.cpp
  600. +++ b/src/client/qwaylanddisplay.cpp
  601. @@ -87,10 +87,203 @@
  602. #include <errno.h>
  603. +#include <tuple> // for std::tie
  604. +
  605. +static void checkWaylandError(struct wl_display *display)
  606. +{
  607. + int ecode = wl_display_get_error(display);
  608. + if ((ecode == EPIPE || ecode == ECONNRESET)) {
  609. + // special case this to provide a nicer error
  610. + qWarning("The Wayland connection broke. Did the Wayland compositor die?");
  611. + } else {
  612. + qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
  613. + }
  614. + _exit(1);
  615. +}
  616. +
  617. QT_BEGIN_NAMESPACE
  618. namespace QtWaylandClient {
  619. +class EventThread : public QThread
  620. +{
  621. + Q_OBJECT
  622. +public:
  623. + enum OperatingMode {
  624. + EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread.
  625. + SelfDispatch, // Dispatch the events inside this thread.
  626. + };
  627. +
  628. + EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue,
  629. + OperatingMode mode)
  630. + : m_fd(wl_display_get_fd(wl))
  631. + , m_pipefd{ -1, -1 }
  632. + , m_wldisplay(wl)
  633. + , m_wlevqueue(ev_queue)
  634. + , m_mode(mode)
  635. + , m_reading(true)
  636. + , m_quitting(false)
  637. + {
  638. + setObjectName(QStringLiteral("WaylandEventThread"));
  639. + }
  640. +
  641. + void readAndDispatchEvents()
  642. + {
  643. + /*
  644. + * Dispatch pending events and flush the requests at least once. If the event thread
  645. + * is not reading, try to call _prepare_read() to allow the event thread to poll().
  646. + * If that fails, re-try dispatch & flush again until _prepare_read() is successful.
  647. + *
  648. + * This allow any call to readAndDispatchEvents() to start event thread's polling,
  649. + * not only the one issued from event thread's waitForReading(), which means functions
  650. + * called from dispatch_pending() can safely spin an event loop.
  651. + */
  652. + for (;;) {
  653. + if (dispatchQueuePending() < 0) {
  654. + checkWaylandError(m_wldisplay);
  655. + return;
  656. + }
  657. +
  658. + wl_display_flush(m_wldisplay);
  659. +
  660. + // We have to check if event thread is reading every time we dispatch
  661. + // something, as that may recursively call this function.
  662. + if (m_reading.loadAcquire())
  663. + break;
  664. +
  665. + if (prepareReadQueue() == 0) {
  666. + QMutexLocker l(&m_mutex);
  667. + m_reading.storeRelease(true);
  668. + m_cond.wakeOne();
  669. + break;
  670. + }
  671. + }
  672. + }
  673. +
  674. + void stop()
  675. + {
  676. + // We have to both write to the pipe and set the flag, as the thread may be
  677. + // either in the poll() or waiting for _prepare_read().
  678. + if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1)
  679. + qWarning("Failed to write to the pipe: %s.", strerror(errno));
  680. +
  681. + {
  682. + QMutexLocker l(&m_mutex);
  683. + m_quitting = true;
  684. + m_cond.wakeOne();
  685. + }
  686. +
  687. + wait();
  688. + }
  689. +
  690. +Q_SIGNALS:
  691. + void needReadAndDispatch();
  692. +
  693. +protected:
  694. + void run() override
  695. + {
  696. + // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets
  697. + // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore.
  698. + struct Pipe
  699. + {
  700. + Pipe(int *fds)
  701. + : fds(fds)
  702. + {
  703. + if (qt_safe_pipe(fds) != 0)
  704. + qWarning("Pipe creation failed. Quitting may hang.");
  705. + }
  706. + ~Pipe()
  707. + {
  708. + if (fds[0] != -1) {
  709. + close(fds[0]);
  710. + close(fds[1]);
  711. + }
  712. + }
  713. +
  714. + int *fds;
  715. + } pipe(m_pipefd);
  716. +
  717. + // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the
  718. + // outbound ones. Wait until it's done before proceeding, unless we're told to quit.
  719. + while (waitForReading()) {
  720. + pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } };
  721. + poll(fds, 2, -1);
  722. +
  723. + if (fds[1].revents & POLLIN) {
  724. + // we don't really care to read the byte that was written here since we're closing down
  725. + wl_display_cancel_read(m_wldisplay);
  726. + break;
  727. + }
  728. +
  729. + if (fds[0].revents & POLLIN)
  730. + wl_display_read_events(m_wldisplay);
  731. + // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop
  732. + // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which
  733. + // case we don't care anymore about them.
  734. + else
  735. + wl_display_cancel_read(m_wldisplay);
  736. + }
  737. + }
  738. +
  739. +private:
  740. + bool waitForReading()
  741. + {
  742. + Q_ASSERT(QThread::currentThread() == this);
  743. +
  744. + m_reading.storeRelease(false);
  745. +
  746. + if (m_mode == SelfDispatch) {
  747. + readAndDispatchEvents();
  748. + } else {
  749. + Q_EMIT needReadAndDispatch();
  750. +
  751. + QMutexLocker lock(&m_mutex);
  752. + // m_reading might be set from our emit or some other invocation of
  753. + // readAndDispatchEvents().
  754. + while (!m_reading.loadRelaxed() && !m_quitting)
  755. + m_cond.wait(&m_mutex);
  756. + }
  757. +
  758. + return !m_quitting;
  759. + }
  760. +
  761. + int dispatchQueuePending()
  762. + {
  763. + if (m_wlevqueue)
  764. + return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue);
  765. + else
  766. + return wl_display_dispatch_pending(m_wldisplay);
  767. + }
  768. +
  769. + int prepareReadQueue()
  770. + {
  771. + if (m_wlevqueue)
  772. + return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue);
  773. + else
  774. + return wl_display_prepare_read(m_wldisplay);
  775. + }
  776. +
  777. + int m_fd;
  778. + int m_pipefd[2];
  779. + wl_display *m_wldisplay;
  780. + wl_event_queue *m_wlevqueue;
  781. + OperatingMode m_mode;
  782. +
  783. + /* Concurrency note when operating in EmitToDispatch mode:
  784. + * m_reading is set to false inside event thread's waitForReading(), and is
  785. + * set to true inside main thread's readAndDispatchEvents().
  786. + * The lock is not taken when setting m_reading to false, as the main thread
  787. + * is not actively waiting for it to turn false. However, the lock is taken
  788. + * inside readAndDispatchEvents() before setting m_reading to true,
  789. + * as the event thread is actively waiting for it under the wait condition.
  790. + */
  791. +
  792. + QAtomicInteger<bool> m_reading;
  793. + bool m_quitting;
  794. + QMutex m_mutex;
  795. + QWaitCondition m_cond;
  796. +};
  797. +
  798. Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging
  799. struct wl_surface *QWaylandDisplay::createSurface(void *handle)
  800. @@ -160,17 +353,16 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
  801. if (!mXkbContext)
  802. qCWarning(lcQpaWayland, "failed to create xkb context");
  803. #endif
  804. -
  805. - forceRoundTrip();
  806. -
  807. - if (!mWaitingScreens.isEmpty()) {
  808. - // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
  809. - forceRoundTrip();
  810. - }
  811. }
  812. QWaylandDisplay::~QWaylandDisplay(void)
  813. {
  814. + if (m_eventThread)
  815. + m_eventThread->stop();
  816. +
  817. + if (m_frameEventQueueThread)
  818. + m_frameEventQueueThread->stop();
  819. +
  820. if (mSyncCallback)
  821. wl_callback_destroy(mSyncCallback);
  822. @@ -187,10 +379,26 @@ QWaylandDisplay::~QWaylandDisplay(void)
  823. #if QT_CONFIG(cursor)
  824. qDeleteAll(mCursorThemes);
  825. #endif
  826. +
  827. + if (m_frameEventQueue)
  828. + wl_event_queue_destroy(m_frameEventQueue);
  829. +
  830. if (mDisplay)
  831. wl_display_disconnect(mDisplay);
  832. }
  833. +// Steps which is called just after constructor. This separates registry_global() out of the constructor
  834. +// so that factory functions in integration can be overridden.
  835. +void QWaylandDisplay::initialize()
  836. +{
  837. + forceRoundTrip();
  838. +
  839. + if (!mWaitingScreens.isEmpty()) {
  840. + // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
  841. + forceRoundTrip();
  842. + }
  843. +}
  844. +
  845. void QWaylandDisplay::ensureScreen()
  846. {
  847. if (!mScreens.empty() || mPlaceholderScreen)
  848. @@ -205,98 +413,37 @@ void QWaylandDisplay::ensureScreen()
  849. void QWaylandDisplay::checkError() const
  850. {
  851. - int ecode = wl_display_get_error(mDisplay);
  852. - if ((ecode == EPIPE || ecode == ECONNRESET)) {
  853. - // special case this to provide a nicer error
  854. - qWarning("The Wayland connection broke. Did the Wayland compositor die?");
  855. - } else {
  856. - qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
  857. - }
  858. - _exit(1);
  859. + checkWaylandError(mDisplay);
  860. }
  861. +// Called in main thread, either from queued signal or directly.
  862. void QWaylandDisplay::flushRequests()
  863. {
  864. - if (wl_display_prepare_read(mDisplay) == 0) {
  865. - wl_display_read_events(mDisplay);
  866. - }
  867. -
  868. - if (wl_display_dispatch_pending(mDisplay) < 0)
  869. - checkError();
  870. -
  871. - {
  872. - QReadLocker locker(&m_frameQueueLock);
  873. - for (const FrameQueue &q : mExternalQueues) {
  874. - QMutexLocker locker(q.mutex);
  875. - while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
  876. - wl_display_dispatch_queue_pending(mDisplay, q.queue);
  877. - wl_display_read_events(mDisplay);
  878. - wl_display_dispatch_queue_pending(mDisplay, q.queue);
  879. - }
  880. - }
  881. -
  882. - wl_display_flush(mDisplay);
  883. -}
  884. -
  885. -void QWaylandDisplay::blockingReadEvents()
  886. -{
  887. - if (wl_display_dispatch(mDisplay) < 0)
  888. - checkError();
  889. -}
  890. -
  891. -void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
  892. -{
  893. - QWriteLocker locker(&m_frameQueueLock);
  894. - auto it = std::find_if(mExternalQueues.begin(),
  895. - mExternalQueues.end(),
  896. - [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
  897. - Q_ASSERT(it != mExternalQueues.end());
  898. - mExternalQueues.erase(it);
  899. - if (q.queue != nullptr)
  900. - wl_event_queue_destroy(q.queue);
  901. - delete q.mutex;
  902. + m_eventThread->readAndDispatchEvents();
  903. }
  904. -QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
  905. +// We have to wait until we have an eventDispatcher before creating the eventThread,
  906. +// otherwise forceRoundTrip() may block inside _events_read() because eventThread is
  907. +// polling.
  908. +void QWaylandDisplay::initEventThread()
  909. {
  910. - QWriteLocker locker(&m_frameQueueLock);
  911. - FrameQueue q{createEventQueue()};
  912. - mExternalQueues.append(q);
  913. - return q;
  914. -}
  915. + m_eventThread.reset(
  916. + new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch));
  917. + connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this,
  918. + &QWaylandDisplay::flushRequests, Qt::QueuedConnection);
  919. + m_eventThread->start();
  920. -wl_event_queue *QWaylandDisplay::createEventQueue()
  921. -{
  922. - return wl_display_create_queue(mDisplay);
  923. + // wl_display_disconnect() free this.
  924. + m_frameEventQueue = wl_display_create_queue(mDisplay);
  925. + m_frameEventQueueThread.reset(
  926. + new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch));
  927. + m_frameEventQueueThread->start();
  928. }
  929. -void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
  930. +void QWaylandDisplay::blockingReadEvents()
  931. {
  932. - if (!condition())
  933. - return;
  934. -
  935. - QElapsedTimer timer;
  936. - timer.start();
  937. - struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
  938. - while (timeout == -1 || timer.elapsed() < timeout) {
  939. - while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
  940. - wl_display_dispatch_queue_pending(mDisplay, queue);
  941. -
  942. - wl_display_flush(mDisplay);
  943. -
  944. - const int remaining = qMax(timeout - timer.elapsed(), 0ll);
  945. - const int pollTimeout = timeout == -1 ? -1 : remaining;
  946. - if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
  947. - wl_display_read_events(mDisplay);
  948. - else
  949. - wl_display_cancel_read(mDisplay);
  950. -
  951. - if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0)
  952. - checkError();
  953. -
  954. - if (!condition())
  955. - break;
  956. - }
  957. + if (wl_display_dispatch(mDisplay) < 0)
  958. + checkWaylandError(mDisplay);
  959. }
  960. QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
  961. @@ -347,7 +494,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
  962. if (interface == QStringLiteral("wl_output")) {
  963. mWaitingScreens << new QWaylandScreen(this, version, id);
  964. } else if (interface == QStringLiteral("wl_compositor")) {
  965. - mCompositorVersion = qMin((int)version, 3);
  966. + mCompositorVersion = qMin((int)version, 4);
  967. mCompositor.init(registry, id, mCompositorVersion);
  968. } else if (interface == QStringLiteral("wl_shm")) {
  969. mShm.reset(new QWaylandShm(this, version, id));
  970. @@ -356,7 +503,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
  971. mInputDevices.append(inputDevice);
  972. #if QT_CONFIG(wayland_datadevice)
  973. } else if (interface == QStringLiteral("wl_data_device_manager")) {
  974. - mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
  975. + mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
  976. #endif
  977. } else if (interface == QStringLiteral("qt_surface_extension")) {
  978. mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
  979. @@ -373,6 +520,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
  980. #if QT_CONFIG(wayland_client_primary_selection)
  981. } else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
  982. mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
  983. + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
  984. + inputDevice->setPrimarySelectionDevice(mPrimarySelectionManager->createDevice(inputDevice));
  985. #endif
  986. } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
  987. mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
  988. @@ -431,6 +580,13 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
  989. inputDevice->setTextInput(nullptr);
  990. mWaylandIntegration->reconfigureInputContext();
  991. }
  992. +#if QT_CONFIG(wayland_client_primary_selection)
  993. + if (global.interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
  994. + mPrimarySelectionManager.reset();
  995. + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
  996. + inputDevice->setPrimarySelectionDevice(nullptr);
  997. + }
  998. +#endif
  999. mGlobals.removeAt(i);
  1000. break;
  1001. }
  1002. @@ -456,9 +612,10 @@ void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
  1003. void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
  1004. {
  1005. - std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
  1006. + auto iter = std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
  1007. return (l.listener == listener && l.data == data);
  1008. });
  1009. + mRegistryListeners.erase(iter, mRegistryListeners.end());
  1010. }
  1011. uint32_t QWaylandDisplay::currentTimeMillisec()
  1012. @@ -471,50 +628,9 @@ uint32_t QWaylandDisplay::currentTimeMillisec()
  1013. return 0;
  1014. }
  1015. -static void
  1016. -sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
  1017. -{
  1018. - Q_UNUSED(serial)
  1019. - bool *done = static_cast<bool *>(data);
  1020. -
  1021. - *done = true;
  1022. -
  1023. - // If the wl_callback done event is received after the condition check in the while loop in
  1024. - // forceRoundTrip(), but before the call to processEvents, the call to processEvents may block
  1025. - // forever if no more events are posted (eventhough the callback is handled in response to the
  1026. - // aboutToBlock signal). Hence, we wake up the event dispatcher so forceRoundTrip may return.
  1027. - // (QTBUG-64696)
  1028. - if (auto *dispatcher = QThread::currentThread()->eventDispatcher())
  1029. - dispatcher->wakeUp();
  1030. -
  1031. - wl_callback_destroy(callback);
  1032. -}
  1033. -
  1034. -static const struct wl_callback_listener sync_listener = {
  1035. - sync_callback
  1036. -};
  1037. -
  1038. void QWaylandDisplay::forceRoundTrip()
  1039. {
  1040. - // wl_display_roundtrip() works on the main queue only,
  1041. - // but we use a separate one, so basically reimplement it here
  1042. - int ret = 0;
  1043. - bool done = false;
  1044. - wl_callback *callback = wl_display_sync(mDisplay);
  1045. - wl_callback_add_listener(callback, &sync_listener, &done);
  1046. - flushRequests();
  1047. - if (QThread::currentThread()->eventDispatcher()) {
  1048. - while (!done && ret >= 0) {
  1049. - QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::WaitForMoreEvents);
  1050. - ret = wl_display_dispatch_pending(mDisplay);
  1051. - }
  1052. - } else {
  1053. - while (!done && ret >= 0)
  1054. - ret = wl_display_dispatch(mDisplay);
  1055. - }
  1056. -
  1057. - if (ret == -1 && !done)
  1058. - wl_callback_destroy(callback);
  1059. + wl_display_roundtrip(mDisplay);
  1060. }
  1061. bool QWaylandDisplay::supportsWindowDecoration() const
  1062. @@ -578,14 +694,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
  1063. if (mLastKeyboardFocus == keyboardFocus)
  1064. return;
  1065. - if (mWaylandIntegration->mShellIntegration) {
  1066. - mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
  1067. - } else {
  1068. - if (keyboardFocus)
  1069. - handleWindowActivated(keyboardFocus);
  1070. - if (mLastKeyboardFocus)
  1071. - handleWindowDeactivated(mLastKeyboardFocus);
  1072. - }
  1073. + if (keyboardFocus)
  1074. + handleWindowActivated(keyboardFocus);
  1075. + if (mLastKeyboardFocus)
  1076. + handleWindowDeactivated(mLastKeyboardFocus);
  1077. mLastKeyboardFocus = keyboardFocus;
  1078. }
  1079. @@ -604,6 +716,19 @@ void QWaylandDisplay::handleWaylandSync()
  1080. QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
  1081. if (activeWindow != QGuiApplication::focusWindow())
  1082. QWindowSystemInterface::handleWindowActivated(activeWindow);
  1083. +
  1084. + if (!activeWindow) {
  1085. + if (lastInputDevice()) {
  1086. +#if QT_CONFIG(clipboard)
  1087. + if (auto *dataDevice = lastInputDevice()->dataDevice())
  1088. + dataDevice->invalidateSelectionOffer();
  1089. +#endif
  1090. +#if QT_CONFIG(wayland_client_primary_selection)
  1091. + if (auto *device = lastInputDevice()->primarySelectionDevice())
  1092. + device->invalidateSelectionOffer();
  1093. +#endif
  1094. + }
  1095. + }
  1096. }
  1097. const wl_callback_listener QWaylandDisplay::syncCallbackListener = {
  1098. @@ -630,6 +755,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
  1099. return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
  1100. }
  1101. +bool QWaylandDisplay::isKeyboardAvailable() const
  1102. +{
  1103. + return std::any_of(
  1104. + mInputDevices.constBegin(), mInputDevices.constEnd(),
  1105. + [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
  1106. +}
  1107. +
  1108. #if QT_CONFIG(cursor)
  1109. QWaylandCursor *QWaylandDisplay::waylandCursor()
  1110. @@ -656,6 +788,8 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
  1111. } // namespace QtWaylandClient
  1112. +#include "qwaylanddisplay.moc"
  1113. +
  1114. QT_END_NAMESPACE
  1115. #include "moc_qwaylanddisplay_p.cpp"
  1116. diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
  1117. index 1bad8b67..cf91b924 100644
  1118. --- a/src/client/qwaylanddisplay_p.h
  1119. +++ b/src/client/qwaylanddisplay_p.h
  1120. @@ -111,6 +111,7 @@ class QWaylandSurface;
  1121. class QWaylandShellIntegration;
  1122. class QWaylandCursor;
  1123. class QWaylandCursorTheme;
  1124. +class EventThread;
  1125. typedef void (*RegistryListener)(void *data,
  1126. struct wl_registry *registry,
  1127. @@ -122,15 +123,11 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland
  1128. Q_OBJECT
  1129. public:
  1130. - struct FrameQueue {
  1131. - FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {}
  1132. - wl_event_queue *queue;
  1133. - QMutex *mutex;
  1134. - };
  1135. -
  1136. QWaylandDisplay(QWaylandIntegration *waylandIntegration);
  1137. ~QWaylandDisplay(void) override;
  1138. + void initialize();
  1139. +
  1140. #if QT_CONFIG(xkbcommon)
  1141. struct xkb_context *xkbContext() const { return mXkbContext.get(); }
  1142. #endif
  1143. @@ -214,11 +211,11 @@ public:
  1144. void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
  1145. void handleWindowDestroyed(QWaylandWindow *window);
  1146. - wl_event_queue *createEventQueue();
  1147. - FrameQueue createFrameQueue();
  1148. - void destroyFrameQueue(const FrameQueue &q);
  1149. - void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
  1150. + wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
  1151. +
  1152. + bool isKeyboardAvailable() const;
  1153. + void initEventThread();
  1154. public slots:
  1155. void blockingReadEvents();
  1156. void flushRequests();
  1157. @@ -241,6 +238,9 @@ private:
  1158. };
  1159. struct wl_display *mDisplay = nullptr;
  1160. + QScopedPointer<EventThread> m_eventThread;
  1161. + wl_event_queue *m_frameEventQueue = nullptr;
  1162. + QScopedPointer<EventThread> m_frameEventQueueThread;
  1163. QtWayland::wl_compositor mCompositor;
  1164. QScopedPointer<QWaylandShm> mShm;
  1165. QList<QWaylandScreen *> mWaitingScreens;
  1166. @@ -279,11 +279,9 @@ private:
  1167. QWaylandInputDevice *mLastInputDevice = nullptr;
  1168. QPointer<QWaylandWindow> mLastInputWindow;
  1169. QPointer<QWaylandWindow> mLastKeyboardFocus;
  1170. - QVector<QWaylandWindow *> mActiveWindows;
  1171. - QVector<FrameQueue> mExternalQueues;
  1172. + QList<QWaylandWindow *> mActiveWindows;
  1173. struct wl_callback *mSyncCallback = nullptr;
  1174. static const wl_callback_listener syncCallbackListener;
  1175. - QReadWriteLock m_frameQueueLock;
  1176. bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
  1177. diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
  1178. index 6535aa16..7c53f5fa 100644
  1179. --- a/src/client/qwaylanddnd.cpp
  1180. +++ b/src/client/qwaylanddnd.cpp
  1181. @@ -66,7 +66,7 @@ void QWaylandDrag::startDrag()
  1182. {
  1183. QBasicDrag::startDrag();
  1184. QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
  1185. - if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
  1186. + if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) {
  1187. icon->addAttachOffset(-drag()->hotSpot());
  1188. } else {
  1189. // Cancelling immediately does not work, since the event loop for QDrag::exec is started
  1190. @@ -80,6 +80,9 @@ void QWaylandDrag::cancel()
  1191. QBasicDrag::cancel();
  1192. m_display->currentInputDevice()->dataDevice()->cancelDrag();
  1193. +
  1194. + if (drag())
  1195. + drag()->deleteLater();
  1196. }
  1197. void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
  1198. @@ -103,33 +106,41 @@ void QWaylandDrag::endDrag()
  1199. m_display->currentInputDevice()->handleEndDrag();
  1200. }
  1201. -void QWaylandDrag::updateTarget(const QString &mimeType)
  1202. +void QWaylandDrag::setResponse(bool accepted)
  1203. {
  1204. - setCanDrop(!mimeType.isEmpty());
  1205. -
  1206. - if (canDrop()) {
  1207. - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
  1208. - } else {
  1209. - updateCursor(Qt::IgnoreAction);
  1210. - }
  1211. + // This method is used for old DataDevices where the drag action is not communicated
  1212. + Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers());
  1213. + setResponse(QPlatformDropQtResponse(accepted, action));
  1214. }
  1215. -void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response)
  1216. +void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response)
  1217. {
  1218. setCanDrop(response.isAccepted());
  1219. if (canDrop()) {
  1220. - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
  1221. + updateCursor(response.acceptedAction());
  1222. } else {
  1223. updateCursor(Qt::IgnoreAction);
  1224. }
  1225. }
  1226. -void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response)
  1227. +void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response)
  1228. {
  1229. setExecutedDropAction(response.acceptedAction());
  1230. +}
  1231. +
  1232. +void QWaylandDrag::finishDrag()
  1233. +{
  1234. QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
  1235. eventFilter(shapedPixmapWindow(), &event);
  1236. +
  1237. + if (drag())
  1238. + drag()->deleteLater();
  1239. +}
  1240. +
  1241. +bool QWaylandDrag::ownsDragObject() const
  1242. +{
  1243. + return true;
  1244. }
  1245. }
  1246. diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
  1247. index 474fe2ab..46f629ac 100644
  1248. --- a/src/client/qwaylanddnd_p.h
  1249. +++ b/src/client/qwaylanddnd_p.h
  1250. @@ -71,9 +71,10 @@ public:
  1251. QWaylandDrag(QWaylandDisplay *display);
  1252. ~QWaylandDrag() override;
  1253. - void updateTarget(const QString &mimeType);
  1254. - void setResponse(const QPlatformDragQtResponse &response);
  1255. - void finishDrag(const QPlatformDropQtResponse &response);
  1256. + void setResponse(bool accepted);
  1257. + void setResponse(const QPlatformDropQtResponse &response);
  1258. + void setDropResponse(const QPlatformDropQtResponse &response);
  1259. + void finishDrag();
  1260. protected:
  1261. void startDrag() override;
  1262. @@ -82,6 +83,7 @@ protected:
  1263. void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
  1264. void endDrag() override;
  1265. + bool ownsDragObject() const override;
  1266. private:
  1267. QWaylandDisplay *m_display = nullptr;
  1268. diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp
  1269. index 47696a6a..9435e961 100644
  1270. --- a/src/client/qwaylandinputcontext.cpp
  1271. +++ b/src/client/qwaylandinputcontext.cpp
  1272. @@ -93,9 +93,14 @@ void QWaylandTextInput::reset()
  1273. void QWaylandTextInput::commit()
  1274. {
  1275. if (QObject *o = QGuiApplication::focusObject()) {
  1276. - QInputMethodEvent event;
  1277. - event.setCommitString(m_preeditCommit);
  1278. - QCoreApplication::sendEvent(o, &event);
  1279. + if (!m_preeditCommit.isEmpty()) {
  1280. +
  1281. + QInputMethodEvent event;
  1282. + event.setCommitString(m_preeditCommit);
  1283. + m_preeditCommit = QString();
  1284. +
  1285. + QCoreApplication::sendEvent(o, &event);
  1286. + }
  1287. }
  1288. reset();
  1289. diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
  1290. index b0e9692b..ab978d3f 100644
  1291. --- a/src/client/qwaylandinputdevice.cpp
  1292. +++ b/src/client/qwaylandinputdevice.cpp
  1293. @@ -310,8 +310,7 @@ void QWaylandInputDevice::Pointer::updateCursor()
  1294. auto shape = seat()->mCursor.shape;
  1295. if (shape == Qt::BlankCursor) {
  1296. - if (mCursor.surface)
  1297. - mCursor.surface->hide();
  1298. + getOrCreateCursorSurface()->hide();
  1299. return;
  1300. }
  1301. @@ -846,7 +845,7 @@ void QWaylandInputDevice::Pointer::releaseButtons()
  1302. mButtons = Qt::NoButton;
  1303. if (auto *window = focusWindow()) {
  1304. - MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
  1305. + ReleaseEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, Qt::NoButton, mParent->modifiers());
  1306. window->handleMouse(mParent, e);
  1307. }
  1308. }
  1309. @@ -1304,14 +1303,6 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
  1310. void QWaylandInputDevice::Keyboard::handleFocusLost()
  1311. {
  1312. mFocus = nullptr;
  1313. -#if QT_CONFIG(clipboard)
  1314. - if (auto *dataDevice = mParent->dataDevice())
  1315. - dataDevice->invalidateSelectionOffer();
  1316. -#endif
  1317. -#if QT_CONFIG(wayland_client_primary_selection)
  1318. - if (auto *device = mParent->primarySelectionDevice())
  1319. - device->invalidateSelectionOffer();
  1320. -#endif
  1321. mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
  1322. mRepeatTimer.stop();
  1323. }
  1324. @@ -1400,6 +1391,7 @@ void QWaylandInputDevice::Touch::touch_cancel()
  1325. if (touchExt)
  1326. touchExt->touchCanceled();
  1327. + mFocus = nullptr;
  1328. QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice);
  1329. }
  1330. diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
  1331. index d257e2e3..54861600 100644
  1332. --- a/src/client/qwaylandintegration.cpp
  1333. +++ b/src/client/qwaylandintegration.cpp
  1334. @@ -125,6 +125,9 @@ QWaylandIntegration::QWaylandIntegration()
  1335. #endif
  1336. reconfigureInputContext();
  1337. +
  1338. + QWaylandWindow::fixedToplevelPositions =
  1339. + !qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
  1340. }
  1341. QWaylandIntegration::~QWaylandIntegration()
  1342. @@ -192,14 +195,18 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
  1343. void QWaylandIntegration::initialize()
  1344. {
  1345. + mDisplay->initEventThread();
  1346. +
  1347. + // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
  1348. + mDisplay->initialize();
  1349. +
  1350. + // But the aboutToBlock() and awake() should be connected after initializePlatform().
  1351. + // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait,
  1352. + // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip().
  1353. QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
  1354. QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
  1355. QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
  1356. - int fd = wl_display_get_fd(mDisplay->wl_display());
  1357. - QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
  1358. - QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
  1359. -
  1360. // Qt does not support running with no screens
  1361. mDisplay->ensureScreen();
  1362. }
  1363. @@ -262,6 +269,14 @@ QWaylandDisplay *QWaylandIntegration::display() const
  1364. return mDisplay.data();
  1365. }
  1366. +Qt::KeyboardModifiers QWaylandIntegration::queryKeyboardModifiers() const
  1367. +{
  1368. + if (auto *seat = mDisplay->currentInputDevice()) {
  1369. + return seat->modifiers();
  1370. + }
  1371. + return Qt::NoModifier;
  1372. +}
  1373. +
  1374. QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const
  1375. {
  1376. if (auto *seat = mDisplay->currentInputDevice())
  1377. diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h
  1378. index ff70ae25..73b80658 100644
  1379. --- a/src/client/qwaylandintegration_p.h
  1380. +++ b/src/client/qwaylandintegration_p.h
  1381. @@ -107,6 +107,8 @@ public:
  1382. QWaylandDisplay *display() const;
  1383. + Qt::KeyboardModifiers queryKeyboardModifiers() const override;
  1384. +
  1385. QList<int> possibleKeys(const QKeyEvent *event) const override;
  1386. QStringList themeNames() const override;
  1387. diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp
  1388. index bf54a1a0..9763c312 100644
  1389. --- a/src/client/qwaylandnativeinterface.cpp
  1390. +++ b/src/client/qwaylandnativeinterface.cpp
  1391. @@ -139,7 +139,7 @@ void *QWaylandNativeInterface::nativeResourceForScreen(const QByteArray &resourc
  1392. {
  1393. QByteArray lowerCaseResource = resourceString.toLower();
  1394. - if (lowerCaseResource == "output")
  1395. + if (lowerCaseResource == "output" && !screen->handle()->isPlaceholder())
  1396. return ((QWaylandScreen *) screen->handle())->output();
  1397. return nullptr;
  1398. diff --git a/src/client/qwaylandprimaryselectionv1.cpp b/src/client/qwaylandprimaryselectionv1.cpp
  1399. index 7805dd73..dac532b2 100644
  1400. --- a/src/client/qwaylandprimaryselectionv1.cpp
  1401. +++ b/src/client/qwaylandprimaryselectionv1.cpp
  1402. @@ -54,11 +54,6 @@ QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1
  1403. : zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
  1404. , m_display(display)
  1405. {
  1406. - // Create devices for all seats.
  1407. - // This only works if we get the global before all devices
  1408. - const auto seats = m_display->inputDevices();
  1409. - for (auto *seat : seats)
  1410. - seat->setPrimarySelectionDevice(createDevice(seat));
  1411. }
  1412. QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
  1413. diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
  1414. index 6cb337de..5537dafd 100644
  1415. --- a/src/client/qwaylandscreen.cpp
  1416. +++ b/src/client/qwaylandscreen.cpp
  1417. @@ -60,7 +60,7 @@ QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandDisplay* display,
  1418. }
  1419. QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id)
  1420. - : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 2))
  1421. + : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 3))
  1422. , m_outputId(id)
  1423. , mWaylandDisplay(waylandDisplay)
  1424. , mOutputName(QStringLiteral("Screen%1").arg(id))
  1425. @@ -72,7 +72,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
  1426. qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor,"
  1427. << "QScreen may not work correctly";
  1428. mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc.
  1429. - mOutputDone = true; // Fake the done event
  1430. + mProcessedEvents |= OutputDoneEvent; // Fake the done event
  1431. maybeInitialize();
  1432. }
  1433. }
  1434. @@ -81,16 +81,29 @@ QWaylandScreen::~QWaylandScreen()
  1435. {
  1436. if (zxdg_output_v1::isInitialized())
  1437. zxdg_output_v1::destroy();
  1438. + if (wl_output::isInitialized() && wl_output_get_version(wl_output::object()) >= WL_OUTPUT_RELEASE_SINCE_VERSION)
  1439. + wl_output::release();
  1440. +}
  1441. +
  1442. +uint QWaylandScreen::requiredEvents() const
  1443. +{
  1444. + uint ret = OutputDoneEvent;
  1445. +
  1446. + if (mWaylandDisplay->xdgOutputManager()) {
  1447. + ret |= XdgOutputNameEvent;
  1448. +
  1449. + if (mWaylandDisplay->xdgOutputManager()->version() < 3)
  1450. + ret |= XdgOutputDoneEvent;
  1451. + }
  1452. + return ret;
  1453. }
  1454. void QWaylandScreen::maybeInitialize()
  1455. {
  1456. Q_ASSERT(!mInitialized);
  1457. - if (!mOutputDone)
  1458. - return;
  1459. -
  1460. - if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone)
  1461. + const uint requiredEvents = this->requiredEvents();
  1462. + if ((mProcessedEvents & requiredEvents) != requiredEvents)
  1463. return;
  1464. mInitialized = true;
  1465. @@ -276,9 +289,8 @@ void QWaylandScreen::output_scale(int32_t factor)
  1466. void QWaylandScreen::output_done()
  1467. {
  1468. - mOutputDone = true;
  1469. - if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3)
  1470. - mXdgOutputDone = true;
  1471. + mProcessedEvents |= OutputDoneEvent;
  1472. +
  1473. if (mInitialized) {
  1474. updateOutputProperties();
  1475. if (zxdg_output_v1::isInitialized())
  1476. @@ -339,7 +351,7 @@ void QWaylandScreen::zxdg_output_v1_done()
  1477. if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3))
  1478. qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor";
  1479. - mXdgOutputDone = true;
  1480. + mProcessedEvents |= XdgOutputDoneEvent;
  1481. if (mInitialized)
  1482. updateXdgOutputProperties();
  1483. else
  1484. @@ -348,7 +360,11 @@ void QWaylandScreen::zxdg_output_v1_done()
  1485. void QWaylandScreen::zxdg_output_v1_name(const QString &name)
  1486. {
  1487. + if (Q_UNLIKELY(mInitialized))
  1488. + qWarning(lcQpaWayland) << "zxdg_output_v1.name received after output has been initialized, this is most likely a bug in the compositor";
  1489. +
  1490. mOutputName = name;
  1491. + mProcessedEvents |= XdgOutputNameEvent;
  1492. }
  1493. void QWaylandScreen::updateXdgOutputProperties()
  1494. diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
  1495. index df1c94f2..050cfdc0 100644
  1496. --- a/src/client/qwaylandscreen_p.h
  1497. +++ b/src/client/qwaylandscreen_p.h
  1498. @@ -116,6 +116,13 @@ public:
  1499. static QWaylandScreen *fromWlOutput(::wl_output *output);
  1500. private:
  1501. + enum Event : uint {
  1502. + XdgOutputDoneEvent = 0x1,
  1503. + OutputDoneEvent = 0x2,
  1504. + XdgOutputNameEvent = 0x4,
  1505. + };
  1506. + uint requiredEvents() const;
  1507. +
  1508. void output_mode(uint32_t flags, int width, int height, int refresh) override;
  1509. void output_geometry(int32_t x, int32_t y,
  1510. int32_t width, int32_t height,
  1511. @@ -148,8 +155,7 @@ private:
  1512. QSize mPhysicalSize;
  1513. QString mOutputName;
  1514. Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
  1515. - bool mOutputDone = false;
  1516. - bool mXdgOutputDone = false;
  1517. + uint mProcessedEvents = 0;
  1518. bool mInitialized = false;
  1519. #if QT_CONFIG(cursor)
  1520. diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
  1521. index dc7ff670..145f933b 100644
  1522. --- a/src/client/qwaylandshmbackingstore.cpp
  1523. +++ b/src/client/qwaylandshmbackingstore.cpp
  1524. @@ -52,6 +52,7 @@
  1525. #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
  1526. +#include <fcntl.h>
  1527. #include <unistd.h>
  1528. #include <sys/mman.h>
  1529. @@ -61,6 +62,9 @@
  1530. # ifndef MFD_CLOEXEC
  1531. # define MFD_CLOEXEC 0x0001U
  1532. # endif
  1533. +# ifndef MFD_ALLOW_SEALING
  1534. +# define MFD_ALLOW_SEALING 0x0002U
  1535. +# endif
  1536. #endif
  1537. QT_BEGIN_NAMESPACE
  1538. @@ -68,14 +72,16 @@ QT_BEGIN_NAMESPACE
  1539. namespace QtWaylandClient {
  1540. QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
  1541. - const QSize &size, QImage::Format format, int scale)
  1542. + const QSize &size, QImage::Format format, qreal scale)
  1543. {
  1544. int stride = size.width() * 4;
  1545. int alloc = stride * size.height();
  1546. int fd = -1;
  1547. -#ifdef SYS_memfd_create
  1548. - fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC);
  1549. +#if defined(SYS_memfd_create) && defined(F_SEAL_SEAL)
  1550. + fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
  1551. + if (fd >= 0)
  1552. + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
  1553. #endif
  1554. QScopedPointer<QFile> filePointer;
  1555. @@ -108,7 +114,7 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
  1556. QWaylandShm* shm = display->shm();
  1557. wl_shm_format wl_format = shm->formatFrom(format);
  1558. mImage = QImage(data, size.width(), size.height(), stride, format);
  1559. - mImage.setDevicePixelRatio(qreal(scale));
  1560. + mImage.setDevicePixelRatio(scale);
  1561. mShmPool = wl_shm_create_pool(shm->object(), fd, alloc);
  1562. init(wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(),
  1563. @@ -180,8 +186,6 @@ void QWaylandShmBackingStore::beginPaint(const QRegion &region)
  1564. mPainting = true;
  1565. ensureSize();
  1566. - waylandWindow()->setCanResize(false);
  1567. -
  1568. if (mBackBuffer->image()->hasAlphaChannel()) {
  1569. QPainter p(paintDevice());
  1570. p.setCompositionMode(QPainter::CompositionMode_Source);
  1571. @@ -196,7 +200,6 @@ void QWaylandShmBackingStore::endPaint()
  1572. mPainting = false;
  1573. if (mPendingFlush)
  1574. flush(window(), mPendingRegion, QPoint());
  1575. - waylandWindow()->setCanResize(true);
  1576. }
  1577. void QWaylandShmBackingStore::ensureSize()
  1578. @@ -271,7 +274,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
  1579. void QWaylandShmBackingStore::resize(const QSize &size)
  1580. {
  1581. QMargins margins = windowDecorationMargins();
  1582. - int scale = waylandWindow()->scale();
  1583. + qreal scale = waylandWindow()->scale();
  1584. QSize sizeWithMargins = (size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom())) * scale;
  1585. // We look for a free buffer to draw into. If the buffer is not the last buffer we used,
  1586. diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h
  1587. index e01632da..f3fae438 100644
  1588. --- a/src/client/qwaylandshmbackingstore_p.h
  1589. +++ b/src/client/qwaylandshmbackingstore_p.h
  1590. @@ -71,7 +71,7 @@ class QWaylandWindow;
  1591. class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer {
  1592. public:
  1593. QWaylandShmBuffer(QWaylandDisplay *display,
  1594. - const QSize &size, QImage::Format format, int scale = 1);
  1595. + const QSize &size, QImage::Format format, qreal scale = 1);
  1596. ~QWaylandShmBuffer() override;
  1597. QSize size() const override { return mImage.size(); }
  1598. int scale() const override { return int(mImage.devicePixelRatio()); }
  1599. diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
  1600. index d57094a7..7a9bccc1 100644
  1601. --- a/src/client/qwaylandwindow.cpp
  1602. +++ b/src/client/qwaylandwindow.cpp
  1603. @@ -76,7 +76,6 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
  1604. QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
  1605. : QPlatformWindow(window)
  1606. , mDisplay(display)
  1607. - , mFrameQueue(mDisplay->createFrameQueue())
  1608. , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
  1609. {
  1610. {
  1611. @@ -95,9 +94,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
  1612. QWaylandWindow::~QWaylandWindow()
  1613. {
  1614. - mDisplay->destroyFrameQueue(mFrameQueue);
  1615. - mDisplay->handleWindowDestroyed(this);
  1616. -
  1617. delete mWindowDecoration;
  1618. if (mSurface)
  1619. @@ -189,7 +185,7 @@ void QWaylandWindow::initWindow()
  1620. // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
  1621. // to inform the compositor that high-resolution buffers will be provided.
  1622. if (mDisplay->compositorVersion() >= 3)
  1623. - mSurface->set_buffer_scale(scale());
  1624. + mSurface->set_buffer_scale(mScale);
  1625. if (QScreen *s = window()->screen())
  1626. setOrientationMask(s->orientationUpdateMask());
  1627. @@ -204,6 +200,8 @@ void QWaylandWindow::initWindow()
  1628. mShellSurface->requestWindowStates(window()->windowStates());
  1629. handleContentOrientationChange(window()->contentOrientation());
  1630. mFlags = window()->flags();
  1631. +
  1632. + mSurface->commit();
  1633. }
  1634. void QWaylandWindow::initializeWlSurface()
  1635. @@ -243,6 +241,7 @@ bool QWaylandWindow::shouldCreateSubSurface() const
  1636. void QWaylandWindow::reset()
  1637. {
  1638. + closeChildPopups();
  1639. delete mShellSurface;
  1640. mShellSurface = nullptr;
  1641. delete mSubSurfaceWindow;
  1642. @@ -255,17 +254,22 @@ void QWaylandWindow::reset()
  1643. mSurface.reset();
  1644. }
  1645. - if (mFrameCallback) {
  1646. - wl_callback_destroy(mFrameCallback);
  1647. - mFrameCallback = nullptr;
  1648. - }
  1649. + {
  1650. + QMutexLocker lock(&mFrameSyncMutex);
  1651. + if (mFrameCallback) {
  1652. + wl_callback_destroy(mFrameCallback);
  1653. + mFrameCallback = nullptr;
  1654. + }
  1655. - mFrameCallbackElapsedTimer.invalidate();
  1656. - mWaitingForFrameCallback = false;
  1657. + mFrameCallbackElapsedTimer.invalidate();
  1658. + mWaitingForFrameCallback = false;
  1659. + }
  1660. mFrameCallbackTimedOut = false;
  1661. mMask = QRegion();
  1662. mQueuedBuffer = nullptr;
  1663. +
  1664. + mDisplay->handleWindowDestroyed(this);
  1665. }
  1666. QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
  1667. @@ -351,19 +355,25 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect)
  1668. }
  1669. }
  1670. -void QWaylandWindow::setGeometry(const QRect &rect)
  1671. +void QWaylandWindow::setGeometry(const QRect &r)
  1672. {
  1673. + auto rect = r;
  1674. + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
  1675. + && window()->type() != Qt::ToolTip) {
  1676. + rect.moveTo(screen()->geometry().topLeft());
  1677. + }
  1678. setGeometry_helper(rect);
  1679. if (window()->isVisible() && rect.isValid()) {
  1680. if (mWindowDecoration)
  1681. mWindowDecoration->update();
  1682. - if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize)
  1683. + if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize) {
  1684. + QMutexLocker lock(&mResizeLock);
  1685. mResizeDirty = true;
  1686. - else
  1687. + } else {
  1688. QWindowSystemInterface::handleGeometryChange(window(), geometry());
  1689. -
  1690. + }
  1691. mSentInitialResize = true;
  1692. }
  1693. QRect exposeGeometry(QPoint(), geometry().size());
  1694. @@ -374,7 +384,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
  1695. mShellSurface->setWindowGeometry(windowContentGeometry());
  1696. if (isOpaque() && mMask.isEmpty())
  1697. - setOpaqueArea(rect);
  1698. + setOpaqueArea(QRect(QPoint(0, 0), rect.size()));
  1699. }
  1700. void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
  1701. @@ -399,21 +409,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
  1702. mLastExposeGeometry = rect;
  1703. }
  1704. -
  1705. -static QVector<QPointer<QWaylandWindow>> activePopups;
  1706. -
  1707. -void QWaylandWindow::closePopups(QWaylandWindow *parent)
  1708. -{
  1709. - while (!activePopups.isEmpty()) {
  1710. - auto popup = activePopups.takeLast();
  1711. - if (popup.isNull())
  1712. - continue;
  1713. - if (popup.data() == parent)
  1714. - return;
  1715. - popup->reset();
  1716. - }
  1717. -}
  1718. -
  1719. QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
  1720. {
  1721. QReadLocker lock(&mSurfaceLock);
  1722. @@ -433,10 +428,7 @@ void QWaylandWindow::setVisible(bool visible)
  1723. lastVisible = visible;
  1724. if (visible) {
  1725. - if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
  1726. - activePopups << this;
  1727. initWindow();
  1728. - mDisplay->flushRequests();
  1729. setGeometry(windowGeometry());
  1730. // Don't flush the events here, or else the newly visible window may start drawing, but since
  1731. @@ -444,7 +436,6 @@ void QWaylandWindow::setVisible(bool visible)
  1732. // QWaylandShmBackingStore::beginPaint().
  1733. } else {
  1734. sendExposeEvent(QRect());
  1735. - closePopups(this);
  1736. reset();
  1737. }
  1738. }
  1739. @@ -487,8 +478,6 @@ void QWaylandWindow::setMask(const QRegion &mask)
  1740. if (isOpaque())
  1741. setOpaqueArea(mMask);
  1742. }
  1743. -
  1744. - mSurface->commit();
  1745. }
  1746. void QWaylandWindow::applyConfigureWhenPossible()
  1747. @@ -556,12 +545,12 @@ void QWaylandWindow::sendRecursiveExposeEvent()
  1748. void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
  1749. {
  1750. - Q_ASSERT(!buffer->committed());
  1751. QReadLocker locker(&mSurfaceLock);
  1752. if (mSurface == nullptr)
  1753. return;
  1754. if (buffer) {
  1755. + Q_ASSERT(!buffer->committed());
  1756. handleUpdate();
  1757. buffer->setBusy();
  1758. @@ -583,7 +572,16 @@ void QWaylandWindow::damage(const QRect &rect)
  1759. if (mSurface == nullptr)
  1760. return;
  1761. - mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
  1762. + const qreal s = scale();
  1763. + if (mDisplay->compositorVersion() >= 4) {
  1764. + const QRect bufferRect =
  1765. + QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
  1766. + .toAlignedRect();
  1767. + mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
  1768. + bufferRect.height());
  1769. + } else {
  1770. + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
  1771. + }
  1772. }
  1773. void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
  1774. @@ -619,8 +617,19 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
  1775. return;
  1776. attachOffset(buffer);
  1777. - for (const QRect &rect: damage)
  1778. - mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
  1779. + if (mDisplay->compositorVersion() >= 4) {
  1780. + const qreal s = scale();
  1781. + for (const QRect &rect : damage) {
  1782. + const QRect bufferRect =
  1783. + QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
  1784. + .toAlignedRect();
  1785. + mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
  1786. + bufferRect.height());
  1787. + }
  1788. + } else {
  1789. + for (const QRect &rect: damage)
  1790. + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
  1791. + }
  1792. Q_ASSERT(!buffer->committed());
  1793. buffer->setCommitted();
  1794. mSurface->commit();
  1795. @@ -635,42 +644,53 @@ void QWaylandWindow::commit()
  1796. const wl_callback_listener QWaylandWindow::callbackListener = {
  1797. [](void *data, wl_callback *callback, uint32_t time) {
  1798. - Q_UNUSED(callback);
  1799. Q_UNUSED(time);
  1800. auto *window = static_cast<QWaylandWindow*>(data);
  1801. - window->handleFrameCallback();
  1802. + window->handleFrameCallback(callback);
  1803. }
  1804. };
  1805. -void QWaylandWindow::handleFrameCallback()
  1806. +void QWaylandWindow::handleFrameCallback(wl_callback* callback)
  1807. {
  1808. + QMutexLocker locker(&mFrameSyncMutex);
  1809. + if (!mFrameCallback) {
  1810. + // This means the callback is already unset by QWaylandWindow::reset.
  1811. + // The wl_callback object will be destroyed there too.
  1812. + return;
  1813. + }
  1814. + Q_ASSERT(callback == mFrameCallback);
  1815. + wl_callback_destroy(callback);
  1816. + mFrameCallback = nullptr;
  1817. +
  1818. mWaitingForFrameCallback = false;
  1819. mFrameCallbackElapsedTimer.invalidate();
  1820. // The rest can wait until we can run it on the correct thread
  1821. - if (!mWaitingForUpdateDelivery) {
  1822. - auto doHandleExpose = [this]() {
  1823. - bool wasExposed = isExposed();
  1824. - mFrameCallbackTimedOut = false;
  1825. - if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
  1826. - sendExposeEvent(QRect(QPoint(), geometry().size()));
  1827. - if (wasExposed && hasPendingUpdateRequest())
  1828. - deliverUpdateRequest();
  1829. -
  1830. - mWaitingForUpdateDelivery = false;
  1831. - };
  1832. + auto doHandleExpose = [this]() {
  1833. + mWaitingForUpdateDelivery.storeRelease(false);
  1834. + bool wasExposed = isExposed();
  1835. + mFrameCallbackTimedOut = false;
  1836. + if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
  1837. + sendExposeEvent(QRect(QPoint(), geometry().size()));
  1838. + if (wasExposed && hasPendingUpdateRequest())
  1839. + deliverUpdateRequest();
  1840. + };
  1841. + if (mWaitingForUpdateDelivery.testAndSetAcquire(false, true)) {
  1842. // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
  1843. // in the single-threaded case.
  1844. - mWaitingForUpdateDelivery = true;
  1845. QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
  1846. }
  1847. +
  1848. + mFrameSyncWait.notify_all();
  1849. }
  1850. bool QWaylandWindow::waitForFrameSync(int timeout)
  1851. {
  1852. - QMutexLocker locker(mFrameQueue.mutex);
  1853. - mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout);
  1854. + QMutexLocker locker(&mFrameSyncMutex);
  1855. +
  1856. + QDeadlineTimer deadline(timeout);
  1857. + while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { }
  1858. if (mWaitingForFrameCallback) {
  1859. qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
  1860. @@ -772,8 +792,6 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient
  1861. Q_UNREACHABLE();
  1862. }
  1863. mSurface->set_buffer_transform(transform);
  1864. - // set_buffer_transform is double buffered, we need to commit.
  1865. - mSurface->commit();
  1866. }
  1867. void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
  1868. @@ -1032,8 +1050,17 @@ void QWaylandWindow::handleScreensChanged()
  1869. if (newScreen == mLastReportedScreen)
  1870. return;
  1871. + if (!newScreen->isPlaceholder() && !newScreen->QPlatformScreen::screen())
  1872. + mDisplay->forceRoundTrip();
  1873. QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
  1874. mLastReportedScreen = newScreen;
  1875. + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
  1876. + && window()->type() != Qt::ToolTip
  1877. + && geometry().topLeft() != newScreen->geometry().topLeft()) {
  1878. + auto geometry = this->geometry();
  1879. + geometry.moveTo(newScreen->geometry().topLeft());
  1880. + setGeometry(geometry);
  1881. + }
  1882. int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
  1883. if (scale != mScale) {
  1884. @@ -1087,14 +1114,14 @@ bool QWaylandWindow::isActive() const
  1885. return mDisplay->isWindowActivated(this);
  1886. }
  1887. -int QWaylandWindow::scale() const
  1888. +qreal QWaylandWindow::scale() const
  1889. {
  1890. - return mScale;
  1891. + return devicePixelRatio();
  1892. }
  1893. qreal QWaylandWindow::devicePixelRatio() const
  1894. {
  1895. - return mScale;
  1896. + return qreal(mScale);
  1897. }
  1898. bool QWaylandWindow::setMouseGrabEnabled(bool grab)
  1899. @@ -1108,10 +1135,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
  1900. return true;
  1901. }
  1902. +Qt::WindowStates QWaylandWindow::windowStates() const
  1903. +{
  1904. + return mLastReportedWindowStates;
  1905. +}
  1906. +
  1907. void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
  1908. {
  1909. createDecoration();
  1910. - QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
  1911. + Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
  1912. + Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
  1913. + QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
  1914. + lastStatesWithoutActive);
  1915. mLastReportedWindowStates = states;
  1916. }
  1917. @@ -1153,19 +1188,24 @@ void QWaylandWindow::timerEvent(QTimerEvent *event)
  1918. if (event->timerId() != mFrameCallbackCheckIntervalTimerId)
  1919. return;
  1920. - bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
  1921. - if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
  1922. - killTimer(mFrameCallbackCheckIntervalTimerId);
  1923. - mFrameCallbackCheckIntervalTimerId = -1;
  1924. - }
  1925. - if (mFrameCallbackElapsedTimer.isValid() && callbackTimerExpired) {
  1926. - mFrameCallbackElapsedTimer.invalidate();
  1927. + {
  1928. + QMutexLocker lock(&mFrameSyncMutex);
  1929. - qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
  1930. - mFrameCallbackTimedOut = true;
  1931. - mWaitingForUpdate = false;
  1932. - sendExposeEvent(QRect());
  1933. + bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
  1934. + if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
  1935. + killTimer(mFrameCallbackCheckIntervalTimerId);
  1936. + mFrameCallbackCheckIntervalTimerId = -1;
  1937. + }
  1938. + if (!mFrameCallbackElapsedTimer.isValid() || !callbackTimerExpired) {
  1939. + return;
  1940. + }
  1941. + mFrameCallbackElapsedTimer.invalidate();
  1942. }
  1943. +
  1944. + qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
  1945. + mFrameCallbackTimedOut = true;
  1946. + mWaitingForUpdate = false;
  1947. + sendExposeEvent(QRect());
  1948. }
  1949. void QWaylandWindow::requestUpdate()
  1950. @@ -1174,8 +1214,11 @@ void QWaylandWindow::requestUpdate()
  1951. Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
  1952. // If we have a frame callback all is good and will be taken care of there
  1953. - if (mWaitingForFrameCallback)
  1954. - return;
  1955. + {
  1956. + QMutexLocker locker(&mFrameSyncMutex);
  1957. + if (mWaitingForFrameCallback)
  1958. + return;
  1959. + }
  1960. // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
  1961. // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
  1962. @@ -1188,7 +1231,12 @@ void QWaylandWindow::requestUpdate()
  1963. // so use invokeMethod to delay the delivery a bit.
  1964. QMetaObject::invokeMethod(this, [this] {
  1965. // Things might have changed in the meantime
  1966. - if (hasPendingUpdateRequest() && !mWaitingForFrameCallback)
  1967. + {
  1968. + QMutexLocker locker(&mFrameSyncMutex);
  1969. + if (mWaitingForFrameCallback)
  1970. + return;
  1971. + }
  1972. + if (hasPendingUpdateRequest())
  1973. deliverUpdateRequest();
  1974. }, Qt::QueuedConnection);
  1975. }
  1976. @@ -1199,19 +1247,18 @@ void QWaylandWindow::requestUpdate()
  1977. void QWaylandWindow::handleUpdate()
  1978. {
  1979. qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
  1980. +
  1981. // TODO: Should sync subsurfaces avoid requesting frame callbacks?
  1982. QReadLocker lock(&mSurfaceLock);
  1983. if (!mSurface)
  1984. return;
  1985. - if (mFrameCallback) {
  1986. - wl_callback_destroy(mFrameCallback);
  1987. - mFrameCallback = nullptr;
  1988. - }
  1989. + QMutexLocker locker(&mFrameSyncMutex);
  1990. + if (mWaitingForFrameCallback)
  1991. + return;
  1992. - QMutexLocker locker(mFrameQueue.mutex);
  1993. struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
  1994. - wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
  1995. + wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue());
  1996. mFrameCallback = wl_surface_frame(wrappedSurface);
  1997. wl_proxy_wrapper_destroy(wrappedSurface);
  1998. wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
  1999. @@ -1221,6 +1268,8 @@ void QWaylandWindow::handleUpdate()
  2000. // Start a timer for handling the case when the compositor stops sending frame callbacks.
  2001. if (mFrameCallbackTimeout > 0) {
  2002. QMetaObject::invokeMethod(this, [this] {
  2003. + QMutexLocker locker(&mFrameSyncMutex);
  2004. +
  2005. if (mWaitingForFrameCallback) {
  2006. if (mFrameCallbackCheckIntervalTimerId < 0)
  2007. mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout);
  2008. @@ -1281,6 +1330,20 @@ void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea)
  2009. wl_region_destroy(region);
  2010. }
  2011. +void QWaylandWindow::addChildPopup(QWaylandWindow *surface) {
  2012. + mChildPopups.append(surface);
  2013. +}
  2014. +
  2015. +void QWaylandWindow::removeChildPopup(QWaylandWindow *surface) {
  2016. + mChildPopups.removeAll(surface);
  2017. +}
  2018. +
  2019. +void QWaylandWindow::closeChildPopups() {
  2020. + while (!mChildPopups.isEmpty()) {
  2021. + auto popup = mChildPopups.takeLast();
  2022. + popup->reset();
  2023. + }
  2024. +}
  2025. }
  2026. QT_END_NAMESPACE
  2027. diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
  2028. index 01337cff..741f9e5c 100644
  2029. --- a/src/client/qwaylandwindow_p.h
  2030. +++ b/src/client/qwaylandwindow_p.h
  2031. @@ -98,6 +98,9 @@ public:
  2032. QWaylandWindow(QWindow *window, QWaylandDisplay *display);
  2033. ~QWaylandWindow() override;
  2034. + // Keep Toplevels position on the top left corner of their screen
  2035. + static inline bool fixedToplevelPositions = true;
  2036. +
  2037. virtual WindowType windowType() const = 0;
  2038. virtual void ensureSize();
  2039. WId winId() const override;
  2040. @@ -148,13 +151,14 @@ public:
  2041. void setWindowState(Qt::WindowStates states) override;
  2042. void setWindowFlags(Qt::WindowFlags flags) override;
  2043. void handleWindowStatesChanged(Qt::WindowStates states);
  2044. + Qt::WindowStates windowStates() const;
  2045. void raise() override;
  2046. void lower() override;
  2047. void setMask(const QRegion &region) override;
  2048. - int scale() const;
  2049. + qreal scale() const;
  2050. qreal devicePixelRatio() const override;
  2051. void requestActivateWindow() override;
  2052. @@ -206,6 +210,10 @@ public:
  2053. void handleUpdate();
  2054. void deliverUpdateRequest() override;
  2055. + void addChildPopup(QWaylandWindow* child);
  2056. + void removeChildPopup(QWaylandWindow* child);
  2057. + void closeChildPopups();
  2058. +
  2059. public slots:
  2060. void applyConfigure();
  2061. @@ -215,7 +223,11 @@ signals:
  2062. protected:
  2063. QWaylandDisplay *mDisplay = nullptr;
  2064. +
  2065. + // mSurface can be written by the main thread. Other threads should claim a read lock for access
  2066. + mutable QReadWriteLock mSurfaceLock;
  2067. QScopedPointer<QWaylandSurface> mSurface;
  2068. +
  2069. QWaylandShellSurface *mShellSurface = nullptr;
  2070. QWaylandSubSurface *mSubSurfaceWindow = nullptr;
  2071. QVector<QWaylandSubSurface *> mChildren;
  2072. @@ -225,13 +237,14 @@ protected:
  2073. Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
  2074. WId mWindowId;
  2075. - bool mWaitingForFrameCallback = false;
  2076. bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
  2077. - bool mWaitingForUpdateDelivery = false;
  2078. int mFrameCallbackCheckIntervalTimerId = -1;
  2079. - QElapsedTimer mFrameCallbackElapsedTimer;
  2080. - struct ::wl_callback *mFrameCallback = nullptr;
  2081. - QWaylandDisplay::FrameQueue mFrameQueue;
  2082. + QAtomicInt mWaitingForUpdateDelivery = false;
  2083. +
  2084. + bool mWaitingForFrameCallback = false; // Protected by mFrameSyncMutex
  2085. + QElapsedTimer mFrameCallbackElapsedTimer; // Protected by mFrameSyncMutex
  2086. + struct ::wl_callback *mFrameCallback = nullptr; // Protected by mFrameSyncMutex
  2087. + QMutex mFrameSyncMutex;
  2088. QWaitCondition mFrameSyncWait;
  2089. // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
  2090. @@ -261,6 +274,8 @@ protected:
  2091. QWaylandBuffer *mQueuedBuffer = nullptr;
  2092. QRegion mQueuedBufferDamage;
  2093. + QList<QPointer<QWaylandWindow>> mChildPopups;
  2094. +
  2095. private:
  2096. void setGeometry_helper(const QRect &rect);
  2097. void initWindow();
  2098. @@ -283,12 +298,10 @@ private:
  2099. QRect mLastExposeGeometry;
  2100. static const wl_callback_listener callbackListener;
  2101. - void handleFrameCallback();
  2102. + void handleFrameCallback(struct ::wl_callback* callback);
  2103. static QWaylandWindow *mMouseGrab;
  2104. - mutable QReadWriteLock mSurfaceLock;
  2105. -
  2106. friend class QWaylandSubSurface;
  2107. };
  2108. diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
  2109. index ccad0048..4cc9b3b8 100644
  2110. --- a/src/client/shellintegration/qwaylandshellintegration_p.h
  2111. +++ b/src/client/shellintegration/qwaylandshellintegration_p.h
  2112. @@ -73,11 +73,10 @@ public:
  2113. return true;
  2114. }
  2115. virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
  2116. + // kept for binary compat with layer-shell-qt
  2117. virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
  2118. - if (newFocus)
  2119. - m_display->handleWindowActivated(newFocus);
  2120. - if (oldFocus)
  2121. - m_display->handleWindowDeactivated(oldFocus);
  2122. + Q_UNUSED(newFocus);
  2123. + Q_UNUSED(oldFocus);
  2124. }
  2125. virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
  2126. Q_UNUSED(resource);
  2127. diff --git a/src/compositor/configure.json b/src/compositor/configure.json
  2128. index bcfd5215..da95d07b 100644
  2129. --- a/src/compositor/configure.json
  2130. +++ b/src/compositor/configure.json
  2131. @@ -7,6 +7,31 @@
  2132. "testDir": "../../config.tests",
  2133. "libraries": {
  2134. + "wayland-client": {
  2135. + "label": "Wayland client library",
  2136. + "headers": "wayland-version.h",
  2137. + "test": {
  2138. + "main": [
  2139. + "#if WAYLAND_VERSION_MAJOR < 1",
  2140. + "# error Wayland 1.8.0 or higher required",
  2141. + "#endif",
  2142. + "#if WAYLAND_VERSION_MAJOR == 1",
  2143. + "# if WAYLAND_VERSION_MINOR < 8",
  2144. + "# error Wayland 1.8.0 or higher required",
  2145. + "# endif",
  2146. + "# if WAYLAND_VERSION_MINOR == 8",
  2147. + "# if WAYLAND_VERSION_MICRO < 0",
  2148. + "# error Wayland 1.8.0 or higher required",
  2149. + "# endif",
  2150. + "# endif",
  2151. + "#endif"
  2152. + ]
  2153. + },
  2154. + "sources": [
  2155. + { "type": "pkgConfig", "args": "wayland-client" },
  2156. + "-lwayland-client"
  2157. + ]
  2158. + },
  2159. "wayland-server": {
  2160. "label": "wayland-server",
  2161. "headers": "wayland-version.h",
  2162. @@ -151,8 +176,7 @@
  2163. "#endif"
  2164. ]
  2165. },
  2166. - "libs": "-ldrm",
  2167. - "use": "egl"
  2168. + "use": "drm egl"
  2169. },
  2170. "dmabuf-client-buffer": {
  2171. "label": "Linux Client dma-buf Buffer Sharing",
  2172. @@ -176,8 +200,7 @@
  2173. "return 0;"
  2174. ]
  2175. },
  2176. - "libs": "-ldrm",
  2177. - "use": "egl"
  2178. + "use": "drm egl"
  2179. },
  2180. "vulkan-server-buffer": {
  2181. "label": "Vulkan Buffer Sharing",
  2182. @@ -195,7 +218,8 @@
  2183. "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
  2184. "return 0;"
  2185. ]
  2186. - }
  2187. + },
  2188. + "use": "wayland-client"
  2189. }
  2190. },
  2191. diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
  2192. index e00c28c3..dbe2845a 100644
  2193. --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
  2194. +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
  2195. @@ -40,6 +40,7 @@
  2196. #include "qwaylandeglwindow.h"
  2197. #include <QtWaylandClient/private/qwaylandscreen_p.h>
  2198. +#include <QtWaylandClient/private/qwaylandsurface_p.h>
  2199. #include "qwaylandglcontext.h"
  2200. #include <QtEglSupport/private/qeglconvenience_p.h>
  2201. @@ -115,6 +116,7 @@ void QWaylandEglWindow::updateSurface(bool create)
  2202. }
  2203. mOffset = QPoint();
  2204. } else {
  2205. + QReadLocker locker(&mSurfaceLock);
  2206. if (m_waylandEglWindow) {
  2207. int current_width, current_height;
  2208. static bool disableResizeCheck = qgetenv("QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
  2209. @@ -122,14 +124,16 @@ void QWaylandEglWindow::updateSurface(bool create)
  2210. if (!disableResizeCheck) {
  2211. wl_egl_window_get_attached_size(m_waylandEglWindow, &current_width, &current_height);
  2212. }
  2213. - if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height())) {
  2214. + if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
  2215. wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y());
  2216. + m_requestedSize = sizeWithMargins;
  2217. mOffset = QPoint();
  2218. m_resize = true;
  2219. }
  2220. - } else if (create && wlSurface()) {
  2221. - m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
  2222. + } else if (create && mSurface) {
  2223. + m_waylandEglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
  2224. + m_requestedSize = sizeWithMargins;
  2225. }
  2226. if (!m_eglSurface && m_waylandEglWindow && create) {
  2227. diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
  2228. index 2fccbcea..ad1e5ee9 100644
  2229. --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
  2230. +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
  2231. @@ -85,6 +85,7 @@ private:
  2232. mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
  2233. QSurfaceFormat m_format;
  2234. + QSize m_requestedSize;
  2235. };
  2236. }
  2237. diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
  2238. index c1f45fa6..bbc63444 100644
  2239. --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
  2240. +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
  2241. @@ -195,7 +195,7 @@ public:
  2242. QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
  2243. QSize surfaceSize = window->surfaceSize();
  2244. - int scale = window->scale() ;
  2245. + qreal scale = window->scale() ;
  2246. glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
  2247. //Draw Decoration
  2248. diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
  2249. index 85d25e3c..60bdd491 100644
  2250. --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
  2251. +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
  2252. @@ -47,18 +47,21 @@ QT_BEGIN_NAMESPACE
  2253. namespace QtWaylandClient {
  2254. -QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window)
  2255. +QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window)
  2256. : QWaylandShellSurface(window)
  2257. , QtWayland::xdg_popup_v5(popup)
  2258. + , m_parent(parent)
  2259. , m_window(window)
  2260. {
  2261. if (window->display()->windowExtension())
  2262. m_extendedWindow = new QWaylandExtendedSurface(window);
  2263. + m_parent->addChildPopup(m_window);
  2264. }
  2265. QWaylandXdgPopupV5::~QWaylandXdgPopupV5()
  2266. {
  2267. xdg_popup_destroy(object());
  2268. + m_parent->removeChildPopup(m_window);
  2269. delete m_extendedWindow;
  2270. }
  2271. diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
  2272. index 7494f6a6..d85f130b 100644
  2273. --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
  2274. +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
  2275. @@ -70,7 +70,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopupV5 : public QWaylandShellSurface
  2276. {
  2277. Q_OBJECT
  2278. public:
  2279. - QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window);
  2280. + QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window);
  2281. ~QWaylandXdgPopupV5() override;
  2282. protected:
  2283. @@ -78,6 +78,7 @@ protected:
  2284. private:
  2285. QWaylandExtendedSurface *m_extendedWindow = nullptr;
  2286. + QWaylandWindow *m_parent = nullptr;
  2287. QWaylandWindow *m_window = nullptr;
  2288. };
  2289. diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
  2290. index 7e242c4a..def8452a 100644
  2291. --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
  2292. +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
  2293. @@ -84,7 +84,7 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, Q
  2294. int x = position.x() + parentWindow->frameMargins().left();
  2295. int y = position.y() + parentWindow->frameMargins().top();
  2296. - auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), window);
  2297. + auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), parentWindow, window);
  2298. m_popups.append(window);
  2299. QObject::connect(popup, &QWaylandXdgPopupV5::destroyed, [this, window](){
  2300. m_popups.removeOne(window);
  2301. diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
  2302. index 4e25949f..cfc60939 100644
  2303. --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
  2304. +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
  2305. @@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
  2306. return m_xdgShell->createXdgSurface(window);
  2307. }
  2308. -void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
  2309. - if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
  2310. - m_display->handleWindowActivated(newFocus);
  2311. - if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
  2312. - m_display->handleWindowDeactivated(oldFocus);
  2313. -}
  2314. -
  2315. }
  2316. QT_END_NAMESPACE
  2317. diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
  2318. index ce6bdb9e..aed88670 100644
  2319. --- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
  2320. +++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
  2321. @@ -67,7 +67,6 @@ public:
  2322. QWaylandXdgShellV5Integration() {}
  2323. bool initialize(QWaylandDisplay *display) override;
  2324. QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
  2325. - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
  2326. private:
  2327. QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
  2328. diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
  2329. index 8c371661..151c78e3 100644
  2330. --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
  2331. +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
  2332. @@ -174,6 +174,7 @@ QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdg
  2333. , m_xdgSurface(xdgSurface)
  2334. , m_parent(parent)
  2335. {
  2336. + m_parent->window()->addChildPopup(m_xdgSurface->window());
  2337. }
  2338. QWaylandXdgSurfaceV6::Popup::~Popup()
  2339. @@ -181,6 +182,8 @@ QWaylandXdgSurfaceV6::Popup::~Popup()
  2340. if (isInitialized())
  2341. destroy();
  2342. + m_parent->window()->removeChildPopup(m_xdgSurface->window());
  2343. +
  2344. if (m_grabbing) {
  2345. auto *shell = m_xdgSurface->m_shell;
  2346. Q_ASSERT(shell->m_topmostGrabbingPopup == this);
  2347. diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
  2348. index 03164316..e8da8ba1 100644
  2349. --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
  2350. +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
  2351. @@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
  2352. return m_xdgShell->getXdgSurface(window);
  2353. }
  2354. -void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
  2355. -{
  2356. - if (newFocus) {
  2357. - auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
  2358. - if (xdgSurface && !xdgSurface->handlesActiveState())
  2359. - m_display->handleWindowActivated(newFocus);
  2360. - }
  2361. - if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
  2362. - auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
  2363. - if (xdgSurface && !xdgSurface->handlesActiveState())
  2364. - m_display->handleWindowDeactivated(oldFocus);
  2365. - }
  2366. -}
  2367. -
  2368. }
  2369. QT_END_NAMESPACE
  2370. diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
  2371. index 261f8cbb..c1bcd5c6 100644
  2372. --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
  2373. +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
  2374. @@ -65,7 +65,6 @@ public:
  2375. QWaylandXdgShellV6Integration() {}
  2376. bool initialize(QWaylandDisplay *display) override;
  2377. QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
  2378. - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
  2379. private:
  2380. QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
  2381. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  2382. index 94ea573e..9c6cbb81 100644
  2383. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  2384. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  2385. @@ -44,6 +44,7 @@
  2386. #include <QtWaylandClient/private/qwaylandwindow_p.h>
  2387. #include <QtWaylandClient/private/qwaylandinputdevice_p.h>
  2388. #include <QtWaylandClient/private/qwaylandscreen_p.h>
  2389. +#include <QtWaylandClient/private/qwaylandcursor_p.h>
  2390. #include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
  2391. #include <QtGui/private/qwindow_p.h>
  2392. @@ -67,11 +68,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
  2393. QWaylandXdgSurface::Toplevel::~Toplevel()
  2394. {
  2395. - if (m_applied.states & Qt::WindowActive) {
  2396. - QWaylandWindow *window = m_xdgSurface->window();
  2397. - window->display()->handleWindowDeactivated(window);
  2398. - }
  2399. -
  2400. // The protocol spec requires that the decoration object is deleted before xdg_toplevel.
  2401. delete m_decoration;
  2402. m_decoration = nullptr;
  2403. @@ -85,16 +81,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
  2404. if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
  2405. m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
  2406. - if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
  2407. + if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
  2408. + && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
  2409. m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
  2410. - if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
  2411. + if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
  2412. + && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
  2413. m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
  2414. - // TODO: none of the other plugins send WindowActive either, but is it on purpose?
  2415. - Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
  2416. -
  2417. - m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
  2418. + m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
  2419. if (m_pending.size.isEmpty()) {
  2420. // An empty size in the configure means it's up to the client to choose the size
  2421. @@ -105,8 +100,6 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
  2422. m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
  2423. }
  2424. - m_xdgSurface->setSizeHints();
  2425. -
  2426. m_applied = m_pending;
  2427. qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
  2428. }
  2429. @@ -203,12 +196,17 @@ QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResi
  2430. | ((edges & Qt::RightEdge) ? resize_edge_right : 0));
  2431. }
  2432. -QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent,
  2433. +QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent,
  2434. QtWayland::xdg_positioner *positioner)
  2435. - : xdg_popup(xdgSurface->get_popup(parent->object(), positioner->object()))
  2436. - , m_xdgSurface(xdgSurface)
  2437. + : m_xdgSurface(xdgSurface)
  2438. + , m_parentXdgSurface(qobject_cast<QWaylandXdgSurface *>(parent->shellSurface()))
  2439. , m_parent(parent)
  2440. {
  2441. +
  2442. + init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr, positioner->object()));
  2443. + if (m_parent) {
  2444. + m_parent->addChildPopup(m_xdgSurface->window());
  2445. + }
  2446. }
  2447. QWaylandXdgSurface::Popup::~Popup()
  2448. @@ -216,10 +214,14 @@ QWaylandXdgSurface::Popup::~Popup()
  2449. if (isInitialized())
  2450. destroy();
  2451. + if (m_parent) {
  2452. + m_parent->removeChildPopup(m_xdgSurface->window());
  2453. + }
  2454. +
  2455. if (m_grabbing) {
  2456. auto *shell = m_xdgSurface->m_shell;
  2457. Q_ASSERT(shell->m_topmostGrabbingPopup == this);
  2458. - shell->m_topmostGrabbingPopup = m_parent->m_popup;
  2459. + shell->m_topmostGrabbingPopup = m_parentXdgSurface ? m_parentXdgSurface->m_popup : nullptr;
  2460. m_grabbing = false;
  2461. // Synthesize Qt enter/leave events for popup
  2462. @@ -228,8 +230,10 @@ QWaylandXdgSurface::Popup::~Popup()
  2463. leave = m_xdgSurface->window()->window();
  2464. QWindowSystemInterface::handleLeaveEvent(leave);
  2465. - if (QWindow *enter = QGuiApplication::topLevelAt(QCursor::pos()))
  2466. - QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
  2467. + if (QWindow *enter = QGuiApplication::topLevelAt(QCursor::pos())) {
  2468. + const auto pos = m_xdgSurface->window()->display()->waylandCursor()->pos();
  2469. + QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
  2470. + }
  2471. }
  2472. }
  2473. @@ -267,6 +271,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
  2474. m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
  2475. }
  2476. }
  2477. + setSizeHints();
  2478. }
  2479. QWaylandXdgSurface::~QWaylandXdgSurface()
  2480. @@ -365,9 +370,6 @@ bool QWaylandXdgSurface::wantsDecorations() const
  2481. void QWaylandXdgSurface::propagateSizeHints()
  2482. {
  2483. setSizeHints();
  2484. -
  2485. - if (m_toplevel && m_window)
  2486. - m_window->commit();
  2487. }
  2488. void QWaylandXdgSurface::setWindowGeometry(const QRect &rect)
  2489. @@ -382,10 +384,10 @@ void QWaylandXdgSurface::setSizeHints()
  2490. const int minHeight = qMax(0, m_window->windowMinimumSize().height());
  2491. m_toplevel->set_min_size(minWidth, minHeight);
  2492. - int maxWidth = qMax(0, m_window->windowMaximumSize().width());
  2493. + int maxWidth = qMax(minWidth, m_window->windowMaximumSize().width());
  2494. if (maxWidth == QWINDOWSIZE_MAX)
  2495. maxWidth = 0;
  2496. - int maxHeight = qMax(0, m_window->windowMaximumSize().height());
  2497. + int maxHeight = qMax(minHeight, m_window->windowMaximumSize().height());
  2498. if (maxHeight == QWINDOWSIZE_MAX)
  2499. maxHeight = 0;
  2500. m_toplevel->set_max_size(maxWidth, maxHeight);
  2501. @@ -410,8 +412,6 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
  2502. {
  2503. Q_ASSERT(!m_toplevel && !m_popup);
  2504. - auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(parent->shellSurface());
  2505. -
  2506. auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner());
  2507. // set_popup expects a position relative to the parent
  2508. QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
  2509. @@ -425,11 +425,10 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
  2510. positioner->set_gravity(QtWayland::xdg_positioner::gravity_bottom_right);
  2511. positioner->set_size(m_window->geometry().width(), m_window->geometry().height());
  2512. positioner->set_constraint_adjustment(QtWayland::xdg_positioner::constraint_adjustment_slide_x
  2513. - | QtWayland::xdg_positioner::constraint_adjustment_slide_y
  2514. - | QtWayland::xdg_positioner::constraint_adjustment_flip_x
  2515. - | QtWayland::xdg_positioner::constraint_adjustment_flip_y);
  2516. - m_popup = new Popup(this, parentXdgSurface, positioner);
  2517. + | QtWayland::xdg_positioner::constraint_adjustment_slide_y);
  2518. + m_popup = new Popup(this, parent, positioner);
  2519. positioner->destroy();
  2520. +
  2521. delete positioner;
  2522. }
  2523. @@ -466,8 +465,10 @@ void QWaylandXdgSurface::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevic
  2524. if (m_popup && m_popup->m_xdgSurface && m_popup->m_xdgSurface->window())
  2525. enter = m_popup->m_xdgSurface->window()->window();
  2526. - if (enter)
  2527. - QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
  2528. + if (enter) {
  2529. + const auto pos = m_popup->m_xdgSurface->window()->display()->waylandCursor()->pos();
  2530. + QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
  2531. + }
  2532. }
  2533. void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial)
  2534. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  2535. index 96785205..4b518f0a 100644
  2536. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  2537. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  2538. @@ -131,14 +131,15 @@ private:
  2539. class Popup : public QtWayland::xdg_popup {
  2540. public:
  2541. - Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent, QtWayland::xdg_positioner *positioner);
  2542. + Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent, QtWayland::xdg_positioner *positioner);
  2543. ~Popup() override;
  2544. void grab(QWaylandInputDevice *seat, uint serial);
  2545. void xdg_popup_popup_done() override;
  2546. QWaylandXdgSurface *m_xdgSurface = nullptr;
  2547. - QWaylandXdgSurface *m_parent = nullptr;
  2548. + QWaylandXdgSurface *m_parentXdgSurface = nullptr;
  2549. + QWaylandWindow *m_parent = nullptr;
  2550. bool m_grabbing = false;
  2551. };
  2552. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
  2553. index 8769d971..da0dd6a7 100644
  2554. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
  2555. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
  2556. @@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
  2557. return m_xdgShell->getXdgSurface(window);
  2558. }
  2559. -void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
  2560. -{
  2561. - if (newFocus) {
  2562. - auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
  2563. - if (xdgSurface && !xdgSurface->handlesActiveState())
  2564. - m_display->handleWindowActivated(newFocus);
  2565. - }
  2566. - if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
  2567. - auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
  2568. - if (xdgSurface && !xdgSurface->handlesActiveState())
  2569. - m_display->handleWindowDeactivated(oldFocus);
  2570. - }
  2571. -}
  2572. -
  2573. }
  2574. QT_END_NAMESPACE
  2575. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
  2576. index b6caa6c9..2f929f98 100644
  2577. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
  2578. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
  2579. @@ -65,7 +65,6 @@ public:
  2580. QWaylandXdgShellIntegration() {}
  2581. bool initialize(QWaylandDisplay *display) override;
  2582. QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
  2583. - void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
  2584. private:
  2585. QScopedPointer<QWaylandXdgShell> m_xdgShell;
  2586. diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp
  2587. index c5266ab3..e2fe1928 100644
  2588. --- a/src/shared/qwaylandmimehelper.cpp
  2589. +++ b/src/shared/qwaylandmimehelper.cpp
  2590. @@ -60,7 +60,7 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &
  2591. buf.open(QIODevice::ReadWrite);
  2592. QByteArray fmt = "BMP";
  2593. if (mimeType.startsWith(QLatin1String("image/"))) {
  2594. - QByteArray imgFmt = mimeType.mid(6).toUpper().toLatin1();
  2595. + QByteArray imgFmt = mimeType.mid(6).toLower().toLatin1();
  2596. if (QImageWriter::supportedImageFormats().contains(imgFmt))
  2597. fmt = imgFmt;
  2598. }
  2599. diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
  2600. index 1568b3b9..067410d0 100644
  2601. --- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
  2602. +++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
  2603. @@ -35,7 +35,7 @@
  2604. using namespace MockCompositor;
  2605. -constexpr int dataDeviceVersion = 1;
  2606. +constexpr int dataDeviceVersion = 3;
  2607. class DataDeviceCompositor : public DefaultCompositor {
  2608. public:
  2609. diff --git a/tests/auto/client/seatv5/tst_seatv5.cpp b/tests/auto/client/seatv5/tst_seatv5.cpp
  2610. index 9312c2e5..2ea382f1 100644
  2611. --- a/tests/auto/client/seatv5/tst_seatv5.cpp
  2612. +++ b/tests/auto/client/seatv5/tst_seatv5.cpp
  2613. @@ -73,6 +73,7 @@ private slots:
  2614. void multiTouch();
  2615. void multiTouchUpAndMotionFrame();
  2616. void tapAndMoveInSameFrame();
  2617. + void cancelTouch();
  2618. };
  2619. void tst_seatv5::bindsToSeat()
  2620. @@ -646,5 +647,34 @@ void tst_seatv5::tapAndMoveInSameFrame()
  2621. QTRY_COMPARE(window.m_events.last().touchPoints.first().state(), Qt::TouchPointState::TouchPointReleased);
  2622. }
  2623. +void tst_seatv5::cancelTouch()
  2624. +{
  2625. + TouchWindow window;
  2626. + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
  2627. +
  2628. + exec([=] {
  2629. + auto *t = touch();
  2630. + auto *c = client();
  2631. + t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
  2632. + t->sendFrame(c);
  2633. + t->sendCancel(c);
  2634. + t->sendFrame(c);
  2635. + });
  2636. +
  2637. + QTRY_VERIFY(!window.m_events.empty());
  2638. + {
  2639. + auto e = window.m_events.takeFirst();
  2640. + QCOMPARE(e.type, QEvent::TouchBegin);
  2641. + QCOMPARE(e.touchPointStates, Qt::TouchPointPressed);
  2642. + QCOMPARE(e.touchPoints.length(), 1);
  2643. + QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
  2644. + }
  2645. + {
  2646. + auto e = window.m_events.takeFirst();
  2647. + QCOMPARE(e.type, QEvent::TouchCancel);
  2648. + QCOMPARE(e.touchPoints.length(), 0);
  2649. + }
  2650. +}
  2651. +
  2652. QCOMPOSITOR_TEST_MAIN(tst_seatv5)
  2653. #include "tst_seatv5.moc"
  2654. diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
  2655. index 0d988521..53e12291 100644
  2656. --- a/tests/auto/client/shared/coreprotocol.cpp
  2657. +++ b/tests/auto/client/shared/coreprotocol.cpp
  2658. @@ -185,6 +185,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource
  2659. if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
  2660. wl_output::send_done(resource->handle);
  2661. +
  2662. + Q_EMIT outputBound(resource);
  2663. }
  2664. // Seat stuff
  2665. @@ -451,6 +453,13 @@ void Touch::sendFrame(wl_client *client)
  2666. send_frame(r->handle);
  2667. }
  2668. +void Touch::sendCancel(wl_client *client)
  2669. +{
  2670. + const auto touchResources = resourceMap().values(client);
  2671. + for (auto *r : touchResources)
  2672. + send_cancel(r->handle);
  2673. +}
  2674. +
  2675. uint Keyboard::sendEnter(Surface *surface)
  2676. {
  2677. auto serial = m_seat->m_compositor->nextSerial();
  2678. diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
  2679. index a1af137a..00c439e1 100644
  2680. --- a/tests/auto/client/shared/coreprotocol.h
  2681. +++ b/tests/auto/client/shared/coreprotocol.h
  2682. @@ -158,7 +158,7 @@ class WlCompositor : public Global, public QtWaylandServer::wl_compositor
  2683. {
  2684. Q_OBJECT
  2685. public:
  2686. - explicit WlCompositor(CoreCompositor *compositor, int version = 3)
  2687. + explicit WlCompositor(CoreCompositor *compositor, int version = 4)
  2688. : QtWaylandServer::wl_compositor(compositor->m_display, version)
  2689. , m_compositor(compositor)
  2690. {}
  2691. @@ -273,6 +273,9 @@ public:
  2692. OutputData m_data;
  2693. int m_version = 1; // TODO: remove on libwayland upgrade
  2694. +Q_SIGNALS:
  2695. + void outputBound(Resource *resource);
  2696. +
  2697. protected:
  2698. void output_bind_resource(Resource *resource) override;
  2699. };
  2700. @@ -364,6 +367,7 @@ public:
  2701. uint sendUp(wl_client *client, int id);
  2702. void sendMotion(wl_client *client, const QPointF &position, int id);
  2703. void sendFrame(wl_client *client);
  2704. + void sendCancel(wl_client *client);
  2705. Seat *m_seat = nullptr;
  2706. };
  2707. diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp
  2708. index a415cbf5..b1d3d07d 100644
  2709. --- a/tests/auto/client/shared_old/mockcompositor.cpp
  2710. +++ b/tests/auto/client/shared_old/mockcompositor.cpp
  2711. @@ -342,7 +342,7 @@ Compositor::Compositor(MockCompositor *mockCompositor)
  2712. exit(EXIT_FAILURE);
  2713. }
  2714. - wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
  2715. + wl_global_create(m_display, &wl_compositor_interface, 4, this, bindCompositor);
  2716. m_data_device_manager.reset(new DataDeviceManager(this, m_display));
  2717. diff --git a/tests/auto/client/shared_old/mocksurface.cpp b/tests/auto/client/shared_old/mocksurface.cpp
  2718. index e9df5f90..c3246e4a 100644
  2719. --- a/tests/auto/client/shared_old/mocksurface.cpp
  2720. +++ b/tests/auto/client/shared_old/mocksurface.cpp
  2721. @@ -125,6 +125,16 @@ void Surface::surface_damage(Resource *resource,
  2722. Q_UNUSED(height);
  2723. }
  2724. +void Surface::surface_damage_buffer(Resource *resource,
  2725. + int32_t x, int32_t y, int32_t width, int32_t height)
  2726. +{
  2727. + Q_UNUSED(resource);
  2728. + Q_UNUSED(x);
  2729. + Q_UNUSED(y);
  2730. + Q_UNUSED(width);
  2731. + Q_UNUSED(height);
  2732. +}
  2733. +
  2734. void Surface::surface_frame(Resource *resource,
  2735. uint32_t callback)
  2736. {
  2737. diff --git a/tests/auto/client/shared_old/mocksurface.h b/tests/auto/client/shared_old/mocksurface.h
  2738. index 949dc23d..d176837e 100644
  2739. --- a/tests/auto/client/shared_old/mocksurface.h
  2740. +++ b/tests/auto/client/shared_old/mocksurface.h
  2741. @@ -65,6 +65,8 @@ protected:
  2742. struct wl_resource *buffer, int x, int y) override;
  2743. void surface_damage(Resource *resource,
  2744. int32_t x, int32_t y, int32_t width, int32_t height) override;
  2745. + void surface_damage_buffer(Resource *resource,
  2746. + int32_t x, int32_t y, int32_t width, int32_t height) override;
  2747. void surface_frame(Resource *resource,
  2748. uint32_t callback) override;
  2749. void surface_commit(Resource *resource) override;
  2750. diff --git a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
  2751. index 80429608..68e8d77a 100644
  2752. --- a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
  2753. +++ b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
  2754. @@ -55,6 +55,7 @@ private slots:
  2755. void primaryScreen();
  2756. void overrideGeometry();
  2757. void changeGeometry();
  2758. + void outputCreateEnterRace();
  2759. };
  2760. void tst_xdgoutput::cleanup()
  2761. @@ -134,5 +135,39 @@ void tst_xdgoutput::changeGeometry()
  2762. exec([=] { remove(output(1)); });
  2763. }
  2764. +void tst_xdgoutput::outputCreateEnterRace()
  2765. +{
  2766. + m_config.autoConfigure = true;
  2767. + m_config.autoEnter = false;
  2768. + QRasterWindow window;
  2769. + QSignalSpy screenChanged(&window, &QWindow::screenChanged);
  2770. + window.resize(400, 320);
  2771. + window.show();
  2772. + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
  2773. + exec([=] { xdgToplevel()->surface()->sendEnter(output(0));});
  2774. +
  2775. + QTRY_COMPARE(QGuiApplication::screens().size(), 1);
  2776. + QScreen *primaryScreen = QGuiApplication::screens().first();
  2777. + QCOMPARE(window.screen(), primaryScreen);
  2778. +
  2779. + auto *out = exec([=] {
  2780. + return add<Output>();
  2781. + });
  2782. +
  2783. + // In Compositor Thread
  2784. + connect(out, &Output::outputBound, this, [this](QtWaylandServer::wl_output::Resource *resource){
  2785. + auto surface = xdgToplevel()->surface();
  2786. + surface->sendLeave(output(0));
  2787. + surface->QtWaylandServer::wl_surface::send_enter(surface->resource()->handle, resource->handle);
  2788. + }, Qt::DirectConnection);
  2789. +
  2790. + QTRY_COMPARE(QGuiApplication::screens().size(), 2);
  2791. + QTRY_COMPARE(window.screen(), QGuiApplication::screens()[1]);
  2792. +
  2793. + exec([=] { remove(out); });
  2794. + m_config.autoConfigure = false;
  2795. + m_config.autoEnter = true;
  2796. +}
  2797. +
  2798. QCOMPOSITOR_TEST_MAIN(tst_xdgoutput)
  2799. #include "tst_xdgoutput.moc"
  2800. diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
  2801. index 2277bbb8..afbeef53 100644
  2802. --- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
  2803. +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
  2804. @@ -31,6 +31,7 @@
  2805. #include <QtGui/QOpenGLWindow>
  2806. #include <QtGui/qpa/qplatformnativeinterface.h>
  2807. #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
  2808. +#include <QtWaylandClient/private/qwaylandwindow_p.h>
  2809. using namespace MockCompositor;
  2810. @@ -45,6 +46,7 @@ private slots:
  2811. void configureStates();
  2812. void popup();
  2813. void tooltipOnPopup();
  2814. + void tooltipAndSiblingPopup();
  2815. void switchPopups();
  2816. void hidePopupParent();
  2817. void pongs();
  2818. @@ -138,6 +140,7 @@ void tst_xdgshell::configureSize()
  2819. void tst_xdgshell::configureStates()
  2820. {
  2821. + QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0"));
  2822. QRasterWindow window;
  2823. window.resize(64, 48);
  2824. window.show();
  2825. @@ -154,9 +157,12 @@ void tst_xdgshell::configureStates()
  2826. // Toplevel windows don't know their position on xdg-shell
  2827. // QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
  2828. -// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
  2829. -// QVERIFY(window.isActive());
  2830. - QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
  2831. + // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
  2832. + // XDGShell this is internal to QtWayland so it is queried directly
  2833. + auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
  2834. + Q_ASSERT(waylandWindow);
  2835. + QTRY_VERIFY(waylandWindow->windowStates().testFlag(
  2836. + Qt::WindowActive)); // Just make sure it eventually get's set correctly
  2837. const QSize screenSize(640, 480);
  2838. const uint maximizedSerial = exec([=] {
  2839. @@ -186,6 +192,7 @@ void tst_xdgshell::configureStates()
  2840. QCOMPARE(window.windowStates(), Qt::WindowNoState);
  2841. QCOMPARE(window.frameGeometry().size(), windowedSize);
  2842. // QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
  2843. + QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
  2844. }
  2845. void tst_xdgshell::popup()
  2846. @@ -340,6 +347,92 @@ void tst_xdgshell::tooltipOnPopup()
  2847. QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
  2848. }
  2849. +void tst_xdgshell::tooltipAndSiblingPopup()
  2850. +{
  2851. + class ToolTip : public QRasterWindow {
  2852. + public:
  2853. + explicit ToolTip(QWindow *parent) {
  2854. + setTransientParent(parent);
  2855. + setFlags(Qt::ToolTip);
  2856. + resize(100, 100);
  2857. + show();
  2858. + }
  2859. + void mousePressEvent(QMouseEvent *event) override {
  2860. + QRasterWindow::mousePressEvent(event);
  2861. + m_popup = new QRasterWindow;
  2862. + m_popup->setTransientParent(transientParent());
  2863. + m_popup->setFlags(Qt::Popup);
  2864. + m_popup->resize(100, 100);
  2865. + m_popup->show();
  2866. + }
  2867. +
  2868. + QRasterWindow *m_popup = nullptr;
  2869. + };
  2870. +
  2871. + class Window : public QRasterWindow {
  2872. + public:
  2873. + void mousePressEvent(QMouseEvent *event) override {
  2874. + QRasterWindow::mousePressEvent(event);
  2875. + m_tooltip = new ToolTip(this);
  2876. + }
  2877. + ToolTip *m_tooltip = nullptr;
  2878. + };
  2879. +
  2880. + Window window;
  2881. + window.resize(200, 200);
  2882. + window.show();
  2883. +
  2884. + QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
  2885. + exec([=] { xdgToplevel()->sendCompleteConfigure(); });
  2886. + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
  2887. +
  2888. + exec([=] {
  2889. + auto *surface = xdgToplevel()->surface();
  2890. + auto *p = pointer();
  2891. + auto *c = client();
  2892. + p->sendEnter(surface, {100, 100});
  2893. + p->sendFrame(c);
  2894. + p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
  2895. + p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
  2896. + p->sendFrame(c);
  2897. + p->sendLeave(surface);
  2898. + p->sendFrame(c);
  2899. + });
  2900. +
  2901. + QCOMPOSITOR_TRY_VERIFY(xdgPopup());
  2902. + exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
  2903. + QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
  2904. + QCOMPOSITOR_TRY_VERIFY(!xdgPopup()->m_grabbed);
  2905. +
  2906. + exec([=] {
  2907. + auto *surface = xdgPopup()->surface();
  2908. + auto *p = pointer();
  2909. + auto *c = client();
  2910. + p->sendEnter(surface, {100, 100});
  2911. + p->sendFrame(c);
  2912. + p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
  2913. + p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
  2914. + p->sendFrame(c);
  2915. + });
  2916. +
  2917. + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
  2918. + exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
  2919. + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
  2920. + QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_grabbed);
  2921. +
  2922. + // Close the middle tooltip (it should not close the sibling popup)
  2923. + window.m_tooltip->close();
  2924. +
  2925. + QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
  2926. + // Verify the remaining xdg surface is a grab popup..
  2927. + QCOMPOSITOR_TRY_VERIFY(xdgPopup(0));
  2928. + QCOMPOSITOR_TRY_VERIFY(xdgPopup(0)->m_grabbed);
  2929. +
  2930. + window.m_tooltip->m_popup->close();
  2931. + QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
  2932. + QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
  2933. +}
  2934. +
  2935. // QTBUG-65680
  2936. void tst_xdgshell::switchPopups()
  2937. {
  2938. @@ -505,15 +598,17 @@ void tst_xdgshell::minMaxSize()
  2939. window.show();
  2940. QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
  2941. - exec([=] { xdgToplevel()->sendCompleteConfigure(); });
  2942. + // we don't roundtrip with our configuration the initial commit should be correct
  2943. QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
  2944. QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
  2945. window.setMaximumSize(QSize(500, 400));
  2946. + window.update();
  2947. QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(500, 400));
  2948. window.setMinimumSize(QSize(50, 40));
  2949. + window.update();
  2950. QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(50, 40));
  2951. }