Compare commits
1008 Commits
Author | SHA1 | Date |
---|---|---|
Sergio Durigan Junior | 7a890f5dad | |
Sergio Durigan Junior | 2826d650dc | |
Sergio Durigan Junior | 732e898e6e | |
Sergio Durigan Junior | 7e2916f0ea | |
Sergio Durigan Junior | 91090b3e92 | |
Sergio Durigan Junior | 7fa139b241 | |
Sergio Durigan Junior | a84927af41 | |
Sergio Durigan Junior | bb954d02ba | |
Sergio Durigan Junior | ccd28b22eb | |
Sergio Durigan Junior | a5c70e7b08 | |
Sergio Durigan Junior | 6121e4d3ef | |
Andres Salomon | 597a50019b | |
Andres Salomon | ab72120436 | |
Yves-Alexis Perez | 2d27f4a46f | |
Ryan Niebur | a92607d4fb | |
Ryan Niebur | cd6899f136 | |
Ryan Niebur | 3c395daddb | |
Ryan Niebur | 5aa73dea25 | |
Ryan Niebur | f5a8cd23ac | |
Ryan Niebur | 50549da7c3 | |
Ryan Niebur | 7509079965 | |
Ryan Niebur | f5457c8c6a | |
Ryan Niebur | 14564ce6cc | |
Koichi Akabe | a9def3c602 | |
Ryan Niebur | 405f565df8 | |
Ryan Niebur | 60d455a553 | |
Yves-Alexis Perez | fae7cfdb3d | |
Yves-Alexis Perez | fd240475ed | |
Christian Dywan | de4fca9402 | |
Christian Dywan | 147acdcaef | |
Christian Dywan | 4e786f10be | |
André Stösel | 5f8cd5c12d | |
Boram Kim | b8f2e25698 | |
Pjotr vertaalt | 035c2a386b | |
Sergio Marques | f2e4e162c5 | |
Christian Dywan | 01b36c5fc4 | |
Christian Dywan | 7e39d05a17 | |
Christian Dywan | b4b795e156 | |
Christian Dywan | 2e3882db4b | |
Paweł Forysiuk | 55c11850bb | |
Paweł Forysiuk | 00bd3f0818 | |
Christian Dywan | d88b9776f2 | |
André Stösel | 13b735e382 | |
Christian Dywan | dd39dab307 | |
Christian Dywan | b3984ab252 | |
Christian Dywan | 09432b2d12 | |
Christian Dywan | 7d5fd0d319 | |
Christian Dywan | 5f18e39221 | |
Christian Dywan | 0da919f4d9 | |
Paweł Forysiuk | 616633d502 | |
David Štancl | 5bb5b17986 | |
David Štancl | cd21f66217 | |
Cristian Marchi | a902248bae | |
Andhika Padmawan | 5db5a0b6cb | |
Christian Dywan | ddc1bec3fe | |
Christian Dywan | 29716305b5 | |
Christian Dywan | 5fdd9bdee0 | |
André Stösel | 1929c51d9d | |
André Stösel | ec04a1a274 | |
Boram Kim | 7124e36dd5 | |
Christian Dywan | ad4e075051 | |
Christian Dywan | 00cb292b80 | |
Christian Dywan | 13c884b5cb | |
Masato Hashimoto | 55c06a4285 | |
Paweł Forysiuk | 5f43dceef0 | |
Christian Dywan | 55e4823c30 | |
Christian Dywan | f185bcb42d | |
Christian Dywan | ca07fe3cec | |
Christian Dywan | 4b533d2f51 | |
Christian Dywan | 886ad1b765 | |
Yarema aka Knedlyk | 2bdaf5057e | |
Christian Dywan | bae360e3f8 | |
Paweł Forysiuk | f29318af7c | |
Paweł Forysiuk | 9af985e7e8 | |
Paweł Forysiuk | 419d4c1ae5 | |
Paweł Forysiuk | 82242a8c2e | |
Paweł Forysiuk | 8de05bc07d | |
Christian Dywan | fefc3b2cbe | |
Christian Dywan | 1ad675e24e | |
Christian Dywan | f715e11ebf | |
Christian Dywan | 33efb94666 | |
Christian Dywan | dd90c2b65b | |
Christian Dywan | 49da17badd | |
Christian Dywan | c8b6e07f27 | |
Paweł Forysiuk | ad99fb1ebb | |
prflr88 | fe2a5c048c | |
Christian Dywan | e3a71596bc | |
Jakob Kramer | b3e604881b | |
Pjotr vertaalt | b62602d28a | |
Sergio Marques | dd0607316b | |
Christian Dywan | 3ff4483736 | |
Christian Dywan | 3bb03bfc56 | |
Paul Menzel | ccd5b5ac99 | |
Christian Dywan | a6744f64ee | |
Ardjuna | 3717185834 | |
Paweł Forysiuk | 3f4b0da5a0 | |
Christian Dywan | 646b41b256 | |
Paweł Forysiuk | e75348c463 | |
Christian Dywan | e2c9660b3a | |
Christian Dywan | 6210c59e31 | |
Christian Dywan | f2960a910d | |
Christian Dywan | fec04dd1b0 | |
David Štancl | be6ea33642 | |
Rafael Ferreira | de47f61360 | |
Yarema aka Knedlyk | 407c46d2f4 | |
Sergio Marques | 0e7cf9eb6d | |
Christian Dywan | 2b134da7d9 | |
Paweł Forysiuk | 81179e175b | |
Paweł Forysiuk | d426a4df9e | |
Paweł Forysiuk | 414a5f07ae | |
Christian Dywan | c1d387f958 | |
Christian Dywan | fee43b8be6 | |
Pjotr vertaalt | 5555b88959 | |
Christian Dywan | 7e1f2655bc | |
Paweł Forysiuk | be61f96bc2 | |
Christian Dywan | c49fb82e87 | |
Christian Dywan | 64c9517459 | |
Christian Dywan | 373ddd5d0b | |
jc jc1 | 253a11d7ef | |
prflr88 | acd116361b | |
Boram Kim | 14abefcea9 | |
Christian Dywan | bc1ff81410 | |
Paweł Forysiuk | 9b09760839 | |
Christian Dywan | db0ae6ab60 | |
Christian Dywan | 287fc53da9 | |
Christian Dywan | b955713b4e | |
Christian Dywan | aa5d387cc7 | |
Christian Dywan | fd49037ae6 | |
Christian Dywan | f4a3e69096 | |
Christian Dywan | ebd0847a39 | |
Christian Dywan | a0d9517053 | |
Christian Dywan | 1ce2b96680 | |
Christian Dywan | 58d1436d4e | |
Christian Dywan | 1c1fd1740e | |
Christian Dywan | f5d0c3ad5d | |
Christian Dywan | 0668aba7cc | |
Yves-Alexis Perez | 194aab3473 | |
jc jc1 | 3fbd36f3f5 | |
David Štancl | fdff73182e | |
Christian Dywan | 0f1f26480d | |
Christian Dywan | 36c3a4925a | |
Christian Dywan | de771db75d | |
Christian Dywan | 915955c0da | |
Christian Dywan | 3fb42ef2d7 | |
Boram Kim | 503f1be5c5 | |
Paweł Forysiuk | 8bf93fcad0 | |
Paweł Forysiuk | 910e2d4842 | |
Christian Dywan | a6606a9cee | |
Christian Dywan | cc4fbca8e3 | |
Christian Dywan | 7f37162fe0 | |
Christian Dywan | 49dae87d36 | |
Christian Dywan | cfb0db3b60 | |
Christian Dywan | f41498e16c | |
Alex Z | b5ff08c4c0 | |
Mario Blättermann | 6226d9847b | |
Mario Blättermann | 78eaf31e30 | |
Christian Dywan | 6757898c95 | |
Paweł Forysiuk | 879d6c41a7 | |
Paweł Forysiuk | 52c8b4aea9 | |
Gheyret Kenji | d641a52de1 | |
Ivica Kolić | 944e9107ff | |
Efstathios Iosifidis | 4e996d1824 | |
Paweł Forysiuk | de1e603eb3 | |
Paweł Forysiuk | bf20c2b7ab | |
Paweł Forysiuk | fd5daab3e2 | |
Christian Dywan | f6595ea15e | |
Paweł Forysiuk | 06341b8ecf | |
Paweł Forysiuk | 57777d402f | |
André Stösel | 43d3a6b07e | |
André Stösel | 06b3a3a1ad | |
Efstathios Iosifidis | 373769cffd | |
Christian Dywan | 544dc08760 | |
Daniel P. Fore | 2e94548d70 | |
Mikalai Udodau | c4693a5084 | |
Sergio Marques | 8c39b1f341 | |
Efstathios Iosifidis | 8f015c6340 | |
Paweł Forysiuk | 78a317d42f | |
Paweł Forysiuk | 870ecca738 | |
Paweł Forysiuk | 21e7464226 | |
Mikalai Udodau | 1dcf70bd9d | |
Rafael Ferreira | 9b59026233 | |
Christian Dywan | 50f38f4b91 | |
Paweł Forysiuk | 6f3eb6fd62 | |
Paweł Forysiuk | 3fbcc93bac | |
prflr88 | 605953ebe6 | |
Yarema aka Knedlyk | b5cd9766f1 | |
Pjotr vertaalt | af47197ed5 | |
David Štancl | a544de436e | |
Boram Kim | a3a46be77f | |
Christian Dywan | b97140d3fd | |
Paweł Forysiuk | 5c26087e62 | |
Walter cheuk | cb7e28b11f | |
Christian Dywan | 35dfebd1c6 | |
Paweł Forysiuk | e5da45a40e | |
Christian Dywan | 2e17639201 | |
Paweł Forysiuk | 3c159386c8 | |
Christian Dywan | da4c27f673 | |
Christian Dywan | 60f93f157a | |
Mikalai Udodau | f145efaabc | |
Christian Dywan | 364345f57f | |
Paweł Forysiuk | db37fbcc74 | |
Christian Dywan | b45222111b | |
Christian Dywan | 75345d5047 | |
Kris Thomsen | 2fa42e0a33 | |
Mișu Moldovan | 90f22c7a28 | |
Gheyret Kenji | 457c89f829 | |
Piarres Beobide | 3d7b28567d | |
Piarres Beobide | 324263d3a6 | |
Christian Dywan | 9fb173ba69 | |
Christian Dywan | b925dbca33 | |
Christian Dywan | 4cd88d5746 | |
Yarema aka Knedlyk | eb0238328e | |
prflr88 | 9ab7b07377 | |
Pjotr vertaalt | 4ddab57690 | |
Mikalai Udodau | 6bf77b45d8 | |
Christian Dywan | fa3ab67cef | |
Paweł Forysiuk | 242a1baf0b | |
Paweł Forysiuk | 8cfebb7dcc | |
Christian Dywan | 3ecdcf0826 | |
Paweł Forysiuk | bf026bd905 | |
prflr88 | acd6ef7eac | |
mbouzada | 42ec8e205b | |
mbouzada | 81cca6c586 | |
mbouzada | 2ecb48893a | |
Mikalai Udodau | 290a53ab6d | |
Ivica Kolić | 43303dffbf | |
Mikalai Udodau | 270b57deac | |
David Štancl | 5d7aae4942 | |
Sergio Marques | ea89eb4ff7 | |
Christian Dywan | 21387841d2 | |
Masato Hashimoto | 6c0e9c43f6 | |
Boram Kim | a87f881149 | |
Boram Kim | 2bdd3be8ed | |
Christian Dywan | 0f525a99fd | |
Christian Dywan | dfec166691 | |
Christian Dywan | 96f616a237 | |
Christian Dywan | 5bed5082ed | |
Christian Dywan | 92e21d50ad | |
Enrico Tröger | 7f91e0985f | |
Paweł Forysiuk | 1e6793330f | |
prflr88 | 917b62e91b | |
Yarema aka Knedlyk | 0f98a0579d | |
Piotr Sokół | 5d03d030f3 | |
Piotr Sokół | 1673f0218f | |
Sergio Marques | c71aae37a8 | |
David Štancl | daebca32c0 | |
Gheyret Kenji | 3e38c0bb69 | |
Gheyret Kenji | 381ae720ed | |
Paweł Forysiuk | de4ea9b3bf | |
Paweł Forysiuk | 75d7a7024c | |
Christian Dywan | 16a0f666da | |
Christian Dywan | 6809231e54 | |
Mikalai Udodau | 94a997a289 | |
Pjotr vertaalt | 29fdd92fe1 | |
Paweł Forysiuk | cc0d81345b | |
Christian Dywan | 21d95c62f4 | |
Paweł Forysiuk | d95513226d | |
Stéphane Marguet | dce8096593 | |
Christian Dywan | 5425f1c3ad | |
Yarema aka Knedlyk | e02a90d844 | |
Sergio Marques | 04417c37c0 | |
Christian Dywan | f82a06afa5 | |
Christian Dywan | d49d314c0b | |
Christian Dywan | 2adb54ae8d | |
prflr88 | f74a210c48 | |
David Štancl | 21c8fb6d84 | |
David Štancl | 00db3195a8 | |
Rafael Ferreira | 0ed991b170 | |
Yarema aka Knedlyk | f67822736f | |
Yarema aka Knedlyk | 100f45a9db | |
Masato Hashimoto | 4eef6a4534 | |
Boram Kim | 2ee0065e34 | |
Pjotr vertaalt | e6ee98b8db | |
Pjotr vertaalt | 8e1b6d23c2 | |
Sergio Marques | da0ecd928e | |
Christian Dywan | 1ea3c81643 | |
Christian Dywan | 3ec314c7f8 | |
Christian Dywan | 6597f1f0b4 | |
Paweł Forysiuk | 6b1abeed69 | |
André Stösel | 7461925615 | |
Christian Dywan | 2cf8d9323e | |
Christian Dywan | d057ab4ddb | |
Christian Dywan | 4daaa98232 | |
Paweł Forysiuk | ae18206f7b | |
Christian Dywan | 91befb0ccc | |
Christian Dywan | b8b0bc341d | |
Christian Dywan | b7f438589f | |
Christian Dywan | 27f5cbfb25 | |
Christian Dywan | 218a6d0b2e | |
Christian Dywan | 2c77e2d1dd | |
Christian Dywan | 5998b6b0ea | |
Boram Kim | d8de8285ef | |
Sergio Marques | 03045fdf53 | |
Gheyret Kenji | 32da4d8f0c | |
Christian Dywan | 7c5410468f | |
Christian Dywan | 31fe130f87 | |
Gheyret Kenji | d549cfd203 | |
Christian Dywan | 3d14faf9be | |
Christian Dywan | 3259ab1be2 | |
Christian Dywan | 7eb4aa78aa | |
André Stösel | 7bcc270b05 | |
Christian Dywan | 760f4895a3 | |
Sergio Marques | 2f2b33abee | |
Christian Dywan | 65844ecf4c | |
Cheng-Chia Tseng | 96ad359d34 | |
Christian Dywan | 05d58f8287 | |
Christian Dywan | c096b46ff3 | |
Christian Dywan | 301bb89dd3 | |
Christian Dywan | 19f291d2be | |
Christian Dywan | ed2a7fea6f | |
Masato Hashimoto | 20d70d2ac7 | |
Cheng-Chia Tseng | 8c85d0f08c | |
Ivica Kolić | 4995e6fd6f | |
Christian Dywan | 4eb8553012 | |
Christian Dywan | 015c6e8428 | |
Christian Dywan | 83609a1a88 | |
Sergio Marques | 377a01948f | |
Christian Dywan | 8c54bd5d38 | |
Christian Dywan | 7d293b5c19 | |
Christian Dywan | 9ac0175899 | |
Christian Dywan | 3627c75e0b | |
Christian Dywan | 49957c95d1 | |
Christian Dywan | 81543161df | |
Piotr Sokół | e28ccf12ac | |
Christian Dywan | 649d079b04 | |
Henrique P. Machado | 612d22bbe3 | |
Christian Dywan | d2ebd4797d | |
Christian Dywan | c13da3b1b3 | |
Christian Dywan | 00ca0c4687 | |
Paweł Forysiuk | 23f9fa606a | |
Paweł Forysiuk | 470b666d6c | |
Johannes Sasongko | cd377bb7a8 | |
Christian Dywan | 93ef102c23 | |
Christian Dywan | 9ca795eec2 | |
Christian Dywan | 125bec6974 | |
Christian Dywan | 68a4ed6c99 | |
Christian Dywan | d260e71a23 | |
Niels Avonds | 6f47ae75fc | |
prflr88 | 28c5af1458 | |
Christian Dywan | c236e4da9e | |
Paweł Forysiuk | 33cede91a7 | |
Christian Dywan | 7a6bc50d0a | |
Christian Dywan | 7f7668048e | |
Cheng-Chia Tseng | 831a185621 | |
Gheyret Kenji | 846853f2db | |
Christian Dywan | 0dcf146b1f | |
Christian Dywan | d089634f6c | |
Christian Dywan | 41dda877ba | |
Christian Dywan | 6a4a506f24 | |
Christian Dywan | 3bdf2e7b73 | |
Christian Dywan | 57397ee229 | |
Christian Dywan | c4791e4a9a | |
Christian Dywan | f9005c63a7 | |
Christian Dywan | a0b2020550 | |
Christian Dywan | 4073c14546 | |
Christian Dywan | 0c201ca2b8 | |
Christian Dywan | 8ad44b86c3 | |
Masato Hashimoto | 184c1133e6 | |
David Štancl | 1d366e4913 | |
Piotr Sokół | ec0591ab8b | |
Sergio Marques | fcaba281fc | |
Andhika Padmawan | 043e786572 | |
Yarema aka Knedlyk | 6e466f3083 | |
Pjotr vertaalt | 14dd9c645d | |
Gheyret Kenji | e4c1e6ec7f | |
Christian Dywan | 75657d1fb4 | |
Paweł Forysiuk | db30c9a3d7 | |
Gheyret Kenji | 8679a5b19e | |
Christian Dywan | 6411603058 | |
Christian Dywan | 66a47613b0 | |
Christian Dywan | d319d40416 | |
Joe Nahmias | 21b643c825 | |
Joe Nahmias | e1fe41f3d7 | |
Christian Dywan | e8cbe34aeb | |
Christian Dywan | 120f7440f6 | |
Ivica Kolić | 74d711d2bd | |
Yarema aka Knedlyk | f598f91208 | |
Christian Dywan | f1db28a6ce | |
Christian Dywan | 64d9533f7b | |
Christian Dywan | ec2a7446e4 | |
Christian Dywan | f9d32072f4 | |
Christian Dywan | d5bf30ec03 | |
Christian Dywan | 708d74038f | |
Johannes Lips | 225e13c06b | |
Christian Dywan | ef4ee2f634 | |
Christian Dywan | 4e51fa1f00 | |
Christian Dywan | 264582f557 | |
Christian Dywan | aa1ffbf1d0 | |
Paweł Forysiuk | 262ded5222 | |
Boram Kim | 103664a8f0 | |
Sergio Marques | 7eac618c5b | |
Andhika Padmawan | 3e80912a03 | |
Johannes Lips | c3a7e53c0c | |
prflr88 | 616fc49048 | |
prflr88 | 0592f19446 | |
prflr88 | 1be88cee24 | |
prflr88 | b6081086bd | |
Rafael Ferreira | f44a09d6ad | |
Pjotr vertaalt | 5e5f68c8b3 | |
David Štancl | 36f451fd97 | |
Ivica Kolić | 860f85eeaa | |
Daniel P. Fore | 2ac581519c | |
Daniel P. Fore | 6cdc67a21e | |
Daniel P. Fore | fd7171298d | |
Christian Dywan | 8dccae9303 | |
Christian Dywan | d100604bba | |
Paweł Forysiuk | 627f367837 | |
Christian Dywan | 8ddc7ac787 | |
David Štancl | 611ca5b43d | |
Pjotr vertaalt | 46ed599c19 | |
Christian Dywan | a6fd514030 | |
Christian Dywan | b18667220c | |
Christian Dywan | 2cec07a6ea | |
Christian Dywan | 6a58d790b8 | |
Christian Dywan | 82741b139b | |
Christian Dywan | d455382a22 | |
Christian Dywan | 959fc712bd | |
Christian Dywan | ebd0ef2a46 | |
Christian Dywan | 3effb9a4ce | |
Paweł Forysiuk | fb00824541 | |
Paweł Forysiuk | a15d4009c2 | |
David Štancl | 12708f535c | |
Andhika Padmawan | 5ad8d5b85a | |
Yarema aka Knedlyk | e62894c3ed | |
Christian Dywan | e840a52a0e | |
Pjotr vertaalt | ab7358c460 | |
Christian Dywan | 50fea06389 | |
Christian Dywan | 448905015c | |
David Štancl | 0ece556d7a | |
Cristian Marchi | 28aefc59ec | |
Yarema aka Knedlyk | 5b8b2f4b28 | |
Pjotr vertaalt | b295462e06 | |
Oliver Hanraths | f840f0508c | |
Ivica Kolić | bc37926516 | |
Sergio Marques | 2496ae13e1 | |
Pjotr vertaalt | ddd7a887e2 | |
Yarema aka Knedlyk | d40b3ed233 | |
Andhika Padmawan | 3a2afa8d65 | |
Christian Dywan | aa51909f69 | |
Ivica Kolić | cb0d99484e | |
David Štancl | af67397456 | |
Pjotr vertaalt | 803a8451b3 | |
Sergio Marques | a96d21213f | |
André Stösel | cef295aae9 | |
André Stösel | 0ecfd696ba | |
André Stösel | 8e3d770e09 | |
André Stösel | eafbc37f0b | |
Christian Dywan | bc3ce47d7d | |
Paweł Forysiuk | fa364f5e71 | |
Paweł Forysiuk | b9b6f512ce | |
Paweł Forysiuk | 0b14449f68 | |
Christian Dywan | 4a1e547cdb | |
Christian Dywan | f71ebb53a9 | |
Мирослав Николић | 9650dd3779 | |
Piarres Beobide | aef1d06ffc | |
Xavier Devlamynck | 290c424bb5 | |
Xavier Devlamynck | 5f8f6ad0a4 | |
Xavier Devlamynck | f1e7036406 | |
Ardjuna | 5b40b6d238 | |
André Stösel | f38715efb2 | |
Christian Dywan | 25d8b8ddfc | |
Christian Dywan | c6f81c62e0 | |
Christian Dywan | 4a4887b511 | |
Boram Kim | af315513a8 | |
Gheyret Kenji | 0fc322f393 | |
Per Kongstad | 066d592c9f | |
David Štancl | fdc6151ac3 | |
Christian Dywan | a0a0325db4 | |
Christian Dywan | 85153f3b49 | |
Paweł Forysiuk | cece70cc68 | |
Christian Dywan | 117b057edc | |
Mișu Moldovan | 8f0950bc5a | |
Yarema aka Knedlyk | 80572b0480 | |
Sergio Marques | 982687646e | |
Cristian Marchi | a131388af1 | |
Masato Hashimoto | 11bedd68d5 | |
Pjotr vertaalt | 6934d8dafd | |
Christian Dywan | 01541da48f | |
Paweł Forysiuk | b854931cfc | |
Yarema aka Knedlyk | d0ca6467cd | |
David Štancl | 96843dadbf | |
Christian Dywan | 94f729f6b3 | |
Paweł Forysiuk | 7a172fff27 | |
Paweł Forysiuk | 5cd78ae297 | |
Boram Kim | 7fad1fedf7 | |
Boram Kim | 41fcbcd4a1 | |
Boram Kim | 7dd4b5c88a | |
Pjotr vertaalt | f7a7f06b84 | |
محمد الحرقان | e6d75db8d5 | |
محمد الحرقان | dda3058776 | |
Christian Dywan | 650efa2aea | |
Christian Dywan | 9ee6612f62 | |
Sergio Marques | be0dc79448 | |
Christian Dywan | fe72235e83 | |
Christian Dywan | 9fe40ad850 | |
Paweł Forysiuk | 2c89501bf4 | |
Saïd Bouras | e6e6fe4363 | |
Masato Hashimoto | 6dda0afa77 | |
玉堂 白鹤 | bcff2fb07b | |
玉堂 白鹤 | e9f8a7efd6 | |
Yves-Alexis Perez | 13dcb271ea | |
Yves-Alexis Perez | 9b1cba045f | |
Yves-Alexis Perez | d26b1fb745 | |
Sergio Marques | 218255bd95 | |
Tomáš Vadina | 0ec2d92573 | |
Piotr Sokół | e549a6fb6c | |
Cristian Marchi | a21ebb3b74 | |
Christian Dywan | d139f1bac8 | |
Christian Dywan | db2869f0a2 | |
Christian Dywan | 2429c10752 | |
Christian Dywan | 4fb6292bb4 | |
Christian Dywan | 81d2567226 | |
Christian Dywan | 8ba3053b41 | |
Pjotr vertaalt | 3d720c5303 | |
David Štancl | 369261a299 | |
Christian Dywan | cd9bb96c44 | |
Christian Dywan | cd238fa46e | |
Alexander Strasser | f5dd1f9ab5 | |
Ivica Kolić | 109ed3cd92 | |
Sergio García | b4d9cd7acc | |
Yarema aka Knedlyk | 678ef8a5c6 | |
Christian Dywan | fb6b01759d | |
André Stösel | 184a664731 | |
Ivica Kolić | 564ac17d73 | |
Christian Dywan | 654950f254 | |
Christian Dywan | 23d51753fd | |
Christian Dywan | 89bae74a32 | |
Christian Dywan | cf1321fe21 | |
Christian Dywan | 94c6fca20f | |
Ivica Kolić | cb40b36c0e | |
Pjotr vertaalt | a230b497b8 | |
Per Kongstad | 1ad1517368 | |
Christian Dywan | 32a480e80c | |
Vincent Cappe | cb8b27f14e | |
Vincent Cappe | 986a7acad6 | |
Vincent Cappe | 45ac40d614 | |
André Stösel | 66abde2db9 | |
Christian Dywan | bc967c5563 | |
Christian Dywan | b29e1278f9 | |
Christian Dywan | 5b4759c045 | |
Christian Dywan | e3e15973cc | |
Yves-Alexis Perez | ee57ca1056 | |
Asier Iturralde Sarasola | c8106ee0ec | |
Andrei Zakharevich | 2e498992df | |
Andrei Zakharevich | b91182cb30 | |
Leandro Regueiro | 5319ce19a3 | |
mbouzada | 374aa30390 | |
Roger Pueyo Centelles | 317f32fd89 | |
Sergio García | 2d5762dcaf | |
Sergio García | 80a6fd3a8f | |
Chipong Luo | b09446e0f5 | |
Jakob Kramer | 1ba786edf1 | |
Masato Hashimoto | c71a531f85 | |
Ivica Kolić | 63039722f2 | |
Boram Kim | 832afc13da | |
Yarema aka Knedlyk | 76d6d8fb85 | |
David Štancl | 2e1da00ab4 | |
Pjotr Anon | 48f28a7081 | |
Tomáš Vadina | 934ba363c5 | |
Jeff Bailes | f567143e29 | |
Per Kongstad | 6748db48f2 | |
Sergio Marques | dc225e6ec0 | |
Masato Hashimoto | 8d08e47746 | |
Cristian Marchi | de5eb758d2 | |
Algimantas Margevičius | da52b65fea | |
Chipong Luo | a0b614f9ce | |
Christian Dywan | 1ce2a57f4b | |
Christian Dywan | e29af0b634 | |
Christian Dywan | 1a5f96013d | |
Gabor Kelemen | 6bcf3d9912 | |
Chipong Luo | 1f2f7ca05b | |
Chipong Luo | 81a0fa1a48 | |
Mario Blättermann | 9fc17a11b8 | |
Jeff Bailes | 81c942e082 | |
Efstathios Iosifidis | a61bc0bca9 | |
Sergio García | 4d2836f858 | |
Yves-Alexis Perez | fd5d3ee02c | |
Martin Natano | 7e04c76bce | |
Martin Natano | 0b8a080695 | |
Martin Natano | 6cbf8031bf | |
Martin Natano | d2059fcec1 | |
Peter Hatina | 410eabea40 | |
Christian Dywan | c7c172f7ff | |
André Stösel | fc7e30f516 | |
Paweł Forysiuk | 2a540a0878 | |
Yves-Alexis Perez | a489245d13 | |
Yves-Alexis Perez | d80c050119 | |
Christian Dywan | 21c047a9b3 | |
Christian Dywan | e88b69be02 | |
Yves-Alexis Perez | 73c6fc5068 | |
Yves-Alexis Perez | da4f15e9bb | |
Masato Hashimoto | c75861ca5f | |
Paweł Forysiuk | 182268a82b | |
Iliyas Jorio | 57d2362a8d | |
André Stösel | 3f795a62cb | |
André Stösel | da5f257314 | |
Algimantas Margevičius | 53b9923108 | |
Christian Dywan | a006013cb4 | |
André Stösel | 8d0d2554ca | |
André Stösel | 08d890e20e | |
Masato Hashimoto | ee4fb4f7ef | |
André Miranda | f7d0e29c41 | |
Vincent Cappe | 3428fbb586 | |
Christian Dywan | e5a793c9e7 | |
Christian Dywan | 13b7e0114f | |
Christian Dywan | e6240e0ee4 | |
Christian Dywan | 2d9f3bbfcf | |
André Stösel | 7400114eac | |
Martin Natano | afd6b652c9 | |
Christian Dywan | 12d49e36c2 | |
Paweł Forysiuk | 89dbbcc1b0 | |
Christian Dywan | f76d538564 | |
Martin Natano | e0c021de3d | |
Leandro Regueiro | 3d00303230 | |
Per Kongstad | acfe263ce1 | |
Paweł Forysiuk | 3a833296b0 | |
Paweł Forysiuk | 3d4ee81ee4 | |
Christian Dywan | 2d921d4416 | |
Paweł Forysiuk | 24a50fbb78 | |
Christian Dywan | 461c3ad440 | |
Christian Dywan | f62964264e | |
Paweł Forysiuk | a01c0fd224 | |
André Stösel | 2377ee3c94 | |
Christian Dywan | c4d1a96ca4 | |
André Stösel | b5d5c17396 | |
André Stösel | 8bba8f9aad | |
André Stösel | d0ef9c6575 | |
Christian Dywan | a32cc0908e | |
David Štancl | f8ab9eaec0 | |
Yaron Shahrabani | b272a2cdd5 | |
Yaron Shahrabani | d9318f9ee5 | |
Christian Dywan | 4d311a9d4b | |
Christian Dywan | cbec9bcb74 | |
Christian Dywan | d7aafda6db | |
Christian Dywan | 1f56e0af6f | |
Per Kongstad | 2d07cbfe45 | |
Ivica Kolić | f9d56a9a98 | |
Carles Muñoz Gorriz | dde5014956 | |
Carles Muñoz Gorriz | 9790d0016f | |
Christian Dywan | b838023289 | |
Christian Dywan | 79942f24aa | |
Alexander Butenko | 3e0dc32017 | |
Christian Dywan | 4c4c849441 | |
André Stösel | a6f9bea939 | |
Benoit THIBAUD | 63ac08c6a3 | |
Saïd Bouras | eccc0eb5d8 | |
André Stösel | 1de28a8a7a | |
André Stösel | ebf2c2d1d9 | |
Yaron Shahrabani | dc19951a21 | |
Christian Dywan | 19f6fefe9b | |
André Stösel | f7d85602f8 | |
Christian Dywan | 5cb1c04481 | |
Olivier Duchateau | 7789bafc68 | |
Paweł Forysiuk | 76be3b9aea | |
Kamil Polczak | a371ef99ef | |
Kamil Polczak | 70e0223212 | |
Utku Berberoğlu | 7e6dcd5df0 | |
André Stösel | a695a91410 | |
Peter Hatina | 357187e264 | |
André Stösel | 90eaea3dca | |
Christian Dywan | 532335702a | |
Christian Dywan | ae7a09a087 | |
Cheng-Chia Tseng | 9751a60dbc | |
Christian Dywan | 70a894a9fc | |
André Stösel | 0b16c9c95c | |
Christian Dywan | d98edca5f2 | |
Christian Dywan | edc88b7b47 | |
Christian Dywan | 5aa526d106 | |
Christian Dywan | 7e64370a8e | |
Christian Dywan | e75b814432 | |
Christian Dywan | f3af1983ed | |
Christian Dywan | a3d8a5aa94 | |
André Stösel | ee8824b93b | |
Andhika Padmawan | bf2ca1c370 | |
Sergio Marques | e18a39d88c | |
André Stösel | f92fa1a33f | |
André Stösel | d93c96daf3 | |
André Stösel | f4697742af | |
Christian Dywan | 2fa5059cc4 | |
Boram Kim | 7d4cdfe462 | |
Pjotr Anon | 50c091f43d | |
Yves-Alexis Perez | 23b89cca6b | |
Algimantas Margevičius | 37c0e0270f | |
Yarema aka Knedlyk | efa634d939 | |
Lucas Baudin | 9f6c4d3e03 | |
Christian Dywan | 7d61f1b897 | |
Christian Dywan | 09c041f740 | |
Christian Dywan | 48368e9951 | |
Cristian Marchi | 4391693cdd | |
Chipong Luo | 4d9eb6cfc7 | |
Roman K | c1238bd82b | |
Tomáš Vadina | 9c2a17b4a5 | |
Christian Dywan | 5aebcd7b30 | |
Christian Dywan | d94da1f69d | |
Christian Dywan | 2612267e4d | |
Christian Dywan | 2c9f219b7a | |
Paweł Forysiuk | 1edfd88d2f | |
Christian Dywan | ecbc8d0772 | |
Sergio Marques | 3184b5226e | |
Andhika Padmawan | 7b2c87a573 | |
Christian Dywan | 5e2b7fdca7 | |
Christian Dywan | c6bdd62f67 | |
Christian Dywan | 7066679bcf | |
Christian Dywan | 0cd1c158d7 | |
Masato Hashimoto | 9742511800 | |
Johannes Lips | 9b0f7203ae | |
Johannes Lips | 1b64505d9d | |
Johannes Lips | 3f1c59ac82 | |
Algimantas Margevičius | 8446a0a426 | |
Cheng-Chia Tseng | 09fb0e2fd1 | |
Mișu Moldovan | 91a784574a | |
Cristian Marchi | e4bc034389 | |
Xavier Devlamynck | e4a2f732c2 | |
André Stösel | 85c2f4a8e1 | |
Yves-Alexis Perez | b104b685da | |
Yves-Alexis Perez | ca25b39213 | |
Yves-Alexis Perez | 794c71685c | |
Yves-Alexis Perez | bf2d83aba2 | |
Yves-Alexis Perez | 6ae8631809 | |
Christian Dywan | 5588a05c8a | |
Christian Dywan | 8c8f985a5c | |
Slavko | 472cbfa5b1 | |
Christian Dywan | 8b78ae5491 | |
Christian Dywan | 7940a02ae8 | |
Seong-ho Cho | 11aa4f437a | |
Boram Kim | d47806bc12 | |
Algimantas Margevičius | 5e0ac8ebbf | |
Christian Dywan | 323177c429 | |
Christian Dywan | f9aa8aed9c | |
Christian Dywan | 6e6faabad9 | |
Christian Dywan | 6c57f7db42 | |
Christian Dywan | 537d002a6f | |
Christian Dywan | f3a5d49434 | |
Olexandr Nesterenko | 1309a77aae | |
Olexandr Nesterenko | 0c1716447b | |
Olexandr Nesterenko | 81cdb802fc | |
Michael Moroni | 3757852ae7 | |
Pjotr Anon | c7dfd851b0 | |
David Štancl | 1145c7417e | |
Chipong Luo | 7faa9d54c4 | |
André Stösel | 2837494ade | |
Christian Dywan | fa22841ec9 | |
Christian Dywan | a83cea4964 | |
Christian Dywan | 1e7ee7db5c | |
Christian Dywan | 4f180216a1 | |
Christian Dywan | 66d4e4c531 | |
Christian Dywan | bf07220bc3 | |
Christian Dywan | ba51341786 | |
Christian Dywan | 4beffc57e9 | |
Christian Dywan | 2bc867054a | |
Tomáš Vadina | c669cef230 | |
Utku Berberoğlu | 782271d47c | |
Yarema aka Knedlyk | f060b6ed1f | |
Masato Hashimoto | 387b782760 | |
Christian Dywan | 7361a80e24 | |
Christian Dywan | 7e61fce9ca | |
Christian Dywan | df8284f650 | |
Christian Dywan | cbe84b6820 | |
Christian Dywan | 079403a806 | |
Christian Dywan | 70b85bf600 | |
Paweł Forysiuk | 271cdf670b | |
Paweł Forysiuk | 17cccfb672 | |
Paweł Forysiuk | 74bf490880 | |
Paweł Forysiuk | f3de5b1112 | |
Paweł Forysiuk | 4fa5bcf721 | |
Michael Moroni | 24884ccafb | |
Michael Moroni | 82991c695c | |
Michael Moroni | 3c3836f485 | |
Sergio Marques | 970d50726d | |
David Štancl | c19c5bdee8 | |
Chipong Luo | 63f2690265 | |
Christian Dywan | 61af413407 | |
Christian Dywan | 7c7be5644d | |
Christian Dywan | 6fd666aa9f | |
Christian Dywan | 4c142e7688 | |
Christian Dywan | 307c79274d | |
Christian Dywan | d3a60802ac | |
Christian Dywan | 81526df6d6 | |
Boram Kim | 95a7e7f3b8 | |
Pjotr Anon | d23ad7374a | |
Andhika Padmawan | eefc27b2b2 | |
Cristian Marchi | 85948e8c19 | |
Algimantas Margevičius | 4d96182f73 | |
Tomasz Szatkowski | 127595f527 | |
Christian Dywan | 1488301535 | |
Christian Dywan | 18b6b48ef5 | |
Christian Dywan | 9275a6cd24 | |
Christian Dywan | 569b8e4779 | |
Dmitry Nikitin | a2ebb7e671 | |
Dmitry Nikitin | 198aaeffa1 | |
Michal Várady | 799d983eac | |
Michal Várady | b0c36f318b | |
Christian Dywan | 77d095f6ef | |
Paweł Forysiuk | f25b677d0c | |
Christian Dywan | 973e481068 | |
Christian Dywan | 403d17400b | |
Christian Dywan | bcc6711f27 | |
Christian Dywan | 8ad470caf5 | |
Christian Dywan | 90ee1384a7 | |
Christian Dywan | 5c0255f7cb | |
Christian Dywan | 5176b38120 | |
Christian Dywan | ffb86ce7ff | |
Christian Dywan | f586c3004b | |
Christian Dywan | 599de9cb74 | |
Michal Várady | 51e3e8e495 | |
Christian Dywan | 55c6dd38d0 | |
Christian Dywan | 7af5019d86 | |
Christian Dywan | 79b29a9362 | |
Christian Dywan | f3a4bd4b6a | |
Christian Dywan | a064a5f120 | |
Christian Dywan | 8960da4c2f | |
Christian Dywan | af9ec62b25 | |
Christian Dywan | 5643728994 | |
Christian Dywan | b20a1e7efd | |
Christian Dywan | f549824b66 | |
Christian Dywan | bbbfa0d677 | |
Christian Dywan | d2fe0791e1 | |
Alexander Butenko | c6b15ff4dc | |
Christian Dywan | 63d7df5a0a | |
Christian Dywan | d2aa1919aa | |
Vincent Cappe | 62f0ef746c | |
Alexander Butenko | 69c319d62a | |
Alexander Butenko | 29d6de3c6e | |
Alexander Butenko | 69f7e176ab | |
Olexandr Nesterenko | cd4928ebd7 | |
Cristian Marchi | 57afee2b9b | |
Cristian Marchi | 05427d6967 | |
Per Kongstad | 4e2f69cc40 | |
Andhika Padmawan | 71c2a52cb7 | |
Sergio Marques | a517a02d02 | |
Thomas Schütz | 99cd9b00af | |
Thomas Schütz | 1ce879e6f6 | |
Chris Leick | 83143c4e5a | |
Aleksandr Ponomarenko | a4f2854217 | |
Aleksandr Ponomarenko | f1603202ac | |
Algimantas Margevičius | e5ffa134a2 | |
David Štancl | f9af2ae05d | |
Yves-Alexis Perez | 9050091b93 | |
Yves-Alexis Perez | fd63447c9c | |
Christian Dywan | 94236e1a9f | |
Christian Dywan | cc7cf39150 | |
Masato Hashimoto | e268ffecfc | |
Pjotr Anon | 51462b0748 | |
Cristian Marchi | 35b11cad17 | |
Tomáš Vadina | c05f2a86b4 | |
Boram Kim | e20ec3fb74 | |
Chipong Luo | 961ed90a01 | |
Paweł Forysiuk | b68b092c51 | |
Paweł Forysiuk | d152163957 | |
Paweł Forysiuk | 523afa1014 | |
Alexander Butenko | 7bf5005617 | |
Christian Dywan | 669167eb9e | |
Christian Dywan | 93bec3142f | |
Christian Dywan | 6c87ccc3b3 | |
Christian Dywan | 3aa37f7953 | |
Christian Dywan | cad539dfed | |
Christian Dywan | 62ed57bde3 | |
Alexander Butenko | 1e941210db | |
Christian Dywan | 66484a7e02 | |
Alexander Butenko | 5e052422f5 | |
Christian Dywan | 8b766ca2a8 | |
Paweł Forysiuk | 50a4cda60c | |
Christian Dywan | 15fd840a9d | |
Christian Dywan | f1289721b6 | |
Alexander Butenko | 01f6279a92 | |
Paweł Forysiuk | a1cb33c046 | |
Paweł Forysiuk | 63e68a63e3 | |
Paweł Forysiuk | 1d700e4ca4 | |
Paweł Forysiuk | e582924a99 | |
Paweł Forysiuk | 6ff166f3ba | |
Paweł Forysiuk | ef1928ad16 | |
Paweł Forysiuk | f387f9c29b | |
Paweł Forysiuk | 93b352aa34 | |
Christian Dywan | 5bb1c5025f | |
Christian Dywan | b6f86b0ca6 | |
Christian Dywan | 9c323ff149 | |
Per Kongstad | f045fb2a5b | |
Chipong Luo | 4479a23319 | |
Chipong Luo | a5c29d05f2 | |
Paul Seyfert | 974a09ff6a | |
Tomáš Vadina | 515123c0c7 | |
Chipong Luo | 9a1113dc42 | |
Masato Hashimoto | cc5566105d | |
Cristian Marchi | e264342ea3 | |
Cristian Marchi | 52c4114639 | |
Algimantas Margevičius | 15b0cc2f23 | |
Algimantas Margevičius | 57e3264d66 | |
Algimantas Margevičius | 1f2fce9fd5 | |
Yarema aka Knedlyk | dbc0eac7dc | |
Algimantas Margevičius | ca56282b75 | |
Sergio Marques | 32bd432e2d | |
Boram Kim | 49f945b421 | |
David Štancl | 3ab5811c07 | |
محمد الحرقان | 8e997590bd | |
Chipong Luo | eecfd42ca4 | |
Chipong Luo | 53d27052aa | |
Christian Dywan | f0c4b3d538 | |
Christian Dywan | e16e1d14d4 | |
Cheng-Chia Tseng | fa12a3fc52 | |
Algimantas Margevičius | 955cf0b132 | |
Andhika Padmawan | 0a96a24fa3 | |
Pjotr Anon | 062c19d0d5 | |
Chipong Luo | 43bbbbd7f3 | |
Chipong Luo | 0effcd3b19 | |
Chipong Luo | 1647ff9638 | |
Christian Dywan | edcd8e1ae4 | |
Christian Dywan | fe1b21a73f | |
Christian Dywan | ce527689c6 | |
Christian Dywan | f1e168b569 | |
Christian Dywan | 32eb583cb5 | |
Chipong Luo | d3863a0abf | |
Christian Dywan | 3f8784213d | |
Christian Dywan | e4475b4c49 | |
Christian Dywan | 3464afd167 | |
Christian Dywan | ab720a177d | |
Christian Dywan | fb44d46db0 | |
Tomáš Vadina | 7fd1c2e5e1 | |
Andres Sanchez | 0bd341496b | |
Per Kongstad | 9ef72e562f | |
Christian Dywan | 1ef7182e95 | |
Christian Dywan | 26485b9be2 | |
Christian Dywan | 41a0ab4bc7 | |
Sergio Marques | 82f13bab12 | |
Boram Kim | 0ae34774a6 | |
Gabor Kelemen | 381a78dc08 | |
David Štancl | ce7c34d724 | |
Carles Muñoz Gorriz | d0a5c58ece | |
Yarema aka Knedlyk | 7ff89970b2 | |
Pjotr Anon | fe131576a1 | |
Cheng-Chia Tseng | 590ecc9c3b | |
Gabor Kelemen | 1b086f5e87 | |
Chipong Luo | 9d900815f9 | |
Chipong Luo | 9f044ee5e4 | |
Christian Dywan | fb2e4eea77 | |
Peter Hatina | c0e0bee467 | |
Christian Dywan | ff95e17f6f | |
Peter Hatina | b045c01d06 | |
Peter Hatina | c9f982633d | |
Chipong Luo | 8eaada95d0 | |
Yarema aka Knedlyk | dc1a39f93d | |
Sergio Marques | d25cc1b132 | |
Pjotr Anon | 055224a73e | |
Yaron Shahrabani | 713c7b5080 | |
Yaron Shahrabani | f500a36903 | |
Tomáš Vadina | 6385a32b99 | |
Tomáš Vadina | e791f3dce0 | |
David Štancl | 7fb7c27db3 | |
Christian Dywan | b20abf8a28 | |
Christian Dywan | 057bb5dc5a | |
Christian Dywan | 9236ffb4bb | |
Alexander Butenko | c3eb4e4403 | |
Alexander Butenko | 164f016924 | |
Yaron Shahrabani | 976eda9157 | |
Yaron Shahrabani | 1c6980ddda | |
Yaron Shahrabani | aede773fb7 | |
Paweł Forysiuk | 4600ea19e6 | |
Alexander Butenko | 74ae33e232 | |
Michał Olber | 274cf6f9d8 | |
Chipong Luo | 95c15f28e7 | |
Alexander Butenko | fd03ff56b4 | |
Alexander Butenko | 3d5d2f4766 | |
Alexander Butenko | 696b377b32 | |
Alexander Butenko | 835f808115 | |
Alexander Butenko | 729e960cd6 | |
Alexander Butenko | 3d774d2d09 | |
Alexander Butenko | 9445539c48 | |
Alexander Butenko | 43952508eb | |
Christian Dywan | bf4ddd3358 | |
Christian Dywan | 556546320b | |
Alexander Butenko | e61743db9c | |
Olexandr | a87321d01c | |
Henrique P. Machado | fb22998273 | |
Sergio Marques | 25498f30e2 | |
André Luiz Dias de Miranda | 519b51a85c | |
Cristian Marchi | e13a55981b | |
Tomáš Vadina | 6ed99e4e88 | |
Alexander Butenko | fe6acc509a | |
Alexander Butenko | b850dd3da2 | |
Christian Dywan | 1bff3b12a3 | |
Alexander Butenko | 20228cfdd6 | |
Paweł Forysiuk | 618fa82077 | |
Per Kongstad | 4de2048f85 | |
Boram Kim | 6f40fbc0a4 | |
Christian Dywan | 451cd1fbea | |
Pjotr Anon | 64d21c2120 | |
David Štancl | 2cc8beba41 | |
Thomas Schütz | fe0f451865 | |
Chipong Luo | 129da98bf5 | |
Christian Dywan | 57b093293a | |
Martin Robinson | 5396456ec2 | |
Christian Dywan | bf7cfa902c | |
Christian Dywan | c3efa0cd7b | |
Alexander Butenko | 3a2ad2d242 | |
Christian Dywan | 98c87e7ca9 | |
Christian Dywan | 81250720de | |
Christian Dywan | 5261fdcf87 | |
Christian Dywan | 6d68f52b8e | |
Christian Dywan | c242639558 | |
Tomáš Vadina | fad246350e | |
Tomáš Vadina | a14be44ce2 | |
Andres Sanchez | 05a14dc273 | |
Chipong Luo | 5fe2fc3a02 | |
Chipong Luo | aaa803d2b4 | |
Cristian Marchi | 9cbeffc696 | |
Masato Hashimoto | af2adeaf08 | |
Christian Dywan | 34c7d601c6 | |
Alexander Butenko | a87b4cd7d8 | |
Paweł Forysiuk | ee055334ce |
|
@ -1,16 +0,0 @@
|
|||
Makefile
|
||||
|
||||
.waf-*
|
||||
.lock-wscript
|
||||
_build_
|
||||
|
||||
po/.intltool-merge-cache
|
||||
po/LINGUAS
|
||||
po/POTFILES
|
||||
po/midori.pot
|
||||
po/stamp-it
|
||||
po/*.gmo
|
||||
|
||||
midori.desktop
|
||||
|
||||
packages.version
|
|
@ -0,0 +1,294 @@
|
|||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(VERSION 2.6)
|
||||
# Work-around a bug in the included FindGettext fixed with 2.8.8
|
||||
# See http://www.cmake.org/pipermail/cmake-commits/2012-February/012117.html
|
||||
if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_LESS "2.8.8")
|
||||
cmake_policy(SET CMP0002 OLD)
|
||||
endif ()
|
||||
project(midori C)
|
||||
add_definitions("-DPACKAGE_NAME=\"${CMAKE_PROJECT_NAME}\"")
|
||||
add_definitions("-DPACKAGE_BUGREPORT=\"https://bugs.launchpad.net/midori\"")
|
||||
|
||||
set(VERSION 0.5.11)
|
||||
add_definitions("-DMIDORI_VERSION_SUFFIX=\"${VERSION}\"")
|
||||
|
||||
string(REPLACE "." ";" VERSION_LIST ${VERSION})
|
||||
LIST(GET VERSION_LIST 0 MIDORI_MAJOR_VERSION)
|
||||
add_definitions("-DMIDORI_MAJOR_VERSION=${MIDORI_MAJOR_VERSION}")
|
||||
LIST(GET VERSION_LIST 1 MIDORI_MINOR_VERSION)
|
||||
add_definitions("-DMIDORI_MINOR_VERSION=${MIDORI_MINOR_VERSION}")
|
||||
LIST(GET VERSION_LIST 2 MIDORI_MICRO_VERSION)
|
||||
add_definitions("-DMIDORI_MICRO_VERSION=${MIDORI_MICRO_VERSION}")
|
||||
|
||||
execute_process(COMMAND "bzr" "revno"
|
||||
OUTPUT_VARIABLE REVISION
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (REVISION)
|
||||
set(VERSION "${VERSION}~r${REVISION}")
|
||||
# All warnings are errors in development builds
|
||||
set(VALAFLAGS ${VALAFLAGS} --fatal-warnings)
|
||||
set(CFLAGS "${CFLAGS}")
|
||||
endif ()
|
||||
add_definitions("-DPACKAGE_VERSION=\"${VERSION}\"")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
# Disallow building during install to avoid permission problems
|
||||
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
|
||||
|
||||
find_package(Vala REQUIRED)
|
||||
vala_require("0.16.0")
|
||||
set(VALAFLAGS ${VALAFLAGS}
|
||||
--enable-deprecated
|
||||
--debug
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
set(DATADIR ${CMAKE_INSTALL_FULL_DATADIR})
|
||||
add_definitions("-DMDATADIR=\"${DATADIR}\"")
|
||||
add_definitions("-DSYSCONFDIR=\"${CMAKE_INSTALL_FULL_SYSCONFDIR}\"")
|
||||
add_definitions("-DLIBDIR=\"${CMAKE_INSTALL_FULL_LIBDIR}\"")
|
||||
add_definitions("-DDOCDIR=\"${CMAKE_INSTALL_FULL_DOCDIR}\"")
|
||||
|
||||
add_definitions("-DENABLE_NLS=1")
|
||||
add_definitions("-DLOCALEDIR=\"${CMAKE_INSTALL_FULL_LOCALEDIR}\"")
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/config.h" "/* # generated file (stub) */")
|
||||
add_definitions("-DHAVE_CONFIG_H=1")
|
||||
|
||||
find_file (UNISTD unistd.h)
|
||||
if (UNISTD)
|
||||
add_definitions("-DHAVE_UNISTD_H")
|
||||
endif ()
|
||||
|
||||
if (UNIX)
|
||||
find_file (SIGNAL signal.h)
|
||||
if (SIGNAL)
|
||||
add_definitions("-DHAVE_SIGNAL_H")
|
||||
endif ()
|
||||
|
||||
find_file (EXEC_INFO execinfo.h)
|
||||
if (EXEC_INFO)
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_EXECINFO_H)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
find_library (X11 X11)
|
||||
if (X11)
|
||||
# Pass /usr/X11R6/include for OpenBSD
|
||||
find_file (SCRNSAVER X11/extensions/scrnsaver.h /usr/X11R6/include)
|
||||
find_library (XSS Xss /usr/lib/X11R6/lib)
|
||||
if (SCRNSAVER AND XSS)
|
||||
add_definitions("-DHAVE_X11_EXTENSIONS_SCRNSAVER_H")
|
||||
set(OPTS_LIBRARIES "${OPTS_LIBRARIES};${XSS};${X11}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_WIN32)
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_FREEBSD)
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "DragonFly")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_DRAGONFLY)
|
||||
set(DFLY 1)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
add_definitions("-DHAVE_OSX=1")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_OSX)
|
||||
else ()
|
||||
add_definitions("-DHAVE_OSX=0")
|
||||
endif ()
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(DEPS REQUIRED
|
||||
libxml-2.0>=2.6
|
||||
sqlite3>=3.6.19
|
||||
gmodule-2.0
|
||||
gio-2.0>=2.32.3
|
||||
libsoup-gnome-2.4>=2.37.1
|
||||
)
|
||||
add_definitions("-DHAVE_LIBXML")
|
||||
add_definitions("-DGIO_VERSION=\"${DEPS_gio-2.0_VERSION}\"")
|
||||
add_definitions("-DLIBSOUP_VERSION=\"${DEPS_libsoup-gnome-2.4_VERSION}\"")
|
||||
set(PKGS posix linux libxml-2.0 sqlite3 gmodule-2.0 gio-2.0 libsoup-2.4)
|
||||
if (${DEPS_libsoup-gnome-2.4_VERSION} VERSION_GREATER "2.40.0")
|
||||
# valac 0.16 didn't have the bindings yet
|
||||
# For consistency we need to ensure C code makes the same assumptions
|
||||
if (${VALA_VERSION} VERSION_GREATER "0.17.0")
|
||||
add_definitions("-DHAVE_LIBSOUP_2_40_0")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_LIBSOUP_2_40_0)
|
||||
endif ()
|
||||
endif ()
|
||||
if (${DEPS_libsoup-gnome-2.4_VERSION} VERSION_GREATER "2.48.0")
|
||||
add_definitions("-DHAVE_LIBSOUP_2_48_0")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_LIBSOUP_2_48_0)
|
||||
endif ()
|
||||
|
||||
if (${DEPS_gio-2.0_VERSION} VERSION_GREATER "2.40.0" OR WIN32)
|
||||
add_definitions("-DLIBNOTIFY_VERSION=\"No\"")
|
||||
else ()
|
||||
pkg_check_modules(NOTIFY REQUIRED libnotify)
|
||||
add_definitions("-DLIBNOTIFY_VERSION=\"${NOTIFY_VERSION}\"")
|
||||
add_definitions("-DHAVE_LIBNOTIFY")
|
||||
set(OPTS_INCLUDE_DIRS "${OPTS_INCLUDE_DIRS};${NOTIFY_INCLUDE_DIRS}")
|
||||
set(OPTS_LIBRARIES "${OPTS_LIBRARIES};${NOTIFY_LIBRARIES}")
|
||||
set(PKGS ${PKGS} libnotify)
|
||||
endif ()
|
||||
|
||||
option(USE_GTK3 "Use GTK+3" OFF)
|
||||
option(HALF_BRO_INCOM_WEBKIT2 "Serve as a guniea pig" OFF)
|
||||
option(USE_ZEITGEIST "Zeitgeist history integration" ON)
|
||||
option(USE_GRANITE "Fancy notebook and pop-overs" OFF)
|
||||
option(USE_APIDOCS "API documentation" OFF)
|
||||
option(USE_GIR "Generate GObject Introspection bindings" OFF)
|
||||
option(EXTRA_WARNINGS "Additional compiler warnings" OFF)
|
||||
|
||||
# GTK+3 is implied here, whether set or not
|
||||
if (USE_GRANITE OR HALF_BRO_INCOM_WEBKIT2)
|
||||
set(USE_GTK3 ON)
|
||||
endif ()
|
||||
|
||||
if (USE_GRANITE)
|
||||
pkg_check_modules(GRANITE granite>=0.2)
|
||||
set(OPTS_INCLUDE_DIRS "${OPTS_INCLUDE_DIRS};${GRANITE_INCLUDE_DIRS}")
|
||||
set(OPTS_LIBRARIES "${OPTS_LIBRARIES};${GRANITE_LIBRARIES}")
|
||||
add_definitions("-DHAVE_GRANITE")
|
||||
add_definitions("-DGRANITE_VERSION=\"${GRANITE_VERSION}\"")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_GRANITE)
|
||||
set(PKGS ${PKGS} granite)
|
||||
else ()
|
||||
add_definitions("-DGRANITE_VERSION=\"No\"")
|
||||
endif()
|
||||
|
||||
if (USE_ZEITGEIST)
|
||||
pkg_check_modules(ZEITGEIST zeitgeist-2.0>=0.3.14)
|
||||
set(OPTS_INCLUDE_DIRS "${OPTS_INCLUDE_DIRS};${ZEITGEIST_INCLUDE_DIRS}")
|
||||
set(OPTS_LIBRARIES "${OPTS_LIBRARIES};${ZEITGEIST_LIBRARIES}")
|
||||
add_definitions("-DHAVE_ZEITGEIST")
|
||||
set(PKGS ${PKGS} zeitgeist-2.0)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_definitions("-DGCR_VERSION=\"No\"")
|
||||
else ()
|
||||
if (USE_GTK3)
|
||||
pkg_check_modules(GCR REQUIRED gcr-3>=2.32)
|
||||
else ()
|
||||
pkg_check_modules(GCR REQUIRED gcr-base-3>=2.32)
|
||||
endif ()
|
||||
add_definitions("-DGCR_VERSION=\"${GCR_VERSION}\"")
|
||||
add_definitions("-DHAVE_GCR")
|
||||
set(OPTS_INCLUDE_DIRS ${OPTS_INCLUDE_DIRS} ${GCR_INCLUDE_DIRS})
|
||||
set(OPTS_LIBRARIES ${OPTS_LIBRARIES} ${GCR_LIBRARIES})
|
||||
endif ()
|
||||
|
||||
if (HALF_BRO_INCOM_WEBKIT2)
|
||||
pkg_check_modules(DEPS_GTK REQUIRED
|
||||
gtk+-3.0>=3.10.0
|
||||
webkit2gtk-4.0>=2.3.91
|
||||
)
|
||||
add_definitions("-DHAVE_WEBKIT2")
|
||||
add_definitions("-DGTK_VERSION=\"${DEPS_GTK_gtk+-3.0_VERSION}\"")
|
||||
add_definitions("-DWEBKIT_VERSION=\"${DEPS_GTK_webkit2gtk-4.0_VERSION}\"")
|
||||
set(PKGS ${PKGS} gtk+-3.0)
|
||||
# set(EXTRA_VAPIS ${EXTRA_VAPIS} "${CMAKE_SOURCE_DIR}/midori/webkit2gtk-web-extension-4.0.vapi")
|
||||
set(EXTRA_VAPIS ${EXTRA_VAPIS} "${CMAKE_SOURCE_DIR}/midori/webkit2gtk-4.0.vapi")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_GTK3)
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_WEBKIT2)
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_WEBKIT2_3_91)
|
||||
elseif (USE_GTK3)
|
||||
pkg_check_modules(DEPS_GTK REQUIRED
|
||||
gtk+-3.0>=3.10.0
|
||||
webkitgtk-3.0>=1.8.1
|
||||
javascriptcoregtk-3.0
|
||||
)
|
||||
add_definitions("-DGTK_VERSION=\"${DEPS_GTK_gtk+-3.0_VERSION}\"")
|
||||
add_definitions("-DWEBKIT_VERSION=\"${DEPS_GTK_webkitgtk-3.0_VERSION}\"")
|
||||
set(PKGS ${PKGS} gtk+-3.0)
|
||||
set(EXTRA_VAPIS ${EXTRA_VAPIS} "${CMAKE_SOURCE_DIR}/midori/webkitgtk-3.0.vapi")
|
||||
set(VALAFLAGS ${VALAFLAGS} -D HAVE_GTK3)
|
||||
else ()
|
||||
pkg_check_modules(DEPS_GTK REQUIRED
|
||||
gtk+-2.0>=2.24.0
|
||||
webkit-1.0>=1.8.1
|
||||
javascriptcoregtk-1.0
|
||||
)
|
||||
add_definitions("-DGTK_VERSION=\"${DEPS_GTK_gtk+-2.0_VERSION}\"")
|
||||
add_definitions("-DWEBKIT_VERSION=\"${DEPS_GTK_webkit-1.0_VERSION}\"")
|
||||
set(PKGS ${PKGS} gtk+-2.0)
|
||||
set(EXTRA_VAPIS ${EXTRA_VAPIS} "${CMAKE_SOURCE_DIR}/midori/webkitgtk-3.0.vapi")
|
||||
endif ()
|
||||
set(EXTRA_VAPIS ${EXTRA_VAPIS} "${CMAKE_SOURCE_DIR}/katze/katze.vapi")
|
||||
|
||||
# dh_translations detects this if there's no variable used
|
||||
set (GETTEXT_PACKAGE "midori")
|
||||
add_definitions("-DGETTEXT_PACKAGE=\"${GETTEXT_PACKAGE}\"")
|
||||
|
||||
set(CFLAGS "${CFLAGS} -Wall -Wundef -Wno-deprecated-declarations -g")
|
||||
|
||||
if (EXTRA_WARNINGS)
|
||||
LIST(APPEND EXTRA_CFLAGS_LIST
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
-Wno-missing-field-initializers
|
||||
-Wno-comment
|
||||
-Waggregate-return
|
||||
-Wredundant-decls
|
||||
-Wshadow -Wpointer-arith -Wcast-align
|
||||
-Winline -Wformat-security -fno-common
|
||||
-Winit-self -Wundef
|
||||
-Wnested-externs
|
||||
)
|
||||
string(REPLACE ";" " " EXTRA_CFLAGS "${EXTRA_CFLAGS_LIST}")
|
||||
set(CFLAGS "${CFLAGS} ${EXTRA_CFLAGS}")
|
||||
else ()
|
||||
if (REVISION)
|
||||
set(CFLAGS "${CFLAGS} -Werror")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# Explicitly add -fPIC for older toolchains
|
||||
set(VALA_CFLAGS "-g -fPIC")
|
||||
|
||||
# With compiler versions that can, enable exactly the non-spurious warnings
|
||||
# in Vala-generated C, otherwise disable warnings
|
||||
if ((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "5.0.0")
|
||||
OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "3.0.0"))
|
||||
set(VALA_CFLAGS "${VALA_CFLAGS} -Werror=implicit-function-declaration")
|
||||
set(VALA_CFLAGS "${VALA_CFLAGS} -Wno-incompatible-pointer-types")
|
||||
set(VALA_CFLAGS "${VALA_CFLAGS} -Wno-discarded-qualifiers")
|
||||
set(VALA_CFLAGS "${VALA_CFLAGS} -Wno-deprecated-declarations")
|
||||
else ()
|
||||
set(VALA_CFLAGS "${VALA_CFLAGS} -w")
|
||||
endif ()
|
||||
|
||||
set(LIBMIDORI "${CMAKE_PROJECT_NAME}-core")
|
||||
|
||||
# CMake provides no uninstall target by design
|
||||
add_custom_target (uninstall
|
||||
COMMAND "xargs" "rm" "-v" "<" "install_manifest.txt")
|
||||
|
||||
install(FILES AUTHORS COPYING ChangeLog EXPAT README DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
|
||||
add_subdirectory (midori)
|
||||
add_subdirectory (extensions)
|
||||
enable_testing()
|
||||
add_subdirectory (tests)
|
||||
add_subdirectory (po)
|
||||
add_subdirectory (icons)
|
||||
add_subdirectory (data)
|
||||
add_subdirectory (config)
|
||||
|
||||
if (USE_APIDOCS)
|
||||
add_subdirectory (docs/api)
|
||||
endif ()
|
||||
if (USE_GIR)
|
||||
add_subdirectory (gir)
|
||||
endif ()
|
658
ChangeLog
658
ChangeLog
|
@ -1,5 +1,663 @@
|
|||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
v0.5.11
|
||||
Add fake theme for built-in icons
|
||||
* Don't truncate long speed dial titles if there's room to display them
|
||||
Fix warnings for -Wformat-security
|
||||
Ensure vala knows the prototypes of functions it calls, fixing pointer truncation in tests
|
||||
Add unit test to check appmenu/menubar visibility
|
||||
Fix last known GTK2 entry placeholder text bugs
|
||||
Make sure that only one of appmenu and menubar are visible *initially* as well as when changed
|
||||
Move adblock icons to hicolor
|
||||
Limit bookmarks panel callbacks to the lifetime of the panel to fix a crash
|
||||
Fix fallout (broken bookmarks and history panel search) from tweaks to GTK2 entry placeholder
|
||||
fix property binding to ensure that exactly one of appmenu button and menubar is always visible
|
||||
Skip open-with codepath with abp links, they are internal
|
||||
Use find_file to locate execinfo.h
|
||||
Fix middle/ctrl/normal clicking bookmarks (not folders) in the bookmarkbar.
|
||||
Add copright header to sanitize_bar.sh
|
||||
Adblock fixup: Escape . in filter with \
|
||||
Don't shadow variable uri in midori_browser_save_uri
|
||||
Switch Adblock icons to 24px color
|
||||
Always include app menu in toolbar
|
||||
Fix various mis[sing ]annotations and style issues in GIR
|
||||
Compile typelib from gir
|
||||
Fix assert when resetting webapp state after inactivity reset
|
||||
clean up handling of double-valued db column in Tabby
|
||||
Add a comment to explain MidoriBrowser popup callback
|
||||
fix warnings printed when right-clicking resize grip between location and search entries
|
||||
Win32: Use Dr. MinGW if present to preserve crash info
|
||||
Fix menubar warning caused by direct cast instead of `as`
|
||||
Helper script for setting up bzr with some usefull plugins and settings
|
||||
Stop using Gtk.Entry.max_width_chars
|
||||
avoid deprecated SoupServer API with libsoup 2.48
|
||||
Use unowned in foreach loops in Midori.Window
|
||||
Use unowned in foreach loops in Midori.Completion
|
||||
Use unowned with Adblock.Subscription and Element in foreach loops
|
||||
Use unowned strings in foreach loops
|
||||
Enable openWith in app mode and make it work with view-new
|
||||
Implement Midori.Window class with toolbar/ headerbar
|
||||
Drop support for libsoup-gnome-2.4 < 2.37.1
|
||||
Make search icons for engines work correctly
|
||||
Move to WebKit2 4.0 which broke ABI
|
||||
Port to zeitgeist-2.0
|
||||
win32: Bump shipped GrayBird theme version to fix some rendering issues
|
||||
avoid deprecated GtkDialog API with GTK+2 >= 2.22
|
||||
Title case for "Export Certificate" button
|
||||
fix incorrect type of MAX(sorting) in Tabby
|
||||
|
||||
v0.5.10
|
||||
use exit instead of return in license script
|
||||
Fix HAVE_GCR guards after GtkPopover port
|
||||
Remove example app and .desktop before creating it in the unit test
|
||||
Fix cache dir path in Adblock and always mkdir tmp
|
||||
Port location action from Granite.PopOver to Gtk.Popover
|
||||
Match https site when user-style is using domain syntax
|
||||
Always disable developer tools on Win32
|
||||
Reimplement Midori.URI.unescape and add various tests
|
||||
Make the inspector resizable with GTK3 by packing into a GtkScrolledWindow
|
||||
Don't build tabs2one in release builds
|
||||
Don't assume GNotification works on Win32
|
||||
update copyright date in About dialog
|
||||
Don't entity-escape history and bookmark results in location completion
|
||||
Only set tabs' error state if errors come from the main frame
|
||||
Implement Paste and Proceed as an action
|
||||
No Gcr on Win for the moment
|
||||
Yet another Speed Dial CSS update:
|
||||
Port bookmark popover from Granite to Gtk.Popover
|
||||
Make application choosers resizable with a sane default size
|
||||
Use GNotification >= 2.40 and use Midori.App API in webmedia
|
||||
Rework mouse button handling in KatzeArrayAction
|
||||
Don't bind :day in HistoryDatabase.query
|
||||
Make GCR mandatory for all builds
|
||||
Update coub support in mediaHerald
|
||||
history-list: Fix gtk+3 build caused by dropping "using Gtk;"
|
||||
Drop all remaining usages of "using *;"
|
||||
Don't open search engines menu when clearing search action
|
||||
Only remove apps in the sidepanel when left-clicking the delete icon
|
||||
Improve robustness of GTK3-compatibility placeholder text fallback
|
||||
Clean up vapi dependency
|
||||
tls_flags from webkit_web_view_get_tls_info need to be 0
|
||||
Don't add failed pages to history
|
||||
Throw error for wrong paramter in Statement.bind
|
||||
Replace NoJS "allow all pages" setting with "allow local pages"
|
||||
Avoid bugs due to race condition in addons delete dialog
|
||||
Calculate transfer progress at regular intervals to fix 0B/s bug and recalcitrant progess bars
|
||||
Fix warnings occurring with EXTRA_WARNINGS
|
||||
Escape parentheses in adblock_fixup_regexp()
|
||||
Use File.query_exist() on win32 when checking for db to attach
|
||||
Handle _NEW_WINDOW_ACTION explicitly to make _blank targets work
|
||||
Fix undefined behavior uint in mouse gestures
|
||||
fix JavaScript keyup event by calling inherited key-release-event handler in MidoriBrowser
|
||||
Inline renaming of speed dials
|
||||
Handle current_size and last_size of Download being equal
|
||||
Add proper copyright headers to element_hider and autosuggestcontrol
|
||||
Add X-GNOME-UsesNotifications to indicate the use of notifications
|
||||
Fix typo in Bookmarks menu UI definition
|
||||
|
||||
v0.5.9
|
||||
Remove dead code from browser and preferences
|
||||
Build-fix: Make PanedAction's Child.widget public
|
||||
fixes tab history undo
|
||||
Set a placeholder text on the URL entry
|
||||
Add "Add Bookmark" to menu
|
||||
Show search menu upon left icon click in location bar
|
||||
Fix crash when saving with associated resources
|
||||
Fix webkit2 downloads based on older branch
|
||||
don't hide window decorations for Midori-Granite
|
||||
Connect bookmarks-db singleton correctly to fix menus
|
||||
Fix some symbol names and transfer annotations in doc comments
|
||||
Use correct signature for window-state-event handler
|
||||
Do not overescape page titles in view completion
|
||||
Make adblock skip non-standard last update metadata strings
|
||||
Drop deprecated Granite LightWindow used for the Clear Private Data dialog
|
||||
Keep storing the last web media tab played.
|
||||
Allocate CookiePermissionManagerModalInfobar correctly
|
||||
Make middle clicking reload button duplicate the current tab, similar to other browsers
|
||||
Use network-changed of GNetworkMonitor to reload all tabs if network becomes available
|
||||
Show different messages based on network connectivity.
|
||||
Fix crash when activating the edit menu
|
||||
Fix "open all in tabs" for bookmarks
|
||||
Fix a few simple leaks
|
||||
Don't focus the locationaction when leaving blank pages
|
||||
Fix leaks of two references to the MidoriApp in Tabby
|
||||
Compile with valac 0.16 again
|
||||
Never display about:new in the urlbar
|
||||
fix crash right-clicking forms on local pages
|
||||
Share 'youtube, vimeo, dailymotion' that you are playing in Midori using org.midori.mediaHerald
|
||||
Give the SoupURI a path when checking cookie relevance
|
||||
Resolve ellipsis and title stripping in completion
|
||||
Add www. and .com/.country_domain and proceed with Ctrl+Enter/Shift+Enter with (readable code)
|
||||
Clean up browser tab/ uri/ title notify
|
||||
Drop pseudo Granite distinction in completion layout
|
||||
Fix visibility of SpeedDial, Toolbar, Bookmarkbar context menu items
|
||||
Distinguish between desc file missing and other parsing issues
|
||||
Use dependencies to clear test folders before execution
|
||||
win32: Drop dropbox usage from win release script, rename resulting output files
|
||||
|
||||
v0.5.8
|
||||
Use png icon instead of svg in set_status
|
||||
We must not pass a Cancellable to FaviconDatabase.get_favicon_pixbuf
|
||||
Retain spelling suggestion menu items from WebKit
|
||||
Properly guard usage of gtk3 get_style_context
|
||||
Mimic the look of Granite.DynamicNotebook when compiled with --enable-granite.
|
||||
Fix X11 lib underlink in midori-core
|
||||
Fix bookmarkbar bookmark click not opening links
|
||||
Use sanitized app URI as wm_classname/ StartupWMClass
|
||||
Make trunk build with WebKit2 again
|
||||
Fix for incorrect tstamp for background tabs
|
||||
Don't declare sorting doubles are nullable and print values when database tracing is enabled
|
||||
Correctly apply saved entry state and treat urlbar as a regular editable item
|
||||
Add missing conditional includes for granite flavoured build
|
||||
Open URIs dragged on tab label or new tab button
|
||||
Small adblock bugfixes
|
||||
Work around GTK3's hard-coded minimum stackswitcher button width
|
||||
Fix building with mingw packages from fedora 18
|
||||
Set page title as basis for print filename
|
||||
Rename notes inline
|
||||
Use EXTRA_WARNINGS option when building for windows
|
||||
Drop forgotten clutter init and obsolete header declarations
|
||||
Rework history-step handling and make it work again
|
||||
Port Tabby to DatabaseStatement API
|
||||
Replace bookmark stracing with generic profiling in Midori.Database
|
||||
Port autocompleter test to async job
|
||||
Finishing touches for Adblock
|
||||
Add filters and defaults
|
||||
Implement and use ContextAction.escaped
|
||||
printf URI in show_message_dialog for download error
|
||||
Improve docs and GIR annotations for KatzeItem, KatzeArray, and MidoriWebSettings
|
||||
Drop redundant TabNew from compact menu and put button in Tab Panel
|
||||
Fix loading file:// pages
|
||||
Implement Send Page Link by Email
|
||||
Use GtkStackSwitcher with GTK+ >= 3.10
|
||||
Implements context popup menu on menu entries of bookmark bar and bookmark menu.
|
||||
Fix building with newer mingw versions
|
||||
Display locationbar suggestions in the correct order
|
||||
Don't bother adblocking internal pages and favicons
|
||||
Don't use trailing comma on last list element in Adblock tests
|
||||
Rewrite Adblock more modularly, add Whitelist support
|
||||
Add support of DragonFlyBSD
|
||||
Change tooltips of Reload and ReloadStop actions while shift modifier is pressed
|
||||
Implement Midori.Database.attach method
|
||||
Allow :memory: as folder to make schema detection work
|
||||
More robust app/ profile creation
|
||||
Add helper callbacks to modify bookmark's tree store with unneded access to bookmarks db
|
||||
Implement more flexible fallback behavior for Cookie Permissions
|
||||
|
||||
v0.5.7:
|
||||
Modify actions and internal items in browser without changing settings
|
||||
Delay tab loading after Midori crashed
|
||||
Uncomment failing assertions about view_source in tab test
|
||||
Fallback to about:home if startup is anything but blank
|
||||
Don't try to create formhistory database if config_dir is NULL
|
||||
Handle url arguments for blank sessions
|
||||
Execute commands given at start time
|
||||
Introduce high-level prepare/ DatabaseStatement API
|
||||
Drop unused GraniteClutter-based animation support
|
||||
Drop uncommented contractor support
|
||||
Drop deprecated StaticNotebook used in KatzePreferences
|
||||
Introduce notebook class converging separate implementations
|
||||
Work around symbol relocation issue old version of gcc present on Ubuntu LTS
|
||||
NULL-check treeview in midori_search_action_get_editor
|
||||
Adjust CMakeList .ico check to not skip nojs icons
|
||||
Enable sidepanel in private mode
|
||||
Move Preferences menu entry above About
|
||||
Set minimum value of 0 on spin button for maximum cache size
|
||||
Give NextForward its own label for toolbar editor
|
||||
Correctly disable favicon database in app and private mode
|
||||
Change preferences to refer to proxy address as a "URI" (not "hostname")
|
||||
Add close tabs to right feature
|
||||
Allow printing without confirmation dialog on kiosk setups
|
||||
|
||||
v0.5.6:
|
||||
instead of creating devpet status icon on extension load, create it only to show new messages
|
||||
Open speed dial or homepage according to preference
|
||||
handle tab duplication
|
||||
Add copyright note to appdata file
|
||||
Tweak searching for resources when running from build folder
|
||||
Swap NULL-check with main frame check
|
||||
Use correct signal when clearing the trash
|
||||
Hide WEbGL preference if it is unavailable
|
||||
Remove stored popup sessions from the database
|
||||
Check all browsers for opened sessions and whether they're popups
|
||||
removed unused preference dialog and related code
|
||||
Fix check for found valac and mention VALAC variable
|
||||
Fix autoscrolling if page contains a frame with our custom error page
|
||||
Don't use context-menu signal in WebKitGTK+ < 1.10.0
|
||||
Fix building on Ubuntu 12.04
|
||||
Reset item ids when re-importing bookmarks
|
||||
Check path being NULL in export before trying to inspect it
|
||||
restore the last closed sessions if no session is opened
|
||||
Cast WebKitDOMHtmlElement for getting source content
|
||||
Use font-set signal and font family for GTK+ 3.2 font chooser
|
||||
add function to view dom source
|
||||
remove unused variable
|
||||
Resolve compiler warnings in current trunk
|
||||
Update win32-release script for cmake, move unused docs/scripts to old folder
|
||||
Try to handle previous runs of cmake in configure wrapper
|
||||
Correct view source assertions in tab unit test
|
||||
Build fix: found undeclared in midori_bookmarks_db_remove_item_recursive
|
||||
Cache bookmark items to avoid their recreation on database reads
|
||||
allow "view source" on about pages
|
||||
Enable old target policy on cmake < 2.8.8
|
||||
Re-arrange data file installing to be more explicit
|
||||
option to modify the number of tabs which will be restored in each idle callback
|
||||
Implement MidoriBookmarksDatabase class by inheritence from MidoriDatabase
|
||||
Ensure tab spinners update as often as the menubar spinner to avoid desync
|
||||
Use tabby sorting increment when importing session.xbel tabs
|
||||
Only install config files to /etc if prefix equals /usr
|
||||
handle urls as argument when starting midori
|
||||
Make tabby compile with Webkit2
|
||||
Drop waf build system and provide cmake-based "configure" script
|
||||
midori_panel_action_activate_cb forgot to update the action group
|
||||
Fixes bug where certificate Security overlay failed to close
|
||||
handle tab movement
|
||||
add tab sorting
|
||||
Untangle implicit GTK+3 for Granite and WebKit2
|
||||
Allow running test under debug tools with cmake
|
||||
Install config files to /etc when install prefix is /usr
|
||||
Add missing PO_FILES argument to GETTEXT_PROCESS_PO_FILES
|
||||
Add USE_APIDOCS to build API docs with CMake
|
||||
Rasterize SVG to PNG with rsvg-convert
|
||||
fix bookmarks test regression after fix-1179200-4
|
||||
Add CMakeLists.txt for config directory
|
||||
Install mo files in locale dir
|
||||
don't change uri/title if the tab isn't loaded
|
||||
use a separate signal to store the tab title
|
||||
Check if execinfo.h header exists on BSD
|
||||
fix endless loop in Midori.Database.init
|
||||
Use destructive-action style class in ClearPrivateData
|
||||
Initialize priv->element to avoid crash when freeing
|
||||
Introduces KatzeArray::update-item to handle metadata changes
|
||||
Refactor excuting schema from file into a function
|
||||
Use stock as string in liststore
|
||||
Drop needless (and wrong) HAVE_LIBNOTIFY in preferences
|
||||
Flip horizontal position of the overlay when hit by the mouse
|
||||
Add Midori.URI.get_base_domain and use it in NoJS
|
||||
Introduce Midori.Database and use for history and tabby
|
||||
ctrl+shift+w should trigger a delete-event
|
||||
Implement dialog windows opened via javascript
|
||||
Make get_res_filename work with different hierarchies
|
||||
fix check for new database
|
||||
Speed up session import
|
||||
Import tab title from old sessions
|
||||
Separate CFLAGS for C and add missing HAVE_
|
||||
Install top-level text files and FAQ html/ css to doc dir
|
||||
Provide and install .appdata.xml file for app stores
|
||||
Move bookmarks db handling to midori-bookmarks-db
|
||||
Add XSS to OPTS_LIBRARIES
|
||||
Update condition for UBUNTU_MENUPROXY to work on Saucy
|
||||
Introduce tabby, the new session manager
|
||||
Fix typo in katze_item_set_meta_integer call
|
||||
Allow bookmark bar update on additions resulting from imports
|
||||
Re-work midori_array_query_recursive to not include folder items twice
|
||||
Fix syntax of icon sizes passed to foreach
|
||||
Add bzr revision number to version if available
|
||||
Unify nojs and cookie policy dialogs, make policy changeable within the list
|
||||
Drop all G_ENABLE_DEBUG guards
|
||||
Add -g to CFLAGS to enable debugging symbols
|
||||
Adjust cmake build for Win32
|
||||
Implement CMake build setup
|
||||
Port MidoriApp from Unique/ sockets to GApplication
|
||||
New signal about-content to provide content for about uris
|
||||
Check if browser is NULL in midori_view_get_tab_menu to prevent a crash. Fixes bug #1215652.
|
||||
Ensure proxy setting widgets callbacks don't outlive the widgets themselves
|
||||
Fix webkit2 build error
|
||||
Show the bookmarks import location combobox.
|
||||
Rename internal completion URLs to avoid confusion
|
||||
|
||||
v0.5.5:
|
||||
Fix name and text fields inversion in XBEL folder import
|
||||
Correct packing of cookie and nojs permission dialog.
|
||||
Don't set tab title/special when a non-main frame displays an error
|
||||
Revise "cookies" debug output, merge expiry check and disallow revival of old cookies
|
||||
Drop now unused cgit module.xml file
|
||||
Use SoupProxyResolverGnome unconditionally and disable prefetching if proxy is active
|
||||
win32: Hide gui for profiles in webapp manager, as they are currently broken on Windows
|
||||
win32: support additional mouse buttons for going back/forward in history
|
||||
Enrich app error messages with filenames
|
||||
Fix segfault if url contains " %00"
|
||||
Replace 'Run as app' in bookmark dialog with 'Create launcher'
|
||||
Split config files and install from folders recursively
|
||||
Implement GTK+ theme switching via Preferences (Win32)
|
||||
Enable set_disk_cache_directory with WebKit2
|
||||
Introduce Midori.ContextAction and refactor page menu from scratch
|
||||
Define large dialog icon size relative to dialog icon size
|
||||
Extension Devpet which shows error messages and backtraces in systray
|
||||
WebKit2 cookie support
|
||||
Check the hit test result for editable to see if , should search
|
||||
Use SoupCookieJarSqlite and drop KatzeHttpCookies(Sqlite)
|
||||
Show folder tree when editing bookmarks
|
||||
Handle double value in _midori_browser_activate_action
|
||||
Add privacy preferences in web app mode
|
||||
Escape parentheses in adblock_fixup_regexp
|
||||
Introduce object oriented API for access to History Database
|
||||
Allow rss feeds with version 0.92
|
||||
Rename History completion to Bookmarks and History
|
||||
Don't show rss feed icon on twitter, underlying API was retired
|
||||
Read apps/ profiles from folder, leave launchers separate
|
||||
Fill in bookmark folder attributes in bookmarkbar populate
|
||||
|
||||
v0.5.4:
|
||||
Refactor history step and allow multiple title updates
|
||||
Call midori_browser_connect_tab with correct type
|
||||
Don't add HistoryCompletion if there's no history
|
||||
Restore reload button icon in error pages
|
||||
Don't insert folders into the log
|
||||
If an url is specified the fallback url should not be loaded
|
||||
Fixed crashes when closing a loading tab + granite's tab moving
|
||||
Test if plugins are redundant instead of skipping them all
|
||||
Avoid selecting bookmark uris that begin by 'javascript:' for completion
|
||||
Set FOREIGN_KEYS pragma on db initialization
|
||||
Implement a default zoom level preference
|
||||
Fix tautological use of G_MAXINT with enum
|
||||
Take current selection into account for bookmark folders when adding/editing bookmark
|
||||
Improve error page visuals, show suggestions on network errors
|
||||
Bump vala to 0.16.0
|
||||
Downgrade glib requirement to 2.32.3 to re-enable building under Ubuntu 12.04 (LTS)
|
||||
Bump glib2 version to 2.32.4
|
||||
Improve and unify thumbnail generation
|
||||
Omit speed dial and blank pages from view completion
|
||||
Makes the elements of the speed dial non-selectable
|
||||
Use NULL-safe comparison in katze_item_icon_loaded_cb
|
||||
Drop non-DOM style sheet injection code path
|
||||
Clean small leftovers from GTK and WebKit version bumps
|
||||
Bump GTK+ requirement to 2.24 and drop support for earlier versions
|
||||
Check for app mode to set browser icon instead of readonly
|
||||
Escape square brackets in adblock_fixup_regexp
|
||||
Fix showing (sub)folders in bookmarkbar
|
||||
Bump WebKit requirement to 1.8.3 and drop support for earlier versions
|
||||
Set menu on dynamic notebook tab
|
||||
Do not run toolbar editor's GtkDialog in its own main loop by prevent calling gtk_dialog_run(). Instead just set the GtkDialog modal and show it.
|
||||
Remove unnecesary harmful code from tab_switched_cb
|
||||
Fix segfault when deleteing tabs with history list
|
||||
Specify int64 id item as a string in bookmark remove/update queries
|
||||
Distinguish between box and event box in the tab label when colouring tabs
|
||||
Show visual feedback when hovering over items in bookmark panel
|
||||
Replace INSTALL/ HACKING with exported Contribute wiki page
|
||||
Delete tabs from history list with Del
|
||||
Check brightness of backgroung color when deciding foreground color of given tab
|
||||
Clean launcher filenames, double-click to open and delete button
|
||||
Avoid declaring browser twice within the same function
|
||||
Add ./waf --update-pot
|
||||
Fix memory leak introduced in r6184
|
||||
Use old function name g_dbus_generate_guid for old valac
|
||||
Move Import and Export into menu Bookmarks
|
||||
Collect multiple download notifications within a minute
|
||||
Fix segfault when right clicking on a web view.
|
||||
Make libnotify mandatory except on Windows
|
||||
Remove the rather unnecessary ./waf --run feature
|
||||
Send a notification after creating a launcher
|
||||
Ambiguous 'Open as App' context menu item was removed
|
||||
Apply label color to label rather than event box
|
||||
Store data of app mode based on URL in ~/.local/share/midori/apps
|
||||
Split colorful tabs code into helper functions and add unit tests
|
||||
Fix History List memory leak when closing Midori window.
|
||||
Replace .gitignore with a .bzrignore
|
||||
Always define GCR_VERSION in GTK+2 build
|
||||
Fix bookmarks dialog rename regression introduced in r6167.
|
||||
Drop check for gcr-3-gtk2 which isn't being maintained.
|
||||
Scrap unneeded background variables in location renderer callbacks
|
||||
Title case and proper packing in bookmark dialog
|
||||
Delete PO files Launchpad spewed into root directory when it couldn't find po/*.pot file.
|
||||
Issue a warning when trying to use MIDORI_DEBUG while running
|
||||
Update dates to 2013 to fix bug #1167075.
|
||||
|
||||
v0.5.2:
|
||||
Re-release with a proper version number and changelog
|
||||
|
||||
v0.5.1:
|
||||
Fix mouse gesture regression breaking context menu
|
||||
Fix --run command line switch by midori_paths_init
|
||||
Fix bug in size calculation for the history list popup
|
||||
Handle diagnostic dialog argument in running instance
|
||||
Fix feed panel default value crash
|
||||
Ensure existence of the applications directory
|
||||
Fix download tooltip crash and extend test case
|
||||
Integrate user interaction exploit demo in about:
|
||||
Don't convey loading or progress on special pages
|
||||
Address missing NULL checks and dead code found by clang
|
||||
No security window for blank pages, but a search icon
|
||||
Introduce UI for created apps/ launchers: Web App Manager
|
||||
Add custom-title setting to override browser title
|
||||
Add a Gtk.Entry to --plain mode for entering URLs
|
||||
Deprecate middle_click_opens_selection in favour of gtk-enable-primary-paste
|
||||
|
||||
Webkit2:
|
||||
Require 1.11.91 aka 2.0.0 for WebKit2
|
||||
Delayed load, clear favicons, clear HTTP cache, tab favicons
|
||||
Navigation policy, mouse buttons, security details
|
||||
basic cookies, download dialog, res://, stock://, print
|
||||
Zoom, default-charset, view-source, spell-check, prefetch
|
||||
Back/ forward, enable-java, plugin listing, web inspector
|
||||
v0.5.0:
|
||||
Store --execute arguments in string array
|
||||
Prevent overlay frame from being caught by show_all
|
||||
Unconditionally show Toolbar Style preference
|
||||
Duplicate current URI when reloading Midori.View
|
||||
Update tabs being closable on setting change in Granite
|
||||
Check default_search before setting SearchAction default
|
||||
Populate application chooser button in idle
|
||||
Bail out of completion resizing if cell height is 0
|
||||
Pass proxy to bookmark dialog when editing via menu
|
||||
Tweak bookmark dialog, button to buttons, toggles side by side
|
||||
Move 'Flash windows' option into History List
|
||||
Use light window for Clear Private Data with Granite
|
||||
Use GtkFontButton with filter func with GTK+ 3.2
|
||||
Implement 'Run in debugger' button in diagnostic dialog
|
||||
Add Win32 work-around to History List for modifiers
|
||||
Make toolbar drag/ drop work in GTK+3
|
||||
Check if active form element is input before getting search text
|
||||
Implement direction-based mouse gesture configuration
|
||||
Implement mouse movement, load-failed, crashed, search in WebKit2
|
||||
Add 'Show last crash log' button to diagnostic dialog
|
||||
Make invalid actions fail; exit on error in new process only
|
||||
Accept setting=value and extension=true/ false in --execute
|
||||
Merged cookie permissions as of 2013-03-08
|
||||
Gray out webGL preference if context is unavailable
|
||||
Use browser API to Close Other in view menu item
|
||||
Fix periods to ellipsis in Custom/ Customize Shortcuts
|
||||
Support Colorful Tabs in History List
|
||||
Add Midori.Tab.fg/ bg_color and Midori.View.set_colors
|
||||
Fix word-wrap, #decription and #message in about.css
|
||||
Set view scroll policy to Never to avoid flickering
|
||||
Use XDG_RUNTIME_DIR for temporary files
|
||||
Build Vala and C parts of core separately
|
||||
Don't provide default value for enable-scripts
|
||||
Respect Open new pages: window for Web Search and Open Image
|
||||
enable-javascript in WebKit1/ 2, macro for (Web)Settings
|
||||
Fix MIDORI_*_VERSION to be integers
|
||||
Fix .desktop file validation unit test and fix errors
|
||||
'New tab behavior' preference: about:dial/ new/ search/ home alias URLs
|
||||
Use stripped down XBEL variant for session and trash
|
||||
Allow any proxies supported by libproxy; list supported types in preferences
|
||||
|
||||
v0.4.9:
|
||||
Let non-Granite security window behave like a window
|
||||
Disable Contractor support in Granite for now
|
||||
Use cache_dir_for_reading in about:paths
|
||||
Strip LRE to prevent it from begin saved to disk
|
||||
Enable stripping 'referer' by default
|
||||
Fix crash on closing Adlock preferences dialog
|
||||
Bail on unset title in completion, fixing strchr urlbar crash
|
||||
Manage cookies accept policy per domain - not installed by default
|
||||
Don't store/ load stock:// icons for special pages
|
||||
Drop KatzeScrolled in favour of GTK+ 3.4 touchscreen support
|
||||
Write XBEL safely to prevent loss on eg. full disk
|
||||
Omit nspluginwrapper Netscape plugins from extensions
|
||||
Add --debug/ -g switch to run Midori in gdb
|
||||
List versions from about:version in --version
|
||||
Work in progress --enable-webkit2 option enabling WebKit2/ GTK+3
|
||||
Rename menu _Window to _Tabs
|
||||
Update Easylist subscription URL for Adblock
|
||||
Stop redundant tab numbering when adding
|
||||
Allow feed panel webview widget to shrink.
|
||||
Don't search for place holder text on cookie list rebuild
|
||||
Add 'Google Translate (gt)' as a search engine
|
||||
Default external Download Manager to "fetch" on FreeBSD
|
||||
Drop GCC-version specific -Wno-unused-but-set-variable
|
||||
Change X-Ayatana-Desktop-Shortcuts to Actions
|
||||
|
||||
v0.4.8:
|
||||
Fix un-delaying of tabs
|
||||
Support downloads with FlashGet on Win32
|
||||
Fix compilation with GLib 2.30
|
||||
Fix error handling in extensions
|
||||
Retain selection in urlbar when switching tabs
|
||||
Fix missing right-click menu on NextForward button
|
||||
Hide error page button if buttons have no images
|
||||
Rework URL completion: suggest open tabs
|
||||
Always highlight matches in inline search
|
||||
Pantheon: Only show private launcher in search
|
||||
Granite: Fix notebook, require 0.2, drop _about_dialog_new
|
||||
Don't include http(s), file or www. in page title
|
||||
Autodetect Twitter RSS feeds
|
||||
Adblock: Improve date parsing
|
||||
Unit test rework: backtraces, regardless of debugging, wine
|
||||
More accurate version numbers in about:version
|
||||
Drop obsolete --log-file command line switch
|
||||
Emit inspector attach-window with correct signature
|
||||
Fix Netscape plugins opening download dialogs
|
||||
Rework path handling and setup in different modes (fix segfaults)
|
||||
Manage Netscape plugins are individual extensions
|
||||
Address gtk_icon_set_render_icon_pixbuf assertions
|
||||
Fix renaming in speed dial with spaces in title
|
||||
Render completion title/ URL side by side with Granite
|
||||
Transparently use Favicon-/ IconDatabase/ file store per WebKit
|
||||
Add TabMoveFirst/ Last hotkeys (without defaults)
|
||||
Drop Hildon support
|
||||
Show URI in 'not responding' dialog
|
||||
Query search engine icons when loading, rather than stupid guesses
|
||||
|
||||
v0.4.7:
|
||||
Unify download behavior: link fingerprints, space check, clearing, tooltips
|
||||
GIO-based check for enough space and permissions, GIO-based themed icons
|
||||
Show opener/ tab domain in download dialog:
|
||||
http://lcamtuf.coredump.cx/fldl/ http://lcamtuf.coredump.cx/switch/
|
||||
Extension to download with a specific command line
|
||||
Size in download dialog and fallback filename heuristic
|
||||
|
||||
Windows: GTK+3, Faenza icons, gdb helper, Netscape plugins,
|
||||
ship CA bundle, fix View source, --portable/ -P on Windows
|
||||
Granite (Beta): about dialog, static notebook, no "New Tab" in toolbar, Print → Share
|
||||
Support building with Wayland-enabled GTK+3
|
||||
Theming: content view, secondary toolbar class, drop old icon names, bigger error icon
|
||||
Introduce --plain mode equivalent to GtkLauncher, lazy URLs for --snapshot/ -s
|
||||
Log bookmarks, history and downloads to zeitgeist
|
||||
|
||||
Show security details and export certificates with GCR, error out instead of colored urlbar
|
||||
Only allow data: URLs in urlbar for images
|
||||
Recognize and cache HSTS, system-wide /etc/xdg/midori/hsts
|
||||
Strip HTTP Host to outsmart some filter proxies
|
||||
|
||||
Completion: Fix PageUp/Down, Shift+Tab and wrap: This is consistent with GTK+ (excluding Tab) and Firefox
|
||||
Change Focus Current Tab to Ctrl+Alt+Home
|
||||
Fix Shift+Space for scrolling upwards
|
||||
Control+Alt+R: Readable mode
|
||||
Handle access key in link hints
|
||||
Drop speed dial keyboard access in favour of "." link hints
|
||||
|
||||
No Open, Bookmark bar, Customize toolbar, Inspect page in app menu; split panel menu
|
||||
Use ellipsises instead of period thresomes
|
||||
Hinted text in bookmarks, history and cookie manager
|
||||
Ellipsize panels (except for Transfers)
|
||||
Add icon to bookmark dialog and remove labels
|
||||
Validate proxy server IP and render invalid URLs in GTK+3
|
||||
Rename "Toplevel" folder to "Bookmarks"
|
||||
|
||||
Chrome identification option; "Automatic" user agent is Chrome-based
|
||||
Search: Create engines from search forms, remove "icon" field
|
||||
Copy Image s/Address// always copy both URL and data
|
||||
Rework debugging by introducing MIDORI_DEBUG; about:paths
|
||||
Adblock: Refresh filters based on file time and meta data, abp: links
|
||||
Optionally save website including resources
|
||||
Merged NextForward akin to StopReload
|
||||
PanedAction, Viewable, SpeedDial, (most of) Settings, Paths in Vala
|
||||
Improved database: requires sqlite 3.6.19 and 0.2.6 in import dialog
|
||||
|
||||
Confirm Caret Browsing before enabling it
|
||||
Support for custom items in Statusbar Features (see FAQ)
|
||||
Draggable favicon as URL or text, URL icon for URL entries
|
||||
Remember if inspector was attached
|
||||
Open tabs in the background by default
|
||||
RTL support in special/ error pages
|
||||
Fix progressbar text with GTK+3
|
||||
Build fix: More robust GTK+2 version check
|
||||
Ensure progress in urlbar and tab match
|
||||
Zoom text and images by default
|
||||
Don't mixup tokens starting with the same letters
|
||||
Seemless running out of build folder
|
||||
No speed dial in --app/ --private, fix layout with many tiles
|
||||
Add X-GNOME-Fullname to .desktop and translate desktop shortcuts
|
||||
Delayed Load extension
|
||||
|
||||
v0.4.6:
|
||||
+ Fix crasher in geolocation infobar
|
||||
+ Fix crasher in about:version on some systems
|
||||
+ Fix crasher opening bookmarks from Unity global menu
|
||||
+ Use WebKitFaviconDatabase as of WebKit 1.8.0
|
||||
+ Use midori-prefixed temp folder in midori_view_save_source
|
||||
+ Fix cancelling downloads with SteadyFlow or Aria2
|
||||
+ Fix crash dialog instead of opening tab in a running window
|
||||
+ Fix page icons in multi-frame sites (gmail, tumbler)
|
||||
+ Distinguish Simplified and Traditional Chinese
|
||||
+ Support go-jump-symbolic
|
||||
+ Handle empty tabs due to download links with a target
|
||||
+ Handle frame load interrupted in the unholy trinity
|
||||
+ Fix libsoup version check and wrong SSL status in location
|
||||
|
||||
v0.4.5:
|
||||
+ Work around black border around widgets on Win32
|
||||
+ Whitelist direct/ re-directed navigation requests in adblock
|
||||
+ Require Vala 0.14
|
||||
+ Provide geolocation diagnostics in about:geolocation
|
||||
+ List available about: URLs and app instance name in about:version
|
||||
+ Replace illegal characters in download filenames
|
||||
+ Tweak app options on Win32 and use ShellExecuteEx in sokoke_show_uri
|
||||
+ Use sokoke_show_uri in midori_browser_download_status_cb
|
||||
+ External Download manager Steadyflow and Aria2 (with cookies)
|
||||
+ Ensure adblock config folder when blocking images
|
||||
+ Use sqlite WAL mode for history if available
|
||||
+ Allow relative -c/ --config path
|
||||
+ Context menus on Back and Forward toolbar items
|
||||
+ Always show the tabbar by default
|
||||
+ Use ubuntu-bug if it exists
|
||||
+ Show inline find while typing and statusbar text in overlay with GTK+ 3.2
|
||||
+ Esc/ closing "downloads still active" should cancel, not continue
|
||||
+ Optional Granite support for notebook and bookmark dialog as pop-over
|
||||
+ Ctrl+j to toggle statusbar aka downloads
|
||||
+ Show at most 3 search engines in completion
|
||||
+ Don't replace existing onclick/ blur with autosuggest
|
||||
+ Implement low_memory_profile for FreeBSD and Win32
|
||||
+ Use var in internal javascript, to fix Google apps
|
||||
+ Handle download requests in frames
|
||||
|
||||
v0.4.4:
|
||||
+ Disable page cache with < 352 MB RAM
|
||||
+ Display filename in download dialog
|
||||
+ Fix box packing in GTK+3 (in most cases)
|
||||
+ Enable experimental HTML5 fullscreen API
|
||||
+ Harden IPv6 address recognition in location
|
||||
+ Experimental site data policy support (see FAQ)
|
||||
+ Close tabs by middle clicking close button
|
||||
+ Merge cookies and other data in Clear Private Data
|
||||
+ Improve KatzeArrayAction for Unity menuproxy compatibility
|
||||
+ Use GDateTime for history to avoid broken C runtimes
|
||||
+ Add Midori tag to DuckDuckGo default URI
|
||||
+ Rewrite completion popup resizing
|
||||
+ Streamline page icon loading stages and fallbacks
|
||||
+ Disable clipboard work-around for WebKit >= 1.4.3
|
||||
+ Re-word .desktop entry as an action
|
||||
+ Display informative text in private browsing
|
||||
+ Consistent clear icons in entries
|
||||
+ Revised download filename generation
|
||||
+ Add 'Open in Image Viewer' menu item
|
||||
+ Formhistory 2.0 with GDOM support
|
||||
+ Handle javascript: and mailto: links better
|
||||
+ Handle = key in Ukrainian layout better
|
||||
+ Fix bookmark export and deletion of bookmark folders
|
||||
+ Speed dial shortcut re-reordering by DND
|
||||
|
||||
v0.4.3:
|
||||
+ Implement about:widgets to test rendering
|
||||
+ Fix resizing of inspector by applying a minimum size
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# Based on "http://iany.me/wiki/Makefile/" by "Ian Yang" licensed under "CC by 3.0"
|
||||
|
||||
BUILD_FOLDER := _build
|
||||
|
||||
CUSTOM_TARGETS := cmake
|
||||
|
||||
# Do not try to use custom target when invoking external makefile
|
||||
EXTERNAL_TARGETS := $(filter-out $(CUSTOM_TARGETS), $(MAKECMDGOALS))
|
||||
|
||||
# Call all targets using `Makefile` in build directory in one `make` command.
|
||||
$(or $(lastword $(EXTERNAL_TARGETS)),all):
|
||||
$(MAKE) -C $(BUILD_FOLDER) $(EXTERNAL_TARGETS)
|
||||
|
||||
# If no targets are specified, use the dummy `all` target
|
||||
.PHONY: $(EXTERNAL_TARGETS) all
|
||||
|
||||
# Do nothing for all targets but last. Also quiet the message "Noting to be done on xxx"
|
||||
$(filter-out $(lastword $(EXTERNAL_TARGETS)), $(EXTERNAL_TARGETS)):
|
||||
@cd .
|
||||
|
||||
cmake: $(BUILD_FOLDER)
|
||||
cd $(BUILD_FOLDER) && cmake ..
|
||||
|
||||
$(BUILD_FOLDER):
|
||||
mkdir $(BUILD_FOLDER)
|
||||
|
||||
.PHONY: cmake
|
476
HACKING
476
HACKING
|
@ -1,169 +1,383 @@
|
|||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
====== Midori - Contribute ======
|
||||
|
||||
+ Hacking guide for Midori +
|
||||
**This document is licensed under the LGPL 2.1.**
|
||||
|
||||
- How to contribute
|
||||
- Coding style
|
||||
- Source files in the project
|
||||
- Examplary source code
|
||||
====== Check out the sources ======
|
||||
|
||||
+++ How to contribute +++
|
||||
bzr branch lp:midori
|
||||
|
||||
There are several ways to contribute to the project:
|
||||
The development **trunk** (master, tip) is the latest iteration of the next release. Browse it online and look for other branches at http://code.launchpad.net/midori or http://bazaar.launchpad.net/~midori/midori/trunk/tarball download a tarball of the latest revision.
|
||||
|
||||
For translating, have a look at the file TRANSLATE.
|
||||
//The code used to be hosted in git.xfce.org/apps/midori.//
|
||||
|
||||
For helping with testing and triaging bug reports, you should register with the bug tracker at https://bugs.launchpad.net/midori and join #midori on irc.freenode.net where a lot of problems are discussed. You can start right away by trying to reproduce bug reports and comment with your findings.
|
||||
Keep your copy updated:
|
||||
|
||||
If you are interested in contributing code, there are a few options. You can join #midori to discuss a particular problem you would like to look into, or a feature you would want to implement. Opening a bug report or feature request if there isn't already one is the next step. To attract some attention, if you attached a patch or have questions, ask in #midori.
|
||||
bzr merge --pull
|
||||
====== Join IRC chat rooms ======
|
||||
|
||||
+++ Coding style +++
|
||||
Join irc://irc.freenode.net/midori #midori on Freenode https://kiwiirc.com/client/irc.freenode.net/midori or use webchat to talk about Midori, discuss bugs and new ideas.
|
||||
====== Contribute other than touching code ======
|
||||
|
||||
Indentation is 4 spaces, no tabs, preferrably at 80 to 120 columns per line to
|
||||
avoid automated line-breaks. Trailing whitespace is not desirable.
|
||||
* http://bugs.launchpad.net/midori Go through problem reports and check Unconfirmed bugs or those lacking information and mark any duplicates you spot
|
||||
* https://www.bountysource.com/#trackers/130181-midori Add a bounty for a feature or bug you'd like to support
|
||||
* https://translations.launchpad.net/midori/trunk/+pots/trunk Translate to your own language
|
||||
* https://github.com/eustasy/midori-browser.org/issues Report website bugs
|
||||
* Write http://wiki.xfce.org/midori/tutorial your own extension - granted that's code, too, but maybe a little easier than hacking the core.
|
||||
|
||||
Declarations go to the beginning of a block, not inline. Variables of one plain
|
||||
type may be grouped in one declaration, pointer types may not be grouped. The
|
||||
asterisk goes next to the type.
|
||||
Variables should be ordered in the order they are used.
|
||||
====== Documentation resources ======
|
||||
|
||||
Comments explain functionality, they should not state facts. The appropriate
|
||||
style is always C style /* */, not C++ style.
|
||||
* https://wiki.gnome.org/Projects/Vala/Tutorial Vala Tutorial
|
||||
* http://midori-browser.org/docs/api/vala/midori/ Midori Vala Docs
|
||||
* http://midori-browser.org/docs/api/c/html/ Midori C Docs
|
||||
|
||||
Variable and function names should be animal, animal_shelter or animalsc in
|
||||
case it would otherwise be very long. Loop counters may be single letters.
|
||||
Type names should be Animal, AnimalShelter or AnimalSC. No prefixes from third
|
||||
party projects should be used, such as GTK or WebKit, while underlines may be
|
||||
used but do not have a particular meaning.
|
||||
====== Build the code ======
|
||||
|
||||
There is a space between functions or keywords and round brackets, and curly
|
||||
brackets always go on separate lines, at the indentation level of the
|
||||
function, conditional or loop expression. Curly brackets are left out for single
|
||||
statement conditionals and loops unless they notably help readability.
|
||||
The type of a function goes on a separate line before the function.
|
||||
Preprocessor instructions are indented with the code they relate to.
|
||||
|
||||
Code history is precious, so one should avoid renaming a lot of functions at
|
||||
once or moving whole paragraphs only to add or remove a level of indentation.
|
||||
Moving blocks of code around is also undesriable because it makes patches less
|
||||
readable since the result looks like new code.
|
||||
mkdir _build
|
||||
cd _build
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
||||
make
|
||||
sudo make install
|
||||
sudo gtk-update-icon-cache /usr/share/icons/hicolor
|
||||
|
||||
|
||||
+++ Source files in the project +++
|
||||
//Advanced Tip: Pass "-G Ninja" to cmake to use http://martine.github.io/ninja/ Ninja instead of make (usually packaged as ninja or ninja-build).//
|
||||
|
||||
Core:
|
||||
Files prefixed with "midori-" in the folder "midori" make up the core. They
|
||||
are essential to running the browser and mostly tailored to the browser.
|
||||
All header files prefixed with "midori-" are considered supported API and
|
||||
can be used to implement extensions.
|
||||
"sokoke" is a collection of very specialized helper functions which change
|
||||
from time to time as needed. In the past some of the code was moved to
|
||||
"katze" when it was considered generally useful.
|
||||
"socket" is a socket implementation with no dependency on other parts of
|
||||
the core, which is used if Midori is built without an external single
|
||||
instance support library.
|
||||
Panels:
|
||||
Files in the "panels" folder are classes that implement MidoriViewable and
|
||||
which are loaded into the MidoriPanel at startup. These panels are in
|
||||
principle optional.
|
||||
Katze:
|
||||
Re-usable classes and utility functions that don't depend on the core and
|
||||
some of that code indeed found its way into other projects.
|
||||
Extensions:
|
||||
These are extensions, written in C, which are loaded optionally if the user
|
||||
so chooses. Extensions can use API from "midori-" and "katze-" headers. Each
|
||||
module consists of either a single .c file or a folder with .c files.
|
||||
Tests:
|
||||
Unit tests are run regularly to verify possible regressions or measure
|
||||
performance of implementations. Except for select cases code changes should
|
||||
not cause failure of unit tests.
|
||||
If using GTK+3 you'll want to add -DUSE_GTK3=1 to the cmake command line.
|
||||
|
||||
You can build Midori using another C Compiler for example Clang. Just
|
||||
add -DCMAKE_C_COMPILER=/path/to/compiler to the cmake arguments.
|
||||
Then you can build following your normal procedure. Like this:
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_C_COMPILER=/usr/bin/clang ..
|
||||
make
|
||||
|
||||
Midori can be **run without being installed**.
|
||||
|
||||
_build/midori/midori
|
||||
|
||||
You can use a **temporary folder for testing** without affecting normal settings
|
||||
|
||||
_build/midori/midori -c /tmp/midoridev
|
||||
|
||||
You'll want to **unit test** the code if you're testing a new version or contributed your own changes:
|
||||
|
||||
xvfb-run make check
|
||||
|
||||
Automated daily builds in Launchpad (https://launchpad.net/~elementary-os/+archive/daily ppa:elementary-os/daily and https://launchpad.net/~midori/+archive/midori-dev ppa:midori/midori-dev) run these tests as well.
|
||||
====== Debugging issues ======
|
||||
|
||||
Testing an installed release may reveal crashers or memory corruption which require investigating from a local build and obtaining a stacktrace (backtrace, crash log).
|
||||
|
||||
_build/midori/midori -g [OPTIONAL ARGUMENTS]
|
||||
|
||||
If the problem is a warning, not a crash GLib has a handy feature
|
||||
|
||||
env G_DEBUG=all _build/midori/midori -g
|
||||
|
||||
For more specific debugging output, depending on the feature in question you may use
|
||||
|
||||
env MIDORI_DEBUG=help _build/midori/midori
|
||||
|
||||
Whilst -g is convenient you may want to use proper gdb:
|
||||
|
||||
gdb
|
||||
file _build/midori/midori
|
||||
run
|
||||
…
|
||||
bt
|
||||
|
||||
On Windows you can open the folder where Midori is installed and double-click gdb.exe. A black command line window should appear.
|
||||
|
||||
file midori.exe
|
||||
run
|
||||
…
|
||||
bt
|
||||
|
||||
To verify a regression you might need to revert a particular change:
|
||||
|
||||
|
||||
+++ Examplary source code +++
|
||||
# Revert only r6304
|
||||
bzr merge . -r 6304..6303
|
||||
|
||||
/*
|
||||
Copyright
|
||||
LICENSE TEXT
|
||||
*/
|
||||
====== Coding style and quality ======
|
||||
|
||||
#include "foo.h"
|
||||
Midori code should in general have:
|
||||
|
||||
#include "bar.h"
|
||||
* 4 space indentation, no tabs
|
||||
* Between 80 to 120 columns
|
||||
* Prefer /* */ style comments
|
||||
* Call variables //animal// and //animal_shelter// instead of <del>camelCase</del>
|
||||
* Keep a space between functions/ keywords and round parentheses
|
||||
|
||||
#include <glib.h>
|
||||
For Vala:
|
||||
|
||||
void
|
||||
foobar (FooEnum bar, const gchar* foo)
|
||||
{
|
||||
gint n, i;
|
||||
* Prefer //new Gtk.Widget ()// over //using Gtk; new Widget ()//
|
||||
* Stick to standard Vala-style curly parentheses on the same line
|
||||
* Cuddled //} else {// and //} catch (Error error) {//
|
||||
|
||||
if (!foo)
|
||||
return;
|
||||
For C:
|
||||
|
||||
#ifdef BAR_STRICT
|
||||
if (bar == FOO_N)
|
||||
{
|
||||
g_print ("illegal value for 'bar'.\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
* Always keep { and } on their own line
|
||||
|
||||
/* this is an example */
|
||||
switch (bar)
|
||||
{
|
||||
case FOO_FOO:
|
||||
n = bar + 1;
|
||||
break;
|
||||
case FOO_BAR:
|
||||
n = bar + 10;
|
||||
break;
|
||||
default:
|
||||
n = 1;
|
||||
}
|
||||
//Extensions may historically diverge from the standard styling on a case-by-case basis//
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
g_print ("%s\n", foo);
|
||||
}
|
||||
}
|
||||
====== Committing code ======
|
||||
|
||||
Header file example:
|
||||
Tell Bazaar your name if you haven't yet
|
||||
bzr whoami "Real Name <email@address>"
|
||||
|
||||
/*
|
||||
Copyright
|
||||
LICENSE TEXT
|
||||
*/
|
||||
See what you did so far
|
||||
bzr diff
|
||||
|
||||
#ifndef __FOO_H__
|
||||
#define __FOO_H__ 1
|
||||
Get an overview of changed and new files
|
||||
bzr status
|
||||
|
||||
#ifdef HAVE_BAR_H
|
||||
#define BAR_STRICT
|
||||
#endif
|
||||
Add new files, move/ rename or delete
|
||||
bzr add FILENAME
|
||||
bzr mv OLDFILE NEWFILE
|
||||
bzr rm FILENAME
|
||||
|
||||
/* Types */
|
||||
Commit all current changes - Bazaar automatically picks up edited files. //If you're used to git, think of an implicit staging area.//
|
||||
bzr commit -p
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FOO_FOO,
|
||||
FOO_BAR,
|
||||
FOO_N
|
||||
} FooEnum;
|
||||
If you have one or more related bug reports you should pass them as arguments. Once these commits are merged the bug will automatically be closed and the commit log shows clickable links to the reports.
|
||||
bzr commit -p --fixes=lp:1111999
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FooEnum foo_bar;
|
||||
} FooStruct;
|
||||
If you've done several commits
|
||||
bzr log | less
|
||||
bzr log -p | less
|
||||
|
||||
/* Declarations */
|
||||
In the case you committed something wrong or want to ammend it:
|
||||
bzr uncommit
|
||||
|
||||
void
|
||||
foo_bar (FooEnum bar,
|
||||
const gchar* foo);
|
||||
If you end up with unrelated debugging code or other patches in the current changes, it's sometimes handy to temporarily clean up. //This may be seen as bzr's version of git stash.//
|
||||
bzr shelve
|
||||
bzr commit -p
|
||||
bzr unshelve
|
||||
|
||||
const gchar*
|
||||
foo_foo (FooStruct foo_struct,
|
||||
guint number,
|
||||
gboolean flag);
|
||||
Remember to keep your branch updated:
|
||||
bzr merge --pull
|
||||
|
||||
#endif /* !__FOO_H__ */
|
||||
As a general rule of thumb, ''bzr help COMMAND'' gives you an explanation of any command and ''bzr help commands'' lists all available commands.
|
||||
|
||||
//If you're a die-hard git user, http://zyga.github.io/git-lp/ checkout git-lp to use git commands with the Bazaar repository.//
|
||||
====== Push proposed changes ======
|
||||
|
||||
If you haven't yet, https://launchpad.net/~/+editsshkeys check that Launchpad has your SSH key - you can create an SSH key with **Passwords and Keys** aka **Seahorse** or ''ssh-keygen -t rsa'' - and use ''bzr launchpad-login'' to make youself known to bzr locally.
|
||||
|
||||
If you checked out trunk, and added your patch(es), just **push it under your username** in Launchpad and you can **propose it for merging into trunk**. This will automatically request a **review from other developers** who can then comment on it and provide feedback.
|
||||
|
||||
bzr push --remember lp:~USERNAME/midori/fix-bug1120383 && bzr lp-propose-merge lp:midori
|
||||
|
||||
lp-propose-merge command may not be working on some distributions like Arch or Fedora.
|
||||
In case you get error like //bzr: ERROR: Unable to import library "launchpadlib": No module named launchpadlib// just use Launchpad's Web UI to propose a merge.
|
||||
|
||||
|
||||
**What happens to all the branches?**
|
||||
|
||||
Leave the branches alone, **approved branches are cleared automatically** by Launchpad.
|
||||
|
||||
For larger feature branches, **use the team** in Launchpad to allow other developers to work on the code with you.
|
||||
|
||||
bzr push --remember lp:~midori/midori/featuritis && bzr lp-propose-merge lp:midori
|
||||
|
||||
What if I want to help out on an **existing merge request** that I can't push to?
|
||||
|
||||
|
||||
bzr branch ~OTHERPERSON/midori/fix-bug1120383
|
||||
cd fix-bug1120383
|
||||
# make commits
|
||||
bzr push lp:USERNAME~/midori/fix-bug1120383
|
||||
bzr lp-propose-merge ~OTHERPERSON/midori/fix-bug1120383
|
||||
|
||||
|
||||
Updating a branch that may be out of sync with trunk:
|
||||
|
||||
|
||||
bzr pull
|
||||
bzr: ERROR: These branches have diverged
|
||||
bzr merge lp:midori
|
||||
# Hand-edit conflicting changes
|
||||
bzr resolve FILENAME
|
||||
# If any conflicts remain continue fixing
|
||||
bzr commit -m 'Merge lp:midori'
|
||||
|
||||
|
||||
Save a little bandwidth, **branch from an existing local copy** that you keep around:
|
||||
|
||||
|
||||
bzr branch lp:midori midori
|
||||
bzr branch midori midori.fix-bug1120383
|
||||
cd midori.fix-bug1120383
|
||||
bzr pull lp:midori
|
||||
|
||||
|
||||
====== Backwards compatibility ======
|
||||
As of Midori 0.5.4 the formula is:
|
||||
* Required dependencies need to be available on the previous stable https://apps.fedoraproject.org/packages/s/webkit Fedora and http://packages.ubuntu.com/search?suite=quantal&keywords=webkit&searchon=names Ubuntu
|
||||
* For reference http://openports.se/www/webkit OpenBSD
|
||||
* Windows XP through 8 are to date ABI compatible, all dependencies are included
|
||||
|
||||
^ package ^ F17 (2012-05-29) ^ U 12.10 (2012-10-18) ^
|
||||
| glib2 | 2.32.4 | 2.34.0 |
|
||||
| vala | 0.16.1 | 0.16 |
|
||||
| gtk3 | 3.4.4 | 3.6.0 |
|
||||
| gtk2 | 2.24.13 | 2.24.13 |
|
||||
| soup | 2.38.1 | 2.40 |
|
||||
| webkit | 1.8.3-1.fc17 | 1.10.0-0ubuntu1 |
|
||||
====== Midori with(out) Granite ======
|
||||
When built with Granite (-DUSE_GRANITE=1 or --enable-granite) there're a few key differences:
|
||||
* Preferences uses a http://valadoc.elementaryos.org/Granite/Granite.Widgets.StaticNotebook.html Granite.Widgets.StaticNotebook
|
||||
* URL completion styling is slightly different
|
||||
* Clear Private Data uses **Granite.Widgets.LightWindow**
|
||||
* Edit Bookmark and Security Details use http://valadoc.elementaryos.org/Granite/Granite.Widgets.PopOver.html Granite.Widgets.PopOver instead of Gtk.Window
|
||||
|
||||
====== Midori for Windows ======
|
||||
|
||||
===== For Linux developers =====
|
||||
==== Dependencies ====
|
||||
Midori for Windows is compiled on a Linux host and MinGW stack. For the current build Fedora 18 packages are used. Packages needed are listed below:
|
||||
|
||||
yum install gcc vala intltool
|
||||
|
||||
For a native build
|
||||
yum install libsoup-devel webkitgtk3-devel sqlite-devel
|
||||
|
||||
For cross-compilation
|
||||
yum install mingw{32,64}-webkitgtk3 mingw{32,64}-glib-networking mingw{32,64}-gdb mingw{32,64}-gstreamer-plugins-good
|
||||
|
||||
Packages needed when assembling the archive
|
||||
yum install faenza-icon-theme p7zip mingw32-nsis greybird-gtk3-theme
|
||||
|
||||
Installing those should get you the packages needed to successfully build and develop Midori for Win32.
|
||||
==== Building ====
|
||||
For 32-bit builds:
|
||||
|
||||
mkdir _mingw32
|
||||
cd _mingw32
|
||||
mingw32-cmake .. -DUSE_ZEITGEIST=0 -DUSE_GTK3=1 -DCMAKE_INSTALL_PREFIX=/usr/i686-w64-mingw32/sys-root/mingw -DCMAKE_VERBOSE_MAKEFILE=0
|
||||
make
|
||||
sudo make install
|
||||
|
||||
For 64-bit builds:
|
||||
|
||||
mkdir _mingw64
|
||||
cd _mingw64
|
||||
mingw64-cmake .. -DUSE_ZEITGEIST=0 -DUSE_GTK3=1 -DCMAKE_INSTALL_PREFIX=/usr/x86_64-w64-mingw32/sys-root/mingw -DCMAKE_VERBOSE_MAKEFILE=0
|
||||
make
|
||||
sudo make install
|
||||
|
||||
Once built and tested you can assemble the Midori archive with a helper script
|
||||
32-bit build:
|
||||
env MINGW_PREFIX="/usr/i686-w64-mingw32/sys-root/mingw" ./win32/makedist/makedist.midori
|
||||
64-bit build:
|
||||
env MINGW_PREFIX="/usr/x86_64-w64-mingw32/sys-root/mingw/" ./win32/makedist/makedist.midori x64
|
||||
===== Testing =====
|
||||
For testing your changes unfortuantely a real system is needed because Midori and WebKitGTK+ don't work properly under Wine. Even if it works some problems are not visible when using Wine, but are present when running under a real Windows system and vice versa.
|
||||
|
||||
One way around it is to virtualize Windows on a Linux host and mount your MinGW directories as a network drive or shared folder.
|
||||
|
||||
===== For Windows developers =====
|
||||
Rough list of prerequisites for building with MinGW on Windows
|
||||
|
||||
If in doubt whether to get 32 or 64 bit versions use 32 bit ones, they are more
|
||||
universal and tend to be less broken.
|
||||
|
||||
|
||||
==== MinGW compiler ====
|
||||
Compiler should match the one that was used to build packages ideally.
|
||||
|
||||
* We will user *mingw64 rubenvb* release
|
||||
* Lastest stable release is gcc 4.8.0
|
||||
|
||||
[[http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting
|
||||
%20Win64/Personal%20Builds/rubenvb/gcc-4.8-release/|Releases]]
|
||||
|
||||
[[http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting
|
||||
%20Win64/Personal%20Builds/rubenvb/gcc-4.8-release/x86_64-w64-mingw32-gcc-4.8.0-
|
||||
win32_rubenvb.7z/download|Download]]
|
||||
|
||||
|
||||
==== 7zip ====
|
||||
We will need 7zip to extract various archives
|
||||
|
||||
http://www.7-zip.org/download.html Homepage
|
||||
|
||||
|
||||
http://downloads.sourceforge.net/sevenzip/7z920.exe 32bit Installer
|
||||
|
||||
|
||||
==== Python3 (to extract rpms) ====
|
||||
We will need python3 to use download-mingw-rpm.py script.
|
||||
If you don't plan to use it you can safely skip this step.
|
||||
|
||||
We get python3, whatever is the lastes stable release.
|
||||
|
||||
http://www.python.org/download/releases/3.3.5 Releases
|
||||
|
||||
http://www.python.org/downloads/release/python-335/ Download
|
||||
|
||||
http://www.python.org/ftp/python/3.3.5/python-3.3.5.amd64.msi Installer
|
||||
|
||||
Install Python and be sure to check "addd python.exe to path" installer checkbox.
|
||||
|
||||
==== download-mingw-rpm.py ====
|
||||
We get download-mingw-rpm.py script from github. It uses Python3 and should fetch and
|
||||
unpack rpm files for us.
|
||||
|
||||
[[https://github.com/mkbosmans/download-mingw-rpm/blob/master/download-
|
||||
mingw-rpm.py|View Script]]
|
||||
|
||||
[[https://github.com/mkbosmans/download-mingw-rpm/raw/master/download-
|
||||
mingw-rpm.py|Download Script]]
|
||||
|
||||
Usage:
|
||||
|
||||
* Launch cmd.exe
|
||||
* Navigate to folder where the script was saved
|
||||
* Make sure that python can access 7z.exe
|
||||
* Run command and wait, it should extract the packages into your current directory
|
||||
|
||||
c:\Python33\python.exe download-mingw-rpm.py -u http://ftp.wsisiz.edu.pl/pub/linux/fedora/linux/updates/18/i386/ --deps mingw32-webkitgtk mingw32-glib-networking mingw32-gdb mingw32-gstreamer-plugins-good
|
||||
|
||||
[[http://dl.fedoraproject.org/pub/fedora/linux/releases/18/Everything/i386/os/Packages
|
||||
/m/|Fedora 18 packages]]
|
||||
|
||||
The above URL for some reason does not work with the script.
|
||||
|
||||
==== MSYS ====
|
||||
Msys contains shell and some small utilities
|
||||
|
||||
[[http://sourceforge.net/projects/mingw-w64/files/External%20binary
|
||||
%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29/MSYS-20111123.zip/download|Download]]
|
||||
|
||||
|
||||
==== CMake ====
|
||||
http://www.cmake.org/cmake/resources/software.html Homepage
|
||||
http://www.cmake.org/files/v2.8/cmake-2.8.12.2-win32-x86.exe Installer
|
||||
|
||||
When installing check the installer checkbox "add to path"
|
||||
|
||||
|
||||
==== Bazaar ====
|
||||
http://wiki.bazaar.canonical.com/WindowsDownloads Homepage
|
||||
|
||||
We will get 2.4 Stable Release (standalone)
|
||||
|
||||
http://launchpad.net/bzr/2.4/2.4.2/+download/bzr-2.4.2-1-setup.exe Installer
|
||||
|
||||
When installing check the installer checkbox "add to path"
|
||||
|
||||
==== Vala ====
|
||||
http://ftp.gnome.org/pub/gnome/sources/vala/0.20/vala-0.20.0.tar.xz Source
|
||||
|
||||
==== Globbing it all together ====
|
||||
|
||||
Extracted rpms msys and mingw packages should form uniform unix like folder.
|
||||
You use msys.bat to launch a shell
|
||||
|
||||
====== Jargon ======
|
||||
* freeze: a period of bug fixes only eg. 4/2 cycle means 4 weeks of features and 2 weeks to focus on resolving existing problems
|
||||
* MR: merge request, a branch proposed for review
|
||||
* ninja: an internal tab, usually empty label, used for taking screenshots
|
||||
* fortress: user of an ancient release like 0.4.3 as found on Raspberry Pie, Debian, Ubuntu
|
||||
* katze, sokoke, tabby: API names and coincidentally cat breeds
|
76
INSTALL
76
INSTALL
|
@ -1,76 +0,0 @@
|
|||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
+++ Installing Midori +++
|
||||
|
||||
Building and installing Midori is straightforward.
|
||||
|
||||
Make sure you have Python 2.4 or higher installed.
|
||||
|
||||
Change to the Midori folder on your hard disk in a terminal.
|
||||
|
||||
Run './waf configure'
|
||||
|
||||
Run './waf build'
|
||||
|
||||
You can now run Midori from the build folder like so
|
||||
|
||||
'./waf build --run'
|
||||
|
||||
Using --run as shown above will make sure extensions as well as
|
||||
localizations are used from the build folder.
|
||||
|
||||
You can install it with './waf install'
|
||||
|
||||
If you need to do a clean rebuild, you can do either './waf clean'
|
||||
in order to remove binaries or './waf distclean' which deletes generated
|
||||
configuration files as well.
|
||||
|
||||
For further options run './waf --help'
|
||||
|
||||
+++ Debugging Midori +++
|
||||
|
||||
Run './waf configure -d full' from the Midori folder.
|
||||
|
||||
Run './waf build'
|
||||
|
||||
Midori is now built with debugging symbols.
|
||||
|
||||
Make sure you have installed 'gdb', the GNU Debugger.
|
||||
|
||||
Run Midori as 'gdb _build_/default/midori/midori'.
|
||||
|
||||
Inside gdb, type 'run'.
|
||||
|
||||
Try to reproduce a crash that you experienced earlier,
|
||||
this time Midori will freeze at the point of the crash.
|
||||
Switch to your terminal, type bt ('backtrace') and hit Return.
|
||||
What you obtained now is a backtrace that should include
|
||||
function names and line numbers.
|
||||
|
||||
If the problem is a warning and not a crash, try this:
|
||||
|
||||
'G_DEBUG=all gdb _build_/default/midori/midori'
|
||||
|
||||
If you are interested in HTTP communication, try this:
|
||||
|
||||
'MIDORI_SOUP_DEBUG=2 _build_/default/midori/midori'
|
||||
|
||||
Where '2' can be a level between 0 and 3.
|
||||
|
||||
If you are interested in (non-) touchscreen behaviour, try this:
|
||||
|
||||
'MIDORI_TOUCHSCREEN=1 _build_/default/midori/midori', or
|
||||
|
||||
'MIDORI_TOUCHSCREEN=0 _build_/default/midori/midori'
|
||||
|
||||
If you want to "dry run" without WebKitGTK+ rendering, try this:
|
||||
|
||||
'MIDORI_UNARMED=1 _build_/default/midori/midori'
|
||||
|
||||
To debug extensions you can specify the path:
|
||||
|
||||
'export MIDORI_EXTENSION_PATH=_build_/default/extensions'
|
||||
|
||||
For further information a tutorial for gdb and
|
||||
reading up on how you can install debugging
|
||||
symbols for libraries used by Midori are recommended.
|
31
README
31
README
|
@ -1,22 +1,25 @@
|
|||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
Midori is a lightweight web browser.
|
||||
Midori is a fast little WebKit browser with support for HTML5. It can manage
|
||||
many open tabs and windows. The URL bar completes history, bookmarks, search
|
||||
engines and open tabs out of the box. Web developers can use the powerful
|
||||
web inspector that is a part of WebKit. Individual pages can easily be turned
|
||||
into web apps and new profiles can be created on demand.
|
||||
|
||||
* Full integration with GTK+2.
|
||||
* Fast rendering with WebKit.
|
||||
* Tabs, windows and session management.
|
||||
* Flexibly configurable Web Search.
|
||||
* User scripts and user styles support.
|
||||
* Straightforward bookmark management.
|
||||
* Customizable and extensible interface.
|
||||
* Extensions written in C.
|
||||
A number of extensions are included by default:
|
||||
|
||||
Requirements: GLib 2.22, GTK+ 2.10, WebkitGTK+ 1.1.17, libXML2,
|
||||
libsoup 2.27.90, sqlite 3.0, Vala 0.10
|
||||
* Adblock with support for ABP filter lists and custom rules is built-in.
|
||||
* You can download files with Aria2 or SteadyFlow.
|
||||
* User scripts and styles support a la Greasemonkey.
|
||||
* Managing cookies and scripts via NoJS and Cookie Security Manager.
|
||||
* Switching open tabs in a vertical panel or a popup window.
|
||||
|
||||
Optional: GTK+ 3.0, Unique 0.9, libnotify
|
||||
Requirements: GLib 2.32.3, GTK+ 2.24, WebkitGTK+ 1.8.1, libXML2,
|
||||
libsoup 2.27.90, sqlite 3.0, Vala 0.16, libnotify
|
||||
|
||||
For installation instructions read INSTALL.
|
||||
Optional: GTK+ 3.0, gcr, Granite 0.2, WebKit2GTK+ 1.11.91/ 2.0.0
|
||||
|
||||
For installation instructions read the file HACKING.
|
||||
|
||||
Please report comments, suggestions and bugs to:
|
||||
https://bugs.launchpad.net/midori
|
||||
|
@ -24,4 +27,4 @@ Please report comments, suggestions and bugs to:
|
|||
And join the IRC channel #midori on irc.freenode.net
|
||||
|
||||
Check for new versions at:
|
||||
http://www.twotoasts.de
|
||||
http://www.midori-browser.org
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
include(ParseArguments)
|
||||
|
||||
macro(contain_test test_name executable)
|
||||
parse_arguments(ARGS "test_name;executable" "" ${ARGN})
|
||||
set(TEST_ENV "")
|
||||
foreach(VARIABLE XDG_CACHE_HOME XDG_CONFIG_HOME XDG_DATA_HOME XDG_RUNTIME_DIR TMPDIR)
|
||||
set(CONTAINER "${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/${VARIABLE}")
|
||||
set(TEST_ENV "${TEST_ENV}${VARIABLE}=${CONTAINER};")
|
||||
endforeach()
|
||||
|
||||
add_dependencies(check contain-${test_name})
|
||||
|
||||
set_tests_properties(${test_name} PROPERTIES
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
TIMEOUT 42
|
||||
ENVIRONMENT "${TEST_ENV}"
|
||||
)
|
||||
add_custom_target("contain-${test_name}"
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/XDG_CACHE_HOME
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/XDG_CONFIG_HOME
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/XDG_DATA_HOME
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/XDG_RUNTIME_DIR
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/TMPDIR
|
||||
)
|
||||
|
||||
string(REPLACE ${executable} ";" " " executable)
|
||||
add_custom_target("gdb-${test_name}"
|
||||
COMMAND env ${TEST_ENV} gdb
|
||||
--batch -ex 'set print thread-events off'
|
||||
-ex 'run' -ex 'bt'
|
||||
--args ${executable}
|
||||
DEPENDS "contain-${test_name}"
|
||||
)
|
||||
|
||||
add_custom_target("valgrind-${test_name}"
|
||||
COMMAND env ${TEST_ENV} valgrind
|
||||
-q --leak-check=no --num-callers=4
|
||||
--show-possibly-lost=no
|
||||
--undef-value-errors=yes
|
||||
--track-origins=yes
|
||||
${executable}
|
||||
DEPENDS "contain-${test_name}"
|
||||
)
|
||||
|
||||
add_custom_target("callgrind-${test_name}"
|
||||
COMMAND env ${TEST_ENV} valgrind
|
||||
--tool=callgrind
|
||||
--callgrind-out-file=${UNIT}.callgrind
|
||||
${executable}
|
||||
DEPENDS "contain-${test_name}"
|
||||
)
|
||||
endmacro(contain_test)
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright (C) 2013 Christian Dywan
|
||||
# Copyright (C) 2013 Olivier Duchateau
|
||||
|
||||
find_program (RSVG_CONVERT rsvg-convert)
|
||||
|
||||
if (RSVG_CONVERT)
|
||||
set (CONVERT_FOUND TRUE)
|
||||
macro (SVG2PNG filename install_destination)
|
||||
string(REPLACE "/" "_" target ${filename})
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${filename}")
|
||||
add_custom_target ("${target}.png" ALL
|
||||
${RSVG_CONVERT} --keep-aspect-ratio --format=png "${CMAKE_CURRENT_SOURCE_DIR}/${filename}.svg"
|
||||
--output "${CMAKE_CURRENT_BINARY_DIR}/${filename}.png"
|
||||
)
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${filename}.png"
|
||||
DESTINATION ${install_destination})
|
||||
endmacro (SVG2PNG filename)
|
||||
endif ()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# FindIntltool.cmake
|
||||
#
|
||||
# Jim Nelson <jim@yorba.org>
|
||||
# Copyright 2012-2013 Yorba Foundation
|
||||
# Copyright (C) 2013 Christian Dywan
|
||||
|
||||
find_program (INTLTOOL_MERGE_EXECUTABLE intltool-merge)
|
||||
find_program (INTLTOOL_UPDATE_EXECUTABLE intltool-update)
|
||||
|
||||
if (INTLTOOL_MERGE_EXECUTABLE)
|
||||
set (INTLTOOL_MERGE_FOUND TRUE)
|
||||
macro (INTLTOOL_MERGE_DESKTOP desktop_id po_dir)
|
||||
add_custom_target ("${desktop_id}.desktop" ALL
|
||||
${INTLTOOL_MERGE_EXECUTABLE} --desktop-style ${CMAKE_SOURCE_DIR}/${po_dir}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${desktop_id}.desktop.in ${desktop_id}.desktop
|
||||
)
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${desktop_id}.desktop"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
|
||||
endmacro (INTLTOOL_MERGE_DESKTOP desktop_id po_dir)
|
||||
macro (INTLTOOL_MERGE_APPDATA desktop_id po_dir)
|
||||
add_custom_target ("${desktop_id}.appdata.xml" ALL
|
||||
${INTLTOOL_MERGE_EXECUTABLE} --xml-style ${CMAKE_SOURCE_DIR}/${po_dir}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${desktop_id}.appdata.xml.in ${desktop_id}.appdata.xml
|
||||
)
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${desktop_id}.appdata.xml"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/appdata")
|
||||
endmacro (INTLTOOL_MERGE_APPDATA desktop_id po_dir)
|
||||
endif ()
|
||||
|
||||
if (INTLTOOL_UPDATE_EXECUTABLE)
|
||||
set (INTLTOOL_UPDATE_FOUND TRUE)
|
||||
add_custom_target (pot
|
||||
COMMAND ${INTLTOOL_UPDATE_EXECUTABLE} "-p" "-g" ${GETTEXT_PACKAGE}
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/po"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
find_program(VALA_EXECUTABLE NAMES $ENV{VALAC} valac)
|
||||
if (VALA_EXECUTABLE)
|
||||
execute_process(COMMAND ${VALA_EXECUTABLE} "--version" OUTPUT_VARIABLE "VALA_VERSION")
|
||||
string(REPLACE "Vala " "" VALA_VERSION ${VALA_VERSION})
|
||||
string(STRIP ${VALA_VERSION} VALA_VERSION)
|
||||
else ()
|
||||
message(FATAL_ERROR "valac not found - install Vala compiler or specify compiler name eg. VALAC=valac-0.20")
|
||||
endif ()
|
||||
|
||||
macro(vala_require VALA_REQUIRED)
|
||||
if (${VALA_VERSION} VERSION_GREATER ${VALA_REQUIRED} OR ${VALA_VERSION} VERSION_EQUAL ${VALA_REQUIRED})
|
||||
message(STATUS "valac ${VALA_VERSION} found")
|
||||
else ()
|
||||
message(FATAL_ERROR "valac >= ${VALA_REQUIRED} or later required")
|
||||
endif ()
|
||||
endmacro(vala_require)
|
|
@ -0,0 +1,38 @@
|
|||
# GIR.cmake
|
||||
#
|
||||
# Macros for building Gobject Introspection bindings for Midori API
|
||||
find_program (GIR_SCANNER_BIN g-ir-scanner)
|
||||
find_program (GIR_COMPILER_BIN g-ir-compiler)
|
||||
|
||||
if (GIR_SCANNER_BIN AND GIR_COMPILER_BIN)
|
||||
|
||||
set (GIR_FOUND TRUE)
|
||||
set (GIR_VERSION "${MIDORI_MAJOR_VERSION}.${MIDORI_MINOR_VERSION}")
|
||||
macro (gir_build module namespace)
|
||||
add_custom_target ("g-ir-scanner_${module}" ALL
|
||||
${GIR_SCANNER_BIN} -Imidori -I${CMAKE_SOURCE_DIR}/ -I${CMAKE_BINARY_DIR}/midori -I${CMAKE_SOURCE_DIR}/${module} -I${CMAKE_SOURCE_DIR}/toolbars -I.
|
||||
--header-only -n ${namespace} --identifier-prefix ${namespace}
|
||||
${CMAKE_SOURCE_DIR}/${module}/${module}-*.c ${CMAKE_SOURCE_DIR}/${module}/${module}-*.h
|
||||
--pkg gtk+-2.0 --pkg webkit-1.0 --pkg gio-2.0 --pkg gobject-2.0
|
||||
--warn-all -iGObject-2.0 -iGLib-2.0 -iGtk-2.0
|
||||
--nsversion ${GIR_VERSION}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/${namespace}-${GIR_VERSION}.gir
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS ${CMAKE_PROJECT_NAME})
|
||||
add_custom_target ("g-ir-compiler_${module}" ALL
|
||||
${GIR_COMPILER_BIN} ${CMAKE_CURRENT_BINARY_DIR}/${namespace}-${GIR_VERSION}.gir
|
||||
--output ${CMAKE_CURRENT_BINARY_DIR}/${namespace}-${GIR_VERSION}.typelib
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS g-ir-scanner_${module})
|
||||
|
||||
endmacro (gir_build module namespace)
|
||||
|
||||
macro (gir module namespace)
|
||||
gir_build (${module} ${namespace})
|
||||
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${namespace}-${GIR_VERSION}.gir"
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/gir-1.0/")
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${namespace}-${GIR_VERSION}.typelib"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/girepository-1.0/")
|
||||
endmacro (gir module)
|
||||
endif ()
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright (C) 2010 David Sansome <me@davidsansome.com>
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
if(POLICY CMP0011)
|
||||
cmake_policy(SET CMP0011 NEW)
|
||||
endif(POLICY CMP0011)
|
||||
|
||||
find_program(GLIB_MKENUMS glib-mkenums)
|
||||
find_program(GLIB_GENMARSHAL glib-genmarshal)
|
||||
|
||||
macro(add_glib_marshal outfiles name prefix otherinclude)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
COMMAND ${GLIB_GENMARSHAL} --header "--prefix=${prefix}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.list"
|
||||
> "${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND echo "\\#include \\\"${otherinclude}\\\"" > "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND echo "\\#include \\\"glib-object.h\\\"" >> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND echo "\\#include \\\"${name}.h\\\"" >> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND ${GLIB_GENMARSHAL} --body "--prefix=${prefix}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.list"
|
||||
>> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
)
|
||||
list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
|
||||
endmacro(add_glib_marshal)
|
||||
|
||||
macro(add_glib_enumtypes_t outfiles name htemplate ctemplate)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
COMMAND ${GLIB_MKENUMS}
|
||||
--template "${htemplate}"
|
||||
${ARGN} > "${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${ARGN} "${htemplate}"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND ${GLIB_MKENUMS}
|
||||
--template "${ctemplate}"
|
||||
${ARGN} > "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${ARGN} ${ctemplate}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${name}.h"
|
||||
)
|
||||
list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
|
||||
endmacro(add_glib_enumtypes_t)
|
||||
|
||||
macro(add_glib_enumtypes outfiles name includeguard)
|
||||
set(htemplate "${CMAKE_CURRENT_BINARY_DIR}/${name}.h.template")
|
||||
set(ctemplate "${CMAKE_CURRENT_BINARY_DIR}/${name}.c.template")
|
||||
|
||||
# Write the .h template
|
||||
add_custom_command(
|
||||
OUTPUT ${htemplate} ${ctemplate}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-Dctemplate=${ctemplate}"
|
||||
"-Dhtemplate=${htemplate}"
|
||||
"-Dname=${name}"
|
||||
"-Dincludeguard=${includeguard}"
|
||||
"\"-Dheaders=${ARGN}\""
|
||||
-P "${CMAKE_SOURCE_DIR}/CMake/MakeGLibEnumTemplates.cmake"
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/CMake/MakeGLibEnumTemplates.cmake" ${headers}
|
||||
)
|
||||
|
||||
add_glib_enumtypes_t(${outfiles} ${name} ${htemplate} ${ctemplate} ${ARGN})
|
||||
endmacro(add_glib_enumtypes)
|
|
@ -0,0 +1,61 @@
|
|||
# GtkDoc.cmake
|
||||
#
|
||||
# Macros for building Midori API documentation.
|
||||
# Copyright (C) 2013 Olivier Duchateau
|
||||
|
||||
find_program (GTKDOC_SCAN_BIN gtkdoc-scan)
|
||||
find_program (GTKDOC_MKDB_BIN gtkdoc-mkdb)
|
||||
find_program (GTKDOC_MKHTML_BIN gtkdoc-mkhtml)
|
||||
find_program (GTKDOC_MKTMPL_BIN gtkdoc-mktmpl)
|
||||
|
||||
if (GTKDOC_SCAN_BIN AND GTKDOC_MKTMPL_BIN AND GTKDOC_MKDB_BIN
|
||||
AND GTKDOC_MKHTML_BIN)
|
||||
|
||||
set (GTKDOC_FOUND TRUE)
|
||||
|
||||
macro (gtkdoc_build module)
|
||||
message("gtkdoc: module ${module}")
|
||||
# file (MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}")
|
||||
add_custom_target ("gtkdoc-scan_${module}" ALL
|
||||
${GTKDOC_SCAN_BIN} --module=${module}
|
||||
--source-dir="${CMAKE_SOURCE_DIR}/${module}"
|
||||
--output-dir="${CMAKE_CURRENT_BINARY_DIR}/${module}"
|
||||
--rebuild-sections --rebuild-types
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
add_custom_target ("gtkdoc-tmpl_${module}" ALL
|
||||
${GTKDOC_MKTMPL_BIN} --module=${module}
|
||||
--output-dir="${CMAKE_CURRENT_BINARY_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}"
|
||||
DEPENDS "gtkdoc-scan_${module}")
|
||||
|
||||
add_custom_target ("gtkdoc-docbook_${module}" ALL
|
||||
${GTKDOC_MKDB_BIN} --module=${module}
|
||||
--output-dir="xml"
|
||||
--source-dir="${CMAKE_SOURCE_DIR}/${module}"
|
||||
--source-suffixes=c,h --output-format=xml
|
||||
--default-includes=${module}/${module}.h
|
||||
--sgml-mode --main-sgml-file=${module}.sgml
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}"
|
||||
DEPENDS "gtkdoc-tmpl_${module}")
|
||||
|
||||
# Keep this target alone, otherwise build fails
|
||||
add_custom_target ("gtkdoc-html_${module}" ALL
|
||||
${GTKDOC_MKHTML_BIN} ${module}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${module}/${module}.sgml"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}/html"
|
||||
DEPENDS "gtkdoc-docbook_${module}")
|
||||
|
||||
endmacro (gtkdoc_build module)
|
||||
|
||||
macro (gtkdoc module)
|
||||
file (MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}/html")
|
||||
gtkdoc_build (${module})
|
||||
|
||||
set (DOC_DIR "html/midori-${MIDORI_MAJOR_VERSION}-${MIDORI_MINOR_VERSION}")
|
||||
install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${module}/html/"
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/gtk-doc/${DOC_DIR}/${module}"
|
||||
PATTERN "html/*"
|
||||
PATTERN "index.sgml" EXCLUDE)
|
||||
endmacro (gtkdoc module)
|
||||
endif ()
|
|
@ -0,0 +1,36 @@
|
|||
##
|
||||
# This is a helper Macro to parse optional arguments in Macros/Functions
|
||||
# It has been taken from the public CMake wiki.
|
||||
# See http://www.cmake.org/Wiki/CMakeMacroParseArguments for documentation and
|
||||
# licensing.
|
||||
##
|
||||
macro(parse_arguments prefix arg_names option_names)
|
||||
set(DEFAULT_ARGS)
|
||||
foreach(arg_name ${arg_names})
|
||||
set(${prefix}_${arg_name})
|
||||
endforeach(arg_name)
|
||||
foreach(option ${option_names})
|
||||
set(${prefix}_${option} FALSE)
|
||||
endforeach(option)
|
||||
|
||||
set(current_arg_name DEFAULT_ARGS)
|
||||
set(current_arg_list)
|
||||
foreach(arg ${ARGN})
|
||||
set(larg_names ${arg_names})
|
||||
list(FIND larg_names "${arg}" is_arg_name)
|
||||
if(is_arg_name GREATER -1)
|
||||
set(${prefix}_${current_arg_name} ${current_arg_list})
|
||||
set(current_arg_name ${arg})
|
||||
set(current_arg_list)
|
||||
else(is_arg_name GREATER -1)
|
||||
set(loption_names ${option_names})
|
||||
list(FIND loption_names "${arg}" is_option)
|
||||
if(is_option GREATER -1)
|
||||
set(${prefix}_${arg} TRUE)
|
||||
else(is_option GREATER -1)
|
||||
set(current_arg_list ${current_arg_list} ${arg})
|
||||
endif(is_option GREATER -1)
|
||||
endif(is_arg_name GREATER -1)
|
||||
endforeach(arg)
|
||||
set(${prefix}_${current_arg_name} ${current_arg_list})
|
||||
endmacro(parse_arguments)
|
|
@ -0,0 +1,236 @@
|
|||
##
|
||||
# Copyright 2009-2010 Jakob Westhoff. All rights reserved.
|
||||
# Copyright 2012 elementary.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of Jakob Westhoff
|
||||
##
|
||||
|
||||
include(ParseArguments)
|
||||
find_package(Vala REQUIRED)
|
||||
|
||||
##
|
||||
# Compile vala files to their c equivalents for further processing.
|
||||
#
|
||||
# The "vala_precompile" macro takes care of calling the valac executable on the
|
||||
# given source to produce c files which can then be processed further using
|
||||
# default cmake functions.
|
||||
#
|
||||
# The first parameter provided is a variable, which will be filled with a list
|
||||
# of c files outputted by the vala compiler. This list can than be used in
|
||||
# conjuction with functions like "add_executable" or others to create the
|
||||
# neccessary compile rules with CMake.
|
||||
#
|
||||
# The initial variable is followed by a list of .vala files to be compiled.
|
||||
# Please take care to add every vala file belonging to the currently compiled
|
||||
# project or library as Vala will otherwise not be able to resolve all
|
||||
# dependencies.
|
||||
#
|
||||
# The following sections may be specified afterwards to provide certain options
|
||||
# to the vala compiler:
|
||||
#
|
||||
# PACKAGES
|
||||
# A list of vala packages/libraries to be used during the compile cycle. The
|
||||
# package names are exactly the same, as they would be passed to the valac
|
||||
# "--pkg=" option.
|
||||
#
|
||||
# OPTIONS
|
||||
# A list of optional options to be passed to the valac executable. This can be
|
||||
# used to pass "--thread" for example to enable multi-threading support.
|
||||
#
|
||||
# CUSTOM_VAPIS
|
||||
# A list of custom vapi files to be included for compilation. This can be
|
||||
# useful to include freshly created vala libraries without having to install
|
||||
# them in the system.
|
||||
#
|
||||
# GENERATE_VAPI
|
||||
# Pass all the needed flags to the compiler to create an internal vapi for
|
||||
# the compiled library. The provided name will be used for this and a
|
||||
# <provided_name>.vapi file will be created.
|
||||
#
|
||||
# GENERATE_HEADER
|
||||
# Let the compiler generate a header file for the compiled code. There will
|
||||
# be a header file as well as an internal header file being generated called
|
||||
# <provided_name>.h and <provided_name>_internal.h
|
||||
#
|
||||
# GENERATE_GIR
|
||||
# Have the compiler generate a GObject-Introspection repository file with
|
||||
# name: <provided_name>.gir. This can be later used to create a binary typelib
|
||||
# using the GI compiler.
|
||||
#
|
||||
# GENERATE_SYMBOLS
|
||||
# Output a <provided_name>.symbols file containing all the exported symbols.
|
||||
#
|
||||
# The following call is a simple example to the vala_precompile macro showing
|
||||
# an example to every of the optional sections:
|
||||
#
|
||||
# vala_precompile(VALA_C mytargetname
|
||||
# source1.vala
|
||||
# source2.vala
|
||||
# source3.vala
|
||||
# PACKAGES
|
||||
# gtk+-2.0
|
||||
# gio-1.0
|
||||
# posix
|
||||
# DIRECTORY
|
||||
# gen
|
||||
# OPTIONS
|
||||
# --thread
|
||||
# CUSTOM_VAPIS
|
||||
# some_vapi.vapi
|
||||
# GENERATE_VAPI
|
||||
# myvapi
|
||||
# GENERATE_HEADER
|
||||
# myheader
|
||||
# GENERATE_GIR
|
||||
# mygir
|
||||
# GENERATE_SYMBOLS
|
||||
# mysymbols
|
||||
# )
|
||||
#
|
||||
# Most important is the variable VALA_C which will contain all the generated c
|
||||
# file names after the call.
|
||||
##
|
||||
|
||||
macro(vala_precompile output target_name)
|
||||
parse_arguments(ARGS "TARGET;PACKAGES;OPTIONS;DIRECTORY;GENERATE_GIR;GENERATE_SYMBOLS;GENERATE_HEADER;GENERATE_VAPI;CUSTOM_VAPIS" "" ${ARGN})
|
||||
|
||||
if(ARGS_DIRECTORY)
|
||||
set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DIRECTORY})
|
||||
else(ARGS_DIRECTORY)
|
||||
set(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif(ARGS_DIRECTORY)
|
||||
include_directories(${DIRECTORY})
|
||||
set(vala_pkg_opts "")
|
||||
foreach(pkg ${ARGS_PACKAGES})
|
||||
list(APPEND vala_pkg_opts "--pkg=${pkg}")
|
||||
endforeach(pkg ${ARGS_PACKAGES})
|
||||
set(in_files "")
|
||||
set(out_files "")
|
||||
set(out_files_display "")
|
||||
set(${output} "")
|
||||
|
||||
foreach(src ${ARGS_DEFAULT_ARGS})
|
||||
string(REGEX MATCH "^/" IS_MATCHED ${src})
|
||||
if(${IS_MATCHED} MATCHES "/")
|
||||
set(src_file_path ${src})
|
||||
else()
|
||||
set(src_file_path ${CMAKE_CURRENT_SOURCE_DIR}/${src})
|
||||
endif()
|
||||
list(APPEND in_files ${src_file_path})
|
||||
string(REPLACE ".vala" ".c" src ${src})
|
||||
string(REPLACE ".gs" ".c" src ${src})
|
||||
if(${IS_MATCHED} MATCHES "/")
|
||||
get_filename_component(VALA_FILE_NAME ${src} NAME)
|
||||
set(out_file "${CMAKE_CURRENT_BINARY_DIR}/${VALA_FILE_NAME}")
|
||||
list(APPEND out_files "${CMAKE_CURRENT_BINARY_DIR}/${VALA_FILE_NAME}")
|
||||
else()
|
||||
set(out_file "${DIRECTORY}/${src}")
|
||||
list(APPEND out_files "${DIRECTORY}/${src}")
|
||||
endif()
|
||||
list(APPEND ${output} ${out_file})
|
||||
list(APPEND out_files_display "${src}")
|
||||
endforeach(src ${ARGS_DEFAULT_ARGS})
|
||||
|
||||
set(custom_vapi_arguments "")
|
||||
if(ARGS_CUSTOM_VAPIS)
|
||||
foreach(vapi ${ARGS_CUSTOM_VAPIS})
|
||||
if(${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR})
|
||||
list(APPEND custom_vapi_arguments ${vapi})
|
||||
else (${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR})
|
||||
list(APPEND custom_vapi_arguments ${CMAKE_CURRENT_SOURCE_DIR}/${vapi})
|
||||
endif(${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR})
|
||||
endforeach(vapi ${ARGS_CUSTOM_VAPIS})
|
||||
endif(ARGS_CUSTOM_VAPIS)
|
||||
|
||||
set(vapi_arguments "")
|
||||
if(ARGS_GENERATE_VAPI)
|
||||
list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_VAPI}.vapi")
|
||||
list(APPEND out_files_display "${ARGS_GENERATE_VAPI}.vapi")
|
||||
set(vapi_arguments "--library=${ARGS_GENERATE_VAPI}" "--vapi=${ARGS_GENERATE_VAPI}.vapi")
|
||||
|
||||
# Header and internal header is needed to generate internal vapi
|
||||
if (NOT ARGS_GENERATE_HEADER)
|
||||
set(ARGS_GENERATE_HEADER ${ARGS_GENERATE_VAPI})
|
||||
endif(NOT ARGS_GENERATE_HEADER)
|
||||
endif(ARGS_GENERATE_VAPI)
|
||||
|
||||
set(header_arguments "")
|
||||
if(ARGS_GENERATE_HEADER)
|
||||
list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}.h")
|
||||
list(APPEND out_files_display "${ARGS_GENERATE_HEADER}.h")
|
||||
list(APPEND header_arguments "--header=${ARGS_GENERATE_HEADER}.h")
|
||||
endif(ARGS_GENERATE_HEADER)
|
||||
|
||||
set(gir_arguments "")
|
||||
if(ARGS_GENERATE_GIR)
|
||||
list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_GIR}.gir")
|
||||
list(APPEND out_files_display "${ARGS_GENERATE_GIR}.gir")
|
||||
set(gir_arguments "--gir=${ARGS_GENERATE_GIR}.gir")
|
||||
endif(ARGS_GENERATE_GIR)
|
||||
|
||||
set(symbols_arguments "")
|
||||
if(ARGS_GENERATE_SYMBOLS)
|
||||
list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_SYMBOLS}.symbols")
|
||||
list(APPEND out_files_display "${ARGS_GENERATE_SYMBOLS}.symbols")
|
||||
set(symbols_arguments "--symbols=${ARGS_GENERATE_SYMBOLS}.symbols")
|
||||
endif(ARGS_GENERATE_SYMBOLS)
|
||||
|
||||
# Workaround for a bug that would make valac run twice. This file is written
|
||||
# after the vala compiler generates C source code.
|
||||
set(OUTPUT_STAMP ${CMAKE_CURRENT_BINARY_DIR}/${target_name}_valac.stamp)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${OUTPUT_STAMP}
|
||||
COMMAND
|
||||
${VALA_EXECUTABLE}
|
||||
ARGS
|
||||
"-C"
|
||||
${header_arguments}
|
||||
${vapi_arguments}
|
||||
${gir_arguments}
|
||||
${symbols_arguments}
|
||||
"-b" ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
"-d" ${DIRECTORY}
|
||||
${vala_pkg_opts}
|
||||
${ARGS_OPTIONS}
|
||||
${in_files}
|
||||
${custom_vapi_arguments}
|
||||
COMMAND
|
||||
touch
|
||||
ARGS
|
||||
${OUTPUT_STAMP}
|
||||
DEPENDS
|
||||
${in_files}
|
||||
${ARGS_CUSTOM_VAPIS}
|
||||
COMMENT
|
||||
"Generating ${out_files_display}"
|
||||
)
|
||||
|
||||
# This command will be run twice for some reason (pass a non-empty string to COMMENT
|
||||
# in order to see it). Since valac is not executed from here, this won't be a problem.
|
||||
add_custom_command(OUTPUT ${out_files} DEPENDS ${OUTPUT_STAMP} COMMENT "")
|
||||
endmacro(vala_precompile)
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (C) 2013 Olivier Duchateau
|
||||
|
||||
set (SYSCONFDIR ${CMAKE_INSTALL_FULL_SYSCONFDIR})
|
||||
set (XDG_CONFIG_DIR "xdg/${CMAKE_PROJECT_NAME}")
|
||||
|
||||
file (GLOB_RECURSE CONFIG_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
|
||||
list (REMOVE_ITEM CONFIG_FILES "CMakeLists.txt")
|
||||
|
||||
if (${CMAKE_INSTALL_PREFIX} STREQUAL "/usr")
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "/etc")
|
||||
endif()
|
||||
|
||||
foreach (FILE ${CONFIG_FILES})
|
||||
string (FIND ${FILE} "adblock" ADBLOCK_CONF)
|
||||
if (ADBLOCK_CONF GREATER -1)
|
||||
string (REPLACE "config" "" dirname ${FILE})
|
||||
install (FILES ${FILE}
|
||||
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/${XDG_CONFIG_DIR}/${dirname}")
|
||||
else ()
|
||||
install (FILES ${FILE}
|
||||
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/${XDG_CONFIG_DIR}")
|
||||
endif ()
|
||||
endforeach ()
|
|
@ -0,0 +1,2 @@
|
|||
[settings]
|
||||
filters=https://easylist-downloads.adblockplus.org/easylist.txt;https://easylist-downloads.adblockplus.org/easyprivacy.txt
|
|
@ -27,3 +27,10 @@ name=The Free Dictionary
|
|||
text=Dictionary, Encyclopedia and Thesaurus
|
||||
uri=http://www.thefreedictionary.com/%s
|
||||
token=fd
|
||||
|
||||
[Google Translate]
|
||||
name=Google Translate
|
||||
text=Localize text or URL
|
||||
uri=http://translate.google.com/?q=
|
||||
token=gt
|
||||
|
|
@ -1,157 +1,83 @@
|
|||
#! /bin/sh
|
||||
|
||||
# waf configure wrapper
|
||||
|
||||
# Fancy colors used to beautify the output a bit.
|
||||
#
|
||||
if [ "$NOCOLOR" ] ; then
|
||||
NORMAL=""
|
||||
BOLD=""
|
||||
RED=""
|
||||
YELLOW=""
|
||||
GREEN=""
|
||||
else
|
||||
NORMAL="\033[0m"
|
||||
BOLD="\033[1m"
|
||||
RED="\033[91m"
|
||||
YELLOW="\033[01;93m"
|
||||
GREEN="\033[92m"
|
||||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# See the file COPYING for the full license text.
|
||||
#
|
||||
#~ Usage:
|
||||
#~ ./configure [OPTIONS]
|
||||
#~ Options:
|
||||
#~ --prefix=PREFIX Installation prefix
|
||||
#~ --enable-gtk3 Use GTK+3
|
||||
#~ --disable-zeitgeist Disable Zeitgeist history integration
|
||||
#~ --enable-granite Fancy notebook and pop-overs
|
||||
#~ --enable-apidocs API documentation
|
||||
#~
|
||||
#~ Environment:
|
||||
#~ VALAC if defined the valac executable to use, for example valac-0.16
|
||||
#
|
||||
|
||||
if [ -z `command -v cmake` ]; then
|
||||
echo Fatal: cmake not installed
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EXIT_SUCCESS=0
|
||||
EXIT_FAILURE=1
|
||||
EXIT_ERROR=2
|
||||
EXIT_BUG=10
|
||||
while [ $# != 0 ]; do
|
||||
case $1 in
|
||||
--enable-gtk3)
|
||||
ARGS="$ARGS -DUSE_GTK3=1";;
|
||||
--disable-zeitgeist)
|
||||
ARGS="$ARGS -DUSE_ZEITGEIST=0";;
|
||||
--enable-granite)
|
||||
ARGS="$ARGS -DUSE_GRANITE=1";;
|
||||
--enable-apidocs)
|
||||
ARGS="$ARGS -DUSE_APIDOCS=1";;
|
||||
--extra-warnings)
|
||||
ARGS="$ARGS -DEXTRA_WARNINGS=1";;
|
||||
--prefix=*)
|
||||
ARGS="$ARGS -DCMAKE_INSTALL_PREFIX=${1#*=}";;
|
||||
*)
|
||||
grep -e '^#~' $0 | sed s/#~//
|
||||
exit
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
CUR_DIR=$PWD
|
||||
BUILD_DIR="_build"
|
||||
|
||||
#possible relative path
|
||||
WORKINGDIR=`dirname $0`
|
||||
cd $WORKINGDIR
|
||||
#abs path
|
||||
WORKINGDIR=`pwd`
|
||||
cd $CUR_DIR
|
||||
|
||||
# Checks for Python interpreter. Honours $PYTHON if set. Stores path to
|
||||
# interpreter in $PYTHON.
|
||||
#
|
||||
checkPython()
|
||||
{
|
||||
if [ -z "$PYTHON" ] ; then
|
||||
PYTHON=`which python2 2>/dev/null`
|
||||
fi
|
||||
if [ -z "$PYTHON" ] ; then
|
||||
PYTHON=`which python 2>/dev/null`
|
||||
fi
|
||||
printf "Checking for Python\t\t\t: "
|
||||
if [ ! -x "$PYTHON" ] ; then
|
||||
printf $RED"not found!"$NORMAL"\n"
|
||||
echo "Please make sure that the Python interpreter is available in your PATH"
|
||||
echo "or invoke configure using the PYTHON flag, e.g."
|
||||
echo "$ PYTHON=/usr/local/bin/python configure"
|
||||
exit $EXIT_FAILURE
|
||||
fi
|
||||
printf $GREEN"$PYTHON"$NORMAL"\n"
|
||||
}
|
||||
|
||||
# Checks for WAF. Honours $WAF if set. Stores path to 'waf' in $WAF.
|
||||
# Requires that $PYTHON is set.
|
||||
#
|
||||
checkWAF()
|
||||
{
|
||||
printf "Checking for WAF\t\t\t: "
|
||||
#installed miniwaf in sourcedir
|
||||
if [ -z "$WAF" ] ; then
|
||||
if [ -f "${WORKINGDIR}/waf" ] ; then
|
||||
WAF="${WORKINGDIR}/waf"
|
||||
if [ ! -x "$WAF" ] ; then
|
||||
chmod +x $WAF
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ -z "$WAF" ] ; then
|
||||
if [ -f "${WORKINGDIR}/waf-light" ] ; then
|
||||
${WORKINGDIR}/waf-light --make-waf
|
||||
WAF="${WORKINGDIR}/waf"
|
||||
fi
|
||||
fi
|
||||
#global installed waf with waf->waf.py link
|
||||
if [ -z "$WAF" ] ; then
|
||||
WAF=`which waf 2>/dev/null`
|
||||
fi
|
||||
# neither waf nor miniwaf could be found
|
||||
if [ ! -x "$WAF" ] ; then
|
||||
printf $RED"not found"$NORMAL"\n"
|
||||
echo "Go to http://code.google.com/p/waf/"
|
||||
echo "and download a waf version"
|
||||
exit $EXIT_FAILURE
|
||||
else
|
||||
printf $GREEN"$WAF"$NORMAL"\n"
|
||||
fi
|
||||
WAF="$PYTHON $WAF"
|
||||
}
|
||||
|
||||
# Generates a Makefile. Requires that $WAF is set.
|
||||
#
|
||||
generateMakefile()
|
||||
{
|
||||
cat > Makefile << EOF
|
||||
#!/usr/bin/make -f
|
||||
# Waf Makefile wrapper
|
||||
WAF_HOME=$CUR_DIR
|
||||
|
||||
all:
|
||||
@$WAF build
|
||||
|
||||
all-debug:
|
||||
@$WAF -v build
|
||||
|
||||
all-progress:
|
||||
@$WAF -p build
|
||||
|
||||
install:
|
||||
@if test -n "\$(DESTDIR)"; then \\
|
||||
$WAF install --destdir="\$(DESTDIR)"; \\
|
||||
else \\
|
||||
$WAF install; \\
|
||||
fi;
|
||||
|
||||
.PHONY: install
|
||||
|
||||
uninstall:
|
||||
@if test -n "\$(DESTDIR)"; then \\
|
||||
$WAF uninstall --destdir="\$(DESTDIR)"; \\
|
||||
else \\
|
||||
$WAF uninstall; \\
|
||||
fi;
|
||||
|
||||
clean:
|
||||
@$WAF clean
|
||||
|
||||
distclean:
|
||||
@$WAF distclean
|
||||
@-rm -rf _build_
|
||||
@-rm -f Makefile
|
||||
|
||||
check:
|
||||
@$WAF check
|
||||
|
||||
dist:
|
||||
@$WAF dist
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
checkPython
|
||||
checkWAF
|
||||
|
||||
echo "calling waf configure with parameters"
|
||||
$WAF configure $* || exit $EXIT_ERROR
|
||||
|
||||
if [ -f "Makefile" ] ; then
|
||||
echo ""
|
||||
else
|
||||
generateMakefile
|
||||
if [ ! -f GNUmakefile ]; then
|
||||
cp -v GNUmakefile.in GNUmakefile || exit 1
|
||||
fi
|
||||
|
||||
exit $EXIT_SUCCESS
|
||||
# cmake was invoked in toplevel folder before
|
||||
# clean up cmake generated build files to prevent conflicts
|
||||
if [ -f CMakeCache.txt ]; then
|
||||
echo
|
||||
echo '####################################################################################'
|
||||
echo 'CMake build files detected in toplevel folder !!'
|
||||
echo 'Please always run "cmake" command from distinct folder when you use cmake yourself.'
|
||||
echo '####################################################################################'
|
||||
echo
|
||||
echo 'Cleaning up...'
|
||||
echo
|
||||
|
||||
rm -fr $BUILD_DIR
|
||||
rm CMakeCache.txt config.h Makefile
|
||||
find . -iname CMakeFiles -type d|xargs rm -fr
|
||||
find . -iname cmake_install.cmake -exec rm {} \;
|
||||
find . -iname CTestTestfile.cmake -exec rm {} \;
|
||||
|
||||
find . -iname *-folders -type d|xargs rm -fr
|
||||
rm -fr data/logo-shade
|
||||
fi
|
||||
|
||||
mkdir -p $BUILD_DIR && cd $BUILD_DIR || exit 1
|
||||
cmake $ARGS .. || exit 1
|
||||
|
||||
echo
|
||||
echo "Configuring done, run \"make\" to compile"
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
include(FindConvert)
|
||||
if (NOT CONVERT_FOUND)
|
||||
message(FATAL_ERROR "rsvg-convert not found")
|
||||
endif ()
|
||||
|
||||
include(FindIntltool)
|
||||
if (NOT INTLTOOL_MERGE_FOUND)
|
||||
message(FATAL_ERROR "intltool-merge not found")
|
||||
elseif (NOT INTLTOOL_UPDATE_FOUND)
|
||||
message(FATAL_ERROR "intltool-update not found")
|
||||
endif ()
|
||||
|
||||
file(GLOB_RECURSE DATA_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
|
||||
list(REMOVE_ITEM DATA_FILES "CMakeLists.txt")
|
||||
|
||||
foreach(FILE ${DATA_FILES})
|
||||
if (${FILE} MATCHES "faq.")
|
||||
install(FILES ${FILE} DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
elseif (${FILE} MATCHES ".desktop")
|
||||
if (NOT WIN32)
|
||||
string(REPLACE ".desktop.in" "" DESKTOP_ID ${FILE})
|
||||
INTLTOOL_MERGE_DESKTOP (${DESKTOP_ID} po)
|
||||
endif ()
|
||||
elseif (${FILE} MATCHES ".appdata.xml")
|
||||
if (NOT WIN32)
|
||||
string(REPLACE ".appdata.xml.in" "" DESKTOP_ID ${FILE})
|
||||
INTLTOOL_MERGE_APPDATA (${DESKTOP_ID} po)
|
||||
endif ()
|
||||
elseif (${FILE} MATCHES "\\.svg$")
|
||||
string(REPLACE ".svg" "" IMG_ID ${FILE})
|
||||
string (FIND ${FILE} "/" IS_DIR)
|
||||
if (IS_DIR GREATER -1)
|
||||
string(REPLACE "/" ";" DIR_LIST ${FILE})
|
||||
LIST(GET DIR_LIST 0 S_DIR)
|
||||
SVG2PNG (${IMG_ID} "${CMAKE_INSTALL_DATADIR}/midori/res/${S_DIR}")
|
||||
else ()
|
||||
SVG2PNG (${IMG_ID} "${CMAKE_INSTALL_DATADIR}/midori/res/")
|
||||
endif()
|
||||
# These are being handled in add_executable for the "midori" binary
|
||||
elseif (${FILE} MATCHES "\\.ico$")
|
||||
elseif (${FILE} MATCHES "\\.rc$")
|
||||
# This is only meant for testing, and not used in production
|
||||
elseif (${FILE} MATCHES "\\.swf$")
|
||||
else()
|
||||
string(FIND ${FILE} "/" IS_DIR)
|
||||
if (IS_DIR GREATER -1)
|
||||
string(REPLACE "/" ";" DIR_LIST ${FILE})
|
||||
LIST(GET DIR_LIST 0 S_DIR)
|
||||
LIST(GET DIR_LIST 1 S_FILE)
|
||||
install(FILES ${S_DIR}/${S_FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/midori/res/${S_DIR})
|
||||
else ()
|
||||
install(FILES ${FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/midori/res/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach()
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
about: page style template for Midori.
|
||||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
*/
|
||||
body {
|
||||
background-color: #dedede;
|
||||
color: #222222;
|
||||
font-family: 'Open Sans', 'Droid Sans', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: normal;
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] #icon {
|
||||
float: right;
|
||||
padding-right: 1%;
|
||||
}
|
||||
|
||||
.indent {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
#main {
|
||||
max-width: 50%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
min-width: 480px;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid rgba(0, 0, 0, .3);
|
||||
padding: 25px;
|
||||
-webkit-border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1);
|
||||
background-position-x: 22px;
|
||||
background-position-y: 54px;
|
||||
}
|
||||
|
||||
#text {
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Open Sans', 'Droid Sans', arial, sans-serif;
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: 300;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
html[dir="ltr"] #logo {
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] #logo {
|
||||
left: 15px;
|
||||
}
|
||||
|
||||
button span,
|
||||
button img {
|
||||
vertical-align: middle;
|
||||
padding: 2px 1px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.message {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#suggestions {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#button {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#logo {
|
||||
position: absolute; bottom: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 0px;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
[Adblock Plus 2.0]
|
||||
! Version: 201402142200
|
||||
! Title: Exercise
|
||||
! Last modified: 11 Feb 2014 22:00 UTC
|
||||
! Expires: 3 days (update frequency)
|
||||
! Homepage: http://www.midori-browser.org
|
||||
! Licence: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
|
||||
! Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
!
|
||||
! Some freeform text:
|
||||
! Yadayada http://example.com/ e-mail (somebody@example.com).
|
||||
!
|
||||
!-----Spam eggs--------!
|
||||
! *** la:le/lu_foo_bar.txt ***
|
||||
|/http://ads.blub.boing/*$domain=xxx.com
|
||||
|/http://ads.blub.boing/*$domain=xxx.com,foo.fr,coco.at
|
||||
/market.php?$domain=adf.ly|foo.com
|
||||
/?placement=$script,domain=putlocker.com|sockshare.com
|
||||
|
||||
! Some basic filters
|
||||
*ads.foo.bar*
|
||||
*ads.bogus.name*
|
||||
||^http://ads.bla.blub/*
|
||||
engine.adct.ru/*?
|
||||
/addyn|*|adtech;
|
||||
doubleclick.net/pfadx/*.mtvi
|
||||
objects.tremormedia.com/embed/xml/*.xml?r=
|
||||
videostrip.com^*/admatcherclient.
|
||||
test.dom/test?var
|
||||
/adpage.
|
||||
br.gcl.ru/cgi-bin/br/
|
||||
_300x600.
|
||||
_rectangle_ads.
|
||||
+adverts/
|
||||
-2/ads/
|
||||
|
||||
! CSS elements
|
||||
old.tv,delicio.us,longc.at###box
|
||||
##.zRightAdNote
|
||||
###advertisingModule160x600
|
||||
##a[href$="/vghd.shtml"]
|
||||
imagetwist.com###left[align="center"] > center > a[target="_blank"]
|
||||
|
||||
! Options
|
||||
||videobox.com/?tid=$popup
|
||||
||sexsearchcom.com^$popup,third-party
|
||||
||206.217.206.137^$third-party
|
||||
/spopunder^$popup
|
||||
||putlocker.com^*.php?*title$subdocument
|
||||
://ads.$popup
|
||||
|
||||
! Whitelist
|
||||
@@||hortifor.com/images/*120x60$~third-party
|
||||
@@||stickam.com/wb/www/category/300x250/$image
|
||||
@@||adultadworld.com/adhandler/$subdocument
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 2014 Alexander V. Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
function getElementsByAttribute (strTagName, strAttributeName, arrAttributeValue) {
|
||||
var arrElements = document.getElementsByTagName (strTagName);
|
||||
var arrReturnElements = new Array();
|
||||
for (var j=0; j<arrAttributeValue.length; j++) {
|
||||
var strAttributeValue = arrAttributeValue[j];
|
||||
for (var i=0; i<arrElements.length; i++) {
|
||||
var oCurrent = arrElements[i];
|
||||
var oAttribute = oCurrent.getAttribute && oCurrent.getAttribute (strAttributeName);
|
||||
if (oAttribute && oAttribute.length > 0 && strAttributeValue.indexOf (oAttribute) != -1)
|
||||
arrReturnElements.push (oCurrent);
|
||||
}
|
||||
}
|
||||
return arrReturnElements;
|
||||
};
|
||||
|
||||
function hideElementBySrc (uris) {
|
||||
var oElements = getElementsByAttribute('img', 'src', uris);
|
||||
if (oElements.length == 0)
|
||||
oElements = getElementsByAttribute ('iframe', 'src', uris);
|
||||
for (var i=0; i<oElements.length; i++) {
|
||||
oElements[i].style.visibility = 'hidden !important';
|
||||
oElements[i].style.width = '0';
|
||||
oElements[i].style.height = '0';
|
||||
}
|
||||
};
|
|
@ -1,7 +1,15 @@
|
|||
/**
|
||||
* An autosuggest textbox control.
|
||||
* from Nicholas C. Zakas (Author) example: http://www.nczonline.net/
|
||||
* Adopted for Midori by Alexander V. Butenko <a.butenka@gmail.com>
|
||||
/*
|
||||
An autosuggest textbox control.
|
||||
Copyright (C) 2012 Nicholas C. Zakas (Author) example: http://www.nczonline.net/
|
||||
Adopted for Midori by Alexander V. Butenko <a.butenka@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of the Nicholas C. Zakas nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
|
||||
|
@ -186,10 +194,10 @@ AutoSuggestControl.prototype.init = function () {
|
|||
};
|
||||
|
||||
//assign onblur event handler (hides suggestions)
|
||||
this.textbox.onblur =
|
||||
this.textbox.onclick = function () {
|
||||
oThis.hideSuggestions();
|
||||
};
|
||||
if (!this.textbox.onblur)
|
||||
this.textbox.onblur = function () { oThis.hideSuggestions(); };
|
||||
if (!this.textbox.onclick)
|
||||
this.textbox.onclick = function () { oThis.hideSuggestions(); };
|
||||
|
||||
//create the suggestions dropdown
|
||||
this.createDropDown();
|
||||
|
@ -299,7 +307,7 @@ function initSuggestions () {
|
|||
if (inputs.length == 0)
|
||||
return false;
|
||||
|
||||
for (i=0;i<inputs.length;i++)
|
||||
for (var i=0;i<inputs.length;i++)
|
||||
{
|
||||
var ename = inputs[i].getAttribute("name");
|
||||
var eid = inputs[i].getAttribute("id");
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
CREATE TABLE IF NOT EXISTS bookmarks
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
parentid INTEGER DEFAULT NULL,
|
||||
title TEXT,
|
||||
uri TEXT,
|
||||
desc TEXT,
|
||||
app INTEGER,
|
||||
toolbar INTEGER,
|
||||
pos_panel INTEGER,
|
||||
pos_bar INTEGER,
|
||||
created DATE DEFAULT CURRENT_TIMESTAMP,
|
||||
last_visit DATE,
|
||||
visit_count INTEGER DEFAULT 0,
|
||||
nick TEXT,
|
||||
|
||||
FOREIGN KEY(parentid) REFERENCES bookmarks(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
/* trigger: insert panel position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosPanel
|
||||
AFTER INSERT ON bookmarks FOR EACH ROW
|
||||
BEGIN UPDATE bookmarks SET pos_panel = (
|
||||
SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks WHERE
|
||||
(NEW.parentid IS NOT NULL AND parentid = NEW.parentid)
|
||||
OR (NEW.parentid IS NULL AND parentid IS NULL))
|
||||
WHERE id = NEW.id; END;
|
||||
|
||||
/* trigger: insert Bookmarkbar position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosBar
|
||||
AFTER INSERT ON bookmarks FOR EACH ROW WHEN NEW.toolbar=1
|
||||
BEGIN UPDATE bookmarks SET pos_bar = (
|
||||
SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE
|
||||
((NEW.parentid IS NOT NULL AND parentid = NEW.parentid)
|
||||
OR (NEW.parentid IS NULL AND parentid IS NULL)) AND toolbar=1)
|
||||
WHERE id = NEW.id; END;
|
||||
|
||||
/* trigger: update panel position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosPanel
|
||||
BEFORE UPDATE OF parentid ON bookmarks FOR EACH ROW
|
||||
WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL)
|
||||
AND NEW.parentid IS NOT OLD.parentid) OR
|
||||
((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL)
|
||||
AND NEW.parentid!=OLD.parentid)
|
||||
BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1
|
||||
WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid)
|
||||
OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel;
|
||||
UPDATE bookmarks SET pos_panel = (
|
||||
SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks
|
||||
WHERE (NEW.parentid IS NOT NULL AND parentid = NEW.parentid)
|
||||
OR (NEW.parentid IS NULL AND parentid IS NULL))
|
||||
WHERE id = OLD.id; END;
|
||||
|
||||
/* trigger: update Bookmarkbar position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar0
|
||||
AFTER UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW
|
||||
WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL)
|
||||
AND NEW.parentid IS NOT OLD.parentid)
|
||||
OR ((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL)
|
||||
AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=1 AND NEW.toolbar=0)
|
||||
BEGIN UPDATE bookmarks SET pos_bar = NULL WHERE id = NEW.id;
|
||||
UPDATE bookmarks SET pos_bar = pos_bar-1
|
||||
WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid)
|
||||
OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;
|
||||
|
||||
/* trigger: update Bookmarkbar position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar1
|
||||
BEFORE UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW
|
||||
WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL)
|
||||
AND NEW.parentid IS NOT OLD.parentid) OR
|
||||
((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL)
|
||||
AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=0 AND NEW.toolbar=1)
|
||||
BEGIN UPDATE bookmarks SET pos_bar = (
|
||||
SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE
|
||||
(NEW.parentid IS NOT NULL AND parentid = NEW.parentid)
|
||||
OR (NEW.parentid IS NULL AND parentid IS NULL))
|
||||
WHERE id = OLD.id; END;
|
||||
|
||||
/* trigger: delete panel position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosPanel
|
||||
AFTER DELETE ON bookmarks FOR EACH ROW
|
||||
BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1
|
||||
WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid)
|
||||
OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; END;
|
||||
|
||||
/* trigger: delete Bookmarkbar position */
|
||||
CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosBar
|
||||
AFTER DELETE ON bookmarks FOR EACH ROW WHEN OLD.toolbar=1
|
||||
BEGIN UPDATE bookmarks SET pos_bar = pos_bar-1
|
||||
WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid)
|
||||
OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;
|
|
@ -0,0 +1,6 @@
|
|||
INSERT INTO main.bookmarks (parentid, title, uri, desc, app, toolbar)
|
||||
SELECT NULL AS parentid, title, uri, desc, app, toolbar
|
||||
FROM old_db.bookmarks;
|
||||
UPDATE main.bookmarks SET parentid = (
|
||||
SELECT id FROM main.bookmarks AS b1 WHERE b1.title = (
|
||||
SELECT folder FROM old_db.bookmarks WHERE title = main.bookmarks.title));
|
BIN
data/close.png
BIN
data/close.png
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,3 +0,0 @@
|
|||
[D-BUS Service]
|
||||
Name=com.nokia.midori
|
||||
Exec=/usr/bin/midori
|
|
@ -2,84 +2,29 @@
|
|||
Error page template for Midori.
|
||||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<html dir="{dir}">
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<link rel="shortcut icon" href="{icon}" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
background: #f6fff3;
|
||||
min-width: 70%;
|
||||
max-width: 70%;
|
||||
margin: 2em auto 1em;
|
||||
padding: 1em;
|
||||
border: 0.2em solid #9acb7f;
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
icon {
|
||||
float: left;
|
||||
padding-left: 1%;
|
||||
padding-top: 1%;
|
||||
}
|
||||
|
||||
#main {
|
||||
float: right;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#logo {
|
||||
position: absolute; right: 15px; bottom: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
button span,
|
||||
button img {
|
||||
vertical-align: middle;
|
||||
padding: 2px 1px;
|
||||
}
|
||||
|
||||
message {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
description {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
</style>
|
||||
{favicon}
|
||||
<link rel="stylesheet" type="text/css" href="res://about.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<img id="logo" src="res://logo-shade.png" />
|
||||
<img id="icon" src="stock://gtk-dialog-error" />
|
||||
<div id="main">
|
||||
<h1>{title}</h1>
|
||||
<p id="message">{message}</p>
|
||||
<p id="description">{description}</p>
|
||||
<form method="GET" action="{uri}">
|
||||
<button type="submit" onclick="location.reload(); return false;">
|
||||
<img src="stock://gtk-refresh"/>
|
||||
<img id="logo" src="res://logo-shade.png" />
|
||||
<div id="main" style="background-image: url({error_icon});">
|
||||
<div id="text">
|
||||
<h1>{title}</h1>
|
||||
<p class="message">{message}<br><i>{description}</i></p>
|
||||
{suggestions}
|
||||
</div>
|
||||
<form method="GET" action="{uri}" id="button">
|
||||
<button type="submit" onclick="location.reload(); return false;" {autofocus}>
|
||||
<img style="{hide-button-images}" src="stock://gtk-refresh"/>
|
||||
<span>{tryagain}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<br style="clear: both;"/>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<br style="clear: both;"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[settings]
|
||||
filters=http://adblockplus.mozdev.org/easylist/easylist.txt;https://easylist-downloads.adblockplus.org/easyprivacy.txt
|
61
data/faq.css
61
data/faq.css
|
@ -8,29 +8,64 @@ Stylesheet for Midori's documentation based on a version of Enrico Troeger.
|
|||
|
||||
@media screen {
|
||||
|
||||
body {
|
||||
background-color: #f6fff3;
|
||||
color: #404040;
|
||||
margin-left: 0.4em;
|
||||
width: 60em;
|
||||
font-size: 90%;
|
||||
html, body {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #013100;
|
||||
* {
|
||||
background: #f6fff3 !important;
|
||||
color: #404040 !important;
|
||||
font-size: 14pt !important;
|
||||
font-family: serif !important;
|
||||
text-align: justify !important;
|
||||
line-height: 1.4em !important;
|
||||
word-spacing: 0.4mm !important;
|
||||
letter-spacing: 0.2mm !important;
|
||||
-webkit-column-count: auto !important;
|
||||
-webkit-column-width: auto !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
width: auto !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #7E558E;
|
||||
div, p {
|
||||
padding: 5pt !important;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-left: 5pt !important;
|
||||
}
|
||||
|
||||
img, *[accesskey], form *, form, iframe,
|
||||
*[id^=navigation], *[id$=navigation], *[id*=navigation], .collapsed, .expanded {
|
||||
display: none !important
|
||||
}
|
||||
|
||||
/* FIXME: we want "images bigger than 50px here" */
|
||||
img[width] {
|
||||
display: inline !important
|
||||
}
|
||||
|
||||
:link, :link * {
|
||||
color: #013100 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
:visited, :visited * {
|
||||
color: #7E558E !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: sans-serif;
|
||||
color: #002a00;
|
||||
font-family: serif !important;
|
||||
color: #002a00 !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
|
905
data/faq.html
905
data/faq.html
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE IF NOT EXISTS tasks
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
once INTEGER DEFAULT 1,
|
||||
command TEXT DEFAULT NULL
|
||||
);
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE IF NOT EXISTS forms
|
||||
(
|
||||
domain text,
|
||||
field text,
|
||||
value text
|
||||
)
|
|
@ -0,0 +1,29 @@
|
|||
.notebook tab .button {
|
||||
-GtkButton-default-border: 0;
|
||||
-GtkButton-default-outside-border: 0;
|
||||
-GtkButton-inner-border: 0;
|
||||
-GtkWidget-focus-line-width: 0;
|
||||
-GtkWidget-focus-padding: 0;
|
||||
padding: 0;
|
||||
border-width: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
GtkOverlay > * {
|
||||
padding: 4px;
|
||||
border-style: solid;
|
||||
border-radius: 0 5px 0 0;
|
||||
border-width: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
GtkOverlay MidoriFindbar {
|
||||
border-radius: 0 0 0 5px;
|
||||
border-width: 0 0 1px 1px; /* top right bottom left */
|
||||
}
|
||||
|
||||
/* Kill grey backround on inactive buttons */
|
||||
GtkDrawingArea,
|
||||
GtkImage,
|
||||
GtkImage:insensitive,
|
||||
GtkImage:selected {
|
||||
background-color: @transparent;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
CREATE TABLE IF NOT EXISTS history
|
||||
(
|
||||
uri text,
|
||||
title text,
|
||||
date integer,
|
||||
day integer
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS search
|
||||
(
|
||||
keywords text,
|
||||
uri text,
|
||||
day integer
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TEMPORARY TABLE backup
|
||||
(
|
||||
uri text,
|
||||
title text,
|
||||
date integer
|
||||
);
|
||||
INSERT INTO backup SELECT uri, title, date FROM history;
|
||||
DROP TABLE history;
|
||||
CREATE TABLE history (uri text, title text, date integer, day integer);
|
||||
INSERT INTO history SELECT uri, title, date,
|
||||
julianday(date(date,'unixepoch','start of day','+1 day'))
|
||||
- julianday('0001-01-01','start of day')
|
||||
FROM backup;
|
||||
DROP TABLE backup;
|
|
@ -9,6 +9,7 @@ Exec=midori --private %U
|
|||
Icon=midori
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
NotShowIn=Pantheon;
|
||||
X-Osso-Type=application/x-executable
|
||||
X-Osso-Service=midori
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2013 Christian Dywan -->
|
||||
<application>
|
||||
<id type="desktop">midori.desktop</id>
|
||||
<licence>CC0</licence>
|
||||
<description>
|
||||
<p>
|
||||
Midori is a fast little WebKit browser with support for HTML5. It can manage
|
||||
many open tabs and windows. The URL bar completes history, bookmarks, search
|
||||
engines and open tabs out of the box. Web developers can use the powerful
|
||||
web inspector that is a part of WebKit. Individual pages can easily be turned
|
||||
into web apps and new profiles can be created on demand.
|
||||
</p>
|
||||
<p>A number of extensions are included by default:</p>
|
||||
<ul>
|
||||
<li>Adblock with support for ABP filter lists and custom rules is built-in</li>
|
||||
<li>You can download files with Aria2 or SteadyFlow</li>
|
||||
<li>User scripts and styles support a la Greasemonkey</li>
|
||||
<li>Managing cookies and scripts via NoJS and Cookie Security Manager</li>
|
||||
<li>Switching open tabs in a vertical panel or a popup window</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url type="homepage">http://www.midori-browser.org/</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">http://www.midori-browser.org/images/screenshots/rdio.png</screenshot>
|
||||
</screenshots>
|
||||
<updatecontact>christian@twotoasts.de</updatecontact>
|
||||
</application>
|
|
@ -3,7 +3,8 @@ Version=1.0
|
|||
Type=Application
|
||||
_Name=Midori
|
||||
_GenericName=Web Browser
|
||||
_Comment=Lightweight web browser
|
||||
_X-GNOME-Fullname=Midori Web Browser
|
||||
_Comment=Browse the Web
|
||||
_X-GNOME-Keywords=Internet;WWW;Explorer
|
||||
_X-AppInstall-Keywords=Internet;WWW;Explorer
|
||||
Categories=GTK;Network;WebBrowser;
|
||||
|
@ -12,22 +13,20 @@ Exec=midori %U
|
|||
Icon=midori
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
X-GNOME-UsesNotifications=true
|
||||
X-Osso-Type=application/x-executable
|
||||
X-Osso-Service=midori
|
||||
X-Ayatana-Desktop-Shortcuts=TabNew;WindowNew;Private
|
||||
Actions=TabNew;WindowNew;Private;
|
||||
|
||||
[TabNew Shortcut Group]
|
||||
Name=New _Tab
|
||||
[Desktop Action TabNew]
|
||||
_Name=New Tab
|
||||
Exec=midori -e TabNew
|
||||
TargetEnvironment=Unity
|
||||
|
||||
[WindowNew Shortcut Group]
|
||||
Name=New _Window
|
||||
[Desktop Action WindowNew]
|
||||
_Name=New Window
|
||||
Exec=midori -e WindowNew
|
||||
TargetEnvironment=Unity
|
||||
|
||||
[Private Shortcut Group]
|
||||
Name=New P_rivate Browsing Window
|
||||
[Desktop Action Private]
|
||||
_Name=New Private Browsing Window
|
||||
Exec=midori --private
|
||||
TargetEnvironment=Unity
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 444 B |
Binary file not shown.
After Width: | Height: | Size: 605 B |
Binary file not shown.
After Width: | Height: | Size: 630 B |
|
@ -0,0 +1,8 @@
|
|||
CREATE TABLE IF NOT EXISTS notes
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
uri TEXT,
|
||||
title TEXT,
|
||||
note_content TEXT,
|
||||
tstamp INTEGER
|
||||
);
|
|
@ -27,6 +27,7 @@
|
|||
cursor: default;
|
||||
font-size: 13px;
|
||||
color: #4d4d4d;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
@ -34,7 +35,11 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
outline: 0;
|
||||
background: #E1E1E1;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
#content {
|
||||
|
@ -55,51 +60,102 @@
|
|||
width: 85%;
|
||||
height: 75%;
|
||||
margin: auto;
|
||||
-webkit-box-shadow: 0 4px 18px rgba(0,0,0,.3), 0 0 2px #fff inset;
|
||||
background-image: -webkit-gradient(
|
||||
linear, center top, center bottom,
|
||||
from(#f6f6f6), to(#e3e3e3));
|
||||
border: 1px solid #bcbcbc;
|
||||
border-bottom-color: #a0a0a0;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12),
|
||||
0 1px 2px rgba(0,0,0,0.24);
|
||||
position: relative;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
transition: all 200ms ease-in-out;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.shortcut .preview img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
div.shortcut .preview.new {
|
||||
background-color: rgba(0,0,0,0.05);
|
||||
border: 1px solid rgba(0,0,0,0.15);
|
||||
|
||||
box-shadow: inset 0 0 1px 1px rgba(0,0,0,0.05),
|
||||
0 1px 0 0 rgba(255,255,255,0.40);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.shortcut .preview.new .add {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
background-color: #777;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
text-align: center;
|
||||
border-radius: 32px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -32px;
|
||||
margin-top: -32px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12),
|
||||
0 1px 2px rgba(0,0,0,0.24);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.shortcut .preview.new .add:after {
|
||||
content: "+";
|
||||
color: #fff;
|
||||
font-size: 48px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.title {
|
||||
background: transparent;
|
||||
border: 2px solid transparent;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 8px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
cursor: text;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.5);
|
||||
outline: none;
|
||||
transition: all 200ms ease-in-out;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.preview.new ~ .title {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.title.active {
|
||||
border-bottom-color: #4CAF50;
|
||||
}
|
||||
|
||||
.cross {
|
||||
color: #fff;
|
||||
display: block;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
top: -14px;
|
||||
right: -14px;
|
||||
background: url(res://close.png);
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
background-color: #555;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12),
|
||||
0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.cross:after {
|
||||
content: '+';
|
||||
-webkit-transform: rotate(45deg);
|
||||
font-size: 22px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div.shortcut .preview:hover .cross {
|
||||
|
@ -111,95 +167,185 @@
|
|||
display:none;
|
||||
}
|
||||
|
||||
div.osd {
|
||||
top: 9px;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.osd span {
|
||||
border: 1px solid #999;
|
||||
background-color: #f5f5f5;
|
||||
padding: 8px;
|
||||
color: #999;
|
||||
-webkit-border-bottom-left-radius: 10px;
|
||||
visibility: hidden;
|
||||
.selectable {
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
var previousName = "";
|
||||
|
||||
var getAction = function (id)
|
||||
{
|
||||
var s = document.getElementById(id).childNodes[0];
|
||||
if (s.className == 'preview')
|
||||
return true;
|
||||
function input_key_down (ev) {
|
||||
// 13 is the key code for enter
|
||||
if(ev.keyCode == 13) ev.target.blur();
|
||||
// 27 is the key code for escape
|
||||
if(ev.keyCode == 27) {
|
||||
ev.target.value = previousName;
|
||||
ev.target.blur();
|
||||
}
|
||||
}
|
||||
|
||||
function add_tile (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var url = prompt ("{enter_shortcut_address}", "http://");
|
||||
if (!url) return false;
|
||||
if (!url)
|
||||
return false;
|
||||
|
||||
if (url.indexOf ("://") == -1)
|
||||
url = "http://" + url;
|
||||
|
||||
console.log ("speed_dial-save-add " + id + " " + url + " ");
|
||||
return false;
|
||||
var id = ev.target.parentNode.parentNode.id;
|
||||
console.log ("speed_dial-save-add " + id + " " + url);
|
||||
}
|
||||
|
||||
var renameShortcut = function (id)
|
||||
{
|
||||
var old_name = document.getElementById(id).childNodes[1].textContent;
|
||||
|
||||
var name = prompt ("{enter_shortcut_name}", old_name);
|
||||
if (!name) return;
|
||||
function done_editing_title (ev) {
|
||||
input = ev.target;
|
||||
input.className = "title";
|
||||
|
||||
var name = ev.target.value;
|
||||
if (name == "")
|
||||
name = previousName;
|
||||
var id = ev.target.parentNode.id;
|
||||
console.log ("speed_dial-save-rename " + id + " " + name);
|
||||
}
|
||||
|
||||
var clearShortcut = function (id)
|
||||
{
|
||||
if(!confirm("{are_you_sure}"))
|
||||
function editing_tile (ev) {
|
||||
input = ev.target;
|
||||
previousName = input.value;
|
||||
// indicate to user they are editing the title
|
||||
input.className = input.className + " active";
|
||||
}
|
||||
|
||||
function delete_tile (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
if (!confirm("{are_you_sure}"))
|
||||
return;
|
||||
|
||||
var id = ev.target.parentNode.parentNode.id;
|
||||
console.log ("speed_dial-save-delete " + id);
|
||||
}
|
||||
|
||||
var key_id = 's';
|
||||
var key_timeout;
|
||||
var firstNode, secondNode;
|
||||
var cursor;
|
||||
|
||||
document.onkeypress = function ()
|
||||
{
|
||||
key_id = key_id + String.fromCharCode (event.which);
|
||||
|
||||
clearTimeout (key_timeout);
|
||||
|
||||
document.getElementById('dialing').innerText = key_id.substr(1);
|
||||
document.getElementById('dialing').style.visibility = 'visible';
|
||||
|
||||
var div = document.getElementById(key_id);
|
||||
if (div)
|
||||
{
|
||||
if (key_id.substr(1) > 9)
|
||||
{
|
||||
if (getAction (key_id))
|
||||
document.location = div.childNodes[0].childNodes[1].href;
|
||||
key_id = 's';
|
||||
}
|
||||
else
|
||||
key_timeout = setTimeout ('if (getAction (key_id)) document.location = document.getElementById(key_id).childNodes[0].childNodes[1].href; key_id = \'s\'', 1000);
|
||||
}
|
||||
else
|
||||
key_id = 's';
|
||||
|
||||
if (key_id.length <= 1)
|
||||
document.getElementById('dialing').style.visibility = 'hidden';
|
||||
|
||||
return false;
|
||||
var get_dial_div = function (ele) {
|
||||
var dial_div;
|
||||
if (ele.nodeName == 'IMG')
|
||||
dial_div = ele.parentNode.parentNode.parentNode;
|
||||
if (ele.className == 'title')
|
||||
dial_div = ele.parentNode;
|
||||
if (ele.className.indexOf ('shortcut') != -1)
|
||||
dial_div = ele;
|
||||
return dial_div;
|
||||
}
|
||||
|
||||
function click (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
/* If the target of the event is an element of class title
|
||||
* and not also of class add-shortcut we are editing title
|
||||
*/
|
||||
var classes = ev.target.className.split(" ");
|
||||
var edit_title = false;
|
||||
for (var i = 0; i < classes.length; i++) {
|
||||
if(classes[i] == "add-shortcut") {
|
||||
edit_title = false;
|
||||
break;
|
||||
}
|
||||
if(classes[i] == "title")
|
||||
edit_title = true;
|
||||
}
|
||||
|
||||
if(edit_title)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
var ele = ev.target;
|
||||
cursor = ele.style.cursor;
|
||||
ele.style.cursor = 'move';
|
||||
|
||||
var eparent = get_dial_div (ele);
|
||||
if (eparent != undefined) {
|
||||
eparent.className = 'shortcut selected';
|
||||
firstNode = eparent.id;
|
||||
}
|
||||
};
|
||||
|
||||
function up (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
ele = ev.target;
|
||||
var eparent = get_dial_div (ele);
|
||||
|
||||
ele.style.cursor = cursor;
|
||||
if(eparent != undefined) secondNode = eparent.id;
|
||||
else return;
|
||||
|
||||
/* ommit just mere clicking the dial */
|
||||
if (firstNode != secondNode && firstNode != undefined)
|
||||
swap();
|
||||
};
|
||||
|
||||
function over (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
var ele = ev.target;
|
||||
var eparent = get_dial_div (ele);
|
||||
|
||||
var dial = document.getElementsByClassName("shortcut");
|
||||
if (firstNode != undefined)
|
||||
{
|
||||
eparent.className = 'shortcut selected';
|
||||
for (var i = 0; i < dial.length; i++) {
|
||||
if (eparent.id != firstNode.id && dial[i].id != eparent.id) {
|
||||
dial[i].className = 'shortcut';
|
||||
}
|
||||
}
|
||||
}
|
||||
ele.style.cursor = cursor;
|
||||
}
|
||||
|
||||
function swap () {
|
||||
console.log ("speed_dial-save-swap " + firstNode + " " + secondNode);
|
||||
};
|
||||
|
||||
function init () {
|
||||
var new_tile = document.getElementsByClassName ("preview new");
|
||||
new_tile[0].addEventListener ('click', add_tile, false);
|
||||
|
||||
var titles = document.getElementsByClassName ("title");
|
||||
var len = titles.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (titles[i].parentNode.childNodes[0].className != "preview new") {
|
||||
titles[i].addEventListener ('click', editing_tile, false);
|
||||
titles[i].addEventListener ('blur', done_editing_title, false);
|
||||
titles[i].addEventListener ('keydown', input_key_down, false);
|
||||
}
|
||||
}
|
||||
|
||||
var crosses = document.getElementsByClassName ("cross");
|
||||
var len = crosses.length;
|
||||
for (var i = 0; i < len; i++)
|
||||
crosses[i].addEventListener ('click', delete_tile, false);
|
||||
|
||||
var occupied_tiles = document.getElementsByClassName ("shortcut");
|
||||
var len = occupied_tiles.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (occupied_tiles[i].childNodes[0].className != "preview new") {
|
||||
occupied_tiles[i].addEventListener('mousedown', click, false);
|
||||
occupied_tiles[i].addEventListener('mouseover', over, false);
|
||||
occupied_tiles[i].addEventListener('mouseup', up, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="osd" >
|
||||
<span id="dialing"></span>
|
||||
</div>
|
||||
<body onload="init ();">
|
||||
<div id="content">
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
CREATE TABLE IF NOT EXISTS sessions
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
parent_id INTEGER DEFAULT 0,
|
||||
crdate INTEGER DEFAULT 0,
|
||||
tstamp INTEGER DEFAULT 0,
|
||||
closed INTEGER DEFAULT 0,
|
||||
title TEXT DEFAULT NULL,
|
||||
FOREIGN KEY(parent_id) REFERENCES sessions(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tabs
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
session_id INTEGER NOT NULL,
|
||||
uri TEXT DEFAULT NULL,
|
||||
icon TEXT DEFAULT NULL,
|
||||
title TEXT DEFAULT NULL,
|
||||
crdate INTEGER DEFAULT 0,
|
||||
tstamp INTEGER DEFAULT 0,
|
||||
closed INTEGER DEFAULT 0,
|
||||
FOREIGN KEY(session_id) REFERENCES sessions(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tab_history
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
tab_id INTEGER,
|
||||
url TEXT,
|
||||
icon TEXT,
|
||||
title TEXT,
|
||||
FOREIGN KEY(tab_id) REFERENCES tabs(id)
|
||||
);
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE tabs ADD sorting REAL DEFAULT 0;
|
||||
|
||||
CREATE INDEX sorting on tabs (sorting ASC);
|
||||
CREATE INDEX tstamp on tabs (tstamp ASC);
|
|
@ -1,3 +1,103 @@
|
|||
midori (0.5.11-2) unstable; urgency=medium
|
||||
|
||||
* Remove "Force SSL verification" patch.
|
||||
The patch "force-ssl-cert-verification.patch" was mistakenly included
|
||||
in the last Midori release; this cased a regression because the user
|
||||
cannot access a website that has a self-signed SSL/TLS certificate
|
||||
anymore. This change removes the patch and allows the user to trust
|
||||
self-signed certificates again. (Closes: #799337)
|
||||
|
||||
-- Sergio Durigan Junior <sergiodj@sergiodj.net> Fri, 18 Sep 2015 15:29:38 -0400
|
||||
|
||||
midori (0.5.11-1) unstable; urgency=low
|
||||
|
||||
[ Yves-Alexis Perez ]
|
||||
* New upstream release.
|
||||
* Apply patch from Colin Watson to improve conffile handling, using new
|
||||
debhelper features. closes: #659773
|
||||
* debian/control:
|
||||
- update standards version to 3.9.3.
|
||||
- update homepage address.
|
||||
- remove myself from uploaders.
|
||||
* debian/midori.maintscript:
|
||||
- handle the /etc/xdg/midori/extensions/libadblock.so removal there.
|
||||
closes: #660303
|
||||
* debian/patches:
|
||||
- force-ssl-cert-verification added, set ssl-strict to TRUE so connections
|
||||
are not done if the ssl certificate can't be trusted.
|
||||
* debian/compat bumped to 9.
|
||||
|
||||
[ Ryan Niebur ]
|
||||
* new upstream version, including the waf unpack changes made thanks
|
||||
to the NMU by Koichi Akabe
|
||||
- refreshed patches
|
||||
- add new Build-Dep on libzeitgeist-dev
|
||||
* Improve dh_auto_clean target in d/rules to handle some leftover
|
||||
files from quilt and waf
|
||||
|
||||
[ Andres Salomon ]
|
||||
* Import Debian patch 0.4.3+dfsg-0.2
|
||||
|
||||
[ Sergio Durigan Junior ]
|
||||
* Changing gbp.conf to not override the default tag name for releases.
|
||||
* Updating section names on debian/gbp.conf
|
||||
* Imported Upstream version 0.5.11
|
||||
* Update debian/patches for the new Midori version (0.5.11).
|
||||
* Revamp build system (use cmake instead of waf)
|
||||
- Update debian/rules, removing old stuff (from waf) and adding new,
|
||||
simpler rules for the cmake-based build.
|
||||
- Update debian/control, listing the new package maintainer and
|
||||
reviewed dependencies.
|
||||
- Delete debian/waf-unpack file.
|
||||
- Rename debian/config/{Debian,Ubuntu}.h files to
|
||||
debian/config/{Debian,Ubuntu}.conf.
|
||||
With this change, it is now unnecessary to create a DFSG-modified
|
||||
version of the package, because Waf is not used as the build system
|
||||
anymore (for more details, see Bug 645191).
|
||||
It is possible to build the package now, but it still has some lintian
|
||||
warnings that will be fixed in the following changes.
|
||||
(Closes: #663185, #758103, #787878)
|
||||
* Adding shlibs and lintian-overrides files.
|
||||
Due to the way libraries (i.e., plugins) are built by Midori (without
|
||||
a proper SONAME), it is necessary (or at least recommended) to provide
|
||||
a shlibs file that contains trustworthy information about the
|
||||
libraries being installed on the system.
|
||||
Unfortunately, it is also necessary to provide a lintian-overrides
|
||||
file in order to silence some lintian warnings (mostly about the
|
||||
shlibs mentioned above). We'll have to work with upstream in order to
|
||||
solve this problem.
|
||||
Another lintian error that needed to be silenced was related to the
|
||||
data/midori.swf file, present at the original tarball. This file is
|
||||
used just for testing (i.e., it is not installed in the system), and
|
||||
is actually generated using the png2swf utility (from the swftools
|
||||
package), which means it can be verified.
|
||||
* Rewrite manpage.
|
||||
The old manpage was too simple and did not cover many of the options
|
||||
supported by Midori on the command line. Fixed that by rewriting it
|
||||
almost completely, including many missing options, updating dates and
|
||||
author, and improving the formatting.
|
||||
|
||||
-- Sergio Durigan Junior <sergiodj@sergiodj.net> Tue, 15 Sep 2015 12:37:55 -0400
|
||||
|
||||
midori (0.4.3+dfsg-0.2) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Drop debian/presubj.in as the webkit text browser
|
||||
GtkLauncher is no longer packaged. (Closes: #759959)
|
||||
|
||||
-- Neil Williams <codehelp@debian.org> Thu, 06 Nov 2014 14:04:07 +0000
|
||||
|
||||
midori (0.4.3+dfsg-0.1) unstable; urgency=low
|
||||
|
||||
* Non-maintainer upload
|
||||
* Repack to extract waf script (Closes: 645191)
|
||||
* debian/waf-unpack
|
||||
- add to describe how to extract waf script
|
||||
* debian/rules
|
||||
- add get-orig-source target
|
||||
|
||||
-- Koichi Akabe <vbkaisetsu@gmail.com> Sat, 24 Nov 2012 17:33:35 +0900
|
||||
|
||||
midori (0.4.3-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
midori/midori-debian.h
|
||||
debian/midori.postinst
|
||||
debian/presubj
|
||||
|
|
|
@ -1 +1 @@
|
|||
7
|
||||
9
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
DEBIAN_DISTRO_DEFAULT_HOMEPAGE "file:///usr/share/doc/midori/user/midori.html"
|
||||
DEBIAN_WWW_ALTERNATIVES_PRIORITY 50
|
|
@ -1,3 +0,0 @@
|
|||
#define DEBIAN_DISTRO_DEFAULT_HOMEPAGE "file:///usr/share/doc/midori/user/midori.html"
|
||||
#define DEBIAN_WWW_ALTERNATIVES_PRIORITY 50
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
DEBIAN_DISTRO_DEFAULT_HOMEPAGE "file:///usr/share/ubuntu-artwork/home/index.html"
|
||||
DEBIAN_WWW_ALTERNATIVES_PRIORITY 39
|
|
@ -1,3 +0,0 @@
|
|||
#define DEBIAN_DISTRO_DEFAULT_HOMEPAGE "file:///usr/share/ubuntu-artwork/home/index.html"
|
||||
#define DEBIAN_WWW_ALTERNATIVES_PRIORITY 39
|
||||
|
|
@ -1,44 +1,37 @@
|
|||
Source: midori
|
||||
Section: web
|
||||
Priority: optional
|
||||
Maintainer: Ryan Niebur <ryan@debian.org>
|
||||
Uploaders: Yves-Alexis Perez <corsac@debian.org>
|
||||
Build-Depends: debhelper (>= 7.0.50),
|
||||
lsb-release,
|
||||
libgtk2.0-dev (>= 2.10),
|
||||
libglib2.0-dev,
|
||||
libwebkitgtk-dev (>= 1.4.3),
|
||||
libxml2-dev (>= 2.6),
|
||||
# For waf:
|
||||
python,
|
||||
# Optional dependencies:
|
||||
intltool,
|
||||
libidn11-dev,
|
||||
librsvg2-bin,
|
||||
libsqlite3-dev,
|
||||
libunique-dev (>= 1.0.6),
|
||||
python-docutils,
|
||||
libsoup2.4-dev (>= 2.25.2),
|
||||
libnotify-dev,
|
||||
valac (>= 0.10),
|
||||
# For testing under xvfb:
|
||||
xvfb,
|
||||
xauth,
|
||||
xfonts-base,
|
||||
hardening-wrapper,
|
||||
libxss-dev
|
||||
# Disabled optional dependencies:
|
||||
Build-Conflicts: gtk-doc-tools,
|
||||
libgtksourceview2.0-dev (>= 2.0),
|
||||
libhildon-1-dev
|
||||
Standards-Version: 3.9.2
|
||||
Homepage: http://www.twotoasts.de/index.php?/pages/midori_summary.html
|
||||
Maintainer: Sergio Durigan Junior <sergiodj@sergiodj.net>
|
||||
Build-Depends: debhelper (>= 9),
|
||||
cmake,
|
||||
valac,
|
||||
lsb-release,
|
||||
libwebkitgtk-dev (>= 1.8.1),
|
||||
libgtk2.0-dev (>= 2.24.0),
|
||||
libglib2.0-dev,
|
||||
libsoup-gnome2.4-dev (>= 2.27.90),
|
||||
libxml2-dev (>= 2.6),
|
||||
libsqlite3-dev (>= 3.6.19),
|
||||
libjavascriptcoregtk-1.0-dev,
|
||||
libnotify-dev,
|
||||
libgcr-3-dev (>= 2.32),
|
||||
librsvg2-bin,
|
||||
intltool,
|
||||
libunique-dev (>= 1.0.6),
|
||||
libzeitgeist-2.0-dev,
|
||||
# Necessary for 'make check'
|
||||
xvfb,
|
||||
xauth,
|
||||
xfonts-base,
|
||||
libxss-dev
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://www.midori-browser.org
|
||||
Vcs-Git: git://git.debian.org/collab-maint/midori.git
|
||||
Vcs-Browser: http://git.debian.org/?p=collab-maint/midori.git;a=summary
|
||||
|
||||
Package: midori
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, dbus-x11
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Recommends: gnome-icon-theme
|
||||
Provides: www-browser
|
||||
# For http://bugs.debian.org/522436 (missing symbols):
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[import-orig]
|
||||
upstream-branch=upstream-unstable
|
||||
debian-branch=master
|
||||
|
||||
[import-dsc]
|
||||
upstream-branch=upstream-unstable
|
||||
debian-branch=master
|
|
@ -1,46 +1,122 @@
|
|||
.TH MIDORI "1" "September 2007" "midori 0.0.6" "User commands"
|
||||
.TH MIDORI "1" "September 2015" "midori 0.5.11" "User commands"
|
||||
|
||||
.SH NAME
|
||||
midori \- fast and lightweight web browser
|
||||
midori \- fast and lightweight Web Browser.
|
||||
|
||||
.SH SYNOPSIS
|
||||
|
||||
.PP
|
||||
\fBmidori\fR [OPTION...] [URL]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBmidori\fR is a lightweight web browser.
|
||||
\fBmidori\fR is a lightweight Web Browser.
|
||||
|
||||
.SH OPTIONS
|
||||
.IP
|
||||
.SS "Application Options:"
|
||||
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Display program version
|
||||
\fB\-a\fR \fIADDRESS\fR\fR, \fB\-\-app\fR=\fIADDRESS\fR
|
||||
|
||||
Run \fIADDRESS\fR as a web application.
|
||||
|
||||
.TP
|
||||
\fB\-c\fR \fIFOLDER\fR, \fB\-\-config\fR=\fIFOLDER\fR
|
||||
|
||||
Use \fIFOLDER\fR as configuration folder.
|
||||
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-private\fR
|
||||
|
||||
Run Midori in private mode. No changes are saved in this mode.
|
||||
|
||||
.TP
|
||||
\fB\-\-plain\fR
|
||||
|
||||
Plain GTK+ window with WebKit, akin to GtkLauncher.
|
||||
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-diagnostic\-dialog\fR
|
||||
|
||||
Show a diagnostic dialog.
|
||||
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-debug\fR
|
||||
|
||||
Run Midori within gdb and save a backtrace on crash. Useful when
|
||||
reporting bugs against the package.
|
||||
|
||||
.TP
|
||||
\fB\-r\fR \fIFILE\fR, \fB\-\-run\fR=\fIFILE\fR
|
||||
|
||||
Run \fIFILE\fR as a JavaScript.
|
||||
|
||||
.TP
|
||||
\fB\-s\fR \fIURI\fR, \fB\-\-snapshot\fR=\fIURI\fR
|
||||
|
||||
Take a snapshot of \fIURI\fR.
|
||||
|
||||
.TP
|
||||
\fB\-e\fR \fICOMMAND\fR, \fB\-\-execute\fR=\fICOMMAND\fR
|
||||
|
||||
Run the specified \fICOMMAND\fR. To obtain a list of supported
|
||||
commands, see \fB\-\-help\-execute\fR below.
|
||||
|
||||
.TP
|
||||
\fB\-\-help\-execute\fR
|
||||
|
||||
Print a list of available commands supported by \fB\-\-execute\fR.
|
||||
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
|
||||
Print the version of Midori.
|
||||
|
||||
.TP
|
||||
\fB\-b\fR \fIPATTERN\fR, \fB\-\-block\-uris\fR=\fIPATTERN\fR
|
||||
|
||||
Block URIs according to the regular expression specified in
|
||||
\fIPATTERN\fR.
|
||||
|
||||
.TP
|
||||
\fB\-i\fR \fISECONDS\fR, \fB\-\-inactivity\-reset\fR=\fISECONDS\fR
|
||||
|
||||
Reset Midori after \fISECONDS\fR seconds of inactivity.
|
||||
|
||||
.TP
|
||||
\fB\-\-display\fR=\fIDISPLAY\fR
|
||||
X display to use
|
||||
|
||||
.SS "Help Options:"
|
||||
X display to use.
|
||||
|
||||
.SS Help Options:
|
||||
|
||||
.TP
|
||||
\-?, \fB\-\-help\fR
|
||||
Show help options
|
||||
|
||||
Show help options described above.
|
||||
|
||||
.TP
|
||||
\fB\-\-help\-all\fR
|
||||
Show all help options
|
||||
|
||||
Show all help options.
|
||||
|
||||
.TP
|
||||
\fB\-\-help\-gtk\fR
|
||||
Show GTK+ Options
|
||||
|
||||
Show GTK+ Options.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Please report comments, suggestions and bugs to christian@twotoasts.de
|
||||
.PP
|
||||
Check for new versions at: http://software.twotoasts.de
|
||||
Please report bugs using the Debian BTS <https://bugs.debian.org>.
|
||||
|
||||
.SH AUTHOR
|
||||
\fBMidori\fR is copyright (C) 2007 Christian Dywan.
|
||||
|
||||
.PP
|
||||
This manual page was written by Emanuele Rocca <ema@debian.org> for
|
||||
the Debian GNU/Linux system (but may be used by others).
|
||||
This manual page was completely rewritten by Sergio Durigan Junior
|
||||
<sergiodj@sergiodj.net>, based on the previous version by Emanuele
|
||||
Rocca <ema@debian.org>. It was written for the Debian GNU/Linux
|
||||
system but may be used by others.
|
||||
|
||||
.PP
|
||||
Permission is granted to copy, distribute and/or modify this document under the
|
||||
terms of the GNU General Public License, Version 2 or any later version published
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
debian/tmp/*
|
||||
debian/presubj /usr/share/bug/midori/
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# Overrides the warnings given by the following shlibs. These
|
||||
# warnings are wrong because these shlibs are private to the project;
|
||||
# they are actually plugins that Midori offers. For the rationale
|
||||
# behind these overrides, see Debian Policy, section 10.2.
|
||||
unused-shlib-entry-in-control-file libabout 1
|
||||
unused-shlib-entry-in-control-file libadblock 1
|
||||
unused-shlib-entry-in-control-file libaddons 1
|
||||
unused-shlib-entry-in-control-file libapps 1
|
||||
unused-shlib-entry-in-control-file libcolorful-tabs 1
|
||||
unused-shlib-entry-in-control-file libcookie-manager 1
|
||||
unused-shlib-entry-in-control-file libcookie-permissions 1
|
||||
unused-shlib-entry-in-control-file libcopy-tabs 1
|
||||
unused-shlib-entry-in-control-file libdelayed-load 1
|
||||
unused-shlib-entry-in-control-file libdevpet 1
|
||||
unused-shlib-entry-in-control-file libdomain-keys 1
|
||||
unused-shlib-entry-in-control-file libexternal-download-manager 1
|
||||
unused-shlib-entry-in-control-file libfeed-panel 1
|
||||
unused-shlib-entry-in-control-file libflummi 1
|
||||
unused-shlib-entry-in-control-file libformhistory 1
|
||||
unused-shlib-entry-in-control-file libhistory-list 1
|
||||
unused-shlib-entry-in-control-file libmouse-gestures 1
|
||||
unused-shlib-entry-in-control-file libnojs 1
|
||||
unused-shlib-entry-in-control-file libnotes 1
|
||||
unused-shlib-entry-in-control-file libnsplugin-manager 1
|
||||
unused-shlib-entry-in-control-file libopen-with 1
|
||||
unused-shlib-entry-in-control-file libshortcuts 1
|
||||
unused-shlib-entry-in-control-file libstatusbar-features 1
|
||||
unused-shlib-entry-in-control-file libstatus-clock 1
|
||||
unused-shlib-entry-in-control-file libtabby 1
|
||||
unused-shlib-entry-in-control-file libtab-panel 1
|
||||
unused-shlib-entry-in-control-file libtabs-minimized 1
|
||||
unused-shlib-entry-in-control-file libtoolbar-editor 1
|
||||
unused-shlib-entry-in-control-file libtransfers 1
|
||||
unused-shlib-entry-in-control-file libwebmedia-now-playing 1
|
||||
|
||||
package-name-doesnt-match-sonames libmidori-core1
|
||||
non-dev-pkg-with-shlib-symlink usr/lib/libmidori-core.so.0.0.0 usr/lib/libmidori-core.so
|
|
@ -0,0 +1,2 @@
|
|||
mv_conffile /etc/xdg/midori/extensions/libadblock.so/config /etc/xdg/midori/extensions/adblock/config 0.4.1-2
|
||||
rm_conffile /etc/xdg/midori/extensions/libadblock.so 0.4.1-2
|
|
@ -9,10 +9,5 @@ case "$1" in
|
|||
x-www-browser.1.gz /usr/share/man/man1/midori.1.gz
|
||||
;;
|
||||
esac
|
||||
dpkg-maintscript-helper mv_conffile \
|
||||
/etc/xdg/midori/extensions/libadblock.so/config \
|
||||
/etc/xdg/midori/extensions/adblock/config \
|
||||
0.4.1-2 midori -- "$@"
|
||||
rmdir /etc/xdg/midori/extensions/libadblock.so || true
|
||||
#DEBHELPER#
|
||||
exit 0
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
dpkg-maintscript-helper mv_conffile \
|
||||
/etc/xdg/midori/extensions/libadblock.so/config \
|
||||
/etc/xdg/midori/extensions/adblock/config \
|
||||
0.4.1-2 midori -- "$@"
|
||||
#DEBHELPER#
|
||||
exit 0
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
dpkg-maintscript-helper mv_conffile \
|
||||
/etc/xdg/midori/extensions/libadblock.so/config \
|
||||
/etc/xdg/midori/extensions/adblock/config \
|
||||
0.4.1-2 midori -- "$@"
|
||||
#DEBHELPER#
|
||||
exit 0
|
|
@ -0,0 +1,31 @@
|
|||
libmidori-core 1 midori
|
||||
libabout 1 midori
|
||||
libadblock 1 midori
|
||||
libaddons 1 midori
|
||||
libapps 1 midori
|
||||
libcolorful-tabs 1 midori
|
||||
libcookie-manager 1 midori
|
||||
libcookie-permissions 1 midori
|
||||
libcopy-tabs 1 midori
|
||||
libdelayed-load 1 midori
|
||||
libdevpet 1 midori
|
||||
libdomain-keys 1 midori
|
||||
libexternal-download-manager 1 midori
|
||||
libfeed-panel 1 midori
|
||||
libflummi 1 midori
|
||||
libformhistory 1 midori
|
||||
libhistory-list 1 midori
|
||||
libmouse-gestures 1 midori
|
||||
libnojs 1 midori
|
||||
libnotes 1 midori
|
||||
libnsplugin-manager 1 midori
|
||||
libopen-with 1 midori
|
||||
libshortcuts 1 midori
|
||||
libstatusbar-features 1 midori
|
||||
libstatus-clock 1 midori
|
||||
libtabby 1 midori
|
||||
libtab-panel 1 midori
|
||||
libtabs-minimized 1 midori
|
||||
libtoolbar-editor 1 midori
|
||||
libtransfers 1 midori
|
||||
libwebmedia-now-playing 1 midori
|
|
@ -1,12 +1,11 @@
|
|||
diff --git a/data/search b/data/search
|
||||
index e759642..59341ee 100644
|
||||
--- a/data/search
|
||||
+++ b/data/search
|
||||
@@ -27,3 +27,17 @@ name=The Free Dictionary
|
||||
text=Dictionary, Encyclopedia and Thesaurus
|
||||
uri=http://www.thefreedictionary.com/%s
|
||||
token=fd
|
||||
+
|
||||
Index: midori-debian-repo/config/search
|
||||
===================================================================
|
||||
--- midori-debian-repo.orig/config/search
|
||||
+++ midori-debian-repo/config/search
|
||||
@@ -34,3 +34,16 @@ text=Localize text or URL
|
||||
uri=http://translate.google.com/?q=
|
||||
token=gt
|
||||
|
||||
+[Debian Packages]
|
||||
+name=Debian Packages
|
||||
+text=Search Debian Packages
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
Sometimes a problem in Midori is caused by a bug in the rendering
|
||||
engine, Webkit. Please take a moment to try to reproduce bugs with
|
||||
the Webkit test browser, %GTKLAUNCHER%.
|
||||
If you are able to reproduce your bug in the Webkit test browser,
|
||||
report the bug against %LIBWEBKIT_PKG% instead. You may also wish
|
||||
to see if your bug has already been reported as a webkit bug:
|
||||
http://bugs.debian.org/src:webkit
|
|
@ -1,73 +1,57 @@
|
|||
#!/usr/bin/make -f
|
||||
# output every command that modifies files on the build system.
|
||||
#DH_VERBOSE = 1
|
||||
|
||||
LDFLAGS=$(shell dpkg-buildflags --get LDFLAGS)
|
||||
CFLAGS=$(shell dpkg-buildflags --get CFLAGS)
|
||||
LDFLAGS+=-Wl,--as-needed -Wl,-O1
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
include /usr/share/dpkg/default.mk
|
||||
|
||||
# waf, thank you _so_ much
|
||||
export LINKFLAGS=$(LDFLAGS)
|
||||
export CCFLAGS=$(CFLAGS)
|
||||
|
||||
export DEB_BUILD_HARDENING=1
|
||||
|
||||
CMD=$(shell echo $@ | sed 's/override_//')
|
||||
|
||||
LIBWEBKIT_PKG=$(shell dpkg-query -p libwebkitgtk-dev | grep Depends | sed -r 's/.*(libwebkitgtk[^ ]+).*/\1/')
|
||||
GTKLAUNCHER=$(shell dpkg-query -L $(LIBWEBKIT_PKG) | grep GtkLauncher)
|
||||
DISTRO=$(shell lsb_release -is)
|
||||
CONFIG_FILE=debian/config/$(DISTRO).h
|
||||
ifneq (0, $(shell test -e $(CONFIG_FILE); echo "$$?"))
|
||||
DISTRO=Debian
|
||||
# Necessary for the configuration file (xdg).
|
||||
DISTRO = $(shell lsb_release -is)
|
||||
CONFIG_FILE = debian/config/$(DISTRO).conf
|
||||
ifneq (0, $(shell test -f $(CONFIG_FILE); echo "$$?"))
|
||||
DISTRO = Debian
|
||||
endif
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
WAF=./waf
|
||||
|
||||
debian/presubj: debian/presubj.in
|
||||
@echo "presubj parameters:"
|
||||
@echo "Replacing %LIBWEBKIT_PKG% with $(LIBWEBKIT_PKG)"
|
||||
@echo "Replacing %GTKLAUNCHER% with $(GTKLAUNCHER)"
|
||||
test -f "/var/lib/dpkg/info/$(LIBWEBKIT_PKG).list"
|
||||
test -f "$(GTKLAUNCHER)"
|
||||
test -n "$(GTKLAUNCHER)"
|
||||
sed -e "s,%LIBWEBKIT_PKG%,$(LIBWEBKIT_PKG),g" -e "s,%GTKLAUNCHER%,$(GTKLAUNCHER),g" $@.in > $@
|
||||
|
||||
override_dh_install: debian/presubj
|
||||
$(CMD) --fail-missing
|
||||
|
||||
override_dh_auto_clean:
|
||||
$(WAF) --nocache distclean
|
||||
rm -rf _build_
|
||||
rm -rf .waf*
|
||||
rm -rf .lock-wscript
|
||||
dh $@ --buildsystem=cmake --builddirectory=_build/
|
||||
|
||||
# Midori uses a "poor man's configure" which only accepts a minimal,
|
||||
# pre-defined set of flags. Therefore, we invoke cmake directly here.
|
||||
override_dh_auto_configure:
|
||||
$(WAF) --nocache configure --debug-level=none --prefix /usr
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DCMAKE_INSTALL_SYSCONFDIR=/etc \
|
||||
-DCMAKE_INSTALL_LIBDIR=/usr/lib \
|
||||
..
|
||||
|
||||
# cmake does not emit useful information when compiling the source
|
||||
# files. We use VERBOSE here for that.
|
||||
override_dh_auto_build:
|
||||
$(WAF) build --nocache -v
|
||||
dh_auto_build -- VERBOSE=1
|
||||
|
||||
#override_dh_auto_test:
|
||||
# xvfb-run $(WAF) --nocache check
|
||||
# We have to override 'make check' because it needs to run under
|
||||
# xvfb-run. And some tests still fail.
|
||||
override_dh_auto_test:
|
||||
(cd _build && xvfb-run make check) || true
|
||||
|
||||
override_dh_auto_install:
|
||||
$(WAF) --nocache install --destdir debian/tmp
|
||||
dh_auto_install
|
||||
rm -f debian/tmp/usr/share/doc/midori/COPYING debian/tmp/usr/share/doc/midori/TRANSLATE
|
||||
install -m 0644 debian/$(DISTRO)-config debian/tmp/etc/xdg/midori/config
|
||||
|
||||
PRIORITY=$(shell sed -r -e '/DEBIAN_WWW_ALTERNATIVES_PRIORITY/ !d' -e 's/.* ([^ ]*)$$/\1/' $(CONFIG_FILE))
|
||||
# Generate the debuginfo package.
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=midori-dbg
|
||||
|
||||
# Updating the alternatives priority
|
||||
PRIORITY = $(shell sed -ne 's/^DEBIAN_WWW_ALTERNATIVES_PRIORITY \([0-9]\+\)/\1/p' $(CONFIG_FILE))
|
||||
|
||||
debian/midori.postinst: debian/midori.postinst.base
|
||||
sed "s/DEBIAN_WWW_ALTERNATIVES_PRIORITY/$(PRIORITY)/g" debian/midori.postinst.base > debian/midori.postinst
|
||||
sed 's/DEBIAN_WWW_ALTERNATIVES_PRIORITY/$(PRIORITY)/g' debian/midori.postinst.base > debian/midori.postinst
|
||||
|
||||
override_dh_installdeb: debian/midori.postinst
|
||||
$(CMD)
|
||||
|
||||
override_dh_strip:
|
||||
$(CMD) --dbg-package=midori-dbg
|
||||
dh_installdeb
|
||||
|
||||
override_dh_installchangelogs:
|
||||
rm -f debian/midori/usr/share/doc/midori/ChangeLog
|
||||
dh_installchangelogs ChangeLog
|
||||
dh_installchangelogs
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# This file is just used for testing, and is not installed with the
|
||||
# package. Moreover, it is generated from a PNG image, using the
|
||||
# following command:
|
||||
#
|
||||
# png2swf -z -j 1 -o data/midori.swf ./icons/16x16/midori.png
|
||||
#
|
||||
# Which means that it can be easily verified. The png2swf command can
|
||||
# be found in the swftools package.
|
||||
midori source: source-is-missing data/midori.swf
|
|
@ -1 +0,0 @@
|
|||
unapply-patches
|
|
@ -1,2 +1,3 @@
|
|||
version=3
|
||||
opts=dversionmangle=s/\+dfsg// \
|
||||
http://archive.xfce.org/src/apps/midori/([\d\.]+)/midori-([\d.]+).tar.bz2
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright (C) 2013 Olivier Duchateau
|
||||
|
||||
include (GtkDoc)
|
||||
|
||||
if (GTKDOC_FOUND)
|
||||
list (APPEND MODULES "katze" "midori")
|
||||
foreach (MOD ${MODULES})
|
||||
if (EXISTS "${CMAKE_SOURCE_DIR}/${MOD}")
|
||||
gtkdoc (${MOD})
|
||||
endif ()
|
||||
endforeach ()
|
||||
else ()
|
||||
message (FATAL_ERROR "gtk-doc not found")
|
||||
endif ()
|
|
@ -1,36 +0,0 @@
|
|||
#! /usr/bin/env python
|
||||
# WAF build script for midori
|
||||
# This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
import pproc as subprocess
|
||||
import os
|
||||
import Utils
|
||||
|
||||
for module in ('midori', 'katze'):
|
||||
try:
|
||||
if not os.access ('_build_', os.F_OK):
|
||||
Utils.check_dir ('_build_')
|
||||
if not os.access ('_build_/docs', os.F_OK):
|
||||
Utils.check_dir ('_build_/docs')
|
||||
if not os.access ('_build_/docs/api', os.F_OK):
|
||||
Utils.check_dir ('_build_/docs/api')
|
||||
subprocess.call (['gtkdoc-scan', '--module=' + module,
|
||||
'--source-dir=' + module, '--output-dir=_build_/docs/api/' + module,
|
||||
'--rebuild-sections', '--rebuild-types'])
|
||||
os.chdir ('_build_/docs/api/' + module)
|
||||
subprocess.call (['gtkdoc-mktmpl', '--module=' + module,
|
||||
'--output-dir=.' + module])
|
||||
subprocess.call (['gtkdoc-mkdb', '--module=' + module,
|
||||
'--source-dir=.', '--output-dir=xml',
|
||||
'--source-suffixes=c,h', '--output-format=xml',
|
||||
'--default-includes=%s/%s.h' % (module, module),
|
||||
'--sgml-mode', '--main-sgml-file=%s.sgml' % module])
|
||||
if not os.access ('html', os.F_OK):
|
||||
Utils.check_dir ('html')
|
||||
os.chdir ('html')
|
||||
subprocess.call (['gtkdoc-mkhtml', module, '../%s.sgml' % module])
|
||||
Utils.pprint ('YELLOW', "Created documentation for %s." % module)
|
||||
os.chdir ('../../../../..')
|
||||
except Exception, msg:
|
||||
print msg
|
||||
Utils.pprint ('RED', "Failed to create documentation for %s." % module)
|
|
@ -0,0 +1,134 @@
|
|||
# Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
set(EXTENSIONDIR "${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_PROJECT_NAME}")
|
||||
include_directories(
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${CMAKE_SOURCE_DIR}/midori"
|
||||
"${CMAKE_SOURCE_DIR}/katze"
|
||||
${DEPS_INCLUDE_DIRS}
|
||||
${OPTS_INCLUDE_DIRS}
|
||||
${DEPS_GTK_INCLUDE_DIRS}
|
||||
${OPTS_GTK_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
"${CMAKE_BINARY_DIR}/midori"
|
||||
)
|
||||
file(GLOB EXTENSIONS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
|
||||
if (HALF_BRO_INCOM_WEBKIT2)
|
||||
list(REMOVE_ITEM EXTENSIONS
|
||||
"cookie-permissions"
|
||||
"addons.c"
|
||||
"formhistory"
|
||||
"external-download-manager.vala"
|
||||
"nojs"
|
||||
"nsplugin-manager.vala"
|
||||
"tabs2one.c"
|
||||
)
|
||||
endif ()
|
||||
|
||||
# FIXME: re-enable webmedia extension
|
||||
# once we have working notifications on win
|
||||
if (WIN32)
|
||||
list(REMOVE_ITEM EXTENSIONS "webmedia-now-playing.vala")
|
||||
endif()
|
||||
|
||||
# FIXME: not stable enough for release
|
||||
if (NOT REVISION)
|
||||
list(REMOVE_ITEM EXTENSIONS "tabs2one.c")
|
||||
endif()
|
||||
|
||||
foreach(UNIT_SRC ${EXTENSIONS})
|
||||
string(FIND ${UNIT_SRC} ".c" UNIT_EXTENSION)
|
||||
if (UNIT_EXTENSION GREATER -1)
|
||||
string(REPLACE ".c" "" UNIT ${UNIT_SRC})
|
||||
add_library(${UNIT} MODULE ${UNIT_SRC})
|
||||
target_link_libraries(${UNIT}
|
||||
${LIBMIDORI}
|
||||
)
|
||||
set_target_properties(${UNIT} PROPERTIES
|
||||
COMPILE_FLAGS ${CFLAGS}
|
||||
)
|
||||
install(TARGETS ${UNIT}
|
||||
LIBRARY DESTINATION ${EXTENSIONDIR}
|
||||
)
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
foreach(UNIT_SRC ${EXTENSIONS})
|
||||
string(FIND ${UNIT_SRC} "." UNIT_EXTENSION)
|
||||
if (UNIT_EXTENSION EQUAL -1)
|
||||
file(GLOB UNIT_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${UNIT_SRC}/*.c")
|
||||
file(GLOB UNIT_FILES_VALA RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${UNIT_SRC}/*.vala")
|
||||
if (UNIT_FILES_VALA)
|
||||
include(ValaPrecompile)
|
||||
vala_precompile(UNIT_SRC_C ${UNIT_SRC}
|
||||
${UNIT_FILES_VALA}
|
||||
PACKAGES
|
||||
${PKGS}
|
||||
OPTIONS
|
||||
${VALAFLAGS}
|
||||
--use-header="${CMAKE_PROJECT_NAME}-core.h"
|
||||
GENERATE_HEADER
|
||||
"${UNIT_SRC}"
|
||||
GENERATE_HEADER
|
||||
${UNIT}
|
||||
CUSTOM_VAPIS
|
||||
${EXTRA_VAPIS}
|
||||
"${CMAKE_SOURCE_DIR}/midori/midori.vapi"
|
||||
"${CMAKE_BINARY_DIR}/midori/${LIBMIDORI}.vapi"
|
||||
)
|
||||
set(UNIT_FILES ${UNIT_FILES} ${UNIT_SRC_C})
|
||||
endif ()
|
||||
if (UNIT_FILES)
|
||||
add_library(${UNIT_SRC} MODULE ${UNIT_FILES})
|
||||
target_link_libraries(${UNIT_SRC}
|
||||
${LIBMIDORI}
|
||||
)
|
||||
install(TARGETS ${UNIT_SRC}
|
||||
LIBRARY DESTINATION ${EXTENSIONDIR}
|
||||
)
|
||||
# extensions with vala code get the lenient VALA_CFLAGS
|
||||
# others get the usual CFLAGS with -Wall and -Werror
|
||||
if (UNIT_FILES_VALA)
|
||||
set_target_properties(${UNIT_SRC} PROPERTIES
|
||||
COMPILE_FLAGS ${VALA_CFLAGS}
|
||||
)
|
||||
else ()
|
||||
set_target_properties(${UNIT_SRC} PROPERTIES
|
||||
COMPILE_FLAGS ${CFLAGS}
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
foreach(UNIT_SRC ${EXTENSIONS})
|
||||
string(FIND ${UNIT_SRC} ".vala" UNIT_EXTENSION)
|
||||
if (UNIT_EXTENSION GREATER -1)
|
||||
string(REPLACE ".vala" "" UNIT ${UNIT_SRC})
|
||||
include(ValaPrecompile)
|
||||
vala_precompile(UNIT_SRC_C ${UNIT}
|
||||
${UNIT_SRC}
|
||||
PACKAGES
|
||||
${PKGS}
|
||||
OPTIONS
|
||||
${VALAFLAGS}
|
||||
--use-header="${CMAKE_PROJECT_NAME}-core.h"
|
||||
GENERATE_HEADER
|
||||
${UNIT}
|
||||
CUSTOM_VAPIS
|
||||
${EXTRA_VAPIS}
|
||||
"${CMAKE_SOURCE_DIR}/midori/midori.vapi"
|
||||
"${CMAKE_BINARY_DIR}/midori/${LIBMIDORI}.vapi"
|
||||
)
|
||||
add_library(${UNIT} MODULE ${UNIT_SRC_C})
|
||||
target_link_libraries(${UNIT}
|
||||
${LIBMIDORI}
|
||||
)
|
||||
set_target_properties(${UNIT} PROPERTIES
|
||||
COMPILE_FLAGS "${VALA_CFLAGS}"
|
||||
)
|
||||
install(TARGETS ${UNIT}
|
||||
LIBRARY DESTINATION ${EXTENSIONDIR}
|
||||
)
|
||||
endif ()
|
||||
endforeach ()
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
Copyright (C) 2013 André Stösel <andre@stoesel.de>
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace About {
|
||||
private abstract class Page : GLib.Object {
|
||||
public abstract string uri { get; set; }
|
||||
public abstract void get_contents (Midori.View view, string uri);
|
||||
protected void load_html (Midori.View view, string content, string uri) {
|
||||
#if HAVE_WEBKIT2
|
||||
view.web_view.load_html (content, uri);
|
||||
#else
|
||||
view.web_view.load_html_string (content, uri);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private class Widgets : Page {
|
||||
public override string uri { get; set; default = "about:widgets"; }
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
string[] widgets = {
|
||||
"<input value=\"demo\"%s>",
|
||||
"<p><input type=\"password\" value=\"demo\"%s></p>",
|
||||
"<p><input type=\"checkbox\" value=\"demo\"%s> demo</p>",
|
||||
"<p><input type=\"radio\" value=\"demo\"%s> demo</p>",
|
||||
"<p><select%s><option>foo bar</option><option selected>spam eggs</option></select></p>",
|
||||
"<p><select%s size=\"3\"><option>foo bar</option><option selected>spam eggs</option></select></p>",
|
||||
"<p><input type=\"file\"%s></p>",
|
||||
"<p><input type=\"file\" multiple%s></p>",
|
||||
"<input type=\"button\" value=\"demo\"%s>",
|
||||
"<p><input type=\"email\" value=\"user@localhost.com\"%s></p>",
|
||||
"<input type=\"url\" value=\"http://www.example.com\"%s>",
|
||||
"<input type=\"tel\" value=\"+1 234 567 890\" pattern=\"^[0+][1-9 /-]*$\"%s>",
|
||||
"<input type=\"number\" min=1 max=9 step=1 value=\"4\"%s>",
|
||||
"<input type=\"range\" min=1 max=9 step=1 value=\"4\"%s>",
|
||||
"<input type=\"date\" min=1990-01-01 max=2010-01-01%s>",
|
||||
"<input type=\"search\" placeholder=\"demo\"%s>",
|
||||
"<textarea%s>Lorem ipsum doloret sit amet…</textarea>",
|
||||
"<input type=\"color\" value=\"#d1eeb9\"%s>",
|
||||
"<progress min=1 max=9 value=4 %s></progress>",
|
||||
"<keygen type=\"rsa\" challenge=\"235ldahlae983dadfar\"%s>",
|
||||
"<p><input type=\"reset\"%s></p>",
|
||||
"<input type=\"submit\"%s>"
|
||||
};
|
||||
|
||||
string content = """<html>
|
||||
<head>
|
||||
<style>
|
||||
.fallback::-webkit-slider-thumb,
|
||||
.fallback, .fallback::-webkit-file-upload-button {
|
||||
-webkit-appearance: none !important;
|
||||
}
|
||||
.column {
|
||||
display:inline-block; vertical-align:top;
|
||||
width:25%;
|
||||
margin-right:1%;
|
||||
}
|
||||
</style>
|
||||
<title>%s</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%s</h1>
|
||||
<div class="column">%s</div>
|
||||
<div class="column">%s</div>
|
||||
<div class="column">%s</div>
|
||||
<p><a href="http://example.com" target="wp" onclick="javascript:window.open('http://example.com','wp','width=320, height=240, toolbar=false'); return false;">Popup window</a></p>
|
||||
</body>
|
||||
</html>""";
|
||||
|
||||
string[] widget_options = {"", " disabled", " class=\"fallback\""};
|
||||
string[] widgets_formated = {"", "", ""};
|
||||
|
||||
for (int i = 0; i < widget_options.length && i < widgets_formated.length; i++) {
|
||||
for (int j = 0; j < widgets.length; j++) {
|
||||
widgets_formated[i] = widgets_formated[i] + widgets[j].printf (widget_options[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.load_html (view, content.printf (uri, uri, widgets_formated[0], widgets_formated[1], widgets_formated[2]), uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Version : Page {
|
||||
public override string uri { get; set; }
|
||||
private GLib.HashTable<string, Page> about_pages;
|
||||
|
||||
public Version (string alias, HashTable<string, Page> about_pages) {
|
||||
this.uri = alias;
|
||||
this.about_pages = about_pages;
|
||||
}
|
||||
|
||||
private string list_about_uris () {
|
||||
string links = "";
|
||||
foreach (unowned string uri in about_pages.get_keys ())
|
||||
links = links + "<a href=\"%s\">%s</a> ".printf (uri, uri);
|
||||
return "<p>%s</p>".printf (links);
|
||||
}
|
||||
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
string contents = """<html>
|
||||
<head><title>about:version</title></head>
|
||||
<body>
|
||||
<h1>a<span style="position: absolute; left: -1000px; top: -1000px">lias a=b; echo Copy carefully #</span>bout:version</h1>
|
||||
<p>%s</p>
|
||||
<img src="res://logo-shade.png" style="position: absolute; right: 15px; bottom: 15px; z-index: -9;">
|
||||
<table>
|
||||
<tr><td>Command line %s</td></tr>
|
||||
%s
|
||||
<tr><td>Platform %s %s %s</td></tr>
|
||||
<tr><td>Identification %s</td></tr>
|
||||
%s
|
||||
</table>
|
||||
<table>
|
||||
%s
|
||||
</table>
|
||||
%s
|
||||
</body>
|
||||
</html>""";
|
||||
|
||||
GLib.StringBuilder versions = new GLib.StringBuilder ();
|
||||
Midori.View.list_versions (versions, true);
|
||||
|
||||
string ident;
|
||||
unowned string architecture;
|
||||
unowned string platform;
|
||||
unowned string sys_name = Midori.WebSettings.get_system_name (out architecture, out platform);
|
||||
view.settings.get ("user-agent", out ident);
|
||||
|
||||
GLib.StringBuilder video_formats = new GLib.StringBuilder ();
|
||||
view.list_video_formats (video_formats, true);
|
||||
|
||||
GLib.StringBuilder ns_plugins = new GLib.StringBuilder ();
|
||||
view.list_plugins (ns_plugins, true);
|
||||
|
||||
/* TODO: list active extensions */
|
||||
|
||||
this.load_html (view, contents.printf (
|
||||
_("Version numbers in brackets show the version used at runtime."),
|
||||
Midori.Paths.get_command_line_str (true),
|
||||
versions.str,
|
||||
platform, sys_name, architecture != null ? architecture : "",
|
||||
ident,
|
||||
video_formats.str,
|
||||
ns_plugins.str,
|
||||
this.list_about_uris ()
|
||||
), uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Private : Page {
|
||||
public override string uri { get; set; default = "about:private"; }
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
this.load_html (view, """<html dir="ltr">
|
||||
<head>
|
||||
<title>%s</title>
|
||||
<link rel="stylesheet" type="text/css" href="res://about.css">
|
||||
</head>
|
||||
<body>
|
||||
<img id="logo" src="res://logo-shade.png" />
|
||||
<div id="main" style="background-image: url(stock://dialog/gtk-dialog-info);">
|
||||
<div id="text">
|
||||
<h1>%s</h1>
|
||||
<p class="message">%s</p><ul class=" suggestions"><li>%s</li><li>%s</li><li>%s</li></ul>
|
||||
<p class="message">%s</p><ul class=" suggestions"><li>%s</li><li>%s</li><li>%s</li><li>%s</li></ul>
|
||||
</div><br style="clear: both"></div>
|
||||
</body>
|
||||
</html>""".printf (
|
||||
_("Private Browsing"), _("Private Browsing"),
|
||||
_("Midori doesn't store any personal data:"),
|
||||
_("No history or web cookies are being saved."),
|
||||
_("Extensions are disabled."),
|
||||
_("HTML5 storage, local database and application caches are disabled."),
|
||||
_("Midori prevents websites from tracking the user:"),
|
||||
_("Referrer URLs are stripped down to the hostname."),
|
||||
_("DNS prefetching is disabled."),
|
||||
_("The language and timezone are not revealed to websites."),
|
||||
_("Flash and other Netscape plugins cannot be listed by websites.")
|
||||
), uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Paths : Page {
|
||||
public override string uri { get; set; default = "about:paths"; }
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
string res_dir = Midori.Paths.get_res_filename ("about.css");
|
||||
string lib_dir = Midori.Paths.get_lib_path (PACKAGE_NAME);
|
||||
this.load_html (view, """<html>
|
||||
<body>
|
||||
<h1>%s</h1>
|
||||
<p>config: <code>%s</code></p>
|
||||
<p>res: <code>%s</code></p>
|
||||
<p>data: <code>%s/%s</code></p>
|
||||
<p>lib: <code>%s</code></p>
|
||||
<p>cache: <code>%s</code></p>
|
||||
<p>tmp: <code>%s</code></p>
|
||||
</body>
|
||||
</html>""".printf (
|
||||
uri, Midori.Paths.get_config_dir_for_reading (), res_dir,
|
||||
Midori.Paths.get_user_data_dir_for_reading (), PACKAGE_NAME,
|
||||
lib_dir, Midori.Paths.get_cache_dir_for_reading (), Midori.Paths.get_tmp_dir ()
|
||||
), uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Dial : Page {
|
||||
public override string uri { get; set; default = "about:dial"; }
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
var browser = Midori.Browser.get_for_widget (view);
|
||||
Midori.SpeedDial dial;
|
||||
browser.get ("speed-dial", out dial);
|
||||
if (dial == null)
|
||||
return;
|
||||
try {
|
||||
this.load_html (view, dial.get_html (), uri);
|
||||
} catch (Error error) {
|
||||
this.load_html (view, error.message, uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Geolocation : Page {
|
||||
public override string uri { get; set; default = "about:geolocation"; }
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
this.load_html (view, """<html>
|
||||
<body>
|
||||
<a href="http://dev.w3.org/geo/api/spec-source.html" id="method"></a>
|
||||
<span id="locationInfo"><noscript>No Geolocation without Javascript</noscript></span>
|
||||
<script>
|
||||
function displayLocation (position) {
|
||||
var geouri = 'geo:' + position.coords.latitude + ',' + position.coords.longitude + ',' + position.coords.altitude + ',u=' + position.coords.accuracy;
|
||||
document.getElementById('locationInfo').innerHTML = '<a href="' + geouri + '">' + geouri + '</a><br><code>'
|
||||
+ ' timestamp: ' + position.timestamp
|
||||
+ ' latitude: ' + position.coords.latitude
|
||||
+ ' longitude: ' + position.coords.longitude
|
||||
+ ' altitude: ' + position.coords.altitude + '<br>'
|
||||
+ ' accuracy: ' + position.coords.accuracy
|
||||
+ ' altitudeAccuracy: ' + position.coords.altitudeAccuracy
|
||||
+ ' heading: ' + position.coords.heading
|
||||
+ ' speed: ' + position.coords.speed
|
||||
+ '</code>';
|
||||
}
|
||||
function handleError (error) {
|
||||
var errorMessage = '<b>' + ['Unknown error', 'Permission denied', 'Position failed', 'Timed out'][error.code] + '</b>';
|
||||
if (error.code == 3) document.getElementById('locationInfo').innerHTML += (' ' + errorMessage);
|
||||
else document.getElementById('locationInfo').innerHTML = errorMessage;
|
||||
}
|
||||
if (navigator.geolocation) {
|
||||
var options = { enableHighAccuracy: true, timeout: 60000, maximumAge: "Infinite" };
|
||||
if (navigator.geolocation.watchPosition) {
|
||||
document.getElementById('method').innerHTML = '<code>geolocation.watchPosition</code>:';
|
||||
navigator.geolocation.watchPosition(displayLocation, handleError, options);
|
||||
} else {
|
||||
document.getElementById('method').innerHTML = '<code>geolocation.getCurrentPosition</code>:';
|
||||
navigator.geolocation.getCurrentPosition(displayLocation, handleError);
|
||||
}
|
||||
} else
|
||||
document.getElementById('locationInfo').innerHTML = 'Geolocation unavailable';
|
||||
</script>
|
||||
</body>
|
||||
</html>""", uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Redirects : Page {
|
||||
public override string uri { get; set; }
|
||||
private string property;
|
||||
public Redirects (string alias, string property) {
|
||||
this.uri = alias;
|
||||
this.property = property;
|
||||
}
|
||||
public override void get_contents (Midori.View view, string uri) {
|
||||
string new_uri = uri;
|
||||
view.settings.get (property, out new_uri);
|
||||
if (uri == "about:search")
|
||||
new_uri = Midori.URI.for_search (new_uri, "");
|
||||
view.set_uri (new_uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class Manager : Midori.Extension {
|
||||
private GLib.HashTable<string, Page>? about_pages;
|
||||
|
||||
private void register (Page page) {
|
||||
this.about_pages.insert (page.uri, page);
|
||||
}
|
||||
|
||||
private bool about_content (Midori.View view, string uri) {
|
||||
unowned Page? page = this.about_pages.get (uri);
|
||||
if (page != null) {
|
||||
page.get_contents (view, uri);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void tab_added (Midori.Browser browser, Midori.View view) {
|
||||
view.about_content.connect (this.about_content);
|
||||
}
|
||||
|
||||
private void tab_removed (Midori.Browser browser, Midori.View view) {
|
||||
view.about_content.disconnect (this.about_content);
|
||||
}
|
||||
|
||||
private void browser_added (Midori.Browser browser) {
|
||||
foreach (Midori.View tab in browser.get_tabs ()) {
|
||||
this.tab_added (browser, tab);
|
||||
}
|
||||
browser.add_tab.connect (this.tab_added);
|
||||
browser.remove_tab.connect (this.tab_removed);
|
||||
}
|
||||
|
||||
private void browser_removed (Midori.Browser browser) {
|
||||
foreach (Midori.View tab in browser.get_tabs ()) {
|
||||
this.tab_removed (browser, tab);
|
||||
}
|
||||
browser.add_tab.disconnect (this.tab_added);
|
||||
browser.remove_tab.disconnect (this.tab_removed);
|
||||
}
|
||||
|
||||
public void activated (Midori.App app) {
|
||||
this.about_pages = new GLib.HashTable<string, Page> (GLib.str_hash, GLib.str_equal);
|
||||
register (new Widgets ());
|
||||
register (new Version ("about:", about_pages));
|
||||
register (new Version ("about:version", about_pages));
|
||||
register (new Private ());
|
||||
register (new Paths ());
|
||||
register (new Geolocation ());
|
||||
register (new Redirects ("about:new", "tabhome"));
|
||||
register (new Redirects ("about:home", "homepage"));
|
||||
register (new Redirects ("about:search", "location-entry-search"));
|
||||
register (new Dial ());
|
||||
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
this.browser_added (browser);
|
||||
}
|
||||
app.add_browser.connect (this.browser_added);
|
||||
}
|
||||
|
||||
public void deactivated () {
|
||||
Midori.App app = this.get_app ();
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
this.browser_removed (browser);
|
||||
}
|
||||
app.add_browser.disconnect (this.browser_added);
|
||||
|
||||
this.about_pages = null;
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: "About pages",
|
||||
description: "Internal about: handler",
|
||||
version: "0.1",
|
||||
authors: "André Stösel <andre@stoesel.de>");
|
||||
|
||||
this.activate.connect (this.activated);
|
||||
this.deactivate.connect (this.deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new About.Manager ();
|
||||
}
|
||||
|
1510
extensions/adblock.c
1510
extensions/adblock.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Config : GLib.Object {
|
||||
List<Subscription> subscriptions;
|
||||
public string? path { get; private set; }
|
||||
KeyFile keyfile;
|
||||
bool should_save;
|
||||
public bool enabled { get; set; }
|
||||
|
||||
public Config (string? path, string? presets) {
|
||||
should_save = false;
|
||||
subscriptions = new GLib.List<Subscription> ();
|
||||
enabled = true;
|
||||
this.path = path;
|
||||
size = 0;
|
||||
load_file (path);
|
||||
load_file (presets);
|
||||
should_save = true;
|
||||
}
|
||||
|
||||
void load_file (string? filename) {
|
||||
if (filename == null)
|
||||
return;
|
||||
|
||||
keyfile = new GLib.KeyFile ();
|
||||
try {
|
||||
keyfile.load_from_file (filename, GLib.KeyFileFlags.NONE);
|
||||
string[] filters = keyfile.get_string_list ("settings", "filters");
|
||||
foreach (unowned string filter in filters) {
|
||||
bool active = false;
|
||||
string uri = filter;
|
||||
if (filter.has_prefix ("http-/"))
|
||||
uri = "http:" + filter.substring (5);
|
||||
else if (filter.has_prefix ("file-/"))
|
||||
uri = "file:" + filter.substring (5);
|
||||
else if (filter.has_prefix ("http-:"))
|
||||
uri = "https" + filter.substring (5);
|
||||
else
|
||||
active = true;
|
||||
Subscription sub = new Subscription (uri);
|
||||
sub.active = active;
|
||||
sub.add_feature (new Updater ());
|
||||
add (sub);
|
||||
}
|
||||
enabled = !keyfile.get_boolean ("settings", "disabled");
|
||||
} catch (KeyFileError.KEY_NOT_FOUND key_error) {
|
||||
/* It's no error if a key is missing */
|
||||
} catch (KeyFileError.GROUP_NOT_FOUND group_error) {
|
||||
/* It's no error if a group is missing */
|
||||
} catch (FileError.NOENT exist_error) {
|
||||
/* It's no error if no config file exists */
|
||||
} catch (GLib.Error settings_error) {
|
||||
warning ("Error reading settings from %s: %s\n", filename, settings_error.message);
|
||||
}
|
||||
|
||||
notify["enabled"].connect (enabled_changed);
|
||||
}
|
||||
|
||||
void enabled_changed (ParamSpec pspec) {
|
||||
keyfile.set_boolean ("settings", "disabled", !enabled);
|
||||
save ();
|
||||
}
|
||||
|
||||
void active_changed (Object subscription, ParamSpec pspec) {
|
||||
update_filters ();
|
||||
}
|
||||
|
||||
void update_filters () {
|
||||
var filters = new StringBuilder ();
|
||||
foreach (unowned Subscription sub in subscriptions) {
|
||||
if (!sub.mutable)
|
||||
continue;
|
||||
if (sub.uri.has_prefix ("http:") && !sub.active)
|
||||
filters.append ("http-" + sub.uri.substring (4));
|
||||
else if (sub.uri.has_prefix ("file:") && !sub.active)
|
||||
filters.append ("file-" + sub.uri.substring (5));
|
||||
else if (sub.uri.has_prefix ("https:") && !sub.active)
|
||||
filters.append ("http-" + sub.uri.substring (5));
|
||||
else
|
||||
filters.append (sub.uri);
|
||||
filters.append_c (';');
|
||||
}
|
||||
|
||||
if (filters.str.has_suffix (";"))
|
||||
filters.truncate (filters.len - 1);
|
||||
string[] list = filters.str.split (";");
|
||||
keyfile.set_string_list ("settings", "filters", list);
|
||||
|
||||
save ();
|
||||
}
|
||||
|
||||
|
||||
public void save () {
|
||||
try {
|
||||
FileUtils.set_contents (path, keyfile.to_data ());
|
||||
} catch (Error error) {
|
||||
warning ("Failed to save settings: %s", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/* foreach support */
|
||||
public new unowned Subscription? get (uint index) {
|
||||
return subscriptions.nth_data (index);
|
||||
}
|
||||
public uint size { get; private set; }
|
||||
|
||||
bool contains (Subscription subscription) {
|
||||
foreach (unowned Subscription sub in subscriptions)
|
||||
if (sub.uri == subscription.uri)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool add (Subscription sub) {
|
||||
if (contains (sub))
|
||||
return false;
|
||||
|
||||
sub.notify["active"].connect (active_changed);
|
||||
subscriptions.append (sub);
|
||||
size++;
|
||||
if (should_save)
|
||||
update_filters ();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void remove (Subscription sub) {
|
||||
if (!contains (sub))
|
||||
return;
|
||||
|
||||
subscriptions.remove (sub);
|
||||
sub.notify["active"].disconnect (active_changed);
|
||||
update_filters ();
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Element : Feature {
|
||||
public HashTable<string, string> blockcssprivate;
|
||||
bool debug_element;
|
||||
|
||||
public Element () {
|
||||
base ();
|
||||
debug_element = "adblock:element" in (Environment.get_variable ("MIDORI_DEBUG") ?? "");
|
||||
}
|
||||
|
||||
public override void clear () {
|
||||
blockcssprivate = new HashTable<string, string> (str_hash, str_equal);
|
||||
}
|
||||
|
||||
public string? lookup (string domain) {
|
||||
return blockcssprivate.lookup (domain);
|
||||
}
|
||||
|
||||
public void insert (string domain, string value) {
|
||||
if (debug_element)
|
||||
stdout.printf ("Element to be blocked %s => %s\n", domain, value);
|
||||
blockcssprivate.insert (domain, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,865 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public enum Directive {
|
||||
ALLOW,
|
||||
BLOCK
|
||||
}
|
||||
|
||||
public enum State {
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
BLOCKED
|
||||
}
|
||||
|
||||
public string? parse_subscription_uri (string? uri) {
|
||||
if (uri == null)
|
||||
return null;
|
||||
|
||||
if (uri.has_prefix ("http") || uri.has_prefix ("abp") || uri.has_prefix ("file"))
|
||||
{
|
||||
string sub_uri = uri;
|
||||
if (uri.has_prefix ("abp:")) {
|
||||
uri.replace ("abp://", "abp:");
|
||||
if (uri.has_prefix ("abp:subscribe?location=")) {
|
||||
/* abp://subscripe?location=http://example.com&title=foo */
|
||||
string[] parts = uri.substring (23, -1).split ("&", 2);
|
||||
sub_uri = parts[0];
|
||||
}
|
||||
}
|
||||
|
||||
string decoded_uri = Soup.URI.decode (sub_uri);
|
||||
return decoded_uri;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public class Extension : Midori.Extension {
|
||||
internal Config config;
|
||||
internal Subscription custom;
|
||||
internal StringBuilder hider_selectors;
|
||||
internal StatusIcon status_icon;
|
||||
internal SubscriptionManager manager;
|
||||
internal bool debug_element;
|
||||
#if !USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
|
||||
internal string? js_hider_function_body;
|
||||
#endif
|
||||
|
||||
#if HAVE_WEBKIT2
|
||||
#if !HAVE_WEBKIT2_3_91
|
||||
public Extension.WebExtension (WebKit.WebExtension web_extension) {
|
||||
init ();
|
||||
web_extension.page_created.connect (page_created);
|
||||
}
|
||||
|
||||
void page_created (WebKit.WebPage web_page) {
|
||||
web_page.send_request.connect (send_request);
|
||||
}
|
||||
|
||||
bool send_request (WebKit.WebPage web_page, WebKit.URIRequest request, WebKit.URIResponse? redirected_response) {
|
||||
return request_handled (request.uri, web_page.uri);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public Extension () {
|
||||
GLib.Object (name: _("Advertisement blocker"),
|
||||
description: _("Block advertisements according to a filter list"),
|
||||
version: "2.0",
|
||||
authors: "Christian Dywan <christian@twotoasts.de>");
|
||||
activate.connect (extension_activated);
|
||||
deactivate.connect (extension_deactivated);
|
||||
open_preferences.connect (extension_preferences);
|
||||
}
|
||||
|
||||
void extension_preferences () {
|
||||
manager.add_subscription (null);
|
||||
}
|
||||
|
||||
void extension_activated (Midori.App app) {
|
||||
#if HAVE_WEBKIT2
|
||||
string cache_dir = Environment.get_user_cache_dir ();
|
||||
string wk2path = Path.build_path (Path.DIR_SEPARATOR_S, cache_dir, "wk2ext");
|
||||
Midori.Paths.mkdir_with_parents (wk2path);
|
||||
string filename = "libadblock." + GLib.Module.SUFFIX;
|
||||
var wk2link = File.new_for_path (wk2path).get_child (filename);
|
||||
var library = File.new_for_path (Midori.Paths.get_lib_path (PACKAGE_NAME)).get_child (filename);
|
||||
try {
|
||||
wk2link.make_symbolic_link (library.get_path ());
|
||||
} catch (IOError.EXISTS exist_error) {
|
||||
/* It's no error if the file already exists. */
|
||||
} catch (Error error) {
|
||||
critical ("Failed to create WebKit2 link: %s", error.message);
|
||||
}
|
||||
#endif
|
||||
init ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_added (browser);
|
||||
app.add_browser.connect (browser_added);
|
||||
app.remove_browser.connect (browser_removed);
|
||||
}
|
||||
|
||||
void extension_deactivated () {
|
||||
var app = get_app ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_removed (browser);
|
||||
app.add_browser.disconnect (browser_added);
|
||||
app.remove_browser.disconnect (browser_removed);
|
||||
}
|
||||
|
||||
void browser_added (Midori.Browser browser) {
|
||||
foreach (var tab in browser.get_tabs ())
|
||||
tab_added (tab);
|
||||
browser.add_tab.connect (tab_added);
|
||||
browser.remove_tab.connect (tab_removed);
|
||||
|
||||
browser.add_action (status_icon);
|
||||
}
|
||||
|
||||
void browser_removed (Midori.Browser browser) {
|
||||
foreach (var tab in browser.get_tabs ())
|
||||
tab_removed (tab);
|
||||
browser.add_tab.disconnect (tab_added);
|
||||
browser.remove_tab.disconnect (tab_removed);
|
||||
browser.remove_action (status_icon);
|
||||
}
|
||||
|
||||
void tab_added (Midori.View view) {
|
||||
view.navigation_requested.connect (navigation_requested);
|
||||
#if !HAVE_WEBKIT2
|
||||
view.web_view.resource_request_starting.connect (resource_requested);
|
||||
#endif
|
||||
view.notify["load-status"].connect (load_status_changed);
|
||||
view.context_menu.connect (context_menu);
|
||||
}
|
||||
|
||||
void tab_removed (Midori.View view) {
|
||||
#if !HAVE_WEBKIT2
|
||||
view.web_view.resource_request_starting.disconnect (resource_requested);
|
||||
#endif
|
||||
view.navigation_requested.disconnect (navigation_requested);
|
||||
view.notify["load-status"].disconnect (load_status_changed);
|
||||
view.context_menu.disconnect (context_menu);
|
||||
}
|
||||
|
||||
void load_status_changed (Object object, ParamSpec pspec) {
|
||||
var view = object as Midori.View;
|
||||
if (config.enabled) {
|
||||
if (view.load_status == Midori.LoadStatus.FINISHED)
|
||||
inject_css (view, view.uri);
|
||||
}
|
||||
}
|
||||
|
||||
void context_menu (WebKit.HitTestResult hit_test_result, Midori.ContextAction menu) {
|
||||
string label, uri;
|
||||
if ((hit_test_result.context & WebKit.HitTestResultContext.IMAGE) != 0) {
|
||||
label = _("Bl_ock image");
|
||||
uri = hit_test_result.image_uri;
|
||||
} else if ((hit_test_result.context & WebKit.HitTestResultContext.LINK) != 0) {
|
||||
label = _("Bl_ock link");
|
||||
uri = hit_test_result.link_uri;
|
||||
} else
|
||||
return;
|
||||
var action = new Gtk.Action ("BlockElement", label, null, null);
|
||||
action.activate.connect ((action) => {
|
||||
CustomRulesEditor custom_rules_editor = new CustomRulesEditor (custom);
|
||||
custom_rules_editor.set_uri (uri);
|
||||
custom_rules_editor.show();
|
||||
});
|
||||
menu.add (action);
|
||||
}
|
||||
|
||||
#if !HAVE_WEBKIT2
|
||||
void resource_requested (WebKit.WebView web_view, WebKit.WebFrame frame,
|
||||
WebKit.WebResource resource, WebKit.NetworkRequest request, WebKit.NetworkResponse? response) {
|
||||
|
||||
if (request_handled (request.uri, web_view.uri)) {
|
||||
request.set_uri ("about:blank");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool navigation_requested (Midori.Tab tab, string uri) {
|
||||
if (uri.has_prefix ("abp:")) {
|
||||
string parsed_uri = parse_subscription_uri (uri);
|
||||
manager.add_subscription (parsed_uri);
|
||||
return true;
|
||||
}
|
||||
status_icon.set_state (config.enabled ? State.ENABLED : State.DISABLED);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
|
||||
string? get_hider_css_for_blocked_resources () {
|
||||
if (hider_selectors.str == "")
|
||||
return null;
|
||||
|
||||
/* Hide elements that were blocked, otherwise we will get "broken image" icon */
|
||||
var code = new StringBuilder (hider_selectors.str);
|
||||
string hider_css;
|
||||
if (debug_element)
|
||||
hider_css = " { background-color: red; border: 4px solid green; }";
|
||||
else
|
||||
hider_css = " { visiblility: hidden; width: 0; height: 0; }";
|
||||
|
||||
code.truncate (code.len -3);
|
||||
code.append (hider_css);
|
||||
if (debug_element)
|
||||
stdout.printf ("hider css: %s\n", code.str);
|
||||
return code.str;
|
||||
}
|
||||
#else
|
||||
string? fetch_js_hider_function_body () {
|
||||
string filename = Midori.Paths.get_res_filename ("adblock/element_hider.js");
|
||||
File js_file = GLib.File.new_for_path (filename);
|
||||
try {
|
||||
uint8[] function_body;
|
||||
js_file.load_contents (null, out function_body, null);
|
||||
return (string)function_body;
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Error while loading adblock hider js: %s\n", error.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
string? get_hider_js_for_blocked_resorces () {
|
||||
if (hider_selectors.str == "")
|
||||
return null;
|
||||
|
||||
if (js_hider_function_body == null || js_hider_function_body == "")
|
||||
return null;
|
||||
|
||||
var js = new StringBuilder ("(function() {");
|
||||
js.append (js_hider_function_body);
|
||||
js.append ("var uris=new Array ();");
|
||||
js.append (hider_selectors.str);
|
||||
js.append (" hideElementBySrc (uris);})();");
|
||||
|
||||
return js.str;
|
||||
}
|
||||
#endif
|
||||
|
||||
string[]? get_domains_for_uri (string uri) {
|
||||
if (uri == null)
|
||||
return null;
|
||||
string[]? domains = null;
|
||||
string domain = Midori.URI.parse_hostname (uri, null);
|
||||
string[] subdomains = domain.split (".");
|
||||
if (subdomains == null)
|
||||
return null;
|
||||
int cnt = subdomains.length - 1;
|
||||
var subdomain = new StringBuilder (subdomains[cnt]);
|
||||
subdomain.prepend_c ('.');
|
||||
cnt--;
|
||||
while (cnt >= 0) {
|
||||
subdomain.prepend (subdomains[cnt]);
|
||||
domains += subdomain.str;
|
||||
subdomain.prepend_c ('.');
|
||||
cnt--;
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
string? get_hider_css_rules_for_uri (string page_uri) {
|
||||
if (page_uri == null)
|
||||
return null;
|
||||
string[]? domains = get_domains_for_uri (page_uri);
|
||||
if (domains == null)
|
||||
return null;
|
||||
var code = new StringBuilder ();
|
||||
int blockscnt = 0;
|
||||
string? style = null;
|
||||
foreach (unowned Subscription sub in config) {
|
||||
foreach (unowned Feature feature in sub) {
|
||||
var element = feature as Element;
|
||||
if (element != null) {
|
||||
foreach (unowned string subdomain in domains) {
|
||||
style = element.lookup (subdomain);
|
||||
if (style != null) {
|
||||
code.append (style);
|
||||
code.append_c (',');
|
||||
blockscnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (blockscnt == 0)
|
||||
return null;
|
||||
code.truncate (code.len - 1);
|
||||
|
||||
string hider_css;
|
||||
if (debug_element)
|
||||
hider_css = " { background-color: red !important; border: 4px solid green !important; }";
|
||||
else
|
||||
hider_css = " { display: none !important }";
|
||||
|
||||
code.append (hider_css);
|
||||
if (debug_element)
|
||||
stdout.printf ("css: %s\n", code.str);
|
||||
|
||||
return code.str;
|
||||
}
|
||||
|
||||
void inject_css (Midori.View view, string page_uri) {
|
||||
/* Don't block ads on internal pages */
|
||||
if (!Midori.URI.is_http (page_uri))
|
||||
return;
|
||||
|
||||
if ("adblock:element" in (Environment.get_variable ("MIDORI_DEBUG") ?? ""))
|
||||
debug_element = true;
|
||||
else
|
||||
debug_element = status_icon.debug_element_toggled;
|
||||
|
||||
#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
|
||||
string? blocked_css = get_hider_css_for_blocked_resources ();
|
||||
if (blocked_css != null)
|
||||
view.inject_stylesheet (blocked_css);
|
||||
#else
|
||||
string? blocked_js = get_hider_js_for_blocked_resorces ();
|
||||
if (blocked_js != null)
|
||||
view.execute_script (blocked_js, null);
|
||||
#endif
|
||||
string? style = get_hider_css_rules_for_uri (page_uri);
|
||||
if (style != null)
|
||||
view.inject_stylesheet (style);
|
||||
}
|
||||
|
||||
internal void init () {
|
||||
hider_selectors = new StringBuilder ();
|
||||
load_config ();
|
||||
manager = new SubscriptionManager (config);
|
||||
status_icon = new StatusIcon (config, manager);
|
||||
foreach (unowned Subscription sub in config) {
|
||||
try {
|
||||
sub.parse ();
|
||||
} catch (GLib.Error error) {
|
||||
warning ("Error parsing %s: %s", sub.uri, error.message);
|
||||
}
|
||||
}
|
||||
config.notify["size"].connect (subscriptions_added_removed);
|
||||
manager.description_label.activate_link.connect (open_link);
|
||||
#if !USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
|
||||
js_hider_function_body = fetch_js_hider_function_body ();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool open_link (string uri) {
|
||||
var browser = get_app ().browser;
|
||||
var view = browser.add_uri (uri);
|
||||
browser.tab = view;
|
||||
return true;
|
||||
}
|
||||
|
||||
void subscriptions_added_removed (ParamSpec pspec) {
|
||||
hider_selectors = new StringBuilder ();
|
||||
}
|
||||
|
||||
void load_config () {
|
||||
#if HAVE_WEBKIT2
|
||||
string config_dir = Path.build_filename (GLib.Environment.get_user_config_dir (), PACKAGE_NAME, "extensions", "libadblock." + GLib.Module.SUFFIX);
|
||||
Midori.Paths.mkdir_with_parents (config_dir);
|
||||
#else
|
||||
string config_dir = Midori.Paths.get_extension_config_dir ("adblock");
|
||||
#endif
|
||||
string presets = Midori.Paths.get_extension_preset_filename ("adblock", "config");
|
||||
string filename = Path.build_filename (config_dir, "config");
|
||||
config = new Config (filename, presets);
|
||||
string custom_list = GLib.Path.build_filename (config_dir, "custom.list");
|
||||
try {
|
||||
custom = new Subscription (Filename.to_uri (custom_list, null));
|
||||
custom.mutable = false;
|
||||
custom.title = _("Custom");
|
||||
config.add (custom);
|
||||
} catch (Error error) {
|
||||
custom = null;
|
||||
warning ("Failed to add custom list %s: %s", custom_list, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
public Adblock.Directive get_directive_for_uri (string request_uri, string page_uri) {
|
||||
if (!config.enabled)
|
||||
return Directive.ALLOW;
|
||||
|
||||
/* Always allow the main page */
|
||||
if (request_uri == page_uri)
|
||||
return Directive.ALLOW;
|
||||
|
||||
/* Skip adblock on internal pages */
|
||||
if (Midori.URI.is_blank (page_uri))
|
||||
return Directive.ALLOW;
|
||||
|
||||
/* Skip adblock on favicons and non http schemes */
|
||||
if (!Midori.URI.is_http (request_uri) || request_uri.has_suffix ("favicon.ico"))
|
||||
return Directive.ALLOW;
|
||||
|
||||
Directive? directive = null;
|
||||
foreach (unowned Subscription sub in config) {
|
||||
directive = sub.get_directive (request_uri, page_uri);
|
||||
if (directive != null)
|
||||
break;
|
||||
}
|
||||
|
||||
if (directive == null)
|
||||
directive = Directive.ALLOW;
|
||||
else if (directive == Directive.BLOCK) {
|
||||
status_icon.set_state (State.BLOCKED);
|
||||
#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
|
||||
hider_selectors.append ("img[src*=\"%s\"] , iframe[src*=\"%s\"] , ".printf (request_uri, request_uri));
|
||||
#else
|
||||
hider_selectors.append (" uris.push ('%s');\n".printf (request_uri));
|
||||
#endif
|
||||
}
|
||||
return directive;
|
||||
}
|
||||
|
||||
internal bool request_handled (string request_uri, string page_uri) {
|
||||
return get_directive_for_uri (request_uri, page_uri) == Directive.BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
static void debug (string format, ...) {
|
||||
bool debug_match = "adblock:match" in (Environment.get_variable ("MIDORI_DEBUG") ?? "");
|
||||
if (!debug_match)
|
||||
return;
|
||||
|
||||
var args = va_list ();
|
||||
stdout.vprintf (format + "\n", args);
|
||||
}
|
||||
|
||||
internal static string? fixup_regex (string prefix, string? src) {
|
||||
if (src == null)
|
||||
return null;
|
||||
|
||||
var fixed = new StringBuilder ();
|
||||
fixed.append(prefix);
|
||||
|
||||
uint i = 0;
|
||||
if (src[0] == '*')
|
||||
i++;
|
||||
uint l = src.length;
|
||||
while (i < l) {
|
||||
char c = src[i];
|
||||
switch (c) {
|
||||
case '*':
|
||||
fixed.append (".*"); break;
|
||||
case '|':
|
||||
case '^':
|
||||
case '+':
|
||||
break;
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
case '.':
|
||||
case '(':
|
||||
case ')':
|
||||
fixed.append_printf ("\\%c", c); break;
|
||||
default:
|
||||
fixed.append_c (c); break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return fixed.str;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_WEBKIT2
|
||||
#if !HAVE_WEBKIT2_3_91
|
||||
Adblock.Extension? filter;
|
||||
public static void webkit_web_extension_initialize (WebKit.WebExtension web_extension) {
|
||||
filter = new Adblock.Extension.WebExtension (web_extension);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new Adblock.Extension ();
|
||||
}
|
||||
|
||||
static string? tmp_folder = null;
|
||||
string get_test_file (string contents) {
|
||||
if (tmp_folder == null)
|
||||
tmp_folder = Midori.Paths.make_tmp_dir ("adblockXXXXXX");
|
||||
string checksum = Checksum.compute_for_string (ChecksumType.MD5, contents);
|
||||
string file = Path.build_path (Path.DIR_SEPARATOR_S, tmp_folder, checksum);
|
||||
try {
|
||||
FileUtils.set_contents (file, contents, -1);
|
||||
} catch (Error file_error) {
|
||||
GLib.error (file_error.message);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
struct TestCaseConfig {
|
||||
public string content;
|
||||
public uint size;
|
||||
public bool enabled;
|
||||
}
|
||||
|
||||
const TestCaseConfig[] configs = {
|
||||
{ "", 0, true },
|
||||
{ "[settings]", 0, true },
|
||||
{ "[settings]\nfilters=foo;", 1, true },
|
||||
{ "[settings]\nfilters=foo;\ndisabled=true", 1, false }
|
||||
};
|
||||
|
||||
void test_adblock_config () {
|
||||
assert (new Adblock.Config (null, null).size == 0);
|
||||
|
||||
foreach (var conf in configs) {
|
||||
var config = new Adblock.Config (get_test_file (conf.content), null);
|
||||
if (config.size != conf.size)
|
||||
error ("Wrong size %s rather than %s:\n%s",
|
||||
config.size.to_string (), conf.size.to_string (), conf.content);
|
||||
if (config.enabled != conf.enabled)
|
||||
error ("Wrongly got enabled=%s rather than %s:\n%s",
|
||||
config.enabled.to_string (), conf.enabled.to_string (), conf.content);
|
||||
}
|
||||
}
|
||||
|
||||
struct TestCaseSub {
|
||||
public string uri;
|
||||
public bool active;
|
||||
}
|
||||
|
||||
const TestCaseSub[] subs = {
|
||||
{ "http://foo.com", true },
|
||||
{ "http://bar.com", false },
|
||||
{ "https://spam.com", true },
|
||||
{ "https://eggs.com", false },
|
||||
{ "file:///bla", true },
|
||||
{ "file:///blub", false }
|
||||
};
|
||||
|
||||
void test_adblock_subs () {
|
||||
var config = new Adblock.Config (get_test_file ("""
|
||||
[settings]
|
||||
filters=http://foo.com;http-//bar.com;https://spam.com;http-://eggs.com;file:///bla;file-///blub;http://foo.com;
|
||||
"""), null);
|
||||
|
||||
assert (config.enabled);
|
||||
foreach (var sub in subs) {
|
||||
bool found = false;
|
||||
foreach (unowned Adblock.Subscription subscription in config) {
|
||||
if (subscription.uri == sub.uri) {
|
||||
assert (subscription.active == sub.active);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
error ("%s not found", sub.uri);
|
||||
}
|
||||
|
||||
/* 6 unique URLs, 1 duplicate */
|
||||
assert (config.size == 6);
|
||||
/* Duplicates aren't added again either */
|
||||
assert (!config.add (new Adblock.Subscription ("https://spam.com")));
|
||||
|
||||
/* Saving the config and loading it should give back identical results */
|
||||
config.save ();
|
||||
var copy = new Adblock.Config (config.path, null);
|
||||
assert (copy.size == config.size);
|
||||
assert (copy.enabled == config.enabled);
|
||||
for (int i = 0; i < config.size; i++) {
|
||||
assert (copy[i].uri == config[i].uri);
|
||||
assert (copy[i].active == config[i].active);
|
||||
}
|
||||
/* Enabled status should be saved and loaded */
|
||||
config.enabled = false;
|
||||
copy = new Adblock.Config (config.path, null);
|
||||
assert (copy.enabled == config.enabled);
|
||||
/* Flipping individual active values should be retained after saving */
|
||||
foreach (unowned Adblock.Subscription sub in config)
|
||||
sub.active = !sub.active;
|
||||
copy = new Adblock.Config (config.path, null);
|
||||
for (uint i = 0; i < config.size; i++) {
|
||||
if (config[i].active != copy[i].active) {
|
||||
string contents;
|
||||
try {
|
||||
FileUtils.get_contents (config.path, out contents, null);
|
||||
} catch (Error file_error) {
|
||||
error (file_error.message);
|
||||
}
|
||||
error ("%s is %s but should be %s:\n%s",
|
||||
copy[i].uri, copy[i].active ? "active" : "disabled", config[i].active ? "active" : "disabled", contents);
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding and removing works, changes size */
|
||||
var s = new Adblock.Subscription ("http://en.de");
|
||||
assert (config.add (s));
|
||||
assert (config.size == 7);
|
||||
config.remove (s);
|
||||
assert (config.size == 6);
|
||||
/* If it was removed before we should be able to add it again */
|
||||
assert (config.add (s));
|
||||
assert (config.size == 7);
|
||||
}
|
||||
|
||||
void test_adblock_init () {
|
||||
/* No config */
|
||||
var extension = new Adblock.Extension ();
|
||||
extension.init ();
|
||||
assert (extension.config.enabled);
|
||||
/* Defaults plus custom */
|
||||
if (extension.config.size != 3)
|
||||
error ("Expected 3 initial subs, got %s".printf (
|
||||
extension.config.size.to_string ()));
|
||||
assert (extension.status_icon.state == Adblock.State.ENABLED);
|
||||
|
||||
/* Add new subscription */
|
||||
string path = Midori.Paths.get_res_filename ("adblock.list");
|
||||
string uri;
|
||||
try {
|
||||
uri = Filename.to_uri (path, null);
|
||||
} catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
var sub = new Adblock.Subscription (uri);
|
||||
extension.config.add (sub);
|
||||
assert (extension.status_icon.state == Adblock.State.ENABLED);
|
||||
assert (extension.config.size == 4);
|
||||
try {
|
||||
sub.parse ();
|
||||
} catch (GLib.Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
/* The page itself never hits */
|
||||
assert (!extension.request_handled ("https://ads.bogus.name/blub", "https://ads.bogus.name/blub"));
|
||||
/* Favicons don't either */
|
||||
assert (!extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub/favicon.ico"));
|
||||
assert (extension.status_icon.state == Adblock.State.ENABLED);
|
||||
/* Some sanity checks to be sure there's no earlier problem */
|
||||
assert (sub.title == "Exercise");
|
||||
assert (sub.get_directive ("https://ads.bogus.name/blub", "") == Adblock.Directive.BLOCK);
|
||||
/* A rule hit should add to the cache */
|
||||
assert (extension.request_handled ("https://ads.bogus.name/blub", "https://foo.com"));
|
||||
assert (extension.status_icon.state == Adblock.State.BLOCKED);
|
||||
assert (extension.hider_selectors.str != "");
|
||||
/* Disabled means no request should be handled */
|
||||
extension.config.enabled = false;
|
||||
assert (!extension.request_handled ("https://ads.bogus.name/blub", "https://foo.com"));
|
||||
// FIXME: assert (extension.status_icon.state == Adblock.State.DISABLED);
|
||||
/* Removing a subscription should clear the cached CSS */
|
||||
extension.config.remove (sub);
|
||||
assert (extension.hider_selectors.str == "");
|
||||
assert (extension.config.size == 3);
|
||||
/* Now let's add a custom rule */
|
||||
extension.config.enabled = true;
|
||||
extension.custom.add_rule ("/adpage.");
|
||||
assert (extension.custom.get_directive ("http://www.engadget.com/_uac/adpage.html", "http://foo.com") == Adblock.Directive.BLOCK);
|
||||
assert (extension.request_handled ("http://www.engadget.com/_uac/adpage.html", "http://foo.com"));
|
||||
assert (extension.status_icon.state == Adblock.State.BLOCKED);
|
||||
/* Second attempt, from cache, same result */
|
||||
assert (extension.custom.get_directive ("http://www.engadget.com/_uac/adpage.html", "http://foo.com") == Adblock.Directive.BLOCK);
|
||||
assert (extension.request_handled ("http://www.engadget.com/_uac/adpage.html", "http://foo.com"));
|
||||
/* Another custom rule */
|
||||
extension.custom.add_rule ("/images/*.png");
|
||||
assert (extension.custom.get_directive ("http://alpha.beta.com/images/yota.png", "https://foo.com") == Adblock.Directive.BLOCK);
|
||||
assert (extension.request_handled ("http://alpha.beta.com/images/yota.png", "https://foo.com"));
|
||||
/* Second attempt, from cache, same result */
|
||||
assert (extension.request_handled ("http://alpha.beta.com/images/yota.png", "https://foo.com"));
|
||||
/* Similar uri but .jpg should pass */
|
||||
assert (!extension.request_handled ("http://alpha.beta.com/images/yota.jpg", "https://foo.com"));
|
||||
assert (extension.custom.get_directive ("http://alpha.beta.com/images/yota.jpg", "https://foo.com") != Adblock.Directive.BLOCK);
|
||||
/* Add whitelist rule */
|
||||
extension.custom.add_rule ("@@http://alpha.beta.com/images/drop*bear.png");
|
||||
assert (!extension.request_handled ("http://alpha.beta.com/images/drop-bear.png", "https://foo.com"));
|
||||
assert (!extension.request_handled ("http://alpha.beta.com/images/dropzone_bear.png", "https://foo.com"));
|
||||
assert (extension.custom.get_directive ("http://alpha.beta.com/images/drop-bear.png", "https://foo.com") != Adblock.Directive.BLOCK);
|
||||
/* Doesn't match whitelist, matches *.png rule, should be blocked */
|
||||
assert (extension.request_handled ("http://alpha.beta.com/images/bear.png", "https://foo.com"));
|
||||
assert (extension.custom.get_directive ("http://alpha.beta.com/images/bear.png", "https://foo.com") == Adblock.Directive.BLOCK);
|
||||
}
|
||||
|
||||
struct TestCaseLine {
|
||||
public string line;
|
||||
public string fixed;
|
||||
}
|
||||
|
||||
const TestCaseLine[] lines = {
|
||||
{ null, null },
|
||||
{ "!", "!" },
|
||||
{ "@@", "@@" },
|
||||
{ "##", "##" },
|
||||
{ "[", "\\[" },
|
||||
{ "+advert/", "advert/" },
|
||||
{ "*foo", "foo" },
|
||||
{ "f*oo", "f.*oo" },
|
||||
{ "?foo", "\\?foo" },
|
||||
{ "foo?", "foo\\?" },
|
||||
{ ".*foo/bar", "..*foo/bar" },
|
||||
{ ".*.*.*.info/popup", "\\..*\\..*\\..*\\.info/popup" },
|
||||
{ "http://bla.blub/*", "http://bla.blub/.*" },
|
||||
{ "bag?r[]=*cpa", "bag\\?r\\[\\]=.*cpa" },
|
||||
{ "(facebookLike,", "\\(facebookLike," }
|
||||
};
|
||||
|
||||
void test_adblock_fixup_regexp () {
|
||||
foreach (var line in lines) {
|
||||
Katze.assert_str_equal (line.line, Adblock.fixup_regex ("", line.line), line.fixed);
|
||||
}
|
||||
}
|
||||
|
||||
struct TestCasePattern {
|
||||
public string uri;
|
||||
public Adblock.Directive directive;
|
||||
}
|
||||
|
||||
const TestCasePattern[] patterns = {
|
||||
{ "http://www.engadget.com/_uac/adpage.html", Adblock.Directive.BLOCK },
|
||||
{ "http://test.dom/test?var=1", Adblock.Directive.BLOCK },
|
||||
{ "http://ads.foo.bar/teddy", Adblock.Directive.BLOCK },
|
||||
{ "http://ads.fuu.bar/teddy", Adblock.Directive.ALLOW },
|
||||
{ "https://ads.bogus.name/blub", Adblock.Directive.BLOCK },
|
||||
// FIXME { "http://ads.bla.blub/kitty", Adblock.Directive.BLOCK },
|
||||
// FIXME { "http://ads.blub.boing/soda", Adblock.Directive.BLOCK },
|
||||
{ "http://ads.foo.boing/beer", Adblock.Directive.ALLOW },
|
||||
{ "https://testsub.engine.adct.ru/test?id=1", Adblock.Directive.BLOCK },
|
||||
{ "http://test.ltd/addyn/test/test?var=adtech;&var2=1", Adblock.Directive.BLOCK },
|
||||
{ "http://add.doubleclick.net/pfadx/aaaa.mtvi", Adblock.Directive.BLOCK },
|
||||
{ "http://add.doubleclick.net/pfadx/aaaa.mtv", Adblock.Directive.ALLOW },
|
||||
{ "http://objects.tremormedia.com/embed/xml/list.xml?r=", Adblock.Directive.BLOCK },
|
||||
{ "http://qq.videostrip.c/sub/admatcherclient.php", Adblock.Directive.ALLOW },
|
||||
{ "http://qq.videostrip.com/sub/admatcherclient.php", Adblock.Directive.BLOCK },
|
||||
{ "http://qq.videostrip.com/sub/admatcherclient.php", Adblock.Directive.BLOCK },
|
||||
{ "http://br.gcl.ru/cgi-bin/br/test", Adblock.Directive.BLOCK },
|
||||
{ "https://bugs.webkit.org/buglist.cgi?query_format=advanced&short_desc_type=allwordssubstr&short_desc=&long_desc_type=substring&long_desc=&bug_file_loc_type=allwordssubstr&bug_file_loc=&keywords_type=allwords&keywords=&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&emailassigned_to1=1&emailtype1=substring&email1=&emailassigned_to2=1&emailreporter2=1&emailcc2=1&emailtype2=substring&email2=&bugidtype=include&bug_id=&votes=&chfieldfrom=&chfieldto=Now&chfieldvalue=&query_based_on=gtkport&field0-0-0=keywords&type0-0-0=anywordssubstr&value0-0-0=Gtk%20Cairo%20soup&field0-0-1=short_desc&type0-0-1=anywordssubstr&value0-0-1=Gtk%20Cairo%20soup%20autoconf%20automake%20autotool&field0-0-2=component&type0-0-2=equals&value0-0-2=WebKit%20Gtk", Adblock.Directive.ALLOW },
|
||||
{ "http://www.engadget.com/2009/09/24/google-hits-android-rom-modder-with-a-cease-and-desist-letter/", Adblock.Directive.ALLOW },
|
||||
{ "http://karibik-invest.com/es/bienes_raices/search.php?sqT=19&sqN=&sqMp=&sqL=0&qR=1&sqMb=&searchMode=1&action=B%FAsqueda", Adblock.Directive.ALLOW },
|
||||
{ "http://google.com", Adblock.Directive.ALLOW }
|
||||
};
|
||||
|
||||
string pretty_directive (Adblock.Directive? directive) {
|
||||
if (directive == null)
|
||||
return "none";
|
||||
return directive.to_string ();
|
||||
}
|
||||
|
||||
void test_adblock_pattern () {
|
||||
string path = Midori.Paths.get_res_filename ("adblock.list");
|
||||
string uri;
|
||||
try {
|
||||
uri = Filename.to_uri (path, null);
|
||||
} catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
var sub = new Adblock.Subscription (uri);
|
||||
try {
|
||||
sub.parse ();
|
||||
} catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
foreach (var pattern in patterns) {
|
||||
Adblock.Directive? directive = sub.get_directive (pattern.uri, "");
|
||||
if (directive == null)
|
||||
directive = Adblock.Directive.ALLOW;
|
||||
if (directive != pattern.directive) {
|
||||
error ("%s expected for %s but got %s",
|
||||
pretty_directive (pattern.directive), pattern.uri, pretty_directive (directive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string pretty_date (DateTime? date) {
|
||||
if (date == null)
|
||||
return "N/A";
|
||||
return date.to_string ();
|
||||
}
|
||||
|
||||
struct TestUpdateExample {
|
||||
public string content;
|
||||
public bool result;
|
||||
public bool valid;
|
||||
}
|
||||
|
||||
const TestUpdateExample[] examples = {
|
||||
{ "[Adblock Plus 1.1]\n! Last modified: 05 Sep 2010 11:00 UTC\n! This list expires after 48 hours\n", true, true },
|
||||
{ "[Adblock Plus 1.1]\n! Last modified: 05.09.2010 11:00 UTC\n! Expires: 2 days (update frequency)\n", true, true },
|
||||
{ "[Adblock Plus 1.1]\n! Updated: 05 Nov 2024 11:00 UTC\n! Expires: 5 days (update frequency)\n", false, true },
|
||||
{ "[Adblock]\n! dutchblock v3\n! This list expires after 14 days\n|http://b*.mookie1.com/\n", false, true },
|
||||
{ "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n! Expires: 5 days (update frequency)\n", true, true },
|
||||
{ "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n", true, true },
|
||||
{ "[Adblock]\n ! dummy, i dont have any dates\n", false, true },
|
||||
/* non-standard update time metadata as found in http://abp.mozilla-hispano.org/nauscopio/filtros.txt */
|
||||
{ "[Adblock Plus 2.0]\n ! Last modified: Oct 26, 2013 18:00 UTC\n ! This list expires after 5 days\n! Last modified by maty: 12Oct2013\n! \n", false, true },
|
||||
{ "\n", false, false }
|
||||
};
|
||||
|
||||
void test_subscription_update () {
|
||||
string uri;
|
||||
FileIOStream iostream;
|
||||
File file;
|
||||
try {
|
||||
file = File.new_tmp ("midori_adblock_update_test_XXXXXX", out iostream);
|
||||
uri = file.get_uri ();
|
||||
} catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
var sub = new Adblock.Subscription (uri);
|
||||
var updater = new Adblock.Updater ();
|
||||
sub.add_feature (updater);
|
||||
|
||||
foreach (var example in examples) {
|
||||
try {
|
||||
file.replace_contents (example.content.data, null, false, FileCreateFlags.NONE, null);
|
||||
sub.clear ();
|
||||
sub.parse ();
|
||||
} catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
if (example.valid != sub.valid)
|
||||
error ("Subscription expected to be %svalid but %svalid:\n%s",
|
||||
example.valid ? "" : "in", sub.valid ? "" : "in", example.content);
|
||||
if (example.result != updater.needs_update)
|
||||
error ("Update%s expected for:\n%s\nLast Updated: %s\nExpires: %s",
|
||||
example.result ? "" : " not", example.content,
|
||||
pretty_date (updater.last_updated), pretty_date (updater.expires));
|
||||
}
|
||||
}
|
||||
|
||||
struct TestSubUri {
|
||||
public string? src_uri;
|
||||
public string? dst_uri;
|
||||
}
|
||||
|
||||
const TestSubUri[] suburis =
|
||||
{
|
||||
{ null, null },
|
||||
{ "not-a-link", null },
|
||||
{ "http://some.uri", "http://some.uri" },
|
||||
{ "abp:subscribe?location=https%3A%2F%2Feasylist-downloads.adblockplus.org%2Fabpindo%2Beasylist.txt&title=ABPindo%2BEasyList", "https://easylist-downloads.adblockplus.org/abpindo+easylist.txt" }
|
||||
};
|
||||
|
||||
void test_subscription_uri_parsing () {
|
||||
string? parsed_uri;
|
||||
foreach (var example in suburis) {
|
||||
parsed_uri = Adblock.parse_subscription_uri (example.src_uri);
|
||||
if (parsed_uri != example.dst_uri)
|
||||
error ("Subscription expected to be %svalid but %svalid:\n%s",
|
||||
example.dst_uri, parsed_uri, example.src_uri);
|
||||
}
|
||||
}
|
||||
|
||||
public void extension_test () {
|
||||
Test.add_func ("/extensions/adblock2/config", test_adblock_config);
|
||||
Test.add_func ("/extensions/adblock2/subs", test_adblock_subs);
|
||||
Test.add_func ("/extensions/adblock2/init", test_adblock_init);
|
||||
Test.add_func ("/extensions/adblock2/parse", test_adblock_fixup_regexp);
|
||||
Test.add_func ("/extensions/adblock2/pattern", test_adblock_pattern);
|
||||
Test.add_func ("/extensions/adblock2/update", test_subscription_update);
|
||||
Test.add_func ("/extensions/adblock2/subsparse", test_subscription_uri_parsing);
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public abstract class Filter : Feature {
|
||||
Options optslist;
|
||||
protected HashTable<string, Regex?> rules;
|
||||
|
||||
public virtual void insert (string sig, Regex regex) {
|
||||
rules.insert (sig, regex);
|
||||
}
|
||||
|
||||
public virtual Regex? lookup (string sig) {
|
||||
return rules.lookup (sig);
|
||||
}
|
||||
|
||||
public virtual uint size () {
|
||||
return rules.size ();
|
||||
}
|
||||
|
||||
protected Filter (Options options) {
|
||||
optslist = options;
|
||||
clear ();
|
||||
}
|
||||
|
||||
public override void clear () {
|
||||
rules = new HashTable<string, Regex> (str_hash, str_equal);
|
||||
}
|
||||
|
||||
protected bool check_rule (Regex regex, string pattern, string request_uri, string page_uri) throws Error {
|
||||
if (!regex.match_full (request_uri))
|
||||
return false;
|
||||
|
||||
var opts = optslist.lookup (pattern);
|
||||
if (opts != null && Regex.match_simple (",third-party", opts,
|
||||
RegexCompileFlags.CASELESS, RegexMatchFlags.NOTEMPTY))
|
||||
if (page_uri != null && regex.match_full (page_uri))
|
||||
return false;
|
||||
debug ("blocked by pattern regexp=%s -- %s", regex.get_pattern (), request_uri);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Keys : Filter {
|
||||
List<Regex> blacklist;
|
||||
|
||||
public Keys (Options options) {
|
||||
base (options);
|
||||
}
|
||||
|
||||
public override void clear () {
|
||||
base.clear ();
|
||||
blacklist = new List<Regex> ();
|
||||
}
|
||||
|
||||
public override Directive? match (string request_uri, string page_uri) throws Error {
|
||||
string? uri = fixup_regex ("", request_uri);
|
||||
if (uri == null)
|
||||
return null;
|
||||
|
||||
int signature_size = 8;
|
||||
int pos, l = uri.length;
|
||||
for (pos = l - signature_size; pos >= 0; pos--) {
|
||||
string signature = uri.offset (pos).ndup (signature_size);
|
||||
var regex = rules.lookup (signature);
|
||||
if (regex == null || blacklist.find (regex) != null)
|
||||
continue;
|
||||
|
||||
if (check_rule (regex, uri, request_uri, page_uri))
|
||||
return Directive.BLOCK;
|
||||
blacklist.prepend (regex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Options : GLib.Object {
|
||||
HashTable<string, string?> optslist;
|
||||
|
||||
public Options () {
|
||||
clear ();
|
||||
}
|
||||
|
||||
public void insert (string sig, string? opts) {
|
||||
optslist.insert (sig, opts);
|
||||
}
|
||||
|
||||
public string? lookup (string sig) {
|
||||
return optslist.lookup (sig);
|
||||
}
|
||||
|
||||
public void clear () {
|
||||
optslist = new HashTable<string, string?> (str_hash, str_equal);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Pattern : Filter {
|
||||
public Pattern (Options options) {
|
||||
base (options);
|
||||
}
|
||||
|
||||
public override Directive? match (string request_uri, string page_uri) throws Error {
|
||||
foreach (unowned string patt in rules.get_keys ())
|
||||
if (check_rule (rules.lookup (patt), patt, request_uri, page_uri))
|
||||
return Directive.BLOCK;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public abstract class Feature : GLib.Object {
|
||||
public virtual bool header (string key, string value) {
|
||||
return false;
|
||||
}
|
||||
public virtual bool parsed (File file) {
|
||||
return true;
|
||||
}
|
||||
public virtual Directive? match (string request_uri, string page_uri) throws Error {
|
||||
return null;
|
||||
}
|
||||
public virtual void clear () {
|
||||
}
|
||||
}
|
||||
|
||||
public class Subscription : GLib.Object {
|
||||
public string? path;
|
||||
bool debug_parse;
|
||||
public string uri { get; set; default = null; }
|
||||
public string title { get; set; default = null; }
|
||||
public bool active { get; set; default = true; }
|
||||
public bool mutable { get; set; default = true; }
|
||||
public bool valid { get; private set; default = true; }
|
||||
HashTable<string, Directive?> cache;
|
||||
List<Feature> features;
|
||||
public Pattern pattern;
|
||||
public Keys keys;
|
||||
public Options optslist;
|
||||
public Whitelist whitelist;
|
||||
public Element element;
|
||||
#if !HAVE_WEBKIT2
|
||||
WebKit.Download? download;
|
||||
#endif
|
||||
|
||||
public Subscription (string uri) {
|
||||
debug_parse = "adblock:parse" in (Environment.get_variable ("MIDORI_DEBUG") ?? "");
|
||||
|
||||
this.uri = uri;
|
||||
|
||||
this.optslist = new Options ();
|
||||
this.whitelist = new Whitelist (optslist);
|
||||
add_feature (this.whitelist);
|
||||
this.keys = new Keys (optslist);
|
||||
add_feature (this.keys);
|
||||
this.pattern = new Pattern (optslist);
|
||||
add_feature (this.pattern);
|
||||
this.element = new Element ();
|
||||
add_feature (this.element);
|
||||
clear ();
|
||||
}
|
||||
|
||||
public void add_feature (Feature feature) {
|
||||
features.append (feature);
|
||||
size++;
|
||||
}
|
||||
|
||||
/* foreach support */
|
||||
public new unowned Feature? get (uint index) {
|
||||
return features.nth_data (index);
|
||||
}
|
||||
public uint size { get; private set; }
|
||||
|
||||
public void clear () {
|
||||
cache = new HashTable<string, Directive?> (str_hash, str_equal);
|
||||
foreach (unowned Feature feature in features)
|
||||
feature.clear ();
|
||||
optslist.clear ();
|
||||
}
|
||||
|
||||
internal void parse_line (string? line) throws Error {
|
||||
if (line.has_prefix ("@@")) {
|
||||
if (line.contains("$") && line.contains ("domain"))
|
||||
return;
|
||||
if (line.has_prefix ("@@||"))
|
||||
add_url_pattern ("^", "whitelist", line.offset (4));
|
||||
else if (line.has_prefix ("@@|"))
|
||||
add_url_pattern ("^", "whitelist", line.offset (3));
|
||||
else
|
||||
add_url_pattern ("", "whitelist", line.offset (2));
|
||||
return;
|
||||
}
|
||||
/* TODO: [include] [exclude] */
|
||||
if (line[0] == '[')
|
||||
return;
|
||||
|
||||
/* CSS block hider */
|
||||
if (line.has_prefix ("##")) {
|
||||
/* TODO */
|
||||
return;
|
||||
}
|
||||
if (line[0] == '#')
|
||||
return;
|
||||
|
||||
/* TODO: CSS hider whitelist */
|
||||
if ("#@#" in line)
|
||||
return;
|
||||
|
||||
/* Per domain CSS hider rule */
|
||||
if ("##" in line) {
|
||||
frame_add_private (line, "##");
|
||||
return;
|
||||
}
|
||||
if ("#" in line) {
|
||||
frame_add_private (line, "#");
|
||||
return;
|
||||
}
|
||||
|
||||
/* URL blocker rule */
|
||||
if (line.has_prefix ("|")) {
|
||||
/* TODO: handle options and domains excludes */
|
||||
if (line.contains("$"))
|
||||
return;
|
||||
|
||||
if (line.has_prefix ("||"))
|
||||
add_url_pattern ("", "fulluri", line.offset (2));
|
||||
else
|
||||
add_url_pattern ("^", "fulluri", line.offset (1));
|
||||
return /* add_url_pattern */;
|
||||
}
|
||||
|
||||
add_url_pattern ("", "uri", line);
|
||||
return /* add_url_pattern */;
|
||||
}
|
||||
|
||||
void frame_add_private (string line, string sep) {
|
||||
string[] data = line.split (sep, 2);
|
||||
if (!(data[1] != null && data[1] != "")
|
||||
|| data[1].chr (-1, '\'') != null
|
||||
|| (data[1].chr (-1, ':') != null
|
||||
&& !Regex.match_simple (".*\\[.*:.*\\].*", data[1],
|
||||
RegexCompileFlags.CASELESS, RegexMatchFlags.NOTEMPTY))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[0].chr (-1, ',') != null) {
|
||||
string[] domains = data[0].split (",", -1);
|
||||
|
||||
foreach (unowned string domain in domains) {
|
||||
/* Ignore Firefox-specific option */
|
||||
if (domain == "~pregecko2")
|
||||
continue;
|
||||
string stripped = domain.strip ();
|
||||
/* FIXME: ~ should negate match */
|
||||
if (stripped[0] == '~')
|
||||
stripped = stripped.substring (1, -1);
|
||||
update_css_hash (stripped, data[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
update_css_hash (data[0], data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool css_element_seems_valid (string element) {
|
||||
bool is_valid = true;
|
||||
string[] valid_elements = { "::after", "::before", "a", "abbr", "address", "article", "aside",
|
||||
"b", "blockquote", "caption", "center", "cite", "code", "div", "dl", "dt", "dd", "em",
|
||||
"feed", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6",
|
||||
"header", "hgroup", "i", "iframe", "iframe html *", "img", "kbd", "label", "legend", "li",
|
||||
"m", "main", "marquee", "menu", "nav", "ol", "option", "p", "pre", "q", "samp", "section",
|
||||
"small", "span", "strong", "summary", "table", "tr", "tbody", "td", "th", "thead", "tt", "ul" };
|
||||
|
||||
if (!element.has_prefix (".") && !element.has_prefix ("#")
|
||||
&& !(element.split("[")[0] in valid_elements))
|
||||
is_valid = false;
|
||||
|
||||
|
||||
bool debug_selectors = "adblock:css" in (Environment.get_variable ("MIDORI_DEBUG") ?? "");
|
||||
if (debug_selectors)
|
||||
stdout.printf ("Adblock '%s' %s: %s\n",
|
||||
this.title, is_valid ? "selector" : "INVALID?", element);
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
void update_css_hash (string domain, string value) {
|
||||
if (css_element_seems_valid (value)) {
|
||||
string? olddata = element.lookup (domain);
|
||||
if (olddata != null) {
|
||||
string newdata = olddata + " , " + value;
|
||||
element.insert (domain, newdata);
|
||||
} else {
|
||||
element.insert (domain, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_url_pattern (string prefix, string type, string line) throws Error {
|
||||
string[]? data = line.split ("$", 2);
|
||||
if (data == null || data[0] == null)
|
||||
return;
|
||||
|
||||
string patt, opts;
|
||||
patt = data[0];
|
||||
opts = type;
|
||||
|
||||
if (data[1] != null)
|
||||
opts = type + "," + data[1];
|
||||
|
||||
if (Regex.match_simple ("subdocument", opts,
|
||||
RegexCompileFlags.CASELESS, RegexMatchFlags.NOTEMPTY))
|
||||
return;
|
||||
|
||||
string format_patt = fixup_regex (prefix, patt);
|
||||
if (debug_parse)
|
||||
stdout.printf ("got: %s opts %s\n", format_patt, opts);
|
||||
compile_regexp (format_patt, opts);
|
||||
/* return format_patt */
|
||||
}
|
||||
|
||||
bool compile_regexp (string? patt, string opts) throws Error {
|
||||
if (patt == null)
|
||||
return false;
|
||||
try {
|
||||
var regex = new Regex (patt, RegexCompileFlags.OPTIMIZE, RegexMatchFlags.NOTEMPTY);
|
||||
/* is pattern is already a regex? */
|
||||
if (Regex.match_simple ("^/.*[\\^\\$\\*].*/$", patt,
|
||||
RegexCompileFlags.UNGREEDY, RegexMatchFlags.NOTEMPTY)
|
||||
|| (opts != null && opts.contains ("whitelist"))) {
|
||||
if (debug_parse)
|
||||
stdout.printf ("patt: %s\n", patt);
|
||||
if (opts.contains ("whitelist"))
|
||||
this.whitelist.insert (patt, regex);
|
||||
else
|
||||
this.pattern.insert (patt, regex);
|
||||
this.optslist.insert (patt, opts);
|
||||
return false;
|
||||
} else { /* nope, no regex */
|
||||
int pos = 0, len;
|
||||
int signature_size = 8;
|
||||
string sig;
|
||||
len = patt.length;
|
||||
|
||||
/* chop up pattern into substrings for faster matching */
|
||||
for (pos = len - signature_size; pos>=0; pos--)
|
||||
{
|
||||
sig = patt.offset (pos).ndup (signature_size);
|
||||
/* we don't have a * nor \\, does not look like regex, save chunk as "key" */
|
||||
if (!Regex.match_simple ("[\\*]", sig, RegexCompileFlags.UNGREEDY, RegexMatchFlags.NOTEMPTY) && keys.lookup (sig) == null) {
|
||||
this.keys.insert (sig, regex);
|
||||
this.optslist.insert (sig, opts);
|
||||
} else {
|
||||
/* starts with * or \\ - save as regex */
|
||||
if ((sig.has_prefix ("*") || sig.has_prefix("\\")) && this.pattern.lookup (sig) == null) {
|
||||
this.pattern.insert (sig, regex);
|
||||
this.optslist.insert (sig, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Adblock compile regexp: %s", error.message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void parse_header (string header) throws Error {
|
||||
/* Headers come in two forms
|
||||
! Foo: Bar
|
||||
! Some freeform text
|
||||
*/
|
||||
string key = header;
|
||||
string value = "";
|
||||
if (header.contains (":")) {
|
||||
string[] parts = header.split (":", 2);
|
||||
if (parts[0] != null && parts[0] != ""
|
||||
&& parts[1] != null && parts[1] != "") {
|
||||
key = parts[0].substring (2, -1);
|
||||
value = parts[1].substring (1, -1);
|
||||
}
|
||||
}
|
||||
debug ("Header '%s' says '%s'", key, value);
|
||||
if (key == "Title")
|
||||
title = value;
|
||||
foreach (unowned Feature feature in features) {
|
||||
if (feature.header (key, value))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !HAVE_WEBKIT2
|
||||
void download_status (ParamSpec pspec) {
|
||||
if (download.get_status () != WebKit.DownloadStatus.FINISHED)
|
||||
return;
|
||||
|
||||
download = null;
|
||||
try {
|
||||
parse ();
|
||||
} catch (Error error) {
|
||||
warning ("Error parsing %s: %s", uri, error.message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void parse () throws Error
|
||||
{
|
||||
if (!active)
|
||||
return;
|
||||
|
||||
debug ("Parsing %s (%s)", uri, path);
|
||||
|
||||
clear ();
|
||||
|
||||
if (uri.has_prefix ("file://"))
|
||||
path = Filename.from_uri (uri);
|
||||
else {
|
||||
string cache_dir = GLib.Path.build_filename (GLib.Environment.get_user_cache_dir (), PACKAGE_NAME, "adblock");
|
||||
Midori.Paths.mkdir_with_parents (cache_dir);
|
||||
string filename = Checksum.compute_for_string (ChecksumType.MD5, this.uri, -1);
|
||||
path = GLib.Path.build_filename (cache_dir, filename);
|
||||
}
|
||||
|
||||
File filter_file = File.new_for_path (path);
|
||||
DataInputStream stream;
|
||||
try {
|
||||
stream = new DataInputStream (filter_file.read ());
|
||||
} catch (IOError.NOT_FOUND exist_error) {
|
||||
#if HAVE_WEBKIT2
|
||||
/* TODO */
|
||||
#else
|
||||
/* Don't bother trying to download local files */
|
||||
if (!uri.has_prefix ("file://")) {
|
||||
if (download != null)
|
||||
return;
|
||||
|
||||
string destination_uri = Filename.to_uri (path, null);
|
||||
debug ("Fetching %s to %s now", uri, destination_uri);
|
||||
download = new WebKit.Download (new WebKit.NetworkRequest (uri));
|
||||
if (!Midori.Download.has_enough_space (download, destination_uri, true))
|
||||
throw new FileError.EXIST ("Can't download to \"%s\"", path);
|
||||
download.destination_uri = destination_uri;
|
||||
download.notify["status"].connect (download_status);
|
||||
download.start ();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
valid = false;
|
||||
string? line;
|
||||
while ((line = stream.read_line (null)) != null) {
|
||||
if (line == null)
|
||||
continue;
|
||||
string chomped = line.chomp ();
|
||||
if (chomped == "")
|
||||
continue;
|
||||
if (line[0] == '!')
|
||||
parse_header (chomped);
|
||||
else
|
||||
parse_line (chomped);
|
||||
/* The file isn't completely empty */
|
||||
valid = true;
|
||||
}
|
||||
|
||||
foreach (unowned Feature feature in features) {
|
||||
if (!feature.parsed (filter_file))
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public Directive? get_directive (string request_uri, string page_uri) {
|
||||
try {
|
||||
Directive? directive = cache.lookup (request_uri);
|
||||
if (directive != null)
|
||||
return directive;
|
||||
foreach (unowned Feature feature in features) {
|
||||
directive = feature.match (request_uri, page_uri);
|
||||
if (directive != null) {
|
||||
debug ("%s gave %s for %s (%s)\n",
|
||||
feature.get_type ().name (), directive.to_string (), request_uri, page_uri);
|
||||
return directive;
|
||||
}
|
||||
}
|
||||
} catch (Error error) {
|
||||
warning ("Adblock match error: %s\n", error.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void add_rule (string rule) {
|
||||
try {
|
||||
var file = File.new_for_uri (uri);
|
||||
file.append_to (FileCreateFlags.NONE).write (("%s\n".printf (rule)).data);
|
||||
parse ();
|
||||
} catch (Error error) {
|
||||
warning ("Failed to add custom rule: %s", error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright (C) 2014 Paweł Forysiuk <tuxator@o2.pl>
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Updater : Feature {
|
||||
string expires_meta;
|
||||
string last_mod_meta;
|
||||
public DateTime last_updated { get; set; }
|
||||
public DateTime expires { get; set; }
|
||||
public bool needs_update { get; set; }
|
||||
|
||||
public Updater () {
|
||||
}
|
||||
|
||||
public override void clear () {
|
||||
expires_meta = null;
|
||||
last_mod_meta = null;
|
||||
last_updated = null;
|
||||
expires = null;
|
||||
needs_update = false;
|
||||
}
|
||||
|
||||
public override bool header (string key, string value) {
|
||||
if (key.has_prefix ("Last mod") || key == "Updated") {
|
||||
last_mod_meta = value;
|
||||
return true;
|
||||
} else if (key == "Expires") {
|
||||
/* ! Expires: 5 days (update frequency) */
|
||||
expires_meta = value;
|
||||
return true;
|
||||
} else if (key.has_prefix ("! This list expires after")) {
|
||||
/* ! This list expires after 14 days */
|
||||
expires_meta = key.substring (26, -1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool parsed (File file) {
|
||||
process_dates (file);
|
||||
/* It's not an error to have no update headers, we go for defaults */
|
||||
return true;
|
||||
}
|
||||
|
||||
int get_month_from_string (string? month) {
|
||||
if (month == null)
|
||||
return 0;
|
||||
|
||||
string[] months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
for (int i = 0; i<= months.length; i++)
|
||||
{
|
||||
if (month.has_prefix (months[i]))
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_dates (File file) {
|
||||
DateTime now = new DateTime.now_local ();
|
||||
last_updated = null;
|
||||
expires = null;
|
||||
|
||||
/* We have "last modification" metadata */
|
||||
if (last_mod_meta != null && (last_mod_meta.contains (" ") && last_mod_meta[0].isdigit () == true)) {
|
||||
int h = 0, min = 0, d, m, y;
|
||||
/* Date in a form of: 20.08.2012 12:34 */
|
||||
if (last_mod_meta.contains (".") || last_mod_meta.contains("-")) {
|
||||
string[] parts = last_mod_meta.split (" ", 2);
|
||||
string[] date_parts;
|
||||
string split_char = " ";
|
||||
|
||||
/* contains time part ? */
|
||||
if (parts[1] != "" && parts[1].contains (":")) {
|
||||
string[] time_parts = parts[1].split (":", 2);
|
||||
h = int.parse(time_parts[0]);
|
||||
min = int.parse(time_parts[1]);
|
||||
}
|
||||
|
||||
/* check if dot or dash was used as a delimiter */
|
||||
if (parts[0].contains ("."))
|
||||
split_char = ".";
|
||||
else if (parts[0].contains ("-"))
|
||||
split_char = "-";
|
||||
|
||||
date_parts = parts[0].split (split_char, 3);
|
||||
m = int.parse(date_parts[1]);
|
||||
if (date_parts[2].length == 4) {
|
||||
y = int.parse(date_parts[2]);
|
||||
d = int.parse(date_parts[0]);
|
||||
} else {
|
||||
y = int.parse(date_parts[0]);
|
||||
d = int.parse(date_parts[2]);
|
||||
}
|
||||
} else { /* Date in a form of: 20 Mar 2012 12:34 */
|
||||
string[] parts = last_mod_meta.split (" ", 4);
|
||||
/* contains time part ? */
|
||||
if (parts[3] != null && parts[3].contains (":")) {
|
||||
string[] time_parts = parts[3].split (":", 2);
|
||||
h = int.parse(time_parts[0]);
|
||||
min = int.parse(time_parts[1]);
|
||||
}
|
||||
|
||||
m = get_month_from_string (parts[1]);
|
||||
if (parts[2].length == 4) {
|
||||
y = int.parse(parts[2]);
|
||||
d = int.parse(parts[0]);
|
||||
} else {
|
||||
y = int.parse(parts[0]);
|
||||
d = int.parse(parts[2]);
|
||||
}
|
||||
}
|
||||
|
||||
last_updated = new DateTime.local (y, m, d, h, min, 0.0);
|
||||
} else {
|
||||
/* FIXME: use file modification date if there's no update header
|
||||
try {
|
||||
string modified = FileAttribute.TIME_MODIFIED;
|
||||
var info = file.query_filesystem_info (modified);
|
||||
last_updated = new DateTime.from_timeval_local (info.get_modification_time ());
|
||||
} catch (Error error) {
|
||||
last_updated = now;
|
||||
}
|
||||
*/
|
||||
last_updated = now;
|
||||
}
|
||||
|
||||
/* We have "expires" metadata */
|
||||
if (expires_meta != null) {
|
||||
if (expires_meta.contains ("days")) {
|
||||
string[] parts = expires_meta.split (" ");
|
||||
expires = last_updated.add_days (int.parse (parts[0]));
|
||||
} else if (expires_meta.contains ("hours")) {
|
||||
string[] parts = expires_meta.split (" ");
|
||||
expires = last_updated.add_hours (int.parse (parts[0]));
|
||||
}
|
||||
} else {
|
||||
/* No expire metadata found, assume x days */
|
||||
int days_to_expire = 7;
|
||||
expires = last_updated.add_days (days_to_expire);
|
||||
}
|
||||
|
||||
/* Check if we are past expire date */
|
||||
needs_update = now.compare (expires) == 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2014 Paweł Forysiuk <tuxator@o2.pl>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
public class Whitelist : Filter {
|
||||
public Whitelist (Options options) {
|
||||
base (options);
|
||||
}
|
||||
|
||||
public override Directive? match (string request_uri, string page_uri) throws Error {
|
||||
foreach (unowned string white in rules.get_keys ()) {
|
||||
var regex = rules.lookup (white);
|
||||
if (!regex.match_full (request_uri))
|
||||
return null;
|
||||
if (Regex.match_simple (regex.get_pattern (), request_uri, RegexCompileFlags.UNGREEDY, RegexMatchFlags.NOTEMPTY))
|
||||
return Directive.ALLOW;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Adblock {
|
||||
|
||||
|
||||
public class StatusIcon : Midori.ContextAction {
|
||||
Config config;
|
||||
SubscriptionManager manager;
|
||||
public State state;
|
||||
public bool debug_element_toggled;
|
||||
|
||||
public StatusIcon (Adblock.Config config, SubscriptionManager manager) {
|
||||
GLib.Object (name: "AdblockStatusMenu");
|
||||
|
||||
this.config = config;
|
||||
this.manager = manager;
|
||||
this.debug_element_toggled = false;
|
||||
|
||||
var item = new Midori.ContextAction ("Preferences",
|
||||
_("Preferences"), null, Gtk.STOCK_PREFERENCES);
|
||||
item.activate.connect (() => {
|
||||
manager.add_subscription (null);
|
||||
});
|
||||
add (item);
|
||||
|
||||
add (null);
|
||||
|
||||
var checkitem = new Gtk.ToggleAction ("Disable", _("Disable"), null, null);
|
||||
checkitem.set_active (!config.enabled);
|
||||
checkitem.toggled.connect (() => {
|
||||
config.enabled = !checkitem.active;
|
||||
set_state (config.enabled ? Adblock.State.ENABLED : Adblock.State.DISABLED);
|
||||
});
|
||||
add (checkitem);
|
||||
|
||||
var hideritem = new Gtk.ToggleAction ("HiddenElements",
|
||||
_("Display hidden elements"), null, null);
|
||||
hideritem.set_active (debug_element_toggled);
|
||||
hideritem.toggled.connect (() => {
|
||||
this.debug_element_toggled = hideritem.active;
|
||||
});
|
||||
add (hideritem);
|
||||
set_status (config.enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
void set_status (string status) {
|
||||
gicon = new GLib.ThemedIcon ("adblock-%s".printf (status));
|
||||
}
|
||||
|
||||
public void set_state (Adblock.State state) {
|
||||
this.state = state;
|
||||
|
||||
if (this.state == State.BLOCKED) {
|
||||
set_status ("blocked");
|
||||
tooltip = _("Blocking");
|
||||
} else if (this.state == State.ENABLED) {
|
||||
set_status ("enabled");
|
||||
tooltip = _("Enabled");
|
||||
} else if (this.state == State.DISABLED) {
|
||||
set_status ("disabled");
|
||||
tooltip = _("Disabled");
|
||||
} else
|
||||
assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
public class SubscriptionManager {
|
||||
Gtk.TreeView treeview;
|
||||
Gtk.ListStore liststore;
|
||||
Adblock.Config config;
|
||||
public Gtk.Label description_label;
|
||||
string description;
|
||||
|
||||
public SubscriptionManager (Config config) {
|
||||
this.config = config;
|
||||
this.liststore = new Gtk.ListStore (1, typeof (Subscription));
|
||||
this.description_label = new Gtk.Label (null);
|
||||
this.description = _("Type the address of a preconfigured filter list in the text entry and hit Enter.\n");
|
||||
this.description += _("You can find more lists by visiting following sites:\n %s, %s\n".printf (
|
||||
"<a href=\"http://adblockplus.org/en/subscriptions\">adblockplus.org/en/subscriptions</a>",
|
||||
"<a href=\"http://easylist.adblockplus.org/\">easylist.adblockplus.org</a>"
|
||||
));
|
||||
}
|
||||
|
||||
public void add_subscription (string? uri) {
|
||||
var dialog = new Gtk.Dialog.with_buttons (_("Configure Advertisement filters"),
|
||||
null,
|
||||
#if !HAVE_GTK3
|
||||
Gtk.DialogFlags.NO_SEPARATOR |
|
||||
#endif
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
Gtk.STOCK_HELP, Gtk.ResponseType.HELP,
|
||||
Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE);
|
||||
#if HAVE_GTK3
|
||||
dialog.get_widget_for_response (Gtk.ResponseType.HELP).get_style_context ().add_class ("help_button");
|
||||
#endif
|
||||
dialog.set_icon_name (Gtk.STOCK_PROPERTIES);
|
||||
dialog.set_response_sensitive (Gtk.ResponseType.HELP, false);
|
||||
|
||||
var hbox = new Gtk.HBox (false, 0);
|
||||
(dialog.get_content_area () as Gtk.Box).pack_start (hbox, true, true, 12);
|
||||
var vbox = new Gtk.VBox (false, 0);
|
||||
hbox.pack_start (vbox, true, true, 4);
|
||||
this.description_label.set_markup (this.description);
|
||||
this.description_label.set_line_wrap (true);
|
||||
vbox.pack_start (this.description_label, false, false, 4);
|
||||
|
||||
var entry = new Gtk.Entry ();
|
||||
if (uri != null)
|
||||
entry.set_text (uri);
|
||||
vbox.pack_start (entry, false, false, 4);
|
||||
|
||||
liststore = new Gtk.ListStore (1, typeof (Subscription));
|
||||
treeview = new Gtk.TreeView.with_model (liststore);
|
||||
treeview.set_headers_visible (false);
|
||||
var column = new Gtk.TreeViewColumn ();
|
||||
var renderer_toggle = new Gtk.CellRendererToggle ();
|
||||
column.pack_start (renderer_toggle, false);
|
||||
column.set_cell_data_func (renderer_toggle, (column, renderer, model, iter) => {
|
||||
Subscription sub;
|
||||
liststore.get (iter, 0, out sub);
|
||||
renderer.set ("active", sub.active,
|
||||
"sensitive", sub.mutable);
|
||||
});
|
||||
renderer_toggle.toggled.connect ((path) => {
|
||||
Gtk.TreeIter iter;
|
||||
if (liststore.get_iter_from_string (out iter, path)) {
|
||||
Subscription sub;
|
||||
liststore.get (iter, 0, out sub);
|
||||
sub.active = !sub.active;
|
||||
}
|
||||
});
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
var renderer_text = new Gtk.CellRendererText ();
|
||||
column.pack_start (renderer_text, false);
|
||||
renderer_text.set ("editable", true);
|
||||
// TODO: renderer_text.edited.connect
|
||||
column.set_cell_data_func (renderer_text, (column, renderer, model, iter) => {
|
||||
Subscription sub;
|
||||
liststore.get (iter, 0, out sub);
|
||||
string status = "";
|
||||
foreach (unowned Feature feature in sub) {
|
||||
var updater = feature as Adblock.Updater;
|
||||
if (updater != null) {
|
||||
if (updater.last_updated != null)
|
||||
status = updater.last_updated.format (_("Last update: %x %X"));
|
||||
}
|
||||
}
|
||||
if (!sub.valid)
|
||||
status = _("File incomplete - broken download?");
|
||||
renderer.set ("markup", (Markup.printf_escaped ("<b>%s</b>\n%s",
|
||||
sub.title ?? sub.uri, status)));
|
||||
});
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_button = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_button, false);
|
||||
column.set_cell_data_func (renderer_button, on_render_button);
|
||||
treeview.append_column (column);
|
||||
|
||||
var scrolled = new Gtk.ScrolledWindow (null, null);
|
||||
scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
|
||||
scrolled.add (treeview);
|
||||
vbox.pack_start (scrolled);
|
||||
int height;
|
||||
treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height);
|
||||
scrolled.set_size_request (-1, height * 5);
|
||||
|
||||
foreach (unowned Subscription sub in config)
|
||||
liststore.insert_with_values (null, 0, 0, sub);
|
||||
treeview.button_release_event.connect (button_released);
|
||||
|
||||
entry.activate.connect (() => {
|
||||
string? parsed_uri = Adblock.parse_subscription_uri (entry.text);
|
||||
if (parsed_uri != null) {
|
||||
var sub = new Subscription (parsed_uri);
|
||||
if (config.add (sub)) {
|
||||
liststore.insert_with_values (null, 0, 0, sub);
|
||||
try {
|
||||
sub.parse ();
|
||||
} catch (GLib.Error error) {
|
||||
warning ("Error parsing %s: %s", sub.uri, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.text = "";
|
||||
});
|
||||
|
||||
dialog.get_content_area ().show_all ();
|
||||
|
||||
dialog.response.connect ((response)=>{ dialog.destroy (); });
|
||||
dialog.show ();
|
||||
}
|
||||
|
||||
void on_render_button (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Subscription sub;
|
||||
liststore.get (iter, 0, out sub);
|
||||
|
||||
renderer.set ("stock-id", sub.mutable ? Gtk.STOCK_DELETE : null,
|
||||
"stock-size", Gtk.IconSize.MENU);
|
||||
}
|
||||
|
||||
public bool button_released (Gdk.EventButton event) {
|
||||
Gtk.TreePath? path;
|
||||
Gtk.TreeViewColumn column;
|
||||
if (treeview.get_path_at_pos ((int)event.x, (int)event.y, out path, out column, null, null)) {
|
||||
if (path != null) {
|
||||
if (column == treeview.get_column (2)) {
|
||||
Gtk.TreeIter iter;
|
||||
if (liststore.get_iter (out iter, path)) {
|
||||
Subscription sub;
|
||||
liststore.get (iter, 0, out sub);
|
||||
if (sub.mutable) {
|
||||
config.remove (sub);
|
||||
liststore.remove (iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class CustomRulesEditor {
|
||||
Gtk.Dialog dialog;
|
||||
Subscription custom;
|
||||
public string? rule { get; set; }
|
||||
|
||||
public CustomRulesEditor (Subscription custom) {
|
||||
this.custom = custom;
|
||||
}
|
||||
|
||||
public void set_uri (string uri) {
|
||||
this.rule = uri;
|
||||
}
|
||||
|
||||
public void show () {
|
||||
this.dialog = new Gtk.Dialog.with_buttons (_("Edit rule"),
|
||||
null,
|
||||
#if !HAVE_GTK3
|
||||
Gtk.DialogFlags.NO_SEPARATOR |
|
||||
#endif
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_ADD, Gtk.ResponseType.ACCEPT);
|
||||
dialog.set_icon_name (Gtk.STOCK_ADD);
|
||||
dialog.resizable = false;
|
||||
|
||||
var hbox = new Gtk.HBox (false, 8);
|
||||
var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
|
||||
hbox.border_width = 5;
|
||||
var label = new Gtk.Label.with_mnemonic (_("_Rule:"));
|
||||
sizegroup.add_widget (label);
|
||||
hbox.pack_start (label, false, false, 0);
|
||||
(dialog.get_content_area () as Gtk.Box).pack_start (hbox, false, true, 0);
|
||||
|
||||
var entry = new Gtk.Entry ();
|
||||
sizegroup.add_widget (entry);
|
||||
entry.activates_default = true;
|
||||
entry.set_text (this.rule);
|
||||
hbox.pack_start (entry, true, true, 0);
|
||||
|
||||
dialog.get_content_area ().show_all ();
|
||||
|
||||
dialog.set_default_response (Gtk.ResponseType.ACCEPT);
|
||||
if (dialog.run () != Gtk.ResponseType.ACCEPT)
|
||||
return;
|
||||
|
||||
this.rule = entry.get_text ();
|
||||
this.dialog.destroy ();
|
||||
custom.add_rule (this.rule);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
/* This extensions add support for user addons: userscripts and userstyles */
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include "midori-core.h"
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "config.h"
|
||||
|
@ -182,8 +183,8 @@ addons_install_response (GtkWidget* infobar,
|
|||
|
||||
if (!filename)
|
||||
filename = g_path_get_basename (uri);
|
||||
folder_path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
PACKAGE_NAME, folder, NULL);
|
||||
folder_path = g_build_path (G_DIR_SEPARATOR_S,
|
||||
midori_paths_get_user_data_dir (), PACKAGE_NAME, folder, NULL);
|
||||
|
||||
if (!g_file_test (folder_path, G_FILE_TEST_EXISTS))
|
||||
katze_mkdir_with_parents (folder_path, 0700);
|
||||
|
@ -242,9 +243,8 @@ addons_notify_load_status_cb (MidoriView* view,
|
|||
MidoriExtension* extension)
|
||||
{
|
||||
const gchar* uri = midori_view_get_display_uri (view);
|
||||
WebKitWebView* web_view = WEBKIT_WEB_VIEW (midori_view_get_web_view (view));
|
||||
|
||||
if (webkit_web_view_get_view_source_mode (web_view))
|
||||
if (midori_tab_get_view_source (MIDORI_TAB (view)))
|
||||
return;
|
||||
|
||||
if (uri && *uri)
|
||||
|
@ -293,13 +293,13 @@ addons_button_add_clicked_cb (GtkToolItem* toolitem,
|
|||
if (addons->kind == ADDONS_USER_SCRIPTS)
|
||||
{
|
||||
addons_type = g_strdup ("userscripts");
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, "scripts", NULL);
|
||||
}
|
||||
else if (addons->kind == ADDONS_USER_STYLES)
|
||||
{
|
||||
addons_type = g_strdup ("userstyles");
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, "styles", NULL);
|
||||
}
|
||||
else
|
||||
|
@ -336,23 +336,13 @@ addons_button_add_clicked_cb (GtkToolItem* toolitem,
|
|||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
katze_mkdir_with_parents (path, 0700);
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 14, 0)
|
||||
files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
|
||||
#else
|
||||
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
|
||||
#endif
|
||||
|
||||
while (files)
|
||||
{
|
||||
GFile* src_file;
|
||||
GError* error = NULL;
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 14, 0)
|
||||
src_file = g_file_new_for_path (files);
|
||||
#else
|
||||
src_file = files->data;
|
||||
#endif
|
||||
|
||||
if (G_IS_FILE (src_file))
|
||||
{
|
||||
GFile* dest_file;
|
||||
|
@ -403,6 +393,9 @@ addons_button_delete_clicked_cb (GtkWidget* toolitem,
|
|||
{
|
||||
GtkTreeModel* model;
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath* path;
|
||||
GtkTreeRowReference* row;
|
||||
gchar* fullpath;
|
||||
|
||||
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (addons->treeview),
|
||||
&model, &iter))
|
||||
|
@ -413,6 +406,11 @@ addons_button_delete_clicked_cb (GtkWidget* toolitem,
|
|||
gchar* markup;
|
||||
|
||||
gtk_tree_model_get (model, &iter, 0, &element, -1);
|
||||
fullpath = g_strdup (element->fullpath);
|
||||
|
||||
path = gtk_tree_model_get_path (model, &iter);
|
||||
row = gtk_tree_row_reference_new (model, path);
|
||||
gtk_tree_path_free (path);
|
||||
dialog = gtk_message_dialog_new (
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (addons))),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
|
@ -434,6 +432,9 @@ addons_button_delete_clicked_cb (GtkWidget* toolitem,
|
|||
GTK_MESSAGE_DIALOG (dialog), "%s", markup);
|
||||
g_free (markup);
|
||||
|
||||
/* The execution of gtk_dialog_run allows the directory watcher to
|
||||
rebuild the treeview and the element list, so our references may be
|
||||
invalid afterward */
|
||||
delete_response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
|
||||
|
@ -443,7 +444,7 @@ addons_button_delete_clicked_cb (GtkWidget* toolitem,
|
|||
GFile* file;
|
||||
gboolean result;
|
||||
|
||||
file = g_file_new_for_path (element->fullpath);
|
||||
file = g_file_new_for_path (fullpath);
|
||||
result = g_file_delete (file, NULL, &error);
|
||||
|
||||
if (!result && error)
|
||||
|
@ -462,11 +463,20 @@ addons_button_delete_clicked_cb (GtkWidget* toolitem,
|
|||
g_error_free (error);
|
||||
}
|
||||
|
||||
if (result)
|
||||
/* The row reference may have been invalidated if the
|
||||
filesystem watcher deleted the row concurrently */
|
||||
if (result && gtk_tree_row_reference_valid (row))
|
||||
{
|
||||
path = gtk_tree_row_reference_get_path (row);
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
gtk_tree_path_free (path);
|
||||
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
|
||||
}
|
||||
|
||||
gtk_tree_row_reference_free (row);
|
||||
g_object_unref (file);
|
||||
}
|
||||
g_free (fullpath);
|
||||
}
|
||||
}
|
||||
static void
|
||||
|
@ -491,12 +501,12 @@ addons_open_in_editor_clicked_cb (GtkWidget* toolitem,
|
|||
|
||||
g_object_get (settings, "text-editor", &text_editor, NULL);
|
||||
if (text_editor && *text_editor)
|
||||
sokoke_spawn_program (text_editor, element->fullpath);
|
||||
sokoke_spawn_program (text_editor, TRUE, element->fullpath, TRUE, FALSE);
|
||||
else
|
||||
{
|
||||
gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL);
|
||||
sokoke_show_uri (NULL, element_uri,
|
||||
gtk_get_current_event_time (), NULL);
|
||||
gboolean handled = FALSE;
|
||||
g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", element_uri, &handled);
|
||||
g_free (element_uri);
|
||||
}
|
||||
|
||||
|
@ -522,15 +532,19 @@ addons_open_target_folder_clicked_cb (GtkWidget* toolitem,
|
|||
folder = g_path_get_dirname (element->fullpath);
|
||||
}
|
||||
else
|
||||
folder = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
PACKAGE_NAME,
|
||||
addons->kind == ADDONS_USER_SCRIPTS
|
||||
? "scripts" : "styles", NULL);
|
||||
{
|
||||
folder = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, addons->kind == ADDONS_USER_SCRIPTS
|
||||
? "scripts" : "styles", NULL);
|
||||
katze_mkdir_with_parents (folder, 0700);
|
||||
}
|
||||
|
||||
folder_uri = g_filename_to_uri (folder, NULL, NULL);
|
||||
g_free (folder);
|
||||
|
||||
sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (addons->treeview)),
|
||||
folder_uri, gtk_get_current_event_time (), NULL);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (addons->treeview);
|
||||
gboolean handled = FALSE;
|
||||
g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", folder_uri, &handled);
|
||||
g_free (folder_uri);
|
||||
}
|
||||
|
||||
|
@ -624,7 +638,6 @@ addons_get_toolbar (MidoriViewable* viewable)
|
|||
if (!ADDONS (viewable)->toolbar)
|
||||
{
|
||||
toolbar = gtk_toolbar_new ();
|
||||
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
|
||||
toolitem = gtk_tool_item_new ();
|
||||
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
|
||||
gtk_widget_show (GTK_WIDGET (toolitem));
|
||||
|
@ -783,11 +796,10 @@ addons_treeview_render_text_cb (GtkTreeViewColumn* column,
|
|||
|
||||
gtk_tree_model_get (model, iter, 0, &element, -1);
|
||||
|
||||
g_object_set (renderer, "text", element->displayname, NULL);
|
||||
if (!element->enabled)
|
||||
g_object_set (renderer, "sensitive", false, NULL);
|
||||
else
|
||||
g_object_set (renderer, "sensitive", true, NULL);
|
||||
g_object_set (renderer, "text", element->displayname,
|
||||
"sensitive", element->enabled,
|
||||
"ellipsize", PANGO_ELLIPSIZE_END,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -831,19 +843,16 @@ addons_get_directories (AddonsKind kind)
|
|||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, folder_name, NULL);
|
||||
if (g_access (path, X_OK) == 0)
|
||||
directories = g_slist_prepend (directories, path);
|
||||
else
|
||||
g_free (path);
|
||||
directories = g_slist_prepend (directories, path);
|
||||
|
||||
datadirs = g_get_system_data_dirs ();
|
||||
while (*datadirs)
|
||||
{
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, *datadirs,
|
||||
PACKAGE_NAME, folder_name, NULL);
|
||||
if (g_slist_find (directories, path) == NULL && g_access (path, X_OK) == 0)
|
||||
if (g_slist_find (directories, path) == NULL)
|
||||
directories = g_slist_prepend (directories, path);
|
||||
else
|
||||
g_free (path);
|
||||
|
@ -940,10 +949,16 @@ js_metadata_from_file (const gchar* filename,
|
|||
/* We don't support these, so abort here */
|
||||
g_free (line);
|
||||
g_io_channel_shutdown (channel, false, 0);
|
||||
g_slist_free (*includes);
|
||||
g_slist_free (*excludes);
|
||||
*includes = NULL;
|
||||
*excludes = NULL;
|
||||
if (includes != NULL)
|
||||
{
|
||||
g_slist_free (*includes);
|
||||
*includes = NULL;
|
||||
}
|
||||
if (excludes != NULL)
|
||||
{
|
||||
g_slist_free (*excludes);
|
||||
*excludes = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else if (includes && g_str_has_prefix (line, "// @include"))
|
||||
|
@ -1049,7 +1064,7 @@ css_metadata_from_file (const gchar* filename,
|
|||
domain = g_strndup (value + begin, end - begin * 2);
|
||||
if (!midori_uri_is_location (domain)
|
||||
&& !g_str_has_prefix (domain, "file://"))
|
||||
tmp_domain = g_strdup_printf ("http://*%s/*", domain);
|
||||
tmp_domain = g_strdup_printf ("http*://*%s/*", domain);
|
||||
else
|
||||
tmp_domain = domain;
|
||||
|
||||
|
@ -1335,8 +1350,9 @@ addons_init (Addons* addons)
|
|||
G_CALLBACK (addons_cell_renderer_toggled_cb), addons);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (addons->treeview), column);
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_column_set_expand (column, TRUE);
|
||||
renderer_text = gtk_cell_renderer_text_new ();
|
||||
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
|
||||
gtk_tree_view_column_pack_start (column, renderer_text, TRUE);
|
||||
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
|
||||
(GtkTreeCellDataFunc)addons_treeview_render_text_cb,
|
||||
addons->treeview, NULL);
|
||||
|
@ -1452,6 +1468,12 @@ static gboolean
|
|||
addons_skip_element (struct AddonElement* element,
|
||||
gchar* uri)
|
||||
{
|
||||
if (midori_debug("addons:match"))
|
||||
{
|
||||
g_print("%s: %s on %s matched: %d\n", G_STRFUNC,
|
||||
element->displayname, uri, addons_may_run (uri, &element->includes, &element->excludes));
|
||||
}
|
||||
|
||||
if (!element->enabled || element->broken)
|
||||
return TRUE;
|
||||
if (element->includes || element->excludes)
|
||||
|
@ -1526,30 +1548,19 @@ addons_add_tab_cb (MidoriBrowser* browser,
|
|||
G_CALLBACK (addons_notify_load_status_cb), extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_add_tab_foreach_cb (MidoriView* view,
|
||||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
addons_add_tab_cb (browser, view, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_deactivate_tabs (MidoriView* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, addons_context_ready_cb, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_browser_destroy (MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* scripts, *styles;
|
||||
|
||||
midori_browser_foreach (browser, (GtkCallback)addons_deactivate_tabs, extension);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (tabs->data);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, addons_context_ready_cb, extension);
|
||||
}
|
||||
g_list_free (tabs);
|
||||
g_signal_handlers_disconnect_by_func (browser, addons_add_tab_cb, extension);
|
||||
|
||||
scripts = (GtkWidget*)g_object_get_data (G_OBJECT (browser), "scripts-addons");
|
||||
|
@ -1629,9 +1640,10 @@ addons_app_add_browser_cb (MidoriApp* app,
|
|||
{
|
||||
GtkWidget* panel;
|
||||
GtkWidget* scripts, *styles;
|
||||
|
||||
midori_browser_foreach (browser,
|
||||
(GtkCallback)addons_add_tab_foreach_cb, extension);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
addons_add_tab_cb (browser, tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (addons_add_tab_cb), extension);
|
||||
panel = katze_object_get_object (browser, "panel");
|
||||
|
@ -1687,10 +1699,10 @@ addons_save_settings (MidoriApp* app,
|
|||
|
||||
config_dir = midori_extension_get_config_dir (extension);
|
||||
config_file = g_build_filename (config_dir, "addons", NULL);
|
||||
katze_mkdir_with_parents (config_dir, 0700);
|
||||
if (config_dir != NULL)
|
||||
katze_mkdir_with_parents (config_dir, 0700);
|
||||
sokoke_key_file_save_to_file (keyfile, config_file, &error);
|
||||
/* If the folder is /, this is a test run, thus no error */
|
||||
if (error && !g_str_equal (config_dir, "/"))
|
||||
if (error && midori_extension_get_config_dir (extension) != NULL)
|
||||
{
|
||||
g_warning (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
_("User addons"), error->message);
|
||||
|
@ -1866,7 +1878,6 @@ addons_activate_cb (MidoriExtension* extension,
|
|||
G_CALLBACK (addons_deactivate_cb), app);
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static void
|
||||
test_addons_simple_regexp (void)
|
||||
{
|
||||
|
@ -1881,6 +1892,8 @@ test_addons_simple_regexp (void)
|
|||
{ "*", "^.*" },
|
||||
{ "http://", "^http://" },
|
||||
{ "https://", "^https://" },
|
||||
{ "http*://", "^http://" },
|
||||
{ "http*://", "^https://" },
|
||||
{ "about:blank", "^about:blank" },
|
||||
{ "file://", "^file://" },
|
||||
{ "ftp://", "^ftp://" },
|
||||
|
@ -1905,7 +1918,6 @@ extension_test (void)
|
|||
{
|
||||
g_test_add_func ("/extensions/addons/simple_regexp", test_addons_simple_regexp);
|
||||
}
|
||||
#endif
|
||||
|
||||
MidoriExtension*
|
||||
extension_init (void)
|
||||
|
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
Copyright (C) 2013 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace Apps {
|
||||
const string APP_PREFIX = PACKAGE_NAME + " -a ";
|
||||
const string PROFILE_PREFIX = PACKAGE_NAME + " -c ";
|
||||
|
||||
private class Launcher : GLib.Object, GLib.Initable {
|
||||
internal GLib.File file;
|
||||
internal string name;
|
||||
internal string icon_name;
|
||||
internal string exec;
|
||||
internal string uri;
|
||||
|
||||
internal static string get_favicon_name_for_uri (string prefix, GLib.File folder, string uri, bool testing)
|
||||
{
|
||||
string icon_name = Midori.Stock.WEB_BROWSER;
|
||||
|
||||
if (testing == true)
|
||||
return icon_name;
|
||||
|
||||
if (prefix != PROFILE_PREFIX)
|
||||
{
|
||||
try {
|
||||
var pixbuf = Midori.Paths.get_icon (uri, null);
|
||||
if (pixbuf == null)
|
||||
throw new FileError.EXIST ("No favicon loaded");
|
||||
string icon_filename = folder.get_child ("icon.png").get_path ();
|
||||
pixbuf.save (icon_filename, "png", null, "compression", "7", null);
|
||||
#if HAVE_WIN32
|
||||
string doubleslash_icon = icon_filename.replace ("\\", "\\\\");
|
||||
icon_name = doubleslash_icon;
|
||||
#else
|
||||
icon_name = icon_filename;
|
||||
#endif
|
||||
}
|
||||
catch (Error error) {
|
||||
GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message);
|
||||
}
|
||||
}
|
||||
return icon_name;
|
||||
}
|
||||
|
||||
internal static string prepare_desktop_file (string prefix, string name, string uri, string title, string icon_name)
|
||||
{
|
||||
string exec;
|
||||
#if HAVE_WIN32
|
||||
string doubleslash_uri = uri.replace ("\\", "\\\\");
|
||||
string quoted_uri = GLib.Shell.quote (doubleslash_uri);
|
||||
exec = prefix + quoted_uri;
|
||||
#else
|
||||
exec = prefix + uri;
|
||||
#endif
|
||||
var keyfile = new GLib.KeyFile ();
|
||||
string entry = "Desktop Entry";
|
||||
|
||||
keyfile.set_string (entry, "Version", "1.0");
|
||||
keyfile.set_string (entry, "Type", "Application");
|
||||
keyfile.set_string (entry, "Name", name);
|
||||
keyfile.set_string (entry, "Exec", exec);
|
||||
keyfile.set_string (entry, "TryExec", PACKAGE_NAME);
|
||||
keyfile.set_string (entry, "Icon", icon_name);
|
||||
keyfile.set_string (entry, "Categories", "Network;");
|
||||
/*
|
||||
Using the sanitized URI as a class matches midori_web_app_new
|
||||
So dock type launchers can distinguish different apps with the same executable
|
||||
*/
|
||||
if (exec.has_prefix (APP_PREFIX))
|
||||
keyfile.set_string (entry, "StartupWMClass", uri.delimit (":.\\/", '_'));
|
||||
|
||||
return keyfile.to_data();
|
||||
}
|
||||
|
||||
internal static File get_app_folder () {
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
|
||||
return data_dir.get_child ("apps");
|
||||
}
|
||||
|
||||
internal static async File create_app (string uri, string title, Gtk.Widget? proxy) {
|
||||
string checksum = Checksum.compute_for_string (ChecksumType.MD5, uri, -1);
|
||||
var folder = get_app_folder ();
|
||||
yield Launcher.create (APP_PREFIX, folder.get_child (checksum),
|
||||
uri, title, proxy);
|
||||
return folder.get_child (checksum);
|
||||
}
|
||||
|
||||
internal static File get_profile_folder () {
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
|
||||
return data_dir.get_child ("profiles");
|
||||
}
|
||||
|
||||
internal static async File create_profile (Gtk.Widget? proxy) {
|
||||
string uuid = g_dbus_generate_guid ();
|
||||
string config = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid);
|
||||
var folder = get_profile_folder ();
|
||||
yield Launcher.create (PROFILE_PREFIX, folder.get_child (uuid),
|
||||
config, _("Midori (%s)").printf (uuid), proxy);
|
||||
return folder.get_child (uuid);
|
||||
}
|
||||
|
||||
internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) {
|
||||
/* Strip LRE leading character and / */
|
||||
string name = title.delimit ("/", ' ').strip();
|
||||
string filename = Midori.Download.clean_filename (name);
|
||||
string icon_name = Midori.Stock.WEB_BROWSER;
|
||||
bool testing = false;
|
||||
if (proxy == null)
|
||||
testing = true;
|
||||
var file = folder.get_child ("desc");
|
||||
|
||||
try {
|
||||
folder.make_directory_with_parents (null);
|
||||
} catch (IOError.EXISTS exist_error) {
|
||||
/* It's no error if the folder already exists */
|
||||
} catch (Error error) {
|
||||
warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
|
||||
}
|
||||
|
||||
icon_name = get_favicon_name_for_uri (prefix, folder, uri, testing);
|
||||
string desktop_file = prepare_desktop_file (prefix, name, uri, title, icon_name);
|
||||
|
||||
try {
|
||||
var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE);
|
||||
yield stream.write_async (desktop_file.data);
|
||||
// Create a launcher/ menu
|
||||
#if HAVE_WIN32
|
||||
Midori.Sokoke.create_win32_desktop_lnk (prefix, filename, uri);
|
||||
#else
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
|
||||
var desktop_dir = data_dir.get_child ("applications");
|
||||
try {
|
||||
desktop_dir.make_directory_with_parents (null);
|
||||
} catch (IOError.EXISTS exist_error) {
|
||||
/* It's no error if the folder already exists */
|
||||
}
|
||||
|
||||
yield file.copy_async (desktop_dir.get_child (filename + ".desktop"),
|
||||
GLib.FileCopyFlags.NONE);
|
||||
#endif
|
||||
if (proxy != null) {
|
||||
var browser = proxy.get_toplevel () as Midori.Browser;
|
||||
browser.send_notification (_("Launcher created"),
|
||||
_("You can now run <b>%s</b> from your launcher or menu").printf (name));
|
||||
}
|
||||
}
|
||||
catch (Error error) {
|
||||
warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
|
||||
if (proxy != null) {
|
||||
var browser = proxy.get_toplevel () as Midori.Browser;
|
||||
browser.send_notification (_("Error creating launcher"),
|
||||
_("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal Launcher (GLib.File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
bool init (GLib.Cancellable? cancellable) throws GLib.Error {
|
||||
var keyfile = new GLib.KeyFile ();
|
||||
try {
|
||||
keyfile.load_from_file (file.get_child ("desc").get_path (), GLib.KeyFileFlags.NONE);
|
||||
} catch (Error desc_error) {
|
||||
throw new FileError.EXIST (_("No file \"desc\" found"));
|
||||
}
|
||||
|
||||
exec = keyfile.get_string ("Desktop Entry", "Exec");
|
||||
if (!exec.has_prefix (APP_PREFIX) && !exec.has_prefix (PROFILE_PREFIX))
|
||||
return false;
|
||||
|
||||
name = keyfile.get_string ("Desktop Entry", "Name");
|
||||
icon_name = keyfile.get_string ("Desktop Entry", "Icon");
|
||||
uri = exec.replace (APP_PREFIX, "").replace (PROFILE_PREFIX, "");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class Sidebar : Gtk.VBox, Midori.Viewable {
|
||||
Gtk.Toolbar? toolbar = null;
|
||||
Gtk.ListStore store = new Gtk.ListStore (1, typeof (Launcher));
|
||||
Gtk.TreeView treeview;
|
||||
Katze.Array array;
|
||||
GLib.File app_folder;
|
||||
GLib.File profile_folder;
|
||||
|
||||
public unowned string get_stock_id () {
|
||||
return Midori.Stock.WEB_BROWSER;
|
||||
}
|
||||
|
||||
public unowned string get_label () {
|
||||
return _("Applications");
|
||||
}
|
||||
|
||||
public Gtk.Widget get_toolbar () {
|
||||
if (toolbar == null) {
|
||||
toolbar = new Gtk.Toolbar ();
|
||||
|
||||
#if !HAVE_WIN32
|
||||
/* FIXME: Profiles are broken on win32 because of no multi instance support */
|
||||
var profile = new Gtk.ToolButton.from_stock (Gtk.STOCK_ADD);
|
||||
profile.label = _("New _Profile");
|
||||
profile.tooltip_text = _("Creates a new, independent profile and a launcher");
|
||||
profile.use_underline = true;
|
||||
profile.is_important = true;
|
||||
profile.show ();
|
||||
profile.clicked.connect (() => {
|
||||
Launcher.create_profile.begin (this);
|
||||
});
|
||||
toolbar.insert (profile, -1);
|
||||
#endif
|
||||
|
||||
var app = new Gtk.ToolButton.from_stock (Gtk.STOCK_ADD);
|
||||
app.label = _("New _App");
|
||||
app.tooltip_text = _("Creates a new app for a specific site");
|
||||
app.use_underline = true;
|
||||
app.is_important = true;
|
||||
app.show ();
|
||||
app.clicked.connect (() => {
|
||||
var view = (get_toplevel () as Midori.Browser).tab as Midori.View;
|
||||
string checksum = Checksum.compute_for_string (ChecksumType.MD5, view.get_display_uri (), -1);
|
||||
Launcher.create.begin (APP_PREFIX, app_folder.get_child (checksum),
|
||||
view.get_display_uri (), view.get_display_title (), this);
|
||||
});
|
||||
toolbar.insert (app, -1);
|
||||
}
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) {
|
||||
Gtk.TreeIter iter;
|
||||
if (store.get_iter (out iter, path)) {
|
||||
Launcher launcher;
|
||||
store.get (iter, 0, out launcher);
|
||||
try {
|
||||
GLib.Process.spawn_command_line_async (launcher.exec);
|
||||
}
|
||||
catch (Error error) {
|
||||
var browser = get_toplevel () as Midori.Browser;
|
||||
browser.send_notification (_("Error launching"), error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool button_released (Gdk.EventButton event) {
|
||||
Gtk.TreePath? path;
|
||||
Gtk.TreeViewColumn column;
|
||||
if (event.button != 1)
|
||||
return false;
|
||||
if (treeview.get_path_at_pos ((int)event.x, (int)event.y, out path, out column, null, null)) {
|
||||
if (path != null) {
|
||||
if (column == treeview.get_column (2)) {
|
||||
Gtk.TreeIter iter;
|
||||
if (store.get_iter (out iter, path)) {
|
||||
Launcher launcher;
|
||||
store.get (iter, 0, out launcher);
|
||||
try {
|
||||
launcher.file.trash (null);
|
||||
store.remove (iter);
|
||||
|
||||
string filename = Midori.Download.clean_filename (launcher.name);
|
||||
#if HAVE_WIN32
|
||||
string lnk_filename = Midori.Sokoke.get_win32_desktop_lnk_path_for_filename (filename);
|
||||
if (Posix.access (lnk_filename, Posix.F_OK) == 0) {
|
||||
var lnk_file = File.new_for_path (lnk_filename);
|
||||
lnk_file.trash ();
|
||||
}
|
||||
#else
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
|
||||
data_dir.get_child ("applications").get_child (filename + ".desktop").trash ();
|
||||
#endif
|
||||
}
|
||||
catch (Error error) {
|
||||
GLib.critical ("Failed to remove launcher (%s): %s", launcher.file.get_path (), error.message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Sidebar (Katze.Array array, GLib.File app_folder, GLib.File profile_folder) {
|
||||
Gtk.TreeViewColumn column;
|
||||
|
||||
treeview = new Gtk.TreeView.with_model (store);
|
||||
treeview.headers_visible = false;
|
||||
|
||||
store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
|
||||
store.set_sort_func (0, tree_sort_func);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_icon, false);
|
||||
column.set_cell_data_func (renderer_icon, on_render_icon);
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
|
||||
Gtk.CellRendererText renderer_text = new Gtk.CellRendererText ();
|
||||
column.pack_start (renderer_text, true);
|
||||
column.set_expand (true);
|
||||
column.set_cell_data_func (renderer_text, on_render_text);
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_button = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_button, false);
|
||||
column.set_cell_data_func (renderer_button, on_render_button);
|
||||
treeview.append_column (column);
|
||||
|
||||
treeview.row_activated.connect (row_activated);
|
||||
treeview.button_release_event.connect (button_released);
|
||||
treeview.show ();
|
||||
pack_start (treeview, true, true, 0);
|
||||
|
||||
this.array = array;
|
||||
array.add_item.connect (launcher_added);
|
||||
array.remove_item.connect (launcher_removed);
|
||||
foreach (GLib.Object item in array.get_items ())
|
||||
launcher_added (item);
|
||||
|
||||
this.app_folder = app_folder;
|
||||
this.profile_folder = profile_folder;
|
||||
}
|
||||
|
||||
private int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
|
||||
Launcher launcher1, launcher2;
|
||||
model.get (a, 0, out launcher1);
|
||||
model.get (b, 0, out launcher2);
|
||||
return strcmp (launcher1.name, launcher2.name);
|
||||
}
|
||||
void launcher_added (GLib.Object item) {
|
||||
var launcher = item as Launcher;
|
||||
Gtk.TreeIter iter;
|
||||
store.append (out iter);
|
||||
store.set (iter, 0, launcher);
|
||||
}
|
||||
|
||||
void launcher_removed (GLib.Object item) {
|
||||
// TODO remove iter
|
||||
}
|
||||
|
||||
private void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Launcher launcher;
|
||||
model.get (iter, 0, out launcher);
|
||||
|
||||
try {
|
||||
int icon_width = 48, icon_height = 48;
|
||||
Gtk.icon_size_lookup_for_settings (get_settings (),
|
||||
Gtk.IconSize.DIALOG, out icon_width, out icon_height);
|
||||
var pixbuf = new Gdk.Pixbuf.from_file_at_size (launcher.icon_name, icon_width, icon_height);
|
||||
renderer.set ("pixbuf", pixbuf);
|
||||
}
|
||||
catch (Error error) {
|
||||
renderer.set ("icon-name", launcher.icon_name);
|
||||
}
|
||||
renderer.set ("stock-size", Gtk.IconSize.DIALOG,
|
||||
"xpad", 4);
|
||||
}
|
||||
|
||||
private void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Launcher launcher;
|
||||
model.get (iter, 0, out launcher);
|
||||
renderer.set ("markup",
|
||||
Markup.printf_escaped ("<b>%s</b>\n%s",
|
||||
launcher.name, launcher.uri),
|
||||
"ellipsize", Pango.EllipsizeMode.END);
|
||||
}
|
||||
|
||||
void on_render_button (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
renderer.set ("stock-id", Gtk.STOCK_DELETE,
|
||||
"stock-size", Gtk.IconSize.MENU);
|
||||
}
|
||||
}
|
||||
|
||||
private class Manager : Midori.Extension {
|
||||
internal Katze.Array array;
|
||||
internal GLib.File app_folder;
|
||||
internal GLib.File profile_folder;
|
||||
internal GLib.List<GLib.FileMonitor> monitors;
|
||||
internal GLib.List<Gtk.Widget> widgets;
|
||||
|
||||
void app_changed (GLib.File file, GLib.File? other, GLib.FileMonitorEvent event) {
|
||||
try {
|
||||
switch (event) {
|
||||
case GLib.FileMonitorEvent.DELETED:
|
||||
// TODO array.remove_item ();
|
||||
break;
|
||||
case GLib.FileMonitorEvent.CREATED:
|
||||
var launcher = new Launcher (file);
|
||||
if (launcher.init ())
|
||||
array.add_item (launcher);
|
||||
break;
|
||||
case GLib.FileMonitorEvent.CHANGED:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Application changed (%s): %s", file.get_path (), error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async void populate_apps (File app_folder) {
|
||||
try {
|
||||
try {
|
||||
app_folder.make_directory_with_parents (null);
|
||||
} catch (IOError.EXISTS exist_error) {
|
||||
/* It's no error if the folder already exists */
|
||||
}
|
||||
|
||||
var monitor = app_folder.monitor_directory (0, null);
|
||||
monitor.changed.connect (app_changed);
|
||||
monitors.append (monitor);
|
||||
|
||||
var enumerator = yield app_folder.enumerate_children_async ("standard::name", 0);
|
||||
while (true) {
|
||||
var files = yield enumerator.next_files_async (10);
|
||||
if (files == null)
|
||||
break;
|
||||
foreach (var info in files) {
|
||||
var file = app_folder.get_child (info.get_name ());
|
||||
try {
|
||||
var launcher = new Launcher (file);
|
||||
if (launcher.init ())
|
||||
array.add_item (launcher);
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Failed to parse launcher (%s): %s", file.get_path (), error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Error io_error) {
|
||||
warning ("Failed to list apps (%s): %s",
|
||||
app_folder.get_path (), io_error.message);
|
||||
}
|
||||
}
|
||||
|
||||
void browser_added (Midori.Browser browser) {
|
||||
var accels = new Gtk.AccelGroup ();
|
||||
browser.add_accel_group (accels);
|
||||
var action_group = browser.get_action_group ();
|
||||
|
||||
var action = new Gtk.Action ("CreateLauncher", _("Create _Launcher"),
|
||||
_("Creates a new app for a specific site"), null);
|
||||
action.activate.connect (() => {
|
||||
var view = browser.tab as Midori.View;
|
||||
Launcher.create_app.begin (view.get_display_uri (), view.get_display_title (), view);
|
||||
});
|
||||
action_group.add_action_with_accel (action, "<Ctrl><Shift>A");
|
||||
action.set_accel_group (accels);
|
||||
action.connect_accelerator ();
|
||||
|
||||
var viewable = new Sidebar (array, app_folder, profile_folder);
|
||||
viewable.show ();
|
||||
browser.panel.append_page (viewable);
|
||||
widgets.append (viewable);
|
||||
}
|
||||
|
||||
void activated (Midori.App app) {
|
||||
array = new Katze.Array (typeof (Launcher));
|
||||
monitors = new GLib.List<GLib.FileMonitor> ();
|
||||
app_folder = Launcher.get_app_folder ();
|
||||
populate_apps.begin (app_folder);
|
||||
/* FIXME: Profiles are broken on win32 because of no multi instance support */
|
||||
profile_folder = Launcher.get_profile_folder ();
|
||||
#if !HAVE_WIN32
|
||||
populate_apps.begin (profile_folder);
|
||||
#endif
|
||||
widgets = new GLib.List<Gtk.Widget> ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_added (browser);
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
|
||||
void deactivated () {
|
||||
var app = get_app ();
|
||||
foreach (var monitor in monitors)
|
||||
monitor.changed.disconnect (app_changed);
|
||||
monitors = null;
|
||||
|
||||
app.add_browser.disconnect (browser_added);
|
||||
foreach (var widget in widgets)
|
||||
widget.destroy ();
|
||||
foreach (var browser in app.get_browsers ()) {
|
||||
var action_group = browser.get_action_group ();
|
||||
var action = action_group.get_action ("CreateLauncher");
|
||||
action_group.remove_action (action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: _("Web App Manager"),
|
||||
description: _("Manage websites installed as applications"),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "Christian Dywan <christian@twotoasts.de>");
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new Apps.Manager ();
|
||||
}
|
||||
|
||||
class ExtensionsAppsDesktop : Midori.Test.Job {
|
||||
public static void test () { new ExtensionsAppsDesktop ().run_sync (); }
|
||||
public override async void run (Cancellable cancellable) throws GLib.Error {
|
||||
string uri = "http://example.com";
|
||||
string checksum = Checksum.compute_for_string (ChecksumType.MD5, uri, -1);
|
||||
var apps = Apps.Launcher.get_app_folder ().get_child (checksum);
|
||||
Midori.Paths.remove_path (apps.get_path ());
|
||||
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
|
||||
var desktop_dir = data_dir.get_child ("applications");
|
||||
Midori.Paths.remove_path (desktop_dir.get_child ("Example.desktop").get_path ());
|
||||
|
||||
var folder = yield Apps.Launcher.create_app (uri, "Example", null);
|
||||
var launcher = new Apps.Launcher (folder);
|
||||
launcher.init ();
|
||||
Katze.assert_str_equal (folder.get_path (), launcher.uri, uri);
|
||||
yield Apps.Launcher.create_profile (null);
|
||||
}
|
||||
}
|
||||
|
||||
public void extension_test () {
|
||||
Test.add_func ("/extensions/apps/desktop", ExtensionsAppsDesktop.test);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2013 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2010 Samuel Creshal <creshal@arcor.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
|
@ -13,23 +13,90 @@
|
|||
#include <midori/midori.h>
|
||||
|
||||
static void
|
||||
colorful_tabs_modify_fg (GtkWidget* label,
|
||||
GdkColor* color)
|
||||
get_foreground_color_for_GdkColor (GdkColor* color,
|
||||
GdkColor* fgcolor)
|
||||
{
|
||||
GtkWidget* box = gtk_bin_get_child (GTK_BIN (label));
|
||||
GList* children = gtk_container_get_children (GTK_CONTAINER (box));
|
||||
for (; children != NULL; children = g_list_next (children))
|
||||
gfloat brightness, r, g, b;
|
||||
|
||||
r = color->red / 255;
|
||||
g = color->green / 255;
|
||||
b = color->blue / 255;
|
||||
|
||||
/* For math used see algorithms for converting from rgb to yuv */
|
||||
brightness = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
|
||||
/* Ensure high contrast by enforcing black/ white text colour. */
|
||||
/* Brigthness (range 0-255) equals value of y from YUV color space. */
|
||||
if (brightness < 128)
|
||||
gdk_color_parse ("white", fgcolor);
|
||||
else
|
||||
gdk_color_parse ("black", fgcolor);
|
||||
}
|
||||
|
||||
static void
|
||||
adjust_brightness (GdkColor* color)
|
||||
{
|
||||
guint dark_grey = 137 * 255;
|
||||
guint adjustment = 78 * 255;
|
||||
guint blue = 39 * 255;
|
||||
guint readjust = 19 * 255;
|
||||
|
||||
if ((color->red < dark_grey)
|
||||
&& (color->green < dark_grey)
|
||||
&& (color->blue < dark_grey))
|
||||
{
|
||||
if (GTK_IS_LABEL (children->data))
|
||||
{
|
||||
gtk_widget_modify_fg (children->data, GTK_STATE_ACTIVE, color);
|
||||
gtk_widget_modify_fg (children->data, GTK_STATE_NORMAL, color);
|
||||
/* Also modify the label itself, for Tab Panel */
|
||||
gtk_widget_modify_fg (label, GTK_STATE_NORMAL, color);
|
||||
break;
|
||||
}
|
||||
color->red += adjustment;
|
||||
color->green += adjustment;
|
||||
color->blue += adjustment;
|
||||
}
|
||||
g_list_free (children);
|
||||
|
||||
if (color->red < blue)
|
||||
color->red = readjust;
|
||||
else
|
||||
color->red -= readjust;
|
||||
|
||||
if (color->blue < blue)
|
||||
color->blue = readjust;
|
||||
else
|
||||
color->blue -= readjust;
|
||||
|
||||
if (color->green < blue)
|
||||
color->green = readjust;
|
||||
else
|
||||
color->green -= readjust;
|
||||
}
|
||||
|
||||
static void
|
||||
view_get_bgcolor_for_favicon (GdkPixbuf* icon,
|
||||
GdkColor* color)
|
||||
{
|
||||
GdkPixbuf* newpix;
|
||||
guchar* pixels;
|
||||
|
||||
newpix = gdk_pixbuf_scale_simple (icon, 1, 1, GDK_INTERP_BILINEAR);
|
||||
pixels = gdk_pixbuf_get_pixels (newpix);
|
||||
color->red = pixels[0] * 255;
|
||||
color->green = pixels[1] * 255;
|
||||
color->blue = pixels[2] * 255;
|
||||
|
||||
adjust_brightness (color);
|
||||
}
|
||||
|
||||
static void
|
||||
view_get_bgcolor_for_hostname (gchar* hostname,
|
||||
GdkColor* color)
|
||||
{
|
||||
gchar* hash, *colorstr;
|
||||
|
||||
hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, hostname, 1);
|
||||
colorstr = g_strndup (hash, 6 + 1);
|
||||
colorstr[0] = '#';
|
||||
gdk_color_parse (colorstr, color);
|
||||
|
||||
g_free (hash);
|
||||
g_free (colorstr);
|
||||
|
||||
adjust_brightness (color);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -37,86 +104,31 @@ colorful_tabs_view_notify_uri_cb (MidoriView* view,
|
|||
GParamSpec* pspec,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* label;
|
||||
gchar* hostname;
|
||||
gchar* colorstr;
|
||||
GdkColor color;
|
||||
GdkColor fgcolor;
|
||||
GdkPixbuf* icon;
|
||||
const gchar* uri = midori_view_get_display_uri (view);
|
||||
if (!*uri)
|
||||
return;
|
||||
|
||||
label = midori_view_get_proxy_tab_label (view);
|
||||
|
||||
if (!midori_uri_is_blank (midori_view_get_display_uri (view))
|
||||
&& (hostname = midori_uri_parse_hostname (midori_view_get_display_uri (view), NULL))
|
||||
&& katze_object_get_enum (view, "load-status") == MIDORI_LOAD_FINISHED)
|
||||
if (!midori_uri_is_blank (uri))
|
||||
{
|
||||
icon = midori_view_get_icon (view);
|
||||
|
||||
if (midori_view_get_icon_uri (view) != NULL)
|
||||
gchar* hostname = midori_uri_parse_hostname (uri, NULL);
|
||||
if (hostname)
|
||||
{
|
||||
GdkPixbuf* newpix;
|
||||
guchar* pixels;
|
||||
GdkColor fgcolor, color;
|
||||
GdkPixbuf* icon = midori_view_get_icon (view);
|
||||
|
||||
newpix = gdk_pixbuf_scale_simple (icon, 1, 1, GDK_INTERP_BILINEAR);
|
||||
g_return_if_fail (gdk_pixbuf_get_bits_per_sample (newpix) == 8);
|
||||
pixels = gdk_pixbuf_get_pixels (newpix);
|
||||
color.red = pixels[0] * 225;
|
||||
color.green = pixels[1] * 225;
|
||||
color.blue = pixels[2] * 225;
|
||||
if (icon)
|
||||
view_get_bgcolor_for_favicon (icon, &color);
|
||||
else
|
||||
view_get_bgcolor_for_hostname (hostname, &color);
|
||||
|
||||
get_foreground_color_for_GdkColor (&color, &fgcolor);
|
||||
midori_view_set_colors (view, &fgcolor, &color);
|
||||
|
||||
g_free (hostname);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, hostname, 1);
|
||||
colorstr = g_strndup (hash, 6 + 1);
|
||||
g_free (hash);
|
||||
colorstr[0] = '#';
|
||||
gdk_color_parse (colorstr, &color);
|
||||
}
|
||||
g_free (hostname);
|
||||
|
||||
if ((color.red < 35000)
|
||||
&& (color.green < 35000)
|
||||
&& (color.blue < 35000))
|
||||
{
|
||||
color.red += 20000;
|
||||
color.green += 20000;
|
||||
color.blue += 20000;
|
||||
}
|
||||
|
||||
/* Ensure high contrast by enforcing black/ white text colour. */
|
||||
if ((color.red < 41000)
|
||||
&& (color.green < 41000)
|
||||
&& (color.blue < 41000))
|
||||
gdk_color_parse ("#fff", &fgcolor);
|
||||
else
|
||||
gdk_color_parse ("#000", &fgcolor);
|
||||
|
||||
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label), TRUE);
|
||||
|
||||
colorful_tabs_modify_fg (label, &fgcolor);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, &color);
|
||||
|
||||
if (color.red < 10000)
|
||||
color.red = 5000;
|
||||
else
|
||||
color.red -= 5000;
|
||||
if (color.blue < 10000)
|
||||
color.blue = 5000;
|
||||
else
|
||||
color.blue -= 5000;
|
||||
if (color.green < 10000)
|
||||
color.green = 5000;
|
||||
else
|
||||
color.green -= 5000;
|
||||
|
||||
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, &color);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
|
||||
colorful_tabs_modify_fg (label, NULL);
|
||||
}
|
||||
midori_view_set_colors (view, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -138,8 +150,7 @@ static void
|
|||
colorful_tabs_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
guint i;
|
||||
GtkWidget* view;
|
||||
GList* children;
|
||||
MidoriApp* app = midori_extension_get_app (extension);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
|
@ -148,17 +159,15 @@ colorful_tabs_deactivate_cb (MidoriExtension* extension,
|
|||
browser, colorful_tabs_browser_add_tab_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
extension, colorful_tabs_deactivate_cb, browser);
|
||||
i = 0;
|
||||
while ((view = midori_browser_get_nth_tab (browser, i++)))
|
||||
|
||||
children = midori_browser_get_tabs (MIDORI_BROWSER (browser));
|
||||
for (; children; children = g_list_next (children))
|
||||
{
|
||||
GtkWidget* label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
|
||||
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label), FALSE);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
|
||||
colorful_tabs_modify_fg (label, NULL);
|
||||
midori_view_set_colors (children->data, NULL, NULL);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
view, colorful_tabs_view_notify_uri_cb, extension);
|
||||
children->data, colorful_tabs_view_notify_uri_cb, extension);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -166,12 +175,13 @@ colorful_tabs_app_add_browser_cb (MidoriApp* app,
|
|||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
guint i;
|
||||
GtkWidget* view;
|
||||
GList* children;
|
||||
|
||||
children = midori_browser_get_tabs (MIDORI_BROWSER (browser));
|
||||
for (; children; children = g_list_next (children))
|
||||
colorful_tabs_browser_add_tab_cb (browser, children->data, extension);
|
||||
g_list_free (children);
|
||||
|
||||
i = 0;
|
||||
while ((view = midori_browser_get_nth_tab (browser, i++)))
|
||||
colorful_tabs_browser_add_tab_cb (browser, view, extension);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (colorful_tabs_browser_add_tab_cb), extension);
|
||||
g_signal_connect (extension, "deactivate",
|
||||
|
@ -195,6 +205,51 @@ colorful_tabs_activate_cb (MidoriExtension* extension,
|
|||
g_object_unref (browsers);
|
||||
}
|
||||
|
||||
void test_colour_for_hostname (void)
|
||||
{
|
||||
GdkColor color;
|
||||
GdkColor fgcolor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar* host;
|
||||
const gchar* fgcolor;
|
||||
const gchar* color;
|
||||
} ColorItem;
|
||||
|
||||
static const ColorItem items[] = {
|
||||
{ "www.last.fm", "#ffffffffffff", "#12ed7da312ed" },
|
||||
{ "git.xfce.org", "#ffffffffffff", "#1c424c72e207" },
|
||||
{ "elementaryos.org", "#000000000000", "#50dbac36b43e" },
|
||||
{ "news.ycombinator.com", "#000000000000", "#a5cba6cc5278" },
|
||||
{ "cgit.freedesktop.org", "#000000000000", "#95bb8db37ca2" },
|
||||
{ "get.cm", "#ffffffffffff", "#1c424c72e207" },
|
||||
};
|
||||
|
||||
guint i;
|
||||
for (i = 0; i < G_N_ELEMENTS (items); i++)
|
||||
{
|
||||
view_get_bgcolor_for_hostname ((gchar*)items[i].host, &color);
|
||||
get_foreground_color_for_GdkColor (&color, &fgcolor);
|
||||
|
||||
g_assert_cmpstr (items[i].color, ==, gdk_color_to_string (&color));
|
||||
g_assert_cmpstr (items[i].fgcolor, ==, gdk_color_to_string (&fgcolor));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
extension_test (void)
|
||||
{
|
||||
#ifndef HAVE_WEBKIT2
|
||||
g_object_set_data (G_OBJECT (webkit_get_default_session ()),
|
||||
"midori-session-initialized", (void*)1);
|
||||
#endif
|
||||
|
||||
/* TODO: Add test which uses favicon codepath */
|
||||
|
||||
g_test_add_func ("/extensions/colorful_tabs/hostname_colour", test_colour_for_hostname);
|
||||
}
|
||||
|
||||
MidoriExtension*
|
||||
extension_init (void)
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include <webkit/webkit.h>
|
||||
#include "katze/katze.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "cookie-manager.h"
|
||||
|
@ -87,10 +87,6 @@ static void cm_create_toolbar(CookieManagerPage *cmp)
|
|||
GtkToolItem *toolitem;
|
||||
|
||||
priv->toolbar = toolbar = gtk_toolbar_new();
|
||||
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
|
||||
gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_BUTTON);
|
||||
gtk_widget_show(toolbar);
|
||||
|
||||
toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_DELETE);
|
||||
gtk_tool_item_set_is_important(toolitem, TRUE);
|
||||
g_signal_connect(toolitem, "clicked", G_CALLBACK(cm_button_delete_clicked_cb), cmp);
|
||||
|
@ -166,12 +162,15 @@ static void cookie_manager_page_cookies_changed_cb(CookieManager *cm, CookieMana
|
|||
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
|
||||
g_object_unref(priv->filter);
|
||||
|
||||
/* if a filter is set, apply it again */
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
/* if a filter is set, apply it again but ignore the place holder text */
|
||||
if (!g_object_get_data (G_OBJECT (priv->filter_entry), "sokoke_showing_default"))
|
||||
{
|
||||
cm_filter_tree(cmp, filter_text);
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
{
|
||||
cm_filter_tree(cmp, filter_text);
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,11 +575,14 @@ static void cm_button_delete_all_clicked_cb(GtkToolButton *button, CookieManager
|
|||
if (toplevel != NULL)
|
||||
gtk_window_set_icon_name(GTK_WINDOW(dialog), gtk_window_get_icon_name(GTK_WINDOW(toplevel)));
|
||||
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
if (!g_object_get_data (G_OBJECT (priv->filter_entry), "sokoke_showing_default"))
|
||||
{
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("Only cookies which match the filter will be deleted."));
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
{
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("Only cookies which match the filter will be deleted."));
|
||||
}
|
||||
}
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
|
||||
|
@ -650,25 +652,20 @@ static void cm_tree_drag_data_get_cb(GtkWidget *widget, GdkDragContext *drag_con
|
|||
|
||||
static gchar *cm_get_cookie_description_text(SoupCookie *cookie)
|
||||
{
|
||||
static gchar date_fmt[512];
|
||||
gchar *expires;
|
||||
gchar *text;
|
||||
time_t expiration_time;
|
||||
const struct tm *tm;
|
||||
|
||||
g_return_val_if_fail(cookie != NULL, NULL);
|
||||
|
||||
if (cookie->expires != NULL)
|
||||
{
|
||||
expiration_time = soup_date_to_time_t(cookie->expires);
|
||||
tm = localtime(&expiration_time);
|
||||
/* even if some gcc versions complain about "%c", there is nothing wrong with and here we
|
||||
* want to use it */
|
||||
strftime(date_fmt, sizeof(date_fmt), "%c", tm);
|
||||
expires = date_fmt;
|
||||
time_t expiration_time = soup_date_to_time_t(cookie->expires);
|
||||
GDateTime* date = g_date_time_new_from_unix_local(expiration_time);
|
||||
expires = g_date_time_format(date, "%c");
|
||||
g_date_time_unref(date);
|
||||
}
|
||||
else
|
||||
expires = _("At the end of the session");
|
||||
expires = g_strdup(_("At the end of the session"));
|
||||
|
||||
text = g_markup_printf_escaped(
|
||||
_("<b>Host</b>: %s\n<b>Name</b>: %s\n<b>Value</b>: %s\n<b>Path</b>: %s\n"
|
||||
|
@ -677,8 +674,10 @@ static gchar *cm_get_cookie_description_text(SoupCookie *cookie)
|
|||
cookie->name,
|
||||
cookie->value,
|
||||
cookie->path,
|
||||
/* i18n: is this cookie secure (SSL)? yes/ no */
|
||||
cookie->secure ? _("Yes") : _("No"),
|
||||
expires);
|
||||
g_free(expires);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
@ -702,7 +701,6 @@ static gchar *cm_get_domain_description_text(const gchar *domain, gint cookie_co
|
|||
}
|
||||
|
||||
|
||||
#if GTK_CHECK_VERSION(2, 12, 0)
|
||||
static gboolean cm_tree_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode,
|
||||
GtkTooltip *tooltip, CookieManagerPage *cmp)
|
||||
{
|
||||
|
@ -731,8 +729,6 @@ static gboolean cm_tree_query_tooltip(GtkWidget *widget, gint x, gint y, gboolea
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static gboolean cm_filter_match(const gchar *haystack, const gchar *needle)
|
||||
{
|
||||
|
@ -812,25 +808,20 @@ static void cm_filter_entry_changed_cb(GtkEditable *editable, CookieManagerPage
|
|||
if (priv->ignore_changed_filter)
|
||||
return;
|
||||
|
||||
text = gtk_entry_get_text(GTK_ENTRY(editable));
|
||||
if (!g_object_get_data (G_OBJECT (editable), "sokoke_showing_default"))
|
||||
text = gtk_entry_get_text(GTK_ENTRY(editable));
|
||||
else
|
||||
text = NULL;
|
||||
cm_filter_tree(cmp, text);
|
||||
|
||||
cookie_manager_update_filter(priv->parent, text);
|
||||
|
||||
if (*text != '\0')
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
else
|
||||
if (text && *text)
|
||||
gtk_tree_view_collapse_all(GTK_TREE_VIEW(priv->treeview));
|
||||
else
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
}
|
||||
|
||||
|
||||
static void cm_filter_entry_clear_icon_released_cb(GtkIconEntry *e, gint pos, gint btn, gpointer data)
|
||||
{
|
||||
if (pos == GTK_ICON_ENTRY_SECONDARY)
|
||||
gtk_entry_set_text(GTK_ENTRY(e), "");
|
||||
}
|
||||
|
||||
|
||||
static void cm_tree_selection_changed_cb(GtkTreeSelection *selection, CookieManagerPage *cmp)
|
||||
{
|
||||
GList *rows;
|
||||
|
@ -1002,6 +993,7 @@ static void cm_tree_render_text_cb(GtkTreeViewColumn *column, GtkCellRenderer *r
|
|||
}
|
||||
else
|
||||
g_object_set(renderer, "text", name, NULL);
|
||||
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||
|
||||
g_free(name);
|
||||
}
|
||||
|
@ -1022,6 +1014,7 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
|
|||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(
|
||||
_("Name"), renderer, "text", COOKIE_MANAGER_COL_NAME, NULL);
|
||||
gtk_tree_view_column_set_expand (column, TRUE);
|
||||
gtk_tree_view_column_set_sort_indicator(column, TRUE);
|
||||
gtk_tree_view_column_set_sort_column_id(column, COOKIE_MANAGER_COL_NAME);
|
||||
gtk_tree_view_column_set_resizable(column, TRUE);
|
||||
|
@ -1045,10 +1038,8 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
|
|||
g_signal_connect(treeview, "popup-menu", G_CALLBACK(cm_tree_popup_menu_cb), cmp);
|
||||
|
||||
/* tooltips */
|
||||
#if GTK_CHECK_VERSION(2, 12, 0)
|
||||
gtk_widget_set_has_tooltip(treeview, TRUE);
|
||||
g_signal_connect(treeview, "query-tooltip", G_CALLBACK(cm_tree_query_tooltip), cmp);
|
||||
#endif
|
||||
|
||||
/* drag'n'drop */
|
||||
gtk_tree_view_enable_model_drag_source(
|
||||
|
@ -1100,7 +1091,6 @@ static void cookie_manager_page_init(CookieManagerPage *self)
|
|||
GtkWidget *desc_swin;
|
||||
GtkWidget *paned;
|
||||
GtkWidget *filter_hbox;
|
||||
GtkWidget *filter_label;
|
||||
GtkWidget *treeview;
|
||||
CookieManagerPagePrivate *priv;
|
||||
|
||||
|
@ -1132,29 +1122,15 @@ static void cookie_manager_page_init(CookieManagerPage *self)
|
|||
tree_swin = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_swin),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_swin), GTK_SHADOW_IN);
|
||||
gtk_container_add(GTK_CONTAINER(tree_swin), treeview);
|
||||
gtk_widget_show(tree_swin);
|
||||
|
||||
filter_label = gtk_label_new(_("Filter:"));
|
||||
gtk_widget_show(filter_label);
|
||||
|
||||
priv->filter_entry = gtk_icon_entry_new();
|
||||
gtk_widget_set_tooltip_text(priv->filter_entry,
|
||||
_("Enter a filter string to show only cookies whose name or domain "
|
||||
"field match the entered filter"));
|
||||
priv->filter_entry = sokoke_search_entry_new (_("Search Cookies by Name or Domain"));
|
||||
gtk_widget_show(priv->filter_entry);
|
||||
gtk_icon_entry_set_icon_from_stock(GTK_ICON_ENTRY(priv->filter_entry),
|
||||
GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_CLEAR);
|
||||
gtk_icon_entry_set_icon_highlight(GTK_ICON_ENTRY (priv->filter_entry),
|
||||
GTK_ICON_ENTRY_SECONDARY, TRUE);
|
||||
g_signal_connect(priv->filter_entry, "icon-release",
|
||||
G_CALLBACK(cm_filter_entry_clear_icon_released_cb), NULL);
|
||||
g_signal_connect(priv->filter_entry, "changed", G_CALLBACK(cm_filter_entry_changed_cb), self);
|
||||
g_signal_connect(priv->filter_entry, "activate", G_CALLBACK(cm_filter_entry_changed_cb), self);
|
||||
|
||||
filter_hbox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(filter_hbox), filter_label, FALSE, FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(filter_hbox), priv->filter_entry, TRUE, TRUE, 3);
|
||||
gtk_widget_show(filter_hbox);
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
#include <webkit/webkit.h>
|
||||
#include "katze/katze.h"
|
||||
#include <libsoup/soup-cookie-jar-sqlite.h>
|
||||
|
||||
#include "cookie-manager.h"
|
||||
#include "cookie-manager-page.h"
|
||||
|
@ -234,7 +235,8 @@ static void cookie_manager_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, S
|
|||
/* We delay these events a little bit to avoid too many rebuilds of the tree.
|
||||
* Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
|
||||
if (priv->timer_id == 0)
|
||||
priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cookie_manager_delayed_refresh, cm);
|
||||
priv->timer_id = midori_timeout_add_seconds(
|
||||
1, (GSourceFunc) cookie_manager_delayed_refresh, cm, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,6 +260,7 @@ static void cookie_manager_finalize(GObject *object)
|
|||
|
||||
g_object_unref(priv->store);
|
||||
g_free(priv->filter_text);
|
||||
g_object_unref(priv->jar);
|
||||
|
||||
G_OBJECT_CLASS(cookie_manager_parent_class)->finalize(object);
|
||||
}
|
||||
|
@ -266,7 +269,6 @@ static void cookie_manager_finalize(GObject *object)
|
|||
static void cookie_manager_init(CookieManager *self)
|
||||
{
|
||||
CookieManagerPrivate *priv;
|
||||
SoupSession *session;
|
||||
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
COOKIE_MANAGER_TYPE, CookieManagerPrivate);
|
||||
|
@ -278,8 +280,15 @@ static void cookie_manager_init(CookieManager *self)
|
|||
COOKIE_MANAGER_COL_NAME, GTK_SORT_ASCENDING);
|
||||
|
||||
/* setup soup */
|
||||
session = webkit_get_default_session();
|
||||
#ifdef HAVE_WEBKIT2
|
||||
gchar *filename = midori_paths_get_config_filename_for_writing ("cookies.db");
|
||||
priv->jar = soup_cookie_jar_sqlite_new (filename, FALSE);
|
||||
g_free(filename);
|
||||
#else
|
||||
SoupSession *session = webkit_get_default_session();
|
||||
priv->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
|
||||
g_object_ref(priv->jar);
|
||||
#endif
|
||||
g_signal_connect(priv->jar, "changed", G_CALLBACK(cookie_manager_jar_changed_cb), self);
|
||||
|
||||
cookie_manager_refresh_store(self);
|
||||
|
|
|
@ -0,0 +1,931 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#include "cookie-permission-manager-preferences-window.h"
|
||||
|
||||
/* Define this class in GObject system */
|
||||
G_DEFINE_TYPE(CookiePermissionManagerPreferencesWindow,
|
||||
cookie_permission_manager_preferences_window,
|
||||
GTK_TYPE_DIALOG)
|
||||
|
||||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_MANAGER,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec* CookiePermissionManagerPreferencesWindowProperties[PROP_LAST]={ 0, };
|
||||
|
||||
/* Private structure - access only by public API if needed */
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowPrivate))
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindowPrivate
|
||||
{
|
||||
/* Extension related */
|
||||
CookiePermissionManager *manager;
|
||||
sqlite3 *database;
|
||||
|
||||
/* Dialog related */
|
||||
GtkWidget *contentArea;
|
||||
GtkListStore *listStore;
|
||||
GtkWidget *list;
|
||||
GtkTreeSelection *listSelection;
|
||||
GtkWidget *editingCombo;
|
||||
GtkWidget *deleteButton;
|
||||
GtkWidget *deleteAllButton;
|
||||
GtkWidget *unknownPolicyCombo;
|
||||
GtkWidget *addDomainEntry;
|
||||
GtkWidget *addDomainPolicyCombo;
|
||||
GtkWidget *addDomainButton;
|
||||
|
||||
gint signalManagerChangedDatabaseID;
|
||||
gint signalManagerUnknownPolicyID;
|
||||
gint signalUnknownPolicyID;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DOMAIN_COLUMN,
|
||||
POLICY_COLUMN,
|
||||
N_COLUMN
|
||||
};
|
||||
|
||||
|
||||
/* IMPLEMENTATION: Private variables and methods */
|
||||
|
||||
/* "Add domain"-button was pressed */
|
||||
static void _cookie_permission_manager_preferences_on_add_domain_clicked(CookiePermissionManagerPreferencesWindow *self,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gchar *domain;
|
||||
const gchar *domainStart, *domainEnd;
|
||||
gchar *realDomain;
|
||||
GtkTreeIter policyIter;
|
||||
|
||||
g_return_if_fail(priv->database);
|
||||
|
||||
/* Get domain name entered */
|
||||
domain=g_hostname_to_ascii(gtk_entry_get_text(GTK_ENTRY(priv->addDomainEntry)));
|
||||
|
||||
/* Trim whitespaces from start and end of entered domain name */
|
||||
domainStart=domain;
|
||||
while(*domainStart && g_ascii_isspace(*domainStart)) domainStart++;
|
||||
|
||||
domainEnd=domain+strlen(domain)-1;
|
||||
while(*domainEnd && g_ascii_isspace(*domainEnd)) domainEnd--;
|
||||
if(domainEnd<=domainStart) return;
|
||||
|
||||
/* Seperate domain name from whitespaces */
|
||||
realDomain=g_strndup(domain, domainEnd-domainStart+1);
|
||||
if(!realDomain) return;
|
||||
|
||||
/* Get policy from combo box */
|
||||
if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->addDomainPolicyCombo), &policyIter))
|
||||
{
|
||||
gchar *sql;
|
||||
gchar *error=NULL;
|
||||
gint success;
|
||||
gint policy;
|
||||
gchar *policyName;
|
||||
|
||||
/* Get policy value to set for domain */
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(priv->addDomainPolicyCombo)),
|
||||
&policyIter,
|
||||
0, &policy,
|
||||
1, &policyName,
|
||||
-1);
|
||||
|
||||
/* Add domain name and the selected policy to database */
|
||||
sql=sqlite3_mprintf("INSERT OR REPLACE INTO policies (domain, value) VALUES ('%q', %d);",
|
||||
realDomain,
|
||||
policy);
|
||||
success=sqlite3_exec(priv->database, sql, NULL, NULL, &error);
|
||||
|
||||
/* Show error message if any */
|
||||
if(success==SQLITE_OK)
|
||||
{
|
||||
gtk_list_store_append(priv->listStore, &policyIter);
|
||||
gtk_list_store_set(priv->listStore,
|
||||
&policyIter,
|
||||
DOMAIN_COLUMN, realDomain,
|
||||
POLICY_COLUMN, policyName,
|
||||
-1);
|
||||
}
|
||||
else g_warning(_("SQL fails: %s"), error);
|
||||
|
||||
|
||||
if(error) sqlite3_free(error);
|
||||
|
||||
/* Free allocated resources */
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
/* Free allocated resources */
|
||||
g_free(realDomain);
|
||||
g_free(domain);
|
||||
}
|
||||
|
||||
/* Entry containing domain name which may be added to list has changed */
|
||||
static void _cookie_permission_manager_preferences_on_add_domain_entry_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkEditable *inEditable)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gchar *asciiDomain, *checkAsciiDomain;
|
||||
gchar *asciiDomainStart, *asciiDomainEnd;
|
||||
gint dots;
|
||||
gboolean isValid=FALSE;
|
||||
|
||||
/* Get ASCII representation of domain name entered */
|
||||
asciiDomain=g_hostname_to_ascii(gtk_entry_get_text(GTK_ENTRY(priv->addDomainEntry)));
|
||||
|
||||
/* Trim whitespaces from start and end of entered domain name */
|
||||
asciiDomainStart=asciiDomain;
|
||||
while(*asciiDomainStart && g_ascii_isspace(*asciiDomainStart)) asciiDomainStart++;
|
||||
|
||||
asciiDomainEnd=asciiDomain+strlen(asciiDomain)-1;
|
||||
while(*asciiDomainEnd && g_ascii_isspace(*asciiDomainEnd)) asciiDomainEnd--;
|
||||
|
||||
/* We allow only domain names and not cookie domain name so entered name
|
||||
* must not start with a dot
|
||||
*/
|
||||
checkAsciiDomain=asciiDomainStart;
|
||||
isValid=(*asciiDomainStart!='.' && *asciiDomainEnd!='.');
|
||||
|
||||
/* Now check if ASCII domain name is valid (very very simple check)
|
||||
* and contains a hostname besides TLD
|
||||
*/
|
||||
dots=0;
|
||||
|
||||
while(*checkAsciiDomain &&
|
||||
checkAsciiDomain<=asciiDomainEnd &&
|
||||
isValid)
|
||||
{
|
||||
/* Check for dot as (at least the first one) seperates hostname from TLD */
|
||||
if(*checkAsciiDomain=='.') dots++;
|
||||
else
|
||||
{
|
||||
/* Check for valid characters in domain name.
|
||||
* Valid domain name can only contain ASCII alphabetic letters,
|
||||
* digits (0-9) and hyphens ('-')
|
||||
*/
|
||||
isValid=(g_ascii_isalpha(*checkAsciiDomain) ||
|
||||
g_ascii_isdigit(*checkAsciiDomain) ||
|
||||
*checkAsciiDomain=='-');
|
||||
}
|
||||
|
||||
checkAsciiDomain++;
|
||||
}
|
||||
|
||||
/* If we have not reached the trimmed end of string something must have gone wrong
|
||||
* and domain entered is invalid. If domain name entered excluding dots is longer
|
||||
* than 255 character it is also invalid.
|
||||
*/
|
||||
if(checkAsciiDomain<asciiDomainEnd) isValid=FALSE;
|
||||
else if((checkAsciiDomain-asciiDomainStart-dots)>255) isValid=FALSE;
|
||||
|
||||
/* We need at least one dot in domain name (minimum number of dots to seperate
|
||||
* hostname from TLD)
|
||||
*/
|
||||
isValid=(isValid && dots>0);
|
||||
|
||||
/* Activate "add" button if hostname (equal to domain name here) is valid */
|
||||
gtk_widget_set_sensitive(priv->addDomainButton, isValid);
|
||||
|
||||
/* Free allocated resources */
|
||||
g_free(asciiDomain);
|
||||
}
|
||||
|
||||
/* Fill domain list with stored policies */
|
||||
static void _cookie_permission_manager_preferences_window_fill(CookiePermissionManagerPreferencesWindow *self)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gint success;
|
||||
sqlite3_stmt *statement=NULL;
|
||||
|
||||
/* Clear tree/list view */
|
||||
gtk_list_store_clear(priv->listStore);
|
||||
|
||||
/* If no database is present return here */
|
||||
if(!priv->database) return;
|
||||
|
||||
/* Fill list store with policies from database */
|
||||
success=sqlite3_prepare_v2(priv->database,
|
||||
"SELECT domain, value FROM policies;",
|
||||
-1,
|
||||
&statement,
|
||||
NULL);
|
||||
if(statement && success==SQLITE_OK)
|
||||
{
|
||||
gchar *domain;
|
||||
gint policy;
|
||||
gchar *policyName;
|
||||
GtkTreeIter iter;
|
||||
|
||||
while(sqlite3_step(statement)==SQLITE_ROW)
|
||||
{
|
||||
/* Get values */
|
||||
domain=(gchar*)sqlite3_column_text(statement, 0);
|
||||
policy=sqlite3_column_int(statement, 1);
|
||||
|
||||
switch(policy)
|
||||
{
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT:
|
||||
policyName=_("Accept");
|
||||
break;
|
||||
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION:
|
||||
policyName=_("Accept for session");
|
||||
break;
|
||||
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_BLOCK:
|
||||
policyName=_("Block");
|
||||
break;
|
||||
|
||||
default:
|
||||
policyName=NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if(policyName)
|
||||
{
|
||||
gtk_list_store_append(priv->listStore, &iter);
|
||||
gtk_list_store_set(priv->listStore,
|
||||
&iter,
|
||||
DOMAIN_COLUMN, domain,
|
||||
POLICY_COLUMN, policyName,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database));
|
||||
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
|
||||
/* Database instance in manager changed */
|
||||
static void _cookie_permission_manager_preferences_window_manager_database_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GParamSpec *inSpec,
|
||||
gpointer inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
CookiePermissionManager *manager=COOKIE_PERMISSION_MANAGER(inUserData);
|
||||
const gchar *databaseFilename;
|
||||
|
||||
/* Close connection to any open database */
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
|
||||
/* Get pointer to new database and open database */
|
||||
g_object_get(manager, "database-filename", &databaseFilename, NULL);
|
||||
if(databaseFilename)
|
||||
{
|
||||
gint success;
|
||||
|
||||
success=sqlite3_open(databaseFilename, &priv->database);
|
||||
if(success!=SQLITE_OK)
|
||||
{
|
||||
g_warning(_("Could not open database of extenstion: %s"), sqlite3_errmsg(priv->database));
|
||||
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill list with new database */
|
||||
_cookie_permission_manager_preferences_window_fill(self);
|
||||
|
||||
/* Set up availability of management buttons */
|
||||
gtk_widget_set_sensitive(priv->deleteAllButton, priv->database!=NULL);
|
||||
gtk_widget_set_sensitive(priv->list, priv->database!=NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* unknown-policy in manager changed or drop-down changed */
|
||||
static void _cookie_permission_manager_preferences_window_manager_unknown_policy_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GParamSpec *inSpec,
|
||||
gpointer inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
CookiePermissionManager *manager=COOKIE_PERMISSION_MANAGER(inUserData);
|
||||
CookiePermissionManagerPolicy policy;
|
||||
|
||||
/* Get new unknown-policy value */
|
||||
g_object_get(manager, "unknown-policy", &policy, NULL);
|
||||
|
||||
/* Set value in combobox (blocking signal to avoid loops) */
|
||||
g_signal_handler_block(priv->unknownPolicyCombo, priv->signalUnknownPolicyID);
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(priv->unknownPolicyCombo), policy);
|
||||
g_signal_handler_unblock(priv->unknownPolicyCombo, priv->signalUnknownPolicyID);
|
||||
}
|
||||
|
||||
static void _cookie_permission_manager_preferences_window_unknown_policy_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
CookiePermissionManagerPolicy policy;
|
||||
GtkTreeIter policyIter;
|
||||
|
||||
if(!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->unknownPolicyCombo), &policyIter))
|
||||
return;
|
||||
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(priv->unknownPolicyCombo)),
|
||||
&policyIter,
|
||||
0, &policy,
|
||||
-1);
|
||||
|
||||
/* Get toogle state of widget (but block signal for manager) and set in manager */
|
||||
g_signal_handler_block(priv->manager, priv->signalManagerUnknownPolicyID);
|
||||
g_object_set(priv->manager, "unknown-policy", policy, NULL);
|
||||
g_signal_handler_unblock(priv->manager, priv->signalManagerUnknownPolicyID);
|
||||
}
|
||||
|
||||
static void _cookie_permission_manager_preferences_on_policy_editing_started(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkCellEditable *editable,
|
||||
gchar *path,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
|
||||
priv->editingCombo=NULL;
|
||||
|
||||
if(!GTK_IS_COMBO_BOX(editable)) return;
|
||||
|
||||
priv->editingCombo=GTK_WIDGET(editable);
|
||||
}
|
||||
|
||||
static void _cookie_permission_manager_preferences_on_policy_editing_canceled(CookiePermissionManagerPreferencesWindow *self,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
|
||||
priv->editingCombo=NULL;
|
||||
}
|
||||
|
||||
static void _cookie_permission_manager_preferences_on_policy_edited(CookiePermissionManagerPreferencesWindow *self,
|
||||
gchar *path,
|
||||
gchar *newText,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gchar *domain;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter policyIter;
|
||||
|
||||
g_return_if_fail(priv->database);
|
||||
|
||||
if (priv->editingCombo == NULL) return;
|
||||
|
||||
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(priv->listStore), &iter, path);
|
||||
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(priv->listStore),
|
||||
&iter,
|
||||
DOMAIN_COLUMN, &domain,
|
||||
-1);
|
||||
|
||||
/* Get policy from combo box */
|
||||
if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->editingCombo), &policyIter))
|
||||
{
|
||||
gchar *sql;
|
||||
gchar *error=NULL;
|
||||
gint success;
|
||||
gint policy;
|
||||
gchar *policyName;
|
||||
|
||||
/* Get policy value to set for domain */
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(priv->editingCombo)),
|
||||
&policyIter,
|
||||
0, &policy,
|
||||
1, &policyName,
|
||||
-1);
|
||||
|
||||
g_return_if_fail(g_strcmp0(policyName, newText)==0);
|
||||
|
||||
/* Add domain name and the selected policy to database */
|
||||
sql=sqlite3_mprintf("UPDATE policies SET value = %d WHERE domain = '%q';",
|
||||
policy,
|
||||
domain);
|
||||
success=sqlite3_exec(priv->database, sql, NULL, NULL, &error);
|
||||
|
||||
/* Show error message if any */
|
||||
if(success==SQLITE_OK)
|
||||
{
|
||||
gtk_list_store_set(priv->listStore,
|
||||
&iter,
|
||||
POLICY_COLUMN, newText,
|
||||
-1);
|
||||
}
|
||||
else g_warning(_("SQL fails: %s"), error);
|
||||
|
||||
|
||||
if(error) sqlite3_free(error);
|
||||
|
||||
/* Free allocated resources */
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
priv->editingCombo=NULL;
|
||||
}
|
||||
|
||||
/* Selection in list changed */
|
||||
void _cookie_permission_manager_preferences_changed_selection(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkTreeSelection *inSelection)
|
||||
{
|
||||
gboolean selected=(gtk_tree_selection_count_selected_rows(inSelection)>0 ? TRUE: FALSE);
|
||||
|
||||
gtk_widget_set_sensitive(self->priv->deleteButton, selected);
|
||||
}
|
||||
|
||||
/* Delete button was clicked on selection */
|
||||
void _cookie_permission_manager_preferences_on_delete_selection(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkButton *inButton)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
GList *rows, *row, *refs=NULL;
|
||||
GtkTreeRowReference *ref;
|
||||
GtkTreeModel *model=GTK_TREE_MODEL(priv->listStore);
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
gchar *domain;
|
||||
gchar *sql;
|
||||
gint success;
|
||||
gchar *error;
|
||||
|
||||
/* Get selected rows in list and create a row reference because
|
||||
* we will modify the model while iterating through selected rows
|
||||
*/
|
||||
rows=gtk_tree_selection_get_selected_rows(priv->listSelection, &model);
|
||||
for(row=rows; row; row=row->next)
|
||||
{
|
||||
ref=gtk_tree_row_reference_new(model, (GtkTreePath*)row->data);
|
||||
refs=g_list_prepend(refs, ref);
|
||||
}
|
||||
g_list_foreach(rows,(GFunc)gtk_tree_path_free, NULL);
|
||||
g_list_free(rows);
|
||||
|
||||
/* Delete each selected row by its reference */
|
||||
for(row=refs; row; row=row->next)
|
||||
{
|
||||
/* Get domain from selected row */
|
||||
path=gtk_tree_row_reference_get_path((GtkTreeRowReference*)row->data);
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_tree_model_get(model, &iter, DOMAIN_COLUMN, &domain, -1);
|
||||
|
||||
/* Delete domain from database */
|
||||
sql=sqlite3_mprintf("DELETE FROM policies WHERE domain='%q';", domain);
|
||||
success=sqlite3_exec(priv->database,
|
||||
sql,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if(success!=SQLITE_OK || error)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
g_critical(_("Failed to execute database statement: %s"), error);
|
||||
sqlite3_free(error);
|
||||
}
|
||||
else g_critical(_("Failed to execute database statement: %s"), sqlite3_errmsg(priv->database));
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
|
||||
/* Delete row from model */
|
||||
gtk_list_store_remove(priv->listStore, &iter);
|
||||
}
|
||||
g_list_foreach(refs,(GFunc)gtk_tree_row_reference_free, NULL);
|
||||
g_list_free(refs);
|
||||
}
|
||||
|
||||
/* Delete all button was clicked */
|
||||
void _cookie_permission_manager_preferences_on_delete_all(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkButton *inButton)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gint success;
|
||||
gchar *error=NULL;
|
||||
GtkWidget *dialog;
|
||||
gint dialogResponse;
|
||||
|
||||
/* Ask user if he really wants to delete all permissions */
|
||||
dialog=gtk_message_dialog_new(GTK_WINDOW(self),
|
||||
GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_QUESTION,
|
||||
GTK_BUTTONS_YES_NO,
|
||||
_("Do you really want to delete all cookie permissions?"));
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Delete all cookie permissions?"));
|
||||
gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PROPERTIES);
|
||||
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("This action will delete all cookie permissions. "
|
||||
"You will be asked for permissions again for each web site visited."));
|
||||
|
||||
dialogResponse=gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
if(dialogResponse==GTK_RESPONSE_NO) return;
|
||||
|
||||
/* Delete all permission */
|
||||
success=sqlite3_exec(priv->database,
|
||||
"DELETE FROM policies;",
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if(success!=SQLITE_OK || error)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
g_critical(_("Failed to execute database statement: %s"), error);
|
||||
sqlite3_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-setup list */
|
||||
_cookie_permission_manager_preferences_window_fill(self);
|
||||
}
|
||||
|
||||
/* Sorting callbacks */
|
||||
static gint _cookie_permission_manager_preferences_sort_string_callback(GtkTreeModel *inModel,
|
||||
GtkTreeIter *inLeft,
|
||||
GtkTreeIter *inRight,
|
||||
gpointer inUserData)
|
||||
{
|
||||
gchar *left, *right;
|
||||
gint column=GPOINTER_TO_INT(inUserData);
|
||||
gint result;
|
||||
|
||||
gtk_tree_model_get(inModel, inLeft, column, &left, -1);
|
||||
gtk_tree_model_get(inModel, inRight, column, &right, -1);
|
||||
|
||||
result=g_strcmp0(left, right);
|
||||
|
||||
g_free(left);
|
||||
g_free(right);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/* IMPLEMENTATION: GObject */
|
||||
|
||||
/* Finalize this object */
|
||||
static void cookie_permission_manager_preferences_window_finalize(GObject *inObject)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject)->priv;
|
||||
|
||||
/* Dispose allocated resources */
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
|
||||
if(priv->manager)
|
||||
{
|
||||
if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID);
|
||||
priv->signalManagerChangedDatabaseID=0;
|
||||
|
||||
if(priv->signalManagerUnknownPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerUnknownPolicyID);
|
||||
priv->signalManagerUnknownPolicyID=0;
|
||||
|
||||
g_object_unref(priv->manager);
|
||||
priv->manager=NULL;
|
||||
}
|
||||
|
||||
/* Call parent's class finalize method */
|
||||
G_OBJECT_CLASS(cookie_permission_manager_preferences_window_parent_class)->finalize(inObject);
|
||||
}
|
||||
|
||||
/* Set/get properties */
|
||||
static void cookie_permission_manager_preferences_window_set_property(GObject *inObject,
|
||||
guint inPropID,
|
||||
const GValue *inValue,
|
||||
GParamSpec *inSpec)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindow *self=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject);
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
GObject *manager;
|
||||
|
||||
switch(inPropID)
|
||||
{
|
||||
/* Construct-only properties */
|
||||
case PROP_MANAGER:
|
||||
/* Release old manager if available and disconnect signals */
|
||||
if(priv->manager)
|
||||
{
|
||||
if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID);
|
||||
priv->signalManagerChangedDatabaseID=0;
|
||||
|
||||
if(priv->signalManagerUnknownPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerUnknownPolicyID);
|
||||
priv->signalManagerUnknownPolicyID=0;
|
||||
|
||||
g_object_unref(priv->manager);
|
||||
priv->manager=NULL;
|
||||
}
|
||||
|
||||
/* Set new cookie permission manager and
|
||||
* listen to changes in database property
|
||||
*/
|
||||
manager=g_value_get_object(inValue);
|
||||
if(manager)
|
||||
{
|
||||
priv->manager=g_object_ref(manager);
|
||||
|
||||
priv->signalManagerChangedDatabaseID=
|
||||
g_signal_connect_swapped(priv->manager,
|
||||
"notify::database-filename",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_manager_database_changed),
|
||||
self);
|
||||
_cookie_permission_manager_preferences_window_manager_database_changed(self, NULL, priv->manager);
|
||||
|
||||
priv->signalManagerUnknownPolicyID=
|
||||
g_signal_connect_swapped(priv->manager,
|
||||
"notify::unknown-policy",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_manager_unknown_policy_changed),
|
||||
self);
|
||||
_cookie_permission_manager_preferences_window_manager_unknown_policy_changed(self, NULL, priv->manager);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cookie_permission_manager_preferences_window_get_property(GObject *inObject,
|
||||
guint inPropID,
|
||||
GValue *outValue,
|
||||
GParamSpec *inSpec)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindow *self=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject);
|
||||
|
||||
switch(inPropID)
|
||||
{
|
||||
case PROP_MANAGER:
|
||||
g_value_set_object(outValue, self->priv->manager);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Class initialization
|
||||
* Override functions in parent classes and define properties and signals
|
||||
*/
|
||||
static void cookie_permission_manager_preferences_window_class_init(CookiePermissionManagerPreferencesWindowClass *klass)
|
||||
{
|
||||
GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
|
||||
|
||||
/* Override functions */
|
||||
gobjectClass->finalize=cookie_permission_manager_preferences_window_finalize;
|
||||
gobjectClass->set_property=cookie_permission_manager_preferences_window_set_property;
|
||||
gobjectClass->get_property=cookie_permission_manager_preferences_window_get_property;
|
||||
|
||||
/* Set up private structure */
|
||||
g_type_class_add_private(klass, sizeof(CookiePermissionManagerPreferencesWindowPrivate));
|
||||
|
||||
/* Define properties */
|
||||
CookiePermissionManagerPreferencesWindowProperties[PROP_MANAGER]=
|
||||
g_param_spec_object("manager",
|
||||
_("Cookie permission manager"),
|
||||
_("Instance of current cookie permission manager"),
|
||||
TYPE_COOKIE_PERMISSION_MANAGER,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties(gobjectClass, PROP_LAST, CookiePermissionManagerPreferencesWindowProperties);
|
||||
}
|
||||
|
||||
/* Object initialization
|
||||
* Create private structure and set up default values
|
||||
*/
|
||||
static void cookie_permission_manager_preferences_window_init(CookiePermissionManagerPreferencesWindow *self)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv;
|
||||
GtkTreeSortable *sortableList;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *widget;
|
||||
gchar *text;
|
||||
gchar *dialogTitle;
|
||||
GtkWidget *scrolled;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
gint width, height;
|
||||
GtkListStore *list;
|
||||
GtkTreeIter listIter;
|
||||
|
||||
priv=self->priv=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_PRIVATE(self);
|
||||
|
||||
/* Set up default values */
|
||||
priv->manager=NULL;
|
||||
|
||||
/* Get content area to add gui controls to */
|
||||
priv->contentArea=gtk_dialog_get_content_area(GTK_DIALOG(self));
|
||||
#ifdef HAVE_GTK3
|
||||
vbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
|
||||
#else
|
||||
vbox=gtk_vbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
/* Set up dialog */
|
||||
dialogTitle=_("Configure cookie permission");
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(self), dialogTitle);
|
||||
gtk_window_set_icon_name(GTK_WINDOW(self), GTK_STOCK_PROPERTIES);
|
||||
|
||||
sokoke_widget_get_text_size(GTK_WIDGET(self), "M", &width, &height);
|
||||
gtk_window_set_default_size(GTK_WINDOW(self), width*52, -1);
|
||||
|
||||
widget=sokoke_xfce_header_new(gtk_window_get_icon_name(GTK_WINDOW(self)), dialogTitle);
|
||||
if(widget) gtk_box_pack_start(GTK_BOX(priv->contentArea), widget, FALSE, FALSE, 0);
|
||||
|
||||
gtk_dialog_add_button(GTK_DIALOG(self), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
|
||||
|
||||
/* Set up description */
|
||||
widget=gtk_label_new(NULL);
|
||||
text=g_strdup_printf(_("Below is a list of all web sites and the policy set for them. "
|
||||
"You can delete policies by marking the entries and clicking on <i>Delete</i>."
|
||||
"You can also add a policy for a domain manually by entering the domain below, "
|
||||
"choosing the policy and clicking on <i>Add</i>."));
|
||||
gtk_label_set_markup(GTK_LABEL(widget), text);
|
||||
g_free(text);
|
||||
gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 4);
|
||||
|
||||
/* Set up model for cookie domain list */
|
||||
priv->listStore=gtk_list_store_new(N_COLUMN,
|
||||
G_TYPE_STRING, /* DOMAIN_COLUMN */
|
||||
G_TYPE_STRING /* POLICY_COLUMN */);
|
||||
|
||||
sortableList=GTK_TREE_SORTABLE(priv->listStore);
|
||||
gtk_tree_sortable_set_sort_func(sortableList,
|
||||
DOMAIN_COLUMN,
|
||||
(GtkTreeIterCompareFunc)_cookie_permission_manager_preferences_sort_string_callback,
|
||||
GINT_TO_POINTER(DOMAIN_COLUMN),
|
||||
NULL);
|
||||
gtk_tree_sortable_set_sort_func(sortableList,
|
||||
POLICY_COLUMN,
|
||||
(GtkTreeIterCompareFunc)_cookie_permission_manager_preferences_sort_string_callback,
|
||||
GINT_TO_POINTER(POLICY_COLUMN),
|
||||
NULL);
|
||||
gtk_tree_sortable_set_sort_column_id(sortableList, DOMAIN_COLUMN, GTK_SORT_ASCENDING);
|
||||
|
||||
/* Set up domain addition widgets */
|
||||
#ifdef HAVE_GTK3
|
||||
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
|
||||
#else
|
||||
hbox=gtk_hbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
priv->addDomainEntry=gtk_entry_new();
|
||||
gtk_entry_set_max_length(GTK_ENTRY(priv->addDomainEntry), 64);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainEntry);
|
||||
g_signal_connect_swapped(priv->addDomainEntry, "changed", G_CALLBACK(_cookie_permission_manager_preferences_on_add_domain_entry_changed), self);
|
||||
|
||||
list=gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT, 1, _("Accept"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION, 1, _("Accept for session"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_BLOCK, 1, _("Block"), -1);
|
||||
|
||||
priv->addDomainPolicyCombo=gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(priv->addDomainPolicyCombo), 0);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainPolicyCombo);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->addDomainPolicyCombo), renderer, TRUE);
|
||||
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(priv->addDomainPolicyCombo), renderer, "text", 1);
|
||||
|
||||
priv->addDomainButton=gtk_button_new_from_stock(GTK_STOCK_ADD);
|
||||
gtk_widget_set_sensitive(priv->addDomainButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainButton);
|
||||
g_signal_connect_swapped(priv->addDomainButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_add_domain_clicked), self);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5);
|
||||
|
||||
/* Set up cookie domain list */
|
||||
priv->list=gtk_tree_view_new_with_model(GTK_TREE_MODEL(priv->listStore));
|
||||
|
||||
#ifndef HAVE_GTK3
|
||||
gtk_widget_set_size_request(priv->list, -1, 300);
|
||||
#endif
|
||||
|
||||
priv->listSelection=gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->list));
|
||||
gtk_tree_selection_set_mode(priv->listSelection, GTK_SELECTION_MULTIPLE);
|
||||
g_signal_connect_swapped(priv->listSelection, "changed", G_CALLBACK(_cookie_permission_manager_preferences_changed_selection), self);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
column=gtk_tree_view_column_new_with_attributes(_("Domain"),
|
||||
renderer,
|
||||
"text", DOMAIN_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_column_set_sort_column_id(column, DOMAIN_COLUMN);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column);
|
||||
|
||||
renderer=gtk_cell_renderer_combo_new();
|
||||
g_object_set(G_OBJECT(renderer), "model", list, "text-column", 1, "has-entry", false, "editable", true, NULL);
|
||||
g_signal_connect_swapped(renderer, "editing-started", G_CALLBACK(_cookie_permission_manager_preferences_on_policy_editing_started), self);
|
||||
g_signal_connect_swapped(renderer, "editing-canceled", G_CALLBACK(_cookie_permission_manager_preferences_on_policy_editing_canceled), self);
|
||||
g_signal_connect_swapped(renderer, "edited", G_CALLBACK(_cookie_permission_manager_preferences_on_policy_edited), self);
|
||||
column=gtk_tree_view_column_new_with_attributes(_("Policy"),
|
||||
renderer,
|
||||
"text", POLICY_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_column_set_sort_column_id(column, POLICY_COLUMN);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column);
|
||||
|
||||
scrolled=gtk_scrolled_window_new(NULL, NULL);
|
||||
#ifdef HAVE_GTK3
|
||||
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), height*10);
|
||||
#endif
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), priv->list);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 5);
|
||||
|
||||
/* Set up cookie domain list management buttons */
|
||||
#ifdef HAVE_GTK3
|
||||
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
|
||||
#else
|
||||
hbox=gtk_hbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
priv->deleteButton=gtk_button_new_from_stock(GTK_STOCK_DELETE);
|
||||
gtk_widget_set_sensitive(priv->deleteButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->deleteButton);
|
||||
g_signal_connect_swapped(priv->deleteButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_delete_selection), self);
|
||||
|
||||
priv->deleteAllButton=gtk_button_new_with_mnemonic(_("Delete _all"));
|
||||
gtk_button_set_image(GTK_BUTTON(priv->deleteAllButton), gtk_image_new_from_stock(GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON));
|
||||
gtk_widget_set_sensitive(priv->deleteAllButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->deleteAllButton);
|
||||
g_signal_connect_swapped(priv->deleteAllButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_delete_all), self);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5);
|
||||
|
||||
/* Add "unknown-policy" combo */
|
||||
#ifdef HAVE_GTK3
|
||||
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
|
||||
#else
|
||||
hbox=gtk_hbox_new(FALSE, 0);
|
||||
#endif
|
||||
widget=gtk_label_new(_("Policy for cookies from domains not in the list: "));
|
||||
gtk_container_add(GTK_CONTAINER(hbox), widget);
|
||||
|
||||
list=gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED, 1, _("Ask for a decision"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT, 1, _("Accept"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION, 1, _("Accept for session"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_BLOCK, 1, _("Block"), -1);
|
||||
|
||||
priv->unknownPolicyCombo=gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(priv->unknownPolicyCombo), 0);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->unknownPolicyCombo);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->unknownPolicyCombo), renderer, TRUE);
|
||||
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(priv->unknownPolicyCombo), renderer, "text", 1);
|
||||
|
||||
priv->signalUnknownPolicyID=g_signal_connect_swapped(priv->unknownPolicyCombo,
|
||||
"changed",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_unknown_policy_changed),
|
||||
self);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5);
|
||||
|
||||
/* Finalize setup of content area */
|
||||
gtk_box_pack_start(GTK_BOX(priv->contentArea), vbox, TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
/* Implementation: Public API */
|
||||
|
||||
/* Create new object */
|
||||
GtkWidget* cookie_permission_manager_preferences_window_new(CookiePermissionManager *inManager)
|
||||
{
|
||||
return(g_object_new(TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW,
|
||||
"manager", inManager,
|
||||
NULL));
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#ifndef __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__
|
||||
#define __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__
|
||||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
|
||||
#include "cookie-permission-manager.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW (cookie_permission_manager_preferences_window_get_type())
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindow))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW))
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowClass))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW))
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowClass))
|
||||
|
||||
typedef struct _CookiePermissionManagerPreferencesWindow CookiePermissionManagerPreferencesWindow;
|
||||
typedef struct _CookiePermissionManagerPreferencesWindowClass CookiePermissionManagerPreferencesWindowClass;
|
||||
typedef struct _CookiePermissionManagerPreferencesWindowPrivate CookiePermissionManagerPreferencesWindowPrivate;
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindow
|
||||
{
|
||||
/* Parent instance */
|
||||
GtkDialog parent_instance;
|
||||
|
||||
/* Private structure */
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindowClass
|
||||
{
|
||||
/* Parent class */
|
||||
GtkDialogClass parent_class;
|
||||
};
|
||||
|
||||
/* Public API */
|
||||
GType cookie_permission_manager_preferences_window_get_type(void);
|
||||
|
||||
GtkWidget* cookie_permission_manager_preferences_window_new(CookiePermissionManager *inManager);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#ifndef __COOKIE_PERMISSION_MANAGER__
|
||||
#define __COOKIE_PERMISSION_MANAGER__
|
||||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
|
||||
#define COOKIE_PERMISSION_DATABASE "domains.db"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Cookie permission manager enums */
|
||||
typedef enum
|
||||
{
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_BLOCK
|
||||
} CookiePermissionManagerPolicy;
|
||||
|
||||
/* Cookie permission manager object */
|
||||
#define TYPE_COOKIE_PERMISSION_MANAGER (cookie_permission_manager_get_type())
|
||||
#define COOKIE_PERMISSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManager))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COOKIE_PERMISSION_MANAGER))
|
||||
#define COOKIE_PERMISSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManagerClass))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COOKIE_PERMISSION_MANAGER))
|
||||
#define COOKIE_PERMISSION_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManagerClass))
|
||||
|
||||
typedef struct _CookiePermissionManager CookiePermissionManager;
|
||||
typedef struct _CookiePermissionManagerClass CookiePermissionManagerClass;
|
||||
typedef struct _CookiePermissionManagerPrivate CookiePermissionManagerPrivate;
|
||||
|
||||
struct _CookiePermissionManager
|
||||
{
|
||||
/* Parent instance */
|
||||
GObject parent_instance;
|
||||
|
||||
/* Private structure */
|
||||
CookiePermissionManagerPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CookiePermissionManagerClass
|
||||
{
|
||||
/* Parent class */
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* Public API */
|
||||
GType cookie_permission_manager_get_type(void);
|
||||
|
||||
CookiePermissionManager* cookie_permission_manager_new(MidoriExtension *inExtension, MidoriApp *inApp);
|
||||
|
||||
CookiePermissionManagerPolicy cookie_permission_manager_get_unknown_policy(CookiePermissionManager *self);
|
||||
void cookie_permission_manager_set_unknown_policy(CookiePermissionManager *self, CookiePermissionManagerPolicy inPolicy);
|
||||
|
||||
/* Enumeration */
|
||||
GType cookie_permission_manager_policy_get_type(void) G_GNUC_CONST;
|
||||
#define COOKIE_PERMISSION_MANAGER_TYPE_POLICY (cookie_permission_manager_policy_get_type())
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COOKIE_PERMISSION_MANAGER__ */
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#include "cookie-permission-manager.h"
|
||||
#include "cookie-permission-manager-preferences-window.h"
|
||||
|
||||
/* Global instance */
|
||||
CookiePermissionManager *cpm=NULL;
|
||||
|
||||
/* This extension was activated */
|
||||
static void _cpm_on_activate(MidoriExtension *inExtension, MidoriApp *inApp, gpointer inUserData)
|
||||
{
|
||||
g_return_if_fail(cpm==NULL);
|
||||
|
||||
cpm=cookie_permission_manager_new(inExtension, inApp);
|
||||
g_object_set(cpm, "unknown-policy", midori_extension_get_integer(inExtension, "unknown-policy"), NULL);
|
||||
}
|
||||
|
||||
/* This extension was deactivated */
|
||||
static void _cpm_on_deactivate(MidoriExtension *inExtension, gpointer inUserData)
|
||||
{
|
||||
g_return_if_fail(cpm);
|
||||
|
||||
g_object_unref(cpm);
|
||||
cpm=NULL;
|
||||
}
|
||||
|
||||
/* Preferences of this extension should be opened */
|
||||
static void _cpm_on_open_preferences_response(GtkWidget* inDialog,
|
||||
gint inResponse,
|
||||
MidoriExtension* inExtension)
|
||||
{
|
||||
gtk_widget_destroy(inDialog);
|
||||
}
|
||||
|
||||
static void _cpm_on_open_preferences(MidoriExtension *inExtension)
|
||||
{
|
||||
g_return_if_fail(cpm);
|
||||
|
||||
/* Show preferences window */
|
||||
GtkWidget* dialog;
|
||||
|
||||
dialog=cookie_permission_manager_preferences_window_new(cpm);
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
|
||||
g_signal_connect(dialog, "response", G_CALLBACK (_cpm_on_open_preferences_response), inExtension);
|
||||
gtk_widget_show_all(dialog);
|
||||
}
|
||||
|
||||
/* Main entry for extension */
|
||||
MidoriExtension *extension_init(void)
|
||||
{
|
||||
/* Set up extension */
|
||||
MidoriExtension *extension=g_object_new(MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Cookie Security Manager"),
|
||||
"description", _("Manage cookie permission per site"),
|
||||
"version", "0.1" MIDORI_VERSION_SUFFIX,
|
||||
"authors", "Stephan Haller <nomad@froevel.de>",
|
||||
NULL);
|
||||
|
||||
midori_extension_install_integer(extension, "unknown-policy", COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED);
|
||||
midori_extension_install_boolean(extension, "show-details-when-ask", FALSE);
|
||||
|
||||
g_signal_connect(extension, "activate", G_CALLBACK(_cpm_on_activate), NULL);
|
||||
g_signal_connect(extension, "deactivate", G_CALLBACK(_cpm_on_deactivate), NULL);
|
||||
g_signal_connect(extension, "open-preferences", G_CALLBACK(_cpm_on_open_preferences), NULL);
|
||||
|
||||
return(extension);
|
||||
}
|
|
@ -28,6 +28,7 @@ copy_tabs_apply_cb (GtkWidget* menuitem,
|
|||
}
|
||||
gtk_clipboard_set_text (clipboard, text->str, -1);
|
||||
g_string_free (text, TRUE);
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (C) 2012-2013 André Stösel <andre@stoesel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
namespace DelayedLoad {
|
||||
private class Manager : Midori.Extension {
|
||||
private void tab_changed (Midori.View? old_view, Midori.View? new_view) {
|
||||
if (new_view != null) {
|
||||
unowned Katze.Item item = new_view.get_proxy_item ();
|
||||
|
||||
int64 delay = item.get_meta_integer ("delay");
|
||||
if (delay == Midori.Delay.PENDING_UNDELAY && new_view.progress < 1.0) {
|
||||
new_view.reload (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void browser_added (Midori.Browser browser) {
|
||||
browser.switch_tab.connect_after (this.tab_changed);
|
||||
}
|
||||
|
||||
private void browser_removed (Midori.Browser browser) {
|
||||
browser.switch_tab.disconnect (this.tab_changed);
|
||||
}
|
||||
|
||||
public void activated (Midori.App app) {
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
browser_added (browser);
|
||||
}
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
|
||||
public void deactivated () {
|
||||
Midori.App app = get_app ();
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
browser_removed (browser);
|
||||
}
|
||||
app.add_browser.disconnect (browser_added);
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: _("Delayed load"),
|
||||
description: _("Delay page load until you actually use the tab."),
|
||||
version: "0.2",
|
||||
authors: "André Stösel <andre@stoesel.de>");
|
||||
|
||||
activate.connect (this.activated);
|
||||
deactivate.connect (this.deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new DelayedLoad.Manager ();
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue