From ad4a9a5ae982f9484088a945cd7dc9bce395fa9b Mon Sep 17 00:00:00 2001 From: Nicholas Fish Date: Thu, 18 Jul 2019 08:12:17 +0200 Subject: mail-client/thunderbird: Add with support for running under Wayland Signed-off-by: Nicholas Fish --- mail-client/thunderbird/Manifest | 65 + .../thunderbird/files/firefox-wayland.patch | 4441 ++++++++++++++++++++ .../files/icon/thunderbird-unbranded.desktop | 9 + .../thunderbird/files/icon/thunderbird.desktop | 9 + .../thunderbird-60-sqlite3-fts3-tokenizer.patch | 99 + .../files/thunderbird-gentoo-default-prefs.js-2 | 10 + mail-client/thunderbird/metadata.xml | 36 + mail-client/thunderbird/thunderbird-60.8.0.ebuild | 610 +++ 8 files changed, 5279 insertions(+) create mode 100644 mail-client/thunderbird/Manifest create mode 100644 mail-client/thunderbird/files/firefox-wayland.patch create mode 100644 mail-client/thunderbird/files/icon/thunderbird-unbranded.desktop create mode 100644 mail-client/thunderbird/files/icon/thunderbird.desktop create mode 100644 mail-client/thunderbird/files/thunderbird-60-sqlite3-fts3-tokenizer.patch create mode 100644 mail-client/thunderbird/files/thunderbird-gentoo-default-prefs.js-2 create mode 100644 mail-client/thunderbird/metadata.xml create mode 100644 mail-client/thunderbird/thunderbird-60.8.0.ebuild 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 +-#ifdef MOZ_WAYLAND + #include +-#include ++#ifdef MOZ_WAYLAND ++#include "nsWaylandDisplay.h" ++#include + #endif + #include + #include +@@ -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_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, ®istry_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 + #include "mozilla/Types.h" + #include ++#include + #include + ++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 ++#include ++ ++#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 + #include + #include +-#include +-#include + #include + +-#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(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(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(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(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( + 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( + 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( +- 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( ++ 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( + 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( ++ 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(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(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(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(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(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(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(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(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, >k_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(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(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( +- 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 +@@ -32,31 +33,75 @@ class DataOffer { + private: + virtual bool RequestDataTransfer(const char* aMimeType, int fd) = 0; + ++ protected: + nsTArray 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 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 mClipboardOffer; + nsAutoPtr mPrimaryOffer; ++ RefPtr 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 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 + + 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 mPendingWindow; + mozilla::LayoutDeviceIntPoint mPendingWindowPoint; + nsCountedRef mPendingDragContext; ++#ifdef MOZ_WAYLAND ++ RefPtr 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 mTargetWidget; + nsCountedRef mTargetDragContext; ++#ifdef MOZ_WAYLAND ++ RefPtr mTargetWaylandDragContext; ++#endif + // mTargetDragContextForRemote is set while waiting for a reply from + // a child process. + nsCountedRef mTargetDragContextForRemote; ++#ifdef MOZ_WAYLAND ++ RefPtr 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 ++#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 + #include ++#ifdef MOZ_WAYLAND ++#include ++#include ++#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 + #include "gfxPlatformGtk.h" ++//#include "mozilla/FontPropertyTypes.h" + #include "ScreenHelperGTK.h" + + #include "gtkdrawing.h" +@@ -31,7 +32,9 @@ + #include + #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(data); ++ ++ if (strcmp(interface, "wl_shm") == 0) { ++ auto shm = static_cast( ++ 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_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_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(wl_registry_bind( ++ registry, id, >k_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_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, ®istry_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 + + #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 ++#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 +@@ -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 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(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( ++ 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( ++ 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(mGtkWindowTypeName.get()); ++ class_hint->res_class = const_cast(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(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 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 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 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 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 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 + #include +- + #ifdef MOZ_X11 + #include + #include "X11UndefineNone.h" +@@ -28,7 +17,16 @@ + #ifdef MOZ_WAYLAND + #include + #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 + #endif + #include // 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 + #include +-#include + #include + #include + ++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 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(data); +- auto shm = static_cast( +- 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, ®istry_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(data); ++static void buffer_release(void* data, wl_buffer* buffer) { ++ auto surface = reinterpret_cast(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 WindowBackBuffer::Lock( +- const LayoutDeviceIntRegion &aRegion) { +- gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); +- gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); +- ++already_AddRefed WindowBackBuffer::Lock() { ++ gfx::IntSize lockSize(mWidth, mHeight); + return gfxPlatform::CreateDrawTargetForData( +- static_cast(mShmPool.GetImageData()), lockSize, +- BUFFER_BPP * mWidth, mWaylandDisplay->GetSurfaceFormat()); ++ static_cast(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(data); ++ auto surface = reinterpret_cast(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 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 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 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 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 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 dt = LockWaylandBuffer( ++ screenRect.width, screenRect.height, mWindow->WaylandSurfaceNeedsClear()); ++ RefPtr surf = ++ gfx::Factory::CreateSourceSurfaceForCairoSurface( ++ mImageSurface->CairoSurface(), mImageSurface->GetSize(), ++ mImageSurface->Format()); ++ if (!dt || !surf) { ++ return false; ++ } ++ ++ uint32_t numRects = aRegion.GetNumRects(); ++ if (numRects != 1) { ++ AutoTArray 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( ++ 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 ++#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 Lock(const LayoutDeviceIntRegion& aRegion); ++ already_AddRefed 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 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 LockWaylandBuffer(int aWidth, int aHeight, ++ bool aClearBuffer); ++ already_AddRefed 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 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 +# 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 @@ + + + + + mozilla@gentoo.org + Gentoo Mozilla Team + + + Disable official Thunderbird branding (icons, name) which + are not binary-redistributable according to upstream. + Use Clang compiler instead of GCC + Enable encryption support with enigmail + Enable Mozilla's DOM inspector + Enable app-global calendar support + (note 38.0 and above bundles calendar support when this flag is off) + Build with user-specified compiler optimizations + (-Os, -O0, -O1, -O2, -O3) from CFLAGS (unsupported) + Use the cairo-gtk2 rendering engine instead of the default cairo-gtk3 + Enable support for using rust compiler (experimental) + Use the system-wide x11-libs/cairo + instead of bundled. + Use the system-wide media-libs/harfbuzz + and media-gfx/graphite2 instead of bundled. + Use the system-wide dev-libs/icu + instead of bundled. + Use the system-wide media-libs/libjpeg-turbo + instead of bundled. + Use the system-wide dev-libs/libevent + instead of bundled. + Use the system-wide media-libs/libvpx + instead of bundled. + Use the system-wide dev-db/sqlite + installation with secure-delete enabled + Remove the software development kit and headers + + 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] + =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