Compare commits
87 Commits
3.28.3
...
wip/cherge
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7f7965d622 | ||
![]() |
92cfb9ab1b | ||
![]() |
f3082a3683 | ||
![]() |
24f400d28a | ||
![]() |
4cac5b4b28 | ||
![]() |
b48e95cba2 | ||
![]() |
5ccf92e804 | ||
![]() |
2040c380bd | ||
![]() |
4e22989f07 | ||
![]() |
cfb92ad392 | ||
![]() |
f87b9f374a | ||
![]() |
2c549bfbbe | ||
![]() |
f597a0a11c | ||
![]() |
3f35ad0cbf | ||
![]() |
bd3227e23f | ||
![]() |
04f847a3c2 | ||
![]() |
41fe2d2c01 | ||
![]() |
161beb71eb | ||
![]() |
13ec3169a6 | ||
![]() |
8702d6647b | ||
![]() |
5703a25e2b | ||
![]() |
09fbb4a127 | ||
![]() |
4c7b20e584 | ||
![]() |
b3045cb964 | ||
![]() |
c41175af45 | ||
![]() |
7b1544a7a2 | ||
![]() |
a0f1ac87e9 | ||
![]() |
1045b35c8b | ||
![]() |
24cdcc56da | ||
![]() |
1b28cdfbf4 | ||
![]() |
a73294312f | ||
![]() |
5e7a7e31a1 | ||
![]() |
8111286463 | ||
![]() |
06c6ecc15b | ||
![]() |
36f9dcd2bd | ||
![]() |
219118e633 | ||
![]() |
1e929357e0 | ||
![]() |
e7463e38ca | ||
![]() |
420c1cbfd1 | ||
![]() |
d53bd98532 | ||
![]() |
128a501b9a | ||
![]() |
b29e243fec | ||
![]() |
fa2ddcc52f | ||
![]() |
fbf194f6a1 | ||
![]() |
5610a2435d | ||
![]() |
a5b36fc7f4 | ||
![]() |
923d80bba8 | ||
![]() |
9e196d2765 | ||
![]() |
94897492be | ||
![]() |
6baf82eb83 | ||
![]() |
65d27aaa43 | ||
![]() |
176aaa4a97 | ||
![]() |
5ae5811155 | ||
![]() |
e027af9548 | ||
![]() |
73649a0d6a | ||
![]() |
7dbcd26619 | ||
![]() |
f30ec4a4c8 | ||
![]() |
c04289853f | ||
![]() |
b72b773d87 | ||
![]() |
da7cd2807f | ||
![]() |
20373ba64e | ||
![]() |
025f6eb68e | ||
![]() |
dc5df5c4c9 | ||
![]() |
81db908339 | ||
![]() |
706a2259b8 | ||
![]() |
e94af71430 | ||
![]() |
a662e7bb87 | ||
![]() |
0b82388c49 | ||
![]() |
b359b937e9 | ||
![]() |
98fb7c33f2 | ||
![]() |
4dfc2e0fd1 | ||
![]() |
9152d3a286 | ||
![]() |
ba33a05dd2 | ||
![]() |
ddb309815c | ||
![]() |
6a796675bd | ||
![]() |
d08497414f | ||
![]() |
82886b7ee8 | ||
![]() |
dca43c7b24 | ||
![]() |
af50a7829f | ||
![]() |
67cb02d46a | ||
![]() |
721ce54037 | ||
![]() |
445eed40a7 | ||
![]() |
fddd122956 | ||
![]() |
df1b46eee2 | ||
![]() |
bf318df7f3 | ||
![]() |
2a2f3c981e | ||
![]() |
8e5eab0498 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "subprojects/gvc"]
|
||||
path = subprojects/gvc
|
||||
url = https://git.gnome.org/browse/libgnome-volume-control
|
||||
url = https://gitlab.gnome.org/GNOME/libgnome-volume-control.git
|
||||
|
27
NEWS
27
NEWS
@@ -1,3 +1,30 @@
|
||||
3.28.4
|
||||
======
|
||||
* Fix wrong window positions in overview on wayland [Marco; #776588]
|
||||
* overview: Fix handling of confirmation dialogs on wayland [verdre; !180]
|
||||
* Avoid some full relayout/redraws [Carlos; !197]
|
||||
* Keep workspace switcher slid out when workspaces are in use [Florian; !161]
|
||||
* Cancel search on overview hiding [Marco; !205]
|
||||
* Fix disappearing network icon [Iain; #140]
|
||||
* Improve performance of app icon animations [Daniel; !253]
|
||||
* notifications: Support icon theme names in 'image-path' hint [Marco; !285]
|
||||
* Avoid focus changes when updating keyboard options [Takao; #391]
|
||||
* Fix unresponsive-app dialog blocking input in other windows [Florian; #273]
|
||||
* Fix ellipsization in dialog subtitles/bodies [Marco; !531]
|
||||
* Misc. bug fixes [Marco, Andrea, Florian, Jasper, Sam, verdre, Jonas,
|
||||
Cosimo, Carlos; #792681, #372, !112, !162, #414, #663461, #788882, #787260,
|
||||
!188, #791233, #602, #632, !305, !286, !314, #781, #693, #618, #430, #799,
|
||||
#783, !293, #298, #1015, #539, #1270]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Andrea Azzarone, Cosimo Cecchi, Takao Fujiwara, Carlos Garnacho,
|
||||
Iain Lane, Florian Müllner, Georges Basile Stavracas Neto, Jasper St. Pierre,
|
||||
Sam Spilsbury, Ray Strode, Will Thompson, Marco Trevisan (Treviño), verdre,
|
||||
Daniel van Vugt
|
||||
|
||||
Translators:
|
||||
Marek Černocký [cs]
|
||||
|
||||
3.28.3
|
||||
======
|
||||
* Fix lagging pointer when zoomed [Daniel; #682013]
|
||||
|
@@ -6,6 +6,7 @@
|
||||
<file>be.json</file>
|
||||
<file>bg.json</file>
|
||||
<file>by.json</file>
|
||||
<file>ca.json</file>
|
||||
<file>cz.json</file>
|
||||
<file>de.json</file>
|
||||
<file>dk.json</file>
|
||||
|
599
data/osk-layouts/ca.json
Normal file
599
data/osk-layouts/ca.json
Normal file
@@ -0,0 +1,599 @@
|
||||
{
|
||||
"levels": [
|
||||
{
|
||||
"level": "",
|
||||
"mode": "default",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"q"
|
||||
],
|
||||
[
|
||||
"w"
|
||||
],
|
||||
[
|
||||
"e",
|
||||
"é",
|
||||
"è",
|
||||
"ê",
|
||||
"ë",
|
||||
"%",
|
||||
"ę",
|
||||
"ė",
|
||||
"ē"
|
||||
],
|
||||
[
|
||||
"r"
|
||||
],
|
||||
[
|
||||
"t"
|
||||
],
|
||||
[
|
||||
"y",
|
||||
"%",
|
||||
"ÿ"
|
||||
],
|
||||
[
|
||||
"u",
|
||||
"ù",
|
||||
"û",
|
||||
"%",
|
||||
"ü",
|
||||
"ú",
|
||||
"ū"
|
||||
],
|
||||
[
|
||||
"i",
|
||||
"î",
|
||||
"%",
|
||||
"ï",
|
||||
"ì",
|
||||
"í",
|
||||
"į",
|
||||
"ī"
|
||||
],
|
||||
[
|
||||
"o",
|
||||
"ô",
|
||||
"œ",
|
||||
"%",
|
||||
"ö",
|
||||
"ò",
|
||||
"ó",
|
||||
"õ",
|
||||
"ø",
|
||||
"ō",
|
||||
"º"
|
||||
],
|
||||
[
|
||||
"p"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"s"
|
||||
],
|
||||
[
|
||||
"d"
|
||||
],
|
||||
[
|
||||
"f"
|
||||
],
|
||||
[
|
||||
"g"
|
||||
],
|
||||
[
|
||||
"h"
|
||||
],
|
||||
[
|
||||
"j"
|
||||
],
|
||||
[
|
||||
"k"
|
||||
],
|
||||
[
|
||||
"l"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"z"
|
||||
],
|
||||
[
|
||||
"x"
|
||||
],
|
||||
[
|
||||
"c",
|
||||
"ç",
|
||||
"ć",
|
||||
"č"
|
||||
],
|
||||
[
|
||||
"v"
|
||||
],
|
||||
[
|
||||
"b"
|
||||
],
|
||||
[
|
||||
"n"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
".",
|
||||
"#",
|
||||
"!",
|
||||
",",
|
||||
"?",
|
||||
"-",
|
||||
":",
|
||||
"'",
|
||||
"@"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "shift",
|
||||
"mode": "latched",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"Q"
|
||||
],
|
||||
[
|
||||
"W"
|
||||
],
|
||||
[
|
||||
"E",
|
||||
"É",
|
||||
"È",
|
||||
"Ê",
|
||||
"Ë",
|
||||
"%",
|
||||
"Ę",
|
||||
"Ė",
|
||||
"Ē"
|
||||
],
|
||||
[
|
||||
"R"
|
||||
],
|
||||
[
|
||||
"T"
|
||||
],
|
||||
[
|
||||
"Y",
|
||||
"%",
|
||||
"Ÿ"
|
||||
],
|
||||
[
|
||||
"U",
|
||||
"Ù",
|
||||
"Û",
|
||||
"%",
|
||||
"Ü",
|
||||
"Ú",
|
||||
"Ū"
|
||||
],
|
||||
[
|
||||
"I",
|
||||
"Î",
|
||||
"%",
|
||||
"Ï",
|
||||
"Ì",
|
||||
"Í",
|
||||
"Į",
|
||||
"Ī"
|
||||
],
|
||||
[
|
||||
"O",
|
||||
"Ô",
|
||||
"Œ",
|
||||
"%",
|
||||
"Ö",
|
||||
"Ò",
|
||||
"Ó",
|
||||
"Õ",
|
||||
"Ø",
|
||||
"Ō",
|
||||
"º"
|
||||
],
|
||||
[
|
||||
"P"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"S"
|
||||
],
|
||||
[
|
||||
"D"
|
||||
],
|
||||
[
|
||||
"F"
|
||||
],
|
||||
[
|
||||
"G"
|
||||
],
|
||||
[
|
||||
"H"
|
||||
],
|
||||
[
|
||||
"J"
|
||||
],
|
||||
[
|
||||
"K"
|
||||
],
|
||||
[
|
||||
"L"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"Z"
|
||||
],
|
||||
[
|
||||
"X"
|
||||
],
|
||||
[
|
||||
"C",
|
||||
"Ç",
|
||||
"Ć",
|
||||
"Č"
|
||||
],
|
||||
[
|
||||
"V"
|
||||
],
|
||||
[
|
||||
"B"
|
||||
],
|
||||
[
|
||||
"N"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
".",
|
||||
"#",
|
||||
"!",
|
||||
",",
|
||||
"?",
|
||||
"-",
|
||||
":",
|
||||
"'",
|
||||
"@"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "opt",
|
||||
"mode": "locked",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"1",
|
||||
"¹",
|
||||
"½",
|
||||
"⅓",
|
||||
"¼",
|
||||
"⅛"
|
||||
],
|
||||
[
|
||||
"2",
|
||||
"²",
|
||||
"⅔"
|
||||
],
|
||||
[
|
||||
"3",
|
||||
"³",
|
||||
"¾",
|
||||
"⅜"
|
||||
],
|
||||
[
|
||||
"4",
|
||||
"⁴"
|
||||
],
|
||||
[
|
||||
"5",
|
||||
"⅝"
|
||||
],
|
||||
[
|
||||
"6"
|
||||
],
|
||||
[
|
||||
"7",
|
||||
"⅞"
|
||||
],
|
||||
[
|
||||
"8"
|
||||
],
|
||||
[
|
||||
"9"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"ⁿ",
|
||||
"∅"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"@"
|
||||
],
|
||||
[
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"¢",
|
||||
"£",
|
||||
"€",
|
||||
"¥",
|
||||
"₱"
|
||||
],
|
||||
[
|
||||
"%",
|
||||
"‰"
|
||||
],
|
||||
[
|
||||
"&"
|
||||
],
|
||||
[
|
||||
"-",
|
||||
"_",
|
||||
"–",
|
||||
"—",
|
||||
"·"
|
||||
],
|
||||
[
|
||||
"+",
|
||||
"±"
|
||||
],
|
||||
[
|
||||
"(",
|
||||
"<",
|
||||
"{",
|
||||
"["
|
||||
],
|
||||
[
|
||||
")",
|
||||
">",
|
||||
"}",
|
||||
"]"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"*",
|
||||
"†",
|
||||
"‡",
|
||||
"★"
|
||||
],
|
||||
[
|
||||
"\"",
|
||||
"“",
|
||||
"”",
|
||||
"«",
|
||||
"»"
|
||||
],
|
||||
[
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
],
|
||||
[
|
||||
":"
|
||||
],
|
||||
[
|
||||
";"
|
||||
],
|
||||
[
|
||||
"!",
|
||||
"¡"
|
||||
],
|
||||
[
|
||||
"?",
|
||||
"¿"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"_"
|
||||
],
|
||||
[
|
||||
"/"
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
".",
|
||||
"…"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "opt+shift",
|
||||
"mode": "locked",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"~"
|
||||
],
|
||||
[
|
||||
"`"
|
||||
],
|
||||
[
|
||||
"|"
|
||||
],
|
||||
[
|
||||
"•",
|
||||
"♪",
|
||||
"♥",
|
||||
"♠",
|
||||
"♦",
|
||||
"♣"
|
||||
],
|
||||
[
|
||||
"√"
|
||||
],
|
||||
[
|
||||
"Π",
|
||||
"π"
|
||||
],
|
||||
[
|
||||
"÷"
|
||||
],
|
||||
[
|
||||
"×"
|
||||
],
|
||||
[
|
||||
"¶",
|
||||
"§"
|
||||
],
|
||||
[
|
||||
"∆"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"£"
|
||||
],
|
||||
[
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"€"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
],
|
||||
[
|
||||
"^",
|
||||
"↑",
|
||||
"↓",
|
||||
"←",
|
||||
"→"
|
||||
],
|
||||
[
|
||||
"°",
|
||||
"′",
|
||||
"″"
|
||||
],
|
||||
[
|
||||
"=",
|
||||
"≠",
|
||||
"≈",
|
||||
"∞"
|
||||
],
|
||||
[
|
||||
"{"
|
||||
],
|
||||
[
|
||||
"}"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"\\"
|
||||
],
|
||||
[
|
||||
"©"
|
||||
],
|
||||
[
|
||||
"®"
|
||||
],
|
||||
[
|
||||
"™"
|
||||
],
|
||||
[
|
||||
"℅"
|
||||
],
|
||||
[
|
||||
"["
|
||||
],
|
||||
[
|
||||
"]"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"<",
|
||||
"‹",
|
||||
"≤",
|
||||
"«"
|
||||
],
|
||||
[
|
||||
">",
|
||||
"›",
|
||||
"≥",
|
||||
"»"
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
".",
|
||||
"…"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"locale": "fr-CA",
|
||||
"name": "French Canada"
|
||||
}
|
@@ -6,10 +6,20 @@
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"q"
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"w"
|
||||
"z"
|
||||
],
|
||||
[
|
||||
"e",
|
||||
@@ -71,17 +81,7 @@
|
||||
],
|
||||
[
|
||||
[
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
"q"
|
||||
],
|
||||
[
|
||||
"s"
|
||||
@@ -106,11 +106,14 @@
|
||||
],
|
||||
[
|
||||
"l"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"z"
|
||||
"w"
|
||||
],
|
||||
[
|
||||
"x"
|
||||
@@ -131,7 +134,11 @@
|
||||
"n"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -161,10 +168,20 @@
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"Q"
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"W"
|
||||
"Z"
|
||||
],
|
||||
[
|
||||
"E",
|
||||
@@ -226,17 +243,7 @@
|
||||
],
|
||||
[
|
||||
[
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
"Q"
|
||||
],
|
||||
[
|
||||
"S"
|
||||
@@ -261,11 +268,14 @@
|
||||
],
|
||||
[
|
||||
"L"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"Z"
|
||||
"W"
|
||||
],
|
||||
[
|
||||
"X"
|
||||
@@ -286,7 +296,11 @@
|
||||
"N"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -369,10 +383,10 @@
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"€",
|
||||
"¢",
|
||||
"£",
|
||||
"€",
|
||||
"$",
|
||||
"¥",
|
||||
"₱"
|
||||
],
|
||||
@@ -511,13 +525,14 @@
|
||||
"£"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"€"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"^",
|
||||
@@ -594,6 +609,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"locale": "fr-CA",
|
||||
"name": "French Canada"
|
||||
"locale": "fr",
|
||||
"name": "French"
|
||||
}
|
@@ -242,11 +242,11 @@ var AuthPrompt = new Lang.Class({
|
||||
this.emit('prompted');
|
||||
},
|
||||
|
||||
_onVerificationFailed() {
|
||||
_onVerificationFailed(userVerifier, canRetry) {
|
||||
this._queryingService = null;
|
||||
this.clear();
|
||||
|
||||
this.updateSensitivity(true);
|
||||
this.updateSensitivity(canRetry);
|
||||
this.setActorInDefaultButtonWell(null);
|
||||
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
|
||||
},
|
||||
@@ -439,6 +439,7 @@ var AuthPrompt = new Lang.Class({
|
||||
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||
this.cancelButton.reactive = true;
|
||||
this.nextButton.label = _("Next");
|
||||
this._preemptiveAnswer = null;
|
||||
|
||||
if (this._userVerifier)
|
||||
this._userVerifier.cancel();
|
||||
|
@@ -534,12 +534,13 @@ var ShellUserVerifier = new Lang.Class({
|
||||
_verificationFailed(retry) {
|
||||
// For Not Listed / enterprise logins, immediately reset
|
||||
// the dialog
|
||||
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
|
||||
// go back to the welcome screen.
|
||||
// Otherwise, when in login mode we allow ALLOWED_FAILURES attempts.
|
||||
// After that, we go back to the welcome screen.
|
||||
|
||||
this._failCounter++;
|
||||
let canRetry = retry && this._userName &&
|
||||
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
|
||||
(this._reauthOnly ||
|
||||
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY));
|
||||
|
||||
if (canRetry) {
|
||||
if (!this.hasPendingMessages) {
|
||||
@@ -562,7 +563,7 @@ var ShellUserVerifier = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('verification-failed');
|
||||
this.emit('verification-failed', canRetry);
|
||||
},
|
||||
|
||||
_onConversationStopped(client, serviceName) {
|
||||
|
@@ -205,7 +205,7 @@ var IBusManager = new Lang.Class({
|
||||
}
|
||||
|
||||
this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
||||
null, callback);
|
||||
null, callback || null);
|
||||
},
|
||||
|
||||
preloadEngines(ids) {
|
||||
|
@@ -236,11 +236,12 @@ var ObjectManager = new Lang.Class({
|
||||
_onNameVanished() {
|
||||
let objectPaths = Object.keys(this._objects);
|
||||
for (let i = 0; i < objectPaths.length; i++) {
|
||||
let object = this._objects[objectPaths];
|
||||
let objectPath = objectPaths[i];
|
||||
let object = this._objects[objectPath];
|
||||
|
||||
let interfaceNames = Object.keys(object);
|
||||
for (let j = 0; i < interfaceNames.length; i++) {
|
||||
let interfaceName = interfaceNames[i];
|
||||
for (let j = 0; j < interfaceNames.length; j++) {
|
||||
let interfaceName = interfaceNames[j];
|
||||
|
||||
if (object[interfaceName])
|
||||
this._removeInterface(objectPath, interfaceName);
|
||||
|
@@ -92,17 +92,8 @@ function _listsIntersect(a, b) {
|
||||
function _getFolderName(folder) {
|
||||
let name = folder.get_string('name');
|
||||
|
||||
if (folder.get_boolean('translate')) {
|
||||
let keyfile = new GLib.KeyFile();
|
||||
let path = 'desktop-directories/' + name;
|
||||
|
||||
try {
|
||||
keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
|
||||
name = keyfile.get_locale_string('Desktop Entry', 'Name', null);
|
||||
} catch(e) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
if (folder.get_boolean('translate'))
|
||||
return Shell.AppCache.get_default().translate_folder(name);
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -499,7 +490,7 @@ var AllView = new Lang.Class({
|
||||
},
|
||||
|
||||
_loadApps() {
|
||||
let apps = Gio.AppInfo.get_all().filter(appInfo => {
|
||||
let apps = Shell.AppCache.get_default().get_all().filter(appInfo => {
|
||||
try {
|
||||
let id = appInfo.get_id(); // catch invalid file encodings
|
||||
} catch(e) {
|
||||
@@ -1329,7 +1320,7 @@ var FolderIcon = new Lang.Class({
|
||||
folderApps.forEach(addAppId);
|
||||
|
||||
let folderCategories = this._folder.get_strv('categories');
|
||||
Gio.AppInfo.get_all().forEach(appInfo => {
|
||||
Shell.AppCache.get_default().get_all().forEach(appInfo => {
|
||||
let appCategories = _getCategories(appInfo);
|
||||
if (!_listsIntersect(folderCategories, appCategories))
|
||||
return;
|
||||
|
@@ -802,6 +802,8 @@ var NotificationMessage = new Lang.Class({
|
||||
},
|
||||
|
||||
_onDestroy() {
|
||||
this.parent();
|
||||
|
||||
if (this._updatedId)
|
||||
this.notification.disconnect(this._updatedId);
|
||||
this._updatedId = 0;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
@@ -13,6 +14,7 @@ const Tweener = imports.ui.tweener;
|
||||
|
||||
var FROZEN_WINDOW_BRIGHTNESS = -0.3
|
||||
var DIALOG_TRANSITION_TIME = 0.15
|
||||
var ALIVE_TIMEOUT = 5000;
|
||||
|
||||
var CloseDialog = new Lang.Class({
|
||||
Name: 'CloseDialog',
|
||||
@@ -26,6 +28,10 @@ var CloseDialog = new Lang.Class({
|
||||
this.parent();
|
||||
this._window = window;
|
||||
this._dialog = null;
|
||||
this._tracked = undefined;
|
||||
this._timeoutId = 0;
|
||||
this._windowFocusChangedId = 0;
|
||||
this._keyFocusChangedId = 0;
|
||||
},
|
||||
|
||||
get window() {
|
||||
@@ -93,10 +99,57 @@ var CloseDialog = new Lang.Class({
|
||||
this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
|
||||
},
|
||||
|
||||
_onFocusChanged() {
|
||||
if (Meta.is_wayland_compositor())
|
||||
return;
|
||||
|
||||
let focusWindow = global.display.focus_window;
|
||||
let keyFocus = global.stage.key_focus;
|
||||
|
||||
let shouldTrack;
|
||||
if (focusWindow != null)
|
||||
shouldTrack = focusWindow == this._window;
|
||||
else
|
||||
shouldTrack = keyFocus && this._dialog.contains(keyFocus);
|
||||
|
||||
if (this._tracked === shouldTrack)
|
||||
return;
|
||||
|
||||
if (shouldTrack)
|
||||
Main.layoutManager.trackChrome(this._dialog,
|
||||
{ affectsInputRegion: true });
|
||||
else
|
||||
Main.layoutManager.untrackChrome(this._dialog);
|
||||
|
||||
// The buttons are broken when they aren't added to the input region,
|
||||
// so disable them properly in that case
|
||||
this._dialog.buttonLayout.get_children().forEach(b => {
|
||||
b.reactive = shouldTrack;
|
||||
});
|
||||
|
||||
this._tracked = shouldTrack;
|
||||
},
|
||||
|
||||
vfunc_show() {
|
||||
if (this._dialog != null)
|
||||
return;
|
||||
|
||||
Meta.disable_unredirect_for_screen(global.screen);
|
||||
|
||||
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ALIVE_TIMEOUT,
|
||||
() => {
|
||||
this._window.check_alive(global.display.get_current_time_roundtrip());
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
});
|
||||
|
||||
this._windowFocusChangedId =
|
||||
global.display.connect('notify::focus-window',
|
||||
this._onFocusChanged.bind(this));
|
||||
|
||||
this._keyFocusChangedId =
|
||||
global.stage.connect('notify::key-focus',
|
||||
this._onFocusChanged.bind(this));
|
||||
|
||||
this._addWindowEffect();
|
||||
this._initDialog();
|
||||
|
||||
@@ -107,9 +160,7 @@ var CloseDialog = new Lang.Class({
|
||||
{ scale_y: 1,
|
||||
transition: 'linear',
|
||||
time: DIALOG_TRANSITION_TIME,
|
||||
onComplete: () => {
|
||||
Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
|
||||
}
|
||||
onComplete: this._onFocusChanged.bind(this)
|
||||
});
|
||||
},
|
||||
|
||||
@@ -117,6 +168,17 @@ var CloseDialog = new Lang.Class({
|
||||
if (this._dialog == null)
|
||||
return;
|
||||
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
|
||||
GLib.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
|
||||
global.display.disconnect(this._windowFocusChangedId)
|
||||
this._windowFocusChangedId = 0;
|
||||
|
||||
global.stage.disconnect(this._keyFocusChangedId);
|
||||
this._keyFocusChangedId = 0;
|
||||
|
||||
let dialog = this._dialog;
|
||||
this._dialog = null;
|
||||
this._removeWindowEffect();
|
||||
|
@@ -210,6 +210,10 @@ var AutomountManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_onVolumeRemoved(monitor, volume) {
|
||||
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
|
||||
Mainloop.source_remove(volume._allowAutorunExpireId);
|
||||
delete volume._allowAutorunExpireId;
|
||||
}
|
||||
this._volumeQueue =
|
||||
this._volumeQueue.filter(element => (element != volume));
|
||||
},
|
||||
@@ -234,8 +238,10 @@ var AutomountManager = new Lang.Class({
|
||||
_allowAutorunExpire(volume) {
|
||||
let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
|
||||
volume.allowAutorun = false;
|
||||
delete volume._allowAutorunExpireId;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
volume._allowAutorunExpireId = id;
|
||||
GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun');
|
||||
}
|
||||
});
|
||||
|
@@ -52,6 +52,8 @@ var DashItemContainer = new Lang.Class({
|
||||
this.animatingOut = false;
|
||||
|
||||
this.connect('destroy', () => {
|
||||
if (this.child != null)
|
||||
this.child.destroy();
|
||||
this.label.destroy();
|
||||
});
|
||||
},
|
||||
|
@@ -183,7 +183,7 @@ var MessageDialogContent = new Lang.Class({
|
||||
this[`_${prop}`].add_style_class_name(`message-dialog-${prop}`);
|
||||
});
|
||||
|
||||
let textProps = { ellipsize_mode: Pango.EllipsizeMode.NONE,
|
||||
let textProps = { ellipsize: Pango.EllipsizeMode.NONE,
|
||||
line_wrap: true };
|
||||
Object.assign(this._subtitle.clutter_text, textProps);
|
||||
Object.assign(this._body.clutter_text, textProps);
|
||||
|
32
js/ui/dnd.js
32
js/ui/dnd.js
@@ -125,6 +125,16 @@ var _Draggable = new Lang.Class({
|
||||
},
|
||||
|
||||
_onTouchEvent(actor, event) {
|
||||
// Here we only handle touch events on wayland. On X11
|
||||
// we do get emulated pointer events, which already works
|
||||
// for single-touch cases. Besides, the X11 passive touch grab
|
||||
// set up by Mutter will make us see first the touch events
|
||||
// and later the pointer events, so it will look like two
|
||||
// unrelated series of events, we want to avoid double handling
|
||||
// in these cases.
|
||||
if (!Meta.is_wayland_compositor())
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
|
||||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
@@ -396,10 +406,15 @@ var _Draggable = new Lang.Class({
|
||||
return true;
|
||||
},
|
||||
|
||||
_pickTargetActor() {
|
||||
return this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
this._dragX, this._dragY);
|
||||
},
|
||||
|
||||
_updateDragHover() {
|
||||
this._updateHoverId = 0;
|
||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
this._dragX, this._dragY);
|
||||
let target = this._pickTargetActor();
|
||||
|
||||
let dragEvent = {
|
||||
x: this._dragX,
|
||||
y: this._dragY,
|
||||
@@ -407,6 +422,18 @@ var _Draggable = new Lang.Class({
|
||||
source: this.actor._delegate,
|
||||
targetActor: target
|
||||
};
|
||||
|
||||
let targetActorDestroyHandlerId;
|
||||
let handleTargetActorDestroyClosure;
|
||||
handleTargetActorDestroyClosure = () => {
|
||||
target = this._pickTargetActor();
|
||||
dragEvent.targetActor = target;
|
||||
targetActorDestroyHandlerId =
|
||||
target.connect('destroy', handleTargetActorDestroyClosure);
|
||||
};
|
||||
targetActorDestroyHandlerId =
|
||||
target.connect('destroy', handleTargetActorDestroyClosure);
|
||||
|
||||
for (let i = 0; i < dragMonitors.length; i++) {
|
||||
let motionFunc = dragMonitors[i].dragMotion;
|
||||
if (motionFunc) {
|
||||
@@ -417,6 +444,7 @@ var _Draggable = new Lang.Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
dragEvent.targetActor.disconnect(targetActorDestroyHandlerId);
|
||||
|
||||
while (target) {
|
||||
if (target._delegate && target._delegate.handleDragOver) {
|
||||
|
@@ -760,7 +760,7 @@ var EndSessionDialog = new Lang.Class({
|
||||
let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
|
||||
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
|
||||
|
||||
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText);
|
||||
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
|
||||
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
|
||||
this._checkBox.actor.checked = (updatePrepared && updateTriggered);
|
||||
|
||||
|
@@ -17,6 +17,9 @@ const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const System = imports.system;
|
||||
|
||||
let _localTimeZone = null;
|
||||
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
// variable initializations, etc, that depend on init() already having
|
||||
@@ -116,9 +119,26 @@ function init() {
|
||||
}
|
||||
};
|
||||
|
||||
// Override to clear our own timezone cache as well
|
||||
const origClearDateCaches = System.clearDateCaches;
|
||||
System.clearDateCaches = function () {
|
||||
_localTimeZone = null;
|
||||
origClearDateCaches();
|
||||
};
|
||||
|
||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||
Date.prototype.toLocaleFormat = function(format) {
|
||||
return Shell.util_format_date(format, this.getTime());
|
||||
if (_localTimeZone === null)
|
||||
_localTimeZone = GLib.TimeZone.new_local();
|
||||
|
||||
let dt = GLib.DateTime.new(_localTimeZone,
|
||||
this.getYear(),
|
||||
this.getMonth() + 1,
|
||||
this.getDate(),
|
||||
this.getHours(),
|
||||
this.getMinutes(),
|
||||
this.getSeconds());
|
||||
return dt ? dt.format(format) : '';
|
||||
};
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
|
@@ -76,6 +76,7 @@ function disableExtension(uuid) {
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -115,13 +116,18 @@ function enableExtension(uuid) {
|
||||
extensionOrder.push(uuid);
|
||||
|
||||
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
for (let i = 0; i < stylesheetNames.length; i++) {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
if (stylesheetFile.query_exists(null)) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
try {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
theme.load_stylesheet(stylesheetFile);
|
||||
extension.stylesheet = stylesheetFile;
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
continue; // not an error
|
||||
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +137,10 @@ function enableExtension(uuid) {
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
return;
|
||||
} catch(e) {
|
||||
if (extension.stylesheet) {
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
|
@@ -418,6 +418,11 @@ var IconGrid = new Lang.Class({
|
||||
},
|
||||
|
||||
_animationDone() {
|
||||
this._clonesAnimating.forEach(clone => {
|
||||
clone.source.reactive = true;
|
||||
clone.source.opacity = 255;
|
||||
clone.destroy();
|
||||
});
|
||||
this._clonesAnimating = [];
|
||||
this.emit('animation-done');
|
||||
},
|
||||
@@ -538,10 +543,6 @@ var IconGrid = new Lang.Class({
|
||||
onComplete: () => {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
|
||||
actor.opacity = 255;
|
||||
actor.reactive = true;
|
||||
actorClone.destroy();
|
||||
}};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
@@ -562,12 +563,8 @@ var IconGrid = new Lang.Class({
|
||||
scale_x: scaleX,
|
||||
scale_y: scaleY,
|
||||
onComplete: () => {
|
||||
if (isLastItem) {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
this._restoreItemsOpacity();
|
||||
}
|
||||
actor.reactive = true;
|
||||
actorClone.destroy();
|
||||
}};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
@@ -581,12 +578,6 @@ var IconGrid = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_restoreItemsOpacity() {
|
||||
for (let index = 0; index < this._items.length; index++) {
|
||||
this._items[index].actor.opacity = 255;
|
||||
}
|
||||
},
|
||||
|
||||
_getAllocatedChildSizeAndSpacing(child) {
|
||||
let [,, natWidth, natHeight] = child.get_preferred_size();
|
||||
let width = Math.min(this._getHItemSize(), natWidth);
|
||||
|
@@ -533,17 +533,25 @@ var FocusTracker = new Lang.Class({
|
||||
},
|
||||
|
||||
_setCurrentRect(rect) {
|
||||
let frameRect = this._currentWindow.get_frame_rect();
|
||||
rect.x -= frameRect.x;
|
||||
rect.y -= frameRect.y;
|
||||
if (this._currentWindow) {
|
||||
let frameRect = this._currentWindow.get_frame_rect();
|
||||
rect.x -= frameRect.x;
|
||||
rect.y -= frameRect.y;
|
||||
}
|
||||
|
||||
this._rect = rect;
|
||||
this.emit('position-changed');
|
||||
},
|
||||
|
||||
getCurrentRect() {
|
||||
let frameRect = this._currentWindow.get_frame_rect();
|
||||
let rect = { x: this._rect.x + frameRect.x, y: this._rect.y + frameRect.y, width: this._rect.width, height: this._rect.height };
|
||||
let rect = { x: this._rect.x, y: this._rect.y,
|
||||
width: this._rect.width, height: this._rect.height };
|
||||
|
||||
if (this._currentWindow) {
|
||||
let frameRect = this._currentWindow.get_frame_rect();
|
||||
rect.x += frameRect.x;
|
||||
rect.y += frameRect.y;
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
@@ -916,9 +924,11 @@ var Keyboard = new Lang.Class({
|
||||
},
|
||||
|
||||
_relayout() {
|
||||
if (this.actor == null)
|
||||
return;
|
||||
let monitor = Main.layoutManager.keyboardMonitor;
|
||||
|
||||
if (this.actor == null || monitor == null)
|
||||
return;
|
||||
|
||||
let maxHeight = monitor.height / 3;
|
||||
this.actor.width = monitor.width;
|
||||
this.actor.height = maxHeight;
|
||||
|
@@ -203,6 +203,7 @@ var LayoutManager = new Lang.Class({
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
|
||||
this.uiGroup.set_flags(Clutter.ActorFlags.NO_LAYOUT);
|
||||
this.uiGroup.connect('allocate', (actor, box, flags) => {
|
||||
let children = actor.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
@@ -557,6 +558,8 @@ var LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
get focusMonitor() {
|
||||
if (this.focusIndex < 0)
|
||||
return null;
|
||||
return this.monitors[this.focusIndex];
|
||||
},
|
||||
|
||||
|
@@ -343,6 +343,9 @@ function loadTheme() {
|
||||
let theme = new St.Theme ({ application_stylesheet: _cssStylesheet,
|
||||
default_stylesheet: _defaultCssStylesheet });
|
||||
|
||||
if (theme.default_stylesheet == null)
|
||||
throw new Error("No valid stylesheet found for '%s'".format(sessionMode.stylesheetName));
|
||||
|
||||
if (previousTheme) {
|
||||
let customStylesheets = previousTheme.get_custom_stylesheets();
|
||||
|
||||
|
@@ -362,7 +362,8 @@ var Message = new Lang.Class({
|
||||
this.setBody(body);
|
||||
|
||||
this._closeButton.connect('clicked', this.close.bind(this));
|
||||
this.actor.connect('notify::hover', this._sync.bind(this));
|
||||
let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this));
|
||||
this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId));
|
||||
this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
this._sync();
|
||||
|
@@ -1320,6 +1320,7 @@ var MessageTray = new Lang.Class({
|
||||
this._bannerBin.y = -this._banner.actor.height;
|
||||
this.actor.show();
|
||||
|
||||
Meta.disable_unredirect_for_screen(global.screen);
|
||||
this._updateShowingNotification();
|
||||
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
@@ -1457,6 +1458,7 @@ var MessageTray = new Lang.Class({
|
||||
|
||||
this._pointerInNotification = false;
|
||||
this._notificationRemoved = false;
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
|
||||
this._banner.actor.destroy();
|
||||
this._banner = null;
|
||||
|
@@ -117,10 +117,8 @@ var FdoNotificationDaemon = new Lang.Class({
|
||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||
return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
|
||||
bitsPerSample, width, height, rowStride);
|
||||
} else if (hints['image-path']) {
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
|
||||
}
|
||||
return null;
|
||||
return this._iconForNotificationData(hints['image-path']);
|
||||
},
|
||||
|
||||
_fallbackIconForNotificationData(hints) {
|
||||
|
@@ -108,15 +108,30 @@ var OsdWindow = new Lang.Class({
|
||||
this._hideTimeoutId = 0;
|
||||
this._reset();
|
||||
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
this._relayout.bind(this));
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._monitorsChangedId =
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
this._relayout.bind(this));
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
themeContext.connect('notify::scale-factor',
|
||||
this._relayout.bind(this));
|
||||
this._scaleChangedId =
|
||||
themeContext.connect('notify::scale-factor',
|
||||
this._relayout.bind(this));
|
||||
this._relayout();
|
||||
Main.uiGroup.add_child(this.actor);
|
||||
},
|
||||
|
||||
_onDestroy() {
|
||||
if (this._monitorsChangedId)
|
||||
Main.layoutManager.disconnect(this._monitorsChangedId);
|
||||
this._monitorsChangedId = 0;
|
||||
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
if (this._scaleChangedId)
|
||||
themeContext.disconnect(this._scaleChangedId);
|
||||
this._scaleChangedId = 0;
|
||||
},
|
||||
|
||||
setIcon(icon) {
|
||||
this._icon.gicon = icon;
|
||||
},
|
||||
|
@@ -393,10 +393,8 @@ var Overview = new Lang.Class({
|
||||
if (!Main.layoutManager.primaryMonitor)
|
||||
return;
|
||||
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
|
||||
this._coverPane.set_position(0, workArea.y);
|
||||
this._coverPane.set_size(workArea.width, workArea.height);
|
||||
this._coverPane.set_position(0, 0);
|
||||
this._coverPane.set_size(global.screen_width, global.screen_height);
|
||||
|
||||
this._updateBackgrounds();
|
||||
},
|
||||
|
@@ -284,6 +284,11 @@ var ThumbnailsSlider = new Lang.Class({
|
||||
return child.get_theme_node().get_length('visible-width');
|
||||
},
|
||||
|
||||
_onDragEnd() {
|
||||
this.actor.sync_hover();
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_getSlide() {
|
||||
if (!this._visible)
|
||||
return 0;
|
||||
|
@@ -796,6 +796,7 @@ var Panel = new Lang.Class({
|
||||
this.actor.connect('get-preferred-height', this._getPreferredHeight.bind(this));
|
||||
this.actor.connect('allocate', this._allocate.bind(this));
|
||||
this.actor.connect('button-press-event', this._onButtonPress.bind(this));
|
||||
this.actor.connect('touch-event', this._onButtonPress.bind(this));
|
||||
this.actor.connect('key-press-event', this._onKeyPress.bind(this));
|
||||
|
||||
Main.overview.connect('showing', () => {
|
||||
@@ -939,8 +940,13 @@ var Panel = new Lang.Class({
|
||||
if (event.get_source() != actor)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let button = event.get_button();
|
||||
if (button != 1)
|
||||
let type = event.type();
|
||||
let isPress = type == Clutter.EventType.BUTTON_PRESS;
|
||||
if (!isPress && type != Clutter.EventType.TOUCH_BEGIN)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let button = isPress ? event.get_button() : -1;
|
||||
if (isPress && button != 1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let focusWindow = global.display.focus_window;
|
||||
@@ -1079,6 +1085,7 @@ var Panel = new Lang.Class({
|
||||
let windows = activeWorkspace.list_windows().filter(metaWindow => {
|
||||
return metaWindow.is_on_primary_monitor() &&
|
||||
metaWindow.showing_on_its_workspace() &&
|
||||
!metaWindow.is_hidden() &&
|
||||
metaWindow.get_window_type() != Meta.WindowType.DESKTOP;
|
||||
});
|
||||
|
||||
|
@@ -141,8 +141,17 @@ var PopupBaseMenuItem = new Lang.Class({
|
||||
},
|
||||
|
||||
_onKeyPressEvent(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
let state = event.get_state();
|
||||
|
||||
// if user has a modifier down (except capslock)
|
||||
// then don't handle the key press here
|
||||
state &= ~Clutter.ModifierType.LOCK_MASK;
|
||||
state &= Clutter.ModifierType.MODIFIER_MASK;
|
||||
|
||||
if (state)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.activate(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
|
@@ -114,18 +114,16 @@ var RunDialog = new Lang.Class({
|
||||
|
||||
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
|
||||
entry: this._entryText });
|
||||
this._entryText.connect('activate', (o) => {
|
||||
this.popModal();
|
||||
this._run(o.get_text(),
|
||||
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
|
||||
if (!this._commandError ||
|
||||
!this.pushModal())
|
||||
this.close();
|
||||
});
|
||||
this._entryText.connect('key-press-event', (o, e) => {
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||
this.popModal();
|
||||
this._run(o.get_text(),
|
||||
e.get_state() & Clutter.ModifierType.CONTROL_MASK);
|
||||
if (!this._commandError ||
|
||||
!this.pushModal())
|
||||
this.close();
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
if (symbol == Clutter.Tab) {
|
||||
let text = o.get_text();
|
||||
let prefix;
|
||||
|
@@ -192,6 +192,7 @@ var SearchResultsBase = new Lang.Class({
|
||||
},
|
||||
|
||||
clear() {
|
||||
this._cancellable.cancel();
|
||||
for (let resultId in this._resultDisplays)
|
||||
this._resultDisplays[resultId].actor.destroy();
|
||||
this._resultDisplays = {};
|
||||
@@ -225,6 +226,12 @@ var SearchResultsBase = new Lang.Class({
|
||||
this._cancellable.reset();
|
||||
|
||||
this.provider.getResultMetas(metasNeeded, metas => {
|
||||
if (this._cancellable.is_cancelled()) {
|
||||
if (metas.length > 0)
|
||||
log(`Search provider ${this.provider.id} returned results after the request was canceled`);
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
if (metas.length != metasNeeded.length) {
|
||||
log('Wrong number of result metas returned by search provider ' + this.provider.id +
|
||||
': expected ' + metasNeeded.length + ' but got ' + metas.length);
|
||||
|
@@ -360,11 +360,14 @@ var InputSourceManager = new Lang.Class({
|
||||
this._settings.connect('per-window-changed', this._sourcesPerWindowChanged.bind(this));
|
||||
this._sourcesPerWindowChanged();
|
||||
this._disableIBus = false;
|
||||
this._reloading = false;
|
||||
},
|
||||
|
||||
reload() {
|
||||
this._reloading = true;
|
||||
this._keyboardManager.setKeyboardOptions(this._settings.keyboardOptions);
|
||||
this._inputSourcesChanged();
|
||||
this._reloading = false;
|
||||
},
|
||||
|
||||
_ibusReadyCallback(im, ready) {
|
||||
@@ -458,7 +461,15 @@ var InputSourceManager = new Lang.Class({
|
||||
},
|
||||
|
||||
activateInputSource(is, interactive) {
|
||||
KeyboardManager.holdKeyboard();
|
||||
// The focus changes during holdKeyboard/releaseKeyboard may trick
|
||||
// the client into hiding UI containing the currently focused entry.
|
||||
// So holdKeyboard/releaseKeyboard are not called when
|
||||
// 'set-content-type' signal is received.
|
||||
// E.g. Focusing on a password entry in a popup in Xorg Firefox
|
||||
// will emit 'set-content-type' signal.
|
||||
// https://gitlab.gnome.org/GNOME/gnome-shell/issues/391
|
||||
if (!this._reloading)
|
||||
KeyboardManager.holdKeyboard();
|
||||
this._keyboardManager.apply(is.xkbId);
|
||||
|
||||
// All the "xkb:..." IBus engines simply "echo" back symbols,
|
||||
@@ -473,7 +484,10 @@ var InputSourceManager = new Lang.Class({
|
||||
else
|
||||
engine = 'xkb:us::eng';
|
||||
|
||||
this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard);
|
||||
if (!this._reloading)
|
||||
this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard);
|
||||
else
|
||||
this._ibusManager.setEngine(engine);
|
||||
this._currentInputSourceChanged(is);
|
||||
|
||||
if (interactive)
|
||||
|
@@ -419,12 +419,14 @@ var NMConnectionDevice = new Lang.Class({
|
||||
this._deactivateItem.actor.visible = this._device.state > NM.DeviceState.DISCONNECTED;
|
||||
|
||||
if (this._activeConnection == null) {
|
||||
this._activeConnection = this._device.active_connection;
|
||||
|
||||
if (this._activeConnection) {
|
||||
ensureActiveConnectionProps(this._activeConnection, this._client);
|
||||
let item = this._connectionItems.get(this._activeConnection.connection.get_uuid());
|
||||
item.setActiveConnection(this._activeConnection);
|
||||
let activeConnection = this._device.active_connection;
|
||||
if (activeConnection && activeConnection.connection) {
|
||||
let item = this._connectionItems.get(activeConnection.connection.get_uuid());
|
||||
if (item) {
|
||||
this._activeConnection = activeConnection;
|
||||
ensureActiveConnectionProps(this._activeConnection, this._client);
|
||||
item.setActiveConnection(this._activeConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,9 @@ var AltSwitcher = new Lang.Class({
|
||||
childToShow = this._standard;
|
||||
} else if (this._alternate.visible) {
|
||||
childToShow = this._alternate;
|
||||
} else {
|
||||
this.actor.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
let childShown = this.actor.get_child();
|
||||
@@ -79,7 +82,7 @@ var AltSwitcher = new Lang.Class({
|
||||
global.sync_pointer();
|
||||
}
|
||||
|
||||
this.actor.visible = (childToShow != null);
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
_onDestroy() {
|
||||
|
@@ -311,6 +311,7 @@ var ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.reset();
|
||||
this._workspacesDisplay.hide();
|
||||
},
|
||||
|
||||
@@ -459,7 +460,11 @@ var ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
reset() {
|
||||
global.stage.set_key_focus(null);
|
||||
// Don't drop the key focus on Clutter's side if anything but the
|
||||
// overview has pushed a modal (e.g. system modals when activated using
|
||||
// the overview).
|
||||
if (Main.modalCount <= 1)
|
||||
global.stage.set_key_focus(null);
|
||||
|
||||
this._entry.text = '';
|
||||
|
||||
|
@@ -627,8 +627,8 @@ var AppSwitchAction = new Lang.Class({
|
||||
|
||||
if (this.get_n_current_points() == 3) {
|
||||
for (let i = 0; i < this.get_n_current_points(); i++) {
|
||||
[startX, startY] = this.get_press_coords(i);
|
||||
[x, y] = this.get_motion_coords(i);
|
||||
let [startX, startY] = this.get_press_coords(i);
|
||||
let [x, y] = this.get_motion_coords(i);
|
||||
|
||||
if (Math.abs(x - startX) > MOTION_THRESHOLD ||
|
||||
Math.abs(y - startY) > MOTION_THRESHOLD)
|
||||
@@ -1173,6 +1173,10 @@ var WindowManager = new Lang.Class({
|
||||
yScale = geom.height / actor.height;
|
||||
} else {
|
||||
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
||||
if (!monitor) {
|
||||
this._minimizeWindowDone();
|
||||
return;
|
||||
}
|
||||
xDest = monitor.x;
|
||||
yDest = monitor.y;
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||
@@ -1248,6 +1252,11 @@ var WindowManager = new Lang.Class({
|
||||
geom.height / actor.height);
|
||||
} else {
|
||||
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
||||
if (!monitor) {
|
||||
actor.show();
|
||||
this._unminimizeWindowDone();
|
||||
return;
|
||||
}
|
||||
actor.set_position(monitor.x, monitor.y);
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||
actor.x += monitor.width;
|
||||
@@ -1754,6 +1763,14 @@ var WindowManager = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < switchData.windows.length; i++) {
|
||||
let w = switchData.windows[i];
|
||||
|
||||
w.windowDestroyId = w.window.connect('destroy', () => {
|
||||
switchData.windows.splice(switchData.windows.indexOf(w), 1);
|
||||
});
|
||||
}
|
||||
|
||||
switchData.inGroup.set_position(-xDest, -yDest);
|
||||
switchData.inGroup.raise_top();
|
||||
|
||||
@@ -1784,8 +1801,8 @@ var WindowManager = new Lang.Class({
|
||||
|
||||
for (let i = 0; i < switchData.windows.length; i++) {
|
||||
let w = switchData.windows[i];
|
||||
if (w.window.is_destroyed()) // Window gone
|
||||
continue;
|
||||
w.window.disconnect(w.windowDestroyId);
|
||||
|
||||
if (w.window.get_parent() == switchData.outGroup) {
|
||||
w.window.reparent(w.parent);
|
||||
w.window.hide();
|
||||
|
@@ -128,11 +128,10 @@ var WindowMenu = new Lang.Class({
|
||||
|
||||
let screen = global.screen;
|
||||
let nMonitors = screen.get_n_monitors();
|
||||
if (nMonitors > 1) {
|
||||
let monitorIndex = window.get_monitor();
|
||||
if (nMonitors > 1 && monitorIndex >= 0) {
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
let monitorIndex = window.get_monitor();
|
||||
|
||||
let dir = Meta.ScreenDirection.UP;
|
||||
let upMonitorIndex =
|
||||
screen.get_monitor_neighbor_index(monitorIndex, dir);
|
||||
|
@@ -137,8 +137,10 @@ var WindowClone = new Lang.Class({
|
||||
this._dragSlot = [0, 0, 0, 0];
|
||||
this._stackAbove = null;
|
||||
|
||||
this._windowClone._updateId = this.metaWindow.connect('size-changed',
|
||||
this._onRealWindowSizeChanged.bind(this));
|
||||
this._windowClone._sizeChangedId = this.metaWindow.connect('size-changed',
|
||||
this._onMetaWindowSizeChanged.bind(this));
|
||||
this._windowClone._posChangedId = this.metaWindow.connect('position-changed',
|
||||
this._computeBoundingBox.bind(this));
|
||||
this._windowClone._destroyId =
|
||||
this.realWindow.connect('destroy', () => {
|
||||
// First destroy the clone and then destroy everything
|
||||
@@ -206,8 +208,7 @@ var WindowClone = new Lang.Class({
|
||||
|
||||
addAttachedDialog(win) {
|
||||
this._doAddAttachedDialog(win, win.get_compositor_private());
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
this._onMetaWindowSizeChanged();
|
||||
},
|
||||
|
||||
hasAttachedDialogs() {
|
||||
@@ -216,15 +217,14 @@ var WindowClone = new Lang.Class({
|
||||
|
||||
_doAddAttachedDialog(metaWin, realWin) {
|
||||
let clone = new Clutter.Clone({ source: realWin });
|
||||
clone._updateId = metaWin.connect('size-changed', () => {
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
});
|
||||
clone._sizeChangedId = metaWin.connect('size-changed',
|
||||
this._onMetaWindowSizeChanged.bind(this));
|
||||
clone._posChangedId = metaWin.connect('position-changed',
|
||||
this._onMetaWindowSizeChanged.bind(this));
|
||||
clone._destroyId = realWin.connect('destroy', () => {
|
||||
clone.destroy();
|
||||
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
this._onMetaWindowSizeChanged();
|
||||
});
|
||||
this.actor.add_child(clone);
|
||||
},
|
||||
@@ -321,12 +321,13 @@ var WindowClone = new Lang.Class({
|
||||
else
|
||||
realWindow = child.source;
|
||||
|
||||
realWindow.meta_window.disconnect(child._updateId);
|
||||
realWindow.meta_window.disconnect(child._sizeChangedId);
|
||||
realWindow.meta_window.disconnect(child._posChangedId);
|
||||
realWindow.disconnect(child._destroyId);
|
||||
});
|
||||
},
|
||||
|
||||
_onRealWindowSizeChanged() {
|
||||
_onMetaWindowSizeChanged() {
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
},
|
||||
@@ -469,7 +470,6 @@ var WindowOverlay = new Lang.Class({
|
||||
this._windowAddedId = 0;
|
||||
|
||||
button.hide();
|
||||
title.hide();
|
||||
|
||||
this.title = title;
|
||||
this.closeButton = button;
|
||||
@@ -544,12 +544,10 @@ var WindowOverlay = new Lang.Class({
|
||||
let titleX = cloneX + (cloneWidth - title.width) / 2;
|
||||
let titleY = cloneY + cloneHeight - (title.height - this.borderSize) / 2;
|
||||
|
||||
if (animate) {
|
||||
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), title.width);
|
||||
} else {
|
||||
title.width = title.width;
|
||||
if (animate)
|
||||
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY));
|
||||
else
|
||||
title.set_position(Math.floor(titleX), Math.floor(titleY));
|
||||
}
|
||||
|
||||
let borderX = cloneX - this.borderSize;
|
||||
let borderY = cloneY - this.borderSize;
|
||||
@@ -568,10 +566,12 @@ var WindowOverlay = new Lang.Class({
|
||||
_animateOverlayActor(actor, x, y, width, height) {
|
||||
let params = { x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' };
|
||||
|
||||
if (width !== undefined)
|
||||
params.width = width;
|
||||
|
||||
if (height !== undefined)
|
||||
params.height = height;
|
||||
|
||||
@@ -1506,7 +1506,7 @@ var Workspace = new Lang.Class({
|
||||
if (metaWin.is_attached_dialog()) {
|
||||
let parent = metaWin.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = metaWin.get_transient_for();
|
||||
parent = parent.get_transient_for();
|
||||
|
||||
let idx = this._lookupIndex (parent);
|
||||
if (idx < 0) {
|
||||
|
@@ -68,7 +68,7 @@ var WindowClone = new Lang.Class({
|
||||
this.realWindow = realWindow;
|
||||
this.metaWindow = realWindow.meta_window;
|
||||
|
||||
this.clone._updateId = this.metaWindow.connect('position-changed',
|
||||
this.clone._updateId = this.realWindow.connect('notify::position',
|
||||
this._onPositionChanged.bind(this));
|
||||
this.clone._destroyId = this.realWindow.connect('destroy', () => {
|
||||
// First destroy the clone and then destroy everything
|
||||
@@ -153,7 +153,7 @@ var WindowClone = new Lang.Class({
|
||||
let clone = new Clutter.Clone({ source: realDialog });
|
||||
this._updateDialogPosition(realDialog, clone);
|
||||
|
||||
clone._updateId = metaDialog.connect('position-changed', dialog => {
|
||||
clone._updateId = realDialog.connect('notify::position', dialog => {
|
||||
this._updateDialogPosition(dialog, clone);
|
||||
});
|
||||
clone._destroyId = realDialog.connect('destroy', () => {
|
||||
@@ -171,7 +171,6 @@ var WindowClone = new Lang.Class({
|
||||
},
|
||||
|
||||
_onPositionChanged() {
|
||||
let rect = this.metaWindow.get_frame_rect();
|
||||
this.actor.set_position(this.realWindow.x, this.realWindow.y);
|
||||
},
|
||||
|
||||
@@ -179,7 +178,7 @@ var WindowClone = new Lang.Class({
|
||||
this.actor.get_children().forEach(child => {
|
||||
let realWindow = child.source;
|
||||
|
||||
realWindow.meta_window.disconnect(child._updateId);
|
||||
realWindow.disconnect(child._updateId);
|
||||
realWindow.disconnect(child._destroyId);
|
||||
});
|
||||
},
|
||||
@@ -417,7 +416,7 @@ var WorkspaceThumbnail = new Lang.Class({
|
||||
} else if (metaWin.is_attached_dialog()) {
|
||||
let parent = metaWin.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = metaWin.get_transient_for();
|
||||
parent = parent.get_transient_for();
|
||||
|
||||
let idx = this._lookupIndex (parent);
|
||||
if (idx < 0) {
|
||||
@@ -677,7 +676,11 @@ var ThumbnailsBox = new Lang.Class({
|
||||
this._settings.connect('changed::dynamic-workspaces',
|
||||
this._updateSwitcherVisibility.bind(this));
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', this._rebuildThumbnails.bind(this));
|
||||
Main.layoutManager.connect('monitors-changed', () => {
|
||||
this._destroyThumbnails();
|
||||
if (Main.overview.visible)
|
||||
this._createThumbnails();
|
||||
});
|
||||
},
|
||||
|
||||
_updateSwitcherVisibility() {
|
||||
@@ -870,9 +873,6 @@ var ThumbnailsBox = new Lang.Class({
|
||||
Main.overview.connect('windows-restacked',
|
||||
this._syncStacking.bind(this));
|
||||
|
||||
this._workareasChangedId =
|
||||
global.screen.connect('workareas-changed', this._rebuildThumbnails.bind(this));
|
||||
|
||||
this._targetScale = 0;
|
||||
this._scale = 0;
|
||||
this._pendingScaleUpdate = false;
|
||||
@@ -902,24 +902,12 @@ var ThumbnailsBox = new Lang.Class({
|
||||
this._syncStackingId = 0;
|
||||
}
|
||||
|
||||
if (this._workareasChangedId > 0) {
|
||||
global.screen.disconnect(this._workareasChangedId);
|
||||
this._workareasChangedId = 0;
|
||||
}
|
||||
|
||||
for (let w = 0; w < this._thumbnails.length; w++)
|
||||
this._thumbnails[w].destroy();
|
||||
this._thumbnails = [];
|
||||
this._porthole = null;
|
||||
},
|
||||
|
||||
_rebuildThumbnails() {
|
||||
this._destroyThumbnails();
|
||||
|
||||
if (Main.overview.visible)
|
||||
this._createThumbnails();
|
||||
},
|
||||
|
||||
_workspacesChanged() {
|
||||
let validThumbnails =
|
||||
this._thumbnails.filter(t => t.state <= ThumbnailState.NORMAL);
|
||||
|
@@ -470,6 +470,7 @@ var WorkspacesDisplay = new Lang.Class({
|
||||
this._switchWorkspaceNotifyId = 0;
|
||||
|
||||
this._notifyOpacityId = 0;
|
||||
this._restackedNotifyId = 0;
|
||||
this._scrollEventId = 0;
|
||||
this._keyPressEventId = 0;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('gnome-shell', 'c',
|
||||
version: '3.28.3',
|
||||
version: '3.28.4',
|
||||
meson_version: '>= 0.42.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
|
2
po/cs.po
2
po/cs.po
@@ -1064,7 +1064,7 @@ msgstr "Načítá se…"
|
||||
#: js/ui/dateMenu.js:321
|
||||
#, javascript-format
|
||||
msgid "Feels like %s."
|
||||
msgstr "Pocitově jako %s."
|
||||
msgstr "Pocitová teplota %s."
|
||||
|
||||
#: js/ui/dateMenu.js:324
|
||||
msgid "Go online for weather information"
|
||||
|
@@ -103,6 +103,7 @@ libshell_menu_dep = declare_dependency(link_with: libshell_menu)
|
||||
|
||||
libshell_public_headers = [
|
||||
'shell-app.h',
|
||||
'shell-app-cache.h',
|
||||
'shell-app-system.h',
|
||||
'shell-app-usage.h',
|
||||
'shell-embedded-window.h',
|
||||
@@ -138,6 +139,7 @@ libshell_private_headers = [
|
||||
libshell_sources = [
|
||||
'gnome-shell-plugin.c',
|
||||
'shell-app.c',
|
||||
'shell-app-cache.c',
|
||||
'shell-app-system.c',
|
||||
'shell-app-usage.c',
|
||||
'shell-embedded-window.c',
|
||||
|
439
src/shell-app-cache.c
Normal file
439
src/shell-app-cache.c
Normal file
@@ -0,0 +1,439 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-app-cache.h"
|
||||
|
||||
/**
|
||||
* SECTION:shell-app-cache
|
||||
* @title: ShellAppCache
|
||||
* @short_description: application information cache
|
||||
*
|
||||
* The #ShellAppCache is responsible for caching information about #GAppInfo
|
||||
* to ensure that the compositor thread never needs to perform disk reads to
|
||||
* access them. All of the work is done off-thread. When the new data has
|
||||
* been loaded, a #ShellAppCache::changed signal is emitted.
|
||||
*
|
||||
* Additionally, the #ShellAppCache caches information about translations for
|
||||
* directories. This allows translation provided in [Desktop Entry] GKeyFiles
|
||||
* to be available when building StLabel and other elements without performing
|
||||
* costly disk reads.
|
||||
*
|
||||
* Various monitors are used to keep this information up to date while the
|
||||
* Shell is running.
|
||||
*/
|
||||
|
||||
#define DEFAULT_TIMEOUT_SECONDS 5
|
||||
|
||||
struct _ShellAppCache
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GMutex mutex;
|
||||
|
||||
GAppInfoMonitor *monitor;
|
||||
GPtrArray *dir_monitors;
|
||||
GHashTable *folders;
|
||||
GCancellable *cancellable;
|
||||
GList *app_infos;
|
||||
|
||||
guint queued_update;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GList *app_infos;
|
||||
GHashTable *folders;
|
||||
} CacheState;
|
||||
|
||||
G_DEFINE_TYPE (ShellAppCache, shell_app_cache, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals [N_SIGNALS];
|
||||
|
||||
static void
|
||||
cache_state_free (CacheState *state)
|
||||
{
|
||||
g_clear_pointer (&state->folders, g_hash_table_unref);
|
||||
g_list_free_full (state->app_infos, g_object_unref);
|
||||
g_slice_free (CacheState, state);
|
||||
}
|
||||
|
||||
static CacheState *
|
||||
cache_state_new (void)
|
||||
{
|
||||
CacheState *state;
|
||||
|
||||
state = g_slice_new0 (CacheState);
|
||||
state->folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
return g_steal_pointer (&state);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_cache_get_default:
|
||||
*
|
||||
* Gets the default #ShellAppCache.
|
||||
*
|
||||
* Returns: (transfer none): a #ShellAppCache
|
||||
*/
|
||||
ShellAppCache *
|
||||
shell_app_cache_get_default (void)
|
||||
{
|
||||
static ShellAppCache *instance;
|
||||
|
||||
if (instance == NULL)
|
||||
{
|
||||
instance = g_object_new (SHELL_TYPE_APP_CACHE, NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void
|
||||
load_folder (GHashTable *folders,
|
||||
const char *path)
|
||||
{
|
||||
g_autoptr(GDir) dir = NULL;
|
||||
const char *name;
|
||||
|
||||
g_assert (folders != NULL);
|
||||
g_assert (path != NULL);
|
||||
|
||||
dir = g_dir_open (path, 0, NULL);
|
||||
if (dir == NULL)
|
||||
return;
|
||||
|
||||
while ((name = g_dir_read_name (dir)))
|
||||
{
|
||||
g_autofree gchar *filename = NULL;
|
||||
g_autoptr(GKeyFile) keyfile = NULL;
|
||||
|
||||
/* First added wins */
|
||||
if (g_hash_table_contains (folders, name))
|
||||
continue;
|
||||
|
||||
filename = g_build_filename (path, name, NULL);
|
||||
keyfile = g_key_file_new ();
|
||||
|
||||
if (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL))
|
||||
g_hash_table_insert (folders,
|
||||
g_strdup (name),
|
||||
g_key_file_get_locale_string (keyfile,
|
||||
"Desktop Entry",
|
||||
"Name",
|
||||
NULL,
|
||||
NULL));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load_folders (GHashTable *folders)
|
||||
{
|
||||
const char * const *dirs;
|
||||
g_autofree gchar *userdir = NULL;
|
||||
guint i;
|
||||
|
||||
g_assert (folders != NULL);
|
||||
|
||||
userdir = g_build_filename (g_get_user_data_dir (), "desktop-directories", NULL);
|
||||
load_folder (folders, userdir);
|
||||
|
||||
dirs = g_get_system_data_dirs ();
|
||||
for (i = 0; dirs[i] != NULL; i++)
|
||||
{
|
||||
g_autofree gchar *sysdir = g_build_filename (dirs[i], "desktop-directories", NULL);
|
||||
load_folder (folders, sysdir);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_cache_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
CacheState *state;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SHELL_IS_APP_CACHE (source_object));
|
||||
|
||||
state = cache_state_new ();
|
||||
state->app_infos = g_app_info_get_all ();
|
||||
load_folders (state->folders);
|
||||
|
||||
g_task_return_pointer (task, state, (GDestroyNotify)cache_state_free);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_update_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppCache *cache = (ShellAppCache *)object;
|
||||
g_autoptr(GError) error = NULL;
|
||||
CacheState *state;
|
||||
|
||||
g_assert (SHELL_IS_APP_CACHE (cache));
|
||||
g_assert (G_IS_TASK (result));
|
||||
g_assert (user_data == NULL);
|
||||
|
||||
state = g_task_propagate_pointer (G_TASK (result), &error);
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
g_mutex_lock (&cache->mutex);
|
||||
g_list_free_full (cache->app_infos, g_object_unref);
|
||||
cache->app_infos = g_steal_pointer (&state->app_infos);
|
||||
g_clear_pointer (&cache->folders, g_hash_table_unref);
|
||||
cache->folders = g_steal_pointer (&state->folders);
|
||||
g_mutex_unlock (&cache->mutex);
|
||||
|
||||
g_signal_emit (cache, signals[CHANGED], 0);
|
||||
|
||||
cache_state_free (state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_app_cache_do_update (gpointer user_data)
|
||||
{
|
||||
ShellAppCache *cache = user_data;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
cache->queued_update = 0;
|
||||
|
||||
/* Reset the cancellable state so we don't race with
|
||||
* two updates coming back overlapped and applying the
|
||||
* information in the wrong order.
|
||||
*/
|
||||
g_cancellable_cancel (cache->cancellable);
|
||||
g_clear_object (&cache->cancellable);
|
||||
cache->cancellable = g_cancellable_new ();
|
||||
|
||||
task = g_task_new (cache, cache->cancellable, apply_update_cb, NULL);
|
||||
g_task_set_source_tag (task, shell_app_cache_do_update);
|
||||
g_task_run_in_thread (task, shell_app_cache_worker);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_cache_queue_update (ShellAppCache *self)
|
||||
{
|
||||
g_assert (SHELL_IS_APP_CACHE (self));
|
||||
|
||||
if (self->queued_update != 0)
|
||||
g_source_remove (self->queued_update);
|
||||
|
||||
self->queued_update = g_timeout_add_seconds (DEFAULT_TIMEOUT_SECONDS,
|
||||
shell_app_cache_do_update,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_data_dir (ShellAppCache *self,
|
||||
const gchar *directory)
|
||||
{
|
||||
g_autofree gchar *subdir = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
g_autoptr(GFileMonitor) monitor = NULL;
|
||||
|
||||
g_assert (SHELL_IS_APP_CACHE (self));
|
||||
|
||||
if (directory == NULL)
|
||||
return;
|
||||
|
||||
subdir = g_build_filename (directory, "desktop-directories", NULL);
|
||||
file = g_file_new_for_path (subdir);
|
||||
monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
|
||||
if (monitor != NULL)
|
||||
{
|
||||
g_file_monitor_set_rate_limit (monitor, DEFAULT_TIMEOUT_SECONDS * 1000);
|
||||
g_signal_connect_object (monitor,
|
||||
"changed",
|
||||
G_CALLBACK (shell_app_cache_queue_update),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_ptr_array_add (self->dir_monitors, g_steal_pointer (&monitor));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_cache_finalize (GObject *object)
|
||||
{
|
||||
ShellAppCache *self = (ShellAppCache *)object;
|
||||
|
||||
g_clear_object (&self->monitor);
|
||||
|
||||
if (self->queued_update)
|
||||
{
|
||||
g_source_remove (self->queued_update);
|
||||
self->queued_update = 0;
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->dir_monitors, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->folders, g_hash_table_unref);
|
||||
g_list_free_full (self->app_infos, g_object_unref);
|
||||
g_mutex_clear (&self->mutex);
|
||||
|
||||
G_OBJECT_CLASS (shell_app_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_cache_class_init (ShellAppCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = shell_app_cache_finalize;
|
||||
|
||||
/**
|
||||
* ShellAppCache::changed:
|
||||
*
|
||||
* The "changed" signal is emitted when the cache has updated
|
||||
* information about installed applications.
|
||||
*/
|
||||
signals [CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_cache_init (ShellAppCache *self)
|
||||
{
|
||||
const gchar * const *sysdirs;
|
||||
guint i;
|
||||
|
||||
g_mutex_init (&self->mutex);
|
||||
|
||||
/* Monitor directories for translation changes */
|
||||
self->dir_monitors = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
monitor_data_dir (self, g_get_user_data_dir ());
|
||||
sysdirs = g_get_system_data_dirs ();
|
||||
for (i = 0; sysdirs[i] != NULL; i++)
|
||||
monitor_data_dir (self, sysdirs[i]);
|
||||
|
||||
/* Load translated directory names immediately */
|
||||
self->folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
load_folders (self->folders);
|
||||
|
||||
/* Setup AppMonitor to track changes */
|
||||
self->monitor = g_app_info_monitor_get ();
|
||||
g_signal_connect_object (self->monitor,
|
||||
"changed",
|
||||
G_CALLBACK (shell_app_cache_queue_update),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
self->app_infos = g_app_info_get_all ();
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_cache_get_all:
|
||||
* @cache: (nullable): a #ShellAppCache or %NULL
|
||||
*
|
||||
* Like g_app_info_get_all() but always returns a
|
||||
* cached set of application info so the caller can be
|
||||
* sure that I/O will not happen on the current thread.
|
||||
*
|
||||
* Returns: (transfer full) (element-type GAppInfo):
|
||||
* a newly allocated GList of references to GAppInfos.
|
||||
*/
|
||||
GList *
|
||||
shell_app_cache_get_all (ShellAppCache *cache)
|
||||
{
|
||||
GList *ret;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = shell_app_cache_get_default ();
|
||||
|
||||
g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
|
||||
g_mutex_lock (&cache->mutex);
|
||||
ret = g_list_copy_deep (cache->app_infos, (GCopyFunc)g_object_ref, NULL);
|
||||
g_mutex_unlock (&cache->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_cache_get_info:
|
||||
* @cache: (nullable): a #ShellAppCache or %NULL
|
||||
* @id: the application id
|
||||
*
|
||||
* A replacement for g_desktop_app_info_new() that will lookup the information
|
||||
* from the cache instead of (re)loading from disk.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a #GDesktopAppInfo or %NULL
|
||||
*/
|
||||
GDesktopAppInfo *
|
||||
shell_app_cache_get_info (ShellAppCache *cache,
|
||||
const char *id)
|
||||
{
|
||||
GDesktopAppInfo *ret = NULL;
|
||||
const GList *iter;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = shell_app_cache_get_default ();
|
||||
|
||||
g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
|
||||
g_mutex_lock (&cache->mutex);
|
||||
|
||||
for (iter = cache->app_infos; iter != NULL; iter = iter->next)
|
||||
{
|
||||
GAppInfo *info = iter->data;
|
||||
|
||||
if (g_strcmp0 (id, g_app_info_get_id (info)) == 0)
|
||||
{
|
||||
ret = g_object_ref (G_DESKTOP_APP_INFO (info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&cache->mutex);
|
||||
|
||||
return g_steal_pointer (&ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_cache_translate_folder:
|
||||
* @cache: (nullable): a #ShellAppCache or %NULL
|
||||
* @name: the folder name
|
||||
*
|
||||
* Gets the translated folder name for @name if any exists. Otherwise
|
||||
* a copy of @name is returned.
|
||||
*
|
||||
* Returns: the translated string
|
||||
*/
|
||||
char *
|
||||
shell_app_cache_translate_folder (ShellAppCache *cache,
|
||||
const char *name)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = shell_app_cache_get_default ();
|
||||
|
||||
g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
g_mutex_lock (&cache->mutex);
|
||||
ret = g_strdup (g_hash_table_lookup (cache->folders, name));
|
||||
g_mutex_unlock (&cache->mutex);
|
||||
|
||||
if (ret == NULL)
|
||||
ret = g_strdup (name);
|
||||
|
||||
return g_steal_pointer (&ret);
|
||||
}
|
19
src/shell-app-cache.h
Normal file
19
src/shell-app-cache.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_APP_CACHE__
|
||||
#define __SHELL_APP_CACHE__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
|
||||
#define SHELL_TYPE_APP_CACHE (shell_app_cache_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ShellAppCache, shell_app_cache, SHELL, APP_CACHE, GObject)
|
||||
|
||||
ShellAppCache *shell_app_cache_get_default (void);
|
||||
GList *shell_app_cache_get_all (ShellAppCache *cache);
|
||||
GDesktopAppInfo *shell_app_cache_get_info (ShellAppCache *cache,
|
||||
const char *id);
|
||||
char *shell_app_cache_translate_folder (ShellAppCache *cache,
|
||||
const char *name);
|
||||
|
||||
#endif /* __SHELL_APP_CACHE__ */
|
@@ -9,11 +9,20 @@
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "shell-app-cache.h"
|
||||
#include "shell-app-private.h"
|
||||
#include "shell-window-tracker-private.h"
|
||||
#include "shell-app-system-private.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-util.h"
|
||||
#include "st.h"
|
||||
|
||||
/* Rescan for at most RESCAN_TIMEOUT_MS * MAX_RESCAN_RETRIES. That
|
||||
* should be plenty of time for even a slow spinning drive to update
|
||||
* the icon cache.
|
||||
*/
|
||||
#define RESCAN_TIMEOUT_MS 2500
|
||||
#define MAX_RESCAN_RETRIES 6
|
||||
|
||||
/* Vendor prefixes are something that can be preprended to a .desktop
|
||||
* file name. Undo this.
|
||||
@@ -50,6 +59,9 @@ struct _ShellAppSystemPrivate {
|
||||
GHashTable *running_apps;
|
||||
GHashTable *id_to_app;
|
||||
GHashTable *startup_wm_class_to_id;
|
||||
|
||||
guint rescan_icons_timeout_id;
|
||||
guint n_rescan_retries;
|
||||
};
|
||||
|
||||
static void shell_app_system_finalize (GObject *object);
|
||||
@@ -82,12 +94,14 @@ static void
|
||||
scan_startup_wm_class_to_id (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv = self->priv;
|
||||
GList *apps, *l;
|
||||
g_autolist(GAppInfo) all = NULL;
|
||||
const GList *l;
|
||||
|
||||
g_hash_table_remove_all (priv->startup_wm_class_to_id);
|
||||
|
||||
apps = g_app_info_get_all ();
|
||||
for (l = apps; l != NULL; l = l->next)
|
||||
all = shell_app_cache_get_all (NULL);
|
||||
|
||||
for (l = all; l != NULL; l = l->next)
|
||||
{
|
||||
GAppInfo *info = l->data;
|
||||
const char *startup_wm_class, *id, *old_id;
|
||||
@@ -105,8 +119,6 @@ scan_startup_wm_class_to_id (ShellAppSystem *self)
|
||||
g_hash_table_insert (priv->startup_wm_class_to_id,
|
||||
g_strdup (startup_wm_class), g_strdup (id));
|
||||
}
|
||||
|
||||
g_list_free_full (apps, g_object_unref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -119,7 +131,7 @@ app_is_stale (ShellApp *app)
|
||||
if (shell_app_is_window_backed (app))
|
||||
return FALSE;
|
||||
|
||||
info = g_desktop_app_info_new (shell_app_get_id (app));
|
||||
info = shell_app_cache_get_info (NULL, shell_app_get_id (app));
|
||||
if (!info)
|
||||
return TRUE;
|
||||
|
||||
@@ -156,12 +168,52 @@ stale_app_remove_func (gpointer key,
|
||||
return app_is_stale (value);
|
||||
}
|
||||
|
||||
static void
|
||||
installed_changed (GAppInfoMonitor *monitor,
|
||||
gpointer user_data)
|
||||
static gboolean
|
||||
rescan_icon_theme_cb (gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = user_data;
|
||||
ShellAppSystemPrivate *priv;
|
||||
ShellAppSystem *self;
|
||||
StTextureCache *texture_cache;
|
||||
gboolean rescanned;
|
||||
|
||||
self = (ShellAppSystem *) user_data;
|
||||
priv = self->priv;
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
rescanned = st_texture_cache_rescan_icon_theme (texture_cache);
|
||||
|
||||
priv->n_rescan_retries++;
|
||||
|
||||
if (rescanned || priv->n_rescan_retries >= MAX_RESCAN_RETRIES)
|
||||
{
|
||||
priv->n_rescan_retries = 0;
|
||||
priv->rescan_icons_timeout_id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
rescan_icon_theme (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv = self->priv;
|
||||
|
||||
priv->n_rescan_retries = 0;
|
||||
|
||||
if (priv->rescan_icons_timeout_id > 0)
|
||||
return;
|
||||
|
||||
priv->rescan_icons_timeout_id = g_timeout_add (RESCAN_TIMEOUT_MS,
|
||||
rescan_icon_theme_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
installed_changed (ShellAppCache *cache,
|
||||
ShellAppSystem *self)
|
||||
{
|
||||
rescan_icon_theme (self);
|
||||
scan_startup_wm_class_to_id (self);
|
||||
|
||||
g_hash_table_foreach_remove (self->priv->id_to_app, stale_app_remove_func, NULL);
|
||||
@@ -173,7 +225,7 @@ static void
|
||||
shell_app_system_init (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv;
|
||||
GAppInfoMonitor *monitor;
|
||||
ShellAppCache *cache;
|
||||
|
||||
self->priv = priv = shell_app_system_get_instance_private (self);
|
||||
|
||||
@@ -184,9 +236,9 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
|
||||
priv->startup_wm_class_to_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
monitor = g_app_info_monitor_get ();
|
||||
g_signal_connect (monitor, "changed", G_CALLBACK (installed_changed), self);
|
||||
installed_changed (monitor, self);
|
||||
cache = shell_app_cache_get_default ();
|
||||
g_signal_connect (cache, "changed", G_CALLBACK (installed_changed), self);
|
||||
installed_changed (cache, self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -199,6 +251,9 @@ shell_app_system_finalize (GObject *object)
|
||||
g_hash_table_destroy (priv->id_to_app);
|
||||
g_hash_table_destroy (priv->startup_wm_class_to_id);
|
||||
|
||||
if (priv->rescan_icons_timeout_id)
|
||||
g_source_remove (priv->rescan_icons_timeout_id);
|
||||
|
||||
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -237,7 +292,7 @@ shell_app_system_lookup_app (ShellAppSystem *self,
|
||||
if (app)
|
||||
return app;
|
||||
|
||||
info = g_desktop_app_info_new (id);
|
||||
info = shell_app_cache_get_info (NULL, id);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
|
@@ -87,6 +87,8 @@ struct _ShellGlobal {
|
||||
/* For sound notifications */
|
||||
ca_context *sound_context;
|
||||
|
||||
GHashTable *save_ops;
|
||||
|
||||
gboolean has_modal;
|
||||
gboolean frame_timestamps;
|
||||
gboolean frame_finish_timestamp;
|
||||
@@ -322,6 +324,10 @@ shell_global_init (ShellGlobal *global)
|
||||
NULL);
|
||||
|
||||
g_strfreev (search_path);
|
||||
|
||||
global->save_ops = g_hash_table_new_full (g_file_hash,
|
||||
(GEqualFunc) g_file_equal,
|
||||
g_object_unref, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -341,6 +347,8 @@ shell_global_finalize (GObject *object)
|
||||
g_free (global->imagedir);
|
||||
g_free (global->userdatadir);
|
||||
|
||||
g_hash_table_unref (global->save_ops);
|
||||
|
||||
G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -1757,20 +1765,133 @@ shell_global_get_session_mode (ShellGlobal *global)
|
||||
}
|
||||
|
||||
static void
|
||||
save_variant (GFile *dir,
|
||||
const char *property_name,
|
||||
GVariant *variant)
|
||||
delete_variant_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellGlobal *global = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_file_delete_finish (G_FILE (object), result, &error))
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
g_warning ("Could not delete runtime/persistent state file: %s\n",
|
||||
error->message);
|
||||
}
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_hash_table_remove (global->save_ops, object);
|
||||
}
|
||||
|
||||
static void
|
||||
replace_contents_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
GFile *file = source_object;
|
||||
GBytes *bytes = task_data;
|
||||
GError *error = NULL;
|
||||
const gchar *data;
|
||||
gsize len;
|
||||
|
||||
data = g_bytes_get_data (bytes, &len);
|
||||
|
||||
if (!g_file_replace_contents (file, data, len, NULL, FALSE,
|
||||
G_FILE_CREATE_REPLACE_DESTINATION,
|
||||
NULL, cancellable, &error))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
replace_contents_async (GFile *path,
|
||||
GBytes *bytes,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_assert (G_IS_FILE (path));
|
||||
g_assert (bytes != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (path, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, replace_contents_async);
|
||||
g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
|
||||
g_task_run_in_thread (task, replace_contents_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
replace_contents_finish (GFile *file,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
replace_variant_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellGlobal *global = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!replace_contents_finish (G_FILE (object), result, &error))
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
g_warning ("Could not replace runtime/persistent state file: %s\n",
|
||||
error->message);
|
||||
}
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_hash_table_remove (global->save_ops, object);
|
||||
}
|
||||
|
||||
static void
|
||||
save_variant (ShellGlobal *global,
|
||||
GFile *dir,
|
||||
const char *property_name,
|
||||
GVariant *variant)
|
||||
{
|
||||
GFile *path = g_file_get_child (dir, property_name);
|
||||
GCancellable *cancellable;
|
||||
|
||||
cancellable = g_hash_table_lookup (global->save_ops, path);
|
||||
g_cancellable_cancel (cancellable);
|
||||
|
||||
cancellable = g_cancellable_new ();
|
||||
g_hash_table_insert (global->save_ops, g_object_ref (path), cancellable);
|
||||
|
||||
if (variant == NULL || g_variant_get_data (variant) == NULL)
|
||||
(void) g_file_delete (path, NULL, NULL);
|
||||
{
|
||||
g_file_delete_async (path, G_PRIORITY_DEFAULT, cancellable,
|
||||
delete_variant_cb, global);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsize size = g_variant_get_size (variant);
|
||||
g_file_replace_contents (path, g_variant_get_data (variant), size,
|
||||
NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
|
||||
NULL, NULL, NULL);
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
|
||||
bytes = g_bytes_new_with_free_func (g_variant_get_data (variant),
|
||||
g_variant_get_size (variant),
|
||||
(GDestroyNotify)g_variant_unref,
|
||||
g_variant_ref (variant));
|
||||
/* g_file_replace_contents_async() can potentially fsync() from the
|
||||
* calling thread when completing the asynchronous task. Instead, we
|
||||
* want to force that fsync() to a thread to avoid blocking the
|
||||
* compositor main loop. Using our own replace_contents_async()
|
||||
* simply executes the operation synchronously from a thread.
|
||||
*/
|
||||
replace_contents_async (path, bytes, cancellable, replace_variant_cb, global);
|
||||
}
|
||||
|
||||
g_object_unref (path);
|
||||
@@ -1824,7 +1945,7 @@ shell_global_set_runtime_state (ShellGlobal *global,
|
||||
const char *property_name,
|
||||
GVariant *variant)
|
||||
{
|
||||
save_variant (global->runtime_state_path, property_name, variant);
|
||||
save_variant (global, global->runtime_state_path, property_name, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1859,7 +1980,7 @@ shell_global_set_persistent_state (ShellGlobal *global,
|
||||
const char *property_name,
|
||||
GVariant *variant)
|
||||
{
|
||||
save_variant (global->userdatadir_path, property_name, variant);
|
||||
save_variant (global, global->userdatadir_path, property_name, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -205,7 +205,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_UPPER,
|
||||
g_param_spec_double ("upper",
|
||||
@@ -215,7 +216,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VALUE,
|
||||
g_param_spec_double ("value",
|
||||
@@ -225,7 +227,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_STEP_INC,
|
||||
g_param_spec_double ("step-increment",
|
||||
@@ -235,7 +238,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PAGE_INC,
|
||||
g_param_spec_double ("page-increment",
|
||||
@@ -245,7 +249,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PAGE_SIZE,
|
||||
g_param_spec_double ("page-size",
|
||||
@@ -255,7 +260,8 @@ st_adjustment_class_init (StAdjustmentClass *klass)
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_EXPLICIT_NOTIFY));
|
||||
/**
|
||||
* StAdjustment::changed:
|
||||
* @self: the #StAdjustment
|
||||
|
@@ -177,15 +177,15 @@ st_bin_get_preferred_height (ClutterActor *self,
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_dispose (GObject *gobject)
|
||||
st_bin_destroy (ClutterActor *actor)
|
||||
{
|
||||
StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (gobject));
|
||||
StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (actor));
|
||||
|
||||
if (priv->child)
|
||||
clutter_actor_destroy (priv->child);
|
||||
g_assert (priv->child == NULL);
|
||||
|
||||
G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject);
|
||||
CLUTTER_ACTOR_CLASS (st_bin_parent_class)->destroy (actor);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -315,11 +315,11 @@ st_bin_class_init (StBinClass *klass)
|
||||
|
||||
gobject_class->set_property = st_bin_set_property;
|
||||
gobject_class->get_property = st_bin_get_property;
|
||||
gobject_class->dispose = st_bin_dispose;
|
||||
|
||||
actor_class->get_preferred_width = st_bin_get_preferred_width;
|
||||
actor_class->get_preferred_height = st_bin_get_preferred_height;
|
||||
actor_class->allocate = st_bin_allocate;
|
||||
actor_class->destroy = st_bin_destroy;
|
||||
|
||||
widget_class->popup_menu = st_bin_popup_menu;
|
||||
widget_class->navigate_focus = st_bin_navigate_focus;
|
||||
|
@@ -90,7 +90,7 @@ adjustment_value_notify_cb (StAdjustment *adjustment,
|
||||
GParamSpec *pspec,
|
||||
StBoxLayout *box)
|
||||
{
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (box));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -490,7 +490,7 @@ st_box_layout_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
StBoxLayout *self = ST_BOX_LAYOUT (actor);
|
||||
gdouble x, y;
|
||||
gdouble x, y, lower, upper;
|
||||
StBoxLayoutPrivate *priv = self->priv;
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
ClutterActorBox allocation_box;
|
||||
@@ -505,13 +505,42 @@ st_box_layout_get_paint_volume (ClutterActor *actor,
|
||||
* our paint volume on that. */
|
||||
if (priv->hadjustment || priv->vadjustment)
|
||||
{
|
||||
gdouble width, height;
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &allocation_box);
|
||||
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
|
||||
origin.x = content_box.x1 - allocation_box.x1;
|
||||
origin.y = content_box.y1 - allocation_box.y2;
|
||||
origin.z = 0.f;
|
||||
clutter_paint_volume_set_width (volume, content_box.x2 - content_box.x1);
|
||||
clutter_paint_volume_set_height (volume, content_box.y2 - content_box.y1);
|
||||
|
||||
if (priv->hadjustment)
|
||||
{
|
||||
g_object_get (priv->hadjustment,
|
||||
"lower", &lower,
|
||||
"upper", &upper,
|
||||
NULL);
|
||||
width = upper - lower;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = content_box.x2 - content_box.x1;
|
||||
}
|
||||
|
||||
if (priv->vadjustment)
|
||||
{
|
||||
g_object_get (priv->vadjustment,
|
||||
"lower", &lower,
|
||||
"upper", &upper,
|
||||
NULL);
|
||||
height = upper - lower;
|
||||
}
|
||||
else
|
||||
{
|
||||
height = content_box.y2 - content_box.y1;
|
||||
}
|
||||
|
||||
clutter_paint_volume_set_width (volume, width);
|
||||
clutter_paint_volume_set_height (volume, height);
|
||||
}
|
||||
else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume))
|
||||
return FALSE;
|
||||
|
@@ -248,14 +248,17 @@ st_button_touch_event (ClutterActor *actor,
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN && !priv->press_sequence)
|
||||
{
|
||||
clutter_input_device_sequence_grab (device, sequence, actor);
|
||||
st_button_press (button, device, 0, sequence);
|
||||
if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event))
|
||||
st_button_press (button, device, 0, sequence);
|
||||
return CLUTTER_EVENT_STOP;
|
||||
}
|
||||
else if (event->type == CLUTTER_TOUCH_END &&
|
||||
priv->device == device &&
|
||||
priv->press_sequence == sequence)
|
||||
{
|
||||
st_button_release (button, device, mask, 0, sequence);
|
||||
if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event))
|
||||
st_button_release (button, device, mask, 0, sequence);
|
||||
|
||||
clutter_input_device_sequence_ungrab (device, sequence);
|
||||
return CLUTTER_EVENT_STOP;
|
||||
}
|
||||
|
@@ -906,6 +906,13 @@ st_entry_unmap (ClutterActor *actor)
|
||||
CLUTTER_ACTOR_CLASS (st_entry_parent_class)->unmap (actor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_entry_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
return clutter_paint_volume_set_from_allocation (volume, actor);
|
||||
}
|
||||
|
||||
static void
|
||||
st_entry_class_init (StEntryClass *klass)
|
||||
{
|
||||
@@ -923,6 +930,7 @@ st_entry_class_init (StEntryClass *klass)
|
||||
actor_class->allocate = st_entry_allocate;
|
||||
actor_class->paint = st_entry_paint;
|
||||
actor_class->unmap = st_entry_unmap;
|
||||
actor_class->get_paint_volume = st_entry_get_paint_volume;
|
||||
|
||||
actor_class->key_press_event = st_entry_key_press_event;
|
||||
actor_class->key_focus_in = st_entry_key_focus_in;
|
||||
@@ -1287,10 +1295,10 @@ st_entry_get_input_hints (StEntry *entry)
|
||||
return clutter_text_get_input_hints (CLUTTER_TEXT (priv->entry));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_st_entry_icon_press_cb (ClutterActor *actor,
|
||||
ClutterButtonEvent *event,
|
||||
StEntry *entry)
|
||||
static void
|
||||
_st_entry_icon_clicked_cb (ClutterClickAction *action,
|
||||
ClutterActor *actor,
|
||||
StEntry *entry)
|
||||
{
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
||||
|
||||
@@ -1298,8 +1306,6 @@ _st_entry_icon_press_cb (ClutterActor *actor,
|
||||
g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0);
|
||||
else
|
||||
g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1309,21 +1315,24 @@ _st_entry_set_icon (StEntry *entry,
|
||||
{
|
||||
if (*icon)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (*icon,
|
||||
_st_entry_icon_press_cb,
|
||||
entry);
|
||||
clutter_actor_remove_action_by_name (*icon, "entry-icon-action");
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (entry), *icon);
|
||||
*icon = NULL;
|
||||
}
|
||||
|
||||
if (new_icon)
|
||||
{
|
||||
ClutterAction *action;
|
||||
|
||||
*icon = g_object_ref (new_icon);
|
||||
|
||||
clutter_actor_set_reactive (*icon, TRUE);
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (entry), *icon);
|
||||
g_signal_connect (*icon, "button-release-event",
|
||||
G_CALLBACK (_st_entry_icon_press_cb), entry);
|
||||
|
||||
action = clutter_click_action_new ();
|
||||
clutter_actor_add_action_with_name (*icon, "entry-icon-action", action);
|
||||
g_signal_connect (action, "clicked",
|
||||
G_CALLBACK (_st_entry_icon_clicked_cb), entry);
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (entry));
|
||||
|
@@ -304,6 +304,13 @@ st_scroll_view_pick (ClutterActor *actor,
|
||||
clutter_actor_paint (priv->vscroll);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_scroll_view_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
return clutter_paint_volume_set_from_allocation (volume, actor);
|
||||
}
|
||||
|
||||
static double
|
||||
get_scrollbar_width (StScrollView *scroll,
|
||||
gfloat for_height)
|
||||
@@ -793,6 +800,7 @@ st_scroll_view_class_init (StScrollViewClass *klass)
|
||||
|
||||
actor_class->paint = st_scroll_view_paint;
|
||||
actor_class->pick = st_scroll_view_pick;
|
||||
actor_class->get_paint_volume = st_scroll_view_get_paint_volume;
|
||||
actor_class->get_preferred_width = st_scroll_view_get_preferred_width;
|
||||
actor_class->get_preferred_height = st_scroll_view_get_preferred_height;
|
||||
actor_class->allocate = st_scroll_view_allocate;
|
||||
|
@@ -780,13 +780,13 @@ st_texture_cache_load (StTextureCache *cache,
|
||||
if (!texture)
|
||||
{
|
||||
texture = load (cache, key, data, error);
|
||||
if (texture)
|
||||
if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
|
||||
g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texture);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cogl_object_ref (texture);
|
||||
if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
|
||||
cogl_object_ref (texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -984,7 +984,7 @@ file_changed_cb (GFileMonitor *monitor,
|
||||
char *key;
|
||||
guint file_hash;
|
||||
|
||||
if (event_type != G_FILE_MONITOR_EVENT_CHANGED)
|
||||
if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
|
||||
return;
|
||||
|
||||
file_hash = g_file_hash (file);
|
||||
@@ -1425,3 +1425,11 @@ st_texture_cache_get_default (void)
|
||||
instance = g_object_new (ST_TYPE_TEXTURE_CACHE, NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
gboolean
|
||||
st_texture_cache_rescan_icon_theme (StTextureCache *cache)
|
||||
{
|
||||
StTextureCachePrivate *priv = cache->priv;
|
||||
|
||||
return gtk_icon_theme_rescan_if_needed (priv->icon_theme);
|
||||
}
|
||||
|
@@ -106,4 +106,6 @@ CoglTexture * st_texture_cache_load (StTextureCache *cache,
|
||||
void *data,
|
||||
GError **error);
|
||||
|
||||
gboolean st_texture_cache_rescan_icon_theme (StTextureCache *cache);
|
||||
|
||||
#endif /* __ST_TEXTURE_CACHE_H__ */
|
||||
|
@@ -229,9 +229,9 @@ unpremultiply (ClutterColor *color)
|
||||
{
|
||||
if (color->alpha != 0)
|
||||
{
|
||||
color->red = (color->red * 255 + 127) / color->alpha;
|
||||
color->green = (color->green * 255 + 127) / color->alpha;
|
||||
color->blue = (color->blue * 255 + 127) / color->alpha;
|
||||
color->red = MIN((color->red * 255 + 127) / color->alpha, 255);
|
||||
color->green = MIN((color->green * 255 + 127) / color->alpha, 255);
|
||||
color->blue = MIN((color->blue * 255 + 127) / color->alpha, 255);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ st_theme_node_lookup_corner (StThemeNode *node,
|
||||
return COGL_INVALID_HANDLE;
|
||||
|
||||
key = corner_to_string (&corner);
|
||||
texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &corner, NULL);
|
||||
texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_FOREVER, load_corner, &corner, NULL);
|
||||
|
||||
if (texture)
|
||||
{
|
||||
@@ -1414,6 +1414,32 @@ st_theme_node_load_background_image (StThemeNode *node)
|
||||
return node->background_texture != COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_theme_node_invalidate_resources_for_file (StThemeNode *node,
|
||||
GFile *file)
|
||||
{
|
||||
StBorderImage *border_image;
|
||||
gboolean changed = FALSE;
|
||||
GFile *theme_file;
|
||||
|
||||
theme_file = st_theme_node_get_background_image (node);
|
||||
if ((theme_file != NULL) && g_file_equal (theme_file, file))
|
||||
{
|
||||
st_theme_node_invalidate_background_image (node);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
theme_file = border_image ? st_border_image_get_file (border_image) : NULL;
|
||||
if ((theme_file != NULL) && g_file_equal (theme_file, file))
|
||||
{
|
||||
st_theme_node_invalidate_border_image (node);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void st_theme_node_prerender_shadow (StThemeNodePaintState *state);
|
||||
|
||||
static void
|
||||
@@ -2751,3 +2777,17 @@ st_theme_node_paint_state_invalidate (StThemeNodePaintState *state)
|
||||
state->alloc_width = 0;
|
||||
state->alloc_height = 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state,
|
||||
GFile *file)
|
||||
{
|
||||
if (state->node != NULL &&
|
||||
st_theme_node_invalidate_resources_for_file (state->node, file))
|
||||
{
|
||||
st_theme_node_paint_state_invalidate (state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -287,6 +287,9 @@ void st_theme_node_paint_state_free (StThemeNodePaintState *state);
|
||||
void st_theme_node_paint_state_copy (StThemeNodePaintState *state,
|
||||
StThemeNodePaintState *other);
|
||||
void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state);
|
||||
gboolean st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state,
|
||||
GFile *file);
|
||||
|
||||
void st_theme_node_paint_state_set_node (StThemeNodePaintState *state,
|
||||
StThemeNode *node);
|
||||
|
||||
|
@@ -289,44 +289,17 @@ st_widget_texture_cache_changed (StTextureCache *cache,
|
||||
{
|
||||
StWidget *actor = ST_WIDGET (user_data);
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (actor);
|
||||
StThemeNode *node = priv->theme_node;
|
||||
StBorderImage *border_image;
|
||||
gboolean changed = FALSE;
|
||||
GFile *theme_file;
|
||||
int i;
|
||||
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
theme_file = st_theme_node_get_background_image (node);
|
||||
if ((theme_file != NULL) && g_file_equal (theme_file, file))
|
||||
for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
|
||||
{
|
||||
st_theme_node_invalidate_background_image (node);
|
||||
changed = TRUE;
|
||||
StThemeNodePaintState *paint_state = &priv->paint_states[i];
|
||||
changed |= st_theme_node_paint_state_invalidate_for_file (paint_state, file);
|
||||
}
|
||||
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
theme_file = border_image ? st_border_image_get_file (border_image) : NULL;
|
||||
if ((theme_file != NULL) && g_file_equal (theme_file, file))
|
||||
{
|
||||
st_theme_node_invalidate_border_image (node);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
/* If we prerender the background / border, we need to update
|
||||
* the paint state. We should probably implement a method to
|
||||
* the theme node to determine this, but for now, just wipe
|
||||
* the entire paint state.
|
||||
*
|
||||
* Use the existing state instead of a new one because it's
|
||||
* assumed the rest of the state will stay the same.
|
||||
*/
|
||||
st_theme_node_paint_state_invalidate (current_paint_state (actor));
|
||||
|
||||
if (clutter_actor_is_mapped (CLUTTER_ACTOR (actor)))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
|
||||
}
|
||||
if (changed && clutter_actor_is_mapped (CLUTTER_ACTOR (actor)))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
|
||||
}
|
||||
|
||||
static void
|
||||
|
Reference in New Issue
Block a user