aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Fish <gentoo@seaofdirac.net>2019-07-18 08:12:17 +0200
committerNicholas Fish <gentoo@seaofdirac.net>2019-07-18 08:13:21 +0200
commitad4a9a5ae982f9484088a945cd7dc9bce395fa9b (patch)
tree5525ba80fbfbf9c8316dd974cfc1d40ca00da60c
parentx11-libs/vte: Fix wrong patch filename (diff)
downloadennui-ad4a9a5ae982f9484088a945cd7dc9bce395fa9b.tar.gz
ennui-ad4a9a5ae982f9484088a945cd7dc9bce395fa9b.tar.bz2
ennui-ad4a9a5ae982f9484088a945cd7dc9bce395fa9b.zip
mail-client/thunderbird: Add with support for running under Wayland
Signed-off-by: Nicholas Fish <gentoo@seaofdirac.net>
-rw-r--r--mail-client/thunderbird/Manifest65
-rw-r--r--mail-client/thunderbird/files/firefox-wayland.patch4441
-rw-r--r--mail-client/thunderbird/files/icon/thunderbird-unbranded.desktop9
-rw-r--r--mail-client/thunderbird/files/icon/thunderbird.desktop9
-rw-r--r--mail-client/thunderbird/files/thunderbird-60-sqlite3-fts3-tokenizer.patch99
-rw-r--r--mail-client/thunderbird/files/thunderbird-gentoo-default-prefs.js-210
-rw-r--r--mail-client/thunderbird/metadata.xml36
-rw-r--r--mail-client/thunderbird/thunderbird-60.8.0.ebuild610
8 files changed, 5279 insertions, 0 deletions
diff --git a/mail-client/thunderbird/Manifest b/mail-client/thunderbird/Manifest
new file mode 100644
index 0000000..71374e0
--- /dev/null
+++ b/mail-client/thunderbird/Manifest
@@ -0,0 +1,65 @@
+AUX firefox-wayland.patch 168461 BLAKE2B b1f2e2ebf3231b3fd822a37b0d12eaa660c5756d6811c30d95cdd9d6f391922dbf788bfbf2a14ac65c5080b5bd3f199fcc6f273a1021d5b41452da524c0cfd74 SHA512 057501ee104601c44545c48ee1ac6cb8fd4a2b64ce56676cd385488013ae3fbf102c57ca318f8a8a57a3ed97bfcc476556a7ab32ec6a9bd7a4dd4bcf925d4050
+AUX icon/thunderbird-unbranded.desktop 228 BLAKE2B bde0c9dab7c25115f65f08149abbae88f404ac3b4559664e1f6d07ade609e8e15fa91c8054c98adac0794458c2614f5f518c2cd41b97faaaa3dbd8a382d9f767 SHA512 c118873cd701f3582d18ebf5c9622b4c593bd9bae51079ec3daf9fd54aceb4b1406f2de20cc08499ced752cc7b4b2183de6777693c5e6853e47714a4df2a6e4a
+AUX icon/thunderbird.desktop 218 BLAKE2B a9c32523f4a4066c02b7971d073ecc9a033c0ed62088691b5cf3003fee7483e80d290a286a8602e113ff89f38d55380869b569f6c7535b51b17c4917ccc3f031 SHA512 0cbe132759012c0da6f81f37d4ede62d2f4138f0d95e590da6259d7593ad858de28467b393e5d6129a6d37d61afa9b078df0f5a8b6a259189860653c44350a72
+AUX thunderbird-60-sqlite3-fts3-tokenizer.patch 3721 BLAKE2B 585af92daf9db441e065510b6dde64280fd6098ff2e9a53d1346ade91c279fbb75d4c8979b36ce61244a43fdc4c51142419deba7dd4a7c8a1ef1a987d5000c10 SHA512 0796db157f5c871c8871d2515ffae943e60ee4b3fbff60ef8f1ef535e5401a4a23ac69042b08c35cc27ccb4049daa92e0ba52dbff0abb6a6a49732f2b3f59003
+AUX thunderbird-gentoo-default-prefs.js-2 461 BLAKE2B a18e1fdbab7ad81feb41af75e60f48adb960800849630a6f9253b7bebcd3e7db33b2517ad0be6302609545a5464b84bd5c5fc67a07fb2ceab0ca1ad98539bee0 SHA512 db115d89a094c395636e5c008307c7864cb084a0a4ebd024d4ce33cac12963cd4a9ff6833227adc6a098430dc3f7ca9e386e26b87400d46920f4ef15741aefa5
+DIST firefox-60.6-patches-07.tar.xz 37404 BLAKE2B 5516ff768bee0253131381fdba3e08785ab31bb29e44ad7f7e2956fb7624fafc9bf22f892ddbd0617e5e7d18500686a9975a60ea77d23a2853f35936cd142030 SHA512 3c4160e632155b0a239e22d0c1b1c701545b0f6d0915f9bdcf3b8431cee1abf650191ffafc5c3224a61279c8b1b52a80444c811a3914e16127411991c963292b
+DIST gdata-provider-4.4.1.tar.xz 78728 BLAKE2B bfe04d714334c38c932d2186ffd859583176ef455b283534c5f8f9e1ab7dc13bdfb8c15db6007de482ab015afc2b8524aad725380bec75ee5f59ea81d6307ba9 SHA512 6c9b5ac41a1064bd1799d2a2f633c3064b27f1294ac3c8908cdef6c1d2eea7b602f2f7bf240b71f507fe9ad286588f030e12f49a41b3bed7bbcc99f3021369f9
+DIST lightning-6.2.5.tar.xz 1745976 BLAKE2B 31e237f8d34ab2a2ac522767460467257d1f49d15fbe24f5b80dde9fb709ffafd0c0442d99c6643ce434cf7bdf0d670447f86da9fcdadc7ada6814431ef41e8a SHA512 1e997bb91d484908f225cc6e971874d308e8a8e2451a3e678f8a74bcb9e360babbd1f8aebcafb3e628ef5b10eb697ee47af2bfedbc956fee71d99084c8816235
+DIST thunderbird-60.0-patches-0.tar.xz 10292 BLAKE2B a81ac6708389baff21accccac1511c1fc372324cac8bb3ee0f3b5d2a0690b6e22ef658b41c887b99168b43c4ea4bb0947d3e48ad9b7e80db558db22c976df868 SHA512 1dae465676b2ff4faae08ebf69e6bac46552bc0331659bf5f444c45b026e4c8d2fc46cd3758e3bd121716aa85d5dcc56de6483919f7f0077b9d9720574dbd1aa
+DIST thunderbird-60.8.0-ar.xpi 627180 BLAKE2B 31d1631f7ec6320830dcf3545a5c3bd9fa346c6d8807e25f8c2071e7dbcb9c04858f2982407154d68abce45277ba96f650971268c389be4691f546464813725f SHA512 c92af1c4eef761c30ac2bbd6a333a18826534f35bbe6f5a0da342cb9cd354151bff4bbcb48cf0b804657de1f8e67c385c4c6ebf14d92a0a6cfc39f34586f961a
+DIST thunderbird-60.8.0-ast.xpi 559643 BLAKE2B 763f6bce63732bec4b01c28f597e2e1948394f5cb8a404f0bcf5ffaef663d8b9ff3e8b09141989347f944e16c841255bbf32ae50614aca25e12e5f2968872e9c SHA512 bb61302d2e14362819a99df3de4e6309f778f025f85758b927604391a0f872d6df63a0b69d669f008972863fcc230a345c1cab9b961d5df4e2a403648c484a3a
+DIST thunderbird-60.8.0-be.xpi 659079 BLAKE2B 698ee1c4c58a8d5e6ddcedfe439ebd4e91a648ae9fe7d7040075f5cdeed733442ab6b933bc10389b58d2c35eaab14735dfb2eabe65e2ce956d0f133c51f4e27c SHA512 a73da736f77c7ff6947534aa7557ec11ea302ff378394d5ceb2cc1b6365bb36f81b556dfbb66c5521ded65168f2fae3a03cd3cd0f59d030093553590a21950e5
+DIST thunderbird-60.8.0-bg.xpi 669318 BLAKE2B d3017dc198e9aa0884a63adf52c2dd5f617613403d1b882d21e040310c2047643a944ec91d069ad9c8cfe89369a09a097ff8c056cfb0c39c7d18e8ddad5438d0 SHA512 0fa3b36072a4d3371e07169990cc18ed8af73dbe824cfd5af2f216d059781f4c56081644e86c26a7b7150257e475c5204a41d72bfe99e327720df70ea6cd01c3
+DIST thunderbird-60.8.0-br.xpi 580370 BLAKE2B aa38fd21ded1067ca1bf5324a8abf02b2ab767591b7bbf5d43c68650d3428c35eb91f72e14189cad542f72ec8cc2709a6d443f3097e85e17921e40601552f66f SHA512 44d3b65877c63a0af035015d7c8013e1577760ca91e367edc5236e293d27dda6eb5166f608aa660fc09e7cb830598890f1ae52f3f296ae6169b16da57cb867e0
+DIST thunderbird-60.8.0-ca.xpi 591971 BLAKE2B d73e5322ef1541047ad3fc52d37a1dcfd666aa86821cb310c8bdf6f9bab0a752dffe434c775f663ec526287bc8eeefaf721d9fc9d8f7d8803174e859bb51599b SHA512 7daa322f628acaf38ed3df27c07f25cc79cff78d2ddf4edb3c499032519ea387bec028954744fe78736c96faa8a8d2c25158ff304ce2af5903d02b61a944d60e
+DIST thunderbird-60.8.0-cs.xpi 611203 BLAKE2B 7a180af22d94001026ade7c38bbbb87d498308899cf988fbcfac99ac99124d815371cf60624502996d9593ce6f45d76a8b8f7400b6944c3ba7c9d57ac3bbc9a8 SHA512 64697bc83c0db92bd48e6a29e3520056e86afe7f12475a96b1b593781cb596baea500736347d51e27fc2f0a11359ce69bc6cfbc07f4354a2a3e1946944b0b5dd
+DIST thunderbird-60.8.0-cy.xpi 586039 BLAKE2B e98e6f253f83f4766a3e4e5981129e2a42be38c6cbffcd012be2d59a128fe4f5ba5a13593147fa758c958e375edfc1e6256da65f803573342848e96f6c489918 SHA512 df91f59b9e93e7a467657c4102f28d999833f19e3a810cd39c090992da89f6ec62aa34ab391b651b95ca1e38ec8fc44f9ee401ad104288b52b7d8313da3a41ca
+DIST thunderbird-60.8.0-da.xpi 570807 BLAKE2B b64d07878b20b7e38cebd5cb7ad96ebf21dac66b82665bfcce02abb6475faa772937b983de87326e5ac6a4867a3a90934d26afda49d18fcc714da3f869ee0691 SHA512 a2de79bf83c5eb1f77f175e97332fada1bda0cd353e0ad575c7ed568a5775fb508cb48ea751979c13f848f8fad66b06019d381835e22b0b41632d4e2b1d5f924
+DIST thunderbird-60.8.0-de.xpi 582575 BLAKE2B 544ee241959f6b0f0acad13c01c20a114fd6b4090250a5b700b9a56ae45b7a6e017437987760d9d215f93fc89ee8188d2ea6fcb4306b0e45ddfd91e467eb5aa6 SHA512 6bde7bc5e4c1d16b2ce758b7dddb3975b39984e07f73825f58c0c030c29d47e0968d7de0deb2a144e86f8e73e87e01a39712552d4d7d22feb20a7dee3c6564d5
+DIST thunderbird-60.8.0-el.xpi 694860 BLAKE2B df7c3e197fde52f53b627f2506b9b0d54fb6eddcccbfb920f1c83711f3bdf3829a646a9fc3960d436428c0f07e4fd0074c11b32e222fc6c1374e4ce2c047a32e SHA512 0be4a1ab3444a7e2b53ddfbc4774bbc0ced663ff726cbb173550050342f935fe1bfcfd8aeabf556a16c0a3bc0b2f4483a4851c5d86fe9939d79f11169fc5e44c
+DIST thunderbird-60.8.0-en-GB.xpi 553895 BLAKE2B 238c7abb07405834f9e29d911e99759712b5e2b795dc8ab51c5810ed0769b0f063a692db67ff9e1aff75ee1d2c1b3b49fc36e149c022ce3e2aa717132e212901 SHA512 e955f9ea391eea87dec7981f5b88c0a43a8dc86212798abdb921a8b4ce048e7d617f864f926686fa073b7bb6789b4f7f39969df2a319f571c7fb991c4bb981d8
+DIST thunderbird-60.8.0-es-AR.xpi 595049 BLAKE2B 0ffe6c2b300aed0da718d29a276f024e4bcfb71d9158b034817ea585a2e26f8204251d199331ddd6e67bb4a7f4ee0251297bf4ab67412c448c5a22fe4d542eb0 SHA512 bd036fc6c83065ca148955a9c92e148980b6d93f7730eb08faef8f7449b32eeecaf8f8c2caf05050302a010709b377d8e9b81a5ba00a12c8fa53fa1303c2a88c
+DIST thunderbird-60.8.0-es-ES.xpi 492212 BLAKE2B 620087bfdc780f9666c820098b8ce6ddc8169514c32a40e64207956ba7b430f39f51248759f45cc4c6154b943c3fd0d5306f19e6ce419635cc0c6af0f60bcf05 SHA512 b48debb9aa2c64074e5dd315140bf0a09126345dc05a1685ea9dec18d25b7cd639b1c07167764ec0823f623cc83524daa07898105098dee6a03e1770d60e42d7
+DIST thunderbird-60.8.0-et.xpi 570868 BLAKE2B a3f9216422e27c75cd9cee262d6deac3d93185c14c6f6179e7306ad0e77e1edcef43cbe1e8778f1497174e6debb79fcdd95c2e69403dd9de59fc3f9f1772f7a1 SHA512 2b0a5455c1664877fe5530422248e8fbfcb1b97e68e264a1fb771ed787f4baeeed758fed4be66a0c389888154fd5f08de8032ab4651188c35cff9fe8a9525371
+DIST thunderbird-60.8.0-eu.xpi 581385 BLAKE2B 70870b9e17677a826486f08f293f9272368756d5bd5dbf0ddb0119df3b7a4596eb5e1405568e3574f40744ddfc48f52e8e56bf47b2f3f704d5a2e6dffc4d0e56 SHA512 30ef0e8dffcb2b42ad3efe43c8a0ab6895a757ec4406de6911f6444840384e427bcb517f8d4eb7a8294567d55f67545c4b8ce593aa063f2e843957c17eac715b
+DIST thunderbird-60.8.0-fi.xpi 575755 BLAKE2B 3176cdedb8a8c9dde11e361687716d3f8978dd3582b0ce677a84967a3bc7a595be37da52f9d22e2a03afd10ace0235ab8e15a9ba34b27ae0babe61cea19aad0d SHA512 b6595fa0e1ca4baa353705c0067ea05a4d1daade48c7de057356a5aeaccc19d666a0648ce2ff5108ccd3464ed3f4e1b59cac48dcba1991426373a04fe1323230
+DIST thunderbird-60.8.0-fr.xpi 608467 BLAKE2B c6b368a0b0a573ad5fe24f473c472ab3250a441a899b11c5971c614a863714ddc3683ab50183b7d408ce371fe3c06759ca2de242884f1796198c272230bd5e71 SHA512 bd76b229973e795516fe6f6c8d3dd60da986a26a915a622450e823043741c8fe6d526d29cd3566faf5bcd78109da89853747a24790ce448ea4f4b072efc18c8a
+DIST thunderbird-60.8.0-fy-NL.xpi 593851 BLAKE2B 37898ec4c76a8741fa3e896160f2ca28686f2eb85af3d5c709df7a68a39a47c0e95408f4c4e46a6de5349699259a390071cd4a559f583377cdcd783e20925ac6 SHA512 d8c359757cb0514271208977df3dc4b40f49287001198fb09e3199866f0712d0bf7c3f4ade3216cd08601ffa7c6b8cf2ca7e2cc91856819d013bfa43940c794d
+DIST thunderbird-60.8.0-ga-IE.xpi 603506 BLAKE2B 7c76830f4d1b34e7ddeef6498a2ddbced3cd07d9d7bc75deeae78792ede033de173f9a0e95cbc93f668f2be56c2c5f07e5bd3c93aac6f216cd0355ed70cde005 SHA512 7f1c59d222fc98825f3aa8eea6c6a122aa904402d3d499d67d26743588da003c6e92214e1492a1b6aa853397161c3d450c6fa4830ba5e3ea75a8fcbfc1f4e662
+DIST thunderbird-60.8.0-gd.xpi 599262 BLAKE2B ed96d797e80caab3867185c0f9d8afa51b1a6d0ae1d37e6a810dba2f9041bac2a16e7d62b0bf149aa2da9ef06f8dd8d46d31f0d05dcae0c0e7364d9dfbfca8c6 SHA512 bb6f36d842a06e34199bf90bb8511b1a91d79fb0c6e073f125b0a555f344d531bcdb9bf78c804472414fcadcff0e66a9bebdc64e0d0832e19fce5dbe3671f3b6
+DIST thunderbird-60.8.0-gl.xpi 580343 BLAKE2B b12d06a801864c9627569f0dbe6b77bd5d2c68b30bc0159d0bba3030b88c26d3252e735bd1d334859b5793170e57cef0002ef84605e216e9328b3644fc9daceb SHA512 666f13a8229f73966456975cc51db9bfbacf2645f887cc072ae0998f227acd6f33c4fafee8a7805f8e8850c9043ed6a05ef9b9fd261c1ec9ebc53127bab2d26d
+DIST thunderbird-60.8.0-he.xpi 617144 BLAKE2B 832e397c908af6422314231333db15f1cb75e307136839e8253d4657456ae2985f8d953e5fe2f5ab5906688fc5c3817c9242b7b24ee006b8549ec95b8321aa5d SHA512 40e66995e06d39d11062955257761d3a6539bbe86849fb14f0a9b111d5556d7edd591abf2a4498ba7e226c2fa13031ebd2f0cb768cdfbc170249cf0586915608
+DIST thunderbird-60.8.0-hr.xpi 582239 BLAKE2B 199bb41a3745cf5aa7d72627d5e2634ef093ed0d93b78be9223a5a4fb5f00f17945d2a37bd1124991b7e6ead746fa0a158ffe08a35f731f88955fe292b6dee81 SHA512 eade1cb89a5c5ec4dfda113774c6a93f68676faf584b0bcc4b6d25ca45c635b3e7e48bde6748e14b899ec0ab5370e1259dfdda0f6a3221bc6b4eac79d2675295
+DIST thunderbird-60.8.0-hsb.xpi 615132 BLAKE2B 4e1e51adf45fd1d09249691fa17c19d0ef522eb8041a301248a9943c7def37f3b604defe531743550ed0cc8788d58f33d21aa95cc97afb4402e929e2a4d978ed SHA512 3efafdca843a17dd950e637fdf58b4003b21ed76afd52021c0b5f428cb218370b57a7784be2db5be7e2c23a937089a5fca10463b778e2d080cb7b7d507838a77
+DIST thunderbird-60.8.0-hu.xpi 615345 BLAKE2B 3680b726ff6b5182d6e1756d2520dba3417939b4a17e5731573182523d32c92c1d0bf11ed6abc9c48713c80590c557176d6858ce0312003ae2e838076dc95eee SHA512 b33b88f566f42e0bc3a80ea2b1e3300addfe0379af5997cd53da4ed6af67bceb2c6a1396de78f788a14b9541518f118e7ad455fe78512019a6cfad5e899d7c17
+DIST thunderbird-60.8.0-hy-AM.xpi 653531 BLAKE2B 249acc09dd0e527c189c0a1602b78ce17d0ae19687ccf80229e3c0aaa8783ea3123da47657432730425a012b6bb73f54b1c3a59eb8ee00ceda24c86d15c0e1a6 SHA512 7c03aac474651a64d7714074ab9b0264fbacd2858f87bb014edd0404111335a5ca36eb3e469a515a83aa036a5439ec4110c42680b3a8b49412c5c072662e1191
+DIST thunderbird-60.8.0-id.xpi 568861 BLAKE2B ce63557ba7626aa03eb4bc395ab7f9488077cb51924b91a87ba7cf0e7f0f4c9b25854f0f778dda7edeb330ae2e3a621018998e9aff87dc4d019f0c91f8e4cdb8 SHA512 685424c205f9d89ae1105beff1964afcf511b44450b6b0f9e19d49e5fbc9edc70dab7533c7c9e2b107bdceb0c0bd9eeff8b9814dff08debb9dcacc681c408c9e
+DIST thunderbird-60.8.0-is.xpi 579047 BLAKE2B 0a1cccf5be68e79273ed4e4943a348065a7fb33c2b5571e5f0ae9a0d2a2edd2f262e29ba3fa17311b5105a8b55fc107fa0eb69da46a5447da5e317d8c187584c SHA512 e1bceb4c8fec5582c8a1eebaa03c6f64876b2d6f4d8cc921a4a76eb380f361003109ddfe05ec249fe8eaaf4c6606e68ed4f55bd93b5160f058abd611de9c1e55
+DIST thunderbird-60.8.0-it.xpi 477500 BLAKE2B d0a8cb5f781781e16aba1b303e17e51eccf2d04a86670e6195c8ca14b909229bf5d2f9b978b2a43dfca5249a23bf6974ecd156cf075394d3565036308f974516 SHA512 fa4cc59f1b64a532b2d31c2ac82f8153284b0135a669b3da36984289234f54ac94474885ab73e525384f3cec93c46ead53d00fa888d3163663696d94a06cf460
+DIST thunderbird-60.8.0-ja.xpi 653344 BLAKE2B eb2e2cb15de3a8a0f935c6e6b167e93e3178ed7295e084fb4632784ee4d2439939efca2341a2b21a6e6cbf40ebad1498fba8fc5ac9cea37db1d8e856650f4af3 SHA512 670a582a4bb8c52903bf00b3aaaed74d9ca29c58a7ee989f20d006771c2e00dc4b512db51617f1c9e65a98441901cb31b9933189a5af07f96a11c4632afd4358
+DIST thunderbird-60.8.0-ko.xpi 619731 BLAKE2B b46a1fe32e63269935ecf697e327f8f25477ce05987bd51fb673e3265985c48b3097395f1e96680eb06af4b149be286f3ac97a459412d15b36026dccbc4a173b SHA512 cee7843a94772578145f03a4726b0d60ea513800365cd7c2fa85c94fbeca536ca45d5203fd091d6333834e6345aa31febdbd27535ed7a11782b80e597765d8e6
+DIST thunderbird-60.8.0-lt.xpi 605441 BLAKE2B e1ed67ec3ecfe5b741cf49537802d3ba634d8ffa562bfba7eb4d8d55c2c76321d70fa5cf2d711231225000267268d7e1df768bc4aba6ec13bc9c3720492e6332 SHA512 7779f34c8c041c29672781cb9e48934fd81ec6a3d2af95db9a39e33c650517d510e527578b8355fcb87b6442b0998004ebf07a57c060d8818c156bbd2487a548
+DIST thunderbird-60.8.0-nb-NO.xpi 577003 BLAKE2B ee86125d4c34291182a98197c4706555e2003b7667ad516341382f3b351670660398f9077cd49901751e4bd58dc2cd37f43ee556bcaadff500260ea98c6e2899 SHA512 53f956cc91a834c69d711fb23f7c4628159d7e3c3a33af9b861c0666bc26279c41c793906a332040c2caa3404a5a71aabaf4082995eb94121ee3a75a5e3745d6
+DIST thunderbird-60.8.0-nl.xpi 583914 BLAKE2B 104a06a3edb470d8bc2e1187f41d5edd28f083a4e93030e7c8a2150833e2e0f2abde9b7257cec7193db0dde5e602b7506cf2f2b8f63680d04fce41cc7729e554 SHA512 44001fcd69c370e12c55891afbe5be79cd7360d3e8b677f1682b4c37601c6a0dcdba68525e0627a537018d1c84b0810fa6b241d980125589f30818cd614cbcdc
+DIST thunderbird-60.8.0-nn-NO.xpi 576422 BLAKE2B 698d282efda0750ab2bdaa818c3f827286d6225f0969ea16a2de1e727bbce02434b08f7f409e0604708b5f813d2a96297e0d24daaf48dc2e572d32db1e4fd03c SHA512 644e7440a5a47c34a281484a3c16c55037eba782ce51717adfc4306f38720a0d4dfa24b59344bbb1affb03de55dc21984b58497450912235cc96668fb9aba748
+DIST thunderbird-60.8.0-pl.xpi 480726 BLAKE2B b3d10588582f8855d714d505e1cba7da8e6a67f1ba752cea52c1396ddcc79d0ba57774889ed3fb7168f8468bb2d3cdb44c11bb457483e8729010f130be900d24 SHA512 ae494b7bd0e0f1287ee6291e6b4bd2b869a8f4ef74113aa88cc53789a75b4190e9d128641feea425804a6a26f853686c4410bb5bcc7253ab89500255a07db03c
+DIST thunderbird-60.8.0-pt-BR.xpi 588834 BLAKE2B c1b2bb38edf447d91642f766e5b394cb44e230c7011b8296979102c5ffc93880e811bae5a7b13efc45e95d06ade6a60e8c21ae162dfbe65c8703dfdf373b03b9 SHA512 bbefc1b55be40d9be280292bd48c48e555dd2d6535f16b4155940e2cf3f2119b6b0d3da7fa83d66e5f530eb5b3c40aa4b7125d249feeb8177063888c26530568
+DIST thunderbird-60.8.0-pt-PT.xpi 593186 BLAKE2B 8e5804d07d6b62f798598365ac407443e5fcdd49a304bb6135fe3fa88a4f1d62718160082986f35854114708cf43931984ae15c948bb986a58bcd03752a69c4d SHA512 b88106161385d9853febfa40666d5fad961fbd331030e382f6ed681ebeb5046fb50daaaafd04a551bc9dab9f50e16aea3fca678d09de93461b4279933314431a
+DIST thunderbird-60.8.0-rm.xpi 578384 BLAKE2B 6527bd3b39ebc26a7d13fa1d5d99ca26eb3547925d36638151c489694c0eb8a74a2758397ae60304b1504680b7181c20a1e86280889f274d1c87e6396cd4a25a SHA512 b7cc627d0c8d367dc6b6ea9a56d5e60dfbec41708cd36c38856d5cee3e9e5cfe7949681fc00714105b6f9d989aa26ec56eac3c3165402f091deb83fbdc01de72
+DIST thunderbird-60.8.0-ro.xpi 584308 BLAKE2B a2c247aaf096cbfa955645c45c8ffabfebaf93dea4c8ab0f7904ddfd3de0e0b751bd4ca06a000ca2e7d74ac959a131c592f3a942fc4a49f21e0f5f96923c07cd SHA512 d413a9f5e04520448b38f5e8729b0ef939a409edd6e8c5409c3fef397056fba0a0d0b323c04c203114b3e5cb37fd406242f9e508e25707719d4eecfecd99f557
+DIST thunderbird-60.8.0-ru.xpi 694706 BLAKE2B ede404c70f22ce9d9cf54c9551386a62cac1c6ca5cd64219fd4cdf793ce26390107db9b04fdc22885aca1c1af36d1e4ec9f95256f840fa7655cee943ad083d97 SHA512 9b868097cb556cff75d59c55fcb56c7688cd844703b346d629e21669d0d10df2dd2c5d80aac2370a62f3eff261819102e6b25be14dc30f3b64fd3234fc0c487f
+DIST thunderbird-60.8.0-si.xpi 647589 BLAKE2B 73f07401247adaa19d7f1ba544b13706459dac4f15454d33ebcf3f49f3ea7ed6d14f8adf3768d56a10d6d08b8986d5a6bff4ec4b940254e25c3b090b561e01a1 SHA512 81d44f9bb1f234d643520164ec5b06c34a2fde0438498ab1c927eafd64a8238148d608173e7c952e582e1357d9e65600748d1c972ad38b5cfa44f5e5a819274b
+DIST thunderbird-60.8.0-sk.xpi 612217 BLAKE2B d8cf6ed4b46d686a0bff800511f4e2cd828692c002e79321bf99f568ba9ddbf68b0f1eba452d95536c83426502e81dec137c31a686158ef0b04886b2f78c6bff SHA512 6c22ccd50ce86f0a70f2b81b55ecf971fa39dd068f4b5250e551a68dde24129023ebbc59c65d8d519f09a2a7bbc62a88216da917365769f2759d6f764ca10dfe
+DIST thunderbird-60.8.0-sl.xpi 589947 BLAKE2B a1b053a2bb45056eaa4dc562cffb1b25dad4b5f74d0a33629bcfb54e49862bf9fbe26c7c6908a0f2a34bf6d07095cb851e16c2e94b29431993c5b47e66f35a16 SHA512 12eb163775da8dc77bd75fb2a3610633285f4b35cb2ee7162905a561e7447c54ce4a95acc20f02e0056ec34193f8bfca9e18dfbc78017615e775a82ecf0ca9bd
+DIST thunderbird-60.8.0-sq.xpi 593096 BLAKE2B 968a923e5680f6fc90fc670e48068f9b8c06f0feb33486f5ea6e5d7b8c94cf9e1d0812a99530185bef0ab1326b173592cacb5b812471917223797dc464889100 SHA512 2e9cfe30fb25c023d370028ee3f81177a25bcfa65505852d57fc3362582017a92ba4acf1a85e645b9aa7cc67d4cb1bb0c5da7017c8deb95c5166c83e993dd9ae
+DIST thunderbird-60.8.0-sr.xpi 641527 BLAKE2B 7f7db0d1aaa29a00df668cfeab6830fcde133d930b2317fd7d4edb370483483caf65487406a480079b9554627205e9ebe4148c6429e08ba8fad16ca2a9eafd7e SHA512 5df131d60f6e88b50849e45dcaecf3db60ffe1f0d60c503804e14ae84656230be245e97d6fcb4546c57ce6d74df1b6b856a693c285cf12dfa412d960a3bf878f
+DIST thunderbird-60.8.0-sv-SE.xpi 594078 BLAKE2B 520e036c5650fcc70e6d20d16c9bc435c4f0f1d5ccc02539b7763760601cc015886b009cfa3e34d41a1ecdc318522fd1672f75236d507b926a5c8acf91fc4a13 SHA512 2552f42a10eba2b27b39c373cb94ef0e990bc6c5712c585635f420b81ac891035843b8fdb90b9fd70430c39e8d730286005bd2334ff255574e7d32370f40fe98
+DIST thunderbird-60.8.0-tr.xpi 598011 BLAKE2B 643705ab19e76136f016d3bcb57a9c0fa4f1bcc2b2c8648e20d8caa9ae336c66cd2e7a720575f9bca8fd734a17e6bc262efaeba7caef932d5811724e3b5fa805 SHA512 5641107aeaa4882373323c8abac60b9312b413e8f706c293d25df981fecd25490be4aa0ec672befacacccaf9b47cf933ec4c58ecb88f391d42b9cf9db62a8d05
+DIST thunderbird-60.8.0-uk.xpi 684155 BLAKE2B 14fab464620240a30a650c4371ce790d91c6287dea8fdecd69d77b55086fba8a87a115ae11fd12d753a8efb47827936bf057ebe300939cc6e612ca67de971c0f SHA512 f45f607c5b3a4bb411afc7126279160e293f04cbb8be4a9a0b6e62f431a860656eee7e57c6761d5709aaa80b244c48c026d294ba54214276b770341ff225ad3b
+DIST thunderbird-60.8.0-vi.xpi 637187 BLAKE2B 7ecd85e521b230a2de85382f0ca2588523e6a0a819124bd440cc34859230d89f827fc2ad3e193dcc5049bedf21fd1ce3bc177c6451278eee13623532828d72a7 SHA512 47dd90cae041761fd58db8a9c9b1c97e7df1933cb6f2e36f11376d683cd7f802fcfb74d8887b5333222484daa1e6c925608d54a4ec30f1ba8d6b234dba324407
+DIST thunderbird-60.8.0-zh-CN.xpi 626284 BLAKE2B 90576f52f491b6af98489ee02fd48a7e27ca25eb4090986abe0ae67edc866240fc77e3b9aeeb768759eef9f2cc0b138f6aa60f59473ad2e6d786e578ff5da194 SHA512 35fc72b7894b7a678c57e8b89332a3478bd8eb49db01e8cd74f9a347466f577ddbcfa07dde487478e9c120d462ada430b0a569ab50114a0f603cbceb8223a137
+DIST thunderbird-60.8.0-zh-TW.xpi 626190 BLAKE2B e388d36ca6963d406372af7d26e9ea612cc69633a162fdf96f298a4d61753058cabdc5c4f400345751e7485a4f1bd5d75cb129dc993722f796936f3659da0ef0 SHA512 41abd5e0a83bb8da396e1b3f469be9c89a09aef74f2a6e9ee7cde27b8d09980b2539d1c36571b65cdafb1bbf765c671105c519db63aa33131781125dacdb3a83
+DIST thunderbird-60.8.0.source.tar.xz 285643576 BLAKE2B 223915c001c19908db5a4d6a580ff210f45b5c61a06212ba630a2d1b348b49b7067985b3ef42ee1f69fdc14725aecafd36ecea55af42cb6f6e4e00197ffc2178 SHA512 b465544a8cbedf0aff0f737cf98e2d030331f1ea016b2e541dfe30a5cf3172f9075e5a9c8d6b7e0f97ffc2e0d3eebbaf9a39e76a499b9fc976bbc0c944dfd058
+EBUILD thunderbird-60.8.0.ebuild 18667 BLAKE2B dba277ae89459276939a434f078d1b8bf5b945a43a5b75a94f5615c856954596c4e773ea503889c94caa4c6d4b039652e4181b21a9ffea2ff0bf75cb7e559c73 SHA512 6c0914bd7aa23606436a91c7905e21163d5f88356ef4ff1d8833f8c13d7d0c20ff03af57939685923d2eb5e0d04f01c7d8147a5944752e8a7a8afaec3b6c86ce
+MISC metadata.xml 1922 BLAKE2B ab89f183e54a3b58bd9b4b8df547c1172f264d00e3e8d753869d0d421c413bcc8ff06a24dd0910c28c70fd5b05cbc5154fc73ebfddf26e3db4d58d80e6e7d2c7 SHA512 0bdec29294b4b1aa77b965ecf78e2267ac75821c7ba7600783b5190755bd4380c675afbcfcb718a50a765dc35cb88112b8fa4956d298c467e91d21ec84509101
diff --git a/mail-client/thunderbird/files/firefox-wayland.patch b/mail-client/thunderbird/files/firefox-wayland.patch
new file mode 100644
index 0000000..ec42d9f
--- /dev/null
+++ b/mail-client/thunderbird/files/firefox-wayland.patch
@@ -0,0 +1,4441 @@
+diff -up thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp.wayland thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp
+--- thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp 2019-02-05 14:26:16.973316654 +0100
+@@ -38,7 +38,9 @@ GtkCompositorWidget::GtkCompositorWidget
+
+ // Grab the window's visual and depth
+ XWindowAttributes windowAttrs;
+- XGetWindowAttributes(mXDisplay, mXWindow, &windowAttrs);
++ if (!XGetWindowAttributes(mXDisplay, mXWindow, &windowAttrs)) {
++ NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
++ }
+
+ Visual* visual = windowAttrs.visual;
+ int depth = windowAttrs.depth;
+diff -up thunderbird-60.5.0/widget/gtk/moz.build.wayland thunderbird-60.5.0/widget/gtk/moz.build
+--- thunderbird-60.5.0/widget/gtk/moz.build.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/moz.build 2019-02-05 14:26:16.974316651 +0100
+@@ -99,6 +99,7 @@ if CONFIG['MOZ_X11']:
+ if CONFIG['MOZ_WAYLAND']:
+ UNIFIED_SOURCES += [
+ 'nsClipboardWayland.cpp',
++ 'nsWaylandDisplay.cpp',
+ 'WindowSurfaceWayland.cpp',
+ ]
+
+@@ -123,6 +124,7 @@ include('/ipc/chromium/chromium-config.m
+ FINAL_LIBRARY = 'xul'
+
+ LOCAL_INCLUDES += [
++ '/layout/base',
+ '/layout/generic',
+ '/layout/xul',
+ '/other-licenses/atk-1.0',
+diff -up thunderbird-60.5.0/widget/gtk/mozcontainer.cpp.wayland thunderbird-60.5.0/widget/gtk/mozcontainer.cpp
+--- thunderbird-60.5.0/widget/gtk/mozcontainer.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/mozcontainer.cpp 2019-02-05 15:09:24.116970135 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -7,9 +7,10 @@
+
+ #include "mozcontainer.h"
+ #include <gtk/gtk.h>
+-#ifdef MOZ_WAYLAND
+ #include <gdk/gdkx.h>
+-#include <gdk/gdkwayland.h>
++#ifdef MOZ_WAYLAND
++#include "nsWaylandDisplay.h"
++#include <wayland-egl.h>
+ #endif
+ #include <stdio.h>
+ #include <dlfcn.h>
+@@ -19,12 +20,20 @@
+ #include "maiRedundantObjectFactory.h"
+ #endif
+
++#ifdef MOZ_WAYLAND
++using namespace mozilla;
++using namespace mozilla::widget;
++#endif
++
+ /* init methods */
+ static void moz_container_class_init(MozContainerClass *klass);
+ static void moz_container_init(MozContainer *container);
+
+ /* widget class methods */
+ static void moz_container_map(GtkWidget *widget);
++#if defined(MOZ_WAYLAND)
++static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event);
++#endif
+ static void moz_container_unmap(GtkWidget *widget);
+ static void moz_container_realize(GtkWidget *widget);
+ static void moz_container_size_allocate(GtkWidget *widget,
+@@ -114,29 +123,6 @@ void moz_container_put(MozContainer *con
+ gtk_widget_set_parent(child_widget, GTK_WIDGET(container));
+ }
+
+-void moz_container_move(MozContainer *container, GtkWidget *child_widget,
+- gint x, gint y, gint width, gint height) {
+- MozContainerChild *child;
+- GtkAllocation new_allocation;
+-
+- child = moz_container_get_child(container, child_widget);
+-
+- child->x = x;
+- child->y = y;
+-
+- new_allocation.x = x;
+- new_allocation.y = y;
+- new_allocation.width = width;
+- new_allocation.height = height;
+-
+- /* printf("moz_container_move %p %p will allocate to %d %d %d %d\n",
+- (void *)container, (void *)child_widget,
+- new_allocation.x, new_allocation.y,
+- new_allocation.width, new_allocation.height); */
+-
+- gtk_widget_size_allocate(child_widget, &new_allocation);
+-}
+-
+ /* static methods */
+
+ void moz_container_class_init(MozContainerClass *klass) {
+@@ -146,6 +132,11 @@ void moz_container_class_init(MozContain
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ widget_class->map = moz_container_map;
++#if defined(MOZ_WAYLAND)
++ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
++ widget_class->map_event = moz_container_map_wayland;
++ }
++#endif
+ widget_class->unmap = moz_container_unmap;
+ widget_class->realize = moz_container_realize;
+ widget_class->size_allocate = moz_container_size_allocate;
+@@ -155,109 +146,81 @@ void moz_container_class_init(MozContain
+ container_class->add = moz_container_add;
+ }
+
+-#if defined(MOZ_WAYLAND)
+-static void registry_handle_global(void *data, struct wl_registry *registry,
+- uint32_t name, const char *interface,
+- uint32_t version) {
+- MozContainer *container = MOZ_CONTAINER(data);
+- if (strcmp(interface, "wl_subcompositor") == 0) {
+- container->subcompositor = static_cast<wl_subcompositor *>(
+- wl_registry_bind(registry, name, &wl_subcompositor_interface, 1));
+- }
+-}
+-
+-static void registry_handle_global_remove(void *data,
+- struct wl_registry *registry,
+- uint32_t name) {}
+-
+-static const struct wl_registry_listener registry_listener = {
+- registry_handle_global, registry_handle_global_remove};
+-#endif
+-
+ void moz_container_init(MozContainer *container) {
+ gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE);
+ gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE);
+ gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
+
+ #if defined(MOZ_WAYLAND)
+- {
+- GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
+- if (GDK_IS_WAYLAND_DISPLAY(gdk_display)) {
+- // Available as of GTK 3.8+
+- static auto sGdkWaylandDisplayGetWlDisplay =
+- (wl_display * (*)(GdkDisplay *))
+- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
+-
+- wl_display *display = sGdkWaylandDisplayGetWlDisplay(gdk_display);
+- wl_registry *registry = wl_display_get_registry(display);
+- wl_registry_add_listener(registry, &registry_listener, container);
+- wl_display_dispatch(display);
+- wl_display_roundtrip(display);
+- }
+- }
++ container->surface = nullptr;
++ container->subsurface = nullptr;
++ container->eglwindow = nullptr;
++ container->frame_callback_handler = nullptr;
++ // We can draw to x11 window any time.
++ container->ready_to_draw = GDK_IS_X11_DISPLAY(gdk_display_get_default());
++ container->surface_needs_clear = true;
+ #endif
+ }
+
+ #if defined(MOZ_WAYLAND)
+-/* We want to draw to GdkWindow owned by mContainer from Compositor thread but
+- * Gtk+ can be used in main thread only. So we create wayland wl_surface
+- * and attach it as an overlay to GdkWindow.
+- *
+- * see gtk_clutter_embed_ensure_subsurface() at gtk-clutter-embed.c
+- * for reference.
+- */
+-static gboolean moz_container_map_surface(MozContainer *container) {
+- // Available as of GTK 3.8+
+- static auto sGdkWaylandDisplayGetWlCompositor =
+- (wl_compositor * (*)(GdkDisplay *))
+- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
++static wl_surface *moz_container_get_gtk_container_surface(
++ MozContainer *container) {
+ static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
+ dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
+
+- GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
+- if (GDK_IS_X11_DISPLAY(display)) return false;
++ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
++ return sGdkWaylandWindowGetWlSurface(window);
++}
+
+- if (container->subsurface && container->surface) return true;
++static void frame_callback_handler(void *data, struct wl_callback *callback,
++ uint32_t time) {
++ MozContainer *container = MOZ_CONTAINER(data);
++ g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
++ container->ready_to_draw = true;
++}
+
+- if (!container->surface) {
+- struct wl_compositor *compositor;
+- compositor = sGdkWaylandDisplayGetWlCompositor(display);
+- container->surface = wl_compositor_create_surface(compositor);
+- }
++static const struct wl_callback_listener frame_listener = {
++ frame_callback_handler};
+
+- if (!container->subsurface) {
+- GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
+- wl_surface *gtk_surface = sGdkWaylandWindowGetWlSurface(window);
+- if (!gtk_surface) {
+- // We requested the underlying wl_surface too early when container
+- // is not realized yet. We'll try again before first rendering
+- // to mContainer.
+- return false;
+- }
++static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event) {
++ MozContainer* container = MOZ_CONTAINER(widget);
+
+- container->subsurface = wl_subcompositor_get_subsurface(
+- container->subcompositor, container->surface, gtk_surface);
+- gint x, y;
+- gdk_window_get_position(window, &x, &y);
+- wl_subsurface_set_position(container->subsurface, x, y);
+- wl_subsurface_set_desync(container->subsurface);
++ if (container->ready_to_draw || container->frame_callback_handler) {
++ return FALSE;
++ }
+
+- // Route input to parent wl_surface owned by Gtk+ so we get input
+- // events from Gtk+.
+- GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
+- wl_compositor *compositor = sGdkWaylandDisplayGetWlCompositor(display);
+- wl_region *region = wl_compositor_create_region(compositor);
+- wl_surface_set_input_region(container->surface, region);
+- wl_region_destroy(region);
++ wl_surface *gtk_container_surface =
++ moz_container_get_gtk_container_surface(container);
++
++ if (gtk_container_surface) {
++ container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
++ wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
++ container);
+ }
+- return true;
++
++ return FALSE;
+ }
+
+-static void moz_container_unmap_surface(MozContainer *container) {
++static void moz_container_unmap_wayland(MozContainer *container) {
+ g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
+ g_clear_pointer(&container->surface, wl_surface_destroy);
++ g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
++
++ container->surface_needs_clear = true;
++ container->ready_to_draw = false;
+ }
+
++static gint moz_container_get_scale(MozContainer *container) {
++ static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
++ RTLD_DEFAULT, "gdk_window_get_scale_factor");
++
++ if (sGdkWindowGetScaleFactorPtr) {
++ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
++ return (*sGdkWindowGetScaleFactorPtr)(window);
++ }
++
++ return 1;
++}
+ #endif
+
+ void moz_container_map(GtkWidget *widget) {
+@@ -283,7 +246,9 @@ void moz_container_map(GtkWidget *widget
+ if (gtk_widget_get_has_window(widget)) {
+ gdk_window_show(gtk_widget_get_window(widget));
+ #if defined(MOZ_WAYLAND)
+- moz_container_map_surface(MOZ_CONTAINER(widget));
++ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
++ moz_container_map_wayland(widget, nullptr);
++ }
+ #endif
+ }
+ }
+@@ -296,7 +261,9 @@ void moz_container_unmap(GtkWidget *widg
+ if (gtk_widget_get_has_window(widget)) {
+ gdk_window_hide(gtk_widget_get_window(widget));
+ #if defined(MOZ_WAYLAND)
+- moz_container_unmap_surface(MOZ_CONTAINER(widget));
++ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
++ moz_container_unmap_wayland(MOZ_CONTAINER(widget));
++ }
+ #endif
+ }
+ }
+@@ -485,13 +452,62 @@ static void moz_container_add(GtkContain
+
+ #ifdef MOZ_WAYLAND
+ struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
+- if (!container->subsurface || !container->surface) {
++ if (!container->surface) {
++ if (!container->ready_to_draw) {
++ return nullptr;
++ }
++ GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
++
++ // Available as of GTK 3.8+
++ static auto sGdkWaylandDisplayGetWlCompositor =
++ (wl_compositor * (*)(GdkDisplay *))
++ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
++ struct wl_compositor *compositor =
++ sGdkWaylandDisplayGetWlCompositor(display);
++ container->surface = wl_compositor_create_surface(compositor);
++
++ nsWaylandDisplay *waylandDisplay = WaylandDisplayGet(display);
++ container->subsurface = wl_subcompositor_get_subsurface(
++ waylandDisplay->GetSubcompositor(), container->surface,
++ moz_container_get_gtk_container_surface(container));
++ WaylandDisplayRelease(waylandDisplay);
++
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
+- if (!gdk_window_is_visible(window)) return nullptr;
++ gint x, y;
++ gdk_window_get_position(window, &x, &y);
++ wl_subsurface_set_position(container->subsurface, x, y);
++ wl_subsurface_set_desync(container->subsurface);
+
+- moz_container_map_surface(container);
++ // Route input to parent wl_surface owned by Gtk+ so we get input
++ // events from Gtk+.
++ wl_region *region = wl_compositor_create_region(compositor);
++ wl_surface_set_input_region(container->surface, region);
++ wl_region_destroy(region);
++
++ wl_surface_set_buffer_scale(container->surface,
++ moz_container_get_scale(container));
+ }
+
+ return container->surface;
+ }
++
++struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container) {
++ if (!container->eglwindow) {
++ wl_surface *surface = moz_container_get_wl_surface(container);
++ if (!surface) {
++ return nullptr;
++ }
++ }
++ return container->eglwindow;
++}
++
++gboolean moz_container_has_wl_egl_window(MozContainer *container) {
++ return container->eglwindow ? true : false;
++}
++
++gboolean moz_container_surface_needs_clear(MozContainer *container) {
++ gboolean state = container->surface_needs_clear;
++ container->surface_needs_clear = false;
++ return state;
++}
+ #endif
+diff -up thunderbird-60.5.0/widget/gtk/mozcontainer.h.wayland thunderbird-60.5.0/widget/gtk/mozcontainer.h
+--- thunderbird-60.5.0/widget/gtk/mozcontainer.h.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/mozcontainer.h 2019-02-05 14:26:16.974316651 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -63,7 +63,6 @@ typedef struct _MozContainerClass MozCon
+ * present in wayland-devel < 1.12
+ */
+ #ifdef MOZ_WAYLAND
+-struct wl_subcompositor;
+ struct wl_surface;
+ struct wl_subsurface;
+ #endif
+@@ -73,9 +72,12 @@ struct _MozContainer {
+ GList *children;
+
+ #ifdef MOZ_WAYLAND
+- struct wl_subcompositor *subcompositor;
+ struct wl_surface *surface;
+ struct wl_subsurface *subsurface;
++ struct wl_egl_window *eglwindow;
++ struct wl_callback *frame_callback_handler;
++ gboolean surface_needs_clear;
++ gboolean ready_to_draw;
+ #endif
+ };
+
+@@ -87,11 +89,13 @@ GType moz_container_get_type(void);
+ GtkWidget *moz_container_new(void);
+ void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x,
+ gint y);
+-void moz_container_move(MozContainer *container, GtkWidget *child_widget,
+- gint x, gint y, gint width, gint height);
+
+ #ifdef MOZ_WAYLAND
+ struct wl_surface *moz_container_get_wl_surface(MozContainer *container);
++struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container);
++
++gboolean moz_container_has_wl_egl_window(MozContainer *container);
++gboolean moz_container_surface_needs_clear(MozContainer *container);
+ #endif
+
+ #endif /* __MOZ_CONTAINER_H__ */
+diff -up thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c.wayland thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c
+--- thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c 2019-02-05 14:26:16.974316651 +0100
+@@ -26,6 +26,7 @@ STUB(gdk_display_sync)
+ STUB(gdk_display_warp_pointer)
+ STUB(gdk_drag_context_get_actions)
+ STUB(gdk_drag_context_get_dest_window)
++STUB(gdk_drag_context_get_source_window)
+ STUB(gdk_drag_context_list_targets)
+ STUB(gdk_drag_status)
+ STUB(gdk_error_trap_pop)
+@@ -55,6 +56,7 @@ STUB(gdk_pointer_grab)
+ STUB(gdk_pointer_ungrab)
+ STUB(gdk_property_change)
+ STUB(gdk_property_get)
++STUB(gdk_property_delete)
+ STUB(gdk_screen_get_default)
+ STUB(gdk_screen_get_display)
+ STUB(gdk_screen_get_font_options)
+@@ -136,6 +138,8 @@ STUB(gdk_x11_get_xatom_by_name)
+ STUB(gdk_x11_get_xatom_by_name_for_display)
+ STUB(gdk_x11_lookup_xdisplay)
+ STUB(gdk_x11_screen_get_xscreen)
++STUB(gdk_x11_screen_get_screen_number)
++STUB(gdk_x11_screen_lookup_visual)
+ STUB(gdk_x11_screen_supports_net_wm_hint)
+ STUB(gdk_x11_visual_get_xvisual)
+ STUB(gdk_x11_window_foreign_new_for_display)
+@@ -267,6 +271,7 @@ STUB(gtk_im_context_set_client_window)
+ STUB(gtk_im_context_set_cursor_location)
+ STUB(gtk_im_context_set_surrounding)
+ STUB(gtk_im_context_simple_new)
++STUB(gtk_im_multicontext_get_context_id)
+ STUB(gtk_im_multicontext_get_type)
+ STUB(gtk_im_multicontext_new)
+ STUB(gtk_info_bar_get_type)
+@@ -411,6 +416,7 @@ STUB(gtk_table_get_type)
+ STUB(gtk_table_new)
+ STUB(gtk_target_list_add)
+ STUB(gtk_target_list_add_image_targets)
++STUB(gtk_target_list_add_text_targets)
+ STUB(gtk_target_list_new)
+ STUB(gtk_target_list_unref)
+ STUB(gtk_targets_include_image)
+@@ -491,6 +497,7 @@ STUB(gtk_widget_unrealize)
+ STUB(gtk_window_deiconify)
+ STUB(gtk_window_fullscreen)
+ STUB(gtk_window_get_group)
++STUB(gtk_window_get_modal)
+ STUB(gtk_window_get_transient_for)
+ STUB(gtk_window_get_type)
+ STUB(gtk_window_get_type_hint)
+diff -up thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c.wayland thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c
+--- thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c.wayland 2019-01-22 20:44:02.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c 2019-02-05 14:26:16.974316651 +0100
+@@ -1,14 +1,23 @@
+-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
++#include <stdlib.h>
+ #include "mozilla/Types.h"
+ #include <gtk/gtk.h>
++#include <gtk/gtkx.h>
+ #include <gdk/gdkwayland.h>
+
++union wl_argument;
++
++/* Those strucures are just placeholders and will be replaced by
++ * real symbols from libwayland during run-time linking. We need to make
++ * them explicitly visible.
++ */
++#pragma GCC visibility push(default)
+ const struct wl_interface wl_buffer_interface;
+ const struct wl_interface wl_callback_interface;
+ const struct wl_interface wl_data_device_interface;
+@@ -22,6 +31,7 @@ const struct wl_interface wl_seat_interf
+ const struct wl_interface wl_surface_interface;
+ const struct wl_interface wl_subsurface_interface;
+ const struct wl_interface wl_subcompositor_interface;
++#pragma GCC visibility pop
+
+ MOZ_EXPORT void wl_event_queue_destroy(struct wl_event_queue *queue) {}
+
+@@ -75,6 +85,10 @@ MOZ_EXPORT const void *wl_proxy_get_list
+ return NULL;
+ }
+
++typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
++ const struct wl_message *,
++ union wl_argument *);
++
+ MOZ_EXPORT int wl_proxy_add_dispatcher(struct wl_proxy *proxy,
+ wl_dispatcher_func_t dispatcher_func,
+ const void *dispatcher_data,
+@@ -160,3 +174,13 @@ MOZ_EXPORT void wl_display_cancel_read(s
+ MOZ_EXPORT int wl_display_read_events(struct wl_display *display) { return -1; }
+
+ MOZ_EXPORT void wl_log_set_handler_client(wl_log_func_t handler) {}
++
++MOZ_EXPORT struct wl_egl_window *wl_egl_window_create(
++ struct wl_surface *surface, int width, int height) {
++ return NULL;
++}
++
++MOZ_EXPORT void wl_egl_window_destroy(struct wl_egl_window *egl_window) {}
++
++MOZ_EXPORT void wl_egl_window_resize(struct wl_egl_window *egl_window,
++ int width, int height, int dx, int dy) {}
+diff -up thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h.wayland thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h
+--- thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h.wayland 2019-02-05 14:26:16.975316648 +0100
++++ thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h 2019-02-05 14:26:16.975316648 +0100
+@@ -0,0 +1,115 @@
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim:expandtab:shiftwidth=4:tabstop=4:
++ */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/* Wayland compatibility header, it makes Firefox build with
++ wayland-1.2 and Gtk+ 3.10.
++*/
++
++#ifndef __MozWayland_h_
++#define __MozWayland_h_
++
++#include "mozilla/Types.h"
++#include <gtk/gtk.h>
++#include <gdk/gdkwayland.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++MOZ_EXPORT int wl_display_roundtrip_queue(struct wl_display *display,
++ struct wl_event_queue *queue);
++MOZ_EXPORT uint32_t wl_proxy_get_version(struct wl_proxy *proxy);
++MOZ_EXPORT struct wl_proxy *wl_proxy_marshal_constructor(
++ struct wl_proxy *proxy, uint32_t opcode,
++ const struct wl_interface *interface, ...);
++
++/* We need implement some missing functions from wayland-client-protocol.h
++ */
++#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
++enum wl_data_device_manager_dnd_action {
++ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
++ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
++ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
++ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4
++};
++#endif
++
++#ifndef WL_DATA_OFFER_SET_ACTIONS
++#define WL_DATA_OFFER_SET_ACTIONS 4
++
++struct moz_wl_data_offer_listener {
++ void (*offer)(void *data, struct wl_data_offer *wl_data_offer,
++ const char *mime_type);
++ void (*source_actions)(void *data, struct wl_data_offer *wl_data_offer,
++ uint32_t source_actions);
++ void (*action)(void *data, struct wl_data_offer *wl_data_offer,
++ uint32_t dnd_action);
++};
++
++static inline void wl_data_offer_set_actions(
++ struct wl_data_offer *wl_data_offer, uint32_t dnd_actions,
++ uint32_t preferred_action) {
++ wl_proxy_marshal((struct wl_proxy *)wl_data_offer, WL_DATA_OFFER_SET_ACTIONS,
++ dnd_actions, preferred_action);
++}
++#else
++typedef struct wl_data_offer_listener moz_wl_data_offer_listener;
++#endif
++
++#ifndef WL_SUBCOMPOSITOR_GET_SUBSURFACE
++#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1
++struct wl_subcompositor;
++
++// Emulate what mozilla header wrapper does - make the
++// wl_subcompositor_interface always visible.
++#pragma GCC visibility push(default)
++extern const struct wl_interface wl_subsurface_interface;
++extern const struct wl_interface wl_subcompositor_interface;
++#pragma GCC visibility pop
++
++#define WL_SUBSURFACE_DESTROY 0
++#define WL_SUBSURFACE_SET_POSITION 1
++#define WL_SUBSURFACE_PLACE_ABOVE 2
++#define WL_SUBSURFACE_PLACE_BELOW 3
++#define WL_SUBSURFACE_SET_SYNC 4
++#define WL_SUBSURFACE_SET_DESYNC 5
++
++static inline struct wl_subsurface *wl_subcompositor_get_subsurface(
++ struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface,
++ struct wl_surface *parent) {
++ struct wl_proxy *id;
++
++ id = wl_proxy_marshal_constructor(
++ (struct wl_proxy *)wl_subcompositor, WL_SUBCOMPOSITOR_GET_SUBSURFACE,
++ &wl_subsurface_interface, NULL, surface, parent);
++
++ return (struct wl_subsurface *)id;
++}
++
++static inline void wl_subsurface_set_position(
++ struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) {
++ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_SET_POSITION,
++ x, y);
++}
++
++static inline void wl_subsurface_set_desync(
++ struct wl_subsurface *wl_subsurface) {
++ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_SET_DESYNC);
++}
++
++static inline void wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) {
++ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_DESTROY);
++
++ wl_proxy_destroy((struct wl_proxy *)wl_subsurface);
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __MozWayland_h_ */
+diff -up thunderbird-60.5.0/widget/gtk/nsClipboard.cpp.wayland thunderbird-60.5.0/widget/gtk/nsClipboard.cpp
+--- thunderbird-60.5.0/widget/gtk/nsClipboard.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsClipboard.cpp 2019-02-05 14:26:16.975316648 +0100
+@@ -72,7 +72,7 @@ nsClipboard::~nsClipboard() {
+ }
+ }
+
+-NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
++NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard, nsIObserver)
+
+ nsresult nsClipboard::Init(void) {
+ GdkDisplay *display = gdk_display_get_default();
+diff -up thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp.wayland thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp
+--- thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp 2019-02-05 14:26:16.975316648 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -20,9 +20,11 @@
+ #include "nsImageToPixbuf.h"
+ #include "nsStringStream.h"
+ #include "nsIObserverService.h"
+-#include "mozilla/Services.h"
+ #include "mozilla/RefPtr.h"
+ #include "mozilla/TimeStamp.h"
++#include "nsDragService.h"
++#include "mozwayland/mozwayland.h"
++#include "nsWaylandDisplay.h"
+
+ #include "imgIContainer.h"
+
+@@ -31,15 +33,43 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <fcntl.h>
+-#include <gtk/gtk.h>
+-#include <gdk/gdkwayland.h>
+ #include <errno.h>
+
+-#include "wayland/gtk-primary-selection-client-protocol.h"
+-
+ const char *nsRetrievalContextWayland::sTextMimeTypes[TEXT_MIME_TYPES_NUM] = {
+ "text/plain;charset=utf-8", "UTF8_STRING", "COMPOUND_TEXT"};
+
++static inline GdkDragAction wl_to_gdk_actions(uint32_t dnd_actions) {
++ GdkDragAction actions = GdkDragAction(0);
++
++ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
++ actions = GdkDragAction(actions | GDK_ACTION_COPY);
++ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
++ actions = GdkDragAction(actions | GDK_ACTION_MOVE);
++
++ return actions;
++}
++
++static inline uint32_t gdk_to_wl_actions(GdkDragAction action) {
++ uint32_t dnd_actions = 0;
++
++ if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
++ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
++ if (action & GDK_ACTION_MOVE)
++ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
++
++ return dnd_actions;
++}
++
++static GtkWidget *get_gtk_widget_for_wl_surface(struct wl_surface *surface) {
++ GdkWindow *gdkParentWindow =
++ static_cast<GdkWindow *>(wl_surface_get_user_data(surface));
++
++ gpointer user_data = nullptr;
++ gdk_window_get_user_data(gdkParentWindow, &user_data);
++
++ return GTK_WIDGET(user_data);
++}
++
+ void DataOffer::AddMIMEType(const char *aMimeType) {
+ GdkAtom atom = gdk_atom_intern(aMimeType, FALSE);
+ mTargetMIMETypes.AppendElement(atom);
+@@ -98,7 +128,7 @@ char *DataOffer::GetData(wl_display *aDi
+
+ GIOChannel *channel = g_io_channel_unix_new(pipe_fd[0]);
+ GError *error = nullptr;
+- char *clipboardData;
++ char *clipboardData = nullptr;
+
+ g_io_channel_set_encoding(channel, nullptr, &error);
+ if (!error) {
+@@ -138,31 +168,92 @@ bool WaylandDataOffer::RequestDataTransf
+ return false;
+ }
+
++void WaylandDataOffer::DragOfferAccept(const char *aMimeType, uint32_t aTime) {
++ wl_data_offer_accept(mWaylandDataOffer, aTime, aMimeType);
++}
++
++/* We follow logic of gdk_wayland_drag_context_commit_status()/gdkdnd-wayland.c
++ * here.
++ */
++void WaylandDataOffer::SetDragStatus(GdkDragAction aAction, uint32_t aTime) {
++ uint32_t dnd_actions = gdk_to_wl_actions(aAction);
++ uint32_t all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
++ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
++
++ wl_data_offer_set_actions(mWaylandDataOffer, all_actions, dnd_actions);
++
++ /* Workaround Wayland D&D architecture here. To get the data_device_drop()
++ signal (which routes to nsDragService::GetData() call) we need to
++ accept at least one mime type before data_device_leave().
++
++ Real wl_data_offer_accept() for actualy requested data mime type is
++ called from nsDragService::GetData().
++ */
++ if (mTargetMIMETypes[0]) {
++ wl_data_offer_accept(mWaylandDataOffer, aTime,
++ gdk_atom_name(mTargetMIMETypes[0]));
++ }
++}
++
++void WaylandDataOffer::SetSelectedDragAction(uint32_t aWaylandAction) {
++ mSelectedDragAction = aWaylandAction;
++}
++
++GdkDragAction WaylandDataOffer::GetSelectedDragAction() {
++ return wl_to_gdk_actions(mSelectedDragAction);
++}
++
++void WaylandDataOffer::SetAvailableDragActions(uint32_t aWaylandActions) {
++ mAvailableDragAction = aWaylandActions;
++}
++
++GdkDragAction WaylandDataOffer::GetAvailableDragActions() {
++ return wl_to_gdk_actions(mAvailableDragAction);
++}
++
+ static void data_offer_offer(void *data, struct wl_data_offer *wl_data_offer,
+ const char *type) {
+ auto *offer = static_cast<DataOffer *>(data);
+ offer->AddMIMEType(type);
+ }
+
++/* Advertise all available drag and drop actions from source.
++ * We don't use that but follow gdk_wayland_drag_context_commit_status()
++ * from gdkdnd-wayland.c here.
++ */
+ static void data_offer_source_actions(void *data,
+ struct wl_data_offer *wl_data_offer,
+- uint32_t source_actions) {}
++ uint32_t source_actions) {
++ auto *offer = static_cast<WaylandDataOffer *>(data);
++ offer->SetAvailableDragActions(source_actions);
++}
+
++/* Advertise recently selected drag and drop action by compositor, based
++ * on source actions and user choice (key modifiers, etc.).
++ */
+ static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer,
+- uint32_t dnd_action) {}
++ uint32_t dnd_action) {
++ auto *offer = static_cast<WaylandDataOffer *>(data);
++ offer->SetSelectedDragAction(dnd_action);
++}
+
+ /* wl_data_offer callback description:
+ *
+ * data_offer_offer - Is called for each MIME type available at wl_data_offer.
+- * data_offer_source_actions - Exposes all available D&D actions.
+- * data_offer_action - Expose one actually selected D&D action.
++ * data_offer_source_actions - This event indicates the actions offered by
++ * the data source.
++ * data_offer_action - This event indicates the action selected by
++ * the compositor after matching the source/destination
++ * side actions.
+ */
+-static const struct wl_data_offer_listener data_offer_listener = {
++static const moz_wl_data_offer_listener data_offer_listener = {
+ data_offer_offer, data_offer_source_actions, data_offer_action};
+
+ WaylandDataOffer::WaylandDataOffer(wl_data_offer *aWaylandDataOffer)
+ : mWaylandDataOffer(aWaylandDataOffer) {
+- wl_data_offer_add_listener(mWaylandDataOffer, &data_offer_listener, this);
++ wl_data_offer_add_listener(
++ mWaylandDataOffer, (struct wl_data_offer_listener *)&data_offer_listener,
++ this);
+ }
+
+ WaylandDataOffer::~WaylandDataOffer(void) {
+@@ -207,20 +298,93 @@ PrimaryDataOffer::~PrimaryDataOffer(void
+ }
+ }
+
+-void nsRetrievalContextWayland::RegisterDataOffer(
++NS_IMPL_ISUPPORTS(nsWaylandDragContext, nsISupports);
++
++nsWaylandDragContext::nsWaylandDragContext(WaylandDataOffer *aDataOffer,
++ wl_display *aDisplay)
++ : mDataOffer(aDataOffer),
++ mDisplay(aDisplay),
++ mTime(0),
++ mGtkWidget(nullptr),
++ mX(0),
++ mY(0) {}
++
++void nsWaylandDragContext::DropDataEnter(GtkWidget *aGtkWidget, uint32_t aTime,
++ nscoord aX, nscoord aY) {
++ mTime = aTime;
++ mGtkWidget = aGtkWidget;
++ mX = aX;
++ mY = aY;
++}
++
++void nsWaylandDragContext::DropMotion(uint32_t aTime, nscoord aX, nscoord aY) {
++ mTime = aTime;
++ mX = aX;
++ mY = aY;
++}
++
++void nsWaylandDragContext::GetLastDropInfo(uint32_t *aTime, nscoord *aX,
++ nscoord *aY) {
++ *aTime = mTime;
++ *aX = mX;
++ *aY = mY;
++}
++
++void nsWaylandDragContext::SetDragStatus(GdkDragAction aAction) {
++ mDataOffer->SetDragStatus(aAction, mTime);
++}
++
++GdkDragAction nsWaylandDragContext::GetSelectedDragAction() {
++ GdkDragAction gdkAction = mDataOffer->GetSelectedDragAction();
++
++ // We emulate gdk_drag_context_get_actions() here.
++ if (!gdkAction) {
++ gdkAction = mDataOffer->GetAvailableDragActions();
++ }
++
++ return gdkAction;
++}
++
++GList *nsWaylandDragContext::GetTargets() {
++ int targetNums;
++ GdkAtom *atoms = mDataOffer->GetTargets(&targetNums);
++
++ GList *targetList = nullptr;
++ for (int i = 0; i < targetNums; i++) {
++ targetList = g_list_append(targetList, GDK_ATOM_TO_POINTER(atoms[i]));
++ }
++
++ return targetList;
++}
++
++char *nsWaylandDragContext::GetData(const char *aMimeType,
++ uint32_t *aContentLength) {
++ mDataOffer->DragOfferAccept(aMimeType, mTime);
++ return mDataOffer->GetData(mDisplay, aMimeType, aContentLength);
++}
++
++void nsRetrievalContextWayland::RegisterNewDataOffer(
+ wl_data_offer *aWaylandDataOffer) {
+ DataOffer *dataOffer = static_cast<DataOffer *>(
+ g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
++ MOZ_ASSERT(
++ dataOffer == nullptr,
++ "Registered WaylandDataOffer already exists. Wayland protocol error?");
++
+ if (!dataOffer) {
+ dataOffer = new WaylandDataOffer(aWaylandDataOffer);
+ g_hash_table_insert(mActiveOffers, aWaylandDataOffer, dataOffer);
+ }
+ }
+
+-void nsRetrievalContextWayland::RegisterDataOffer(
++void nsRetrievalContextWayland::RegisterNewDataOffer(
+ gtk_primary_selection_offer *aPrimaryDataOffer) {
+ DataOffer *dataOffer = static_cast<DataOffer *>(
+ g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
++ MOZ_ASSERT(
++ dataOffer == nullptr,
++ "Registered PrimaryDataOffer already exists. Wayland protocol error?");
++
+ if (!dataOffer) {
+ dataOffer = new PrimaryDataOffer(aPrimaryDataOffer);
+ g_hash_table_insert(mActiveOffers, aPrimaryDataOffer, dataOffer);
+@@ -229,21 +393,30 @@ void nsRetrievalContextWayland::Register
+
+ void nsRetrievalContextWayland::SetClipboardDataOffer(
+ wl_data_offer *aWaylandDataOffer) {
+- DataOffer *dataOffer = static_cast<DataOffer *>(
+- g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
+- NS_ASSERTION(dataOffer, "We're missing clipboard data offer!");
+- if (dataOffer) {
+- g_hash_table_remove(mActiveOffers, aWaylandDataOffer);
+- mClipboardOffer = dataOffer;
++ // Delete existing clipboard data offer
++ mClipboardOffer = nullptr;
++
++ // null aWaylandDataOffer indicates that our clipboard content
++ // is no longer valid and should be release.
++ if (aWaylandDataOffer != nullptr) {
++ DataOffer *dataOffer = static_cast<DataOffer *>(
++ g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
++ NS_ASSERTION(dataOffer, "We're missing stored clipboard data offer!");
++ if (dataOffer) {
++ g_hash_table_remove(mActiveOffers, aWaylandDataOffer);
++ mClipboardOffer = dataOffer;
++ }
+ }
+ }
+
+ void nsRetrievalContextWayland::SetPrimaryDataOffer(
+ gtk_primary_selection_offer *aPrimaryDataOffer) {
+- if (aPrimaryDataOffer == nullptr) {
+- // Release any primary offer we have.
+- mPrimaryOffer = nullptr;
+- } else {
++ // Release any primary offer we have.
++ mPrimaryOffer = nullptr;
++
++ // aPrimaryDataOffer can be null which means we lost
++ // the mouse selection.
++ if (aPrimaryDataOffer) {
+ DataOffer *dataOffer = static_cast<DataOffer *>(
+ g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
+ NS_ASSERTION(dataOffer, "We're missing primary data offer!");
+@@ -254,9 +427,26 @@ void nsRetrievalContextWayland::SetPrima
+ }
+ }
+
+-void nsRetrievalContextWayland::ClearDataOffers(void) {
+- if (mClipboardOffer) mClipboardOffer = nullptr;
+- if (mPrimaryOffer) mPrimaryOffer = nullptr;
++void nsRetrievalContextWayland::AddDragAndDropDataOffer(
++ wl_data_offer *aDropDataOffer) {
++ // Remove any existing D&D contexts.
++ mDragContext = nullptr;
++
++ WaylandDataOffer *dataOffer = static_cast<WaylandDataOffer *>(
++ g_hash_table_lookup(mActiveOffers, aDropDataOffer));
++ NS_ASSERTION(dataOffer, "We're missing drag and drop data offer!");
++ if (dataOffer) {
++ g_hash_table_remove(mActiveOffers, aDropDataOffer);
++ mDragContext = new nsWaylandDragContext(dataOffer, mDisplay->GetDisplay());
++ }
++}
++
++nsWaylandDragContext *nsRetrievalContextWayland::GetDragContext(void) {
++ return mDragContext;
++}
++
++void nsRetrievalContextWayland::ClearDragAndDropDataOffer(void) {
++ mDragContext = nullptr;
+ }
+
+ // We have a new fresh data content.
+@@ -266,7 +456,7 @@ static void data_device_data_offer(void
+ struct wl_data_offer *offer) {
+ nsRetrievalContextWayland *context =
+ static_cast<nsRetrievalContextWayland *>(data);
+- context->RegisterDataOffer(offer);
++ context->RegisterNewDataOffer(offer);
+ }
+
+ // The new fresh data content is clipboard.
+@@ -281,15 +471,65 @@ static void data_device_selection(void *
+ // The new fresh wayland data content is drag and drop.
+ static void data_device_enter(void *data, struct wl_data_device *data_device,
+ uint32_t time, struct wl_surface *surface,
+- int32_t x, int32_t y,
+- struct wl_data_offer *offer) {}
++ int32_t x_fixed, int32_t y_fixed,
++ struct wl_data_offer *offer) {
++ nsRetrievalContextWayland *context =
++ static_cast<nsRetrievalContextWayland *>(data);
++ context->AddDragAndDropDataOffer(offer);
++
++ nsWaylandDragContext *dragContext = context->GetDragContext();
++
++ GtkWidget *gtkWidget = get_gtk_widget_for_wl_surface(surface);
++ if (!gtkWidget) {
++ NS_WARNING("DragAndDrop: Unable to get GtkWidget for wl_surface!");
++ return;
++ }
++
++ LOGDRAG(("nsWindow data_device_enter for GtkWidget %p\n", (void *)gtkWidget));
++
++ dragContext->DropDataEnter(gtkWidget, time, wl_fixed_to_int(x_fixed),
++ wl_fixed_to_int(y_fixed));
++}
++
++static void data_device_leave(void *data, struct wl_data_device *data_device) {
++ nsRetrievalContextWayland *context =
++ static_cast<nsRetrievalContextWayland *>(data);
+
+-static void data_device_leave(void *data, struct wl_data_device *data_device) {}
++ nsWaylandDragContext *dropContext = context->GetDragContext();
++ WindowDragLeaveHandler(dropContext->GetWidget());
++
++ context->ClearDragAndDropDataOffer();
++}
+
+ static void data_device_motion(void *data, struct wl_data_device *data_device,
+- uint32_t time, int32_t x, int32_t y) {}
++ uint32_t time, int32_t x_fixed,
++ int32_t y_fixed) {
++ nsRetrievalContextWayland *context =
++ static_cast<nsRetrievalContextWayland *>(data);
++
++ nsWaylandDragContext *dropContext = context->GetDragContext();
+
+-static void data_device_drop(void *data, struct wl_data_device *data_device) {}
++ nscoord x = wl_fixed_to_int(x_fixed);
++ nscoord y = wl_fixed_to_int(y_fixed);
++ dropContext->DropMotion(time, x, y);
++
++ WindowDragMotionHandler(dropContext->GetWidget(), nullptr, dropContext, x, y,
++ time);
++}
++
++static void data_device_drop(void *data, struct wl_data_device *data_device) {
++ nsRetrievalContextWayland *context =
++ static_cast<nsRetrievalContextWayland *>(data);
++
++ nsWaylandDragContext *dropContext = context->GetDragContext();
++
++ uint32_t time;
++ nscoord x, y;
++ dropContext->GetLastDropInfo(&time, &x, &y);
++
++ WindowDragDropHandler(dropContext->GetWidget(), nullptr, dropContext, x, y,
++ time);
++}
+
+ /* wl_data_device callback description:
+ *
+@@ -323,7 +563,7 @@ static void primary_selection_data_offer
+ // create and add listener
+ nsRetrievalContextWayland *context =
+ static_cast<nsRetrievalContextWayland *>(data);
+- context->RegisterDataOffer(gtk_primary_offer);
++ context->RegisterNewDataOffer(gtk_primary_offer);
+ }
+
+ static void primary_selection_selection(
+@@ -335,6 +575,19 @@ static void primary_selection_selection(
+ context->SetPrimaryDataOffer(gtk_primary_offer);
+ }
+
++/* gtk_primary_selection_device callback description:
++ *
++ * primary_selection_data_offer - It's called when there's a new
++ * gtk_primary_selection_offer available. We need to
++ * attach gtk_primary_selection_offer_listener to it
++ * to get available MIME types.
++ *
++ * primary_selection_selection - It's called when the new
++ * gtk_primary_selection_offer is a primary selection
++ * content. It can be also called with
++ * gtk_primary_selection_offer = null which means
++ * there's no primary selection.
++ */
+ static const struct gtk_primary_selection_device_listener
+ primary_selection_device_listener = {
+ primary_selection_data_offer,
+@@ -342,149 +595,29 @@ static const struct gtk_primary_selectio
+ };
+
+ bool nsRetrievalContextWayland::HasSelectionSupport(void) {
+- return mPrimarySelectionDataDeviceManager != nullptr;
+-}
+-
+-static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
+- uint32_t format, int fd, uint32_t size) {}
+-
+-static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
+- uint32_t serial, struct wl_surface *surface,
+- struct wl_array *keys) {}
+-
+-static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
+- uint32_t serial, struct wl_surface *surface) {
+- // We lost focus so our clipboard data are outdated
+- nsRetrievalContextWayland *context =
+- static_cast<nsRetrievalContextWayland *>(data);
+-
+- context->ClearDataOffers();
++ return mDisplay->GetPrimarySelectionDeviceManager() != nullptr;
+ }
+
+-static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
+- uint32_t serial, uint32_t time, uint32_t key,
+- uint32_t state) {}
+-
+-static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
+- uint32_t serial, uint32_t mods_depressed,
+- uint32_t mods_latched,
+- uint32_t mods_locked, uint32_t group) {}
+-
+-static const struct wl_keyboard_listener keyboard_listener = {
+- keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave,
+- keyboard_handle_key, keyboard_handle_modifiers,
+-};
+-
+-void nsRetrievalContextWayland::ConfigureKeyboard(wl_seat_capability caps) {
+- // ConfigureKeyboard() is called when wl_seat configuration is changed.
+- // We look for the keyboard only, get it when is't available and release it
+- // when it's lost (we don't have focus for instance).
+- if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
+- mKeyboard = wl_seat_get_keyboard(mSeat);
+- wl_keyboard_add_listener(mKeyboard, &keyboard_listener, this);
+- } else if (mKeyboard && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
+- wl_keyboard_destroy(mKeyboard);
+- mKeyboard = nullptr;
+- }
+-}
+-
+-static void seat_handle_capabilities(void *data, struct wl_seat *seat,
+- unsigned int caps) {
+- nsRetrievalContextWayland *context =
+- static_cast<nsRetrievalContextWayland *>(data);
+- context->ConfigureKeyboard((wl_seat_capability)caps);
+-}
+-
+-static const struct wl_seat_listener seat_listener = {
+- seat_handle_capabilities,
+-};
+-
+-void nsRetrievalContextWayland::InitDataDeviceManager(wl_registry *registry,
+- uint32_t id,
+- uint32_t version) {
+- int data_device_manager_version = MIN(version, 3);
+- mDataDeviceManager = (wl_data_device_manager *)wl_registry_bind(
+- registry, id, &wl_data_device_manager_interface,
+- data_device_manager_version);
+-}
+-
+-void nsRetrievalContextWayland::InitPrimarySelectionDataDeviceManager(
+- wl_registry *registry, uint32_t id) {
+- mPrimarySelectionDataDeviceManager =
+- (gtk_primary_selection_device_manager *)wl_registry_bind(
+- registry, id, &gtk_primary_selection_device_manager_interface, 1);
+-}
+-
+-void nsRetrievalContextWayland::InitSeat(wl_registry *registry, uint32_t id,
+- uint32_t version, void *data) {
+- mSeat = (wl_seat *)wl_registry_bind(registry, id, &wl_seat_interface, 1);
+- wl_seat_add_listener(mSeat, &seat_listener, data);
+-}
+-
+-static void gdk_registry_handle_global(void *data, struct wl_registry *registry,
+- uint32_t id, const char *interface,
+- uint32_t version) {
+- nsRetrievalContextWayland *context =
+- static_cast<nsRetrievalContextWayland *>(data);
+-
+- if (strcmp(interface, "wl_data_device_manager") == 0) {
+- context->InitDataDeviceManager(registry, id, version);
+- } else if (strcmp(interface, "wl_seat") == 0) {
+- context->InitSeat(registry, id, version, data);
+- } else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
+- context->InitPrimarySelectionDataDeviceManager(registry, id);
+- }
+-}
+-
+-static void gdk_registry_handle_global_remove(void *data,
+- struct wl_registry *registry,
+- uint32_t id) {}
+-
+-static const struct wl_registry_listener clipboard_registry_listener = {
+- gdk_registry_handle_global, gdk_registry_handle_global_remove};
+-
+ nsRetrievalContextWayland::nsRetrievalContextWayland(void)
+ : mInitialized(false),
+- mSeat(nullptr),
+- mDataDeviceManager(nullptr),
+- mPrimarySelectionDataDeviceManager(nullptr),
+- mKeyboard(nullptr),
++ mDisplay(WaylandDisplayGet()),
+ mActiveOffers(g_hash_table_new(NULL, NULL)),
+ mClipboardOffer(nullptr),
+ mPrimaryOffer(nullptr),
++ mDragContext(nullptr),
+ mClipboardRequestNumber(0),
+ mClipboardData(nullptr),
+ mClipboardDataLength(0) {
+- // Available as of GTK 3.8+
+- static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
+- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
+-
+- mDisplay = sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
+- wl_registry_add_listener(wl_display_get_registry(mDisplay),
+- &clipboard_registry_listener, this);
+- // Call wl_display_roundtrip() twice to make sure all
+- // callbacks are processed.
+- wl_display_roundtrip(mDisplay);
+- wl_display_roundtrip(mDisplay);
+-
+- // mSeat/mDataDeviceManager should be set now by
+- // gdk_registry_handle_global() as a response to
+- // wl_registry_add_listener() call.
+- if (!mDataDeviceManager || !mSeat) return;
+-
+- wl_data_device *dataDevice =
+- wl_data_device_manager_get_data_device(mDataDeviceManager, mSeat);
++ wl_data_device *dataDevice = wl_data_device_manager_get_data_device(
++ mDisplay->GetDataDeviceManager(), mDisplay->GetSeat());
+ wl_data_device_add_listener(dataDevice, &data_device_listener, this);
+- // We have to call wl_display_roundtrip() twice otherwise data_offer_listener
+- // may not be processed because it's called from data_device_data_offer
+- // callback.
+- wl_display_roundtrip(mDisplay);
+- wl_display_roundtrip(mDisplay);
+
+- if (mPrimarySelectionDataDeviceManager) {
++ gtk_primary_selection_device_manager *manager =
++ mDisplay->GetPrimarySelectionDeviceManager();
++ if (manager) {
+ gtk_primary_selection_device *primaryDataDevice =
+- gtk_primary_selection_device_manager_get_device(
+- mPrimarySelectionDataDeviceManager, mSeat);
++ gtk_primary_selection_device_manager_get_device(manager,
++ mDisplay->GetSeat());
+ gtk_primary_selection_device_add_listener(
+ primaryDataDevice, &primary_selection_device_listener, this);
+ }
+@@ -492,8 +625,21 @@ nsRetrievalContextWayland::nsRetrievalCo
+ mInitialized = true;
+ }
+
++static gboolean offer_hash_remove(gpointer wl_offer, gpointer aDataOffer,
++ gpointer user_data) {
++#ifdef DEBUG
++ nsPrintfCString msg("nsRetrievalContextWayland(): leaked nsDataOffer %p\n",
++ aDataOffer);
++ NS_WARNING(msg.get());
++#endif
++ delete static_cast<DataOffer *>(aDataOffer);
++ return true;
++}
++
+ nsRetrievalContextWayland::~nsRetrievalContextWayland(void) {
++ g_hash_table_foreach_remove(mActiveOffers, offer_hash_remove, nullptr);
+ g_hash_table_destroy(mActiveOffers);
++ WaylandDisplayRelease(mDisplay);
+ }
+
+ GdkAtom *nsRetrievalContextWayland::GetTargets(int32_t aWhichClipboard,
+@@ -533,12 +679,14 @@ static void wayland_clipboard_contents_r
+ void nsRetrievalContextWayland::TransferFastTrackClipboard(
+ int aClipboardRequestNumber, GtkSelectionData *aSelectionData) {
+ if (mClipboardRequestNumber == aClipboardRequestNumber) {
+- mClipboardDataLength = gtk_selection_data_get_length(aSelectionData);
+- if (mClipboardDataLength > 0) {
++ int dataLength = gtk_selection_data_get_length(aSelectionData);
++ if (dataLength > 0) {
++ mClipboardDataLength = dataLength;
+ mClipboardData = reinterpret_cast<char *>(
+- g_malloc(sizeof(char) * mClipboardDataLength));
++ g_malloc(sizeof(char) * (mClipboardDataLength + 1)));
+ memcpy(mClipboardData, gtk_selection_data_get_data(aSelectionData),
+ sizeof(char) * mClipboardDataLength);
++ mClipboardData[mClipboardDataLength] = '\0';
+ }
+ } else {
+ NS_WARNING("Received obsoleted clipboard data!");
+@@ -572,8 +720,8 @@ const char *nsRetrievalContextWayland::G
+ mClipboardData = nullptr;
+ mClipboardDataLength = 0;
+ } else {
+- mClipboardData =
+- dataOffer->GetData(mDisplay, aMimeType, &mClipboardDataLength);
++ mClipboardData = dataOffer->GetData(mDisplay->GetDisplay(), aMimeType,
++ &mClipboardDataLength);
+ }
+ }
+
+@@ -588,7 +736,7 @@ const char *nsRetrievalContextWayland::G
+ (selection == GDK_SELECTION_PRIMARY) ? mPrimaryOffer : mClipboardOffer;
+ if (!dataOffer) return nullptr;
+
+- for (unsigned int i = 0; i < sizeof(sTextMimeTypes); i++) {
++ for (unsigned int i = 0; i < TEXT_MIME_TYPES_NUM; i++) {
+ if (dataOffer->HasTarget(sTextMimeTypes[i])) {
+ uint32_t unused;
+ return GetClipboardData(sTextMimeTypes[i], aWhichClipboard, &unused);
+diff -up thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h.wayland thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h
+--- thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h 2019-02-05 14:26:16.975316648 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -9,6 +9,7 @@
+ #define __nsClipboardWayland_h_
+
+ #include "nsIClipboard.h"
++#include "mozwayland/mozwayland.h"
+ #include "wayland/gtk-primary-selection-client-protocol.h"
+
+ #include <gtk/gtk.h>
+@@ -32,31 +33,75 @@ class DataOffer {
+ private:
+ virtual bool RequestDataTransfer(const char* aMimeType, int fd) = 0;
+
++ protected:
+ nsTArray<GdkAtom> mTargetMIMETypes;
+ };
+
+ class WaylandDataOffer : public DataOffer {
+ public:
+- WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
++ explicit WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
++
++ void DragOfferAccept(const char* aMimeType, uint32_t aTime);
++ void SetDragStatus(GdkDragAction aAction, uint32_t aTime);
++
++ GdkDragAction GetSelectedDragAction();
++ void SetSelectedDragAction(uint32_t aWaylandAction);
++
++ void SetAvailableDragActions(uint32_t aWaylandActions);
++ GdkDragAction GetAvailableDragActions();
+
+- private:
+ virtual ~WaylandDataOffer();
++
++ private:
+ bool RequestDataTransfer(const char* aMimeType, int fd) override;
+
+ wl_data_offer* mWaylandDataOffer;
++ uint32_t mSelectedDragAction;
++ uint32_t mAvailableDragAction;
+ };
+
+ class PrimaryDataOffer : public DataOffer {
+ public:
+- PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
++ explicit PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
++ void SetAvailableDragActions(uint32_t aWaylandActions){};
+
+- private:
+ virtual ~PrimaryDataOffer();
++
++ private:
+ bool RequestDataTransfer(const char* aMimeType, int fd) override;
+
+ gtk_primary_selection_offer* mPrimaryDataOffer;
+ };
+
++class nsWaylandDragContext : public nsISupports {
++ NS_DECL_ISUPPORTS
++
++ public:
++ nsWaylandDragContext(WaylandDataOffer* aWaylandDataOffer,
++ wl_display* aDisplay);
++
++ void DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime, nscoord aX,
++ nscoord aY);
++ void DropMotion(uint32_t aTime, nscoord aX, nscoord aY);
++ void GetLastDropInfo(uint32_t* aTime, nscoord* aX, nscoord* aY);
++
++ void SetDragStatus(GdkDragAction action);
++ GdkDragAction GetSelectedDragAction();
++
++ GtkWidget* GetWidget() { return mGtkWidget; }
++ GList* GetTargets();
++ char* GetData(const char* aMimeType, uint32_t* aContentLength);
++
++ private:
++ virtual ~nsWaylandDragContext(){};
++
++ nsAutoPtr<WaylandDataOffer> mDataOffer;
++ wl_display* mDisplay;
++ uint32_t mTime;
++ GtkWidget* mGtkWidget;
++ nscoord mX, mY;
++};
++
+ class nsRetrievalContextWayland : public nsRetrievalContext {
+ public:
+ nsRetrievalContextWayland();
+@@ -71,38 +116,30 @@ class nsRetrievalContextWayland : public
+ int* aTargetNum) override;
+ virtual bool HasSelectionSupport(void) override;
+
+- void RegisterDataOffer(wl_data_offer* aWaylandDataOffer);
+- void RegisterDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
++ void RegisterNewDataOffer(wl_data_offer* aWaylandDataOffer);
++ void RegisterNewDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
+
+ void SetClipboardDataOffer(wl_data_offer* aWaylandDataOffer);
+ void SetPrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
++ void AddDragAndDropDataOffer(wl_data_offer* aWaylandDataOffer);
++ nsWaylandDragContext* GetDragContext();
+
+- void ClearDataOffers();
++ void ClearDragAndDropDataOffer();
+
+- void ConfigureKeyboard(wl_seat_capability caps);
+ void TransferFastTrackClipboard(int aClipboardRequestNumber,
+ GtkSelectionData* aSelectionData);
+
+- void InitDataDeviceManager(wl_registry* registry, uint32_t id,
+- uint32_t version);
+- void InitPrimarySelectionDataDeviceManager(wl_registry* registry,
+- uint32_t id);
+- void InitSeat(wl_registry* registry, uint32_t id, uint32_t version,
+- void* data);
+ virtual ~nsRetrievalContextWayland() override;
+
+ private:
+ bool mInitialized;
+- wl_display* mDisplay;
+- wl_seat* mSeat;
+- wl_data_device_manager* mDataDeviceManager;
+- gtk_primary_selection_device_manager* mPrimarySelectionDataDeviceManager;
+- wl_keyboard* mKeyboard;
++ nsWaylandDisplay* mDisplay;
+
+ // Data offers provided by Wayland data device
+ GHashTable* mActiveOffers;
+ nsAutoPtr<DataOffer> mClipboardOffer;
+ nsAutoPtr<DataOffer> mPrimaryOffer;
++ RefPtr<nsWaylandDragContext> mDragContext;
+
+ int mClipboardRequestNumber;
+ char* mClipboardData;
+diff -up thunderbird-60.5.0/widget/gtk/nsDragService.cpp.wayland thunderbird-60.5.0/widget/gtk/nsDragService.cpp
+--- thunderbird-60.5.0/widget/gtk/nsDragService.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsDragService.cpp 2019-02-05 14:26:16.976316645 +0100
+@@ -1,5 +1,5 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+-/* vim: set ts=4 et sw=4 tw=80: */
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=4 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+@@ -9,6 +9,7 @@
+ #include "nsIObserverService.h"
+ #include "nsWidgetsCID.h"
+ #include "nsWindow.h"
++#include "nsSystemInfo.h"
+ #include "nsIServiceManager.h"
+ #include "nsXPCOM.h"
+ #include "nsISupportsPrimitives.h"
+@@ -34,7 +35,6 @@
+ #include "nsPresContext.h"
+ #include "nsIContent.h"
+ #include "nsIDocument.h"
+-#include "nsISelection.h"
+ #include "nsViewManager.h"
+ #include "nsIFrame.h"
+ #include "nsGtkUtils.h"
+@@ -43,10 +43,15 @@
+ #include "gfxPlatform.h"
+ #include "ScreenHelperGTK.h"
+ #include "nsArrayUtils.h"
++#ifdef MOZ_WAYLAND
++#include "nsClipboardWayland.h"
++#endif
+
+ using namespace mozilla;
+ using namespace mozilla::gfx;
+
++#define NS_SYSTEMINFO_CONTRACTID "@mozilla.org/system-info;1"
++
+ // This sets how opaque the drag image is
+ #define DRAG_IMAGE_ALPHA_LEVEL 0.5
+
+@@ -68,6 +73,7 @@ static const char gMimeListType[] = "app
+ static const char gMozUrlType[] = "_NETSCAPE_URL";
+ static const char gTextUriListType[] = "text/uri-list";
+ static const char gTextPlainUTF8Type[] = "text/plain;charset=utf-8";
++static const char gXdndDirectSaveType[] = "XdndDirectSave0";
+
+ static void invisibleSourceDragBegin(GtkWidget *aWidget,
+ GdkDragContext *aContext, gpointer aData);
+@@ -85,7 +91,15 @@ static void invisibleSourceDragDataGet(G
+ guint aInfo, guint32 aTime,
+ gpointer aData);
+
+-nsDragService::nsDragService() : mScheduledTask(eDragTaskNone), mTaskSource(0) {
++nsDragService::nsDragService()
++ : mScheduledTask(eDragTaskNone),
++ mTaskSource(0)
++#ifdef MOZ_WAYLAND
++ ,
++ mPendingWaylandDragContext(nullptr),
++ mTargetWaylandDragContext(nullptr)
++#endif
++{
+ // We have to destroy the hidden widget before the event loop stops
+ // running.
+ nsCOMPtr<nsIObserverService> obsServ =
+@@ -159,7 +173,7 @@ nsDragService::Observe(nsISupports *aSub
+ }
+ TargetResetData();
+ } else {
+- NS_NOTREACHED("unexpected topic");
++ MOZ_ASSERT_UNREACHABLE("unexpected topic");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+@@ -457,6 +471,9 @@ nsDragService::EndDragSession(bool aDone
+
+ // We're done with the drag context.
+ mTargetDragContextForRemote = nullptr;
++#ifdef MOZ_WAYLAND
++ mTargetWaylandDragContextForRemote = nullptr;
++#endif
+
+ return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
+ }
+@@ -550,6 +567,14 @@ nsDragService::GetNumDropItems(uint32_t
+ return NS_OK;
+ }
+
++#ifdef MOZ_WAYLAND
++ // TODO: Wayland implementation of text/uri-list.
++ if (!mTargetDragContext) {
++ *aNumItems = 1;
++ return NS_OK;
++ }
++#endif
++
+ bool isList = IsTargetContextList();
+ if (isList)
+ mSourceDataItems->GetLength(aNumItems);
+@@ -907,9 +932,18 @@ nsDragService::IsDataFlavorSupported(con
+ }
+
+ // check the target context vs. this flavor, one at a time
+- GList *tmp;
+- for (tmp = gdk_drag_context_list_targets(mTargetDragContext); tmp;
+- tmp = tmp->next) {
++ GList *tmp = nullptr;
++ if (mTargetDragContext) {
++ tmp = gdk_drag_context_list_targets(mTargetDragContext);
++ }
++#ifdef MOZ_WAYLAND
++ else if (mTargetWaylandDragContext) {
++ tmp = mTargetWaylandDragContext->GetTargets();
++ }
++ GList *tmp_head = tmp;
++#endif
++
++ for (; tmp; tmp = tmp->next) {
+ /* Bug 331198 */
+ GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
+ gchar *name = nullptr;
+@@ -946,6 +980,15 @@ nsDragService::IsDataFlavorSupported(con
+ }
+ g_free(name);
+ }
++
++#ifdef MOZ_WAYLAND
++ // mTargetWaylandDragContext->GetTargets allocates the list
++ // so we need to free it here.
++ if (!mTargetDragContext && tmp_head) {
++ g_list_free(tmp_head);
++ }
++#endif
++
+ return NS_OK;
+ }
+
+@@ -975,6 +1018,34 @@ void nsDragService::ReplyToDragMotion(Gd
+ gdk_drag_status(aDragContext, action, mTargetTime);
+ }
+
++#ifdef MOZ_WAYLAND
++void nsDragService::ReplyToDragMotion(nsWaylandDragContext *aDragContext) {
++ MOZ_LOG(sDragLm, LogLevel::Debug,
++ ("nsDragService::ReplyToDragMotion %d", mCanDrop));
++
++ GdkDragAction action = (GdkDragAction)0;
++ if (mCanDrop) {
++ // notify the dragger if we can drop
++ switch (mDragAction) {
++ case DRAGDROP_ACTION_COPY:
++ action = GDK_ACTION_COPY;
++ break;
++ case DRAGDROP_ACTION_LINK:
++ action = GDK_ACTION_LINK;
++ break;
++ case DRAGDROP_ACTION_NONE:
++ action = (GdkDragAction)0;
++ break;
++ default:
++ action = GDK_ACTION_MOVE;
++ break;
++ }
++ }
++
++ aDragContext->SetDragStatus(action);
++}
++#endif
++
+ void nsDragService::TargetDataReceived(GtkWidget *aWidget,
+ GdkDragContext *aContext, gint aX,
+ gint aY,
+@@ -999,6 +1070,11 @@ void nsDragService::TargetDataReceived(G
+ bool nsDragService::IsTargetContextList(void) {
+ bool retval = false;
+
++#ifdef MOZ_WAYLAND
++ // TODO: We need a wayland implementation here.
++ if (!mTargetDragContext) return retval;
++#endif
++
+ // gMimeListType drags only work for drags within a single process. The
+ // gtk_drag_get_source_widget() function will return nullptr if the source
+ // of the drag is another app, so we use it to check if a gMimeListType
+@@ -1032,17 +1108,27 @@ void nsDragService::GetTargetDragData(Gd
+ mTargetDragContext.get()));
+ // reset our target data areas
+ TargetResetData();
+- gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
+
+- MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
+- PRTime entryTime = PR_Now();
+- while (!mTargetDragDataReceived && mDoingDrag) {
+- // check the number of iterations
+- MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
+- PR_Sleep(20 * PR_TicksPerSecond() / 1000); /* sleep for 20 ms/iteration */
+- if (PR_Now() - entryTime > NS_DND_TIMEOUT) break;
+- gtk_main_iteration();
++ if (mTargetDragContext) {
++ gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
++
++ MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
++ PRTime entryTime = PR_Now();
++ while (!mTargetDragDataReceived && mDoingDrag) {
++ // check the number of iterations
++ MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
++ PR_Sleep(20 * PR_TicksPerSecond() / 1000); /* sleep for 20 ms/iteration */
++ if (PR_Now() - entryTime > NS_DND_TIMEOUT) break;
++ gtk_main_iteration();
++ }
+ }
++#ifdef MOZ_WAYLAND
++ else {
++ mTargetDragData = mTargetWaylandDragContext->GetData(gdk_atom_name(aFlavor),
++ &mTargetDragDataLen);
++ mTargetDragDataReceived = true;
++ }
++#endif
+ MOZ_LOG(sDragLm, LogLevel::Debug, ("finished inner iteration\n"));
+ }
+
+@@ -1218,6 +1304,10 @@ void nsDragService::SourceEndDragSession
+ // this just releases the list of data items that we provide
+ mSourceDataItems = nullptr;
+
++ // Remove this property, if it exists, to satisfy the Direct Save Protocol.
++ GdkAtom property = gdk_atom_intern(gXdndDirectSaveType, FALSE);
++ gdk_property_delete(gdk_drag_context_get_source_window(aContext), property);
++
+ if (!mDoingDrag || mScheduledTask == eDragTaskSourceEnd)
+ // EndDragSession() was already called on drop
+ // or SourceEndDragSession on drag-failed
+@@ -1276,7 +1366,7 @@ void nsDragService::SourceEndDragSession
+ }
+
+ // Schedule the appropriate drag end dom events.
+- Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
++ Schedule(eDragTaskSourceEnd, nullptr, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
+ }
+
+ static void CreateUriList(nsIArray *items, gchar **text, gint *length) {
+@@ -1585,11 +1675,11 @@ static void invisibleSourceDragEnd(GtkWi
+ // Gecko drag events are in flight. This helps event handlers that may not
+ // expect nested events, while accessing an event's dataTransfer for example.
+
+-gboolean nsDragService::ScheduleMotionEvent(nsWindow *aWindow,
+- GdkDragContext *aDragContext,
+- LayoutDeviceIntPoint aWindowPoint,
+- guint aTime) {
+- if (mScheduledTask == eDragTaskMotion) {
++gboolean nsDragService::ScheduleMotionEvent(
++ nsWindow *aWindow, GdkDragContext *aDragContext,
++ nsWaylandDragContext *aWaylandDragContext,
++ LayoutDeviceIntPoint aWindowPoint, guint aTime) {
++ if (aDragContext && mScheduledTask == eDragTaskMotion) {
+ // The drag source has sent another motion message before we've
+ // replied to the previous. That shouldn't happen with Xdnd. The
+ // spec for Motif drags is less clear, but we'll just update the
+@@ -1600,23 +1690,26 @@ gboolean nsDragService::ScheduleMotionEv
+
+ // Returning TRUE means we'll reply with a status message, unless we first
+ // get a leave.
+- return Schedule(eDragTaskMotion, aWindow, aDragContext, aWindowPoint, aTime);
++ return Schedule(eDragTaskMotion, aWindow, aDragContext, aWaylandDragContext,
++ aWindowPoint, aTime);
+ }
+
+ void nsDragService::ScheduleLeaveEvent() {
+ // We don't know at this stage whether a drop signal will immediately
+ // follow. If the drop signal gets sent it will happen before we return
+ // to the main loop and the scheduled leave task will be replaced.
+- if (!Schedule(eDragTaskLeave, nullptr, nullptr, LayoutDeviceIntPoint(), 0)) {
++ if (!Schedule(eDragTaskLeave, nullptr, nullptr, nullptr,
++ LayoutDeviceIntPoint(), 0)) {
+ NS_WARNING("Drag leave after drop");
+ }
+ }
+
+-gboolean nsDragService::ScheduleDropEvent(nsWindow *aWindow,
+- GdkDragContext *aDragContext,
+- LayoutDeviceIntPoint aWindowPoint,
+- guint aTime) {
+- if (!Schedule(eDragTaskDrop, aWindow, aDragContext, aWindowPoint, aTime)) {
++gboolean nsDragService::ScheduleDropEvent(
++ nsWindow *aWindow, GdkDragContext *aDragContext,
++ nsWaylandDragContext *aWaylandDragContext,
++ LayoutDeviceIntPoint aWindowPoint, guint aTime) {
++ if (!Schedule(eDragTaskDrop, aWindow, aDragContext, aWaylandDragContext,
++ aWindowPoint, aTime)) {
+ NS_WARNING("Additional drag drop ignored");
+ return FALSE;
+ }
+@@ -1629,6 +1722,7 @@ gboolean nsDragService::ScheduleDropEven
+
+ gboolean nsDragService::Schedule(DragTask aTask, nsWindow *aWindow,
+ GdkDragContext *aDragContext,
++ nsWaylandDragContext *aWaylandDragContext,
+ LayoutDeviceIntPoint aWindowPoint,
+ guint aTime) {
+ // If there is an existing leave or motion task scheduled, then that
+@@ -1647,6 +1741,9 @@ gboolean nsDragService::Schedule(DragTas
+ mScheduledTask = aTask;
+ mPendingWindow = aWindow;
+ mPendingDragContext = aDragContext;
++#ifdef MOZ_WAYLAND
++ mPendingWaylandDragContext = aWaylandDragContext;
++#endif
+ mPendingWindowPoint = aWindowPoint;
+ mPendingTime = aTime;
+
+@@ -1717,6 +1814,9 @@ gboolean nsDragService::RunScheduledTask
+ // succeeed.
+ mTargetWidget = mTargetWindow->GetMozContainerWidget();
+ mTargetDragContext.steal(mPendingDragContext);
++#ifdef MOZ_WAYLAND
++ mTargetWaylandDragContext = mPendingWaylandDragContext.forget();
++#endif
+ mTargetTime = mPendingTime;
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
+@@ -1748,10 +1848,20 @@ gboolean nsDragService::RunScheduledTask
+ if (task == eDragTaskMotion) {
+ if (TakeDragEventDispatchedToChildProcess()) {
+ mTargetDragContextForRemote = mTargetDragContext;
++#ifdef MOZ_WAYLAND
++ mTargetWaylandDragContextForRemote = mTargetWaylandDragContext;
++#endif
+ } else {
+ // Reply to tell the source whether we can drop and what
+ // action would be taken.
+- ReplyToDragMotion(mTargetDragContext);
++ if (mTargetDragContext) {
++ ReplyToDragMotion(mTargetDragContext);
++ }
++#ifdef MOZ_WAYLAND
++ else if (mTargetWaylandDragContext) {
++ ReplyToDragMotion(mTargetWaylandDragContext);
++ }
++#endif
+ }
+ }
+ }
+@@ -1762,8 +1872,10 @@ gboolean nsDragService::RunScheduledTask
+ // Perhaps we should set the del parameter to TRUE when the drag
+ // action is move, but we don't know whether the data was successfully
+ // transferred.
+- gtk_drag_finish(mTargetDragContext, success,
+- /* del = */ FALSE, mTargetTime);
++ if (mTargetDragContext) {
++ gtk_drag_finish(mTargetDragContext, success,
++ /* del = */ FALSE, mTargetTime);
++ }
+
+ // This drag is over, so clear out our reference to the previous
+ // window.
+@@ -1776,6 +1888,9 @@ gboolean nsDragService::RunScheduledTask
+ // We're done with the drag context.
+ mTargetWidget = nullptr;
+ mTargetDragContext = nullptr;
++#ifdef MOZ_WAYLAND
++ mTargetWaylandDragContext = nullptr;
++#endif
+
+ // If we got another drag signal while running the sheduled task, that
+ // must have happened while running a nested event loop. Leave the task
+@@ -1802,7 +1917,16 @@ void nsDragService::UpdateDragAction() {
+
+ // default is to do nothing
+ int action = nsIDragService::DRAGDROP_ACTION_NONE;
+- GdkDragAction gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
++ GdkDragAction gdkAction = GDK_ACTION_DEFAULT;
++ if (mTargetDragContext) {
++ gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
++ }
++#ifdef MOZ_WAYLAND
++ else if (mTargetWaylandDragContext) {
++ // We got the selected D&D action from compositor on Wayland.
++ gdkAction = mTargetWaylandDragContext->GetSelectedDragAction();
++ }
++#endif
+
+ // set the default just in case nothing matches below
+ if (gdkAction & GDK_ACTION_DEFAULT)
+@@ -1830,6 +1954,12 @@ nsDragService::UpdateDragEffect() {
+ ReplyToDragMotion(mTargetDragContextForRemote);
+ mTargetDragContextForRemote = nullptr;
+ }
++#ifdef MOZ_WAYLAND
++ else if (mTargetWaylandDragContextForRemote) {
++ ReplyToDragMotion(mTargetWaylandDragContextForRemote);
++ mTargetWaylandDragContextForRemote = nullptr;
++ }
++#endif
+ return NS_OK;
+ }
+
+diff -up thunderbird-60.5.0/widget/gtk/nsDragService.h.wayland thunderbird-60.5.0/widget/gtk/nsDragService.h
+--- thunderbird-60.5.0/widget/gtk/nsDragService.h.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsDragService.h 2019-02-05 14:26:16.976316645 +0100
+@@ -1,5 +1,5 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+-/* vim: set ts=4 et sw=4 tw=80: */
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=4 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+@@ -14,6 +14,7 @@
+ #include <gtk/gtk.h>
+
+ class nsWindow;
++class nsWaylandDragContext;
+
+ namespace mozilla {
+ namespace gfx {
+@@ -91,10 +92,12 @@ class nsDragService final : public nsBas
+ guint aInfo, guint32 aTime);
+
+ gboolean ScheduleMotionEvent(nsWindow *aWindow, GdkDragContext *aDragContext,
++ nsWaylandDragContext *aPendingWaylandDragContext,
+ mozilla::LayoutDeviceIntPoint aWindowPoint,
+ guint aTime);
+ void ScheduleLeaveEvent();
+ gboolean ScheduleDropEvent(nsWindow *aWindow, GdkDragContext *aDragContext,
++ nsWaylandDragContext *aPendingWaylandDragContext,
+ mozilla::LayoutDeviceIntPoint aWindowPoint,
+ guint aTime);
+
+@@ -111,6 +114,8 @@ class nsDragService final : public nsBas
+ void SourceDataGet(GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint32 aTime);
+
++ void SourceBeginDrag(GdkDragContext *aContext);
++
+ // set the drag icon during drag-begin
+ void SetDragIcon(GdkDragContext *aContext);
+
+@@ -144,6 +149,9 @@ class nsDragService final : public nsBas
+ RefPtr<nsWindow> mPendingWindow;
+ mozilla::LayoutDeviceIntPoint mPendingWindowPoint;
+ nsCountedRef<GdkDragContext> mPendingDragContext;
++#ifdef MOZ_WAYLAND
++ RefPtr<nsWaylandDragContext> mPendingWaylandDragContext;
++#endif
+ guint mPendingTime;
+
+ // mTargetWindow and mTargetWindowPoint record the position of the last
+@@ -155,9 +163,15 @@ class nsDragService final : public nsBas
+ // motion or drop events. mTime records the corresponding timestamp.
+ nsCountedRef<GtkWidget> mTargetWidget;
+ nsCountedRef<GdkDragContext> mTargetDragContext;
++#ifdef MOZ_WAYLAND
++ RefPtr<nsWaylandDragContext> mTargetWaylandDragContext;
++#endif
+ // mTargetDragContextForRemote is set while waiting for a reply from
+ // a child process.
+ nsCountedRef<GdkDragContext> mTargetDragContextForRemote;
++#ifdef MOZ_WAYLAND
++ RefPtr<nsWaylandDragContext> mTargetWaylandDragContextForRemote;
++#endif
+ guint mTargetTime;
+
+ // is it OK to drop on us?
+@@ -196,6 +210,7 @@ class nsDragService final : public nsBas
+
+ gboolean Schedule(DragTask aTask, nsWindow *aWindow,
+ GdkDragContext *aDragContext,
++ nsWaylandDragContext *aPendingWaylandDragContext,
+ mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
+
+ // Callback for g_idle_add_full() to run mScheduledTask.
+@@ -204,6 +219,9 @@ class nsDragService final : public nsBas
+ void UpdateDragAction();
+ void DispatchMotionEvents();
+ void ReplyToDragMotion(GdkDragContext *aDragContext);
++#ifdef MOZ_WAYLAND
++ void ReplyToDragMotion(nsWaylandDragContext *aDragContext);
++#endif
+ gboolean DispatchDropEvent();
+ static uint32_t GetCurrentModifiers();
+ };
+diff -up thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp.wayland thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp
+--- thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp 2019-02-05 14:26:16.976316645 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -28,6 +28,10 @@
+ #include "mozilla/MouseEvents.h"
+ #include "mozilla/TextEvents.h"
+
++#ifdef MOZ_WAYLAND
++#include <sys/mman.h>
++#endif
++
+ namespace mozilla {
+ namespace widget {
+
+@@ -200,7 +204,11 @@ void KeymapWrapper::Init() {
+ mModifierKeys.Clear();
+ memset(mModifierMasks, 0, sizeof(mModifierMasks));
+
+- if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) InitBySystemSettings();
++ if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) InitBySystemSettingsX11();
++#ifdef MOZ_WAYLAND
++ else
++ InitBySystemSettingsWayland();
++#endif
+
+ gdk_window_add_filter(nullptr, FilterEvents, this);
+
+@@ -276,9 +284,9 @@ void KeymapWrapper::InitXKBExtension() {
+ ("%p InitXKBExtension, Succeeded", this));
+ }
+
+-void KeymapWrapper::InitBySystemSettings() {
++void KeymapWrapper::InitBySystemSettingsX11() {
+ MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
+- ("%p InitBySystemSettings, mGdkKeymap=%p", this, mGdkKeymap));
++ ("%p InitBySystemSettingsX11, mGdkKeymap=%p", this, mGdkKeymap));
+
+ Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
+
+@@ -439,6 +447,163 @@ void KeymapWrapper::InitBySystemSettings
+ XFree(xkeymap);
+ }
+
++#ifdef MOZ_WAYLAND
++void KeymapWrapper::SetModifierMask(xkb_keymap* aKeymap,
++ ModifierIndex aModifierIndex,
++ const char* aModifierName) {
++ static auto sXkbKeymapModGetIndex =
++ (xkb_mod_index_t(*)(struct xkb_keymap*, const char*))dlsym(
++ RTLD_DEFAULT, "xkb_keymap_mod_get_index");
++
++ xkb_mod_index_t index = sXkbKeymapModGetIndex(aKeymap, aModifierName);
++ if (index != XKB_MOD_INVALID) {
++ mModifierMasks[aModifierIndex] = (1 << index);
++ }
++}
++
++void KeymapWrapper::SetModifierMasks(xkb_keymap* aKeymap) {
++ KeymapWrapper* keymapWrapper = GetInstance();
++
++ // This mapping is derived from get_xkb_modifiers() at gdkkeys-wayland.c
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_NUM_LOCK, XKB_MOD_NAME_NUM);
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_ALT, XKB_MOD_NAME_ALT);
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_META, "Meta");
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_SUPER, "Super");
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_HYPER, "Hyper");
++
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_SCROLL_LOCK, "ScrollLock");
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, "Level3");
++ keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, "Level5");
++
++ MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
++ ("%p KeymapWrapper::SetModifierMasks, CapsLock=0x%X, NumLock=0x%X, "
++ "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
++ "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
++ keymapWrapper, keymapWrapper->GetModifierMask(CAPS_LOCK),
++ keymapWrapper->GetModifierMask(NUM_LOCK),
++ keymapWrapper->GetModifierMask(SCROLL_LOCK),
++ keymapWrapper->GetModifierMask(LEVEL3),
++ keymapWrapper->GetModifierMask(LEVEL5),
++ keymapWrapper->GetModifierMask(SHIFT),
++ keymapWrapper->GetModifierMask(CTRL),
++ keymapWrapper->GetModifierMask(ALT),
++ keymapWrapper->GetModifierMask(META),
++ keymapWrapper->GetModifierMask(SUPER),
++ keymapWrapper->GetModifierMask(HYPER)));
++}
++
++/* This keymap routine is derived from weston-2.0.0/clients/simple-im.c
++ */
++static void keyboard_handle_keymap(void* data, struct wl_keyboard* wl_keyboard,
++ uint32_t format, int fd, uint32_t size) {
++ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
++ close(fd);
++ return;
++ }
++
++ char* mapString = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
++ if (mapString == MAP_FAILED) {
++ close(fd);
++ return;
++ }
++
++ static auto sXkbContextNew =
++ (struct xkb_context * (*)(enum xkb_context_flags))
++ dlsym(RTLD_DEFAULT, "xkb_context_new");
++ static auto sXkbKeymapNewFromString =
++ (struct xkb_keymap * (*)(struct xkb_context*, const char*,
++ enum xkb_keymap_format,
++ enum xkb_keymap_compile_flags))
++ dlsym(RTLD_DEFAULT, "xkb_keymap_new_from_string");
++
++ struct xkb_context* xkb_context = sXkbContextNew(XKB_CONTEXT_NO_FLAGS);
++ struct xkb_keymap* keymap =
++ sXkbKeymapNewFromString(xkb_context, mapString, XKB_KEYMAP_FORMAT_TEXT_V1,
++ XKB_KEYMAP_COMPILE_NO_FLAGS);
++
++ munmap(mapString, size);
++ close(fd);
++
++ if (!keymap) {
++ NS_WARNING("keyboard_handle_keymap(): Failed to compile keymap!\n");
++ return;
++ }
++
++ KeymapWrapper::SetModifierMasks(keymap);
++
++ static auto sXkbKeymapUnRef =
++ (void (*)(struct xkb_keymap*))dlsym(RTLD_DEFAULT, "xkb_keymap_unref");
++ sXkbKeymapUnRef(keymap);
++
++ static auto sXkbContextUnref =
++ (void (*)(struct xkb_context*))dlsym(RTLD_DEFAULT, "xkb_context_unref");
++ sXkbContextUnref(xkb_context);
++}
++
++static void keyboard_handle_enter(void* data, struct wl_keyboard* keyboard,
++ uint32_t serial, struct wl_surface* surface,
++ struct wl_array* keys) {}
++static void keyboard_handle_leave(void* data, struct wl_keyboard* keyboard,
++ uint32_t serial, struct wl_surface* surface) {
++}
++static void keyboard_handle_key(void* data, struct wl_keyboard* keyboard,
++ uint32_t serial, uint32_t time, uint32_t key,
++ uint32_t state) {}
++static void keyboard_handle_modifiers(void* data, struct wl_keyboard* keyboard,
++ uint32_t serial, uint32_t mods_depressed,
++ uint32_t mods_latched,
++ uint32_t mods_locked, uint32_t group) {}
++
++static const struct wl_keyboard_listener keyboard_listener = {
++ keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave,
++ keyboard_handle_key, keyboard_handle_modifiers,
++};
++
++static void seat_handle_capabilities(void* data, struct wl_seat* seat,
++ unsigned int caps) {
++ static wl_keyboard* keyboard = nullptr;
++
++ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) {
++ keyboard = wl_seat_get_keyboard(seat);
++ wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr);
++ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) {
++ wl_keyboard_destroy(keyboard);
++ keyboard = nullptr;
++ }
++}
++
++static const struct wl_seat_listener seat_listener = {
++ seat_handle_capabilities,
++};
++
++static void gdk_registry_handle_global(void* data, struct wl_registry* registry,
++ uint32_t id, const char* interface,
++ uint32_t version) {
++ if (strcmp(interface, "wl_seat") == 0) {
++ wl_seat* seat =
++ (wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 1);
++ wl_seat_add_listener(seat, &seat_listener, data);
++ }
++}
++
++static void gdk_registry_handle_global_remove(void* data,
++ struct wl_registry* registry,
++ uint32_t id) {}
++
++static const struct wl_registry_listener keyboard_registry_listener = {
++ gdk_registry_handle_global, gdk_registry_handle_global_remove};
++
++void KeymapWrapper::InitBySystemSettingsWayland() {
++ // Available as of GTK 3.8+
++ static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay*))
++ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
++ wl_display* display =
++ sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
++ wl_registry_add_listener(wl_display_get_registry(display),
++ &keyboard_registry_listener, this);
++}
++#endif
++
+ KeymapWrapper::~KeymapWrapper() {
+ gdk_window_remove_filter(nullptr, FilterEvents, this);
+ g_signal_handlers_disconnect_by_func(mGdkKeymap,
+@@ -1473,6 +1638,14 @@ void KeymapWrapper::WillDispatchKeyboard
+
+ void KeymapWrapper::WillDispatchKeyboardEventInternal(
+ WidgetKeyboardEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) {
++ if (!aGdkKeyEvent) {
++ // If aGdkKeyEvent is nullptr, we're trying to dispatch a fake keyboard
++ // event in such case, we don't need to set alternative char codes.
++ // So, we don't need to do nothing here. This case is typically we're
++ // dispatching eKeyDown or eKeyUp event during composition.
++ return;
++ }
++
+ uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
+ if (!charCode) {
+ MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
+diff -up thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h.wayland thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h
+--- thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h 2019-02-05 14:26:16.976316645 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -13,6 +13,10 @@
+
+ #include <gdk/gdk.h>
+ #include <X11/XKBlib.h>
++#ifdef MOZ_WAYLAND
++#include <gdk/gdkwayland.h>
++#include <xkbcommon/xkbcommon.h>
++#endif
+
+ namespace mozilla {
+ namespace widget {
+@@ -145,6 +149,14 @@ class KeymapWrapper {
+ static void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyEvent,
+ GdkEventKey* aGdkKeyEvent);
+
++#ifdef MOZ_WAYLAND
++ /**
++ * Utility function to set all supported modifier masks
++ * from xkb_keymap. We call that from Wayland backend routines.
++ */
++ static void SetModifierMasks(xkb_keymap* aKeymap);
++#endif
++
+ /**
+ * Destroys the singleton KeymapWrapper instance, if it exists.
+ */
+@@ -168,7 +180,10 @@ class KeymapWrapper {
+ */
+ void Init();
+ void InitXKBExtension();
+- void InitBySystemSettings();
++ void InitBySystemSettingsX11();
++#ifdef MOZ_WAYLAND
++ void InitBySystemSettingsWayland();
++#endif
+
+ /**
+ * mModifierKeys stores each hardware key information.
+@@ -360,6 +375,14 @@ class KeymapWrapper {
+ */
+ void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent,
+ GdkEventKey* aGdkKeyEvent);
++
++#ifdef MOZ_WAYLAND
++ /**
++ * Utility function to set Xkb modifier key mask.
++ */
++ void SetModifierMask(xkb_keymap* aKeymap, ModifierIndex aModifierIndex,
++ const char* aModifierName);
++#endif
+ };
+
+ } // namespace widget
+diff -up thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp.wayland thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp
+--- thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp 2019-02-05 14:26:16.977316642 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -18,6 +18,7 @@
+
+ #include <fontconfig/fontconfig.h>
+ #include "gfxPlatformGtk.h"
++//#include "mozilla/FontPropertyTypes.h"
+ #include "ScreenHelperGTK.h"
+
+ #include "gtkdrawing.h"
+@@ -31,7 +32,9 @@
+ #include <cairo-gobject.h>
+ #include "WidgetStyleCache.h"
+ #include "prenv.h"
++#include "nsCSSColorUtils.h"
+
++using namespace mozilla;
+ using mozilla::LookAndFeel;
+
+ #define GDK_COLOR_TO_NS_RGB(c) \
+@@ -170,7 +173,7 @@ static bool GetBorderColors(GtkStyleCont
+ // GTK has an initial value of zero for border-widths, and so themes
+ // need to explicitly set border-widths to make borders visible.
+ GtkBorder border;
+- gtk_style_context_get_border(aContext, GTK_STATE_FLAG_NORMAL, &border);
++ gtk_style_context_get_border(aContext, state, &border);
+ visible = border.top != 0 || border.right != 0 || border.bottom != 0 ||
+ border.left != 0;
+ }
+@@ -199,6 +202,57 @@ static bool GetBorderColors(GtkStyleCont
+ return ret;
+ }
+
++// Finds ideal cell highlight colors used for unfocused+selected cells distinct
++// from both Highlight, used as focused+selected background, and the listbox
++// background which is assumed to be similar to -moz-field
++nsresult nsLookAndFeel::InitCellHighlightColors() {
++ // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE is the a11y standard for text
++ // on a background. Use 20% of that standard since we have a background
++ // on top of another background
++ int32_t minLuminosityDifference = NS_SUFFICIENT_LUMINOSITY_DIFFERENCE / 5;
++ int32_t backLuminosityDifference =
++ NS_LUMINOSITY_DIFFERENCE(mMozWindowBackground, mMozFieldBackground);
++ if (backLuminosityDifference >= minLuminosityDifference) {
++ mMozCellHighlightBackground = mMozWindowBackground;
++ mMozCellHighlightText = mMozWindowText;
++ return NS_OK;
++ }
++
++ uint16_t hue, sat, luminance;
++ uint8_t alpha;
++ mMozCellHighlightBackground = mMozFieldBackground;
++ mMozCellHighlightText = mMozFieldText;
++
++ NS_RGB2HSV(mMozCellHighlightBackground, hue, sat, luminance, alpha);
++
++ uint16_t step = 30;
++ // Lighten the color if the color is very dark
++ if (luminance <= step) {
++ luminance += step;
++ }
++ // Darken it if it is very light
++ else if (luminance >= 255 - step) {
++ luminance -= step;
++ }
++ // Otherwise, compute what works best depending on the text luminance.
++ else {
++ uint16_t textHue, textSat, textLuminance;
++ uint8_t textAlpha;
++ NS_RGB2HSV(mMozCellHighlightText, textHue, textSat, textLuminance,
++ textAlpha);
++ // Text is darker than background, use a lighter shade
++ if (textLuminance < luminance) {
++ luminance += step;
++ }
++ // Otherwise, use a darker shade
++ else {
++ luminance -= step;
++ }
++ }
++ NS_HSV2RGB(mMozCellHighlightBackground, hue, sat, luminance, alpha);
++ return NS_OK;
++}
++
+ void nsLookAndFeel::NativeInit() { EnsureInit(); }
+
+ void nsLookAndFeel::RefreshImpl() {
+@@ -248,7 +302,6 @@ nsresult nsLookAndFeel::NativeGetColor(C
+ case eColorID_IMESelectedRawTextBackground:
+ case eColorID_IMESelectedConvertedTextBackground:
+ case eColorID__moz_dragtargetzone:
+- case eColorID__moz_cellhighlight:
+ case eColorID__moz_html_cellhighlight:
+ case eColorID_highlight: // preference selected item,
+ aColor = mTextSelectedBackground;
+@@ -258,10 +311,15 @@ nsresult nsLookAndFeel::NativeGetColor(C
+ case eColorID_IMESelectedRawTextForeground:
+ case eColorID_IMESelectedConvertedTextForeground:
+ case eColorID_highlighttext:
+- case eColorID__moz_cellhighlighttext:
+ case eColorID__moz_html_cellhighlighttext:
+ aColor = mTextSelectedText;
+ break;
++ case eColorID__moz_cellhighlight:
++ aColor = mMozCellHighlightBackground;
++ break;
++ case eColorID__moz_cellhighlighttext:
++ aColor = mMozCellHighlightText;
++ break;
+ case eColorID_Widget3DHighlight:
+ aColor = NS_RGB(0xa0, 0xa0, 0xa0);
+ break;
+@@ -961,6 +1019,9 @@ void nsLookAndFeel::EnsureInit() {
+ mOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
+ gtk_style_context_restore(style);
+
++ // Compute cell highlight colors
++ InitCellHighlightColors();
++
+ // GtkFrame has a "border" subnode on which Adwaita draws the border.
+ // Some themes do not draw on this node but draw a border on the widget
+ // root node, so check the root node if no border is found on the border
+diff -up thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h.wayland thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h
+--- thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h 2019-02-05 14:26:16.977316642 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -8,6 +8,7 @@
+ #ifndef __nsLookAndFeel
+ #define __nsLookAndFeel
+
++#include "X11UndefineNone.h"
+ #include "nsXPLookAndFeel.h"
+ #include "nsCOMPtr.h"
+ #include "gfxFont.h"
+@@ -75,6 +76,8 @@ class nsLookAndFeel final : public nsXPL
+ nscolor mMozWindowActiveBorder;
+ nscolor mMozWindowInactiveBorder;
+ nscolor mMozWindowInactiveCaption;
++ nscolor mMozCellHighlightBackground;
++ nscolor mMozCellHighlightText;
+ nscolor mTextSelectedText;
+ nscolor mTextSelectedBackground;
+ nscolor mMozScrollbar;
+@@ -89,6 +92,9 @@ class nsLookAndFeel final : public nsXPL
+ bool mInitialized;
+
+ void EnsureInit();
++
++ private:
++ nsresult InitCellHighlightColors();
+ };
+
+ #endif
+diff -up thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp.wayland thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp
+--- thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp.wayland 2019-02-05 14:26:16.977316642 +0100
++++ thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp 2019-02-05 14:26:16.977316642 +0100
+@@ -0,0 +1,222 @@
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim:expandtab:shiftwidth=4:tabstop=4:
++ */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsWaylandDisplay.h"
++
++#include "base/message_loop.h" // for MessageLoop
++#include "base/task.h" // for NewRunnableMethod, etc
++#include "mozilla/StaticMutex.h"
++
++namespace mozilla {
++namespace widget {
++
++#define MAX_DISPLAY_CONNECTIONS 2
++
++static nsWaylandDisplay *gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
++static StaticMutex gWaylandDisplaysMutex;
++
++// Each thread which is using wayland connection (wl_display) has to operate
++// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
++// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
++//
++// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
++// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
++// compositor (not the main) thread.
++static void WaylandDisplayLoop(wl_display *aDisplay);
++
++// Get WaylandDisplay for given wl_display and actual calling thread.
++static nsWaylandDisplay *WaylandDisplayGetLocked(wl_display *aDisplay,
++ const StaticMutexAutoLock &) {
++ for (auto &display : gWaylandDisplays) {
++ if (display && display->Matches(aDisplay)) {
++ NS_ADDREF(display);
++ return display;
++ }
++ }
++
++ for (auto &display : gWaylandDisplays) {
++ if (display == nullptr) {
++ display = new nsWaylandDisplay(aDisplay);
++ NS_ADDREF(display);
++ return display;
++ }
++ }
++
++ MOZ_CRASH("There's too many wayland display conections!");
++ return nullptr;
++}
++
++nsWaylandDisplay *WaylandDisplayGet(GdkDisplay *aGdkDisplay) {
++ if (!aGdkDisplay) {
++ aGdkDisplay = gdk_display_get_default();
++ }
++
++ // Available as of GTK 3.8+
++ static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
++ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
++
++ wl_display *display = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
++
++ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
++ return WaylandDisplayGetLocked(display, lock);
++}
++
++static bool WaylandDisplayReleaseLocked(nsWaylandDisplay *aDisplay,
++ const StaticMutexAutoLock &) {
++ for (auto &display : gWaylandDisplays) {
++ if (display == aDisplay) {
++ int rc = display->Release();
++ if (rc == 0) {
++ display = nullptr;
++ }
++ return true;
++ }
++ }
++ MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
++ return false;
++}
++
++void WaylandDisplayRelease(nsWaylandDisplay *aDisplay) {
++ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
++ WaylandDisplayReleaseLocked(aDisplay, lock);
++}
++
++static void WaylandDisplayLoopLocked(wl_display *aDisplay,
++ const StaticMutexAutoLock &) {
++ for (auto &display : gWaylandDisplays) {
++ if (display && display->Matches(aDisplay)) {
++ if (display->DisplayLoop()) {
++ MessageLoop::current()->PostDelayedTask(
++ NewRunnableFunction("WaylandDisplayLoop", &WaylandDisplayLoop,
++ aDisplay),
++ EVENT_LOOP_DELAY);
++ }
++ break;
++ }
++ }
++}
++
++static void WaylandDisplayLoop(wl_display *aDisplay) {
++ MOZ_ASSERT(!NS_IsMainThread());
++ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
++ WaylandDisplayLoopLocked(aDisplay, lock);
++}
++
++void nsWaylandDisplay::SetShm(wl_shm *aShm) { mShm = aShm; }
++
++void nsWaylandDisplay::SetSubcompositor(wl_subcompositor *aSubcompositor) {
++ mSubcompositor = aSubcompositor;
++}
++
++void nsWaylandDisplay::SetDataDeviceManager(
++ wl_data_device_manager *aDataDeviceManager) {
++ mDataDeviceManager = aDataDeviceManager;
++}
++
++void nsWaylandDisplay::SetSeat(wl_seat *aSeat) { mSeat = aSeat; }
++
++void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
++ gtk_primary_selection_device_manager *aPrimarySelectionDeviceManager) {
++ mPrimarySelectionDeviceManager = aPrimarySelectionDeviceManager;
++}
++
++static void global_registry_handler(void *data, wl_registry *registry,
++ uint32_t id, const char *interface,
++ uint32_t version) {
++ auto display = reinterpret_cast<nsWaylandDisplay *>(data);
++
++ if (strcmp(interface, "wl_shm") == 0) {
++ auto shm = static_cast<wl_shm *>(
++ wl_registry_bind(registry, id, &wl_shm_interface, 1));
++ wl_proxy_set_queue((struct wl_proxy *)shm, display->GetEventQueue());
++ display->SetShm(shm);
++ } else if (strcmp(interface, "wl_data_device_manager") == 0) {
++ int data_device_manager_version = MIN(version, 3);
++ auto data_device_manager = static_cast<wl_data_device_manager *>(
++ wl_registry_bind(registry, id, &wl_data_device_manager_interface,
++ data_device_manager_version));
++ wl_proxy_set_queue((struct wl_proxy *)data_device_manager,
++ display->GetEventQueue());
++ display->SetDataDeviceManager(data_device_manager);
++ } else if (strcmp(interface, "wl_seat") == 0) {
++ auto seat = static_cast<wl_seat *>(
++ wl_registry_bind(registry, id, &wl_seat_interface, 1));
++ wl_proxy_set_queue((struct wl_proxy *)seat, display->GetEventQueue());
++ display->SetSeat(seat);
++ } else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
++ auto primary_selection_device_manager =
++ static_cast<gtk_primary_selection_device_manager *>(wl_registry_bind(
++ registry, id, &gtk_primary_selection_device_manager_interface, 1));
++ wl_proxy_set_queue((struct wl_proxy *)primary_selection_device_manager,
++ display->GetEventQueue());
++ display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
++ } else if (strcmp(interface, "wl_subcompositor") == 0) {
++ auto subcompositor = static_cast<wl_subcompositor *>(
++ wl_registry_bind(registry, id, &wl_subcompositor_interface, 1));
++ wl_proxy_set_queue((struct wl_proxy *)subcompositor,
++ display->GetEventQueue());
++ display->SetSubcompositor(subcompositor);
++ }
++}
++
++static void global_registry_remover(void *data, wl_registry *registry,
++ uint32_t id) {}
++
++static const struct wl_registry_listener registry_listener = {
++ global_registry_handler, global_registry_remover};
++
++bool nsWaylandDisplay::DisplayLoop() {
++ wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
++ return true;
++}
++
++bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
++ return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
++}
++
++NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
++
++nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
++ : mThreadId(PR_GetCurrentThread()),
++ mDisplay(aDisplay),
++ mEventQueue(nullptr),
++ mDataDeviceManager(nullptr),
++ mSubcompositor(nullptr),
++ mSeat(nullptr),
++ mShm(nullptr),
++ mPrimarySelectionDeviceManager(nullptr) {
++ wl_registry *registry = wl_display_get_registry(mDisplay);
++ wl_registry_add_listener(registry, &registry_listener, this);
++
++ if (NS_IsMainThread()) {
++ // Use default event queue in main thread operated by Gtk+.
++ mEventQueue = nullptr;
++ wl_display_roundtrip(mDisplay);
++ wl_display_roundtrip(mDisplay);
++ } else {
++ mEventQueue = wl_display_create_queue(mDisplay);
++ MessageLoop::current()->PostTask(NewRunnableFunction(
++ "WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
++ wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
++ wl_display_roundtrip_queue(mDisplay, mEventQueue);
++ wl_display_roundtrip_queue(mDisplay, mEventQueue);
++ }
++}
++
++nsWaylandDisplay::~nsWaylandDisplay() {
++ MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
++ // Owned by Gtk+, we don't need to release
++ mDisplay = nullptr;
++
++ if (mEventQueue) {
++ wl_event_queue_destroy(mEventQueue);
++ mEventQueue = nullptr;
++ }
++}
++
++} // namespace widget
++} // namespace mozilla
+diff -up thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h.wayland thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h
+--- thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h.wayland 2019-02-05 14:26:16.977316642 +0100
++++ thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h 2019-02-05 14:26:16.977316642 +0100
+@@ -0,0 +1,72 @@
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim:expandtab:shiftwidth=4:tabstop=4:
++ */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef __MOZ_WAYLAND_REGISTRY_H__
++#define __MOZ_WAYLAND_REGISTRY_H__
++
++#include "nsISupports.h"
++#include "mozwayland/mozwayland.h"
++#include "wayland/gtk-primary-selection-client-protocol.h"
++
++namespace mozilla {
++namespace widget {
++
++// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending()
++// with compositor event loop.
++#define EVENT_LOOP_DELAY (1000 / 240)
++
++// Our general connection to Wayland display server,
++// holds our display connection and runs event loop.
++class nsWaylandDisplay : public nsISupports {
++ NS_DECL_THREADSAFE_ISUPPORTS
++
++ public:
++ explicit nsWaylandDisplay(wl_display* aDisplay);
++
++ bool DisplayLoop();
++ bool Matches(wl_display* aDisplay);
++
++ wl_display* GetDisplay() { return mDisplay; };
++ wl_event_queue* GetEventQueue() { return mEventQueue; };
++ wl_subcompositor* GetSubcompositor(void) { return mSubcompositor; };
++ wl_data_device_manager* GetDataDeviceManager(void) {
++ return mDataDeviceManager;
++ };
++ wl_seat* GetSeat(void) { return mSeat; };
++ wl_shm* GetShm(void) { return mShm; };
++ gtk_primary_selection_device_manager* GetPrimarySelectionDeviceManager(void) {
++ return mPrimarySelectionDeviceManager;
++ };
++
++ public:
++ void SetShm(wl_shm* aShm);
++ void SetSubcompositor(wl_subcompositor* aSubcompositor);
++ void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager);
++ void SetSeat(wl_seat* aSeat);
++ void SetPrimarySelectionDeviceManager(
++ gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
++
++ private:
++ virtual ~nsWaylandDisplay();
++
++ PRThread* mThreadId;
++ wl_display* mDisplay;
++ wl_event_queue* mEventQueue;
++ wl_data_device_manager* mDataDeviceManager;
++ wl_subcompositor* mSubcompositor;
++ wl_seat* mSeat;
++ wl_shm* mShm;
++ gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
++};
++
++nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
++void WaylandDisplayRelease(nsWaylandDisplay* aDisplay);
++
++} // namespace widget
++} // namespace mozilla
++
++#endif // __MOZ_WAYLAND_REGISTRY_H__
+diff -up thunderbird-60.5.0/widget/gtk/nsWindow.cpp.wayland thunderbird-60.5.0/widget/gtk/nsWindow.cpp
+--- thunderbird-60.5.0/widget/gtk/nsWindow.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsWindow.cpp 2019-02-05 14:26:16.978316639 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -18,6 +18,7 @@
+ #include "mozilla/TouchEvents.h"
+ #include "mozilla/UniquePtrExtensions.h"
+ #include "mozilla/WidgetUtils.h"
++#include "mozilla/dom/WheelEventBinding.h"
+ #include <algorithm>
+
+ #include "GeckoProfiler.h"
+@@ -25,13 +26,15 @@
+ #include "prlink.h"
+ #include "nsGTKToolkit.h"
+ #include "nsIRollupListener.h"
+-#include "nsIDOMNode.h"
++#include "nsINode.h"
+
+ #include "nsWidgetsCID.h"
+ #include "nsDragService.h"
+ #include "nsIWidgetListener.h"
+ #include "nsIScreenManager.h"
+ #include "SystemTimeConverter.h"
++#include "nsIPresShell.h"
++#include "nsViewManager.h"
+
+ #include "nsGtkKeyUtils.h"
+ #include "nsGtkCursors.h"
+@@ -56,6 +59,7 @@
+
+ #if defined(MOZ_WAYLAND)
+ #include <gdk/gdkwayland.h>
++#include "nsView.h"
+ #endif
+
+ #include "nsGkAtoms.h"
+@@ -116,6 +120,7 @@ using namespace mozilla::widget;
+ #include "mozilla/layers/CompositorThread.h"
+
+ #ifdef MOZ_X11
++#include "GLContextGLX.h" // for GLContextGLX::FindVisual()
+ #include "GtkCompositorWidget.h"
+ #include "gfxXlibSurface.h"
+ #include "WindowSurfaceX11Image.h"
+@@ -129,8 +134,6 @@ using namespace mozilla::widget;
+ #include "nsShmImage.h"
+ #include "gtkdrawing.h"
+
+-#include "nsIDOMWheelEvent.h"
+-
+ #include "NativeKeyBindings.h"
+
+ #include <dlfcn.h>
+@@ -140,6 +143,7 @@ using namespace mozilla::gfx;
+ using namespace mozilla::widget;
+ using namespace mozilla::layers;
+ using mozilla::gl::GLContext;
++using mozilla::gl::GLContextGLX;
+
+ // Don't put more than this many rects in the dirty region, just fluff
+ // out to the bounding-box if there are more
+@@ -152,9 +156,12 @@ const gint kEvents =
+ #if GTK_CHECK_VERSION(3, 4, 0)
+ GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK |
+ #endif
+- GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK;
++ GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK |
++ GDK_FOCUS_CHANGE_MASK;
+
+ /* utility functions */
++static void theme_changed_cb(GtkSettings *settings, GParamSpec *pspec,
++ nsWindow *data);
+ static bool is_mouse_in_window(GdkWindow *aWindow, gdouble aMouseX,
+ gdouble aMouseY);
+ static nsWindow *get_window_for_gtk_widget(GtkWidget *widget);
+@@ -196,8 +203,6 @@ static void hierarchy_changed_cb(GtkWidg
+ GtkWidget *previous_toplevel);
+ static gboolean window_state_event_cb(GtkWidget *widget,
+ GdkEventWindowState *event);
+-static void theme_changed_cb(GtkSettings *settings, GParamSpec *pspec,
+- nsWindow *data);
+ static void check_resize_cb(GtkContainer *container, gpointer user_data);
+ static void screen_composited_changed_cb(GdkScreen *screen, gpointer user_data);
+ static void widget_composited_changed_cb(GtkWidget *widget, gpointer user_data);
+@@ -550,7 +555,7 @@ static GtkWidget *EnsureInvisibleContain
+ }
+
+ static void CheckDestroyInvisibleContainer() {
+- NS_PRECONDITION(gInvisibleContainer, "oh, no");
++ MOZ_ASSERT(gInvisibleContainer, "oh, no");
+
+ if (!gdk_window_peek_children(gtk_widget_get_window(gInvisibleContainer))) {
+ // No children, so not in use.
+@@ -639,9 +644,6 @@ void nsWindow::Destroy() {
+
+ ClearCachedResources();
+
+- g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
+- FuncToGpointer(theme_changed_cb), this);
+-
+ nsIRollupListener *rollupListener = nsBaseWidget::GetActiveRollupListener();
+ if (rollupListener) {
+ nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+@@ -725,7 +727,7 @@ double nsWindow::GetDefaultScaleInternal
+ DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() {
+ #ifdef MOZ_WAYLAND
+ GdkDisplay *gdkDisplay = gdk_display_get_default();
+- if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
++ if (!GDK_IS_X11_DISPLAY(gdkDisplay)) {
+ return DesktopToLayoutDeviceScale(GdkScaleFactor());
+ }
+ #endif
+@@ -735,8 +737,14 @@ DesktopToLayoutDeviceScale nsWindow::Get
+ }
+
+ void nsWindow::SetParent(nsIWidget *aNewParent) {
+- if (mContainer || !mGdkWindow) {
+- NS_NOTREACHED("nsWindow::SetParent called illegally");
++ if (!mGdkWindow) {
++ MOZ_ASSERT_UNREACHABLE("The native window has already been destroyed");
++ return;
++ }
++
++ if (mContainer) {
++ // FIXME bug 1469183
++ NS_ERROR("nsWindow should not have a container here");
+ return;
+ }
+
+@@ -774,7 +782,7 @@ void nsWindow::SetParent(nsIWidget *aNew
+ bool nsWindow::WidgetTypeSupportsAcceleration() { return !IsSmallPopup(); }
+
+ void nsWindow::ReparentNativeWidget(nsIWidget *aNewParent) {
+- NS_PRECONDITION(aNewParent, "");
++ MOZ_ASSERT(aNewParent, "null widget");
+ NS_ASSERTION(!mIsDestroyed, "");
+ NS_ASSERTION(!static_cast<nsWindow *>(aNewParent)->mIsDestroyed, "");
+
+@@ -1331,7 +1339,7 @@ LayoutDeviceIntRect nsWindow::GetClientB
+ }
+
+ void nsWindow::UpdateClientOffset() {
+- AUTO_PROFILER_LABEL("nsWindow::UpdateClientOffset", GRAPHICS);
++ AUTO_PROFILER_LABEL("nsWindow::UpdateClientOffset", OTHER);
+
+ if (!mIsTopLevel || !mShell || !mIsX11Display ||
+ gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
+@@ -1373,9 +1381,7 @@ LayoutDeviceIntPoint nsWindow::GetClient
+ }
+
+ gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget *aWidget,
+- GdkEventProperty *aEvent)
+-
+-{
++ GdkEventProperty *aEvent) {
+ if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
+ UpdateClientOffset();
+
+@@ -1820,6 +1826,9 @@ gboolean nsWindow::OnExposeEvent(cairo_t
+
+ // Windows that are not visible will be painted after they become visible.
+ if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE;
++#ifdef MOZ_WAYLAND
++ if (mContainer && !mContainer->ready_to_draw) return FALSE;
++#endif
+
+ nsIWidgetListener *listener = GetListener();
+ if (!listener) return FALSE;
+@@ -3000,6 +3009,33 @@ void nsWindow::OnWindowStateEvent(GtkWid
+ }
+ // else the widget is a shell widget.
+
++ // The block below is a bit evil.
++ //
++ // When a window is resized before it is shown, gtk_window_resize() delays
++ // resizes until the window is shown. If gtk_window_state_event() sees a
++ // GDK_WINDOW_STATE_MAXIMIZED change [1] before the window is shown, then
++ // gtk_window_compute_configure_request_size() ignores the values from the
++ // resize [2]. See bug 1449166 for an example of how this could happen.
++ //
++ // [1] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L7967
++ // [2] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L9377
++ //
++ // In order to provide a sensible size for the window when the user exits
++ // maximized state, we hide the GDK_WINDOW_STATE_MAXIMIZED change from
++ // gtk_window_state_event() so as to trick GTK into using the values from
++ // gtk_window_resize() in its configure request.
++ //
++ // We instead notify gtk_window_state_event() of the maximized state change
++ // once the window is shown.
++ if (!mIsShown) {
++ aEvent->changed_mask = static_cast<GdkWindowState>(
++ aEvent->changed_mask & ~GDK_WINDOW_STATE_MAXIMIZED);
++ } else if (aEvent->changed_mask & GDK_WINDOW_STATE_WITHDRAWN &&
++ aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
++ aEvent->changed_mask = static_cast<GdkWindowState>(
++ aEvent->changed_mask | GDK_WINDOW_STATE_MAXIMIZED);
++ }
++
+ // We don't care about anything but changes in the maximized/icon/fullscreen
+ // states
+ if ((aEvent->changed_mask &
+@@ -3075,6 +3111,7 @@ void nsWindow::OnDPIChanged() {
+ // Update menu's font size etc
+ presShell->ThemeChanged();
+ }
++ mWidgetListener->UIResolutionChanged();
+ }
+ }
+
+@@ -3443,13 +3480,15 @@ nsresult nsWindow::Create(nsIWidget *aPa
+ gtk_style_context_has_class(style, "csd");
+ eventWidget = (drawToContainer) ? container : mShell;
+
+- gtk_widget_add_events(eventWidget, kEvents);
+- if (drawToContainer)
+- gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
+-
+ // Prevent GtkWindow from painting a background to avoid flickering.
+ gtk_widget_set_app_paintable(eventWidget, TRUE);
+
++ gtk_widget_add_events(eventWidget, kEvents);
++ if (drawToContainer) {
++ gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
++ gtk_widget_set_app_paintable(mShell, TRUE);
++ }
++
+ // If we draw to mContainer window then configure it now because
+ // gtk_container_add() realizes the child widget.
+ gtk_widget_set_has_window(container, drawToContainer);
+@@ -3698,6 +3737,15 @@ nsresult nsWindow::Create(nsIWidget *aPa
+ mXDepth = gdk_visual_get_depth(gdkVisual);
+
+ mSurfaceProvider.Initialize(mXDisplay, mXWindow, mXVisual, mXDepth);
++
++ if (mIsTopLevel) {
++ // Set window manager hint to keep fullscreen windows composited.
++ //
++ // If the window were to get unredirected, there could be visible
++ // tearing because Gecko does not align its framebuffer updates with
++ // vblank.
++ // SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
++ }
+ }
+ #ifdef MOZ_WAYLAND
+ else if (!mIsX11Display) {
+@@ -3708,12 +3756,37 @@ nsresult nsWindow::Create(nsIWidget *aPa
+ return NS_OK;
+ }
+
++void nsWindow::RefreshWindowClass(void) {
++ if (mGtkWindowTypeName.IsEmpty() || mGtkWindowRoleName.IsEmpty()) return;
++
++ GdkWindow *gdkWindow = gtk_widget_get_window(mShell);
++ gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
++
++#ifdef MOZ_X11
++ if (mIsX11Display) {
++ XClassHint *class_hint = XAllocClassHint();
++ if (!class_hint) {
++ return;
++ }
++ const char *res_class = gdk_get_program_class();
++ if (!res_class) return;
++
++ class_hint->res_name = const_cast<char *>(mGtkWindowTypeName.get());
++ class_hint->res_class = const_cast<char *>(res_class);
++
++ // Can't use gtk_window_set_wmclass() for this; it prints
++ // a warning & refuses to make the change.
++ GdkDisplay *display = gdk_display_get_default();
++ XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
++ gdk_x11_window_get_xid(gdkWindow), class_hint);
++ XFree(class_hint);
++ }
++#endif /* MOZ_X11 */
++}
++
+ void nsWindow::SetWindowClass(const nsAString &xulWinType) {
+ if (!mShell) return;
+
+- const char *res_class = gdk_get_program_class();
+- if (!res_class) return;
+-
+ char *res_name = ToNewCString(xulWinType);
+ if (!res_name) return;
+
+@@ -3733,29 +3806,11 @@ void nsWindow::SetWindowClass(const nsAS
+ res_name[0] = toupper(res_name[0]);
+ if (!role) role = res_name;
+
+- GdkWindow *gdkWindow = gtk_widget_get_window(mShell);
+- gdk_window_set_role(gdkWindow, role);
+-
+-#ifdef MOZ_X11
+- if (mIsX11Display) {
+- XClassHint *class_hint = XAllocClassHint();
+- if (!class_hint) {
+- free(res_name);
+- return;
+- }
+- class_hint->res_name = res_name;
+- class_hint->res_class = const_cast<char *>(res_class);
+-
+- // Can't use gtk_window_set_wmclass() for this; it prints
+- // a warning & refuses to make the change.
+- GdkDisplay *display = gdk_display_get_default();
+- XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
+- gdk_x11_window_get_xid(gdkWindow), class_hint);
+- XFree(class_hint);
+- }
+-#endif /* MOZ_X11 */
+-
++ mGtkWindowTypeName = res_name;
++ mGtkWindowRoleName = role;
+ free(res_name);
++
++ RefreshWindowClass();
+ }
+
+ void nsWindow::NativeResize() {
+@@ -3820,6 +3875,8 @@ void nsWindow::NativeMoveResize() {
+ NativeShow(false);
+ }
+ NativeMove();
++
++ return;
+ }
+
+ GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
+@@ -3832,6 +3889,8 @@ void nsWindow::NativeMoveResize() {
+ // x and y give the position of the window manager frame top-left.
+ gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
+ // This sets the client window size.
++ MOZ_ASSERT(size.width > 0 && size.height > 0,
++ "Can't resize window smaller than 1x1.");
+ gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
+ } else if (mContainer) {
+ GtkAllocation allocation;
+@@ -3877,6 +3936,16 @@ void nsWindow::NativeShow(bool aAction)
+ gdk_window_show_unraised(mGdkWindow);
+ }
+ } else {
++#ifdef MOZ_WAYLAND
++ if (mContainer && moz_container_has_wl_egl_window(mContainer)) {
++ // Because wl_egl_window is destroyed on moz_container_unmap(),
++ // the current compositor cannot use it anymore. To avoid crash,
++ // destroy the compositor & recreate a new compositor on next
++ // expose event.
++ DestroyLayerManager();
++ }
++#endif
++
+ if (mIsTopLevel) {
+ // Workaround window freezes on GTK versions before 3.21.2 by
+ // ensuring that configure events get dispatched to windows before
+@@ -5436,9 +5505,10 @@ void nsWindow::InitDragEvent(WidgetDragE
+ KeymapWrapper::InitInputEvent(aEvent, modifierState);
+ }
+
+-static gboolean drag_motion_event_cb(GtkWidget *aWidget,
+- GdkDragContext *aDragContext, gint aX,
+- gint aY, guint aTime, gpointer aData) {
++gboolean WindowDragMotionHandler(GtkWidget *aWidget,
++ GdkDragContext *aDragContext,
++ nsWaylandDragContext *aWaylandDragContext,
++ gint aX, gint aY, guint aTime) {
+ RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
+ if (!window) return FALSE;
+
+@@ -5459,13 +5529,17 @@ static gboolean drag_motion_event_cb(Gtk
+ LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({retx, rety});
+
+ RefPtr<nsDragService> dragService = nsDragService::GetInstance();
+- return dragService->ScheduleMotionEvent(innerMostWindow, aDragContext, point,
+- aTime);
++ return dragService->ScheduleMotionEvent(innerMostWindow, aDragContext,
++ aWaylandDragContext, point, aTime);
+ }
+
+-static void drag_leave_event_cb(GtkWidget *aWidget,
+- GdkDragContext *aDragContext, guint aTime,
+- gpointer aData) {
++static gboolean drag_motion_event_cb(GtkWidget *aWidget,
++ GdkDragContext *aDragContext, gint aX,
++ gint aY, guint aTime, gpointer aData) {
++ return WindowDragMotionHandler(aWidget, aDragContext, nullptr, aX, aY, aTime);
++}
++
++void WindowDragLeaveHandler(GtkWidget *aWidget) {
+ RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
+ if (!window) return;
+
+@@ -5495,9 +5569,15 @@ static void drag_leave_event_cb(GtkWidge
+ dragService->ScheduleLeaveEvent();
+ }
+
+-static gboolean drag_drop_event_cb(GtkWidget *aWidget,
+- GdkDragContext *aDragContext, gint aX,
+- gint aY, guint aTime, gpointer aData) {
++static void drag_leave_event_cb(GtkWidget *aWidget,
++ GdkDragContext *aDragContext, guint aTime,
++ gpointer aData) {
++ WindowDragLeaveHandler(aWidget);
++}
++
++gboolean WindowDragDropHandler(GtkWidget *aWidget, GdkDragContext *aDragContext,
++ nsWaylandDragContext *aWaylandDragContext,
++ gint aX, gint aY, guint aTime) {
+ RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
+ if (!window) return FALSE;
+
+@@ -5518,8 +5598,14 @@ static gboolean drag_drop_event_cb(GtkWi
+ LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({retx, rety});
+
+ RefPtr<nsDragService> dragService = nsDragService::GetInstance();
+- return dragService->ScheduleDropEvent(innerMostWindow, aDragContext, point,
+- aTime);
++ return dragService->ScheduleDropEvent(innerMostWindow, aDragContext,
++ aWaylandDragContext, point, aTime);
++}
++
++static gboolean drag_drop_event_cb(GtkWidget *aWidget,
++ GdkDragContext *aDragContext, gint aX,
++ gint aY, guint aTime, gpointer aData) {
++ return WindowDragDropHandler(aWidget, aDragContext, nullptr, aX, aY, aTime);
+ }
+
+ static void drag_data_received_event_cb(GtkWidget *aWidget,
+@@ -5877,11 +5963,6 @@ nsIWidget::LayerManager *nsWindow::GetLa
+ return mLayerManager;
+ }
+
+- if (!mLayerManager && !IsComposited() &&
+- eTransparencyTransparent == GetTransparencyMode()) {
+- mLayerManager = CreateBasicLayerManager();
+- }
+-
+ return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint,
+ aPersistence);
+ }
+@@ -5919,6 +6000,13 @@ void nsWindow::ClearCachedResources() {
+ * It works only for CSD decorated GtkWindow.
+ */
+ void nsWindow::UpdateClientOffsetForCSDWindow() {
++ // We update window offset on X11 as the window position is calculated
++ // relatively to mShell. We don't do that on Wayland as our wl_subsurface
++ // is attached to mContainer and mShell is ignored.
++ if (!mIsX11Display) {
++ return;
++ }
++
+ // _NET_FRAME_EXTENTS is not set on client decorated windows,
+ // so we need to read offset between mContainer and toplevel mShell
+ // window.
+@@ -6005,6 +6093,15 @@ void nsWindow::SetDrawsInTitlebar(bool a
+ mNeedsShow = true;
+ NativeResize();
+
++ // Label mShell toplevel window so property_notify_event_cb callback
++ // can find its way home.
++ g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)), "nsWindow",
++ this);
++#ifdef MOZ_X11
++ // SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
++#endif
++ RefreshWindowClass();
++
+ // When we use system titlebar setup managed by Gtk+ we also get
+ // _NET_FRAME_EXTENTS property for our toplevel window so we can't
+ // update the client offset it here.
+@@ -6019,13 +6116,11 @@ void nsWindow::SetDrawsInTitlebar(bool a
+ }
+
+ gint nsWindow::GdkScaleFactor() {
+-#if (MOZ_WIDGET_GTK >= 3)
+ // Available as of GTK 3.10+
+ static auto sGdkWindowGetScaleFactorPtr =
+ (gint(*)(GdkWindow *))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
+ if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
+ return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
+-#endif
+ return ScreenHelperGTK::GetGTKMonitorScaleFactor();
+ }
+
+@@ -6287,6 +6382,8 @@ nsWindow::CSDSupportLevel nsWindow::GetS
+ // KDE Plasma
+ } else if (strstr(currentDesktop, "KDE") != nullptr) {
+ sCSDSupportLevel = CSD_SUPPORT_CLIENT;
++ } else if (strstr(currentDesktop, "Enlightenment") != nullptr) {
++ sCSDSupportLevel = CSD_SUPPORT_CLIENT;
+ } else if (strstr(currentDesktop, "LXDE") != nullptr) {
+ sCSDSupportLevel = CSD_SUPPORT_CLIENT;
+ } else if (strstr(currentDesktop, "openbox") != nullptr) {
+@@ -6303,6 +6400,8 @@ nsWindow::CSDSupportLevel nsWindow::GetS
+ sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
+ } else if (strstr(currentDesktop, "LXQt") != nullptr) {
+ sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
++ } else if (strstr(currentDesktop, "Deepin") != nullptr) {
++ sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
+ } else {
+ // Release or beta builds are not supposed to be broken
+ // so disable titlebar rendering on untested/unknown systems.
+@@ -6351,34 +6450,19 @@ int32_t nsWindow::RoundsWidgetCoordinate
+
+ void nsWindow::GetCompositorWidgetInitData(
+ mozilla::widget::CompositorWidgetInitData *aInitData) {
++ // Make sure the window XID is propagated to X server, we can fail otherwise
++ // in GPU process (Bug 1401634).
++ if (mXDisplay && mXWindow != X11None) {
++ XFlush(mXDisplay);
++ }
++
+ *aInitData = mozilla::widget::GtkCompositorWidgetInitData(
+ (mXWindow != X11None) ? mXWindow : (uintptr_t) nullptr,
+ mXDisplay ? nsCString(XDisplayString(mXDisplay)) : nsCString(),
+ GetClientSize());
+ }
+
+-bool nsWindow::IsComposited() const {
+- if (!mGdkWindow) {
+- NS_WARNING("nsWindow::HasARGBVisual called before realization!");
+- return false;
+- }
+-
+- GdkScreen *gdkScreen = gdk_screen_get_default();
+- return gdk_screen_is_composited(gdkScreen) &&
+- (gdk_window_get_visual(mGdkWindow) ==
+- gdk_screen_get_rgba_visual(gdkScreen));
+-}
+-
+ #ifdef MOZ_WAYLAND
+-wl_display *nsWindow::GetWaylandDisplay() {
+- // Available as of GTK 3.8+
+- static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
+- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
+-
+- GdkDisplay *gdkDisplay = gdk_display_get_default();
+- return mIsX11Display ? nullptr : sGdkWaylandDisplayGetWlDisplay(gdkDisplay);
+-}
+-
+ wl_surface *nsWindow::GetWaylandSurface() {
+ if (mContainer)
+ return moz_container_get_wl_surface(MOZ_CONTAINER(mContainer));
+@@ -6388,4 +6472,80 @@ wl_surface *nsWindow::GetWaylandSurface(
+ "drawing!");
+ return nullptr;
+ }
++
++bool nsWindow::WaylandSurfaceNeedsClear() {
++ if (mContainer) {
++ return moz_container_surface_needs_clear(MOZ_CONTAINER(mContainer));
++ }
++
++ NS_WARNING(
++ "nsWindow::WaylandSurfaceNeedsClear(): We don't have any mContainer!");
++ return false;
++}
+ #endif
++
++#ifdef MOZ_X11
++/* XApp progress support currently works by setting a property
++ * on a window with this Atom name. A supporting window manager
++ * will notice this and pass it along to whatever handling has
++ * been implemented on that end (e.g. passing it on to a taskbar
++ * widget.) There is no issue if WM support is lacking, this is
++ * simply ignored in that case.
++ *
++ * See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c
++ * for further details.
++ */
++
++#define PROGRESS_HINT "_NET_WM_XAPP_PROGRESS"
++
++static void set_window_hint_cardinal(Window xid, const gchar *atom_name,
++ gulong cardinal) {
++ GdkDisplay *display;
++
++ display = gdk_display_get_default();
++
++ if (cardinal > 0) {
++ XChangeProperty(GDK_DISPLAY_XDISPLAY(display), xid,
++ gdk_x11_get_xatom_by_name_for_display(display, atom_name),
++ XA_CARDINAL, 32, PropModeReplace, (guchar *)&cardinal, 1);
++ } else {
++ XDeleteProperty(GDK_DISPLAY_XDISPLAY(display), xid,
++ gdk_x11_get_xatom_by_name_for_display(display, atom_name));
++ }
++}
++#endif // MOZ_X11
++
++void nsWindow::SetProgress(unsigned long progressPercent) {
++#ifdef MOZ_X11
++
++ if (!mIsX11Display) {
++ return;
++ }
++
++ if (!mShell) {
++ return;
++ }
++
++ progressPercent = MIN(progressPercent, 100);
++
++ set_window_hint_cardinal(GDK_WINDOW_XID(gtk_widget_get_window(mShell)),
++ PROGRESS_HINT, progressPercent);
++#endif // MOZ_X11
++}
++
++#ifdef MOZ_X11
++void nsWindow::SetCompositorHint(WindowComposeRequest aState) {
++ if (mIsX11Display &&
++ (!GetLayerManager() ||
++ GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC)) {
++ gulong value = aState;
++ GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
++ gdk_property_change(gtk_widget_get_window(mShell),
++ gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE),
++ cardinal_atom,
++ 32, // format
++ GDK_PROP_MODE_REPLACE, (guchar *)&value, 1);
++ }
++}
++#endif
++
+diff -up thunderbird-60.5.0/widget/gtk/nsWindow.h.wayland thunderbird-60.5.0/widget/gtk/nsWindow.h
+--- thunderbird-60.5.0/widget/gtk/nsWindow.h.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/nsWindow.h 2019-02-05 14:26:16.978316639 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+@@ -8,19 +8,8 @@
+ #ifndef __nsWindow_h__
+ #define __nsWindow_h__
+
+-#include "mozcontainer.h"
+-#include "mozilla/RefPtr.h"
+-#include "mozilla/UniquePtr.h"
+-#include "nsIDragService.h"
+-#include "nsITimer.h"
+-#include "nsGkAtoms.h"
+-#include "nsRefPtrHashtable.h"
+-
+-#include "nsBaseWidget.h"
+-#include "CompositorWidget.h"
+ #include <gdk/gdk.h>
+ #include <gtk/gtk.h>
+-
+ #ifdef MOZ_X11
+ #include <gdk/gdkx.h>
+ #include "X11UndefineNone.h"
+@@ -28,7 +17,16 @@
+ #ifdef MOZ_WAYLAND
+ #include <gdk/gdkwayland.h>
+ #endif
+-
++#include "mozcontainer.h"
++#include "mozilla/RefPtr.h"
++#include "mozilla/UniquePtr.h"
++#include "nsIDragService.h"
++#include "nsITimer.h"
++#include "nsGkAtoms.h"
++#include "nsRefPtrHashtable.h"
++#include "nsIFrame.h"
++#include "nsBaseWidget.h"
++#include "CompositorWidget.h"
+ #include "mozilla/widget/WindowSurface.h"
+ #include "mozilla/widget/WindowSurfaceProvider.h"
+
+@@ -66,6 +64,19 @@ extern mozilla::LazyLogModule gWidgetDra
+
+ #endif /* MOZ_LOGGING */
+
++#ifdef MOZ_WAYLAND
++class nsWaylandDragContext;
++
++gboolean WindowDragMotionHandler(GtkWidget* aWidget,
++ GdkDragContext* aDragContext,
++ nsWaylandDragContext* aWaylandDragContext,
++ gint aX, gint aY, guint aTime);
++gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
++ nsWaylandDragContext* aWaylandDragContext,
++ gint aX, gint aY, guint aTime);
++void WindowDragLeaveHandler(GtkWidget* aWidget);
++#endif
++
+ class gfxPattern;
+
+ namespace mozilla {
+@@ -77,6 +88,7 @@ class nsWindow final : public nsBaseWidg
+ public:
+ typedef mozilla::gfx::DrawTarget DrawTarget;
+ typedef mozilla::WidgetEventTime WidgetEventTime;
++ typedef mozilla::WidgetKeyboardEvent WidgetKeyboardEvent;
+ typedef mozilla::widget::PlatformCompositorWidgetDelegate
+ PlatformCompositorWidgetDelegate;
+
+@@ -216,6 +228,8 @@ class nsWindow final : public nsBaseWidg
+ mozilla::gfx::DrawTarget* aDrawTarget,
+ LayoutDeviceIntRegion& aInvalidRegion) override;
+
++ void SetProgress(unsigned long progressPercent);
++
+ private:
+ void UpdateAlpha(mozilla::gfx::SourceSurface* aSourceSurface,
+ nsIntRect aBoundsRect);
+@@ -335,6 +349,7 @@ class nsWindow final : public nsBaseWidg
+ #ifdef MOZ_WAYLAND
+ wl_display* GetWaylandDisplay();
+ wl_surface* GetWaylandSurface();
++ bool WaylandSurfaceNeedsClear();
+ #endif
+ virtual void GetCompositorWidgetInitData(
+ mozilla::widget::CompositorWidgetInitData* aInitData) override;
+@@ -436,13 +451,23 @@ class nsWindow final : public nsBaseWidg
+ gint* aButton, gint* aRootX, gint* aRootY);
+ void ClearCachedResources();
+ nsIWidgetListener* GetListener();
+- bool IsComposited() const;
+
+ void UpdateClientOffsetForCSDWindow();
+
+ nsWindow* GetTransientForWindowIfPopup();
+ bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
+
++#ifdef MOZ_X11
++ typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
++ GTK_WIDGET_COMPOSIDED_DISABLED = 1,
++ GTK_WIDGET_COMPOSIDED_ENABLED = 2} WindowComposeRequest;
++
++ void SetCompositorHint(WindowComposeRequest aState);
++#endif
++ nsCString mGtkWindowTypeName;
++ nsCString mGtkWindowRoleName;
++ void RefreshWindowClass();
++
+ GtkWidget* mShell;
+ MozContainer* mContainer;
+ GdkWindow* mGdkWindow;
+diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h
+--- thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h 2019-02-05 14:26:16.978316639 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+@@ -17,6 +17,7 @@
+ #include <gdk/gdkwayland.h>
+ #endif
+ #include <X11/Xlib.h> // for Window, Display, Visual, etc.
++#include "X11UndefineNone.h"
+
+ class nsWindow;
+
+@@ -70,6 +71,7 @@ class WindowSurfaceProvider final {
+ #ifdef MOZ_WAYLAND
+ nsWindow* mWidget;
+ #endif
++ bool mIsShaped;
+ };
+
+ } // namespace widget
+diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp
+--- thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp 2019-02-05 14:26:16.979316635 +0100
+@@ -1,27 +1,28 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
++#include "nsWaylandDisplay.h"
+ #include "WindowSurfaceWayland.h"
+
+-#include "base/message_loop.h" // for MessageLoop
+-#include "base/task.h" // for NewRunnableMethod, etc
+ #include "nsPrintfCString.h"
+ #include "mozilla/gfx/2D.h"
+ #include "mozilla/gfx/Tools.h"
+ #include "gfxPlatform.h"
+ #include "mozcontainer.h"
+-#include "nsCOMArray.h"
+-#include "mozilla/StaticMutex.h"
++#include "nsTArray.h"
++#include "base/message_loop.h" // for MessageLoop
++#include "base/task.h" // for NewRunnableMethod, etc
+
+-#include <gdk/gdkwayland.h>
+ #include <sys/mman.h>
+-#include <assert.h>
+ #include <fcntl.h>
+ #include <errno.h>
+
++namespace mozilla {
++namespace widget {
++
+ /*
+ Wayland multi-thread rendering scheme
+
+@@ -131,188 +132,16 @@ handle to wayland compositor by WindowBa
+ (wl_buffer/wl_surface).
+ */
+
+-namespace mozilla {
+-namespace widget {
+-
+ #define BUFFER_BPP 4
+-
+-// TODO: How many rendering threads do we actualy handle?
+-static nsCOMArray<nsWaylandDisplay> gWaylandDisplays;
+-static StaticMutex gWaylandDisplaysMutex;
+-
+-// Each thread which is using wayland connection (wl_display) has to operate
+-// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
+-// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
+-//
+-// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
+-// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
+-// compositor (not the main) thread.
+-static nsWaylandDisplay *WaylandDisplayGet(wl_display *aDisplay);
+-static void WaylandDisplayRelease(wl_display *aDisplay);
+-static void WaylandDisplayLoop(wl_display *aDisplay);
+-
+-// TODO: is the 60pfs loop correct?
+-#define EVENT_LOOP_DELAY (1000 / 60)
+-
+-// Get WaylandDisplay for given wl_display and actual calling thread.
+-static nsWaylandDisplay *WaylandDisplayGetLocked(wl_display *aDisplay,
+- const StaticMutexAutoLock &) {
+- nsWaylandDisplay *waylandDisplay = nullptr;
+-
+- int len = gWaylandDisplays.Count();
+- for (int i = 0; i < len; i++) {
+- if (gWaylandDisplays[i]->Matches(aDisplay)) {
+- waylandDisplay = gWaylandDisplays[i];
+- break;
+- }
+- }
+-
+- if (!waylandDisplay) {
+- waylandDisplay = new nsWaylandDisplay(aDisplay);
+- gWaylandDisplays.AppendObject(waylandDisplay);
+- }
+-
+- NS_ADDREF(waylandDisplay);
+- return waylandDisplay;
+-}
+-
+-static nsWaylandDisplay *WaylandDisplayGet(wl_display *aDisplay) {
+- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
+- return WaylandDisplayGetLocked(aDisplay, lock);
+-}
+-
+-static bool WaylandDisplayReleaseLocked(wl_display *aDisplay,
+- const StaticMutexAutoLock &) {
+- int len = gWaylandDisplays.Count();
+- for (int i = 0; i < len; i++) {
+- if (gWaylandDisplays[i]->Matches(aDisplay)) {
+- int rc = gWaylandDisplays[i]->Release();
+- // nsCOMArray::AppendObject()/RemoveObjectAt() also call
+- // AddRef()/Release() so remove WaylandDisplay when ref count is 1.
+- if (rc == 1) {
+- gWaylandDisplays.RemoveObjectAt(i);
+- }
+- return true;
+- }
+- }
+- MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
+- return false;
+-}
+-
+-static void WaylandDisplayRelease(wl_display *aDisplay) {
+- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
+- WaylandDisplayReleaseLocked(aDisplay, lock);
+-}
+-
+-static void WaylandDisplayLoopLocked(wl_display *aDisplay,
+- const StaticMutexAutoLock &) {
+- int len = gWaylandDisplays.Count();
+- for (int i = 0; i < len; i++) {
+- if (gWaylandDisplays[i]->Matches(aDisplay)) {
+- if (gWaylandDisplays[i]->DisplayLoop()) {
+- MessageLoop::current()->PostDelayedTask(
+- NewRunnableFunction("WaylandDisplayLoop", &WaylandDisplayLoop,
+- aDisplay),
+- EVENT_LOOP_DELAY);
+- }
+- break;
+- }
+- }
+-}
+-
+-static void WaylandDisplayLoop(wl_display *aDisplay) {
+- MOZ_ASSERT(!NS_IsMainThread());
+- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
+- WaylandDisplayLoopLocked(aDisplay, lock);
+-}
+-
+-static void global_registry_handler(void *data, wl_registry *registry,
+- uint32_t id, const char *interface,
+- uint32_t version) {
+- if (strcmp(interface, "wl_shm") == 0) {
+- auto interface = reinterpret_cast<nsWaylandDisplay *>(data);
+- auto shm = static_cast<wl_shm *>(
+- wl_registry_bind(registry, id, &wl_shm_interface, 1));
+- wl_proxy_set_queue((struct wl_proxy *)shm, interface->GetEventQueue());
+- interface->SetShm(shm);
+- }
+-}
+-
+-static void global_registry_remover(void *data, wl_registry *registry,
+- uint32_t id) {}
+-
+-static const struct wl_registry_listener registry_listener = {
+- global_registry_handler, global_registry_remover};
+-
+-wl_shm *nsWaylandDisplay::GetShm() {
+- MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
+-
+- if (!mShm) {
+- // wl_shm is not provided by Gtk so we need to query wayland directly
+- // See weston/simple-shm.c and create_display() for reference.
+- wl_registry *registry = wl_display_get_registry(mDisplay);
+- wl_registry_add_listener(registry, &registry_listener, this);
+-
+- wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
+- if (mEventQueue) {
+- wl_display_roundtrip_queue(mDisplay, mEventQueue);
+- } else {
+- wl_display_roundtrip(mDisplay);
+- }
+-
+- MOZ_RELEASE_ASSERT(mShm, "Wayland registry query failed!");
+- }
+-
+- return (mShm);
+-}
+-
+-bool nsWaylandDisplay::DisplayLoop() {
+- wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
+- return true;
+-}
+-
+-bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
+- return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
+-}
+-
+-NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
+-
+-nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
+- : mThreadId(PR_GetCurrentThread())
+- // gfx::SurfaceFormat::B8G8R8A8 is a basic Wayland format
+- // and is always present.
+- ,
+- mFormat(gfx::SurfaceFormat::B8G8R8A8),
+- mShm(nullptr),
+- mDisplay(aDisplay) {
+- if (NS_IsMainThread()) {
+- // Use default event queue in main thread operated by Gtk+.
+- mEventQueue = nullptr;
+- } else {
+- mEventQueue = wl_display_create_queue(mDisplay);
+- MessageLoop::current()->PostTask(NewRunnableFunction(
+- "WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
+- }
+-}
+-
+-nsWaylandDisplay::~nsWaylandDisplay() {
+- MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
+- // Owned by Gtk+, we don't need to release
+- mDisplay = nullptr;
+-
+- if (mEventQueue) {
+- wl_event_queue_destroy(mEventQueue);
+- mEventQueue = nullptr;
+- }
+-}
++gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
+
+ int WaylandShmPool::CreateTemporaryFile(int aSize) {
+- const char *tmppath = getenv("XDG_RUNTIME_DIR");
++ const char* tmppath = getenv("XDG_RUNTIME_DIR");
+ MOZ_RELEASE_ASSERT(tmppath, "Missing XDG_RUNTIME_DIR env variable.");
+
+ nsPrintfCString tmpname("%s/mozilla-shared-XXXXXX", tmppath);
+
+- char *filename;
++ char* filename;
+ int fd = -1;
+ int ret = 0;
+
+@@ -353,7 +182,7 @@ int WaylandShmPool::CreateTemporaryFile(
+ return fd;
+ }
+
+-WaylandShmPool::WaylandShmPool(nsWaylandDisplay *aWaylandDisplay, int aSize)
++WaylandShmPool::WaylandShmPool(nsWaylandDisplay* aWaylandDisplay, int aSize)
+ : mAllocatedSize(aSize) {
+ mShmPoolFd = CreateTemporaryFile(mAllocatedSize);
+ mImageData = mmap(nullptr, mAllocatedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
+@@ -365,7 +194,7 @@ WaylandShmPool::WaylandShmPool(nsWayland
+ wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, mAllocatedSize);
+
+ // We set our queue to get mShmPool events at compositor thread.
+- wl_proxy_set_queue((struct wl_proxy *)mShmPool,
++ wl_proxy_set_queue((struct wl_proxy*)mShmPool,
+ aWaylandDisplay->GetEventQueue());
+ }
+
+@@ -394,7 +223,7 @@ bool WaylandShmPool::Resize(int aSize) {
+ return true;
+ }
+
+-void WaylandShmPool::SetImageDataFromPool(class WaylandShmPool *aSourcePool,
++void WaylandShmPool::SetImageDataFromPool(class WaylandShmPool* aSourcePool,
+ int aImageDataSize) {
+ MOZ_ASSERT(mAllocatedSize >= aImageDataSize, "WaylandShmPool overflows!");
+ memcpy(mImageData, aSourcePool->GetImageData(), aImageDataSize);
+@@ -406,8 +235,8 @@ WaylandShmPool::~WaylandShmPool() {
+ close(mShmPoolFd);
+ }
+
+-static void buffer_release(void *data, wl_buffer *buffer) {
+- auto surface = reinterpret_cast<WindowBackBuffer *>(data);
++static void buffer_release(void* data, wl_buffer* buffer) {
++ auto surface = reinterpret_cast<WindowBackBuffer*>(data);
+ surface->Detach();
+ }
+
+@@ -422,7 +251,7 @@ void WindowBackBuffer::Create(int aWidth
+ mWaylandBuffer =
+ wl_shm_pool_create_buffer(mShmPool.GetShmPool(), 0, aWidth, aHeight,
+ aWidth * BUFFER_BPP, WL_SHM_FORMAT_ARGB8888);
+- wl_proxy_set_queue((struct wl_proxy *)mWaylandBuffer,
++ wl_proxy_set_queue((struct wl_proxy*)mWaylandBuffer,
+ mWaylandDisplay->GetEventQueue());
+ wl_buffer_add_listener(mWaylandBuffer, &buffer_listener, this);
+
+@@ -435,7 +264,11 @@ void WindowBackBuffer::Release() {
+ mWidth = mHeight = 0;
+ }
+
+-WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay *aWaylandDisplay,
++void WindowBackBuffer::Clear() {
++ memset(mShmPool.GetImageData(), 0, mHeight * mWidth * BUFFER_BPP);
++}
++
++WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay,
+ int aWidth, int aHeight)
+ : mShmPool(aWaylandDisplay, aWidth * aHeight * BUFFER_BPP),
+ mWaylandBuffer(nullptr),
+@@ -457,7 +290,7 @@ bool WindowBackBuffer::Resize(int aWidth
+ return (mWaylandBuffer != nullptr);
+ }
+
+-void WindowBackBuffer::Attach(wl_surface *aSurface) {
++void WindowBackBuffer::Attach(wl_surface* aSurface) {
+ wl_surface_attach(aSurface, mWaylandBuffer, 0, 0);
+ wl_surface_commit(aSurface);
+ wl_display_flush(mWaylandDisplay->GetDisplay());
+@@ -466,8 +299,8 @@ void WindowBackBuffer::Attach(wl_surface
+
+ void WindowBackBuffer::Detach() { mAttached = false; }
+
+-bool WindowBackBuffer::SetImageDataFromBackBuffer(
+- class WindowBackBuffer *aSourceBuffer) {
++bool WindowBackBuffer::SetImageDataFromBuffer(
++ class WindowBackBuffer* aSourceBuffer) {
+ if (!IsMatchingSize(aSourceBuffer)) {
+ Resize(aSourceBuffer->mWidth, aSourceBuffer->mHeight);
+ }
+@@ -478,204 +311,381 @@ bool WindowBackBuffer::SetImageDataFromB
+ return true;
+ }
+
+-already_AddRefed<gfx::DrawTarget> WindowBackBuffer::Lock(
+- const LayoutDeviceIntRegion &aRegion) {
+- gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+- gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
+-
++already_AddRefed<gfx::DrawTarget> WindowBackBuffer::Lock() {
++ gfx::IntSize lockSize(mWidth, mHeight);
+ return gfxPlatform::CreateDrawTargetForData(
+- static_cast<unsigned char *>(mShmPool.GetImageData()), lockSize,
+- BUFFER_BPP * mWidth, mWaylandDisplay->GetSurfaceFormat());
++ static_cast<unsigned char*>(mShmPool.GetImageData()), lockSize,
++ BUFFER_BPP * mWidth, mFormat);
+ }
+
+-static void frame_callback_handler(void *data, struct wl_callback *callback,
++static void frame_callback_handler(void* data, struct wl_callback* callback,
+ uint32_t time) {
+- auto surface = reinterpret_cast<WindowSurfaceWayland *>(data);
++ auto surface = reinterpret_cast<WindowSurfaceWayland*>(data);
+ surface->FrameCallbackHandler();
+ }
+
+ static const struct wl_callback_listener frame_listener = {
+ frame_callback_handler};
+
+-WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
++WindowSurfaceWayland::WindowSurfaceWayland(nsWindow* aWindow)
+ : mWindow(aWindow),
+- mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay())),
+- mFrontBuffer(nullptr),
+- mBackBuffer(nullptr),
++ mWaylandDisplay(WaylandDisplayGet()),
++ mWaylandBuffer(nullptr),
+ mFrameCallback(nullptr),
+- mFrameCallbackSurface(nullptr),
++ mLastCommittedSurface(nullptr),
+ mDisplayThreadMessageLoop(MessageLoop::current()),
+- mDelayedCommit(false),
+- mFullScreenDamage(false),
+- mIsMainThread(NS_IsMainThread()) {}
++ mDelayedCommitHandle(nullptr),
++ mDrawToWaylandBufferDirectly(true),
++ mPendingCommit(false),
++ mWaylandBufferFullScreenDamage(false),
++ mIsMainThread(NS_IsMainThread()),
++ mNeedScaleFactorUpdate(true) {
++ for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr;
++}
+
+ WindowSurfaceWayland::~WindowSurfaceWayland() {
+- delete mFrontBuffer;
+- delete mBackBuffer;
++ if (mPendingCommit) {
++ NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
++ }
++
++ if (mDelayedCommitHandle) {
++ // Delete reference to this to prevent WaylandBufferDelayCommitHandler()
++ // operate on released this. mDelayedCommitHandle itself will
++ // be released at WaylandBufferDelayCommitHandler().
++ *mDelayedCommitHandle = nullptr;
++ }
+
+ if (mFrameCallback) {
+ wl_callback_destroy(mFrameCallback);
+ }
+
++ delete mWaylandBuffer;
++
++ for (int i = 0; i < BACK_BUFFER_NUM; i++) {
++ if (mBackupBuffer[i]) {
++ delete mBackupBuffer[i];
++ }
++ }
++
+ if (!mIsMainThread) {
+ // We can be destroyed from main thread even though we was created/used
+ // in compositor thread. We have to unref/delete WaylandDisplay in
+ // compositor thread then and we can't use MessageLoop::current() here.
+- mDisplayThreadMessageLoop->PostTask(
+- NewRunnableFunction("WaylandDisplayRelease", &WaylandDisplayRelease,
+- mWaylandDisplay->GetDisplay()));
++ mDisplayThreadMessageLoop->PostTask(NewRunnableFunction(
++ "WaylandDisplayRelease", &WaylandDisplayRelease, mWaylandDisplay));
+ } else {
+- WaylandDisplayRelease(mWaylandDisplay->GetDisplay());
+- }
+-}
+-
+-void WindowSurfaceWayland::UpdateScaleFactor() {
+- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
+- if (waylandSurface) {
+- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
++ WaylandDisplayRelease(mWaylandDisplay);
+ }
+ }
+
+-WindowBackBuffer *WindowSurfaceWayland::GetBufferToDraw(int aWidth,
+- int aHeight) {
+- if (!mFrontBuffer) {
+- mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
+- mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
+- return mFrontBuffer;
++WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth,
++ int aHeight) {
++ if (!mWaylandBuffer) {
++ mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
++ return mWaylandBuffer;
+ }
+
+- if (!mFrontBuffer->IsAttached()) {
+- if (!mFrontBuffer->IsMatchingSize(aWidth, aHeight)) {
+- mFrontBuffer->Resize(aWidth, aHeight);
++ if (!mWaylandBuffer->IsAttached()) {
++ if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
++ mWaylandBuffer->Resize(aWidth, aHeight);
+ // There's a chance that scale factor has been changed
+ // when buffer size changed
+- UpdateScaleFactor();
++ mNeedScaleFactorUpdate = true;
++ }
++ return mWaylandBuffer;
++ }
++
++ MOZ_ASSERT(!mPendingCommit,
++ "Uncommitted buffer switch, screen artifacts ahead.");
++
++ // Front buffer is used by compositor, select a back buffer
++ int availableBuffer;
++ for (availableBuffer = 0; availableBuffer < BACK_BUFFER_NUM;
++ availableBuffer++) {
++ if (!mBackupBuffer[availableBuffer]) {
++ mBackupBuffer[availableBuffer] =
++ new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
++ break;
++ }
++
++ if (!mBackupBuffer[availableBuffer]->IsAttached()) {
++ break;
+ }
+- return mFrontBuffer;
+ }
+
+- // Front buffer is used by compositor, draw to back buffer
+- if (mBackBuffer->IsAttached()) {
++ if (MOZ_UNLIKELY(availableBuffer == BACK_BUFFER_NUM)) {
+ NS_WARNING("No drawing buffer available");
+ return nullptr;
+ }
+
+- MOZ_ASSERT(!mDelayedCommit,
+- "Uncommitted buffer switch, screen artifacts ahead.");
+-
+- WindowBackBuffer *tmp = mFrontBuffer;
+- mFrontBuffer = mBackBuffer;
+- mBackBuffer = tmp;
++ WindowBackBuffer* lastWaylandBuffer = mWaylandBuffer;
++ mWaylandBuffer = mBackupBuffer[availableBuffer];
++ mBackupBuffer[availableBuffer] = lastWaylandBuffer;
+
+- if (mBackBuffer->IsMatchingSize(aWidth, aHeight)) {
++ if (lastWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
+ // Former front buffer has the same size as a requested one.
+ // Gecko may expect a content already drawn on screen so copy
+ // existing data to the new buffer.
+- mFrontBuffer->SetImageDataFromBackBuffer(mBackBuffer);
++ mWaylandBuffer->SetImageDataFromBuffer(lastWaylandBuffer);
+ // When buffer switches we need to damage whole screen
+ // (https://bugzilla.redhat.com/show_bug.cgi?id=1418260)
+- mFullScreenDamage = true;
++ mWaylandBufferFullScreenDamage = true;
+ } else {
+ // Former buffer has different size from the new request. Only resize
+ // the new buffer and leave gecko to render new whole content.
+- mFrontBuffer->Resize(aWidth, aHeight);
++ mWaylandBuffer->Resize(aWidth, aHeight);
+ }
+
+- return mFrontBuffer;
++ return mWaylandBuffer;
+ }
+
+-already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::Lock(
+- const LayoutDeviceIntRegion &aRegion) {
+- MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
+-
+- // We allocate back buffer to widget size but return only
+- // portion requested by aRegion.
+- LayoutDeviceIntRect rect = mWindow->GetBounds();
+- WindowBackBuffer *buffer = GetBufferToDraw(rect.width, rect.height);
++already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockWaylandBuffer(
++ int aWidth, int aHeight, bool aClearBuffer) {
++ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight);
+ if (!buffer) {
+- NS_WARNING("No drawing buffer available");
++ NS_WARNING(
++ "WindowSurfaceWayland::LockWaylandBuffer(): No buffer available");
+ return nullptr;
+ }
+
+- return buffer->Lock(aRegion);
++ if (aClearBuffer) {
++ buffer->Clear();
++ }
++
++ return buffer->Lock();
++}
++
++already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockImageSurface(
++ const gfx::IntSize& aLockSize) {
++ if (!mImageSurface || mImageSurface->CairoStatus() ||
++ !(aLockSize <= mImageSurface->GetSize())) {
++ mImageSurface = new gfxImageSurface(
++ aLockSize,
++ SurfaceFormatToImageFormat(WindowBackBuffer::GetSurfaceFormat()));
++ if (mImageSurface->CairoStatus()) {
++ return nullptr;
++ }
++ }
++
++ return gfxPlatform::CreateDrawTargetForData(
++ mImageSurface->Data(), mImageSurface->GetSize(), mImageSurface->Stride(),
++ WindowBackBuffer::GetSurfaceFormat());
+ }
+
+-void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion &aInvalidRegion) {
++/*
++ There are some situations which can happen here:
++
++ A) Lock() is called to whole surface. In that case we don't need
++ to clip/buffer the drawing and we can return wl_buffer directly
++ for drawing.
++ - mWaylandBuffer is available - that's an ideal situation.
++ - mWaylandBuffer is locked by compositor - flip buffers and draw.
++ - if we can't flip buffers - go B)
++
++ B) Lock() is requested for part(s) of screen. We need to provide temporary
++ surface to draw into and copy result (clipped) to target wl_surface.
++ */
++already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::Lock(
++ const LayoutDeviceIntRegion& aRegion) {
+ MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
+
+- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
++ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
++ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
++ gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
++
++ // Are we asked for entire nsWindow to draw?
++ mDrawToWaylandBufferDirectly =
++ (aRegion.GetNumRects() == 1 && bounds.x == 0 && bounds.y == 0 &&
++ lockSize.width == screenRect.width &&
++ lockSize.height == screenRect.height);
++
++ if (mDrawToWaylandBufferDirectly) {
++ RefPtr<gfx::DrawTarget> dt =
++ LockWaylandBuffer(screenRect.width, screenRect.height,
++ mWindow->WaylandSurfaceNeedsClear());
++ if (dt) {
++ return dt.forget();
++ }
++
++ // We don't have any front buffer available. Try indirect drawing
++ // to mImageSurface which is mirrored to front buffer at commit.
++ mDrawToWaylandBufferDirectly = false;
++ }
++
++ return LockImageSurface(lockSize);
++}
++
++bool WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer(
++ const LayoutDeviceIntRegion& aRegion) {
++ MOZ_ASSERT(!mDrawToWaylandBufferDirectly);
++
++ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
++ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
++
++ gfx::Rect rect(bounds);
++ if (rect.IsEmpty()) {
++ return false;
++ }
++
++ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(
++ screenRect.width, screenRect.height, mWindow->WaylandSurfaceNeedsClear());
++ RefPtr<gfx::SourceSurface> surf =
++ gfx::Factory::CreateSourceSurfaceForCairoSurface(
++ mImageSurface->CairoSurface(), mImageSurface->GetSize(),
++ mImageSurface->Format());
++ if (!dt || !surf) {
++ return false;
++ }
++
++ uint32_t numRects = aRegion.GetNumRects();
++ if (numRects != 1) {
++ AutoTArray<IntRect, 32> rects;
++ rects.SetCapacity(numRects);
++ for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
++ rects.AppendElement(iter.Get().ToUnknownRect());
++ }
++ dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length());
++ }
++
++ dt->DrawSurface(surf, rect, rect);
++
++ if (numRects != 1) {
++ dt->PopClip();
++ }
++
++ return true;
++}
++
++static void WaylandBufferDelayCommitHandler(WindowSurfaceWayland** aSurface) {
++ if (*aSurface) {
++ (*aSurface)->DelayedCommitHandler();
++ } else {
++ // Referenced WindowSurfaceWayland is already deleted.
++ // Do nothing but just release the mDelayedCommitHandle allocated at
++ // WindowSurfaceWayland::CommitWaylandBuffer().
++ free(aSurface);
++ }
++}
++
++void WindowSurfaceWayland::CommitWaylandBuffer() {
++ MOZ_ASSERT(mPendingCommit, "Committing empty surface!");
++
++ wl_surface* waylandSurface = mWindow->GetWaylandSurface();
+ if (!waylandSurface) {
+- // Target window is already destroyed - don't bother to render there.
++ // Target window is not created yet - delay the commit. This can happen only
++ // when the window is newly created and there's no active
++ // frame callback pending.
++ MOZ_ASSERT(!mFrameCallback || waylandSurface != mLastCommittedSurface,
++ "Missing wayland surface at frame callback!");
++
++ // Do nothing if there's already mDelayedCommitHandle pending.
++ if (!mDelayedCommitHandle) {
++ mDelayedCommitHandle = static_cast<WindowSurfaceWayland**>(
++ moz_xmalloc(sizeof(*mDelayedCommitHandle)));
++ *mDelayedCommitHandle = this;
++
++ MessageLoop::current()->PostDelayedTask(
++ NewRunnableFunction("WaylandBackBufferCommit",
++ &WaylandBufferDelayCommitHandler,
++ mDelayedCommitHandle),
++ EVENT_LOOP_DELAY);
++ }
+ return;
+ }
+- wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
++ wl_proxy_set_queue((struct wl_proxy*)waylandSurface,
+ mWaylandDisplay->GetEventQueue());
+
+- if (mFullScreenDamage) {
++ // We have an active frame callback request so handle it.
++ if (mFrameCallback) {
++ if (waylandSurface == mLastCommittedSurface) {
++ // We have an active frame callback pending from our recent surface.
++ // It means we should defer the commit to FrameCallbackHandler().
++ return;
++ }
++ // If our stored wl_surface does not match the actual one it means the frame
++ // callback is no longer active and we should release it.
++ wl_callback_destroy(mFrameCallback);
++ mFrameCallback = nullptr;
++ mLastCommittedSurface = nullptr;
++ }
++
++ if (mWaylandBufferFullScreenDamage) {
+ LayoutDeviceIntRect rect = mWindow->GetBounds();
+ wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height);
+- mFullScreenDamage = false;
++ mWaylandBufferFullScreenDamage = false;
+ } else {
+- for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
+- const mozilla::LayoutDeviceIntRect &r = iter.Get();
+- wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height);
++ gint scaleFactor = mWindow->GdkScaleFactor();
++ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done();
++ iter.Next()) {
++ const mozilla::LayoutDeviceIntRect& r = iter.Get();
++ // We need to remove the scale factor because the wl_surface_damage
++ // also multiplies by current scale factor.
++ wl_surface_damage(waylandSurface, r.x / scaleFactor, r.y / scaleFactor,
++ r.width / scaleFactor, r.height / scaleFactor);
+ }
+ }
+
+- // Frame callback is always connected to actual wl_surface. When the surface
+- // is unmapped/deleted the frame callback is never called. Unfortunatelly
+- // we don't know if the frame callback is not going to be called.
+- // But our mozcontainer code deletes wl_surface when the GdkWindow is hidden
+- // creates a new one when is visible.
+- if (mFrameCallback && mFrameCallbackSurface == waylandSurface) {
+- // Do nothing here - we have a valid wl_surface and the buffer will be
+- // commited to compositor in next frame callback event.
+- mDelayedCommit = true;
+- return;
+- } else {
+- if (mFrameCallback) {
+- // Delete frame callback connected to obsoleted wl_surface.
+- wl_callback_destroy(mFrameCallback);
+- }
++ // Clear all back buffer damage as we're committing
++ // all requested regions.
++ mWaylandBufferDamage.SetEmpty();
+
+- mFrameCallback = wl_surface_frame(waylandSurface);
+- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
+- mFrameCallbackSurface = waylandSurface;
+-
+- // There's no pending frame callback so we can draw immediately
+- // and create frame callback for possible subsequent drawing.
+- mFrontBuffer->Attach(waylandSurface);
+- mDelayedCommit = false;
++ mFrameCallback = wl_surface_frame(waylandSurface);
++ wl_callback_add_listener(mFrameCallback, &frame_listener, this);
++
++ if (mNeedScaleFactorUpdate || mLastCommittedSurface != waylandSurface) {
++ wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
++ mNeedScaleFactorUpdate = false;
+ }
++
++ mWaylandBuffer->Attach(waylandSurface);
++ mLastCommittedSurface = waylandSurface;
++
++ // There's no pending commit, all changes are sent to compositor.
++ mPendingCommit = false;
++}
++
++void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) {
++ MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
++
++ // We have new content at mImageSurface - copy data to mWaylandBuffer first.
++ if (!mDrawToWaylandBufferDirectly) {
++ CommitImageSurfaceToWaylandBuffer(aInvalidRegion);
++ }
++
++ // If we're not at fullscreen damage add drawing area from aInvalidRegion
++ if (!mWaylandBufferFullScreenDamage) {
++ mWaylandBufferDamage.OrWith(aInvalidRegion);
++ }
++
++ // We're ready to commit.
++ mPendingCommit = true;
++ CommitWaylandBuffer();
+ }
+
+ void WindowSurfaceWayland::FrameCallbackHandler() {
+ MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
++ MOZ_ASSERT(mFrameCallback != nullptr,
++ "FrameCallbackHandler() called without valid frame callback!");
++ MOZ_ASSERT(mLastCommittedSurface != nullptr,
++ "FrameCallbackHandler() called without valid wl_surface!");
+
+- if (mFrameCallback) {
+- wl_callback_destroy(mFrameCallback);
+- mFrameCallback = nullptr;
+- mFrameCallbackSurface = nullptr;
++ wl_callback_destroy(mFrameCallback);
++ mFrameCallback = nullptr;
++
++ if (mPendingCommit) {
++ CommitWaylandBuffer();
+ }
++}
+
+- if (mDelayedCommit) {
+- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
+- if (!waylandSurface) {
+- // Target window is already destroyed - don't bother to render there.
+- NS_WARNING("No drawing buffer available");
+- return;
+- }
+- wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
+- mWaylandDisplay->GetEventQueue());
++void WindowSurfaceWayland::DelayedCommitHandler() {
++ MOZ_ASSERT(mDelayedCommitHandle != nullptr, "Missing mDelayedCommitHandle!");
+
+- // Send pending surface to compositor and register frame callback
+- // for possible subsequent drawing.
+- mFrameCallback = wl_surface_frame(waylandSurface);
+- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
+- mFrameCallbackSurface = waylandSurface;
++ *mDelayedCommitHandle = nullptr;
++ free(mDelayedCommitHandle);
++ mDelayedCommitHandle = nullptr;
+
+- mFrontBuffer->Attach(waylandSurface);
+- mDelayedCommit = false;
++ if (mPendingCommit) {
++ CommitWaylandBuffer();
+ }
+ }
+
+diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h
+--- thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h.wayland 2019-01-22 20:44:03.000000000 +0100
++++ thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h 2019-02-05 14:26:16.979316635 +0100
+@@ -1,4 +1,4 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+@@ -8,37 +8,14 @@
+ #define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
+
+ #include <prthread.h>
++#include "mozilla/gfx/Types.h"
++#include "nsWaylandDisplay.h"
++
++#define BACK_BUFFER_NUM 2
+
+ namespace mozilla {
+ namespace widget {
+
+-// Our general connection to Wayland display server,
+-// holds our display connection and runs event loop.
+-class nsWaylandDisplay : public nsISupports {
+- NS_DECL_THREADSAFE_ISUPPORTS
+-
+- public:
+- nsWaylandDisplay(wl_display* aDisplay);
+-
+- wl_shm* GetShm();
+- void SetShm(wl_shm* aShm) { mShm = aShm; };
+-
+- wl_display* GetDisplay() { return mDisplay; };
+- wl_event_queue* GetEventQueue() { return mEventQueue; };
+- gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; };
+- bool DisplayLoop();
+- bool Matches(wl_display* aDisplay);
+-
+- private:
+- virtual ~nsWaylandDisplay();
+-
+- PRThread* mThreadId;
+- gfx::SurfaceFormat mFormat;
+- wl_shm* mShm;
+- wl_event_queue* mEventQueue;
+- wl_display* mDisplay;
+-};
+-
+ // Allocates and owns shared memory for Wayland drawing surface
+ class WaylandShmPool {
+ public:
+@@ -66,14 +43,15 @@ class WindowBackBuffer {
+ WindowBackBuffer(nsWaylandDisplay* aDisplay, int aWidth, int aHeight);
+ ~WindowBackBuffer();
+
+- already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion);
++ already_AddRefed<gfx::DrawTarget> Lock();
+
+ void Attach(wl_surface* aSurface);
+ void Detach();
+ bool IsAttached() { return mAttached; }
+
++ void Clear();
+ bool Resize(int aWidth, int aHeight);
+- bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
++ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer);
+
+ bool IsMatchingSize(int aWidth, int aHeight) {
+ return aWidth == mWidth && aHeight == mHeight;
+@@ -82,6 +60,8 @@ class WindowBackBuffer {
+ return aBuffer->mWidth == mWidth && aBuffer->mHeight == mHeight;
+ }
+
++ static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; }
++
+ private:
+ void Create(int aWidth, int aHeight);
+ void Release();
+@@ -96,35 +76,48 @@ class WindowBackBuffer {
+ int mHeight;
+ bool mAttached;
+ nsWaylandDisplay* mWaylandDisplay;
++ static gfx::SurfaceFormat mFormat;
+ };
+
+ // WindowSurfaceWayland is an abstraction for wl_surface
+ // and related management
+ class WindowSurfaceWayland : public WindowSurface {
+ public:
+- WindowSurfaceWayland(nsWindow* aWindow);
++ explicit WindowSurfaceWayland(nsWindow* aWindow);
+ ~WindowSurfaceWayland();
+
+ already_AddRefed<gfx::DrawTarget> Lock(
+ const LayoutDeviceIntRegion& aRegion) override;
+ void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
+ void FrameCallbackHandler();
++ void DelayedCommitHandler();
+
+ private:
+- WindowBackBuffer* GetBufferToDraw(int aWidth, int aHeight);
+- void UpdateScaleFactor();
++ WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight);
++
++ already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(int aWidth, int aHeight,
++ bool aClearBuffer);
++ already_AddRefed<gfx::DrawTarget> LockImageSurface(
++ const gfx::IntSize& aLockSize);
++ bool CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion);
++ void CommitWaylandBuffer();
+
+ // TODO: Do we need to hold a reference to nsWindow object?
+ nsWindow* mWindow;
+ nsWaylandDisplay* mWaylandDisplay;
+- WindowBackBuffer* mFrontBuffer;
+- WindowBackBuffer* mBackBuffer;
++ WindowBackBuffer* mWaylandBuffer;
++ LayoutDeviceIntRegion mWaylandBufferDamage;
++ WindowBackBuffer* mBackupBuffer[BACK_BUFFER_NUM];
++ RefPtr<gfxImageSurface> mImageSurface;
+ wl_callback* mFrameCallback;
+- wl_surface* mFrameCallbackSurface;
++ wl_surface* mLastCommittedSurface;
+ MessageLoop* mDisplayThreadMessageLoop;
+- bool mDelayedCommit;
+- bool mFullScreenDamage;
++ WindowSurfaceWayland** mDelayedCommitHandle;
++ bool mDrawToWaylandBufferDirectly;
++ bool mPendingCommit;
++ bool mWaylandBufferFullScreenDamage;
+ bool mIsMainThread;
++ bool mNeedScaleFactorUpdate;
+ };
+
+ } // namespace widget
+diff -up thunderbird-60.6.1/widget/gtk/WindowSurfaceProvider.cpp.old thunderbird-60.6.1/widget/gtk/WindowSurfaceProvider.cpp
+--- thunderbird-60.6.1/widget/gtk/WindowSurfaceProvider.cpp.old 2019-05-14 21:11:50.219841534 +0200
++++ thunderbird-60.6.1/widget/gtk/WindowSurfaceProvider.cpp 2019-05-14 21:11:58.228755117 +0200
+@@ -52,9 +52,6 @@ void WindowSurfaceProvider::Initialize(D
+
+ #ifdef MOZ_WAYLAND
+ void WindowSurfaceProvider::Initialize(nsWindow* aWidget) {
+- MOZ_ASSERT(aWidget->GetWaylandDisplay(),
+- "We are supposed to have a Wayland display!");
+-
+ mWidget = aWidget;
+ mIsX11Display = false;
+ }
diff --git a/mail-client/thunderbird/files/icon/thunderbird-unbranded.desktop b/mail-client/thunderbird/files/icon/thunderbird-unbranded.desktop
new file mode 100644
index 0000000..f9d87be
--- /dev/null
+++ b/mail-client/thunderbird/files/icon/thunderbird-unbranded.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Mozilla Thunderbird
+Comment=Mail & News Reader
+Exec=/usr/bin/thunderbird %u
+Icon=thunderbird-icon-unbranded
+Terminal=false
+Type=Application
+Categories=Office;Network;Email;
+MimeType=x-scheme-handler/mailto;
diff --git a/mail-client/thunderbird/files/icon/thunderbird.desktop b/mail-client/thunderbird/files/icon/thunderbird.desktop
new file mode 100644
index 0000000..f9c31eb
--- /dev/null
+++ b/mail-client/thunderbird/files/icon/thunderbird.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Mozilla Thunderbird
+Comment=Mail & News Reader
+Exec=/usr/bin/thunderbird %u
+Icon=thunderbird-icon
+Terminal=false
+Type=Application
+Categories=Office;Network;Email;
+MimeType=x-scheme-handler/mailto;
diff --git a/mail-client/thunderbird/files/thunderbird-60-sqlite3-fts3-tokenizer.patch b/mail-client/thunderbird/files/thunderbird-60-sqlite3-fts3-tokenizer.patch
new file mode 100644
index 0000000..48ebbf1
--- /dev/null
+++ b/mail-client/thunderbird/files/thunderbird-60-sqlite3-fts3-tokenizer.patch
@@ -0,0 +1,99 @@
+# HG changeset patch
+# User Arfrever Frehtes Taifersar Arahesis <Arfrever@Apache.Org>
+# Date 1543532530 0
+# Thu Nov 29 23:02:10 2018 +0000
+# Node ID 1c480085935783bd1d240860bb44f410e2d36322
+# Parent 6453222232be364fb8ce3fd29b6cbcd480e5f2e3
+Bug 1270882 - Enable support for SQLite custom FTS3 tokenizers at run time.
+
+Do not require that SQLite has been built with support for custom FTS3
+tokenizers enabled by default. This allows to use system SQLite in
+distributions which provide SQLite configured in this way (which is SQLite
+upstream's default configuration due to security concerns).
+
+Requires exposing the sqlite3_db_config symbol in bundled SQLite.
+
+Disable no longer needed setting of SQLITE_ENABLE_FTS3_TOKENIZER macro in
+bundled SQLite build.
+
+--- a/db/sqlite3/src/moz.build Thu Nov 29 19:08:28 2018 +0000
++++ b/db/sqlite3/src/moz.build Thu Nov 29 23:02:10 2018 +0000
+@@ -58,10 +58,6 @@
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
+ DEFINES['SQLITE_ENABLE_LOCKING_STYLE'] = 0
+
+-# Thunderbird needs the 2-argument version of fts3_tokenizer()
+-if CONFIG['MOZ_THUNDERBIRD'] or CONFIG['MOZ_SUITE']:
+- DEFINES['SQLITE_ENABLE_FTS3_TOKENIZER'] = 1
+-
+ # Turn on SQLite's assertions in debug builds.
+ if CONFIG['MOZ_DEBUG']:
+ DEFINES['SQLITE_DEBUG'] = 1
+--- a/db/sqlite3/src/sqlite.symbols Thu Nov 29 19:08:28 2018 +0000
++++ b/db/sqlite3/src/sqlite.symbols Thu Nov 29 23:02:10 2018 +0000
+@@ -45,6 +45,7 @@
+ sqlite3_create_function16
+ sqlite3_create_module
+ sqlite3_data_count
++sqlite3_db_config
+ sqlite3_db_filename
+ sqlite3_db_handle
+ sqlite3_db_mutex
+--- a/storage/mozStorageConnection.cpp Thu Nov 29 19:08:28 2018 +0000
++++ b/storage/mozStorageConnection.cpp Thu Nov 29 23:02:10 2018 +0000
+@@ -679,6 +679,10 @@
+ return convertResultCode(srv);
+ }
+
++#ifdef INIT_SQLITE_FTS3_TOKENIZER
++ ::sqlite3_db_config(mDBConn, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
++#endif
++
+ // Do not set mDatabaseFile or mFileURL here since this is a "memory"
+ // database.
+
+@@ -715,6 +719,10 @@
+ return convertResultCode(srv);
+ }
+
++#ifdef INIT_SQLITE_FTS3_TOKENIZER
++ ::sqlite3_db_config(mDBConn, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
++#endif
++
+ // Do not set mFileURL here since this is database does not have an associated
+ // URL.
+ mDatabaseFile = aDatabaseFile;
+@@ -746,6 +754,10 @@
+ return convertResultCode(srv);
+ }
+
++#ifdef INIT_SQLITE_FTS3_TOKENIZER
++ ::sqlite3_db_config(mDBConn, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
++#endif
++
+ // Set both mDatabaseFile and mFileURL here.
+ mFileURL = aFileURL;
+ mDatabaseFile = databaseFile;
+--- a/storage/moz.build 2018-11-14 10:14:14.000000000 -0500
++++ b/storage/moz.build 2018-11-29 17:05:42.106058951 -0500
+@@ -101,16 +101,20 @@
+ #
+ # Note: On Windows our sqlite build assumes we use jemalloc. If you disable
+ # MOZ_STORAGE_MEMORY on Windows, you will also need to change the "ifdef
+ # MOZ_MEMORY" options in db/sqlite3/src/Makefile.in.
+ if CONFIG['MOZ_MEMORY'] and not CONFIG['MOZ_SYSTEM_SQLITE']:
+ if CONFIG['OS_TARGET'] != 'Android':
+ DEFINES['MOZ_STORAGE_MEMORY'] = True
+
++# Thunderbird needs the 2-argument version of fts3_tokenizer()
++if CONFIG['MOZ_THUNDERBIRD'] or CONFIG['MOZ_SUITE']:
++ DEFINES['INIT_SQLITE_FTS3_TOKENIZER'] = 1
++
+ # This is the default value. If we ever change it when compiling sqlite, we
+ # will need to change it here as well.
+ DEFINES['SQLITE_MAX_LIKE_PATTERN_LENGTH'] = 50000
+
+ # See Sqlite moz.build for reasoning about TEMP_STORE.
+ # For system sqlite we cannot use the compile time option, so we use a pragma.
+ if CONFIG['MOZ_SYSTEM_SQLITE'] and (CONFIG['OS_TARGET'] == 'Android'
+ or CONFIG['HAVE_64BIT_BUILD']):
diff --git a/mail-client/thunderbird/files/thunderbird-gentoo-default-prefs.js-2 b/mail-client/thunderbird/files/thunderbird-gentoo-default-prefs.js-2
new file mode 100644
index 0000000..9770a1a
--- /dev/null
+++ b/mail-client/thunderbird/files/thunderbird-gentoo-default-prefs.js-2
@@ -0,0 +1,10 @@
+pref("app.update.enabled", false);
+pref("app.update.autoInstallEnabled", false);
+pref("browser.display.use_system_colors", true);
+pref("intl.locale.matchOS", true);
+pref("intl.locale.requested", "");
+pref("general.useragent.locale", "chrome://global/locale/intl.properties");
+pref("mail.shell.checkDefaultClient", false);
+# Do not switch to Smart Folders after upgrade to 3.0b4
+pref("mail.folder.views.version", "1");
+pref("extensions.autoDisableScopes", 0);
diff --git a/mail-client/thunderbird/metadata.xml b/mail-client/thunderbird/metadata.xml
new file mode 100644
index 0000000..5216de1
--- /dev/null
+++ b/mail-client/thunderbird/metadata.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+<maintainer type="project">
+ <email>mozilla@gentoo.org</email>
+ <name>Gentoo Mozilla Team</name>
+</maintainer>
+<use>
+ <flag name="bindist">Disable official Thunderbird branding (icons, name) which
+ are not binary-redistributable according to upstream.</flag>
+ <flag name="clang">Use Clang compiler instead of GCC</flag>
+ <flag name="crypt"> Enable encryption support with enigmail</flag>
+ <flag name="mozdom">Enable Mozilla's DOM inspector</flag>
+ <flag name="lightning">Enable app-global calendar support
+ (note 38.0 and above bundles calendar support when this flag is off)</flag>
+ <flag name="custom-optimization">Build with user-specified compiler optimizations
+ (-Os, -O0, -O1, -O2, -O3) from CFLAGS (unsupported)</flag>
+ <flag name="gtk2">Use the cairo-gtk2 rendering engine instead of the default cairo-gtk3</flag>
+ <flag name="rust">Enable support for using rust compiler (experimental)</flag>
+ <flag name="system-cairo">Use the system-wide <pkg>x11-libs/cairo</pkg>
+ instead of bundled.</flag>
+ <flag name="system-harfbuzz">Use the system-wide <pkg>media-libs/harfbuzz</pkg>
+ and <pkg>media-gfx/graphite2</pkg> instead of bundled.</flag>
+ <flag name="system-icu">Use the system-wide <pkg>dev-libs/icu</pkg>
+ instead of bundled.</flag>
+ <flag name="system-jpeg">Use the system-wide <pkg>media-libs/libjpeg-turbo</pkg>
+ instead of bundled.</flag>
+ <flag name="system-libevent">Use the system-wide <pkg>dev-libs/libevent</pkg>
+ instead of bundled.</flag>
+ <flag name="system-libvpx">Use the system-wide <pkg>media-libs/libvpx</pkg>
+ instead of bundled.</flag>
+ <flag name="system-sqlite">Use the system-wide <pkg>dev-db/sqlite</pkg>
+ installation with secure-delete enabled</flag>
+ <flag name="minimal">Remove the software development kit and headers</flag>
+</use>
+</pkgmetadata>
diff --git a/mail-client/thunderbird/thunderbird-60.8.0.ebuild b/mail-client/thunderbird/thunderbird-60.8.0.ebuild
new file mode 100644
index 0000000..35ff14e
--- /dev/null
+++ b/mail-client/thunderbird/thunderbird-60.8.0.ebuild
@@ -0,0 +1,610 @@
+# Copyright 1999-2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+VIRTUALX_REQUIRED="pgo"
+WANT_AUTOCONF="2.1"
+MOZ_ESR=""
+MOZ_LIGHTNING_VER="6.2.5"
+MOZ_LIGHTNING_GDATA_VER="4.4.1"
+
+PYTHON_COMPAT=( python3_{5,6,7} )
+PYTHON_REQ_USE='ncurses,sqlite,ssl,threads(+)'
+
+# This list can be updated using scripts/get_langs.sh from the mozilla overlay
+MOZ_LANGS=(ar ast be bg br ca cs cy da de el en en-GB en-US es-AR
+es-ES et eu fi fr fy-NL ga-IE gd gl he hr hsb hu hy-AM id is it
+ja ko lt nb-NO nl nn-NO pl pt-BR pt-PT rm ro ru si sk sl sq sr
+sv-SE tr uk vi zh-CN zh-TW )
+
+# Convert the ebuild version to the upstream mozilla version, used by mozlinguas
+MOZ_PV="${PV/_beta/b}"
+
+# Patches
+PATCHTB="thunderbird-60.0-patches-0"
+PATCHFF="firefox-60.6-patches-07"
+
+MOZ_HTTP_URI="https://archive.mozilla.org/pub/${PN}/releases"
+
+# ESR releases have slightly version numbers
+if [[ ${MOZ_ESR} == 1 ]]; then
+ MOZ_PV="${MOZ_PV}esr"
+fi
+MOZ_P="${PN}-${MOZ_PV}"
+
+LLVM_MAX_SLOT=8
+
+inherit check-reqs flag-o-matic toolchain-funcs gnome2-utils llvm mozcoreconf-v6 pax-utils xdg-utils autotools mozlinguas-v2
+
+DESCRIPTION="Thunderbird Mail Client"
+HOMEPAGE="https://www.mozilla.org/thunderbird"
+
+KEYWORDS="~amd64 ~x86 ~x86-fbsd ~amd64-linux ~x86-linux"
+SLOT="0"
+LICENSE="MPL-2.0 GPL-2 LGPL-2.1"
+IUSE="bindist clang dbus debug hardened jack lightning neon pulseaudio
+ selinux startup-notification system-harfbuzz system-icu system-jpeg
+ system-libevent system-libvpx system-sqlite wayland wifi"
+RESTRICT="!bindist? ( bindist )"
+
+PATCH_URIS=( https://dev.gentoo.org/~{anarchy,axs,polynomial-c,whissi}/mozilla/patchsets/{${PATCHTB},${PATCHFF}}.tar.xz )
+SRC_URI="${SRC_URI}
+ ${MOZ_HTTP_URI}/${MOZ_PV}/source/${MOZ_P}.source.tar.xz
+ https://dev.gentoo.org/~axs/distfiles/lightning-${MOZ_LIGHTNING_VER}.tar.xz
+ lightning? ( https://dev.gentoo.org/~axs/distfiles/gdata-provider-${MOZ_LIGHTNING_GDATA_VER}.tar.xz )
+ ${PATCH_URIS[@]}"
+
+ASM_DEPEND=">=dev-lang/yasm-1.1"
+
+CDEPEND="
+ >=dev-libs/nss-3.36.7
+ >=dev-libs/nspr-4.19
+ >=app-text/hunspell-1.5.4:=
+ dev-libs/atk
+ dev-libs/expat
+ >=x11-libs/cairo-1.10[X]
+ >=x11-libs/gtk+-2.18:2
+ >=x11-libs/gtk+-3.4.0:3
+ x11-libs/gdk-pixbuf
+ >=x11-libs/pango-1.22.0
+ >=media-libs/libpng-1.6.34:0=[apng]
+ >=media-libs/mesa-10.2:*
+ media-libs/fontconfig
+ >=media-libs/freetype-2.4.10
+ kernel_linux? ( !pulseaudio? ( media-libs/alsa-lib ) )
+ virtual/freedesktop-icon-theme
+ dbus? (
+ >=sys-apps/dbus-0.60
+ >=dev-libs/dbus-glib-0.72
+ )
+ startup-notification? ( >=x11-libs/startup-notification-0.8 )
+ >=x11-libs/pixman-0.19.2
+ >=dev-libs/glib-2.26:2
+ >=sys-libs/zlib-1.2.3
+ >=virtual/libffi-3.0.10:=
+ virtual/ffmpeg
+ x11-libs/libX11
+ x11-libs/libXcomposite
+ x11-libs/libXdamage
+ x11-libs/libXext
+ x11-libs/libXfixes
+ x11-libs/libXrender
+ x11-libs/libXt
+ system-harfbuzz? (
+ >=media-libs/harfbuzz-1.4.2:0=
+ >=media-gfx/graphite2-1.3.9-r1
+ )
+ system-icu? ( >=dev-libs/icu-59.1:= )
+ system-jpeg? ( >=media-libs/libjpeg-turbo-1.2.1:= )
+ system-libevent? ( >=dev-libs/libevent-2.0:0=[threads] )
+ system-libvpx? (
+ >=media-libs/libvpx-1.5.0:0=[postproc]
+ <media-libs/libvpx-1.8:0=[postproc]
+ )
+ system-sqlite? ( >=dev-db/sqlite-3.23.1:3[secure-delete,debug=] )
+ wifi? (
+ kernel_linux? (
+ >=sys-apps/dbus-0.60
+ >=dev-libs/dbus-glib-0.72
+ net-misc/networkmanager
+ )
+ )
+ jack? ( virtual/jack )"
+
+DEPEND="${CDEPEND}
+ app-arch/zip
+ app-arch/unzip
+ >=sys-devel/binutils-2.30
+ sys-apps/findutils
+ || (
+ (
+ sys-devel/clang:8
+ !clang? ( sys-devel/llvm:8 )
+ clang? (
+ =sys-devel/lld-8*
+ sys-devel/llvm:8[gold]
+ )
+ )
+ (
+ sys-devel/clang:7
+ !clang? ( sys-devel/llvm:7 )
+ clang? (
+ =sys-devel/lld-7*
+ sys-devel/llvm:7[gold]
+ )
+ )
+ (
+ sys-devel/clang:6
+ !clang? ( sys-devel/llvm:6 )
+ clang? (
+ =sys-devel/lld-6*
+ sys-devel/llvm:6[gold]
+ )
+ )
+ )
+ pulseaudio? ( media-sound/pulseaudio )
+ elibc_glibc? (
+ virtual/cargo
+ virtual/rust
+ )
+ elibc_musl? (
+ virtual/cargo
+ virtual/rust
+ )
+ amd64? (
+ ${ASM_DEPEND}
+ virtual/opengl
+ )
+ x86? (
+ ${ASM_DEPEND}
+ virtual/opengl
+ )"
+
+RDEPEND="${CDEPEND}
+ pulseaudio? (
+ || (
+ media-sound/pulseaudio
+ >=media-sound/apulse-0.1.9
+ )
+ )
+ selinux? (
+ sec-policy/selinux-mozilla
+ sec-policy/selinux-thunderbird
+ )"
+
+REQUIRED_USE="wifi? ( dbus )"
+
+S="${WORKDIR}/${MOZ_P%b[0-9]*}"
+
+BUILD_OBJ_DIR="${S}/tbird"
+
+llvm_check_deps() {
+ if ! has_version "sys-devel/clang:${LLVM_SLOT}" ; then
+ ewarn "sys-devel/clang:${LLVM_SLOT} is missing! Cannot use LLVM slot ${LLVM_SLOT} ..."
+ return 1
+ fi
+
+ if use clang ; then
+ if ! has_version "=sys-devel/lld-${LLVM_SLOT}*" ; then
+ ewarn "=sys-devel/lld-${LLVM_SLOT}* is missing! Cannot use LLVM slot ${LLVM_SLOT} ..."
+ return 1
+ fi
+ fi
+
+ einfo "Will use LLVM slot ${LLVM_SLOT}!"
+}
+
+pkg_setup() {
+ moz_pkgsetup
+
+ # Avoid PGO profiling problems due to enviroment leakage
+ # These should *always* be cleaned up anyway
+ unset DBUS_SESSION_BUS_ADDRESS \
+ DISPLAY \
+ ORBIT_SOCKETDIR \
+ SESSION_MANAGER \
+ XDG_SESSION_COOKIE \
+ XAUTHORITY
+
+ if ! use bindist ; then
+ elog "You are enabling official branding. You may not redistribute this build"
+ elog "to any users on your network or the internet. Doing so puts yourself into"
+ elog "a legal problem with Mozilla Foundation"
+ elog "You can disable it by emerging ${PN} _with_ the bindist USE-flag"
+ elog
+ fi
+
+ addpredict /proc/self/oom_score_adj
+
+ llvm_pkg_setup
+}
+
+pkg_pretend() {
+ # Ensure we have enough disk space to compile
+ CHECKREQS_DISK_BUILD="4G"
+ check-reqs_pkg_setup
+}
+
+src_unpack() {
+ unpack ${A}
+
+ # Unpack language packs
+ mozlinguas_src_unpack
+}
+
+src_prepare() {
+ # Apply our patchset from firefox to thunderbird as well
+ rm -f "${WORKDIR}"/firefox/2007_fix_nvidia_latest.patch \
+ "${WORKDIR}"/firefox/2005_ffmpeg4.patch \
+ "${WORKDIR}"/firefox/2012_update-cc-to-honor-CC.patch \
+ || die
+ eapply "${WORKDIR}/firefox"
+
+ eapply "${FILESDIR}"/thunderbird-60-sqlite3-fts3-tokenizer.patch
+
+ # Ensure that are plugins dir is enabled as default
+ sed -i -e "s:/usr/lib/mozilla/plugins:/usr/lib/nsbrowser/plugins:" \
+ "${S}"/xpcom/io/nsAppFileLocationProvider.cpp || die "sed failed to replace plugin path for 32bit!"
+ sed -i -e "s:/usr/lib64/mozilla/plugins:/usr/lib64/nsbrowser/plugins:" \
+ "${S}"/xpcom/io/nsAppFileLocationProvider.cpp || die "sed failed to replace plugin path for 64bit!"
+
+ # Don't error out when there's no files to be removed:
+ sed 's@\(xargs rm\)$@\1 -f@' \
+ -i "${S}"/toolkit/mozapps/installer/packager.mk || die
+
+ # Don't exit with error when some libs are missing which we have in
+ # system.
+ sed '/^MOZ_PKG_FATAL_WARNINGS/s@= 1@= 0@' \
+ -i "${S}"/comm/mail/installer/Makefile.in || die
+
+ # Apply our Thunderbird patchset
+ pushd "${S}"/comm &>/dev/null || die
+ eapply "${WORKDIR}"/thunderbird
+
+ # NOT TRIGGERED starting with 60.3, as script just maps ${PV} without any actual
+ # check on lightning version or changes:
+ #
+ # Confirm the version of lightning being grabbed for langpacks is the same
+ # as that used in thunderbird
+ #local THIS_MOZ_LIGHTNING_VER=$(${PYTHON} calendar/lightning/build/makeversion.py ${PV})
+ #if [[ ${MOZ_LIGHTNING_VER} != ${THIS_MOZ_LIGHTNING_VER} ]]; then
+ # eqawarn "The version of lightning used for localization differs from the version"
+ # eqawarn "in thunderbird. Please update MOZ_LIGHTNING_VER in the ebuild from ${MOZ_LIGHTNING_VER}"
+ # eqawarn "to ${THIS_MOZ_LIGHTNING_VER}"
+ #fi
+
+ popd &>/dev/null || die
+
+ # Backport work on Firefox components to allow Thunderbird to run under Wayland
+ # See https://mastransky.wordpress.com/2019/02/08/thunderbird-for-wayland/ and https://src.fedoraproject.org/rpms/thunderbird
+ eapply "${FILESDIR}"/firefox-wayland.patch
+
+ # Allow user to apply any additional patches without modifing ebuild
+ eapply_user
+
+ # Autotools configure is now called old-configure.in
+ # This works because there is still a configure.in that happens to be for the
+ # shell wrapper configure script
+ eautoreconf old-configure.in
+
+ # Must run autoconf in js/src
+ cd "${S}"/js/src || die
+ eautoconf old-configure.in
+}
+
+src_configure() {
+ # Add information about TERM to output (build.log) to aid debugging
+ # blessings problems
+ if [[ -n "${TERM}" ]] ; then
+ einfo "TERM is set to: \"${TERM}\""
+ else
+ einfo "TERM is unset."
+ fi
+
+ if use clang && ! tc-is-clang ; then
+ # Force clang
+ einfo "Enforcing the use of clang due to USE=clang ..."
+ CC=${CHOST}-clang
+ CXX=${CHOST}-clang++
+ strip-unsupported-flags
+ elif ! use clang && ! tc-is-gcc ; then
+ # Force gcc
+ einfo "Enforcing the use of gcc due to USE=-clang ..."
+ CC=${CHOST}-gcc
+ CXX=${CHOST}-g++
+ strip-unsupported-flags
+ fi
+
+ ####################################
+ #
+ # mozconfig, CFLAGS and CXXFLAGS setup
+ #
+ ####################################
+
+ mozconfig_init
+ # common config components
+ mozconfig_annotate 'system_libs' \
+ --with-system-zlib \
+ --with-system-bz2
+
+ # Must pass release in order to properly select linker
+ mozconfig_annotate 'Enable by Gentoo' --enable-release
+
+ # Avoid auto-magic on linker
+ if use clang ; then
+ # This is upstream's default
+ mozconfig_annotate "forcing ld=lld due to USE=clang" --enable-linker=lld
+ elif tc-ld-is-gold ; then
+ mozconfig_annotate "linker is set to gold" --enable-linker=gold
+ else
+ mozconfig_annotate "linker is set to bfd" --enable-linker=bfd
+ fi
+
+ # It doesn't compile on alpha without this LDFLAGS
+ use alpha && append-ldflags "-Wl,--no-relax"
+
+ # Add full relro support for hardened
+ if use hardened; then
+ append-ldflags "-Wl,-z,relro,-z,now"
+ mozconfig_use_enable hardened hardening
+ fi
+
+ # Modifications to better support ARM, bug 553364
+ if use neon ; then
+ mozconfig_annotate '' --with-fpu=neon
+
+ if ! tc-is-clang ; then
+ # thumb options aren't supported when using clang, bug 666966
+ mozconfig_annotate '' --with-thumb=yes
+ mozconfig_annotate '' --with-thumb-interwork=no
+ fi
+ fi
+ if [[ ${CHOST} == armv*h* ]] ; then
+ mozconfig_annotate '' --with-float-abi=hard
+ if ! use system-libvpx ; then
+ sed -i -e "s|softfp|hard|" \
+ "${S}"/media/libvpx/moz.build
+ fi
+ fi
+
+ mozconfig_use_enable !bindist official-branding
+ # Enable position independent executables
+ mozconfig_annotate 'enabled by Gentoo' --enable-pie
+
+ mozconfig_use_enable debug
+ mozconfig_use_enable debug tests
+ if ! use debug ; then
+ mozconfig_annotate 'disabled by Gentoo' --disable-debug-symbols
+ else
+ mozconfig_annotate 'enabled by Gentoo' --enable-debug-symbols
+ fi
+ # These are enabled by default in all mozilla applications
+ mozconfig_annotate '' --with-system-nspr --with-nspr-prefix="${SYSROOT}${EPREFIX}"/usr
+ mozconfig_annotate '' --with-system-nss --with-nss-prefix="${SYSROOT}${EPREFIX}"/usr
+ mozconfig_annotate '' --x-includes="${SYSROOT}${EPREFIX}"/usr/include \
+ --x-libraries="${SYSROOT}${EPREFIX}"/usr/$(get_libdir)
+ mozconfig_annotate '' --prefix="${EPREFIX}"/usr
+ mozconfig_annotate '' --libdir="${EPREFIX}"/usr/$(get_libdir)
+ mozconfig_annotate 'Gentoo default' --enable-system-hunspell
+ mozconfig_annotate '' --disable-crashreporter
+ mozconfig_annotate 'Gentoo default' --with-system-png
+ mozconfig_annotate '' --enable-system-ffi
+ mozconfig_annotate '' --disable-gconf
+ mozconfig_annotate '' --with-intl-api
+ mozconfig_annotate '' --enable-system-pixman
+ # Instead of the standard --build= and --host=, mozilla uses --host instead
+ # of --build, and --target intstead of --host.
+ # Note, mozilla also has --build but it does not do what you think it does.
+ # Set both --target and --host as mozilla uses python to guess values otherwise
+ mozconfig_annotate '' --target="${CHOST}"
+ mozconfig_annotate '' --host="${CBUILD:-${CHOST}}"
+ if use system-libevent; then
+ mozconfig_annotate '' --with-system-libevent="${SYSROOT}${EPREFIX}"/usr
+ fi
+
+ # skia has no support for big-endian platforms
+ if [[ $(tc-endian) == "big" ]]; then
+ mozconfig_annotate 'big endian target' --disable-skia
+ else
+ mozconfig_annotate '' --enable-skia
+ fi
+
+ # use the gtk3 toolkit (the only one supported at this point)
+ if use wayland ; then
+ mozconfig_annotate '' --enable-default-toolkit=cairo-gtk3-wayland
+ else
+ mozconfig_annotate '' --enable-default-toolkit=cairo-gtk3
+ fi
+
+ mozconfig_use_enable startup-notification
+ mozconfig_use_enable system-sqlite
+ mozconfig_use_with system-jpeg
+ mozconfig_use_with system-icu
+ mozconfig_use_with system-libvpx
+ mozconfig_use_with system-harfbuzz
+ mozconfig_use_with system-harfbuzz system-graphite2
+ mozconfig_use_enable pulseaudio
+ # force the deprecated alsa sound code if pulseaudio is disabled
+ if use kernel_linux && ! use pulseaudio ; then
+ mozconfig_annotate '-pulseaudio' --enable-alsa
+ fi
+
+ mozconfig_use_enable dbus
+
+ mozconfig_use_enable wifi necko-wifi
+
+ # enable JACK, bug 600002
+ mozconfig_use_enable jack
+
+ # Other tb-specific settings
+ mozconfig_annotate '' --with-user-appdir=.thunderbird
+ mozconfig_annotate '' --enable-ldap
+ mozconfig_annotate '' --enable-calendar
+
+ # Disable built-in ccache support to avoid sandbox violation, #665420
+ # Use FEATURES=ccache instead!
+ mozconfig_annotate '' --without-ccache
+ sed -i -e 's/ccache_stats = None/return None/' \
+ python/mozbuild/mozbuild/controller/building.py || \
+ die "Failed to disable ccache stats call"
+
+ # Stylo is only broken on x86 builds
+ use x86 && mozconfig_annotate 'Upstream bug 1341234' --disable-stylo
+
+ # Stylo is horribly broken on arm, renders GUI unusable
+ use arm && mozconfig_annotate 'breaks UI on arm' --disable-stylo
+
+ if use clang ; then
+ # libprldap60.so: terminate called after throwing an instance of 'std::runtime_error', bug 667186
+ mozconfig_annotate 'elf-hack is broken when using clang' --disable-elf-hack
+ elif use arm ; then
+ mozconfig_annotate 'elf-hack is broken on arm' --disable-elf-hack
+ fi
+
+ # Use an objdir to keep things organized.
+ echo "mk_add_options MOZ_OBJDIR=${BUILD_OBJ_DIR}" >> "${S}"/.mozconfig
+ echo "mk_add_options XARGS=/usr/bin/xargs" >> "${S}"/.mozconfig
+
+ mozlinguas_mozconfig
+
+ # Finalize and report settings
+ mozconfig_final
+
+ ####################################
+ #
+ # Configure and build
+ #
+ ####################################
+
+ # Disable no-print-directory
+ MAKEOPTS=${MAKEOPTS/--no-print-directory/}
+
+ if [[ $(gcc-major-version) -lt 4 ]]; then
+ append-cxxflags -fno-stack-protector
+ fi
+
+ # workaround for funky/broken upstream configure...
+ SHELL="${SHELL:-${EPREFIX}/bin/bash}" MOZ_NOSPAM=1 \
+ ./mach configure || die
+}
+
+src_compile() {
+ MOZ_MAKE_FLAGS="${MAKEOPTS}" SHELL="${SHELL:-${EPREFIX}/bin/bash}" MOZ_NOSPAM=1 \
+ ./mach build --verbose || die
+}
+
+src_install() {
+ declare emid
+ cd "${BUILD_OBJ_DIR}" || die
+
+ # Pax mark xpcshell for hardened support, only used for startupcache creation.
+ pax-mark m "${BUILD_OBJ_DIR}"/dist/bin/xpcshell
+
+ # Copy our preference before omnijar is created.
+ cp "${FILESDIR}"/thunderbird-gentoo-default-prefs.js-2 \
+ "${BUILD_OBJ_DIR}/dist/bin/defaults/pref/all-gentoo.js" \
+ || die
+
+ # set dictionary path, to use system hunspell
+ echo "pref(\"spellchecker.dictionary_path\", \"${EPREFIX}/usr/share/myspell\");" \
+ >>"${BUILD_OBJ_DIR}/dist/bin/defaults/pref/all-gentoo.js" || die
+
+ # force the graphite pref if system-harfbuzz is enabled, since the pref cant disable it
+ if use system-harfbuzz ; then
+ echo "sticky_pref(\"gfx.font_rendering.graphite.enabled\",true);" \
+ >>"${BUILD_OBJ_DIR}/dist/bin/defaults/pref/all-gentoo.js" || die
+ fi
+
+ # force cairo as the canvas renderer on platforms without skia support
+ if [[ $(tc-endian) == "big" ]] ; then
+ echo "sticky_pref(\"gfx.canvas.azure.backends\",\"cairo\");" \
+ >>"${BUILD_OBJ_DIR}/dist/bin/defaults/pref/all-gentoo.js" || die
+ echo "sticky_pref(\"gfx.content.azure.backends\",\"cairo\");" \
+ >>"${BUILD_OBJ_DIR}/dist/bin/defaults/pref/all-gentoo.js" || die
+ fi
+
+ cd "${S}" || die
+ MOZ_MAKE_FLAGS="${MAKEOPTS}" SHELL="${SHELL:-${EPREFIX}/bin/bash}" MOZ_NOSPAM=1 \
+ DESTDIR="${D}" ./mach install || die
+
+ # Install language packs
+ MOZ_INSTALL_L10N_XPIFILE="1" mozlinguas_src_install
+
+ local size sizes icon_path icon
+ if ! use bindist; then
+ icon_path="${S}/comm/mail/branding/thunderbird"
+ icon="${PN}-icon"
+
+ domenu "${FILESDIR}"/icon/${PN}.desktop
+ else
+ icon_path="${S}/comm/mail/branding/nightly"
+ icon="${PN}-icon-unbranded"
+
+ newmenu "${FILESDIR}"/icon/${PN}-unbranded.desktop \
+ ${PN}.desktop
+
+ sed -i -e "s:Mozilla\ Thunderbird:EarlyBird:g" \
+ "${ED}"/usr/share/applications/${PN}.desktop
+ fi
+
+ # Install a 48x48 icon into /usr/share/pixmaps for legacy DEs
+ newicon "${icon_path}"/default48.png "${icon}".png
+ # Install icons for menu entry
+ sizes="16 22 24 32 48 256"
+ for size in ${sizes}; do
+ newicon -s ${size} "${icon_path}/default${size}.png" "${icon}.png"
+ done
+
+ local emid
+ # stage extra locales for lightning and install over existing
+ emid='{e2fda1a4-762b-4020-b5ad-a41df1933103}'
+ rm -f "${ED}"/${MOZILLA_FIVE_HOME}/distribution/extensions/${emid}.xpi || die
+ mozlinguas_xpistage_langpacks "${BUILD_OBJ_DIR}"/dist/bin/distribution/extensions/${emid} \
+ "${WORKDIR}"/lightning-${MOZ_LIGHTNING_VER} lightning calendar
+
+ mkdir -p "${T}/${emid}" || die
+ cp -RLp -t "${T}/${emid}" "${BUILD_OBJ_DIR}"/dist/bin/distribution/extensions/${emid}/* || die
+ insinto ${MOZILLA_FIVE_HOME}/distribution/extensions
+ doins -r "${T}/${emid}"
+
+ if use lightning; then
+ # move lightning out of distribution/extensions and into extensions for app-global install
+ mv "${ED}"/${MOZILLA_FIVE_HOME}/{distribution,}/extensions/${emid} || die
+
+ # stage extra locales for gdata-provider and install app-global
+ mozlinguas_xpistage_langpacks "${BUILD_OBJ_DIR}"/dist/xpi-stage/gdata-provider \
+ "${WORKDIR}"/gdata-provider-${MOZ_LIGHTNING_GDATA_VER}
+ emid='{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}'
+ mkdir -p "${T}/${emid}" || die
+ cp -RLp -t "${T}/${emid}" "${BUILD_OBJ_DIR}"/dist/xpi-stage/gdata-provider/* || die
+
+ # manifest.json does not allow the addon to load, put install.rdf in place
+ # note, version number needs to be set properly
+ cp -RLp -t "${T}/${emid}" "${WORKDIR}"/gdata-provider-${MOZ_LIGHTNING_GDATA_VER}/install.rdf
+ sed -i -e '/em:version/ s/>[^<]*</>4.1</' "${T}/${emid}"/install.rdf
+
+ insinto ${MOZILLA_FIVE_HOME}/extensions
+ doins -r "${T}/${emid}"
+ fi
+
+ # thunderbird and thunderbird-bin are identical
+ rm "${ED%/}"${MOZILLA_FIVE_HOME}/thunderbird-bin || die
+ dosym thunderbird ${MOZILLA_FIVE_HOME}/thunderbird-bin
+
+ # Required in order to use plugins and even run thunderbird on hardened.
+ pax-mark pm "${ED%/}"${MOZILLA_FIVE_HOME}/{thunderbird,plugin-container}
+}
+
+pkg_preinst() {
+ gnome2_icon_savelist
+}
+
+pkg_postinst() {
+ gnome2_icon_cache_update
+ xdg_desktop_database_update
+}
+
+pkg_postrm() {
+ gnome2_icon_cache_update
+ xdg_desktop_database_update
+}