Compare commits
1326 Commits
METACITY_2
...
METACITY_2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
91c8674acf | ||
![]() |
a50c7cd589 | ||
![]() |
3a7ce7d109 | ||
![]() |
9ef1da6ec2 | ||
![]() |
cd1885cec4 | ||
![]() |
27797e7f78 | ||
![]() |
0de86fc8ea | ||
![]() |
c0452be980 | ||
![]() |
963ac3ff32 | ||
![]() |
f3cc59c78a | ||
![]() |
56609cbb39 | ||
![]() |
16a8add6f8 | ||
![]() |
036a61d198 | ||
![]() |
9739346c85 | ||
![]() |
47e6bd5648 | ||
![]() |
502003e47b | ||
![]() |
57b16ab4c7 | ||
![]() |
83480c1ac9 | ||
![]() |
db108c1fc3 | ||
![]() |
5a28c4c423 | ||
![]() |
f1701a751f | ||
![]() |
ad65847d7d | ||
![]() |
88ea02a77a | ||
![]() |
b70fdf1a5f | ||
![]() |
2195dfc9f8 | ||
![]() |
27eb5a60f3 | ||
![]() |
339719568f | ||
![]() |
fd13022dc4 | ||
![]() |
d53afd3ae1 | ||
![]() |
57f9a51a58 | ||
![]() |
799f3274d9 | ||
![]() |
a788bee6f9 | ||
![]() |
0a83c10948 | ||
![]() |
dfa9c24b87 | ||
![]() |
7bf8eee605 | ||
![]() |
664216dc8b | ||
![]() |
b3f95bf7d1 | ||
![]() |
f2e783b2c5 | ||
![]() |
e68b1b6c42 | ||
![]() |
217ba6c1b7 | ||
![]() |
74a8b5b78b | ||
![]() |
81fab83067 | ||
![]() |
0f23f3f05b | ||
![]() |
4b3b706369 | ||
![]() |
595cbe2ac0 | ||
![]() |
b20391780d | ||
![]() |
dd8e9e5725 | ||
![]() |
007a1f0d0d | ||
![]() |
40a710dad0 | ||
![]() |
6770329e69 | ||
![]() |
4f448440d4 | ||
![]() |
039ffb0cb4 | ||
![]() |
2f561e5553 | ||
![]() |
2d314d84cd | ||
![]() |
3b7f92ae5d | ||
![]() |
4f7e28ff3c | ||
![]() |
47cf3085e7 | ||
![]() |
3d996ff73d | ||
![]() |
1b7a651a33 | ||
![]() |
a605da04c1 | ||
![]() |
cc7195547a | ||
![]() |
c820769bce | ||
![]() |
b2d009d01d | ||
![]() |
fe8abfa887 | ||
![]() |
2fdb75ad45 | ||
![]() |
07c0a53316 | ||
![]() |
e5cf7ff55b | ||
![]() |
3c1fe8bedd | ||
![]() |
88aeeb8cd5 | ||
![]() |
1b323f87d7 | ||
![]() |
2d74e25058 | ||
![]() |
98e882720c | ||
![]() |
93c5a042ee | ||
![]() |
99d7cadf67 | ||
![]() |
0e3ecc7a31 | ||
![]() |
c635a55612 | ||
![]() |
5a088c5bbc | ||
![]() |
a27089a110 | ||
![]() |
35c64b45dd | ||
![]() |
daf93c5ed0 | ||
![]() |
56d75ebf44 | ||
![]() |
5815ebd3a4 | ||
![]() |
78f925c6a6 | ||
![]() |
1115e22481 | ||
![]() |
c2ba0a7d67 | ||
![]() |
e699ff2e83 | ||
![]() |
804411bd68 | ||
![]() |
690100f1ad | ||
![]() |
95b0ee480e | ||
![]() |
4be245a26a | ||
![]() |
a0863fc437 | ||
![]() |
c9f0005b05 | ||
![]() |
104786735a | ||
![]() |
191b3f2c21 | ||
![]() |
860ae37db5 | ||
![]() |
9bde925d3d | ||
![]() |
7630d22b8d | ||
![]() |
a92be6e319 | ||
![]() |
0bb3361b73 | ||
![]() |
b1c1e4a7db | ||
![]() |
82673cb51f | ||
![]() |
4ebdb0b9c0 | ||
![]() |
4c5e4442c1 | ||
![]() |
01fa9cfc63 | ||
![]() |
6ff017e875 | ||
![]() |
8d892f76da | ||
![]() |
03bbe3de17 | ||
![]() |
47a1c285c7 | ||
![]() |
4ccb120922 | ||
![]() |
423b5f5f39 | ||
![]() |
feefcdd892 | ||
![]() |
927a6def1b | ||
![]() |
d538690bd4 | ||
![]() |
24d8655188 | ||
![]() |
917dfefd6c | ||
![]() |
9378a4fb4d | ||
![]() |
67c36f0917 | ||
![]() |
d5083baea0 | ||
![]() |
6a0f4f6ccb | ||
![]() |
901ad18a67 | ||
![]() |
6ac67f80a6 | ||
![]() |
a88f44ea64 | ||
![]() |
5c10e0a859 | ||
![]() |
3c384d37c6 | ||
![]() |
2592efeee4 | ||
![]() |
66b2e8bc3f | ||
![]() |
17dc2d6151 | ||
![]() |
2218b79143 | ||
![]() |
17b8a1f3e6 | ||
![]() |
830a52ee25 | ||
![]() |
18b38ac526 | ||
![]() |
8658268847 | ||
![]() |
8a271ee5ac | ||
![]() |
cf15ea0a3d | ||
![]() |
669cdc4bb6 | ||
![]() |
68d6a92972 | ||
![]() |
4770da34b3 | ||
![]() |
9197c4f835 | ||
![]() |
6aff3466c6 | ||
![]() |
e98fad3e62 | ||
![]() |
6628acb59c | ||
![]() |
d76d953d69 | ||
![]() |
e9358b5eea | ||
![]() |
6d7d586f3c | ||
![]() |
481accd6bd | ||
![]() |
2a97ddd60a | ||
![]() |
8441fada07 | ||
![]() |
a60b735e2d | ||
![]() |
199d20197e | ||
![]() |
5fdb8ab7d6 | ||
![]() |
7c80b0a335 | ||
![]() |
7eb5a67b3d | ||
![]() |
37640a925e | ||
![]() |
c446955b8d | ||
![]() |
0895abd894 | ||
![]() |
f7c04aff1e | ||
![]() |
89ca4aab3d | ||
![]() |
a4dc0d581a | ||
![]() |
a889ff3469 | ||
![]() |
320ef83bfc | ||
![]() |
8849fad8f9 | ||
![]() |
9839087306 | ||
![]() |
d31e28be70 | ||
![]() |
26c2ae81ea | ||
![]() |
922932d240 | ||
![]() |
28fbdc611e | ||
![]() |
99c7dc8b85 | ||
![]() |
ef0816bdce | ||
![]() |
e99ebf6ef0 | ||
![]() |
ef44f8066b | ||
![]() |
47d5189812 | ||
![]() |
d71ef42ded | ||
![]() |
e37091654f | ||
![]() |
dcd097d67e | ||
![]() |
b5261cdbda | ||
![]() |
dc40522ea7 | ||
![]() |
de44b2d794 | ||
![]() |
1117d45f8a | ||
![]() |
294cc23179 | ||
![]() |
bd74d85560 | ||
![]() |
3a119e13db | ||
![]() |
b413f5e7e0 | ||
![]() |
d75b9158bd | ||
![]() |
b5b127f083 | ||
![]() |
1206f9880e | ||
![]() |
629af6bb36 | ||
![]() |
08ca40aad9 | ||
![]() |
fa4c0bf54a | ||
![]() |
01f94925a5 | ||
![]() |
ae83b19b28 | ||
![]() |
9cdbfc53a8 | ||
![]() |
a13dbea266 | ||
![]() |
a236cfd7a8 | ||
![]() |
27b4e46a16 | ||
![]() |
9ddacb019e | ||
![]() |
a4a32a54c3 | ||
![]() |
8ff2a10c96 | ||
![]() |
586eda6199 | ||
![]() |
a522c3479e | ||
![]() |
e5a2ddd777 | ||
![]() |
77fb995c4c | ||
![]() |
0494e221af | ||
![]() |
6e77b6f656 | ||
![]() |
dbcf03535d | ||
![]() |
a644753073 | ||
![]() |
23b5ea0eee | ||
![]() |
a2b6ff6d42 | ||
![]() |
5ea067a1d8 | ||
![]() |
8b924ece14 | ||
![]() |
9615538389 | ||
![]() |
9c53e2f5f1 | ||
![]() |
81da59a8a4 | ||
![]() |
22eab481b1 | ||
![]() |
71cd8948d2 | ||
![]() |
288e10f7fe | ||
![]() |
a9e5560c36 | ||
![]() |
fcd56c3ef0 | ||
![]() |
7dc793c3be | ||
![]() |
2fc880db19 | ||
![]() |
60a453f5a0 | ||
![]() |
32a587e4a3 | ||
![]() |
8deed5d601 | ||
![]() |
f8b4a391e3 | ||
![]() |
2f3ed8ab65 | ||
![]() |
306fc4ee61 | ||
![]() |
5200e59ba3 | ||
![]() |
d06dee2778 | ||
![]() |
19105eedb2 | ||
![]() |
a252050cb8 | ||
![]() |
435bf3f2e4 | ||
![]() |
1fcd5e9704 | ||
![]() |
5188e9c4d0 | ||
![]() |
1d57293511 | ||
![]() |
ebbc388205 | ||
![]() |
fb5f3f6bb0 | ||
![]() |
5558451c11 | ||
![]() |
5727235572 | ||
![]() |
74fa2a7ab2 | ||
![]() |
e49cc883bb | ||
![]() |
3b54d71058 | ||
![]() |
2a90c0225d | ||
![]() |
f7e42bc4c4 | ||
![]() |
2ffc505c19 | ||
![]() |
154da1f68a | ||
![]() |
b45a357652 | ||
![]() |
7962cfa83e | ||
![]() |
2d89ba9c87 | ||
![]() |
00672554ed | ||
![]() |
f2c0ff8979 | ||
![]() |
dc52a32aad | ||
![]() |
bd779534af | ||
![]() |
cf0bd5bdc1 | ||
![]() |
5dcc25693a | ||
![]() |
1443f06471 | ||
![]() |
63a6f2121e | ||
![]() |
68fca2e5e5 | ||
![]() |
42182cbe77 | ||
![]() |
d08fa29612 | ||
![]() |
311f435120 | ||
![]() |
788ea66b1f | ||
![]() |
fa075eb8f1 | ||
![]() |
e1102bc6ff | ||
![]() |
f92eadf9d6 | ||
![]() |
34ec58af0a | ||
![]() |
b6389fbf60 | ||
![]() |
e26992e419 | ||
![]() |
40ea74f46c | ||
![]() |
971f3f1207 | ||
![]() |
3a39036dcb | ||
![]() |
3428ed1adf | ||
![]() |
81e4cb44aa | ||
![]() |
acb625ddeb | ||
![]() |
44508380dc | ||
![]() |
4d8414acfd | ||
![]() |
70d0446190 | ||
![]() |
793a630e2f | ||
![]() |
2936391fc8 | ||
![]() |
85826d0d9a | ||
![]() |
0a20419628 | ||
![]() |
2d4503ee59 | ||
![]() |
010e620a34 | ||
![]() |
3f6bad087d | ||
![]() |
c523d2827c | ||
![]() |
a53fea96ab | ||
![]() |
0bb8538e2f | ||
![]() |
03b3e98a51 | ||
![]() |
e0963e6b66 | ||
![]() |
6262db51a2 | ||
![]() |
58df4ee985 | ||
![]() |
85abc9bfe7 | ||
![]() |
993c7075f3 | ||
![]() |
4469a42a77 | ||
![]() |
bf965f8465 | ||
![]() |
f87a8c212f | ||
![]() |
3663ba0259 | ||
![]() |
b9900681e7 | ||
![]() |
3edad8599c | ||
![]() |
903f3d7e6e | ||
![]() |
051e404d09 | ||
![]() |
d1a853557b | ||
![]() |
f441033959 | ||
![]() |
0fa4954c46 | ||
![]() |
59958b0f0a | ||
![]() |
4549e42480 | ||
![]() |
1620fd5408 | ||
![]() |
1d692936e0 | ||
![]() |
6153a17a64 | ||
![]() |
b77590ba7a | ||
![]() |
c9df553d02 | ||
![]() |
967ac0f1d9 | ||
![]() |
ebf2c77c50 | ||
![]() |
c370a3e503 | ||
![]() |
9e2608524d | ||
![]() |
7fc6c99987 | ||
![]() |
3ad5618596 | ||
![]() |
4b02b0ddf1 | ||
![]() |
1ac3f938de | ||
![]() |
b422d86256 | ||
![]() |
8ac4e04e12 | ||
![]() |
d05cfba523 | ||
![]() |
6f458fc9d6 | ||
![]() |
a0d8c3c703 | ||
![]() |
11ee26bb65 | ||
![]() |
96e20f83bb | ||
![]() |
e841a492c8 | ||
![]() |
d93b0d319c | ||
![]() |
a7c344bbc5 | ||
![]() |
f64a231620 | ||
![]() |
a8f9e2e919 | ||
![]() |
9569096991 | ||
![]() |
2722c277ee | ||
![]() |
2eec8daff5 | ||
![]() |
75fa56391d | ||
![]() |
ec9cf27a81 | ||
![]() |
0996da5e8e | ||
![]() |
a8708e1c55 | ||
![]() |
7c5e40e0ea | ||
![]() |
e1d2b95459 | ||
![]() |
9bd17f4fae | ||
![]() |
40ec58787f | ||
![]() |
304fae9369 | ||
![]() |
72a7f57e5d | ||
![]() |
0fee2ac499 | ||
![]() |
708a86cfee | ||
![]() |
04fcad7c13 | ||
![]() |
ebbc4c499b | ||
![]() |
3c8b051e31 | ||
![]() |
d34e54785d | ||
![]() |
51e74d4027 | ||
![]() |
2d662f67a5 | ||
![]() |
67cbbeb6c1 | ||
![]() |
cc7493cac9 | ||
![]() |
be96be95f6 | ||
![]() |
6b144cd2eb | ||
![]() |
38412b4460 | ||
![]() |
b8287d3aca | ||
![]() |
5eb4eea57e | ||
![]() |
af3b5b77b1 | ||
![]() |
5f75334d57 | ||
![]() |
4481be72d1 | ||
![]() |
c595a7ac0f | ||
![]() |
fa3de81741 | ||
![]() |
6094763def | ||
![]() |
4e96dd7ea6 | ||
![]() |
6e6e85632a | ||
![]() |
6af9a11361 | ||
![]() |
8377c7776c | ||
![]() |
73cce3b174 | ||
![]() |
947adb6d07 | ||
![]() |
d0f1f084e8 | ||
![]() |
c27d89218c | ||
![]() |
15c5ddbec4 | ||
![]() |
546679cbd1 | ||
![]() |
b54c422b93 | ||
![]() |
5049fdc13a | ||
![]() |
d8bb7c8ae9 | ||
![]() |
61d5423b5d | ||
![]() |
d85012ecfd | ||
![]() |
fb9ad1eb13 | ||
![]() |
8764b89942 | ||
![]() |
48bc82e82f | ||
![]() |
e8d63890fc | ||
![]() |
6ed08019c2 | ||
![]() |
00d6f549f9 | ||
![]() |
02a491c1bc | ||
![]() |
ed25155fc1 | ||
![]() |
e65a70ded9 | ||
![]() |
3b49b81ff5 | ||
![]() |
bdcc6cb20d | ||
![]() |
e616f930d3 | ||
![]() |
536d51183c | ||
![]() |
6a3c1fbe57 | ||
![]() |
2cca0f0eac | ||
![]() |
cdb4e2541c | ||
![]() |
9b03b75aaf | ||
![]() |
f5072b7f3a | ||
![]() |
b60bb724aa | ||
![]() |
7d7f8aab93 | ||
![]() |
3b133195fd | ||
![]() |
18990530b0 | ||
![]() |
b424364710 | ||
![]() |
4fb05e54ab | ||
![]() |
3ee5ad8b12 | ||
![]() |
b73ea5eb0a | ||
![]() |
e710d9f1b8 | ||
![]() |
ae07c8677d | ||
![]() |
2a24562f45 | ||
![]() |
b7d27d9114 | ||
![]() |
5169a06dd0 | ||
![]() |
e868a001f9 | ||
![]() |
a8526454b0 | ||
![]() |
fabc5507f3 | ||
![]() |
82bd20911c | ||
![]() |
95d747269b | ||
![]() |
d02dbd62e9 | ||
![]() |
bcb9de9198 | ||
![]() |
3558657e53 | ||
![]() |
1187edeadb | ||
![]() |
0c684c6f35 | ||
![]() |
c1b863ee75 | ||
![]() |
8922b0ecc6 | ||
![]() |
6cd916ea39 | ||
![]() |
4b18f64914 | ||
![]() |
1e6a8a31d1 | ||
![]() |
9e7a26500c | ||
![]() |
5d862ac29b | ||
![]() |
25b9a9e37d | ||
![]() |
da7918554e | ||
![]() |
e45eda148b | ||
![]() |
b24308eab1 | ||
![]() |
366399eb0c | ||
![]() |
25615f929e | ||
![]() |
667a056066 | ||
![]() |
c2fbb37c8c | ||
![]() |
45269e0e2d | ||
![]() |
8f7eda43a8 | ||
![]() |
339a86150b | ||
![]() |
374e5d400d | ||
![]() |
0e5727eeb3 | ||
![]() |
9073724c2b | ||
![]() |
92c8ba0497 | ||
![]() |
efb26cb769 | ||
![]() |
050e55c9d7 | ||
![]() |
e402f41b33 | ||
![]() |
859c1e752d | ||
![]() |
198398ba88 | ||
![]() |
5d2f307735 | ||
![]() |
70bd23278b | ||
![]() |
76bfdcf038 | ||
![]() |
8e14da1759 | ||
![]() |
24ecc29f49 | ||
![]() |
4a23782f51 | ||
![]() |
b619f9baa8 | ||
![]() |
878d6df404 | ||
![]() |
5e5ebc7914 | ||
![]() |
e2155c8fee | ||
![]() |
036747fba5 | ||
![]() |
a8f93c454a | ||
![]() |
aad72e575d | ||
![]() |
b799630ba5 | ||
![]() |
90748385c2 | ||
![]() |
1d22cb8518 | ||
![]() |
4832cc6d63 | ||
![]() |
f8226bf1bb | ||
![]() |
6cfcc01334 | ||
![]() |
f8b2f6ca5c | ||
![]() |
d9a2207ebe | ||
![]() |
1be097628f | ||
![]() |
c51a55b0e5 | ||
![]() |
f88852cff6 | ||
![]() |
8d266f5550 | ||
![]() |
b9e86197f2 | ||
![]() |
b9e4faa1aa | ||
![]() |
625b7a25b0 | ||
![]() |
0e6b393896 | ||
![]() |
109761e973 | ||
![]() |
fd5557f44c | ||
![]() |
79d28b4709 | ||
![]() |
5cf84e6702 | ||
![]() |
f218216a2c | ||
![]() |
5f99b61f07 | ||
![]() |
a5fa06ebb1 | ||
![]() |
a0d3c8e20b | ||
![]() |
1ece207400 | ||
![]() |
91641c2cf3 | ||
![]() |
4045ee474d | ||
![]() |
e3b364c055 | ||
![]() |
89c31c43ca | ||
![]() |
0d1e643e1c | ||
![]() |
f6b4f11ebe | ||
![]() |
908198c25d | ||
![]() |
f4cb740aac | ||
![]() |
a2d0235d68 | ||
![]() |
bda692174a | ||
![]() |
e7e47a8b85 | ||
![]() |
32a8bf50b7 | ||
![]() |
b0818f97f2 | ||
![]() |
ea45e43082 | ||
![]() |
1ad94dec1c | ||
![]() |
995aef2577 | ||
![]() |
5817e204b4 | ||
![]() |
50b5a2b8d8 | ||
![]() |
8a9a4aba77 | ||
![]() |
4ad2d1a048 | ||
![]() |
07296490b4 | ||
![]() |
d3b2764ff6 | ||
![]() |
6c51b8ae6a | ||
![]() |
4fdc3667a3 | ||
![]() |
fd8c3514d6 | ||
![]() |
c2700863ca | ||
![]() |
18d32248ab | ||
![]() |
d8a59d7cd1 | ||
![]() |
4213beea4b | ||
![]() |
967777b965 | ||
![]() |
ba18c630b7 | ||
![]() |
a70fc3259f | ||
![]() |
094df1295c | ||
![]() |
8db78742c3 | ||
![]() |
9c337d0a8f | ||
![]() |
e0c8b245ef | ||
![]() |
8d314aead8 | ||
![]() |
15d28dfd97 | ||
![]() |
48b00403b6 | ||
![]() |
d78fab02eb | ||
![]() |
d275e4bbc2 | ||
![]() |
d26ad2c490 | ||
![]() |
cef58f676d | ||
![]() |
214bcceaea | ||
![]() |
5e1439f89e | ||
![]() |
eb40c5c2cf | ||
![]() |
ba3cf950ba | ||
![]() |
d26eb15bff | ||
![]() |
aed65de051 | ||
![]() |
bf767e8420 | ||
![]() |
ad65fda1a8 | ||
![]() |
170d3ed121 | ||
![]() |
7f1dfffab3 | ||
![]() |
40e3058408 | ||
![]() |
3e05c7c6c6 | ||
![]() |
fd135d0869 | ||
![]() |
5452a0ecac | ||
![]() |
6557627d8f | ||
![]() |
cfa2e165ba | ||
![]() |
e9999aa93c | ||
![]() |
b8788e9c0d | ||
![]() |
60293ee189 | ||
![]() |
2541da1d83 | ||
![]() |
bd537dcfc6 | ||
![]() |
b95dd0574c | ||
![]() |
49dca9e5b1 | ||
![]() |
02a8fb4a37 | ||
![]() |
1a5b861dff | ||
![]() |
0970829146 | ||
![]() |
3ee131245c | ||
![]() |
80a1a8d26b | ||
![]() |
d1aaf6a9b1 | ||
![]() |
5590e8878b | ||
![]() |
de703edfd7 | ||
![]() |
772bbb8d91 | ||
![]() |
b17b88595e | ||
![]() |
e64d1bf881 | ||
![]() |
40696052ca | ||
![]() |
b567879eac | ||
![]() |
0163c58ee1 | ||
![]() |
bc3b64f922 | ||
![]() |
765cb51df3 | ||
![]() |
b56824f650 | ||
![]() |
c613fed9ef | ||
![]() |
6c18374142 | ||
![]() |
a64b868dbd | ||
![]() |
cfd2d87fea | ||
![]() |
77349f6878 | ||
![]() |
5efd276a22 | ||
![]() |
373f6de13e | ||
![]() |
e0a4c2a1df | ||
![]() |
9feebc05c7 | ||
![]() |
d7917c02fe | ||
![]() |
1d0b5ef660 | ||
![]() |
ee84fbb81f | ||
![]() |
6a1abc7482 | ||
![]() |
7f36a8c7d1 | ||
![]() |
d1d7767033 | ||
![]() |
18973c23b3 | ||
![]() |
93289dc950 | ||
![]() |
817c357335 | ||
![]() |
f5bf830754 | ||
![]() |
b3a1122b2a | ||
![]() |
c7d9042e5d | ||
![]() |
4512f8317a | ||
![]() |
effec94613 | ||
![]() |
c9c67387ce | ||
![]() |
81089c2d8c | ||
![]() |
04c9c3e058 | ||
![]() |
4d5cc9d0bb | ||
![]() |
0d88e93787 | ||
![]() |
5a8af8c2fb | ||
![]() |
e8097a6f8f | ||
![]() |
cb27f0c4be | ||
![]() |
c3a5c4c169 | ||
![]() |
bc46b2f0e0 | ||
![]() |
ce657d7807 | ||
![]() |
9702903343 | ||
![]() |
15a05467bd | ||
![]() |
0041f49d3f | ||
![]() |
0cfb05a661 | ||
![]() |
c6b475b251 | ||
![]() |
37a1e6f57b | ||
![]() |
0c5cacf7cc | ||
![]() |
95e5a13131 | ||
![]() |
c1a88f5457 | ||
![]() |
70b6a57003 | ||
![]() |
915c2db3b9 | ||
![]() |
eb647577c3 | ||
![]() |
1094410ff8 | ||
![]() |
6e90c238e8 | ||
![]() |
44a63a9911 | ||
![]() |
149e8d12cd | ||
![]() |
9888f0434d | ||
![]() |
370982b812 | ||
![]() |
5c5de1c6b3 | ||
![]() |
5ba2fa893f | ||
![]() |
4eb8a93c83 | ||
![]() |
3da0b1c7d9 | ||
![]() |
aa62466091 | ||
![]() |
337812d51d | ||
![]() |
17ac646f70 | ||
![]() |
e3cfa163d0 | ||
![]() |
9657b6cebe | ||
![]() |
90b8a5a20b | ||
![]() |
54c50e96e7 | ||
![]() |
8c2e8ddf5c | ||
![]() |
9740b3f1df | ||
![]() |
0c57ebca70 | ||
![]() |
ae577d7724 | ||
![]() |
82e5cb578c | ||
![]() |
4ba0ce89c4 | ||
![]() |
0df65b9f9f | ||
![]() |
30e3cf5050 | ||
![]() |
25ca0e21db | ||
![]() |
f08337d939 | ||
![]() |
372dc090fd | ||
![]() |
81b6316081 | ||
![]() |
fc4a0aef0d | ||
![]() |
a1bb0e0015 | ||
![]() |
b8e5a4d707 | ||
![]() |
979392efa5 | ||
![]() |
9de7b59e93 | ||
![]() |
0388149904 | ||
![]() |
7b0cd87838 | ||
![]() |
7641c6f952 | ||
![]() |
261c9a74ef | ||
![]() |
a544f68ac9 | ||
![]() |
ba9d2d1a71 | ||
![]() |
f4920a9249 | ||
![]() |
94b6dde6bb | ||
![]() |
791ab07bd4 | ||
![]() |
437093dee0 | ||
![]() |
407ec7b495 | ||
![]() |
3407dffed0 | ||
![]() |
e802acf413 | ||
![]() |
f001625e5b | ||
![]() |
43a726efe7 | ||
![]() |
f37245ace2 | ||
![]() |
08ddfbb884 | ||
![]() |
e96e7ffc89 | ||
![]() |
2926f0a501 | ||
![]() |
6c325e9070 | ||
![]() |
efc82ee1b9 | ||
![]() |
5ae85e9c07 | ||
![]() |
74b3bca93d | ||
![]() |
e7e41b045d | ||
![]() |
47f67eb270 | ||
![]() |
e608366a8e | ||
![]() |
03a3183b1c | ||
![]() |
e64a42732f | ||
![]() |
45a2c2e905 | ||
![]() |
f5f20efe0d | ||
![]() |
49a9e74900 | ||
![]() |
207eef305e | ||
![]() |
4694ded7cd | ||
![]() |
d027c27ca1 | ||
![]() |
ee26de98de | ||
![]() |
94e75ba53c | ||
![]() |
f4e602a791 | ||
![]() |
6ab198ac22 | ||
![]() |
a030448cde | ||
![]() |
5da8c8f708 | ||
![]() |
09cc9e5d93 | ||
![]() |
195d136faa | ||
![]() |
d2cd398594 | ||
![]() |
8232b8ba6d | ||
![]() |
cfa98e02fc | ||
![]() |
efa3a05a35 | ||
![]() |
34fdccd3fb | ||
![]() |
b9db62bc43 | ||
![]() |
9ae52f1e46 | ||
![]() |
419b29f5b4 | ||
![]() |
0134973907 | ||
![]() |
fcb791d5a0 | ||
![]() |
175565eb71 | ||
![]() |
aa91d9f78b | ||
![]() |
730715228a | ||
![]() |
e151a2f153 | ||
![]() |
1a04ec9f33 | ||
![]() |
3d47456f56 | ||
![]() |
3bdf5ea05e | ||
![]() |
4b91c5aa03 | ||
![]() |
0932b98c34 | ||
![]() |
cbb0b8e66c | ||
![]() |
a6a7407faa | ||
![]() |
a5c4eaa55c | ||
![]() |
44cbcaa387 | ||
![]() |
a5237524b2 | ||
![]() |
9e062cd7a8 | ||
![]() |
5eddcaef89 | ||
![]() |
95bddff99d | ||
![]() |
34ea09264a | ||
![]() |
20c5761bcd | ||
![]() |
900de3c304 | ||
![]() |
8b7447b282 | ||
![]() |
66f03613b7 | ||
![]() |
f1b58398b0 | ||
![]() |
cbb4a91113 | ||
![]() |
b9002db37f | ||
![]() |
7e29e47e4b | ||
![]() |
0f9bdb18f5 | ||
![]() |
29d17da1ba | ||
![]() |
ce78866002 | ||
![]() |
0ac412da0f | ||
![]() |
2ba63f3462 | ||
![]() |
590c2d72ab | ||
![]() |
db3fe54006 | ||
![]() |
b23b32f84d | ||
![]() |
c39a03ad59 | ||
![]() |
0ac034ad4c | ||
![]() |
8d36bbd7ab | ||
![]() |
e74969bd17 | ||
![]() |
b5a99f049c | ||
![]() |
f86c3e6253 | ||
![]() |
964e69127c | ||
![]() |
f3a4631395 | ||
![]() |
1afc7df221 | ||
![]() |
51521d147d | ||
![]() |
c3b9b816f7 | ||
![]() |
f881cdaae6 | ||
![]() |
600501924f | ||
![]() |
80d64e6418 | ||
![]() |
c36a344387 | ||
![]() |
2581654922 | ||
![]() |
d86c90a162 | ||
![]() |
9ed1636ffe | ||
![]() |
bb9cc21d8e | ||
![]() |
b9529231b4 | ||
![]() |
689bcd14aa | ||
![]() |
42440b17e8 | ||
![]() |
27e35b8bcd | ||
![]() |
501264647e | ||
![]() |
fb09ca1868 | ||
![]() |
8a847ee7dc | ||
![]() |
2c41717e30 | ||
![]() |
2fb121b1c9 | ||
![]() |
c17e916978 | ||
![]() |
75109ac211 | ||
![]() |
02bcf06809 | ||
![]() |
c540438b91 | ||
![]() |
154e38e71e | ||
![]() |
7179d77d0c | ||
![]() |
4c3a20c3f2 | ||
![]() |
b78ad2e12d | ||
![]() |
f36d236a55 | ||
![]() |
9a72bf1858 | ||
![]() |
79857803de | ||
![]() |
4fcc9f052e | ||
![]() |
8c5369d522 | ||
![]() |
311052d555 | ||
![]() |
d299fbd8da | ||
![]() |
8a5cce91bf | ||
![]() |
7a598e5567 | ||
![]() |
ceb771aeb6 | ||
![]() |
ebae7a654e | ||
![]() |
1e0d6c3346 | ||
![]() |
ff652ff407 | ||
![]() |
f6853d0947 | ||
![]() |
6ec56406cf | ||
![]() |
00dcef82e3 | ||
![]() |
f15e959634 | ||
![]() |
43c7a44e1d | ||
![]() |
9cdd64b58f | ||
![]() |
1cd4938224 | ||
![]() |
f3446fad9a | ||
![]() |
d81fdce482 | ||
![]() |
585e362526 | ||
![]() |
8984fd358b | ||
![]() |
583596178f | ||
![]() |
ae148bc89f | ||
![]() |
dc5a81ac77 | ||
![]() |
b51e6bdaa4 | ||
![]() |
95e4c6ac2a | ||
![]() |
9e86812928 | ||
![]() |
43dd208874 | ||
![]() |
e8a9a6063b | ||
![]() |
e22eea105f | ||
![]() |
319f590e1a | ||
![]() |
69090f0bf0 | ||
![]() |
f289b64030 | ||
![]() |
cb57ebd470 | ||
![]() |
509495e224 | ||
![]() |
96f64031d4 | ||
![]() |
9abae5b0a2 | ||
![]() |
98c3b06ffd | ||
![]() |
1af2020151 | ||
![]() |
88a0d1ff03 | ||
![]() |
28958e51ef | ||
![]() |
78a2866980 | ||
![]() |
6f6e533380 | ||
![]() |
f7b55bfdcc | ||
![]() |
5975c80270 | ||
![]() |
7e0b4d4a78 | ||
![]() |
f51eed31d8 | ||
![]() |
197c81178c | ||
![]() |
dc73aaeb39 | ||
![]() |
9c08499787 | ||
![]() |
8e2d576805 | ||
![]() |
26ea31107f | ||
![]() |
a6620b663b | ||
![]() |
dccd7a9b99 | ||
![]() |
badb397bce | ||
![]() |
812f783084 | ||
![]() |
826a0c4e10 | ||
![]() |
ebb788140a | ||
![]() |
637d35a74b | ||
![]() |
2be93847ce | ||
![]() |
f0a74e2e95 | ||
![]() |
b30802e35f | ||
![]() |
086f74fb29 | ||
![]() |
b908e45208 | ||
![]() |
23cefa0bb5 | ||
![]() |
42639fc9fb | ||
![]() |
a38c16e57e | ||
![]() |
a535ef6117 | ||
![]() |
eb42281fd4 | ||
![]() |
93902aabfd | ||
![]() |
7d068e6909 | ||
![]() |
7593c6fdee | ||
![]() |
4e66c5dc6c | ||
![]() |
a62b3c8b29 | ||
![]() |
8c3437fd27 | ||
![]() |
efeedae712 | ||
![]() |
b392d206d7 | ||
![]() |
d826e620a9 | ||
![]() |
1db28d3b3f | ||
![]() |
b6177f74a7 | ||
![]() |
086f3d807e | ||
![]() |
6b72d622a5 | ||
![]() |
f0a811421f | ||
![]() |
b3a72a61fd | ||
![]() |
f94a3d08e0 | ||
![]() |
d910267364 | ||
![]() |
d7b4eec74a | ||
![]() |
86b34a45b1 | ||
![]() |
34c04823ff | ||
![]() |
7cff2734d1 | ||
![]() |
e5dc1b01ac | ||
![]() |
6e577c12c1 | ||
![]() |
97b629ad5b | ||
![]() |
5eca441b1c | ||
![]() |
8a8171ebc7 | ||
![]() |
0243071f15 | ||
![]() |
de42a62f4e | ||
![]() |
854e58fd82 | ||
![]() |
fb49dabcc2 | ||
![]() |
b0d3660c91 | ||
![]() |
dbcacfa5ba | ||
![]() |
e51e7ab77a | ||
![]() |
6cda7d0b11 | ||
![]() |
c7a72aeed3 | ||
![]() |
e354442c93 | ||
![]() |
3e3bbe0eb5 | ||
![]() |
82a6ba0238 | ||
![]() |
82a43d88f5 | ||
![]() |
c3b63c96d7 | ||
![]() |
899b6347b1 | ||
![]() |
213846a685 | ||
![]() |
346a8b5aaf | ||
![]() |
5faeb552b7 | ||
![]() |
b44845ad66 | ||
![]() |
f1097bfbe1 | ||
![]() |
47353f88c7 | ||
![]() |
7ff56e67e9 | ||
![]() |
d7cac40332 | ||
![]() |
e0e6dab50f | ||
![]() |
00e572800c | ||
![]() |
702eab3a6c | ||
![]() |
3ed032bf8b | ||
![]() |
b3f3014058 | ||
![]() |
39f2c804a3 | ||
![]() |
4dfc8d16be | ||
![]() |
bab3f73370 | ||
![]() |
dc9d951255 | ||
![]() |
fecaa42962 | ||
![]() |
8057a2f68a | ||
![]() |
9bad861649 | ||
![]() |
deed8016ed | ||
![]() |
b168954ed3 | ||
![]() |
fb5a3a8998 | ||
![]() |
459d8f9c9d | ||
![]() |
1efd5432ef | ||
![]() |
31b211550f | ||
![]() |
538a06fd55 | ||
![]() |
be44a1d9a5 | ||
![]() |
e694f07144 | ||
![]() |
2b780e5486 | ||
![]() |
9e8800561e | ||
![]() |
5fba648e85 | ||
![]() |
019b5cacc3 | ||
![]() |
81e52735a2 | ||
![]() |
9bcdc8be00 | ||
![]() |
a7c8cea1b5 | ||
![]() |
47f0557175 | ||
![]() |
24c91c3a37 | ||
![]() |
89b00f25a7 | ||
![]() |
8ebadbce28 | ||
![]() |
875e6dc0f9 | ||
![]() |
7df9ce1731 | ||
![]() |
8d07496c75 | ||
![]() |
c776871d52 | ||
![]() |
7fea250304 | ||
![]() |
6617781f4f | ||
![]() |
ac31a7f143 | ||
![]() |
fffb277250 | ||
![]() |
966c399154 | ||
![]() |
fb448b2f31 | ||
![]() |
85815f8188 | ||
![]() |
22bbeb0ae0 | ||
![]() |
3e4253f23e | ||
![]() |
400e82daa3 | ||
![]() |
0a513b0678 | ||
![]() |
b4743ee236 | ||
![]() |
dd8acae43c | ||
![]() |
e28902b102 | ||
![]() |
d5bcea27e3 | ||
![]() |
d0e109f96c | ||
![]() |
9d68b98bc9 | ||
![]() |
a242f622ea | ||
![]() |
4e2d5154fe | ||
![]() |
d5e31129d5 | ||
![]() |
b7f1a5fae7 | ||
![]() |
fe20139722 | ||
![]() |
c6b3408398 | ||
![]() |
d4b91dc654 | ||
![]() |
8da3b943a9 | ||
![]() |
3a745537f0 | ||
![]() |
3d62f360fe | ||
![]() |
bfd67fadef | ||
![]() |
2f74af1c04 | ||
![]() |
49f9ba96cc | ||
![]() |
90ff51acdb | ||
![]() |
f7c2b446f2 | ||
![]() |
619e2c36b5 | ||
![]() |
737d3cbbf5 | ||
![]() |
6aaf2738c9 | ||
![]() |
31ba0b1f95 | ||
![]() |
68eb780c75 | ||
![]() |
03498549b2 | ||
![]() |
6077c26cdf | ||
![]() |
0498d55314 | ||
![]() |
4b5eda0b0a | ||
![]() |
0cf10075e1 | ||
![]() |
ceb2f700f5 | ||
![]() |
2e19e3c9f7 | ||
![]() |
aad6035c57 | ||
![]() |
2eeb984e4e | ||
![]() |
a1c5f93ef0 | ||
![]() |
b0af92b1d8 | ||
![]() |
068c16b162 | ||
![]() |
91bf299f16 | ||
![]() |
f24be6ccc3 | ||
![]() |
0cbf47ca30 | ||
![]() |
a40a9eccf4 | ||
![]() |
e19d4c048a | ||
![]() |
35bdbec054 | ||
![]() |
af845f4de7 | ||
![]() |
d466c615ed | ||
![]() |
cc3c995d80 | ||
![]() |
a4fe1ad960 | ||
![]() |
750cb70f69 | ||
![]() |
4f70698493 | ||
![]() |
30ff4540d0 | ||
![]() |
71552fb08d | ||
![]() |
2536b82084 | ||
![]() |
d70e08039c | ||
![]() |
49fe8f0399 | ||
![]() |
4e9ac83b15 | ||
![]() |
0f1f2283e7 | ||
![]() |
2567ee81b8 | ||
![]() |
b29a41fa43 | ||
![]() |
1b8dd23884 | ||
![]() |
860a1298b5 | ||
![]() |
7366527aa7 | ||
![]() |
6e7669e4d7 | ||
![]() |
691c6f802d | ||
![]() |
009a439259 | ||
![]() |
82b064ed7d | ||
![]() |
bb35f88925 | ||
![]() |
9b39feab95 | ||
![]() |
74cf783be3 | ||
![]() |
6c38f577fe | ||
![]() |
5f65ca07d7 | ||
![]() |
2c73ab41ed | ||
![]() |
53bddf9ceb | ||
![]() |
5151c5102d | ||
![]() |
973662d5c3 | ||
![]() |
b94beb3289 | ||
![]() |
af83598ad3 | ||
![]() |
41e99288b5 | ||
![]() |
a3460b8ac8 | ||
![]() |
9598affa03 | ||
![]() |
2679d3cf00 | ||
![]() |
487c6cfaaa | ||
![]() |
052a794427 | ||
![]() |
6fe940afc7 | ||
![]() |
912afb6e6b | ||
![]() |
6d2c558bd8 | ||
![]() |
8f5c12d76d | ||
![]() |
0494b044d5 | ||
![]() |
3f7203a3a4 | ||
![]() |
9138b9aa3c | ||
![]() |
de41777c69 | ||
![]() |
7b9877258f | ||
![]() |
41120f2a79 | ||
![]() |
6f8a7f1870 | ||
![]() |
7fbbd0200f | ||
![]() |
cf4ef8cab2 | ||
![]() |
011a7f77a6 | ||
![]() |
80fb12a0b9 | ||
![]() |
80c4897ced | ||
![]() |
c56914dd5d | ||
![]() |
559f6e8f19 | ||
![]() |
718b077b82 | ||
![]() |
14dccacfde | ||
![]() |
82ceb7c837 | ||
![]() |
03481ae2d0 | ||
![]() |
17b4eab4d4 | ||
![]() |
cb1b7deefa | ||
![]() |
cd40cc9edb | ||
![]() |
e8267b20fe | ||
![]() |
c64ada94a5 | ||
![]() |
a32503a75a | ||
![]() |
53268f985f | ||
![]() |
e4e200a1dc | ||
![]() |
e9053f1f52 | ||
![]() |
e3156b007d | ||
![]() |
e691b664e3 | ||
![]() |
4ee70f0780 | ||
![]() |
995e8da006 | ||
![]() |
5fd4fb96f7 | ||
![]() |
1d818b7b7c | ||
![]() |
8183c509d9 | ||
![]() |
115c086eb9 | ||
![]() |
6603ee6084 | ||
![]() |
f5c10f387b | ||
![]() |
458e125c09 | ||
![]() |
b98ae68f39 | ||
![]() |
d23fa8c870 | ||
![]() |
ebc69e1127 | ||
![]() |
4c64e88631 | ||
![]() |
dd56688cd8 | ||
![]() |
afcd24b603 | ||
![]() |
7527670eef | ||
![]() |
089e595b28 | ||
![]() |
2a71cab8c4 | ||
![]() |
1ee119f3dc | ||
![]() |
206cff1547 | ||
![]() |
d02060e201 | ||
![]() |
f965726d15 | ||
![]() |
38ff6a49c4 | ||
![]() |
fa0592ebc7 | ||
![]() |
a500a7e668 | ||
![]() |
4c323b8f33 | ||
![]() |
4aea4e7dc6 | ||
![]() |
1e28a50647 | ||
![]() |
4677a6ab76 | ||
![]() |
661c0fdad9 | ||
![]() |
faf818940d | ||
![]() |
615abebd9d | ||
![]() |
62c5d3df06 | ||
![]() |
bfc47ccd6e | ||
![]() |
80cd793f75 | ||
![]() |
42936562de | ||
![]() |
9e2cfcd699 | ||
![]() |
9b86849068 | ||
![]() |
11089cb824 | ||
![]() |
35a2f2df76 | ||
![]() |
447eba6007 | ||
![]() |
5e8ceda7e7 | ||
![]() |
c89be4ac8a | ||
![]() |
fdb20df78b | ||
![]() |
262e6fab27 | ||
![]() |
d443d92446 | ||
![]() |
5429690467 | ||
![]() |
a922dadde0 | ||
![]() |
c1358625c9 | ||
![]() |
20a98e1c2a | ||
![]() |
ac2aa5337d | ||
![]() |
efa0ae8373 | ||
![]() |
bedddaa717 | ||
![]() |
2d01419577 | ||
![]() |
20218dac92 | ||
![]() |
214ac20a69 | ||
![]() |
3b8db16d9f | ||
![]() |
6f8474cf04 | ||
![]() |
53bdcfc12b | ||
![]() |
ca38a13205 | ||
![]() |
1feeb731c9 | ||
![]() |
37dd796b53 | ||
![]() |
a7378b709b | ||
![]() |
813e6f459f | ||
![]() |
0ed0c3bab6 | ||
![]() |
c6ebcae729 | ||
![]() |
0ca04ed7aa | ||
![]() |
28cae9c995 | ||
![]() |
56da0d3df7 | ||
![]() |
78478110fa | ||
![]() |
1b0100792f | ||
![]() |
a9b7683110 | ||
![]() |
a2d4594e19 | ||
![]() |
dffad0e982 | ||
![]() |
e48976b926 | ||
![]() |
e5b944ce09 | ||
![]() |
d06be91342 | ||
![]() |
ac56962c29 | ||
![]() |
f5e9ff5a82 | ||
![]() |
2bad2844f5 | ||
![]() |
245c9c2d7e | ||
![]() |
29a86695d1 | ||
![]() |
7b9eccb489 | ||
![]() |
339bdf8dd2 | ||
![]() |
116fc5546f | ||
![]() |
844a8ac13f | ||
![]() |
bd712d7f8f | ||
![]() |
9d84a23cd1 | ||
![]() |
ed2e19e4d7 | ||
![]() |
f233617a90 | ||
![]() |
4f3b78c64c | ||
![]() |
75fa1d1b09 | ||
![]() |
ced833fdfc | ||
![]() |
51d9f9dce6 | ||
![]() |
43b67afc41 | ||
![]() |
d91715dc8f | ||
![]() |
090096b1e2 | ||
![]() |
d2061f8398 | ||
![]() |
835863e397 | ||
![]() |
e605dff37f | ||
![]() |
e6984e727c | ||
![]() |
5ad12fbe90 | ||
![]() |
8f1cfefbb2 | ||
![]() |
f33a46072b | ||
![]() |
7279f2a9cd | ||
![]() |
84c3050a7c | ||
![]() |
8ae714eeae | ||
![]() |
2be2d8ccbe | ||
![]() |
fee55e548c | ||
![]() |
41e5fbb963 | ||
![]() |
9c5809ce5e | ||
![]() |
089eb7e6de | ||
![]() |
add8c23c13 | ||
![]() |
e263d441f5 | ||
![]() |
26022db469 | ||
![]() |
ad47a95074 | ||
![]() |
195dd875a7 | ||
![]() |
23079e848b | ||
![]() |
f374f94644 | ||
![]() |
838d999d86 | ||
![]() |
8ddeb4f953 | ||
![]() |
33dd196cba | ||
![]() |
c4bc6b7445 | ||
![]() |
d1889d1395 | ||
![]() |
a63cbb186d | ||
![]() |
b52ee424e4 | ||
![]() |
5b4e9c01cc | ||
![]() |
7eac9e4958 | ||
![]() |
855d19cc0a | ||
![]() |
d34cc4a683 | ||
![]() |
5fdb8463de | ||
![]() |
19d2e8c7e1 | ||
![]() |
3194faaa9c | ||
![]() |
e532a300b0 | ||
![]() |
229589616f | ||
![]() |
b2bbb306f4 | ||
![]() |
da6ded6f3f | ||
![]() |
884dcec781 | ||
![]() |
402c0b5036 | ||
![]() |
9ed27d3dcb | ||
![]() |
f36ba88085 | ||
![]() |
ac85e1e225 | ||
![]() |
d9934a2d8c | ||
![]() |
8b680dfdd2 | ||
![]() |
3d1d70b727 | ||
![]() |
029004f289 | ||
![]() |
06ec2b948f | ||
![]() |
60f48e44ff | ||
![]() |
501a60ab20 | ||
![]() |
b9701454b8 | ||
![]() |
ee1361fb6e | ||
![]() |
86e9191d34 | ||
![]() |
edb4d0a8c4 | ||
![]() |
362e9af8e8 | ||
![]() |
a665b422bd | ||
![]() |
ac7f2cdef9 | ||
![]() |
8bf3fe0d19 | ||
![]() |
921e556b3a | ||
![]() |
c92222b1b2 | ||
![]() |
7134dc513a | ||
![]() |
a29d12c67d | ||
![]() |
da9bae158b | ||
![]() |
ae659e1c52 | ||
![]() |
946a2dc446 | ||
![]() |
69dae32c37 | ||
![]() |
ac7524508b | ||
![]() |
4af0425d72 | ||
![]() |
fa803fd88f | ||
![]() |
3fa131695b | ||
![]() |
7fa28277a1 | ||
![]() |
041b33c450 | ||
![]() |
06a0c62f86 | ||
![]() |
6981a8198b | ||
![]() |
b3778e4470 | ||
![]() |
8c8d500495 | ||
![]() |
e312daffd5 | ||
![]() |
3f05f34286 | ||
![]() |
248487a63c | ||
![]() |
420c29dea9 | ||
![]() |
5ccb32efed | ||
![]() |
4f107f84eb | ||
![]() |
6bae734d41 | ||
![]() |
8c5e683296 | ||
![]() |
ff5315d551 | ||
![]() |
4395fd581a | ||
![]() |
3b9c81f390 | ||
![]() |
abc8cb6ff7 | ||
![]() |
f663a511b3 | ||
![]() |
3e92e3b1df | ||
![]() |
d080f816b6 | ||
![]() |
bacc9c0afc | ||
![]() |
2af36b1e56 | ||
![]() |
85a01b3945 | ||
![]() |
7069fc9b50 | ||
![]() |
01a5b5762d | ||
![]() |
1c1f4d7c93 | ||
![]() |
a29c93a95a | ||
![]() |
842eb3fa93 | ||
![]() |
bbd6396f40 | ||
![]() |
fcaeaa0328 | ||
![]() |
282b52d6b7 | ||
![]() |
9c8824542e | ||
![]() |
e8bc8e95e2 | ||
![]() |
cfd3cdd64e | ||
![]() |
ec4edcb78c | ||
![]() |
94c3b02eef | ||
![]() |
f83ac8476c | ||
![]() |
4edccc4eb5 | ||
![]() |
0398a78b4a | ||
![]() |
ec6a455fb0 | ||
![]() |
e55ead0419 | ||
![]() |
f22b9dfd94 | ||
![]() |
ec4dfd0cbc | ||
![]() |
350ecb1dcf | ||
![]() |
38a878171a | ||
![]() |
dad1b107f5 | ||
![]() |
582a80f518 | ||
![]() |
808d21e857 | ||
![]() |
0a1f2b3a47 | ||
![]() |
4c104e1cb7 | ||
![]() |
ecf75915c7 | ||
![]() |
7be4c63ee4 | ||
![]() |
b09a781a80 | ||
![]() |
52dc32031d | ||
![]() |
a926a4a0ca | ||
![]() |
39df21227d | ||
![]() |
2830c9d748 | ||
![]() |
3886f0ecac | ||
![]() |
b1c7811e89 | ||
![]() |
1385d192c5 | ||
![]() |
82aa7363f9 | ||
![]() |
a4346200e8 | ||
![]() |
9f66f63bf5 | ||
![]() |
3645fef5e0 | ||
![]() |
f386494ba4 | ||
![]() |
936adc6ea5 | ||
![]() |
bc787fc1f3 | ||
![]() |
1c6c7350e1 | ||
![]() |
2a0a5dfdf8 | ||
![]() |
501dd26713 | ||
![]() |
3e1c68b88a | ||
![]() |
6d31d4756e | ||
![]() |
bea9d1f679 | ||
![]() |
4abbd4b1e5 | ||
![]() |
27c81cad33 | ||
![]() |
db0a7e2978 | ||
![]() |
4d2f018ddb | ||
![]() |
5eb43d34ff | ||
![]() |
ddfffe270f | ||
![]() |
cebbafdd22 | ||
![]() |
46082f8c71 | ||
![]() |
e51c12d1cd | ||
![]() |
f562e65d5f | ||
![]() |
04e09d4c56 | ||
![]() |
78a68f3e10 | ||
![]() |
b2444df787 | ||
![]() |
f70993be97 | ||
![]() |
92a965b979 | ||
![]() |
922749e5b3 | ||
![]() |
9acaa50f59 | ||
![]() |
60f531af35 | ||
![]() |
246ac5e578 | ||
![]() |
505282697a | ||
![]() |
6768aefb9d | ||
![]() |
fc8db63716 | ||
![]() |
d6bf2f5e80 | ||
![]() |
8c7b04edb9 | ||
![]() |
11b14d327f | ||
![]() |
d8561cb4c3 | ||
![]() |
47ce823aa5 | ||
![]() |
971419c880 | ||
![]() |
0ee26a5168 | ||
![]() |
204cf63805 |
30
.cvsignore
Normal file
30
.cvsignore
Normal file
@@ -0,0 +1,30 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
confdefs.h
|
||||
config.cache
|
||||
config.guess
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
configure.scan
|
||||
libtool
|
||||
ltconfig
|
||||
ltmain.sh
|
||||
stamp-h
|
||||
stamp-h.in
|
||||
stamp.h
|
||||
version.h
|
||||
config.h.in
|
||||
install-sh
|
||||
missing
|
||||
mkinstalldirs
|
||||
INSTALL
|
||||
intl
|
||||
ABOUT-NLS
|
||||
COPYING
|
||||
intltool-*
|
||||
metacity.spec
|
||||
autom4te.cache
|
161
COMPLIANCE
Normal file
161
COMPLIANCE
Normal file
@@ -0,0 +1,161 @@
|
||||
Metacity Standards Compliance
|
||||
=============================
|
||||
$Id$
|
||||
|
||||
1) Introduction
|
||||
2) EWMH Compliance
|
||||
a. Root Window Properties
|
||||
b. Root Window Messages
|
||||
c. Application Window Properties
|
||||
d. Window Manager Protocols
|
||||
3) ICCCM Compliance
|
||||
|
||||
1) Introduction
|
||||
---------------
|
||||
|
||||
This document details metacity compliance with the relevent standards.
|
||||
The format of this document is as follows:
|
||||
|
||||
[-/+?] Hint Name/Feature Name (Version number)
|
||||
Errata/Comments
|
||||
|
||||
The first character indicates the level of compliance as follows:
|
||||
- none
|
||||
/ partial
|
||||
+ complete
|
||||
? unknown
|
||||
|
||||
The title indicates a feature or a hint in the specification, and the
|
||||
version number indicates the minimum version of the specification
|
||||
supported by metacity. Later versions may be supported if no
|
||||
incompatible changes have been made in the specification.
|
||||
|
||||
2) EWMH Compliance
|
||||
------------------
|
||||
|
||||
The EWMH, or Extended Window Manager Hints is a freedesktop.org-
|
||||
developed standard to support a number of conventions for
|
||||
communication between the window manager and clients. It builds on
|
||||
and extends the ICCCM (See Section 3). A copy of the current EWMH
|
||||
standard is available at http://freedesktop.org/Standards/wm-spec/
|
||||
|
||||
a. Root Window Properties
|
||||
-------------------------
|
||||
|
||||
+ _NET_SUPPORTED (1.3)
|
||||
|
||||
+ _NET_CLIENT_LIST (1.3)
|
||||
|
||||
+ _NET_NUMBER_OF_DESKTOPS (1.3)
|
||||
|
||||
- _NET_DESKTOP_GEOMETRY (-)
|
||||
Metacity does not implement large desktops. Regardless, according
|
||||
to the specification, metacity SHOULD set this property to the
|
||||
screen size, and update it if the screen size changes because of a
|
||||
RandR change.
|
||||
|
||||
- _NET_DESKTOP_VIEWPORT (-)
|
||||
Metacity does not implement viewports. However, according to the
|
||||
specification, metacity MUST set this property to (0,0)
|
||||
|
||||
+ _NET_CURRENT_DESKTOP (1.3)
|
||||
|
||||
+ _NET_DESKTOP_NAMES (1.3)
|
||||
|
||||
+ _NET_ACTIVE_WINDOW (1.3)
|
||||
|
||||
+ _NET_WORKAREA (1.3)
|
||||
|
||||
+ _NET_SUPPORTING_WM_CHECK (1.3)
|
||||
|
||||
+ _NET_VIRTUAL_ROOTS (1.3)
|
||||
Metacity does not read or set this property, but it does not use
|
||||
virtual roots to implement virtual desktops, so it complies with the
|
||||
specification.
|
||||
|
||||
+ _NET_DESKTOP_LAYOUT (1.3)
|
||||
|
||||
+ _NET_SHOWING_DESKTOP (1.3)
|
||||
|
||||
b. Root Window Messages
|
||||
-----------------------
|
||||
|
||||
+ _NET_CLOSE_WINDOW (1.3)
|
||||
|
||||
- _NET_MOVERESIZE_WINDOW (-)
|
||||
Metacity does not support this message. The specification states
|
||||
that metacity should treat this message like a ConfigureRequest.
|
||||
Not hard to implement; just hasn't been done.
|
||||
|
||||
+ _NET_WM_MOVERESIZE (1.3)
|
||||
|
||||
- _NET_RESTACK_WINDOW (-)
|
||||
Metacity does not currently support this message.
|
||||
|
||||
+ _NET_REQUEST_FRAME_EXTENTS (1.3)
|
||||
|
||||
c. Application Window Properties
|
||||
--------------------------------
|
||||
|
||||
+ _NET_WM_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_ICON_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_ICON_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_DESKTOP (1.3)
|
||||
|
||||
+ _NET_WM_WINDOW_TYPE (1.3)
|
||||
|
||||
/ _NET_WM_STATE (1.3)
|
||||
Metacity does not recognize separate vertical and horizontal
|
||||
maximization states. Currently metacity will do a two-dimensional
|
||||
maximization if either property is set.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=113601
|
||||
Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is
|
||||
unimplemented.
|
||||
_NET_WM_STATE_DEMANDS_ATTENTION is neither read nor updated by
|
||||
metacity. Metacity should unset it on window activation.
|
||||
|
||||
+ _NET_WM_ALLOWED_ACTIONS (1.3)
|
||||
Metacity keeps this hint up to date. The code is somewhat crufty
|
||||
and should be rewritten, though it is functional.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=90420
|
||||
|
||||
+ _NET_WM_STRUT (1.3)
|
||||
|
||||
+ _NET_WM_STRUT_PARTIAL (1.3)
|
||||
|
||||
+ _NET_WM_ICON_GEOMETRY (1.3)
|
||||
Metacity uses this property to draw minimize/restore animations
|
||||
|
||||
+ _NET_WM_ICON (1.3)
|
||||
|
||||
+ _NET_WM_PID (1.3)
|
||||
|
||||
+ _NET_WM_HANDLED_ICONS (1.3)
|
||||
Metacity does not read or set this property. However, metacity
|
||||
never managed iconified windows, and so has no need to do so.
|
||||
|
||||
- _NET_WM_USER_TIME (-)
|
||||
Metacity does not read or set this property. The EWMH does not
|
||||
require it to do so, but it should support it.
|
||||
|
||||
+ _NET_FRAME_EXTENTS (1.3)
|
||||
If set in response to a _NET_REQUEST_FRAME_EXTENTS message received
|
||||
prior to the window being mapped, this may be an estimate. This is,
|
||||
however, expressly allowed by the specification.
|
||||
|
||||
d. Window Manager Protocols
|
||||
---------------------------
|
||||
+ _NET_WM_PING (1.3)
|
||||
|
||||
3) ICCCM Compliance
|
||||
-------------------
|
||||
TODO
|
63
HACKING
63
HACKING
@@ -1,11 +1,63 @@
|
||||
Making a release
|
||||
===
|
||||
|
||||
To make a release of metacity, do the following:
|
||||
|
||||
- check out a fresh copy from CVS
|
||||
|
||||
- increment the version number in configure.in,
|
||||
see the comment above the version for the next fibonacci number
|
||||
|
||||
- update the file NEWS based on the ChangeLog
|
||||
|
||||
- add a ChangeLog entry containing the version number
|
||||
you're releasing ("Released 2.5.4" or something)
|
||||
so people can see which changes were before and after
|
||||
a given release.
|
||||
|
||||
- "make distcheck" (DO NOT just "make dist" - pass the check!)
|
||||
|
||||
- if make distcheck fails, fix it.
|
||||
|
||||
- once distcheck succeeds, "cvs commit"
|
||||
|
||||
- if someone else made changes and the commit fails,
|
||||
you have to "cvs up" and run "make distcheck" again
|
||||
|
||||
- once the commit succeeds, WITHOUT cvs updating, "cvs tag
|
||||
METACITY_X_Y_Z" where
|
||||
X_Y_Z map to version X.Y.Z
|
||||
|
||||
- scp the tarball to master.gnome.org
|
||||
|
||||
- run install-module on master.gnome.org to install the tarball
|
||||
on the ftp site
|
||||
|
||||
Misc stuff
|
||||
===
|
||||
|
||||
Don't commit substantive code in here without asking me,
|
||||
hp@redhat.com. Adding translations, no-brainer typo fixes, etc. is
|
||||
fine.
|
||||
|
||||
The script src/run-metacity.sh is useful to hack on the window manager.
|
||||
It runs metacity in an Xnest. e.g.:
|
||||
CLIENTS=3 ./run-metacity.sh
|
||||
or
|
||||
DEBUG=memprof ./run-metacity.sh
|
||||
or
|
||||
DEBUG_TEST=1 ./run-metacity-sh
|
||||
or whatever.
|
||||
|
||||
The tool metacity-message can be used as follows:
|
||||
metacity-message reload-theme
|
||||
metacity-message restart
|
||||
metacity-message enable-keybindings
|
||||
metacity-message disable-keybindings
|
||||
|
||||
metacity-window-demo is good for trying behavior of various kinds of window
|
||||
without launching a full desktop.
|
||||
|
||||
src/window.c is where all the guts of the window manager live. This is
|
||||
basically the only remotely scary file.
|
||||
|
||||
@@ -25,6 +77,10 @@ display.h or window.h or other core files.
|
||||
Files in the core (display.[hc], window.[hc]) are not supposed to
|
||||
include gdk.h or gtk.h.
|
||||
|
||||
src/theme.c and src/theme-parser.c have the theme system; this is
|
||||
well-modularized from the rest of the code, since the theme viewer app
|
||||
links to these files in addition to the WM itself.
|
||||
|
||||
When hacking, remember that you can have multiple screens. The code is
|
||||
also written to support multiple displays, but this is useless, since
|
||||
you can just run two copies of the WM. Also, an XKillClient() or
|
||||
@@ -45,4 +101,9 @@ be NULL.
|
||||
|
||||
The code could use cleanup in a lot of places, feel free to do so.
|
||||
|
||||
|
||||
Metacity is ideally a fully ICCCM and EWMH-compliant window manager.
|
||||
Reading these specifications is a useful first step to understanding
|
||||
the role of a window manager on an X11 desktop and the standards and
|
||||
conventions on which X11 desktops are based. Please refer to the
|
||||
COMPLIANCE file for additional information on these specifications and
|
||||
metacity's compliance therewith.
|
||||
|
@@ -1,4 +1,5 @@
|
||||
|
||||
SUBDIRS=src
|
||||
SUBDIRS=src po doc
|
||||
|
||||
EXTRA_DIST=HACKING
|
||||
EXTRA_DIST=HACKING rationales.txt \
|
||||
intltool-extract.in intltool-merge.in intltool-update.in
|
||||
|
216
NEWS
216
NEWS
@@ -0,0 +1,216 @@
|
||||
2.7.1
|
||||
===
|
||||
|
||||
Thanks to Rob Adams for fixes in this release.
|
||||
|
||||
- bug #122016 - fix a focus race
|
||||
- Change move_to_workspace_left/right/up/down keybindings to
|
||||
<Control><Alt><Shift> arrow to avoid conflicting with new
|
||||
keybindings in spacial nautilus.
|
||||
- fix dialog stacking order issues so e.g. panel properties
|
||||
dialog is above the panel
|
||||
|
||||
2.7.0
|
||||
===
|
||||
|
||||
First unstable release tarball for GNOME 2.6.
|
||||
|
||||
Thanks to Anders Carlsson, Elijah Newren, Rob Adams, James Cape,
|
||||
Thomas Fitzimmons, Calum Benson for fixes in this release.
|
||||
|
||||
2.6.2
|
||||
===
|
||||
|
||||
Thanks to Yukihiro Nakai, Rached Ben Mustapha, Gwenole Beauchesne,
|
||||
Padraig O'Briain, Laurent Vivier, Rob Adams for contributions to this
|
||||
release.
|
||||
|
||||
- fix to repaint after resize always, so on maximize
|
||||
and theme changes we get things drawn properly
|
||||
- fix a compile issue on HPUX
|
||||
- fix translations of metacity-message output
|
||||
- fix to update window icons when they change
|
||||
- put a limit on number of characters displayed in
|
||||
window titles during Alt+tab
|
||||
- fix configure check for Xrandr
|
||||
- fix 64-bit bug in property reading that broke
|
||||
things badly on 64-bit
|
||||
- don't move focus when clicking close button on a window
|
||||
- fix a crash in getting pixmap icons
|
||||
- spawn dialogs and child processes on the proper
|
||||
screen in multihead situations
|
||||
- if the focus gets set to None, set it back to
|
||||
something sane
|
||||
- load accessibility modules and set accessibility roles
|
||||
- fix hang after displaying warning dialogs
|
||||
- fix a memory corruption when sticking/unsticking windows
|
||||
that lead to a frequent crash and windows appearing
|
||||
in Alt+tab improperly
|
||||
- fix some handling of partial-width panel struts
|
||||
- more translations
|
||||
|
||||
2.6.1
|
||||
===
|
||||
|
||||
- rebuild with fixed glib-gettext.m4
|
||||
|
||||
2.6.0
|
||||
===
|
||||
|
||||
- some additional translations
|
||||
|
||||
2.5.5
|
||||
===
|
||||
|
||||
Thanks to Rob Adams, Arvind Samptur, Andreas Volz, Ray Strode, John
|
||||
Paul Wallington, Soeren Sandmann for contributions to this release.
|
||||
And as always thanks to the translators.
|
||||
|
||||
- fix aspect ratio handling
|
||||
- fix "shake loose" functionality for maximized windows
|
||||
- handle Xrandr size changes properly again
|
||||
- fix fullscreen window detection
|
||||
- fix workspace name handling
|
||||
- don't steal button press events on root window
|
||||
- nuke metacity.spec due to nonmaintenance
|
||||
- allow too-large-for-screen windows to move their titlebar offscreen
|
||||
- keep an MRU list of windows per-workspace and use it to focus
|
||||
the next window when the focused window disappears
|
||||
- fix cursor when moving
|
||||
- improve appearance of opaque resize
|
||||
- make BELOW window state work
|
||||
- fix a crash when gdk_pixmap_foreign_new() returned NULL
|
||||
|
||||
2.5.3
|
||||
===
|
||||
|
||||
Thanks to Jordi Mallach, Padraig O'Briain, Rob Adams, Julio Merino,
|
||||
Ben Jansens, Jurg Billeter, Ray Strode, marcus@freebsd.org, James
|
||||
Laska, for contributions to this release. Thanks also to
|
||||
all the tireless translators.
|
||||
|
||||
- fixups to .desktop file
|
||||
- activate window prior to grab end, avoiding
|
||||
extra focus events
|
||||
- add support for partial-width panels (fixes corner panel
|
||||
and xinerama window position constraints)
|
||||
- added keybinding to toggle window as "always on top"
|
||||
- support --disable-schemas-install option to configure
|
||||
- destroy support for legacy GNOME 1.x hints; metacity
|
||||
no longer works with GNOME 1.x
|
||||
- disable raise-on-click for mouse focus modes
|
||||
- fix bug that broke many Javascript popup menus with mozilla
|
||||
- allow "shaking loose" maximized windows, to move them
|
||||
between Xinerama heads or whatever
|
||||
- honor desktop-wide double click timeout
|
||||
- handle window placement properly for windows that
|
||||
start out maximized
|
||||
- integrate Ximian patch to go ahead and log out after 4 minutes
|
||||
even if a dialog is open
|
||||
- fix a segfault
|
||||
- fix bug where window groups weren't always kept up to date
|
||||
- fix bug where focus got confused when switching workspaces
|
||||
with mouse focus mode
|
||||
- fix 64-bit crash on s390x
|
||||
- chdir to user's homedir on startup
|
||||
- keep window in fullscreen layer when its transients are focused
|
||||
- fix keybindings bug when you had ScrollLock enabled
|
||||
- many translation updates
|
||||
|
||||
2.5.2
|
||||
===
|
||||
|
||||
Thanks to David Santiago, Julien Olivier, Anders Carlsson, Rob Adams
|
||||
for fixes in this release.
|
||||
|
||||
- improved wording/UI for some dialogs
|
||||
- while clicking a window button, if you move the mouse outside
|
||||
the button such that releasing the mouse button won't activate
|
||||
the window button, visually indicate by "popping out" the button.
|
||||
- fix some valgrind errors
|
||||
- change "show desktop mode" to convert to "everything is minimized
|
||||
mode" if you open a new window while showing desktop, rather
|
||||
than previous behavior of simply leaving show desktop mode.
|
||||
- fix a trivial memory leak
|
||||
- change "move to workspace N" so it doesn't switch workspaces,
|
||||
just moves the window.
|
||||
- translation updates
|
||||
|
||||
2.5.1
|
||||
===
|
||||
|
||||
Thanks to Rob Adams, Peter O'Shea, Dafydd Harries, Masahiro Sakai,
|
||||
Soeren Sandmann for fixes in this release.
|
||||
|
||||
- fix bug where fullscreen windows were below top panels
|
||||
- build fix for Solaris
|
||||
- support diagonal window movement with numeric keypad
|
||||
- multihead fix
|
||||
- build fix for Cygwin
|
||||
- place on xinerama containing the pointer
|
||||
- fix totally hosed window placement/movement for frameless
|
||||
windows
|
||||
- improvement to smoothness of window move/resize
|
||||
|
||||
2.5.0
|
||||
===
|
||||
|
||||
Thanks to Rob Adams, Owen Taylor, Frederic Crozat, Arvind Samptur,
|
||||
Bill Haneman, Akira Tagoh for help with fixes in this release.
|
||||
|
||||
- many new translations
|
||||
- fix an infinite loop while holding a server grab triggered by
|
||||
some recent Qt versions doing weird stuff
|
||||
- fix bug where Alt+rightclick repeatedly on titlebar resulted
|
||||
in zillions of menus
|
||||
- fix Alt+Tab to *actually* put minimized windows at the end,
|
||||
though this was always intended
|
||||
- rewrite size/positions constraint code (currently known
|
||||
to be quite buggy, e.g. xmms is hosed)
|
||||
- enforce size of at least 1x1 on windows
|
||||
- reduce latency of managing new windows still further
|
||||
by using async properties code in more places
|
||||
- don't grab keybindings on docks, so gnome-panel
|
||||
can handle them
|
||||
- suck in the panel's screenshot and run dialog global
|
||||
bindings
|
||||
- lots of improvements to window placement
|
||||
- sync max number of workspaces with pager applet
|
||||
- fix to keep focus when inside window frame in
|
||||
strict mouse focus mode
|
||||
- make it possible to start a reverse tab with
|
||||
shift+alt+tab (vs. alt+tab then shift)
|
||||
- fix a multihead issue with constraints between two
|
||||
windows on different heads
|
||||
- require GTK+ 2.2.0 and fontconfig
|
||||
- default theme is now Simple
|
||||
- add visual bell feature
|
||||
- incorporate many fixes from 2.4.34
|
||||
- other stuff
|
||||
|
||||
2.4.13
|
||||
===
|
||||
|
||||
- we were making all dialogs skip the taskbar, even non-transient
|
||||
ones, though this was supposedly fixed a while ago. Now really
|
||||
fixed.
|
||||
- change back to Alt+click by default for the window drag feature.
|
||||
- assign Alt+F12 to shade window
|
||||
- fix not deleting enough workspaces when the number
|
||||
was reduced via the pager config dialog (readams@hmc.edu)
|
||||
- don't allow windows under the top panel ever, even if they
|
||||
are tall windows (Arvind)
|
||||
- fix up the window layout for directional workspace nav,
|
||||
so you always stop at the edges and always end up
|
||||
where you expect (hp, with tweaks from readams@hmc.edu)
|
||||
- focus new windows in mouse focus mode (readams@hmc.edu)
|
||||
- support xeyes, oclock, etc. by applying shape mask
|
||||
to the window manager frame (yeah it resizes slow, deal)
|
||||
- fix vertical/horizontal maximize
|
||||
- handle crossing events resizing for more opaque resize goodness
|
||||
(Soeren)
|
||||
- add wacky _METACITY_UPDATE_COUNTER experimental extension
|
||||
to do nice opaque resizing (does nothing without a GTK patch)
|
||||
- fix a crash setting workspace names
|
||||
- fix internationalized WM_NAME reading
|
||||
|
||||
|
536
README
536
README
@@ -3,28 +3,72 @@ Meta-ness as in the state of being meta. i.e. metacity : meta as
|
||||
opacity : opaque. Also it may have something to do with the Meta key
|
||||
on UNIX keyboards.
|
||||
|
||||
The first release of Metacity is version 2.3. Metacity has no need for
|
||||
The first release of Metacity was version 2.3. Metacity has no need for
|
||||
your petty hangups about version numbers.
|
||||
|
||||
The stable releases so far are 2.4.x, 2.6.x
|
||||
|
||||
Unstable branches are 2.3.x, 2.5.x
|
||||
|
||||
COMPILING METACITY
|
||||
===
|
||||
|
||||
You need GTK+ 1.3.x (to become 2.0). At the moment CVS HEAD is
|
||||
required. Once 1.3.7 is available that will probably work. Metacity is
|
||||
a fairly trivial 6000-line C program, so once you get GTK+ built it
|
||||
should be no problem to build Metacity.
|
||||
You need GTK+ 2.2. For startup notification to work you need
|
||||
libstartup-notification at
|
||||
http://www.freedesktop.org/software/startup-notification/ or on the
|
||||
GNOME ftp site. You also need GConf 1.2 (unless building a funky
|
||||
extra-small embedded metacity with --disable-gconf, see below).
|
||||
|
||||
REPORTING BUGS AND SUBMITTING PATCHES
|
||||
===
|
||||
|
||||
Report new bugs to hp@redhat.com for now. Will switch to Bugzilla
|
||||
sometime probably.
|
||||
Report new bugs on http://bugzilla.gnome.org. Please check for
|
||||
duplicates, *especially* if you are reporting a feature request.
|
||||
|
||||
Feel free to send patches too; Metacity is really small and simple, so
|
||||
if you find a bug or want to add a feature it should be pretty easy.
|
||||
Please do *not* add "me too!" or "yes I really want this!" comments to
|
||||
feature requests in bugzilla. Please read
|
||||
http://pobox.com/~hp/features.html prior to adding any kind of flame
|
||||
about missing features or misfeatures.
|
||||
|
||||
Feel free to send patches too; Metacity is relatively small and
|
||||
simple, so if you find a bug or want to add a feature it should be
|
||||
pretty easy. Send me mail, or put the patch in bugzilla.
|
||||
|
||||
See the HACKING file for some notes on hacking Metacity.
|
||||
|
||||
SHRINKING METACITY
|
||||
===
|
||||
|
||||
Not that metacity is huge, but a substantial amount of code is in
|
||||
preferences handling, in static strings that aren't essential, and in
|
||||
the theme engine.
|
||||
|
||||
You can strip about 70K from the metacity binary by compiling with
|
||||
options such as:
|
||||
|
||||
--disable-gconf
|
||||
--disable-sm
|
||||
--disable-verbose
|
||||
--disable-startup-notification
|
||||
|
||||
However the result is no good for desktop use, all prefs have to be
|
||||
hardcoded in the binary, for example. If you wanted to make a really
|
||||
small metacity, here's some additional stuff you might consider
|
||||
implementing:
|
||||
|
||||
- add --disable-themes, which would replace theme.c and theme-parser.c
|
||||
with a hardcoded implementation of the interface in theme.h,
|
||||
should save about 80K. This should be fairly easy.
|
||||
|
||||
- add --disable-gtk, which would implement the interface in ui.h
|
||||
without using GTK. This one is easier than you think because the
|
||||
main part of the window manager doesn't use GTK directly, but is
|
||||
still fairly hard to do. You would probably have to give up some
|
||||
of the features, such as window menus, as menus are pretty complex
|
||||
to implement well. So time may be better spent adding a GTK
|
||||
configure script feature to build GTK with only a small core set of
|
||||
functionality.
|
||||
|
||||
METACITY FEATURES
|
||||
===
|
||||
|
||||
@@ -34,16 +78,62 @@ METACITY FEATURES
|
||||
- Uses GTK+ 2.0 for drawing window frames. This means colors, fonts,
|
||||
etc. come from GTK+ theme.
|
||||
|
||||
- There are 6 workspaces.
|
||||
- Does not expose the concept of "window manager" to the user. Some
|
||||
of the features in the GNOME control panel and other parts of the
|
||||
desktop happen to be implemented in metacity, such as changing your
|
||||
window border theme, or changing your window navigation shortcuts,
|
||||
but the user doesn't need to know this.
|
||||
|
||||
- Global keybindings:
|
||||
Alt-F1 to Alt-F6 switch workspaces
|
||||
Alt-1 to Alt-6 switch workspaces
|
||||
Alt-Tab forward cycle window focus
|
||||
Alt-Shift-Tab backward cycle focus
|
||||
Alt-Escape focus previous window
|
||||
- Includes only the window manager; does not try to be a desktop
|
||||
environment. The pager, configuration, etc. are all separate and
|
||||
modular. The "libwnck" library (which I also wrote) is available
|
||||
for writing metacity extensions, pagers, and so on. (But libwnck
|
||||
isn't metacity specific, or GNOME-dependent; it requires only GTK,
|
||||
and should work with KWin, fvwm2, and other EWMH-compliant WMs.)
|
||||
|
||||
- Has a simple theme system and a couple of extra themes come with it.
|
||||
Change themes via gconf-editor or gconftool or GNOME themes control
|
||||
panel:
|
||||
gconftool-2 --type=string --set /apps/metacity/general/theme Crux
|
||||
gconftool-2 --type=string --set /apps/metacity/general/theme Gorilla
|
||||
gconftool-2 --type=string --set /apps/metacity/general/theme Atlanta
|
||||
gconftool-2 --type=string --set /apps/metacity/general/theme Bright
|
||||
|
||||
See theme-format.txt for docs on the theme format. Use
|
||||
metacity-theme-viewer to preview themes.
|
||||
|
||||
- Change number of workspaces via gconf-editor or gconftool:
|
||||
gconftool-2 --type=int --set /apps/metacity/general/num_workspaces 5
|
||||
|
||||
Can also change workspaces from GNOME 2 pager.
|
||||
|
||||
- Change focus mode:
|
||||
gconftool-2 --type=string --set /apps/metacity/general/focus_mode mouse
|
||||
gconftool-2 --type=string --set /apps/metacity/general/focus_mode sloppy
|
||||
gconftool-2 --type=string --set /apps/metacity/general/focus_mode click
|
||||
|
||||
- Global keybinding defaults include:
|
||||
|
||||
Alt-Tab forward cycle window focus
|
||||
Alt-Shift-Tab backward cycle focus
|
||||
Alt-Ctrl-Tab forward cycle focus among panels
|
||||
Alt-Ctrl-Shift-Tab backward cycle focus among panels
|
||||
Alt-Escape cycle window focus without a popup thingy
|
||||
Ctrl-Alt-Left Arrow previous workspace
|
||||
Ctrl-Alt-Right Arrow next workspace
|
||||
Ctrl-Alt-D minimize/unminimize all, to show desktop
|
||||
|
||||
Change keybindings for example:
|
||||
|
||||
unst gconftool-2 --type=string --set /apps/metacity/global_keybindings/switch_to_workspace_1 '<Alt>F1'
|
||||
|
||||
Also try the GNOME keyboard shortcuts control panel, or
|
||||
gconf-editor.
|
||||
|
||||
See metacity.schemas for all available bindings.
|
||||
|
||||
- Window keybindings:
|
||||
|
||||
Alt-space window menu
|
||||
|
||||
Mnemonics work in the menu. That is, Alt-space then underlined
|
||||
@@ -55,7 +145,11 @@ METACITY FEATURES
|
||||
Shift to snap to edges.
|
||||
|
||||
Choose Resize from menu, and nothing happens yet, but
|
||||
eventually I might implement something.
|
||||
eventually I might implement something.
|
||||
|
||||
Keybindings for things like maximize window, vertical maximize,
|
||||
etc. can be bound, but may not all exist by default. See
|
||||
metacity.schemas.
|
||||
|
||||
- Window mouse bindings:
|
||||
|
||||
@@ -70,14 +164,15 @@ METACITY FEATURES
|
||||
If you click and drag the titlebar with button 1 it moves the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 2 it moves the window,
|
||||
without raising it.
|
||||
If you click anywhere on the frame with button 2 it lowers the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 3 it shows the
|
||||
window menu.
|
||||
|
||||
If you hold down Alt and click inside a window, it will move the
|
||||
window (buttons 1 and 2) or show menu (button 3).
|
||||
If you hold down Super (windows key) and click inside a window, it
|
||||
will move the window (buttons 1 and 2) or show menu (button 3).
|
||||
Or you can configure a different modifier for this.
|
||||
|
||||
If you pick up a window with button 1 and then switch workspaces
|
||||
the window will come with you to the new workspace, this is
|
||||
@@ -92,225 +187,109 @@ METACITY FEATURES
|
||||
be respawned. It theoretically restores sizes/positions/workspace
|
||||
for session-aware applications.
|
||||
|
||||
- Here is an example of how you can configure the Metacity
|
||||
window border appearance in ~/.gtkrc-2.0:
|
||||
|
||||
style "metacity-style"
|
||||
{
|
||||
font_name = "Sans 16"
|
||||
MetaFrames::title_border = { 7, 7, 7, 7 }
|
||||
MetaFrames::button_width = 25
|
||||
bg[NORMAL] = { 0.0, 0.0, 0.0 }
|
||||
}
|
||||
|
||||
class "MetaFrames" style "metacity-style"
|
||||
|
||||
You get the idea. It is just your basic GTK+ rc file, the
|
||||
window borders are a widget called MetaFrames,
|
||||
look in frames.c:meta_frames_class_init() for all the style
|
||||
properties that you can configure.
|
||||
|
||||
Metacity-specific styles can also be included in any GTK+
|
||||
theme.
|
||||
|
||||
- Metacity implements much of the new window manager spec from
|
||||
freedesktop.org, and much of the ICCCM. But then there are
|
||||
parts of each that it doesn't implement, just because I haven't
|
||||
yet.
|
||||
- Metacity implements much of the EWMH window manager specification
|
||||
from freedesktop.org, as well as the older ICCCM. Please refer to
|
||||
the COMPLIANCE file for information on metacity compliance with
|
||||
these standards.
|
||||
|
||||
- Uses Pango to render text, so has cool i18n capabilities.
|
||||
Supports UTF-8 window titles and such.
|
||||
|
||||
- There are simple animations for actions such as minimization,
|
||||
to help users see what is happening. Should probably
|
||||
have a few more of these and make them nicer.
|
||||
|
||||
- if you have the proper X setup, set the GDK_USE_XFT=1
|
||||
environment variable to get antialiased window titles.
|
||||
|
||||
- considers the panel when placing windows and maximizing
|
||||
them.
|
||||
|
||||
- handles the window manager selection from the ICCCM. Will exit if
|
||||
another WM claims it, and can claim it from another WM if you pass
|
||||
the --replace argument. So if you're running another
|
||||
ICCCM-compliant WM, you can run "metacity --replace" to replace it
|
||||
with Metacity.
|
||||
|
||||
- does basic colormap handling
|
||||
|
||||
- and much more! well, maybe not a lot more.
|
||||
|
||||
HOW TO ADD EXTERNAL FEATURES
|
||||
===
|
||||
|
||||
You can write a metacity "plugin" such as a pager, window list, icon
|
||||
box, task menu, or even things like "window matching" using the
|
||||
Extended Window Manager Hints. See http://www.freedesktop.org for the
|
||||
EWMH specification. An easy-to-use library called "libwnck" is
|
||||
available that uses the EWMH and is specifically designed for writing
|
||||
WM accessories.
|
||||
|
||||
You might be interested in existing accessories such as "Devil's Pie"
|
||||
by Ross Burton, which add features to Metacity (or other
|
||||
EWMH-compliant WMs).
|
||||
|
||||
METACITY BUGS, NON-FEATURES, AND CAVEATS
|
||||
===
|
||||
|
||||
- Metacity creates a big file in your home directory called
|
||||
~/metacity.log with a bunch of debug spew.
|
||||
|
||||
- If you want a number of workspaces which is not 6, you have to
|
||||
edit screen.c and recompile.
|
||||
|
||||
- If you want keybindings which are not the ones mentioned above
|
||||
as features, you have to edit keybindings.c and recompile.
|
||||
|
||||
- Metacity does not have any way to unminimize a window. So
|
||||
clicking the minimize button is sort of a bad idea.
|
||||
(If you had a WM-spec-compliant tasklist, it would work
|
||||
for unminimization.)
|
||||
|
||||
- Metacity uses the new window manager spec, but only random bits of
|
||||
the old GNOME spec. It correctly advertises exactly which parts of
|
||||
the GNOME spec it supports, but it does not support enough of it to
|
||||
make the GNOME task list and desk guide happy, and they do not
|
||||
support the new spec. I don't want anyone to spend time sending me
|
||||
patches to support the old GNOME spec in Metacity; instead, send
|
||||
patches to the task list and desk guide to support the new spec. As
|
||||
far as I know, Metacity does support enough of the new spec to
|
||||
allow a working tasklist and pager.
|
||||
|
||||
Upshot: task list and desk guide DO NOT WORK with Metacity.
|
||||
|
||||
- Metacity turns off its keybindings for Emacs, because I use
|
||||
Alt-space in Emacs, and getting a window menu annoys me.
|
||||
This is a broken feature. My planned fix is to use super/hyper
|
||||
instead of Alt as the main keybinding shortcut, if super/hyper
|
||||
exist, and then keyboards with a windows key can use that for
|
||||
WM functions and Alt for application shortcuts.
|
||||
We'd fall back to Alt if no other suitable modifier existed.
|
||||
|
||||
- Cycling windows with Alt-Tab is flickery, AFAIK because
|
||||
Metacity passes the entire window stack to XRestackWindows()
|
||||
every time you restack. Instead it should probably only restack
|
||||
windows that have changed their stacking with respect to one
|
||||
another. (But sometimes I don't see the flicker, so
|
||||
I'm not sure.)
|
||||
|
||||
- Various operations, such as minimize, maximize, etc., should
|
||||
have simple animations to make them clearer to users.
|
||||
|
||||
- I haven't even read the ICCCM section about colormaps. So if you
|
||||
have an 8-bit display you are basically screwed.
|
||||
|
||||
- Metacity doesn't properly claim the window manager selection
|
||||
as described in the ICCCM. But then, most other window managers
|
||||
don't handle this correctly either.
|
||||
|
||||
- There are probably other ICCCM-compliance issues.
|
||||
|
||||
- I know there's at least one race condition involving rapidly
|
||||
created and destroyed windows that will crash Metacity. I think a
|
||||
small test app that did a lot of rapid show/hide on a GtkWindow,
|
||||
in combination with the METACITY_SYNC environment variable and
|
||||
Metacity in a debugger, would turn this up quickly.
|
||||
|
||||
- Window placement is always cascade for now; I want to implement
|
||||
"first fit, falling back to cascade if no fit."
|
||||
(Configurable placement algorithms are stupid though, don't
|
||||
send me patches for any bogus ones. Let's just pick a good one.)
|
||||
|
||||
- Maximization and movement constraints do not take the
|
||||
GNOME panel into account. Most of the code already handles
|
||||
this (using workspace->workarea in workspace.h), but
|
||||
workspace->workarea isn't ever actually calculated.
|
||||
Metacity needs to keep this area up-to-date using the hints the
|
||||
panel sets.
|
||||
|
||||
- Should support click-to-focus as an option.
|
||||
|
||||
- Windows has a neat way of implementing Alt-Tab for
|
||||
window cycling that I would like to copy. (The little
|
||||
popup window thing.)
|
||||
|
||||
- People seem to like shortcuts using arrow keys for moving
|
||||
between workspaces. My only question here is that I'm not sure
|
||||
what the spatial relationship between workspaces is.
|
||||
(Are they in a grid, or a horizontal row, or what.)
|
||||
I think we may need a window manager spec extension to
|
||||
share this information between the WM and the pager.
|
||||
We could add left/right arrow and pretend they're in
|
||||
a row for the short term though.
|
||||
|
||||
- Should Metacity support flipping in right-to-left locales?
|
||||
I don't know what window managers look like in a right-to-left
|
||||
locale. I assume the window titles should be right-justified;
|
||||
should the window controls also be flipped?
|
||||
|
||||
- Need keyboard shortcuts for hide/show desktop (minimize/unminimize
|
||||
all windows temporarily, basically, and focus desktop); also
|
||||
for focusing dock windows (though since current GNOME panel has
|
||||
no useful keynav, this doesn't get you far at the moment).
|
||||
|
||||
- Resize menu item doesn't do anything. It's intended to enter
|
||||
resize-with-the-keyboard mode, similar to Move menu item.
|
||||
|
||||
- I haven't set up the po subdir and translations, mostly because
|
||||
autotools seem to get all confused if you set these up but
|
||||
don't actually have any translations. So if someone translates
|
||||
something we can set it up.
|
||||
|
||||
- If you switch from sawfish to metacity without restarting X,
|
||||
the panel often ends up buried behind the Nautilus desktop window.
|
||||
|
||||
What happens is that the panel detects Sawfish has gone away, and
|
||||
turns on override redirect mode because no GNOME-aware WM is
|
||||
running (i.e. it goes into "ignore the window manager" mode). But
|
||||
the panel doesn't notice that Metacity has appeared and is
|
||||
(partially) GNOME-compliant. So Metacity doesn't see the override
|
||||
redirect panel, and leaves it behind the Nautilus desktop. I'm not
|
||||
sure whether Metacity or the panel is to blame for this.
|
||||
|
||||
(To debug - use "xwininfo" on the panel, if override redirect is
|
||||
"Yes" then Metacity won't have any awareness of a window and can't
|
||||
properly stack it above the desktop. If override redirect is "No"
|
||||
then Metacity can see the panel and handle it properly. Look at
|
||||
xstuff.c:xstuff_is_compliant_wm() in the panel to get started on
|
||||
how the panel deals with this.)
|
||||
See bugzilla: http://bugzilla.gnome.org/query.cgi
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
Q: Will you add my feature?
|
||||
|
||||
A: If it makes sense to turn on unconditionally,
|
||||
or is genuinely a harmless preference that I would not
|
||||
be embarrassed to put in a simple, uncluttered, user-friendly
|
||||
configuration dialog.
|
||||
A: If it makes sense to turn on unconditionally, or is genuinely a
|
||||
harmless preference that I would not be embarrassed to put in a
|
||||
simple, uncluttered, user-friendly configuration dialog.
|
||||
|
||||
If the only rationale for your feature is that other window
|
||||
managers have it, or that you are personally used to it, or something
|
||||
like that, then I will not be impressed. Metacity is firmly in the
|
||||
"choose good defaults" camp rather than the "offer 6 equally broken
|
||||
ways to do it, and let the user pick one" camp.
|
||||
managers have it, or that you are personally used to it, or
|
||||
something like that, then I will not be impressed. Metacity is
|
||||
firmly in the "choose good defaults" camp rather than the "offer 6
|
||||
equally broken ways to do it, and let the user pick one" camp.
|
||||
|
||||
This is part of a "no crackrock" policy, despite some exceptions
|
||||
I'm mildly embarrassed about. For example, multiple workspaces
|
||||
probably constitute crackrock, they confuse most users
|
||||
and really are not that useful if you have a decent tasklist and
|
||||
so on. But I am too used to them to turn them off.
|
||||
Sloppy focus is probably crackrock too. Oh, and my Alt-1 thru Alt-6
|
||||
keybindings are definitely on crack.
|
||||
probably constitute crackrock, they confuse most users and really
|
||||
are not that useful if you have a decent tasklist and so on. But I
|
||||
am too used to them to turn them off. Or alternatively
|
||||
iconification/tasklist is crack, and workspaces/pager are good. But
|
||||
having both is certainly a bit wrong. Sloppy focus is probably
|
||||
crackrock too.
|
||||
|
||||
But don't think unlimited crack is OK just because I slipped up a
|
||||
little. No slippery slope here.
|
||||
little. No slippery slope here.
|
||||
|
||||
Don't let this discourage patches and fixes - I love those. ;-)
|
||||
Just be prepared to hear the above objections if your patch
|
||||
adds some crack-ridden configuration option.
|
||||
Just be prepared to hear the above objections if your patch adds
|
||||
some crack-ridden configuration option.
|
||||
|
||||
Q: How do I add a configuration option?
|
||||
|
||||
A: You don't, until GConf 2 is relatively easy to compile and I feel
|
||||
like adding it as a dependency.
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Will Metacity be part of GNOME?
|
||||
|
||||
A: This is not the current plan, though of course I'm happy to see the
|
||||
code used by anyone who's interested. Metacity may continue to suck
|
||||
forever because I might get tired of working on it; or Metacity's
|
||||
feature set might not make sense for GNOME. Who knows.
|
||||
|
||||
For now Metacity is my toy hobby project that I work on when I feel
|
||||
like it.
|
||||
A: It is officially part of GNOME as of GNOME 2.2. Prior to that,
|
||||
it was unofficially shipped as the default GNOME WM by several
|
||||
OS vendors.
|
||||
|
||||
Q: Is Metacity a Red Hat project?
|
||||
|
||||
A: Metacity is in no way funded, endorsed, or encouraged by Red Hat,
|
||||
Inc. - I'm guessing Red Hat would not consider "insufficient number
|
||||
of window managers for Linux" an urgent problem. Just a wild guess
|
||||
though.
|
||||
A: Metacity's original creation was in no way funded, endorsed, or
|
||||
encouraged by Red Hat, Inc. - I'm guessing Red Hat would not
|
||||
consider "insufficient number of window managers for Linux" an
|
||||
urgent problem. Just a wild guess though.
|
||||
|
||||
Now that metacity is the default WM however, Red Hat supports some
|
||||
bugfixing and other work.
|
||||
|
||||
Q: Why can't I move XMMS?
|
||||
|
||||
A: Because XMMS is broken and is trying to move itself. Metacity
|
||||
does not tolerate insolent windows who believe they can
|
||||
self-manage. Use Alt-button1 to move XMMS using Metacity.
|
||||
|
||||
Q: Why does Metacity remember the workspace/position of some apps
|
||||
but not others?
|
||||
but not others across logout/login?
|
||||
|
||||
A: Metacity only stores sizes/positions for apps that are session
|
||||
managed. As far as I can determine, there is no way to attempt
|
||||
to remember workspace/position for non-session-aware apps without
|
||||
A: Metacity only stores sizes/positions for apps that are session
|
||||
managed. As far as I can determine, there is no way to attempt to
|
||||
remember workspace/position for non-session-aware apps without
|
||||
causing a lot of weird effects.
|
||||
|
||||
The reason is that you don't know which non-SM-aware apps were
|
||||
@@ -349,17 +328,144 @@ A: I could conceivably be convinced to use viewports _instead_ of
|
||||
think it makes any sense to have both; it's just confusing. They
|
||||
are functionally equivalent.
|
||||
|
||||
You may think this means that you won't have certain keybindings,
|
||||
or something like that. This is a misconception. The only
|
||||
_fundamental_ difference between viewports and workspaces is that
|
||||
with viewports, windows can "overlap" and appear partially on
|
||||
one and partially on another. All other differences that
|
||||
traditionally exist in other window managers are accidental -
|
||||
the features commonly associated with viewports can be implemented
|
||||
for workspaces, and vice versa.
|
||||
|
||||
So I don't want to have two kinds of
|
||||
workspace/desktop/viewport/whatever, but I'm willing to add
|
||||
features traditionally associated with either kind if those
|
||||
features make sense.
|
||||
|
||||
Q: Why is the panel always on top?
|
||||
|
||||
A: Because it's a better user interface, and until we made this not
|
||||
configurable a bunch of apps were not getting fixed (the app
|
||||
authors were just saying "put your panel on the bottom" instead of
|
||||
properly supporting fullscreen mode, and such).
|
||||
|
||||
rationales.txt has the bugzilla URL for some flamefesting on this,
|
||||
if you want to go back and relive the glory.
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why is there no edge flipping?
|
||||
|
||||
A: This one is also in rationales.txt. Because "ouija board" UI, where
|
||||
you just move the mouse around and the computer guesses what you
|
||||
mean, has a lot of issues. This includes mouse focus, shade-hover
|
||||
mode, edge flipping, autoraise, etc. Metacity has mouse focus and
|
||||
autoraise as a compromise, but these features are all confusing for
|
||||
many users, and cause problems with accessibility, fitt's law, and
|
||||
so on.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why does wireframe move/resize suck?
|
||||
|
||||
A: You can turn it on with the reduced_resources setting.
|
||||
|
||||
But: it has low usability, and is a pain
|
||||
to implement, and there's no reason opaque move/resize should be a
|
||||
problem on any setup that can run a modern desktop worth a darn to
|
||||
begin with.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
The reason we had to add wireframe anyway was broken
|
||||
proprietary apps that can't handle lots of resize events.
|
||||
|
||||
Q: Why no XYZ?
|
||||
|
||||
A: You are probably getting the idea by now - check rationales.txt,
|
||||
query/search bugzilla, and read http://pobox.com/~hp/features.html
|
||||
and http://pobox.com/~hp/free-software-ui.html
|
||||
|
||||
Then sit down and answer the question for yourself. Is the feature
|
||||
good? What's the rationale for it? Answer "why" not just "why not."
|
||||
Justify in terms of users as a whole, not just users like
|
||||
yourself. How else can you solve the same problem? etc. If that
|
||||
leads you to a strong opinion, then please, post the rationale for
|
||||
discussion to an appropriate bugzilla bug, or to
|
||||
usability@gnome.org.
|
||||
|
||||
Please don't just "me too!" on bugzilla bugs, please don't think
|
||||
flames will get you anywhere, and please don't repeat rationale
|
||||
that's already been offered.
|
||||
|
||||
Q: Your dumb web pages you made me read talk about solving problems in
|
||||
fundamental ways instead of adding preferences or workarounds.
|
||||
What are some examples where metacity has done this?
|
||||
|
||||
A: There are quite a few, though many opportunities remain. Sometimes
|
||||
the real fix involves application changes. The metacity approach is
|
||||
that it's OK to require apps to change, though there are also
|
||||
plenty of workarounds in metacity for battles considered too hard
|
||||
to fight.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- fullscreen mode was introduced to allow position constraints,
|
||||
panel-on-top, and other such things to apply to normal windows
|
||||
while still allowing video players etc. to "just work"
|
||||
|
||||
- "whether to include minimized windows in Alt+Tab" was solved
|
||||
by putting minimized windows at the *end* of the tab order.
|
||||
|
||||
- Whether to pop up a feedback display during Alt+Tab was solved by
|
||||
having both Alt+Tab and Alt+Esc
|
||||
|
||||
- Whether to have a "kill" feature was solved by automatically
|
||||
detecting and offering to kill stuck apps. Better, metacity
|
||||
actually does "kill -9" on the process, it doesn't just
|
||||
disconnect the process from the X server. You'll appreciate this
|
||||
if you ever did a "kill" on Netscape 4, and watched it keep
|
||||
eating 100% CPU even though the X server had booted it.
|
||||
|
||||
- The workspaces vs. viewports mess was avoided by adding
|
||||
directional navigation and such to workspaces, see discussion
|
||||
earlier in this file.
|
||||
|
||||
- Instead of configurable placement algorithms, there's just one
|
||||
that works fairly well most of the time.
|
||||
|
||||
- To avoid excess CPU use during opaque move/resize, we rate limit
|
||||
the updates to the application window's size.
|
||||
|
||||
- Instead of configurable "show size of window while resizing,"
|
||||
it's only shown for windows where it matters, such as terminals.
|
||||
(Only use-case given for all windows is for web designers
|
||||
choosing their web browser size, but there are web sites and
|
||||
desktop backgrounds that do this for you.)
|
||||
|
||||
- Using startup notification, applications open on the workspace
|
||||
where you launched them, not the active workspace when their
|
||||
window is opened.
|
||||
|
||||
- and much more.
|
||||
|
||||
Q: I think metacity sucks.
|
||||
|
||||
A: Feel free to use any WM you like. The reason metacity follows the
|
||||
ICCCM and EWMH specifications is that it makes metacity a modular,
|
||||
interchangeable part in the desktop. libwnck-based apps such as the
|
||||
GNOME window list will work just fine with any EWMH-compliant WM.
|
||||
|
||||
Q: Did you spend a lot of time on this?
|
||||
|
||||
A: Metacity is about 6000 lines of code, which took a few weekends and
|
||||
evenings to write. If it ever becomes more polished it will
|
||||
probably grow 2-3 more thousand lines of code and suck a few more
|
||||
weekends of time. If I started adding all kinds of features and
|
||||
crack-ridden configuration options, it might take more time than that.
|
||||
A: Originally the answer was no. Sadly the answer is now yes.
|
||||
|
||||
Q: How can you claim that you are anti-crack, while still
|
||||
writing a window manager?
|
||||
|
||||
A: I have no comment on that.
|
||||
|
||||
|
||||
|
12
acconfig.h
12
acconfig.h
@@ -1,12 +0,0 @@
|
||||
#undef PACKAGE
|
||||
#undef VERSION
|
||||
#undef HAVE_CATGETS
|
||||
#undef HAVE_GETTEXT
|
||||
#undef HAVE_LC_MESSAGES
|
||||
#undef HAVE_STPCPY
|
||||
#undef ENABLE_NLS
|
||||
#undef HAVE_PTHREAD_H
|
||||
#undef GETTEXT_PACKAGE
|
||||
#undef HAVE_SHAPE_EXT
|
||||
#undef HAVE_XFT
|
||||
#undef HAVE_SM
|
73
autogen.sh
73
autogen.sh
@@ -12,6 +12,14 @@ FILE=src/display.c
|
||||
|
||||
DIE=0
|
||||
|
||||
AUTOMAKE=automake-1.4
|
||||
ACLOCAL=aclocal-1.4
|
||||
|
||||
($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
|
||||
AUTOMAKE=automake
|
||||
ACLOCAL=aclocal
|
||||
}
|
||||
|
||||
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "You must have autoconf installed to compile $PROJECT."
|
||||
@@ -20,7 +28,7 @@ DIE=0
|
||||
DIE=1
|
||||
}
|
||||
|
||||
(automake --version) < /dev/null > /dev/null 2>&1 || {
|
||||
($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "You must have automake installed to compile $PROJECT."
|
||||
echo "Get ftp://sourceware.cygnus.com/pub/automake/automake-1.4.tar.gz"
|
||||
@@ -38,16 +46,29 @@ DIE=0
|
||||
}
|
||||
}
|
||||
|
||||
grep "^AM_GNU_GETTEXT" configure.in >/dev/null && {
|
||||
grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
|
||||
(gettext --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "**Error**: You must have \`gettext' installed to compile $PROJECT."
|
||||
echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
|
||||
echo "(or a newer version if it is available)"
|
||||
DIE=1
|
||||
}
|
||||
}
|
||||
CONFIGURE=configure.in
|
||||
if grep "^AM_[A-Z0-9_]\{1,\}_GETTEXT" "$CONFIGURE" >/dev/null; then
|
||||
if grep "sed.*POTFILES" "$CONFIGURE" >/dev/null; then
|
||||
GETTEXTIZE=""
|
||||
else
|
||||
if grep "^AM_GLIB_GNU_GETTEXT" "$CONFIGURE" >/dev/null; then
|
||||
GETTEXTIZE="glib-gettextize"
|
||||
GETTEXTIZE_URL="ftp://ftp.gtk.org/pub/gtk/v2.0/glib-2.0.0.tar.gz"
|
||||
else
|
||||
GETTEXTIZE="gettextize"
|
||||
GETTEXTIZE_URL="ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
|
||||
fi
|
||||
|
||||
$GETTEXTIZE --version < /dev/null > /dev/null 2>&1
|
||||
if test $? -ne 0; then
|
||||
echo
|
||||
echo "**Error**: You must have \`$GETTEXTIZE' installed to compile $PKG_NAME."
|
||||
echo "Get $GETTEXTIZE_URL"
|
||||
echo "(or a newer version if it is available)"
|
||||
DIE=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$DIE" -eq 1; then
|
||||
exit 1
|
||||
@@ -67,7 +88,7 @@ case $CC in
|
||||
*xlc | *xlc\ * | *lcc | *lcc\ *) am_opt=--include-deps;;
|
||||
esac
|
||||
|
||||
for coin in `find . -name configure.in -print`
|
||||
for coin in .
|
||||
do
|
||||
dr=`dirname $coin`
|
||||
if test -f $dr/NO-AUTO-GEN; then
|
||||
@@ -84,38 +105,38 @@ do
|
||||
## echo "**Warning**: No such directory \`$k'. Ignored."
|
||||
fi
|
||||
done
|
||||
if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then
|
||||
if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then
|
||||
if grep "sed.*POTFILES" configure.in >/dev/null; then
|
||||
: do nothing -- we still have an old unmodified configure.in
|
||||
else
|
||||
echo "Creating $dr/aclocal.m4 ..."
|
||||
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
|
||||
echo "Running gettextize... Ignore non-fatal messages."
|
||||
echo "no" | gettextize --force --copy
|
||||
echo "Running glib-gettextize... Ignore non-fatal messages."
|
||||
echo "no" | glib-gettextize --force --copy
|
||||
echo "Making $dr/aclocal.m4 writable ..."
|
||||
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
|
||||
fi
|
||||
fi
|
||||
if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then
|
||||
echo "Creating $dr/aclocal.m4 ..."
|
||||
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
|
||||
echo "Running gettextize... Ignore non-fatal messages."
|
||||
echo "no" | gettextize --force --copy
|
||||
echo "Making $dr/aclocal.m4 writable ..."
|
||||
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
|
||||
if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then
|
||||
echo "Running intltoolize..."
|
||||
intltoolize --force --copy --automake
|
||||
fi
|
||||
if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then
|
||||
echo "Running libtoolize..."
|
||||
libtoolize --force --copy
|
||||
fi
|
||||
echo "Running aclocal $aclocalinclude ..."
|
||||
aclocal $aclocalinclude
|
||||
|
||||
echo "Running $ACLOCAL $aclocalinclude ..."
|
||||
$ACLOCAL $aclocalinclude
|
||||
|
||||
if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
|
||||
echo "Running autoheader..."
|
||||
autoheader
|
||||
fi
|
||||
echo "Running automake --gnu $am_opt ..."
|
||||
automake --add-missing --gnu $am_opt
|
||||
|
||||
echo "Running $AUTOMAKE --gnu $am_opt ..."
|
||||
$AUTOMAKE --add-missing --gnu $am_opt
|
||||
|
||||
echo "Running autoconf ..."
|
||||
autoconf
|
||||
)
|
||||
|
396
configure.in
396
configure.in
@@ -1,21 +1,43 @@
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(src/display.c)
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
AM_INIT_AUTOMAKE(metacity, 2.3.1)
|
||||
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987
|
||||
# releases on a branch add a 4th version like 2.4.21.1
|
||||
AM_INIT_AUTOMAKE(metacity, 2.7.1)
|
||||
|
||||
# Honor aclocal flags
|
||||
ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
|
||||
|
||||
GETTEXT_PACKAGE=metacity
|
||||
AC_SUBST(GETTEXT_PACKAGE)
|
||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE")
|
||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain])
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_PROG_INTLTOOL([0.21])
|
||||
AC_PROG_CC
|
||||
AC_ISC_POSIX
|
||||
AC_HEADER_STDC
|
||||
AC_ARG_PROGRAM
|
||||
AC_LIBTOOL_WIN32_DLL
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
#### Integer sizes
|
||||
|
||||
AC_CHECK_SIZEOF(char)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(void *)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(__int64)
|
||||
|
||||
## byte order
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
#### Warnings
|
||||
|
||||
changequote(,)dnl
|
||||
if test "x$GCC" = "xyes"; then
|
||||
case " $CFLAGS " in
|
||||
@@ -23,6 +45,46 @@ if test "x$GCC" = "xyes"; then
|
||||
*) CFLAGS="$CFLAGS -Wall" ;;
|
||||
esac
|
||||
|
||||
# case " $CFLAGS " in
|
||||
# *[\ \ ]-Wshadow[\ \ ]*) ;;
|
||||
# *) CFLAGS="$CFLAGS -Wshadow" ;;
|
||||
# esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wnested-externs[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wnested-externs" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wpointer-arith[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wpointer-arith" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wcast-align[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wcast-align" ;;
|
||||
esac
|
||||
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wsign-compare[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wsign-compare" ;;
|
||||
esac
|
||||
|
||||
if test "x$enable_ansi" = "xyes"; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-ansi[\ \ ]*) ;;
|
||||
@@ -37,40 +99,344 @@ if test "x$GCC" = "xyes"; then
|
||||
fi
|
||||
changequote([,])dnl
|
||||
|
||||
ALL_LINGUAS=""
|
||||
dnl AM_GNU_GETTEXT
|
||||
METACITY_PC_MODULES='gtk+-2.0 >= 2.2.0 pango >= 1.2.0'
|
||||
|
||||
AC_ARG_ENABLE(config-dialog, [ --enable-config-dialog enable the config dialog that you need with GNOME 2.0 (obsolete with GNOME 2.2)],,enable_config_dialog=no)
|
||||
|
||||
AM_CONDITIONAL(BUILD_CONFIG_DIALOG, test x$enable_config_dialog = xyes)
|
||||
if test x$enable_config_dialog = xyes; then
|
||||
AC_DEFINE(BUILD_CONFIG_DIALOG,1,[Build configuration dialog])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(gconf, [ --disable-gconf disable gconf usage, for embedded/size-sensitive non-GNOME builds],,enable_gconf=yes)
|
||||
|
||||
if test x$enable_gconf = xyes; then
|
||||
AC_DEFINE(HAVE_GCONF,1,[Build with gconf support])
|
||||
METACITY_PC_MODULES="$METACITY_PC_MODULES gconf-2.0 >= 1.2.0"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(verbose-mode, [ --disable-verbose disable metacity's ability to do verbose logging, for embedded/size-sensitive custom builds],,enable_verbose_mode=yes)
|
||||
|
||||
if test x$enable_verbose_mode = xyes; then
|
||||
AC_DEFINE(WITH_VERBOSE_MODE,1,[Build with verbose mode support])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sm, [ --disable-sm disable metacity's session management support, for embedded/size-sensitive custom non-GNOME builds],,enable_sm=auto)
|
||||
|
||||
AC_ARG_ENABLE(startup-notification, [ --disable-startup-notification disable metacity's startup notification support, for embedded/size-sensitive custom non-GNOME builds],,enable_startup_notification=auto)
|
||||
|
||||
AC_ARG_ENABLE(compositor, [ --disable-compositor disable metacity's compositing manager],,enable_compositor=auto)
|
||||
|
||||
AC_ARG_ENABLE(xsync, [ --disable-xsync disable metacity's use of the XSync extension],,enable_xsync=auto)
|
||||
|
||||
AC_ARG_ENABLE(shape, [ --disable-shape disable metacity's use of the shaped window extension],,enable_shape=auto)
|
||||
|
||||
## try definining HAVE_BACKTRACE
|
||||
AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
|
||||
|
||||
ALL_LINGUAS="am ar az be bg bn ca cs cy da de el en_CA en_GB es fa fi fr ga gl he hi hr hu id is it ja ko lt lv mk ml mn ms nl nn no pl pt pt_BR ro ru sl sk sq sr sr@Latn sv ta th tr uk vi wa zh_CN zh_TW"
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
|
||||
## here we get the flags we'll actually use
|
||||
PKG_CHECK_MODULES(METACITY, gtk+-2.0 >= 1.3.6)
|
||||
PKG_CHECK_MODULES(METACITY_MESSAGE, gtk+-2.0 >= 2.2.0)
|
||||
PKG_CHECK_MODULES(METACITY_WINDOW_DEMO, gtk+-2.0 >= 2.2.0)
|
||||
|
||||
CFLAGS="$METACITY_CFLAGS $CFLAGS"
|
||||
if test x$enable_config_dialog = xyes; then
|
||||
PKG_CHECK_MODULES(METACITY_PROPS, gtk+-2.0 >= 2.2.0 gconf-2.0 >= 1.1.9 libglade-2.0)
|
||||
fi
|
||||
|
||||
found_sm=false
|
||||
if $PKG_CONFIG --atleast-version 1.2.0 pangoxft; then
|
||||
echo "pangoxft found"
|
||||
else
|
||||
AC_MSG_ERROR("Pango 1.2.0 or greater based on Xft2 is required")
|
||||
fi
|
||||
|
||||
STARTUP_NOTIFICATION_VERSION=0.4
|
||||
AC_MSG_CHECKING([Startup notification library >= $STARTUP_NOTIFICATION_VERSION])
|
||||
if $PKG_CONFIG --atleast-version $STARTUP_NOTIFICATION_VERSION libstartup-notification-1.0; then
|
||||
have_startup_notification=yes
|
||||
else
|
||||
have_startup_notification=no
|
||||
fi
|
||||
AC_MSG_RESULT($have_startup_notification)
|
||||
|
||||
if test x$enable_startup_notification = xyes; then
|
||||
have_startup_notification=yes
|
||||
echo "startup-notification support forced on"
|
||||
elif test x$enable_startup_notification = xauto; then
|
||||
true
|
||||
else
|
||||
have_startup_notification=no
|
||||
fi
|
||||
|
||||
if test x$have_startup_notification = xyes; then
|
||||
echo "Building with libstartup-notification"
|
||||
METACITY_PC_MODULES="$METACITY_PC_MODULES libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_VERSION"
|
||||
AC_DEFINE(HAVE_STARTUP_NOTIFICATION, , [Building with startup notification support])
|
||||
else
|
||||
echo "Building without libstartup-notification"
|
||||
fi
|
||||
|
||||
XCOMPOSITE_VERSION=1.0
|
||||
AC_MSG_CHECKING([Xcomposite >= $XCOMPOSITE_VERSION])
|
||||
if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
|
||||
have_xcomposite=yes
|
||||
else
|
||||
have_xcomposite=no
|
||||
fi
|
||||
AC_MSG_RESULT($have_xcomposite)
|
||||
|
||||
if test x$enable_compositor = xyes; then
|
||||
have_xcomposite=yes
|
||||
echo "CompositeExt support forced on"
|
||||
elif test x$enable_compositor = xauto; then
|
||||
true
|
||||
else
|
||||
have_xcomposite=no
|
||||
fi
|
||||
|
||||
if test x$have_xcomposite = xyes; then
|
||||
echo "Building with CompositeExt"
|
||||
METACITY_PC_MODULES="$METACITY_PC_MODULES xcomposite >= $XCOMPOSITE_VERSION xfixes xrender xdamage"
|
||||
AC_DEFINE(HAVE_COMPOSITE_EXTENSIONS, , [Building with compositing manager support])
|
||||
else
|
||||
echo "Building without compositing manager"
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(METACITY, $METACITY_PC_MODULES)
|
||||
|
||||
AC_PATH_XTRA
|
||||
|
||||
ALL_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
|
||||
|
||||
# Check for Xinerama extension (Solaris impl or Xfree impl)
|
||||
metacity_save_cppflags="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
|
||||
|
||||
AC_ARG_ENABLE(xinerama,[ --disable-xinerama disable metacity's use of the Xinerama extension],
|
||||
try_xinerama=no,try_xinerama=yes)
|
||||
|
||||
use_solaris_xinerama=no
|
||||
use_xfree_xinerama=no
|
||||
if test "${try_xinerama}" != no; then
|
||||
case "$host" in
|
||||
*-*-solaris*)
|
||||
# Check for solaris
|
||||
use_solaris_xinerama=yes
|
||||
AC_CHECK_LIB(Xext, XineramaGetInfo,
|
||||
use_solaris_xinerama=yes, use_solaris_xinerama=no,
|
||||
$ALL_X_LIBS)
|
||||
if test "x$use_solaris_xinerama" = "xyes"; then
|
||||
AC_CHECK_HEADER(X11/extensions/xinerama.h,
|
||||
if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then
|
||||
X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS"
|
||||
fi
|
||||
AC_DEFINE(HAVE_SOLARIS_XINERAMA, , [Have Solaris-style Xinerama])
|
||||
AC_DEFINE(HAVE_XINERAMA, , [Have some version of Xinerama]),
|
||||
use_solaris_xinerama=no,
|
||||
[#include <X11/Xlib.h>])
|
||||
fi
|
||||
AC_MSG_CHECKING(for Xinerama support on Solaris)
|
||||
AC_MSG_RESULT($use_solaris_xinerama);
|
||||
;;
|
||||
*)
|
||||
# Check for XFree
|
||||
use_xfree_xinerama=yes
|
||||
AC_CHECK_LIB(Xinerama, XineramaQueryExtension,
|
||||
[AC_CHECK_HEADER(X11/extensions/Xinerama.h,
|
||||
X_EXTRA_LIBS="-lXinerama $X_EXTRA_LIBS"
|
||||
if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then
|
||||
X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS"
|
||||
fi
|
||||
AC_DEFINE(HAVE_XFREE_XINERAMA, , [Have XFree86-style Xinerama])
|
||||
AC_DEFINE(HAVE_XINERAMA,, [Have some version of Xinerama]),
|
||||
use_xfree_xinerama=no,
|
||||
[#include <X11/Xlib.h>])],
|
||||
use_xfree_xinerama=no, -lXext $ALL_X_LIBS)
|
||||
AC_MSG_CHECKING(for Xinerama support on XFree86)
|
||||
AC_MSG_RESULT($use_xfree_xinerama);
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
CPPFLAGS="$metacity_save_cppflags"
|
||||
|
||||
SHAPE_LIBS=
|
||||
found_shape=no
|
||||
AC_CHECK_LIB(Xext, XShapeQueryExtension,
|
||||
[AC_CHECK_HEADER(X11/extensions/shape.h,
|
||||
SHAPE_LIBS=-lXext found_shape=yes)],
|
||||
, $ALL_X_LIBS)
|
||||
|
||||
if test x$enable_shape = xno; then
|
||||
found_shape=no
|
||||
fi
|
||||
|
||||
if test x$enable_shape = xyes; then
|
||||
if test "$found_shape" = "no"; then
|
||||
AC_MSG_ERROR([--enable-shape forced and Shape not found])
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$found_shape" = "xyes"; then
|
||||
AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library])
|
||||
fi
|
||||
|
||||
found_xkb=no
|
||||
AC_CHECK_LIB(X11, XkbQueryExtension,
|
||||
[AC_CHECK_HEADER(X11/XKBlib.h,
|
||||
found_xkb=yes)],
|
||||
, $ALL_X_LIBS)
|
||||
|
||||
if test "x$found_xkb" = "xyes"; then
|
||||
AC_DEFINE(HAVE_XKB, , [Have keyboard extension library])
|
||||
fi
|
||||
|
||||
|
||||
RANDR_LIBS=
|
||||
found_randr=no
|
||||
AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
|
||||
[AC_CHECK_HEADER(X11/extensions/Xrandr.h,
|
||||
RANDR_LIBS=-lXrandr found_randr=yes,,
|
||||
[#include <X11/Xlib.h>])],
|
||||
, -lXrender -lXext $ALL_X_LIBS)
|
||||
|
||||
if test "x$found_randr" = "xyes"; then
|
||||
AC_DEFINE(HAVE_RANDR, , [Have the Xrandr extension library])
|
||||
fi
|
||||
|
||||
XSYNC_LIBS=
|
||||
found_xsync=no
|
||||
AC_CHECK_LIB(Xext, XSyncQueryExtension,
|
||||
[AC_CHECK_HEADER(X11/extensions/sync.h,
|
||||
found_xsync=yes,,
|
||||
[#include <X11/Xlib.h>])],
|
||||
, $ALL_X_LIBS)
|
||||
|
||||
if test x$enable_xsync = xno; then
|
||||
found_xsync=no
|
||||
fi
|
||||
|
||||
if test x$enable_xsync = xyes; then
|
||||
if test "$found_xsync" = "no"; then
|
||||
AC_MSG_ERROR([--enable-xsync forced and XSync not found])
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$found_xsync" = "xyes"; then
|
||||
XSYNC_LIBS=-lXext
|
||||
AC_DEFINE(HAVE_XSYNC, , [Have the Xsync extension library])
|
||||
fi
|
||||
|
||||
METACITY_LIBS="$XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_LIBS"
|
||||
METACITY_MESSAGE_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_MESSAGE_LIBS"
|
||||
METACITY_WINDOW_DEMO_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_WINDOW_DEMO_LIBS"
|
||||
METACITY_PROPS_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_PROPS_LIBS"
|
||||
|
||||
found_sm=no
|
||||
case "$METACITY_LIBS" in
|
||||
*-lSM*)
|
||||
found_sm=true
|
||||
found_sm=yes
|
||||
;;
|
||||
*)
|
||||
AC_CHECK_LIB(SM, SmcSaveYourselfDone,
|
||||
AC_CHECK_HEADERS(X11/SM/SMlib.h,
|
||||
METACITY_LIBS="-lSM -lICE $METACITY_LIBS" found_sm=true),
|
||||
[AC_CHECK_HEADERS(X11/SM/SMlib.h,
|
||||
METACITY_LIBS="-lSM -lICE $METACITY_LIBS" found_sm=no)],
|
||||
, $METACITY_LIBS)
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$found_sm" = "true"; then
|
||||
AC_DEFINE(HAVE_SM)
|
||||
if test x$enable_sm = xno; then
|
||||
found_sm=no
|
||||
fi
|
||||
|
||||
# Check for shaped window extension
|
||||
AC_CHECK_LIB(Xext, XShapeCombineMask, AC_DEFINE(HAVE_SHAPE_EXT),,$METACITY_LIBS)
|
||||
if test x$enable_sm = xyes; then
|
||||
if test "$found_sm" = "no"; then
|
||||
AC_MSG_ERROR([--enable-sm forced and -lSM not found])
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$found_sm" = "yes"; then
|
||||
AC_DEFINE(HAVE_SM, , [Building with SM support])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_SM, test "$found_sm" = "yes")
|
||||
|
||||
HOST_ALIAS=$host_alias
|
||||
AC_SUBST(HOST_ALIAS)
|
||||
|
||||
AC_PATH_PROG(GDK_PIXBUF_CSOURCE, gdk-pixbuf-csource, no)
|
||||
|
||||
if test x"$GDK_PIXBUF_CSOURCE" = xno; then
|
||||
AC_MSG_ERROR([gdk-pixbuf-csource executable not found in your path - should be installed with GTK])
|
||||
fi
|
||||
|
||||
AC_SUBST(GDK_PIXBUF_CSOURCE)
|
||||
|
||||
## hack to work with old GTK versions for now
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$METACITY_LIBS $LDFLAGS"
|
||||
AC_CHECK_FUNCS(gdk_pixbuf_new_from_stream)
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
|
||||
if test x$enable_gconf = xyes; then
|
||||
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
|
||||
if test x"$GCONFTOOL" = xno; then
|
||||
AC_MSG_ERROR([gconftool-2 executable not found in your path - should be installed with GConf])
|
||||
fi
|
||||
|
||||
AM_GCONF_SOURCE_2
|
||||
fi
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
src/wm-tester/Makefile
|
||||
src/libmetacity-private.pc
|
||||
src/tools/Makefile
|
||||
src/themes/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
if test x$enable_gconf = xno; then
|
||||
echo "*** WARNING WARNING WARNING WARNING WARNING"
|
||||
echo "*** Building without GConf"
|
||||
echo "*** This means there's no way to change prefs except"
|
||||
echo "*** hacking source code, at least for now."
|
||||
echo "*** Also, some prefs may have broken defaults."
|
||||
echo "*** Patches needed for a simple no-gconf config file."
|
||||
echo "*** This is intended for embedded systems etc., not for normal use."
|
||||
fi
|
||||
|
||||
if test x$enable_verbose_mode = xno; then
|
||||
echo "*** WARNING WARNING WARNING WARNING WARNING"
|
||||
echo "*** Building without verbose mode"
|
||||
echo "*** This means there's no way to debug metacity problems."
|
||||
echo "*** Please build normal desktop versions of metacity"
|
||||
echo "*** with verbose mode enabled so users can use it when they report bugs."
|
||||
fi
|
||||
|
||||
dnl ==========================================================================
|
||||
echo "
|
||||
metacity-$VERSION:
|
||||
|
||||
prefix: ${prefix}
|
||||
source code location: ${srcdir}
|
||||
compiler: ${CC}
|
||||
|
||||
GConf: ${enable_gconf}
|
||||
XFree86 Xinerama: ${use_xfree_xinerama}
|
||||
Solaris Xinerama: ${use_solaris_xinerama}
|
||||
Startup notification: ${have_startup_notification}
|
||||
Compositing manager: ${have_xcomposite}
|
||||
Session management: ${found_sm}
|
||||
Shape extension: ${found_shape}
|
||||
Resize-and-rotate: ${found_randr}
|
||||
Xsync: ${found_xsync}
|
||||
Deprecated config dialog: ${enable_config_dialog}
|
||||
"
|
||||
echo "This is the UNSTABLE branch of metacity, use 2.6.x for stable (gnome-2-4 branch in CVS)"
|
||||
|
2
doc/.cvsignore
Normal file
2
doc/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
Makefile
|
||||
Makefile.in
|
2
doc/Makefile.am
Normal file
2
doc/Makefile.am
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
EXTRA_DIST=theme-format.txt metacity-theme.dtd dialogs.txt
|
32
doc/dialogs.txt
Normal file
32
doc/dialogs.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
Dialogs which have no transient parent or root window being
|
||||
their tranisent parent are the ones which will be visible in
|
||||
the tasklist.
|
||||
|
||||
All such dialogs will be *always* on top of the window
|
||||
group i.e they would transients for the whole group.
|
||||
|
||||
|
||||
1) Modal dialogs
|
||||
|
||||
|
||||
* If you wish to open another window from a modal dialog
|
||||
|
||||
open *only* a modal dialog and set it's transient parent.
|
||||
|
||||
|
||||
2) Normal dialog
|
||||
|
||||
|
||||
without transient parent
|
||||
|
||||
* If you wish to open another window from a normal dialog
|
||||
|
||||
open either a normal dialog or a modal dialog only.
|
||||
Set the transient parent for the child dialog if you do not
|
||||
want them to be transient for all the other windows in the group.
|
||||
|
||||
with transient parent
|
||||
|
||||
* If you wish to open another window from a normal dialog
|
||||
|
||||
you could open any type of window.
|
273
doc/metacity-theme.dtd
Normal file
273
doc/metacity-theme.dtd
Normal file
@@ -0,0 +1,273 @@
|
||||
<!--
|
||||
DTD for Metacity themes, as of Metacity 2.4.1
|
||||
Author: Ross Burton <ross@burtonini.com>
|
||||
Copyright (C) 2002 Ross Burton
|
||||
Licensed under the GPL, version 2
|
||||
-->
|
||||
|
||||
<!-- Top-level element -->
|
||||
<!ELEMENT metacity_theme (info,(window|frame_style_set|frame_style|frame_geometry|constant|draw_ops|menu_icon)+)>
|
||||
|
||||
<!-- Theme metadata -->
|
||||
<!ELEMENT info (name?|author?|copyright?|date?|description?)*>
|
||||
<!ELEMENT name (#PCDATA)>
|
||||
<!ELEMENT author (#PCDATA)>
|
||||
<!ELEMENT copyright (#PCDATA)>
|
||||
<!ELEMENT date (#PCDATA)>
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
<!ENTITY % xyrequired "
|
||||
x CDATA #REQUIRED
|
||||
y CDATA #REQUIRED
|
||||
">
|
||||
|
||||
<!ENTITY % xyimplied "
|
||||
x CDATA #IMPLIED
|
||||
y CDATA #IMPLIED
|
||||
">
|
||||
|
||||
<!ENTITY % widthheightrequired "
|
||||
width CDATA #REQUIRED
|
||||
height CDATA #REQUIRED
|
||||
">
|
||||
|
||||
<!ENTITY % widthheightimplied "
|
||||
width CDATA #IMPLIED
|
||||
height CDATA #IMPLIED
|
||||
">
|
||||
|
||||
<!ENTITY % boolean "(true|false)">
|
||||
|
||||
<!ENTITY % piece_positions "
|
||||
(entire_background|titlebar|titlebar_middle|left_titlebar_edge|right_titlebar_edge|top_titlebar_edge|bottom_titlebar_edge|title|left_edge|right_edge|bottom_edge|overlay)
|
||||
">
|
||||
|
||||
<!ENTITY % gtk-state "
|
||||
state (normal|prelight|active|selected|insensitive) #REQUIRED
|
||||
">
|
||||
|
||||
<!ENTITY % gtk-shadow "
|
||||
shadow (none|in|out|etched_in|etched_out) #REQUIRED
|
||||
">
|
||||
|
||||
|
||||
<!-- The actual theme -->
|
||||
|
||||
<!ELEMENT window EMPTY>
|
||||
<!ATTLIST window
|
||||
type (normal|dialog|modal_dialog|menu|utility|border) #REQUIRED
|
||||
style_set CDATA #REQUIRED
|
||||
>
|
||||
|
||||
|
||||
<!ELEMENT frame_style_set (frame+)>
|
||||
<!ATTLIST frame_style_set
|
||||
name CDATA #REQUIRED
|
||||
parent CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT frame EMPTY>
|
||||
<!ATTLIST frame
|
||||
focus (yes|no) #REQUIRED
|
||||
state (normal|maximized|shaded|maximized_and_shaded) #REQUIRED
|
||||
resize (both|horizontal|vertical|none) #IMPLIED
|
||||
style CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT frame_style (piece|button)*>
|
||||
<!ATTLIST frame_style
|
||||
name CDATA #REQUIRED
|
||||
geometry CDATA #REQUIRED
|
||||
parent CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT piece (draw_ops?)>
|
||||
<!ATTLIST piece
|
||||
position %piece_positions; #REQUIRED
|
||||
draw_ops CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT button (draw_ops?)>
|
||||
<!ATTLIST button
|
||||
function (menu|minimize|maximize|close|left_left_background|left_middle_background|left_right_background|right_left_background|right_middle_background|right_right_background) #REQUIRED
|
||||
state (normal|prelight|pressed) #REQUIRED
|
||||
draw_ops CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT frame_geometry (border|(aspect_ratio|distance))+>
|
||||
<!ATTLIST frame_geometry
|
||||
name CDATA #REQUIRED
|
||||
parent CDATA #IMPLIED
|
||||
title_scale (xx-small|x-small|small|medium|large|x-large|xx-large) #IMPLIED
|
||||
has_title (true|false) 'true'
|
||||
rounded_top_left %boolean; #IMPLIED
|
||||
rounded_top_right %boolean; #IMPLIED
|
||||
rounded_bottom_left %boolean; #IMPLIED
|
||||
rounded_bottom_right %boolean; #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT distance EMPTY>
|
||||
<!ATTLIST distance
|
||||
name (left_width|right_width|bottom_height|title_vertical_pad|right_titlebar_edge|left_titlebar_edge|button_width|button_height) #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT border EMPTY>
|
||||
<!ATTLIST border
|
||||
name CDATA #REQUIRED
|
||||
top CDATA #REQUIRED
|
||||
bottom CDATA #REQUIRED
|
||||
left CDATA #REQUIRED
|
||||
right CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT aspect_ratio EMPTY>
|
||||
<!ATTLIST aspect_ratio
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT draw_ops (line|rectangle|arc|tint|gradient|image|gtk_arrow|gtk_box|gtk_vline|icon|title|clip|include|tile)*>
|
||||
<!-- not sure about this.. maybe it should be removed. see #3478 in theme-parser.c -->
|
||||
<!ATTLIST draw_ops
|
||||
name CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT line EMPTY>
|
||||
<!ATTLIST line
|
||||
color CDATA #REQUIRED
|
||||
x1 CDATA #REQUIRED
|
||||
y1 CDATA #REQUIRED
|
||||
x2 CDATA #REQUIRED
|
||||
y2 CDATA #REQUIRED
|
||||
width CDATA #IMPLIED
|
||||
dash_on_length CDATA #IMPLIED
|
||||
dash_off_length CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT rectangle EMPTY>
|
||||
<!ATTLIST rectangle
|
||||
color CDATA #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
filled %boolean; 'false'
|
||||
>
|
||||
|
||||
<!ELEMENT arc EMPTY>
|
||||
<!ATTLIST arc
|
||||
color CDATA #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
start_angle CDATA #REQUIRED
|
||||
extent_angle CDATA #REQUIRED
|
||||
filled %boolean; 'false'
|
||||
>
|
||||
|
||||
<!ELEMENT icon EMPTY>
|
||||
<!ATTLIST icon
|
||||
%xyrequired;
|
||||
width CDATA #REQUIRED
|
||||
height CDATA #REQUIRED
|
||||
alpha CDATA #IMPLIED
|
||||
fill_type (tile|scale) 'scale'
|
||||
>
|
||||
|
||||
<!ELEMENT image EMPTY>
|
||||
<!ATTLIST image
|
||||
filename CDATA #REQUIRED
|
||||
colorize CDATA #IMPLIED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
alpha CDATA #IMPLIED
|
||||
fill_type (tile|scale) 'scale'
|
||||
>
|
||||
|
||||
<!ELEMENT tile EMPTY>
|
||||
<!ATTLIST tile
|
||||
name CDATA #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
tile_xoffset CDATA #IMPLIED
|
||||
tile_yoffset CDATA #IMPLIED
|
||||
tile_width CDATA #REQUIRED
|
||||
tile_height CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT clip EMPTY>
|
||||
<!ATTLIST clip
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
>
|
||||
|
||||
<!ELEMENT title EMPTY>
|
||||
<!ATTLIST title
|
||||
color CDATA #REQUIRED
|
||||
%xyrequired;
|
||||
>
|
||||
|
||||
<!ELEMENT tint EMPTY>
|
||||
<!ATTLIST tint
|
||||
color CDATA #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
alpha CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT gtk_box EMPTY>
|
||||
<!ATTLIST gtk_box
|
||||
%gtk-state;
|
||||
%gtk-shadow;
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
>
|
||||
|
||||
<!ELEMENT gtk_arrow EMPTY>
|
||||
<!ATTLIST gtk_arrow
|
||||
%gtk-state;
|
||||
%gtk-shadow;
|
||||
arrow (up|down|left|right) #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
filed CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT gtk_vline EMPTY>
|
||||
<!ATTLIST gtk_vline
|
||||
%gtk-state;
|
||||
x CDATA #REQUIRED
|
||||
y1 CDATA #REQUIRED
|
||||
y2 CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT gradient (color)+>
|
||||
<!ATTLIST gradient
|
||||
type (vertical|horizontal|diagonal) #REQUIRED
|
||||
%xyrequired;
|
||||
%widthheightrequired;
|
||||
alpha CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT color EMPTY>
|
||||
<!ATTLIST color
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT include EMPTY>
|
||||
<!ATTLIST include
|
||||
name CDATA #REQUIRED
|
||||
%xyimplied;
|
||||
%widthheightimplied;
|
||||
>
|
||||
|
||||
<!ELEMENT constant EMPTY>
|
||||
<!ATTLIST constant
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT menu_icon (draw_ops?)>
|
||||
<!ATTLIST menu_icon
|
||||
function (close|maximize|minimize|unmaximize) #REQUIRED
|
||||
%gtk-state;
|
||||
draw_ops CDATA #IMPLIED
|
||||
>
|
245
doc/theme-format.txt
Normal file
245
doc/theme-format.txt
Normal file
@@ -0,0 +1,245 @@
|
||||
Docs on the theme format
|
||||
|
||||
Themes are in a simple XML-subset format.
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<metacity_theme>
|
||||
<!-- Only one info section is allowed -->
|
||||
<info>
|
||||
<name>Foo</name>
|
||||
<author>Foo P. Bar</author>
|
||||
<copyright>whoever, 2002</copyright>
|
||||
<date>Jan 31 2005</date>
|
||||
<description>A sentence about the theme.</description>
|
||||
</info>
|
||||
|
||||
<!-- define a frame geometry to be referenced later -->
|
||||
<!-- frame_geometry has an optional has_title attribute which
|
||||
determines whether the title text height is included in the
|
||||
height calculation. if not specified, defaults to true.
|
||||
It also has an optional text_size="medium" attribute
|
||||
(same sizes as with Pango markup, xx-small thru medium thru
|
||||
xx-large)
|
||||
|
||||
Finally it has optional args rounded_top_left=true,
|
||||
rounded_top_right=true, rounded_bottom_left=true,
|
||||
rounded_bottom_right=true.
|
||||
|
||||
-->
|
||||
<frame_geometry name="normal" has_title="true" title_scale="medium">
|
||||
<distance name="left_width" value="6"/>
|
||||
<distance name="right_width" value="6"/>
|
||||
<distance name="bottom_height" value="7"/>
|
||||
<distance name="left_titlebar_edge" value="6"/>
|
||||
<distance name="right_titlebar_edge" value="6"/>
|
||||
<distance name="button_width" value="17"/>
|
||||
<distance name="button_height" value="17"/>
|
||||
<!-- alternative to button_width button_height distances -->
|
||||
<aspect_ratio name="button" value="1.0"/>
|
||||
<distance name="title_vertical_pad" value="4"/>
|
||||
<border name="title_border" left="3" right="12" top="4" bottom="3"/>
|
||||
<border name="button_border" left="0" right="0" top="1" bottom="1"/>
|
||||
</frame_geometry>
|
||||
|
||||
<!-- inheritance is allowed; simply overwrites values from parent -->
|
||||
<frame_geometry name="borderless" parent="normal">
|
||||
<distance name="left_width" value="0"/>
|
||||
<distance name="right_width" value="0"/>
|
||||
<distance name="bottom_height" value="0"/>
|
||||
<distance name="left_titlebar_edge" value="0"/>
|
||||
<distance name="right_titlebar_edge" value="0"/>
|
||||
</frame_geometry>
|
||||
|
||||
<!-- define a constant to use in positions/sizes of draw operations;
|
||||
constant names must start with a capital letter.
|
||||
-->
|
||||
<constant name="LineOffset" value="3"/>
|
||||
|
||||
<!-- define drawing operations to be referenced later;
|
||||
these draw-op lists can also be placed inline.
|
||||
|
||||
Positions/lengths are given as expressions.
|
||||
Operators are: +,-,*,/,%,`max`,`min`
|
||||
All operators are infix including `max` and `min`,
|
||||
i.e. "2 `max` 5"
|
||||
|
||||
Some variables are predefined, and constants can also
|
||||
be used. Variables are:
|
||||
|
||||
width - width of target area
|
||||
height - height of target area
|
||||
object_width - natural width of object being drawn
|
||||
object_height - natural height of object being drawn
|
||||
left_width - distance from left of frame to client window
|
||||
right_width - distance from right of frame to client window
|
||||
top_height - distance from top of frame to client window
|
||||
bottom_height - distance from bottom of frame to client window
|
||||
mini_icon_width - width of mini icon for window
|
||||
mini_icon_height - height of mini icon
|
||||
icon_width - width of large icon
|
||||
icon_height - height of large icon
|
||||
title_width - width of title text
|
||||
title_height - height of title text
|
||||
|
||||
All these are always defined, except object_width/object_height
|
||||
which only exists for <image> right now.
|
||||
|
||||
-->
|
||||
|
||||
<draw_ops name="demo_all_ops">
|
||||
<line color="#00FF00" x1="LineOffset" y1="0" x2="0" y2="height"/>
|
||||
<line color="gtk:fg[NORMAL]"
|
||||
x1="width - 1" y1="0" x2="width - 1" y2="height"
|
||||
width="3" dash_on_length="2" dash_off_length="3"/>
|
||||
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.7"
|
||||
x="0" y="0" width="width - 1" height="height - 1" filled="true"/>
|
||||
<arc color="dark gray" x="0" y="0" width="width - 1" height="height - 1"
|
||||
filled="false" start_angle="30" extent_angle="180"/>
|
||||
<tint color="orange" alpha="0.5" x="0" y="0" width="width" height="height"/>
|
||||
<!-- may be vertical, horizontal, diagonal -->
|
||||
<gradient type="diagonal"
|
||||
x="10" y="30" width="width / 3" height="height / 4">
|
||||
<!-- any number of colors allowed here. A color can be
|
||||
a color name like "blue" (look at gcolorsel), a hex color
|
||||
as in HTML (#FFBB99), or a color from the gtk theme
|
||||
given as "gtk:base[NORMAL]", "gtk:fg[ACTIVE]", etc.
|
||||
-->
|
||||
<color value="gtk:fg[SELECTED]"/>
|
||||
<!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
|
||||
<color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
|
||||
</gradient>
|
||||
<!-- image has an optional colorize="#color" attribute to give the
|
||||
image a certain color -->
|
||||
<image filename="foo.png" alpha="0.7"
|
||||
x="10" y="30" width="width / 3" height="height / 4"/>
|
||||
<gtk_arrow state="normal" shadow="in" arrow="up"
|
||||
filled="true"
|
||||
x="2" y="2" width="width - 4" height="height - 4"/>
|
||||
<gtk_box state="normal" shadow="out"
|
||||
x="2" y="2" width="width - 4" height="height - 4"/>
|
||||
<gtk_vline state="normal" x="2" y1="0" y2="height"/>
|
||||
<!-- window's icon -->
|
||||
<icon alpha="0.7"
|
||||
x="10" y="30" width="width / 3" height="height / 4"/>
|
||||
<!-- window's title -->
|
||||
<title color="gtk:text[NORMAL]" x="20" y="30"/>
|
||||
<!-- include another draw ops list; has optional x/y/width/height attrs -->
|
||||
<include name="some_other_draw_ops"/>
|
||||
<!-- tile another draw ops list; has optional
|
||||
x/y/width/height/tile_xoffset/tile_yoffset -->
|
||||
<tile name="some_other_draw_ops" tile_width="10" tile_height="10"/>
|
||||
</draw_ops>
|
||||
|
||||
<frame_style name="normal" geometry="normal">
|
||||
<!-- How to draw each piece of the frame.
|
||||
For each piece, a draw_ops can be given inline or referenced
|
||||
by name. If a piece is omitted, then nothing will be drawn
|
||||
for that piece.
|
||||
|
||||
For each piece, the "width" and "height" variables in
|
||||
coordinate expressions refers to the dimensions of the piece,
|
||||
the origin is at the top left of the piece.
|
||||
|
||||
So <rectangle x="0" y="0" width="width-1" height="height-1"/>
|
||||
will outline a piece.
|
||||
-->
|
||||
|
||||
<piece position="entire_background" draw_ops="demo_all_ops"/>
|
||||
<piece position="left_titlebar_edge">
|
||||
<draw_ops>
|
||||
<line color="#00FF00" x1="0" y1="0" x2="0" y2="height"/>
|
||||
</draw_ops>
|
||||
</piece>
|
||||
|
||||
<!-- The complete list of frame pieces:
|
||||
|
||||
entire_background: whole frame
|
||||
titlebar: entire area above the app's window
|
||||
titlebar_middle: area of titlebar_background not considered
|
||||
part of an edge
|
||||
left_titlebar_edge: left side of titlebar background
|
||||
right_titlebar_edge: right side of titlebar background
|
||||
top_titlebar_edge: top side of titlebar background
|
||||
bottom_titlebar_edge: bottom side of titlebar background
|
||||
title: the title area (doesn't include buttons)
|
||||
left_edge: left edge of the frame
|
||||
right_edge: right edge of the frame
|
||||
bottom_edge: bottom edge of the frame
|
||||
overlay: same area as entire_background, but drawn after
|
||||
drawing all sub-pieces instead of before
|
||||
|
||||
-->
|
||||
|
||||
<!-- For buttons, drawing methods have to be provided for
|
||||
each of three states:
|
||||
normal, pressed, prelight
|
||||
and the button function or position must be provided:
|
||||
close, maximize, minimize, menu,
|
||||
left_left_background, left_middle_background,
|
||||
left_right_background, right_left_background,
|
||||
right_middle_background, right_right_background
|
||||
So a working theme needs 3*4 = 12 button declarations
|
||||
and a theme may have up to 3*10 = 30 button declarations
|
||||
in order to handle button-rearrangement preferences.
|
||||
|
||||
(The name "function" for the attribute is from before the
|
||||
background values existed.)
|
||||
-->
|
||||
|
||||
<button function="close" state="normal" draw_ops="previously_named"/>
|
||||
<button function="menu" state="normal">
|
||||
<draw_ops>
|
||||
<icon alpha="0.7"
|
||||
x="0" y="0" width="object_width" height="object_height"/>
|
||||
</draw_ops>
|
||||
</button>
|
||||
|
||||
</frame_style>
|
||||
|
||||
<!-- styles can inherit from each other with the parent="" attribute.
|
||||
In a subclass anything can be re-specified to override
|
||||
the parent style. -->
|
||||
<frame_style name="focused" parent="normal">
|
||||
<piece position="title">
|
||||
<draw_ops>
|
||||
<rectangle color="gtk:bg[SELECTED]"
|
||||
x="0" y="0" width="width-1" height="height-1"/>
|
||||
<title color="gtk:fg[SELECTED]" x="(width - title_width) / 2"
|
||||
y="(height - title_height) / 2"/>
|
||||
</draw_ops>
|
||||
</piece>
|
||||
</frame_style>
|
||||
|
||||
<!-- Maps styles to states of frame.
|
||||
|
||||
Focus: yes (focused), no (not focused)
|
||||
Window states: normal, maximized, shaded, maximized_and_shaded
|
||||
Window resizability: none, vertical, horizontal, both
|
||||
|
||||
Everything unspecified just does the same as
|
||||
unfocused/normal/both.
|
||||
|
||||
only state="normal" needs a resize="" attribute.
|
||||
-->
|
||||
<frame_style_set name="normal">
|
||||
<frame focus="yes" state="normal" resize="both" style="focused"/>
|
||||
<frame focus="no" state="normal" resize="both" style="normal"/>
|
||||
</frame_style_set>
|
||||
|
||||
<!-- Each window type needs a style set
|
||||
Types: normal, dialog, modal_dialog, menu, utility, border
|
||||
-->
|
||||
<window type="normal" style_set="normal"/>
|
||||
|
||||
|
||||
<!-- For menu icons, drawing methods are needed for the same
|
||||
four types as the buttons, and GTK states
|
||||
(insensitive,prelight,normal,etc.)
|
||||
-->
|
||||
|
||||
<menu_icon function="close" state="normal" draw_ops="previously_named"/>
|
||||
|
||||
|
||||
</metacity_theme>
|
||||
|
||||
|
@@ -1,6 +1,11 @@
|
||||
*.gmo
|
||||
*.mo
|
||||
*.pot
|
||||
Makefile
|
||||
Makefile.in
|
||||
Makefile.in.in
|
||||
POTFILES
|
||||
Makefile.in
|
||||
Makefile
|
||||
stamp-cat-id
|
||||
cat-id-tbl.c
|
||||
messages
|
||||
missing
|
||||
stamp-cat-id
|
||||
|
1770
po/ChangeLog
Normal file
1770
po/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
src/tools/metacity-message.c
|
||||
src/delete.c
|
||||
src/display.c
|
||||
src/errors.c
|
||||
src/frames.c
|
||||
src/keybindings.c
|
||||
src/main.c
|
||||
src/menu.c
|
||||
src/metaaccellabel.c
|
||||
src/metacity-dialog.c
|
||||
src/metacity.desktop.in
|
||||
src/metacity.schemas.in
|
||||
src/prefs.c
|
||||
src/resizepopup.c
|
||||
src/screen.c
|
||||
src/session.c
|
||||
src/theme-parser.c
|
||||
src/theme-viewer.c
|
||||
src/theme.c
|
||||
src/tools/metacity-properties.desktop.in
|
||||
src/tools/metacity-properties.glade
|
||||
src/util.c
|
||||
src/window-props.c
|
||||
src/window.c
|
||||
src/workspace.c
|
||||
src/xprops.c
|
||||
|
3180
po/en_CA.po
Normal file
3180
po/en_CA.po
Normal file
File diff suppressed because it is too large
Load Diff
2457
po/en_GB.po
Normal file
2457
po/en_GB.po
Normal file
File diff suppressed because it is too large
Load Diff
3273
po/pt_BR.po
Normal file
3273
po/pt_BR.po
Normal file
File diff suppressed because it is too large
Load Diff
3241
po/sr@Latn.po
Normal file
3241
po/sr@Latn.po
Normal file
File diff suppressed because it is too large
Load Diff
3013
po/zh_CN.po
Normal file
3013
po/zh_CN.po
Normal file
File diff suppressed because it is too large
Load Diff
2935
po/zh_TW.po
Normal file
2935
po/zh_TW.po
Normal file
File diff suppressed because it is too large
Load Diff
37
rationales.txt
Normal file
37
rationales.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
History
|
||||
====
|
||||
|
||||
Focus windows on map: see http://bugzilla.gnome.org/show_bug.cgi?id=82921
|
||||
Keep panel always on top: http://bugzilla.gnome.org/show_bug.cgi?id=81551
|
||||
Edge flipping: http://bugzilla.gnome.org/show_bug.cgi?id=82917
|
||||
Opaque resize: http://bugzilla.gnome.org/show_bug.cgi?id=92618
|
||||
Super+click to resize: http://bugzilla.gnome.org/show_bug.cgi?id=79315
|
||||
minimized windows in Alt+tab: http://bugzilla.gnome.org/show_bug.cgi?id=89416
|
||||
dialogs above entire app group: http://bugzilla.gnome.org/show_bug.cgi?id=88926
|
||||
display window size/position: http://bugzilla.gnome.org/show_bug.cgi?id=85213,
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=106645
|
||||
|
||||
configure click actions, alt+click:
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=83210
|
||||
|
||||
system modal dialogs: http://bugzilla.gnome.org/show_bug.cgi?id=83357
|
||||
|
||||
workspace wrapping: http://bugzilla.gnome.org/show_bug.cgi?id=89315
|
||||
|
||||
raise windows on click:
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=86108
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=115072
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=115753
|
||||
|
||||
Some discussion of how pointer focus is inherently a bit buggy because
|
||||
of the "sometimes focus window that isn't under the mouse" heuristics:
|
||||
http://bugzilla.gnome.org/show_bug.cgi?id=124798
|
||||
(there are some other bugs that may have better explanation)
|
||||
|
||||
Tracking bugs
|
||||
====
|
||||
|
||||
session management: http://bugzilla.gnome.org/show_bug.cgi?id=107063
|
||||
|
||||
revise theme format: http://bugzilla.gnome.org/show_bug.cgi?id=102547
|
@@ -3,3 +3,11 @@ Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
metacity
|
||||
metacity-theme-viewer
|
||||
metacity-dialog
|
||||
testgradient
|
||||
inlinepixbufs.h
|
||||
metacity.desktop
|
||||
metacity.schemas
|
||||
libmetacity-private.pc
|
||||
testasyncgetprop
|
||||
|
150
src/Makefile.am
150
src/Makefile.am
@@ -1,12 +1,32 @@
|
||||
lib_LTLIBRARIES = libmetacity-private.la
|
||||
|
||||
INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\"
|
||||
SUBDIRS=wm-tester tools themes
|
||||
|
||||
INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DMETACITY_LIBDIR=\"$(libdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMETACITY_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMETACITY_PKGDATADIR=\"$(pkgdatadir)\" -DMETACITY_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"metacity\" -DSN_API_NOT_YET_FROZEN=1
|
||||
|
||||
EGGFILES= \
|
||||
eggaccelerators.c \
|
||||
eggaccelerators.h
|
||||
|
||||
metacity_SOURCES= \
|
||||
async-getprop.c \
|
||||
async-getprop.h \
|
||||
bell.h \
|
||||
bell.c \
|
||||
common.h \
|
||||
compositor.c \
|
||||
compositor.h \
|
||||
constraints.c \
|
||||
constraints.h \
|
||||
core.c \
|
||||
core.h \
|
||||
delete.c \
|
||||
display.c \
|
||||
display.h \
|
||||
draw-workspace.c \
|
||||
draw-workspace.h \
|
||||
effects.c \
|
||||
effects.h \
|
||||
errors.c \
|
||||
errors.h \
|
||||
eventqueue.c \
|
||||
@@ -17,29 +37,151 @@ metacity_SOURCES= \
|
||||
frame.h \
|
||||
frames.c \
|
||||
frames.h \
|
||||
gradient.c \
|
||||
gradient.h \
|
||||
group.c \
|
||||
group.h \
|
||||
group-private.h \
|
||||
group-props.c \
|
||||
group-props.h \
|
||||
iconcache.c \
|
||||
iconcache.h \
|
||||
inlinepixbufs.h \
|
||||
keybindings.c \
|
||||
keybindings.h \
|
||||
main.c \
|
||||
main.h \
|
||||
menu.c \
|
||||
menu.h \
|
||||
metaaccellabel.c \
|
||||
metaaccellabel.h \
|
||||
metacity-Xatomtype.h \
|
||||
place.c \
|
||||
place.h \
|
||||
prefs.c \
|
||||
prefs.h \
|
||||
resizepopup.c \
|
||||
resizepopup.h \
|
||||
screen.c \
|
||||
screen.h \
|
||||
session.c \
|
||||
session.h \
|
||||
stack.c \
|
||||
stack.h \
|
||||
tabpopup.c \
|
||||
tabpopup.h \
|
||||
theme.c \
|
||||
theme.h \
|
||||
theme-parser.c \
|
||||
theme-parser.h \
|
||||
themewidget.c \
|
||||
themewidget.h \
|
||||
ui.c \
|
||||
ui.h \
|
||||
util.c \
|
||||
util.h \
|
||||
window.c \
|
||||
window.h \
|
||||
window-props.c \
|
||||
window-props.h \
|
||||
workspace.c \
|
||||
workspace.h
|
||||
workspace.h \
|
||||
xprops.c \
|
||||
xprops.h \
|
||||
$(EGGFILES)
|
||||
|
||||
bin_PROGRAMS=metacity
|
||||
libmetacity_private_la_SOURCES= \
|
||||
gradient.c \
|
||||
gradient.h \
|
||||
preview-widget.c \
|
||||
preview-widget.h \
|
||||
theme.c \
|
||||
theme.h \
|
||||
theme-parser.c \
|
||||
theme-parser.h \
|
||||
util.c \
|
||||
util.h \
|
||||
common.h
|
||||
|
||||
metacity_LDADD= @METACITY_LIBS@
|
||||
libmetacity_private_la_LDFLAGS = -no-undefined
|
||||
libmetacity_private_la_LIBADD = @METACITY_LIBS@
|
||||
|
||||
libmetacityincludedir = $(includedir)/metacity-1/metacity-private
|
||||
|
||||
libmetacityinclude_HEADERS = \
|
||||
common.h \
|
||||
gradient.h \
|
||||
preview-widget.h \
|
||||
theme.h \
|
||||
theme-parser.h \
|
||||
util.h
|
||||
|
||||
metacity_theme_viewer_SOURCES= \
|
||||
theme-viewer.c
|
||||
|
||||
metacity_dialog_SOURCES= \
|
||||
metacity-dialog.c
|
||||
|
||||
bin_PROGRAMS=metacity metacity-theme-viewer
|
||||
libexec_PROGRAMS=metacity-dialog
|
||||
|
||||
EFENCE=
|
||||
metacity_LDADD=@METACITY_LIBS@ $(EFENCE)
|
||||
metacity_theme_viewer_LDADD= @METACITY_LIBS@ libmetacity-private.la
|
||||
metacity_dialog_LDADD=@METACITY_LIBS@
|
||||
|
||||
testgradient_SOURCES=gradient.h gradient.c testgradient.c
|
||||
testasyncgetprop_SOURCES=async-getprop.h async-getprop.c testasyncgetprop.c
|
||||
|
||||
noinst_PROGRAMS=testgradient testasyncgetprop
|
||||
|
||||
testgradient_LDADD= @METACITY_LIBS@
|
||||
testasyncgetprop_LDADD= @METACITY_LIBS@
|
||||
|
||||
desktopfilesdir=$(datadir)/gnome/wm-properties
|
||||
desktopfiles_in_files=metacity.desktop.in
|
||||
desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop)
|
||||
desktopfiles_DATA = $(desktopfiles_files)
|
||||
@INTLTOOL_DESKTOP_RULE@
|
||||
|
||||
schemadir = @GCONF_SCHEMA_FILE_DIR@
|
||||
schema_in_files = metacity.schemas.in
|
||||
schema_DATA = $(schema_in_files:.schemas.in=.schemas)
|
||||
|
||||
@INTLTOOL_SCHEMAS_RULE@
|
||||
|
||||
if GCONF_SCHEMAS_INSTALL
|
||||
install-data-local:
|
||||
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(schema_DATA)
|
||||
else
|
||||
install-data-local:
|
||||
endif
|
||||
|
||||
IMAGES=default_icon.png stock_maximize.png stock_minimize.png stock_delete.png
|
||||
VARIABLES=default_icon_data $(srcdir)/default_icon.png \
|
||||
stock_maximize_data $(srcdir)/stock_maximize.png \
|
||||
stock_minimize_data $(srcdir)/stock_minimize.png \
|
||||
stock_delete_data $(srcdir)/stock_delete.png
|
||||
|
||||
BUILT_SOURCES = inlinepixbufs.h
|
||||
CLEANFILES = inlinepixbufs.h
|
||||
|
||||
inlinepixbufs.h: $(IMAGES)
|
||||
$(GDK_PIXBUF_CSOURCE) --raw --build-list $(VARIABLES) >$(srcdir)/inlinepixbufs.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
pkgconfig_DATA = libmetacity-private.pc
|
||||
|
||||
EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(IMAGES) $(schema_DATA) \
|
||||
update-from-egg.sh \
|
||||
$(desktopfiles_in_files) \
|
||||
$(schema_in_files) \
|
||||
libmetacity-private.pc.in
|
||||
|
||||
|
||||
EGGDIR=$(srcdir)/../../libegg/libegg
|
||||
|
||||
regenerate-built-sources:
|
||||
EGGFILES="$(EGGFILES)" EGGDIR="$(EGGDIR)" $(srcdir)/update-from-egg.sh
|
||||
|
681
src/async-getprop.c
Normal file
681
src/async-getprop.c
Normal file
@@ -0,0 +1,681 @@
|
||||
/* Asynchronous X property getting hack */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Havoc Pennington
|
||||
* Copyright (C) 1986, 1998 The Open Group
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of The Open Group shall not be
|
||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
||||
* in this Software without prior written authorization from The Open Group.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#undef DEBUG_SPEW
|
||||
#ifdef DEBUG_SPEW
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "async-getprop.h"
|
||||
|
||||
#define NEED_REPLIES
|
||||
#include <X11/Xlibint.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
typedef struct _ListNode ListNode;
|
||||
typedef struct _AgPerDisplayData AgPerDisplayData;
|
||||
|
||||
struct _ListNode
|
||||
{
|
||||
ListNode *next;
|
||||
};
|
||||
|
||||
struct _AgGetPropertyTask
|
||||
{
|
||||
ListNode node;
|
||||
|
||||
AgPerDisplayData *dd;
|
||||
Window window;
|
||||
Atom property;
|
||||
|
||||
unsigned long request_seq;
|
||||
int error;
|
||||
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
|
||||
unsigned long n_items;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *data;
|
||||
|
||||
Bool have_reply;
|
||||
};
|
||||
|
||||
struct _AgPerDisplayData
|
||||
{
|
||||
ListNode node;
|
||||
_XAsyncHandler async;
|
||||
|
||||
Display *display;
|
||||
ListNode *pending_tasks;
|
||||
ListNode *pending_tasks_tail;
|
||||
ListNode *completed_tasks;
|
||||
ListNode *completed_tasks_tail;
|
||||
int n_tasks_pending;
|
||||
int n_tasks_completed;
|
||||
};
|
||||
|
||||
static ListNode *display_datas = NULL;
|
||||
static ListNode *display_datas_tail = NULL;
|
||||
|
||||
static void
|
||||
append_to_list (ListNode **head,
|
||||
ListNode **tail,
|
||||
ListNode *task)
|
||||
{
|
||||
task->next = NULL;
|
||||
|
||||
if (*tail == NULL)
|
||||
{
|
||||
assert (*head == NULL);
|
||||
*head = task;
|
||||
*tail = task;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*tail)->next = task;
|
||||
*tail = task;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_from_list (ListNode **head,
|
||||
ListNode **tail,
|
||||
ListNode *task)
|
||||
{
|
||||
ListNode *prev;
|
||||
ListNode *node;
|
||||
|
||||
prev = NULL;
|
||||
node = *head;
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node == task)
|
||||
{
|
||||
if (prev)
|
||||
prev->next = node->next;
|
||||
else
|
||||
*head = node->next;
|
||||
|
||||
if (node == *tail)
|
||||
*tail = prev;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* can't remove what's not there */
|
||||
assert (node != NULL);
|
||||
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
move_to_completed (AgPerDisplayData *dd,
|
||||
AgGetPropertyTask *task)
|
||||
{
|
||||
remove_from_list (&dd->pending_tasks,
|
||||
&dd->pending_tasks_tail,
|
||||
&task->node);
|
||||
|
||||
append_to_list (&dd->completed_tasks,
|
||||
&dd->completed_tasks_tail,
|
||||
&task->node);
|
||||
|
||||
dd->n_tasks_pending -= 1;
|
||||
dd->n_tasks_completed += 1;
|
||||
}
|
||||
|
||||
static AgGetPropertyTask*
|
||||
find_pending_by_request_sequence (AgPerDisplayData *dd,
|
||||
unsigned long request_seq)
|
||||
{
|
||||
ListNode *node;
|
||||
|
||||
/* if the sequence is after our last pending task, we
|
||||
* aren't going to find a match
|
||||
*/
|
||||
{
|
||||
AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
|
||||
if (task != NULL)
|
||||
{
|
||||
if (task->request_seq < request_seq)
|
||||
return NULL;
|
||||
else if (task->request_seq == request_seq)
|
||||
return task; /* why not check this */
|
||||
}
|
||||
}
|
||||
|
||||
/* Generally we should get replies in the order we sent
|
||||
* requests, so we should usually be using the task
|
||||
* at the head of the list, if we use any task at all.
|
||||
* I'm not sure this is 100% guaranteed, if it is,
|
||||
* it would be a big speedup.
|
||||
*/
|
||||
|
||||
node = dd->pending_tasks;
|
||||
while (node != NULL)
|
||||
{
|
||||
AgGetPropertyTask *task = (AgGetPropertyTask*) node;
|
||||
|
||||
if (task->request_seq == request_seq)
|
||||
return task;
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Bool
|
||||
async_get_property_handler (Display *dpy,
|
||||
xReply *rep,
|
||||
char *buf,
|
||||
int len,
|
||||
XPointer data)
|
||||
{
|
||||
xGetPropertyReply replbuf;
|
||||
xGetPropertyReply *reply;
|
||||
AgGetPropertyTask *task;
|
||||
AgPerDisplayData *dd;
|
||||
int bytes_read;
|
||||
|
||||
dd = (AgPerDisplayData*) data;
|
||||
|
||||
#if 0
|
||||
printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
|
||||
dpy->last_request_read, len);
|
||||
#endif
|
||||
|
||||
task = find_pending_by_request_sequence (dd, dpy->last_request_read);
|
||||
|
||||
if (task == NULL)
|
||||
return False;
|
||||
|
||||
assert (dpy->last_request_read == task->request_seq);
|
||||
|
||||
task->have_reply = True;
|
||||
move_to_completed (dd, task);
|
||||
|
||||
/* read bytes so far */
|
||||
bytes_read = SIZEOF (xReply);
|
||||
|
||||
if (rep->generic.type == X_Error)
|
||||
{
|
||||
xError errbuf;
|
||||
|
||||
task->error = rep->error.errorCode;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n",
|
||||
__FUNCTION__, task->error, (SIZEOF (xError) - bytes_read),
|
||||
rep->generic.length);
|
||||
#endif
|
||||
|
||||
/* We return True (meaning we consumed the reply)
|
||||
* because otherwise it would invoke the X error handler,
|
||||
* and an async API is useless if you have to synchronously
|
||||
* trap X errors. Also GetProperty can always fail, pretty
|
||||
* much, so trapping errors is always what you want.
|
||||
*
|
||||
* We have to eat all the error reply data here.
|
||||
* (kind of a charade as we know sizeof(xError) == sizeof(xReply))
|
||||
*
|
||||
* Passing discard = True seems to break things; I don't understand
|
||||
* why, because there should be no extra data in an error reply,
|
||||
* right?
|
||||
*/
|
||||
_XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
|
||||
(SIZEOF (xError) - bytes_read) >> 2, /* in 32-bit words */
|
||||
False); /* really seems like it should be True */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n",
|
||||
__FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
|
||||
SIZEOF (xGetPropertyReply), rep->generic.length);
|
||||
#endif
|
||||
|
||||
/* (kind of a silly as we know sizeof(xGetPropertyReply) == sizeof(xReply)) */
|
||||
reply = (xGetPropertyReply *)
|
||||
_XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
|
||||
(SIZEOF (xGetPropertyReply) - bytes_read) >> 2, /* in 32-bit words */
|
||||
False); /* False means expecting more data to follow,
|
||||
* don't eat the rest of the reply
|
||||
*/
|
||||
|
||||
bytes_read = SIZEOF (xGetPropertyReply);
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n",
|
||||
__FUNCTION__, reply->propertyType, reply->format, reply->nItems);
|
||||
#endif
|
||||
|
||||
assert (task->data == NULL);
|
||||
|
||||
/* This is all copied from XGetWindowProperty(). Not sure we should
|
||||
* LockDisplay(). Not sure I'm passing the right args to
|
||||
* XGetAsyncData(). Not sure about a lot of things.
|
||||
*/
|
||||
|
||||
/* LockDisplay (dpy); */
|
||||
|
||||
if (reply->propertyType != None)
|
||||
{
|
||||
long nbytes, netbytes;
|
||||
|
||||
/* this alignment macro from orbit2 */
|
||||
#define ALIGN_VALUE(this, boundary) \
|
||||
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
|
||||
|
||||
switch (reply->format)
|
||||
{
|
||||
/*
|
||||
* One extra byte is malloced than is needed to contain the property
|
||||
* data, but this last byte is null terminated and convenient for
|
||||
* returning string properties, so the client doesn't then have to
|
||||
* recopy the string to make it null terminated.
|
||||
*/
|
||||
case 8:
|
||||
nbytes = reply->nItems;
|
||||
/* there's padding to word boundary */
|
||||
netbytes = ALIGN_VALUE (nbytes, 4);
|
||||
if (nbytes + 1 > 0 &&
|
||||
(task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: already read %d bytes using %ld, more eating %ld more\n",
|
||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
||||
#endif
|
||||
/* _XReadPad (dpy, (char *) task->data, netbytes); */
|
||||
_XGetAsyncData (dpy, task->data, buf, len,
|
||||
bytes_read, nbytes,
|
||||
netbytes);
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
nbytes = reply->nItems * sizeof (short);
|
||||
netbytes = reply->nItems << 1;
|
||||
netbytes = ALIGN_VALUE (netbytes, 4); /* align to word boundary */
|
||||
if (nbytes + 1 > 0 &&
|
||||
(task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
|
||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
||||
#endif
|
||||
/* _XRead16Pad (dpy, (short *) task->data, netbytes); */
|
||||
_XGetAsyncData (dpy, task->data, buf, len,
|
||||
bytes_read, nbytes, netbytes);
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
/* NOTE buffer is in longs to match XGetWindowProperty() */
|
||||
nbytes = reply->nItems * sizeof (long);
|
||||
netbytes = reply->nItems << 2; /* wire size is always 32 bits though */
|
||||
if (nbytes + 1 > 0 &&
|
||||
(task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
|
||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
||||
#endif
|
||||
|
||||
/* We have to copy the XGetWindowProperty() crackrock
|
||||
* and get format 32 as long even on 64-bit platforms.
|
||||
*/
|
||||
if (sizeof (long) == 8)
|
||||
{
|
||||
unsigned char *netdata;
|
||||
unsigned char *lptr;
|
||||
unsigned char *end_lptr;
|
||||
|
||||
/* Store the 32-bit values in the end of the array */
|
||||
netdata = task->data + nbytes / 2;
|
||||
|
||||
_XGetAsyncData (dpy, netdata, buf, len,
|
||||
bytes_read, netbytes,
|
||||
netbytes);
|
||||
|
||||
/* Now move the 32-bit values to the front */
|
||||
|
||||
lptr = task->data;
|
||||
end_lptr = task->data + nbytes;
|
||||
while (lptr != end_lptr)
|
||||
{
|
||||
*(long*) lptr = *(CARD32*) netdata;
|
||||
lptr += sizeof (long);
|
||||
netdata += sizeof (CARD32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here the wire format matches our actual format */
|
||||
_XGetAsyncData (dpy, task->data, buf, len,
|
||||
bytes_read, netbytes,
|
||||
netbytes);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* This part of the code should never be reached. If it is,
|
||||
* the server sent back a property with an invalid format.
|
||||
* This is a BadImplementation error.
|
||||
*
|
||||
* However this async GetProperty API doesn't report errors
|
||||
* via the standard X mechanism, so don't do anything about
|
||||
* it, other than store it in task->error.
|
||||
*/
|
||||
{
|
||||
#if 0
|
||||
xError error;
|
||||
#endif
|
||||
|
||||
task->error = BadImplementation;
|
||||
|
||||
#if 0
|
||||
error.sequenceNumber = task->request_seq;
|
||||
error.type = X_Error;
|
||||
error.majorCode = X_GetProperty;
|
||||
error.minorCode = 0;
|
||||
error.errorCode = BadImplementation;
|
||||
|
||||
_XError (dpy, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
nbytes = netbytes = 0L;
|
||||
break;
|
||||
}
|
||||
|
||||
if (task->data == NULL)
|
||||
{
|
||||
task->error = BadAlloc;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: already read %d bytes eating %ld\n",
|
||||
__FUNCTION__, bytes_read, netbytes);
|
||||
#endif
|
||||
/* _XEatData (dpy, (unsigned long) netbytes); */
|
||||
_XGetAsyncData (dpy, NULL, buf, len,
|
||||
bytes_read, 0, netbytes);
|
||||
|
||||
/* UnlockDisplay (dpy); */
|
||||
return BadAlloc; /* not Success */
|
||||
}
|
||||
|
||||
(task->data)[nbytes] = '\0';
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%s: have data\n", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
task->actual_type = reply->propertyType;
|
||||
task->actual_format = reply->format;
|
||||
task->n_items = reply->nItems;
|
||||
task->bytes_after = reply->bytesAfter;
|
||||
|
||||
/* UnlockDisplay (dpy); */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static AgPerDisplayData*
|
||||
get_display_data (Display *display,
|
||||
Bool create)
|
||||
{
|
||||
ListNode *node;
|
||||
AgPerDisplayData *dd;
|
||||
|
||||
node = display_datas;
|
||||
while (node != NULL)
|
||||
{
|
||||
dd = (AgPerDisplayData*) node;
|
||||
|
||||
if (dd->display == display)
|
||||
return dd;
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
dd = Xcalloc (1, sizeof (AgPerDisplayData));
|
||||
if (dd == NULL)
|
||||
return NULL;
|
||||
|
||||
dd->display = display;
|
||||
dd->async.next = display->async_handlers;
|
||||
dd->async.handler = async_get_property_handler;
|
||||
dd->async.data = (XPointer) dd;
|
||||
dd->display->async_handlers = &dd->async;
|
||||
|
||||
append_to_list (&display_datas,
|
||||
&display_datas_tail,
|
||||
&dd->node);
|
||||
|
||||
return dd;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_free_display_data (AgPerDisplayData *dd)
|
||||
{
|
||||
if (dd->pending_tasks == NULL &&
|
||||
dd->completed_tasks == NULL)
|
||||
{
|
||||
DeqAsyncHandler (dd->display, &dd->async);
|
||||
remove_from_list (&display_datas, &display_datas_tail,
|
||||
&dd->node);
|
||||
XFree (dd);
|
||||
}
|
||||
}
|
||||
|
||||
AgGetPropertyTask*
|
||||
ag_task_create (Display *dpy,
|
||||
Window window,
|
||||
Atom property,
|
||||
long offset,
|
||||
long length,
|
||||
Bool delete,
|
||||
Atom req_type)
|
||||
{
|
||||
AgGetPropertyTask *task;
|
||||
xGetPropertyReq *req;
|
||||
xError error;
|
||||
AgPerDisplayData *dd;
|
||||
|
||||
/* Fire up our request */
|
||||
LockDisplay (dpy);
|
||||
|
||||
dd = get_display_data (dpy, True);
|
||||
if (dd == NULL)
|
||||
{
|
||||
UnlockDisplay (dpy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GetReq (GetProperty, req);
|
||||
req->window = window;
|
||||
req->property = property;
|
||||
req->type = req_type;
|
||||
req->delete = delete;
|
||||
req->longOffset = offset;
|
||||
req->longLength = length;
|
||||
|
||||
error.sequenceNumber = dpy->request;
|
||||
|
||||
/* Queue up our async task */
|
||||
task = Xcalloc (1, sizeof (AgGetPropertyTask));
|
||||
if (task == NULL)
|
||||
{
|
||||
UnlockDisplay (dpy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task->dd = dd;
|
||||
task->window = window;
|
||||
task->property = property;
|
||||
task->request_seq = dpy->request;
|
||||
|
||||
append_to_list (&dd->pending_tasks,
|
||||
&dd->pending_tasks_tail,
|
||||
&task->node);
|
||||
dd->n_tasks_pending += 1;
|
||||
|
||||
UnlockDisplay (dpy);
|
||||
|
||||
SyncHandle ();
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static void
|
||||
free_task (AgGetPropertyTask *task)
|
||||
{
|
||||
remove_from_list (&task->dd->completed_tasks,
|
||||
&task->dd->completed_tasks_tail,
|
||||
&task->node);
|
||||
task->dd->n_tasks_completed -= 1;
|
||||
maybe_free_display_data (task->dd);
|
||||
XFree (task);
|
||||
}
|
||||
|
||||
Status
|
||||
ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
||||
Atom *actual_type,
|
||||
int *actual_format,
|
||||
unsigned long *nitems,
|
||||
unsigned long *bytesafter,
|
||||
unsigned char **prop)
|
||||
{
|
||||
Display *dpy;
|
||||
|
||||
*prop = NULL;
|
||||
|
||||
dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */
|
||||
|
||||
if (task->error != Success)
|
||||
{
|
||||
Status s = task->error;
|
||||
|
||||
free_task (task);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
if (!task->have_reply)
|
||||
{
|
||||
free_task (task);
|
||||
|
||||
return BadAlloc; /* not Success */
|
||||
}
|
||||
|
||||
*actual_type = task->actual_type;
|
||||
*actual_format = task->actual_format;
|
||||
*nitems = task->n_items;
|
||||
*bytesafter = task->bytes_after;
|
||||
|
||||
*prop = task->data; /* pass out ownership of task->data */
|
||||
|
||||
SyncHandle ();
|
||||
|
||||
free_task (task);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Bool
|
||||
ag_task_have_reply (AgGetPropertyTask *task)
|
||||
{
|
||||
return task->have_reply;
|
||||
}
|
||||
|
||||
Atom
|
||||
ag_task_get_property (AgGetPropertyTask *task)
|
||||
{
|
||||
return task->property;
|
||||
}
|
||||
|
||||
Window
|
||||
ag_task_get_window (AgGetPropertyTask *task)
|
||||
{
|
||||
return task->window;
|
||||
}
|
||||
|
||||
Display*
|
||||
ag_task_get_display (AgGetPropertyTask *task)
|
||||
{
|
||||
return task->dd->display;
|
||||
}
|
||||
|
||||
AgGetPropertyTask*
|
||||
ag_get_next_completed_task (Display *display)
|
||||
{
|
||||
AgPerDisplayData *dd;
|
||||
|
||||
dd = get_display_data (display, False);
|
||||
|
||||
if (dd == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
printf ("%d pending %d completed\n",
|
||||
dd->n_tasks_pending,
|
||||
dd->n_tasks_completed);
|
||||
#endif
|
||||
|
||||
return (AgGetPropertyTask*) dd->completed_tasks;
|
||||
}
|
||||
|
||||
void*
|
||||
ag_Xmalloc (unsigned long bytes)
|
||||
{
|
||||
return (void*) Xmalloc (bytes);
|
||||
}
|
||||
|
||||
void*
|
||||
ag_Xmalloc0 (unsigned long bytes)
|
||||
{
|
||||
return (void*) Xcalloc (bytes, 1);
|
||||
}
|
65
src/async-getprop.h
Normal file
65
src/async-getprop.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Asynchronous X property getting hack */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Havoc Pennington
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of The Open Group shall not be
|
||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
||||
* in this Software without prior written authorization from The Open Group.
|
||||
*/
|
||||
|
||||
#ifndef ASYNC_GETPROP_H
|
||||
#define ASYNC_GETPROP_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
typedef struct _AgGetPropertyTask AgGetPropertyTask;
|
||||
|
||||
AgGetPropertyTask* ag_task_create (Display *display,
|
||||
Window window,
|
||||
Atom property,
|
||||
long offset,
|
||||
long length,
|
||||
Bool delete,
|
||||
Atom req_type);
|
||||
Status ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
||||
Atom *actual_type,
|
||||
int *actual_format,
|
||||
unsigned long *nitems,
|
||||
unsigned long *bytesafter,
|
||||
unsigned char **prop);
|
||||
|
||||
Bool ag_task_have_reply (AgGetPropertyTask *task);
|
||||
Atom ag_task_get_property (AgGetPropertyTask *task);
|
||||
Window ag_task_get_window (AgGetPropertyTask *task);
|
||||
Display* ag_task_get_display (AgGetPropertyTask *task);
|
||||
|
||||
AgGetPropertyTask* ag_get_next_completed_task (Display *display);
|
||||
|
||||
/* so other headers don't have to include internal Xlib goo */
|
||||
void* ag_Xmalloc (unsigned long bytes);
|
||||
void* ag_Xmalloc0 (unsigned long bytes);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
250
src/bell.c
Normal file
250
src/bell.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/* Metacity visual bell */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Sun Microsystems Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "bell.h"
|
||||
#include "screen.h"
|
||||
#include "prefs.h"
|
||||
|
||||
static void
|
||||
meta_bell_flash_screen (MetaDisplay *display,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
Window root = screen->xroot;
|
||||
int width = screen->width;
|
||||
int height = screen->height;
|
||||
|
||||
if (screen->flash_window == None)
|
||||
{
|
||||
Visual *visual = CopyFromParent;
|
||||
XSetWindowAttributes xswa;
|
||||
int depth = CopyFromParent;
|
||||
xswa.save_under = True;
|
||||
xswa.override_redirect = True;
|
||||
/*
|
||||
* TODO: use XGetVisualInfo and determine which is an
|
||||
* overlay, if one is present, and use the Overlay visual
|
||||
* for this window (for performance reasons).
|
||||
* Not sure how to tell this yet...
|
||||
*/
|
||||
screen->flash_window = XCreateWindow (display->xdisplay, root,
|
||||
0, 0, width, height,
|
||||
0, depth,
|
||||
InputOutput,
|
||||
visual,
|
||||
/* note: XSun doesn't like SaveUnder here */
|
||||
CWSaveUnder | CWOverrideRedirect,
|
||||
&xswa);
|
||||
XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSync (display->xdisplay, False);
|
||||
XFlush (display->xdisplay);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just draw something in the window */
|
||||
GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
WhitePixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
BlackPixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XFlush (display->xdisplay);
|
||||
XSync (display->xdisplay, False);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
}
|
||||
XFlush (display->xdisplay);
|
||||
}
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
static void
|
||||
meta_bell_flash_fullscreen (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
|
||||
MetaScreen *screen;
|
||||
|
||||
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||
if (xkb_bell_ev->window != None)
|
||||
{
|
||||
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
|
||||
if (screen)
|
||||
meta_bell_flash_screen (display, screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSList *screen_list = display->screens;
|
||||
while (screen_list)
|
||||
{
|
||||
screen = (MetaScreen *) screen_list->data;
|
||||
meta_bell_flash_screen (display, screen);
|
||||
screen_list = screen_list->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_bell_unflash_frame (gpointer data)
|
||||
{
|
||||
MetaFrame *frame = (MetaFrame *) data;
|
||||
frame->is_flashing = 0;
|
||||
meta_frame_queue_draw (frame);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_bell_flash_window_frame (MetaWindow *window)
|
||||
{
|
||||
g_assert (window->frame != NULL);
|
||||
window->frame->is_flashing = 1;
|
||||
meta_frame_queue_draw (window->frame);
|
||||
g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 100,
|
||||
meta_bell_unflash_frame, window->frame, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_bell_flash_frame (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
|
||||
MetaWindow *window;
|
||||
|
||||
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
|
||||
if (!window && (display->focus_window) && (display->focus_window->frame))
|
||||
{
|
||||
window = display->focus_window;
|
||||
}
|
||||
if (window)
|
||||
{
|
||||
meta_bell_flash_window_frame (window);
|
||||
}
|
||||
else /* revert to fullscreen flash if there's no focussed window */
|
||||
{
|
||||
meta_bell_flash_fullscreen (display, xkb_ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_bell_visual_notify (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
switch (meta_prefs_get_visual_bell_type ())
|
||||
{
|
||||
case META_VISUAL_BELL_FULLSCREEN_FLASH:
|
||||
meta_bell_flash_fullscreen (display, xkb_ev);
|
||||
break;
|
||||
case META_VISUAL_BELL_FRAME_FLASH:
|
||||
meta_bell_flash_frame (display, xkb_ev); /* does nothing yet */
|
||||
break;
|
||||
case META_VISUAL_BELL_INVALID:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_bell_notify (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
/* flash something */
|
||||
if (meta_prefs_get_visual_bell ())
|
||||
meta_bell_visual_notify (display, xkb_ev);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
XkbChangeEnabledControls (display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
audible ? XkbAudibleBellMask : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_bell_init (MetaDisplay *display)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
int xkb_base_error_type, xkb_opcode;
|
||||
|
||||
if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
|
||||
&display->xkb_base_event_type,
|
||||
&xkb_base_error_type,
|
||||
NULL, NULL))
|
||||
{
|
||||
display->xkb_base_event_type = -1;
|
||||
g_message ("could not find XKB extension.");
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int mask = XkbBellNotifyMask;
|
||||
gboolean visual_bell_auto_reset = FALSE;
|
||||
/* TRUE if and when non-broken version is available */
|
||||
XkbSelectEvents (display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbBellNotifyMask,
|
||||
XkbBellNotifyMask);
|
||||
XkbChangeEnabledControls (display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
meta_prefs_bell_is_audible ()
|
||||
? XkbAudibleBellMask : 0);
|
||||
if (visual_bell_auto_reset) {
|
||||
XkbSetAutoResetControls (display->xdisplay,
|
||||
XkbAudibleBellMask,
|
||||
&mask,
|
||||
&mask);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_bell_shutdown (MetaDisplay *display)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
/* TODO: persist initial bell state in display, reset here */
|
||||
XkbChangeEnabledControls (display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
XkbAudibleBellMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
meta_bell_notify_frame_destroy (MetaFrame *frame)
|
||||
{
|
||||
if (frame->is_flashing)
|
||||
g_idle_remove_by_data (frame);
|
||||
}
|
35
src/bell.h
Normal file
35
src/bell.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Metacity visual bell */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Sun Microsystems Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#ifdef HAVE_XKB
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
#include "display.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev);
|
||||
#endif
|
||||
void meta_bell_set_audible (MetaDisplay *display, gboolean audible);
|
||||
gboolean meta_bell_init (MetaDisplay *display);
|
||||
void meta_bell_shutdown (MetaDisplay *display);
|
||||
void meta_bell_notify_frame_destroy (MetaFrame *frame);
|
137
src/common.h
137
src/common.h
@@ -26,21 +26,24 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct _MetaResizePopup MetaResizePopup;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_FRAME_ALLOWS_DELETE = 1 << 0,
|
||||
META_FRAME_ALLOWS_MENU = 1 << 1,
|
||||
META_FRAME_ALLOWS_MINIMIZE = 1 << 2,
|
||||
META_FRAME_ALLOWS_MAXIMIZE = 1 << 3,
|
||||
META_FRAME_ALLOWS_MAXIMIZE = 1 << 3,
|
||||
META_FRAME_ALLOWS_VERTICAL_RESIZE = 1 << 4,
|
||||
META_FRAME_ALLOWS_HORIZONTAL_RESIZE = 1 << 5,
|
||||
META_FRAME_TRANSIENT = 1 << 6,
|
||||
META_FRAME_HAS_FOCUS = 1 << 7,
|
||||
META_FRAME_SHADED = 1 << 8,
|
||||
META_FRAME_STUCK = 1 << 9,
|
||||
META_FRAME_MAXIMIZED = 1 << 10,
|
||||
META_FRAME_ALLOWS_SHADE = 1 << 11,
|
||||
META_FRAME_ALLOWS_MOVE = 1 << 12
|
||||
META_FRAME_HAS_FOCUS = 1 << 6,
|
||||
META_FRAME_SHADED = 1 << 7,
|
||||
META_FRAME_STUCK = 1 << 8,
|
||||
META_FRAME_MAXIMIZED = 1 << 9,
|
||||
META_FRAME_ALLOWS_SHADE = 1 << 10,
|
||||
META_FRAME_ALLOWS_MOVE = 1 << 11,
|
||||
META_FRAME_FULLSCREEN = 1 << 12,
|
||||
META_FRAME_IS_FLASHING = 1 << 13
|
||||
} MetaFrameFlags;
|
||||
|
||||
typedef enum
|
||||
@@ -55,7 +58,13 @@ typedef enum
|
||||
META_MENU_OP_STICK = 1 << 7,
|
||||
META_MENU_OP_WORKSPACES = 1 << 8,
|
||||
META_MENU_OP_MOVE = 1 << 9,
|
||||
META_MENU_OP_RESIZE = 1 << 10
|
||||
META_MENU_OP_RESIZE = 1 << 10,
|
||||
META_MENU_OP_ABOVE = 1 << 11,
|
||||
META_MENU_OP_UNABOVE = 1 << 12,
|
||||
META_MENU_OP_MOVE_LEFT = 1 << 13,
|
||||
META_MENU_OP_MOVE_RIGHT = 1 << 14,
|
||||
META_MENU_OP_MOVE_UP = 1 << 15,
|
||||
META_MENU_OP_MOVE_DOWN = 1 << 16
|
||||
} MetaMenuOp;
|
||||
|
||||
typedef struct _MetaWindowMenu MetaWindowMenu;
|
||||
@@ -67,9 +76,13 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
|
||||
int workspace,
|
||||
gpointer data);
|
||||
|
||||
/* when changing this enum, there are various switch statements
|
||||
* you have to update
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
META_GRAB_OP_NONE,
|
||||
|
||||
/* Mouse ops */
|
||||
META_GRAB_OP_MOVING,
|
||||
META_GRAB_OP_RESIZING_SE,
|
||||
@@ -80,6 +93,7 @@ typedef enum
|
||||
META_GRAB_OP_RESIZING_NW,
|
||||
META_GRAB_OP_RESIZING_W,
|
||||
META_GRAB_OP_RESIZING_E,
|
||||
|
||||
/* Keyboard ops */
|
||||
META_GRAB_OP_KEYBOARD_MOVING,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
|
||||
@@ -87,14 +101,29 @@ typedef enum
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_N,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_W,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_E,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_SE,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_NE,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_SW,
|
||||
META_GRAB_OP_KEYBOARD_RESIZING_NW,
|
||||
|
||||
/* Alt+Tab */
|
||||
META_GRAB_OP_KEYBOARD_TABBING_NORMAL,
|
||||
META_GRAB_OP_KEYBOARD_TABBING_DOCK,
|
||||
|
||||
/* Alt+Esc */
|
||||
META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL,
|
||||
META_GRAB_OP_KEYBOARD_ESCAPING_DOCK,
|
||||
|
||||
META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING,
|
||||
|
||||
/* Frame button ops */
|
||||
META_GRAB_OP_CLICKING_MINIMIZE,
|
||||
META_GRAB_OP_CLICKING_MAXIMIZE,
|
||||
META_GRAB_OP_CLICKING_UNMAXIMIZE,
|
||||
META_GRAB_OP_CLICKING_DELETE,
|
||||
META_GRAB_OP_CLICKING_MENU
|
||||
} MetaGrabOp;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_CURSOR_DEFAULT,
|
||||
@@ -105,10 +134,96 @@ typedef enum
|
||||
META_CURSOR_SE_RESIZE,
|
||||
META_CURSOR_SW_RESIZE,
|
||||
META_CURSOR_NE_RESIZE,
|
||||
META_CURSOR_NW_RESIZE
|
||||
META_CURSOR_NW_RESIZE,
|
||||
META_CURSOR_MOVE_WINDOW,
|
||||
META_CURSOR_RESIZE_WINDOW,
|
||||
META_CURSOR_BUSY
|
||||
|
||||
} MetaCursor;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_FOCUS_MODE_CLICK,
|
||||
META_FOCUS_MODE_SLOPPY,
|
||||
META_FOCUS_MODE_MOUSE
|
||||
} MetaFocusMode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_ACTION_DOUBLE_CLICK_TITLEBAR_TOGGLE_SHADE,
|
||||
META_ACTION_DOUBLE_CLICK_TITLEBAR_TOGGLE_MAXIMIZE,
|
||||
META_ACTION_DOUBLE_CLICK_TITLEBAR_LAST
|
||||
} MetaActionDoubleClickTitlebar;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_FRAME_TYPE_NORMAL,
|
||||
META_FRAME_TYPE_DIALOG,
|
||||
META_FRAME_TYPE_MODAL_DIALOG,
|
||||
META_FRAME_TYPE_UTILITY,
|
||||
META_FRAME_TYPE_MENU,
|
||||
META_FRAME_TYPE_BORDER,
|
||||
META_FRAME_TYPE_LAST
|
||||
} MetaFrameType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Create gratuitous divergence from regular
|
||||
* X mod bits, to be sure we find bugs
|
||||
*/
|
||||
META_VIRTUAL_SHIFT_MASK = 1 << 5,
|
||||
META_VIRTUAL_CONTROL_MASK = 1 << 6,
|
||||
META_VIRTUAL_ALT_MASK = 1 << 7,
|
||||
META_VIRTUAL_META_MASK = 1 << 8,
|
||||
META_VIRTUAL_SUPER_MASK = 1 << 9,
|
||||
META_VIRTUAL_HYPER_MASK = 1 << 10,
|
||||
META_VIRTUAL_MOD2_MASK = 1 << 11,
|
||||
META_VIRTUAL_MOD3_MASK = 1 << 12,
|
||||
META_VIRTUAL_MOD4_MASK = 1 << 13,
|
||||
META_VIRTUAL_MOD5_MASK = 1 << 14
|
||||
} MetaVirtualModifier;
|
||||
|
||||
|
||||
/* Function a window button can have. Note, you can't add stuff here
|
||||
* without extending the theme format to draw a new function and
|
||||
* breaking all existing themes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
META_BUTTON_FUNCTION_MENU,
|
||||
META_BUTTON_FUNCTION_MINIMIZE,
|
||||
META_BUTTON_FUNCTION_MAXIMIZE,
|
||||
META_BUTTON_FUNCTION_CLOSE,
|
||||
META_BUTTON_FUNCTION_LAST
|
||||
} MetaButtonFunction;
|
||||
|
||||
#define MAX_BUTTONS_PER_CORNER META_BUTTON_FUNCTION_LAST
|
||||
|
||||
typedef struct _MetaButtonLayout MetaButtonLayout;
|
||||
struct _MetaButtonLayout
|
||||
{
|
||||
/* buttons in the group on the left side */
|
||||
MetaButtonFunction left_buttons[MAX_BUTTONS_PER_CORNER];
|
||||
|
||||
/* buttons in the group on the right side */
|
||||
MetaButtonFunction right_buttons[MAX_BUTTONS_PER_CORNER];
|
||||
};
|
||||
|
||||
/* should investigate changing these to whatever most apps use */
|
||||
#define META_ICON_WIDTH 32
|
||||
#define META_ICON_HEIGHT 32
|
||||
#define META_MINI_ICON_WIDTH 16
|
||||
#define META_MINI_ICON_HEIGHT 16
|
||||
|
||||
#define META_PRIORITY_PREFS_NOTIFY (G_PRIORITY_DEFAULT_IDLE + 10)
|
||||
#define META_PRIORITY_WORK_AREA_HINT (G_PRIORITY_DEFAULT_IDLE + 15)
|
||||
|
||||
#define POINT_IN_RECT(xcoord, ycoord, rect) \
|
||||
((xcoord) >= (rect).x && \
|
||||
(xcoord) < ((rect).x + (rect).width) && \
|
||||
(ycoord) >= (rect).y && \
|
||||
(ycoord) < ((rect).y + (rect).height))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
1305
src/compositor.c
Normal file
1305
src/compositor.c
Normal file
File diff suppressed because it is too large
Load Diff
56
src/compositor.h
Normal file
56
src/compositor.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Metacity compositing manager */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2003 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_COMPOSITOR_H
|
||||
#define META_COMPOSITOR_H
|
||||
|
||||
#include "util.h"
|
||||
#include "display.h"
|
||||
|
||||
MetaCompositor* meta_compositor_new (MetaDisplay *display);
|
||||
void meta_compositor_unref (MetaCompositor *compositor);
|
||||
void meta_compositor_process_event (MetaCompositor *compositor,
|
||||
XEvent *xevent,
|
||||
MetaWindow *window);
|
||||
void meta_compositor_add_window (MetaCompositor *compositor,
|
||||
Window xwindow,
|
||||
XWindowAttributes *attrs);
|
||||
void meta_compositor_remove_window (MetaCompositor *compositor,
|
||||
Window xwindow);
|
||||
|
||||
void meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
MetaScreen *screen);
|
||||
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
||||
MetaScreen *screen);
|
||||
|
||||
void meta_compositor_damage_window (MetaCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
#endif /* META_COMPOSITOR_H */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1612
src/constraints.c
Normal file
1612
src/constraints.c
Normal file
File diff suppressed because it is too large
Load Diff
59
src/constraints.h
Normal file
59
src/constraints.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Metacity size/position constraints */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_CONSTRAINTS_H
|
||||
#define META_CONSTRAINTS_H
|
||||
|
||||
#include "util.h"
|
||||
#include "window.h"
|
||||
#include "frame.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_RESIZE_LEFT_OR_TOP,
|
||||
META_RESIZE_CENTER,
|
||||
META_RESIZE_RIGHT_OR_BOTTOM
|
||||
} MetaResizeDirection;
|
||||
|
||||
void meta_window_constrain (MetaWindow *window,
|
||||
MetaFrameGeometry *fgeom,
|
||||
const MetaRectangle *orig,
|
||||
int x_move_delta,
|
||||
int y_move_delta,
|
||||
MetaResizeDirection x_direction,
|
||||
int x_delta,
|
||||
MetaResizeDirection y_direction,
|
||||
int y_delta,
|
||||
MetaRectangle *new);
|
||||
|
||||
MetaResizeDirection meta_x_direction_from_gravity (int gravity);
|
||||
MetaResizeDirection meta_y_direction_from_gravity (int gravity);
|
||||
|
||||
#endif /* META_CONSTRAINTS_H */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
373
src/core.c
373
src/core.c
@@ -2,6 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -19,15 +20,17 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "core.h"
|
||||
#include "frame.h"
|
||||
#include "workspace.h"
|
||||
#include "prefs.h"
|
||||
|
||||
void
|
||||
meta_core_get_frame_size (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *width,
|
||||
int *height)
|
||||
meta_core_get_client_size (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
@@ -39,9 +42,25 @@ meta_core_get_frame_size (Display *xdisplay,
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
if (width)
|
||||
*width = window->frame->rect.width;
|
||||
*width = window->rect.width;
|
||||
if (height)
|
||||
*height = window->frame->rect.height;
|
||||
*height = window->rect.height;
|
||||
}
|
||||
|
||||
Window
|
||||
meta_core_get_client_xwindow (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
return window->xwindow;
|
||||
}
|
||||
|
||||
MetaFrameFlags
|
||||
@@ -60,6 +79,93 @@ meta_core_get_frame_flags (Display *xdisplay,
|
||||
return meta_frame_get_flags (window->frame);
|
||||
}
|
||||
|
||||
MetaFrameType
|
||||
meta_core_get_frame_type (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
MetaFrameType base_type;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
base_type = META_FRAME_TYPE_LAST;
|
||||
|
||||
switch (window->type)
|
||||
{
|
||||
case META_WINDOW_NORMAL:
|
||||
base_type = META_FRAME_TYPE_NORMAL;
|
||||
break;
|
||||
|
||||
case META_WINDOW_DIALOG:
|
||||
base_type = META_FRAME_TYPE_DIALOG;
|
||||
break;
|
||||
|
||||
case META_WINDOW_MODAL_DIALOG:
|
||||
base_type = META_FRAME_TYPE_MODAL_DIALOG;
|
||||
break;
|
||||
|
||||
case META_WINDOW_MENU:
|
||||
base_type = META_FRAME_TYPE_MENU;
|
||||
break;
|
||||
|
||||
case META_WINDOW_UTILITY:
|
||||
base_type = META_FRAME_TYPE_UTILITY;
|
||||
break;
|
||||
|
||||
case META_WINDOW_DESKTOP:
|
||||
case META_WINDOW_DOCK:
|
||||
case META_WINDOW_TOOLBAR:
|
||||
case META_WINDOW_SPLASHSCREEN:
|
||||
/* No frame */
|
||||
base_type = META_FRAME_TYPE_LAST;
|
||||
break;
|
||||
}
|
||||
|
||||
if (base_type == META_FRAME_TYPE_LAST)
|
||||
return META_FRAME_TYPE_LAST; /* can't add border if undecorated */
|
||||
else if (window->border_only)
|
||||
return META_FRAME_TYPE_BORDER; /* override base frame type */
|
||||
else
|
||||
return base_type;
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
meta_core_get_mini_icon (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
return window->mini_icon;
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
meta_core_get_icon (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
return window->icon;
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_queue_frame_resize (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
@@ -91,8 +197,7 @@ meta_core_user_move (Display *xdisplay,
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
window->user_has_moved = TRUE;
|
||||
meta_window_move (window, x, y);
|
||||
meta_window_move (window, TRUE, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -111,8 +216,7 @@ meta_core_user_resize (Display *xdisplay,
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
window->user_has_resized = TRUE;
|
||||
meta_window_resize_with_gravity (window, width, height, gravity);
|
||||
meta_window_resize_with_gravity (window, TRUE, width, height, gravity);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -131,6 +235,22 @@ meta_core_user_raise (Display *xdisplay,
|
||||
meta_window_raise (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_user_lower (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
meta_window_lower (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_user_focus (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
@@ -220,6 +340,25 @@ meta_core_maximize (Display *xdisplay,
|
||||
meta_window_maximize (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_toggle_maximize (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
if (window->maximized)
|
||||
meta_window_unmaximize (window);
|
||||
else
|
||||
meta_window_maximize (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_unmaximize (Display *xdisplay,
|
||||
Window frame_xwindow)
|
||||
@@ -332,9 +471,8 @@ meta_core_change_workspace (Display *xdisplay,
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
meta_window_change_workspace (window,
|
||||
meta_display_get_workspace_by_screen_index (display,
|
||||
window->screen,
|
||||
new_workspace));
|
||||
meta_screen_get_workspace_by_index (window->screen,
|
||||
new_workspace));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -354,7 +492,7 @@ meta_core_get_active_workspace (Screen *xscreen)
|
||||
|
||||
screen = meta_screen_for_x_screen (xscreen);
|
||||
|
||||
return meta_workspace_screen_index (screen->active_workspace);
|
||||
return meta_workspace_index (screen->active_workspace);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -373,6 +511,34 @@ meta_core_get_frame_workspace (Display *xdisplay,
|
||||
return meta_window_get_net_wm_desktop (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_get_frame_extents (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *x,
|
||||
int *y,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
if (x)
|
||||
*x = window->frame->rect.x;
|
||||
if (y)
|
||||
*y = window->frame->rect.y;
|
||||
if (width)
|
||||
*width = window->frame->rect.width;
|
||||
if (height)
|
||||
*height = window->frame->rect.height;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
meta_core_show_window_menu (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
@@ -390,14 +556,142 @@ meta_core_show_window_menu (Display *xdisplay,
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
meta_window_raise (window);
|
||||
meta_window_focus (window, timestamp);
|
||||
|
||||
meta_window_show_menu (window, root_x, root_y, button, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_get_menu_accelerator (MetaMenuOp menu_op,
|
||||
int workspace,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = NULL;
|
||||
|
||||
switch (menu_op)
|
||||
{
|
||||
case META_MENU_OP_DELETE:
|
||||
name = META_KEYBINDING_CLOSE;
|
||||
break;
|
||||
case META_MENU_OP_MINIMIZE:
|
||||
name = META_KEYBINDING_MINIMIZE;
|
||||
break;
|
||||
case META_MENU_OP_UNMAXIMIZE:
|
||||
name = META_KEYBINDING_UNMAXIMIZE;
|
||||
break;
|
||||
case META_MENU_OP_MAXIMIZE:
|
||||
name = META_KEYBINDING_MAXIMIZE;
|
||||
break;
|
||||
case META_MENU_OP_UNSHADE:
|
||||
case META_MENU_OP_SHADE:
|
||||
name = META_KEYBINDING_TOGGLE_SHADE;
|
||||
break;
|
||||
case META_MENU_OP_UNSTICK:
|
||||
case META_MENU_OP_STICK:
|
||||
name = META_KEYBINDING_TOGGLE_STICKY;
|
||||
break;
|
||||
case META_MENU_OP_ABOVE:
|
||||
case META_MENU_OP_UNABOVE:
|
||||
name = META_KEYBINDING_TOGGLE_ABOVE;
|
||||
break;
|
||||
case META_MENU_OP_WORKSPACES:
|
||||
switch (workspace)
|
||||
{
|
||||
case 1:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_1;
|
||||
break;
|
||||
case 2:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_2;
|
||||
break;
|
||||
case 3:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_3;
|
||||
break;
|
||||
case 4:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_4;
|
||||
break;
|
||||
case 5:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_5;
|
||||
break;
|
||||
case 6:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_6;
|
||||
break;
|
||||
case 7:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_7;
|
||||
break;
|
||||
case 8:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_8;
|
||||
break;
|
||||
case 9:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_9;
|
||||
break;
|
||||
case 10:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_10;
|
||||
break;
|
||||
case 11:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_11;
|
||||
break;
|
||||
case 12:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_12;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case META_MENU_OP_MOVE:
|
||||
name = META_KEYBINDING_BEGIN_MOVE;
|
||||
break;
|
||||
case META_MENU_OP_RESIZE:
|
||||
name = META_KEYBINDING_BEGIN_RESIZE;
|
||||
break;
|
||||
case META_MENU_OP_MOVE_LEFT:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_LEFT;
|
||||
break;
|
||||
case META_MENU_OP_MOVE_RIGHT:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_RIGHT;
|
||||
break;
|
||||
case META_MENU_OP_MOVE_UP:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_UP;
|
||||
break;
|
||||
case META_MENU_OP_MOVE_DOWN:
|
||||
name = META_KEYBINDING_MOVE_WORKSPACE_DOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
meta_prefs_get_window_binding (name, keysym, modifiers);
|
||||
}
|
||||
else
|
||||
{
|
||||
*keysym = 0;
|
||||
*modifiers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
meta_core_get_workspace_name_with_index (Display *xdisplay,
|
||||
Window xroot,
|
||||
int index)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWorkspace *workspace;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_root (display, xroot);
|
||||
g_assert (screen != NULL);
|
||||
workspace = meta_screen_get_workspace_by_index (screen, index);
|
||||
return workspace ? meta_workspace_get_name (workspace) : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_core_begin_grab_op (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
MetaGrabOp op,
|
||||
gboolean pointer_already_grabbed,
|
||||
int event_serial,
|
||||
int button,
|
||||
gulong modmask,
|
||||
Time timestamp,
|
||||
@@ -406,15 +700,20 @@ meta_core_begin_grab_op (Display *xdisplay,
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
MetaScreen *screen;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_xwindow (display, frame_xwindow);
|
||||
window = meta_display_lookup_x_window (display, frame_xwindow);
|
||||
|
||||
g_assert (screen != NULL);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
return meta_display_begin_grab_op (display, window,
|
||||
return meta_display_begin_grab_op (display, screen, window,
|
||||
op, pointer_already_grabbed,
|
||||
event_serial,
|
||||
button, modmask,
|
||||
timestamp, root_x, root_y);
|
||||
}
|
||||
@@ -447,7 +746,14 @@ meta_core_get_grab_frame (Display *xdisplay)
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
g_assert (display != NULL);
|
||||
g_assert (display->grab_op == META_GRAB_OP_NONE ||
|
||||
display->grab_screen != NULL);
|
||||
g_assert (display->grab_op == META_GRAB_OP_NONE ||
|
||||
display->grab_screen->display->xdisplay == xdisplay);
|
||||
|
||||
if (display->grab_op != META_GRAB_OP_NONE &&
|
||||
display->grab_window &&
|
||||
display->grab_window->frame)
|
||||
return display->grab_window->frame->xwindow;
|
||||
else
|
||||
@@ -474,7 +780,8 @@ meta_core_grab_buttons (Display *xdisplay,
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
|
||||
meta_verbose ("Grabbing buttons on frame 0x%lx\n", frame_xwindow);
|
||||
meta_display_grab_window_buttons (display, frame_xwindow);
|
||||
}
|
||||
|
||||
@@ -492,5 +799,37 @@ meta_core_set_screen_cursor (Display *xdisplay,
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_on_screen);
|
||||
|
||||
meta_screen_set_cursor (window->screen, cursor);
|
||||
meta_frame_set_screen_cursor (window->frame, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_get_screen_size (Display *xdisplay,
|
||||
Window frame_on_screen,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
window = meta_display_lookup_x_window (display, frame_on_screen);
|
||||
|
||||
if (window == NULL || window->frame == NULL)
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_on_screen);
|
||||
|
||||
if (width)
|
||||
*width = window->screen->width;
|
||||
if (height)
|
||||
*height = window->screen->height;
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_increment_event_serial (Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
meta_display_increment_event_serial (display);
|
||||
}
|
||||
|
||||
|
54
src/core.h
54
src/core.h
@@ -23,18 +23,26 @@
|
||||
#define META_CORE_H
|
||||
|
||||
/* Don't include core headers here */
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include "frames.h"
|
||||
#include "common.h"
|
||||
|
||||
void meta_core_get_frame_size (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *width,
|
||||
int *height);
|
||||
void meta_core_get_client_size (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
Window meta_core_get_client_xwindow (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
|
||||
MetaFrameFlags meta_core_get_frame_flags (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
MetaFrameType meta_core_get_frame_type (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
|
||||
GdkPixbuf* meta_core_get_mini_icon (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
GdkPixbuf* meta_core_get_icon (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
|
||||
void meta_core_queue_frame_resize (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
@@ -52,6 +60,8 @@ void meta_core_user_resize (Display *xdisplay,
|
||||
|
||||
void meta_core_user_raise (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
void meta_core_user_lower (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
|
||||
void meta_core_user_focus (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
@@ -70,6 +80,8 @@ void meta_core_get_size (Display *xdisplay,
|
||||
|
||||
void meta_core_minimize (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
void meta_core_toggle_maximize (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
void meta_core_unmaximize (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
void meta_core_maximize (Display *xdisplay,
|
||||
@@ -93,6 +105,17 @@ int meta_core_get_num_workspaces (Screen *xscreen);
|
||||
int meta_core_get_active_workspace (Screen *xscreen);
|
||||
int meta_core_get_frame_workspace (Display *xdisplay,
|
||||
Window frame_xwindow);
|
||||
const char* meta_core_get_workspace_name_with_index (Display *xdisplay,
|
||||
Window xroot,
|
||||
int index);
|
||||
|
||||
void meta_core_get_frame_extents (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int *x,
|
||||
int *y,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
|
||||
void meta_core_show_window_menu (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
@@ -101,10 +124,16 @@ void meta_core_show_window_menu (Display *xdisplay,
|
||||
int button,
|
||||
Time timestamp);
|
||||
|
||||
void meta_core_get_menu_accelerator (MetaMenuOp menu_op,
|
||||
int workspace,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers);
|
||||
|
||||
gboolean meta_core_begin_grab_op (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
MetaGrabOp op,
|
||||
gboolean pointer_already_grabbed,
|
||||
int event_serial,
|
||||
int button,
|
||||
gulong modmask,
|
||||
Time timestamp,
|
||||
@@ -124,6 +153,19 @@ void meta_core_set_screen_cursor (Display *xdisplay,
|
||||
Window frame_on_screen,
|
||||
MetaCursor cursor);
|
||||
|
||||
void meta_core_get_screen_size (Display *xdisplay,
|
||||
Window frame_on_screen,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
/* Used because we ignore EnterNotify when a window is unmapped that
|
||||
* really shouldn't cause focus changes, by comparing the event serial
|
||||
* of the EnterNotify and the UnmapNotify.
|
||||
*/
|
||||
void meta_core_increment_event_serial (Display *display);
|
||||
|
||||
int meta_ui_get_last_event_serial (Display *xdisplay);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
BIN
src/default_icon.png
Normal file
BIN
src/default_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 424 B |
507
src/delete.c
Normal file
507
src/delete.c
Normal file
@@ -0,0 +1,507 @@
|
||||
/* Metacity window deletion */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "util.h"
|
||||
#include "window.h"
|
||||
#include "errors.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void meta_window_present_delete_dialog (MetaWindow *window);
|
||||
|
||||
static void
|
||||
delete_ping_reply_func (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
void *user_data)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Got reply to delete ping for %s\n",
|
||||
((MetaWindow*)user_data)->desc);
|
||||
|
||||
/* we do nothing */
|
||||
}
|
||||
|
||||
static Window
|
||||
window_from_string (const char *str)
|
||||
{
|
||||
char *end;
|
||||
unsigned long l;
|
||||
|
||||
end = NULL;
|
||||
|
||||
l = strtoul (str, &end, 16);
|
||||
|
||||
if (end == NULL || end == str)
|
||||
{
|
||||
meta_warning (_("Could not parse \"%s\" as an integer"),
|
||||
str);
|
||||
return None;
|
||||
}
|
||||
|
||||
if (*end != '\0')
|
||||
{
|
||||
meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
|
||||
end, str);
|
||||
return None;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static int
|
||||
pid_from_string (const char *str)
|
||||
{
|
||||
char *end;
|
||||
long l;
|
||||
|
||||
end = NULL;
|
||||
|
||||
l = strtol (str, &end, 10);
|
||||
|
||||
if (end == NULL || end == str)
|
||||
{
|
||||
meta_warning (_("Could not parse \"%s\" as an integer"),
|
||||
str);
|
||||
return None;
|
||||
}
|
||||
|
||||
if (*end != '\0')
|
||||
{
|
||||
meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
|
||||
end, str);
|
||||
return None;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_dialog_output (const char *str,
|
||||
int *pid_out,
|
||||
Window *win_out)
|
||||
{
|
||||
char **split;
|
||||
|
||||
split = g_strsplit (str, "\n", 2);
|
||||
if (split && split[0] && split[1])
|
||||
{
|
||||
g_strchomp (split[0]);
|
||||
g_strchomp (split[1]);
|
||||
|
||||
*pid_out = pid_from_string (split[0]);
|
||||
*win_out = window_from_string (split[1]);
|
||||
|
||||
g_strfreev (split);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_strfreev (split);
|
||||
meta_warning (_("Failed to parse message \"%s\" from dialog process\n"),
|
||||
str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
search_and_destroy_window (int pid,
|
||||
Window xwindow)
|
||||
{
|
||||
/* Find the window with the given dialog PID,
|
||||
* double check that it matches "xwindow", then
|
||||
* kill the window.
|
||||
*/
|
||||
GSList *tmp;
|
||||
gboolean found;
|
||||
|
||||
if (xwindow == None)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Window to destroy is None, doing nothing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
found = FALSE;
|
||||
tmp = meta_displays_list ();
|
||||
while (tmp != NULL)
|
||||
{
|
||||
GSList *windows = meta_display_list_windows (tmp->data);
|
||||
GSList *tmp2;
|
||||
|
||||
tmp2 = windows;
|
||||
while (tmp2 != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp2->data;
|
||||
|
||||
if (w->dialog_pid == pid)
|
||||
{
|
||||
if (w->xwindow != xwindow)
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Dialog pid matches but not xwindow (0x%lx vs. 0x%lx)\n",
|
||||
w->xwindow, xwindow);
|
||||
else
|
||||
{
|
||||
meta_window_kill (w);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
tmp2 = tmp2->next;
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Did not find a window with dialog pid %d xwindow 0x%lx\n",
|
||||
pid, xwindow);
|
||||
}
|
||||
|
||||
static void
|
||||
release_window_with_fd (int fd)
|
||||
{
|
||||
/* Find the window with the given dialog PID,
|
||||
* double check that it matches "xwindow", then
|
||||
* kill the window.
|
||||
*/
|
||||
GSList *tmp;
|
||||
gboolean found;
|
||||
|
||||
found = FALSE;
|
||||
|
||||
tmp = meta_displays_list ();
|
||||
while (tmp != NULL)
|
||||
{
|
||||
GSList *windows = meta_display_list_windows (tmp->data);
|
||||
GSList *tmp2;
|
||||
|
||||
tmp2 = windows;
|
||||
while (tmp2 != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp2->data;
|
||||
|
||||
if (w->dialog_pid >= 0 &&
|
||||
w->dialog_pipe == fd)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Removing dialog with fd %d pid %d from window %s\n",
|
||||
fd, w->dialog_pid, w->desc);
|
||||
meta_window_free_delete_dialog (w);
|
||||
found = TRUE;
|
||||
}
|
||||
|
||||
tmp2 = tmp2->next;
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Did not find a window with a dialog pipe %d\n",
|
||||
fd);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
io_from_ping_dialog (GIOChannel *channel,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"IO handler from ping dialog, condition = %x\n",
|
||||
condition);
|
||||
|
||||
if (condition & G_IO_IN)
|
||||
{
|
||||
char *str;
|
||||
int len;
|
||||
GError *err;
|
||||
|
||||
/* Go ahead and block for all data from child */
|
||||
str = NULL;
|
||||
len = 0;
|
||||
err = NULL;
|
||||
g_io_channel_read_to_end (channel,
|
||||
&str, &len,
|
||||
&err);
|
||||
|
||||
if (err)
|
||||
{
|
||||
meta_warning (_("Error reading from dialog display process: %s\n"),
|
||||
err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Read %d bytes strlen %d \"%s\" from child\n",
|
||||
len, str ? strlen (str) : 0, str ? str : "NULL");
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* We're supposed to kill the given window */
|
||||
int pid;
|
||||
Window xwindow;
|
||||
|
||||
if (parse_dialog_output (str, &pid, &xwindow))
|
||||
search_and_destroy_window (pid, xwindow);
|
||||
}
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
release_window_with_fd (g_io_channel_unix_get_fd (channel));
|
||||
|
||||
/* Remove the callback */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_ping_timeout_func (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
void *user_data)
|
||||
{
|
||||
MetaWindow *window = user_data;
|
||||
GError *err;
|
||||
int child_pid;
|
||||
int outpipe;
|
||||
char *argv[7];
|
||||
char numbuf[32];
|
||||
char *window_id_str;
|
||||
GIOChannel *channel;
|
||||
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Got delete ping timeout for %s\n",
|
||||
window->desc);
|
||||
|
||||
if (window->dialog_pid >= 0)
|
||||
{
|
||||
meta_window_present_delete_dialog (window);
|
||||
return;
|
||||
}
|
||||
|
||||
window_id_str = g_strdup_printf ("0x%lx", window->xwindow);
|
||||
|
||||
sprintf (numbuf, "%d", window->screen->number);
|
||||
|
||||
argv[0] = METACITY_LIBEXECDIR"/metacity-dialog";
|
||||
argv[1] = "--screen";
|
||||
argv[2] = numbuf;
|
||||
argv[3] = "--kill-window-question";
|
||||
argv[4] = window->title;
|
||||
argv[5] = window_id_str;
|
||||
argv[6] = NULL;
|
||||
|
||||
err = NULL;
|
||||
if (!g_spawn_async_with_pipes ("/",
|
||||
argv,
|
||||
NULL,
|
||||
0,
|
||||
NULL, NULL,
|
||||
&child_pid,
|
||||
NULL,
|
||||
&outpipe,
|
||||
NULL,
|
||||
&err))
|
||||
{
|
||||
meta_warning (_("Error launching metacity-dialog to ask about killing an application: %s\n"),
|
||||
err->message);
|
||||
g_error_free (err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
window->dialog_pid = child_pid;
|
||||
window->dialog_pipe = outpipe;
|
||||
|
||||
channel = g_io_channel_unix_new (window->dialog_pipe);
|
||||
g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
||||
io_from_ping_dialog,
|
||||
NULL, NULL);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
out:
|
||||
g_free (window_id_str);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_delete (MetaWindow *window,
|
||||
Time timestamp)
|
||||
{
|
||||
meta_error_trap_push (window->display);
|
||||
if (window->delete_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Deleting %s with delete_window request\n",
|
||||
window->desc);
|
||||
meta_window_send_icccm_message (window,
|
||||
window->display->atom_wm_delete_window,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Deleting %s with explicit kill\n",
|
||||
window->desc);
|
||||
XKillClient (window->display->xdisplay, window->xwindow);
|
||||
}
|
||||
meta_error_trap_pop (window->display, FALSE);
|
||||
|
||||
meta_display_ping_window (window->display,
|
||||
window,
|
||||
timestamp,
|
||||
delete_ping_reply_func,
|
||||
delete_ping_timeout_func,
|
||||
window);
|
||||
|
||||
if (window->has_focus)
|
||||
{
|
||||
/* FIXME Clean this up someday
|
||||
* http://bugzilla.gnome.org/show_bug.cgi?id=108706
|
||||
*/
|
||||
#if 0
|
||||
/* This is unfortunately going to result in weirdness
|
||||
* if the window doesn't respond to the delete event.
|
||||
* I don't know how to avoid that though.
|
||||
*/
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing MRU window because focus window %s was deleted/killed\n",
|
||||
window->desc);
|
||||
meta_workspace_focus_mru_window (window->screen->active_workspace,
|
||||
window);
|
||||
#else
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Not unfocusing %s on delete/kill\n",
|
||||
window->desc);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Window %s was deleted/killed but didn't have focus\n",
|
||||
window->desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
meta_window_kill (MetaWindow *window)
|
||||
{
|
||||
char buf[257];
|
||||
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Killing %s brutally\n",
|
||||
window->desc);
|
||||
|
||||
if (window->wm_client_machine != NULL &&
|
||||
window->net_wm_pid > 0)
|
||||
{
|
||||
if (gethostname (buf, sizeof(buf)-1) == 0)
|
||||
{
|
||||
if (strcmp (buf, window->wm_client_machine) == 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Killing %s with kill()\n",
|
||||
window->desc);
|
||||
|
||||
if (kill (window->net_wm_pid, 9) < 0)
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Failed to signal %s: %s\n",
|
||||
window->desc, strerror (errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_warning (_("Failed to get hostname: %s\n"),
|
||||
strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Disconnecting %s with XKillClient()\n",
|
||||
window->desc);
|
||||
meta_error_trap_push (window->display);
|
||||
XKillClient (window->display->xdisplay, window->xwindow);
|
||||
meta_error_trap_pop (window->display, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_free_delete_dialog (MetaWindow *window)
|
||||
{
|
||||
if (window->dialog_pid >= 0)
|
||||
{
|
||||
kill (window->dialog_pid, 9);
|
||||
close (window->dialog_pipe);
|
||||
window->dialog_pid = -1;
|
||||
window->dialog_pipe = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_present_delete_dialog (MetaWindow *window)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Presenting existing ping dialog for %s\n",
|
||||
window->desc);
|
||||
|
||||
if (window->dialog_pid >= 0)
|
||||
{
|
||||
GSList *windows;
|
||||
GSList *tmp;
|
||||
|
||||
/* Activate transient for window that belongs to
|
||||
* metacity-dialog
|
||||
*/
|
||||
|
||||
windows = meta_display_list_windows (window->display);
|
||||
tmp = windows;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
|
||||
if (w->xtransient_for == window->xwindow &&
|
||||
w->res_class &&
|
||||
g_strcasecmp (w->res_class, "metacity-dialog") == 0)
|
||||
{
|
||||
meta_window_activate (w,
|
||||
meta_display_get_current_time (w->display));
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
}
|
||||
}
|
3836
src/display.c
3836
src/display.c
File diff suppressed because it is too large
Load Diff
324
src/display.h
324
src/display.h
@@ -2,6 +2,8 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2002 Red Hat, Inc.
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -22,11 +24,25 @@
|
||||
#ifndef META_DISPLAY_H
|
||||
#define META_DISPLAY_H
|
||||
|
||||
#ifndef PACKAGE
|
||||
#error "config.h not included"
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include "eventqueue.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
#include <libsn/sn.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
|
||||
#define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0)
|
||||
|
||||
/* this doesn't really belong here, oh well. */
|
||||
typedef struct _MetaRectangle MetaRectangle;
|
||||
|
||||
@@ -38,18 +54,35 @@ struct _MetaRectangle
|
||||
int height;
|
||||
};
|
||||
|
||||
typedef struct _MetaDisplay MetaDisplay;
|
||||
typedef struct _MetaFrame MetaFrame;
|
||||
typedef struct _MetaScreen MetaScreen;
|
||||
typedef struct _MetaStack MetaStack;
|
||||
typedef struct _MetaUISlave MetaUISlave;
|
||||
typedef struct _MetaWindow MetaWindow;
|
||||
typedef struct _MetaWorkspace MetaWorkspace;
|
||||
typedef struct MetaCompositor MetaCompositor;
|
||||
typedef struct _MetaDisplay MetaDisplay;
|
||||
typedef struct _MetaFrame MetaFrame;
|
||||
typedef struct _MetaKeyBinding MetaKeyBinding;
|
||||
typedef struct _MetaScreen MetaScreen;
|
||||
typedef struct _MetaStack MetaStack;
|
||||
typedef struct _MetaUISlave MetaUISlave;
|
||||
typedef struct _MetaWindow MetaWindow;
|
||||
typedef struct _MetaWorkspace MetaWorkspace;
|
||||
|
||||
typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
|
||||
typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
|
||||
|
||||
typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
|
||||
|
||||
/* This is basically a bogus number, just has to be large enough
|
||||
* to handle the expected case of the alt+tab operation, where
|
||||
* we want to ignore serials from UnmapNotify on the tab popup,
|
||||
* and the LeaveNotify/EnterNotify from the pointer ungrab
|
||||
*/
|
||||
#define N_IGNORED_SERIALS 4
|
||||
|
||||
struct _MetaDisplay
|
||||
{
|
||||
char *name;
|
||||
@@ -76,7 +109,7 @@ struct _MetaDisplay
|
||||
Atom atom_wm_window_role;
|
||||
Atom atom_net_current_desktop;
|
||||
Atom atom_net_supporting_wm_check;
|
||||
Atom atom_net_wm_supported;
|
||||
Atom atom_net_supported;
|
||||
Atom atom_net_wm_window_type;
|
||||
Atom atom_net_wm_window_type_desktop;
|
||||
Atom atom_net_wm_window_type_dock;
|
||||
@@ -89,47 +122,202 @@ struct _MetaDisplay
|
||||
Atom atom_net_client_list_stacking;
|
||||
Atom atom_net_wm_state_skip_taskbar;
|
||||
Atom atom_net_wm_state_skip_pager;
|
||||
Atom atom_win_workspace;
|
||||
Atom atom_win_layer;
|
||||
Atom atom_win_protocols;
|
||||
Atom atom_win_supporting_wm_check;
|
||||
Atom atom_net_wm_icon_name;
|
||||
Atom atom_net_wm_icon;
|
||||
|
||||
Atom atom_net_wm_icon_geometry;
|
||||
Atom atom_utf8_string;
|
||||
Atom atom_wm_icon_size;
|
||||
Atom atom_kwm_win_icon;
|
||||
Atom atom_net_wm_moveresize;
|
||||
Atom atom_net_active_window;
|
||||
Atom atom_metacity_restart_message;
|
||||
Atom atom_net_wm_strut;
|
||||
Atom atom_metacity_reload_theme_message;
|
||||
Atom atom_metacity_set_keybindings_message;
|
||||
Atom atom_net_wm_state_hidden;
|
||||
Atom atom_net_wm_window_type_utility;
|
||||
Atom atom_net_wm_window_type_splash;
|
||||
Atom atom_net_wm_ping;
|
||||
Atom atom_net_wm_pid;
|
||||
Atom atom_wm_client_machine;
|
||||
Atom atom_net_wm_state_fullscreen;
|
||||
Atom atom_net_workarea;
|
||||
Atom atom_net_showing_desktop;
|
||||
Atom atom_net_desktop_layout;
|
||||
Atom atom_manager;
|
||||
Atom atom_targets;
|
||||
Atom atom_multiple;
|
||||
Atom atom_timestamp;
|
||||
Atom atom_version;
|
||||
Atom atom_atom_pair;
|
||||
Atom atom_net_desktop_names;
|
||||
Atom atom_net_wm_allowed_actions;
|
||||
Atom atom_net_wm_action_move;
|
||||
Atom atom_net_wm_action_resize;
|
||||
Atom atom_net_wm_action_fullscreen;
|
||||
Atom atom_net_wm_action_minimize;
|
||||
Atom atom_net_wm_action_shade;
|
||||
Atom atom_net_wm_action_stick;
|
||||
Atom atom_net_wm_action_maximize_horz;
|
||||
Atom atom_net_wm_action_maximize_vert;
|
||||
Atom atom_net_wm_action_change_desktop;
|
||||
Atom atom_net_wm_action_close;
|
||||
Atom atom_net_wm_state_above;
|
||||
Atom atom_net_wm_state_below;
|
||||
Atom atom_net_startup_id;
|
||||
Atom atom_metacity_toggle_verbose;
|
||||
Atom atom_metacity_update_counter;
|
||||
Atom atom_sync_counter;
|
||||
Atom atom_gnome_panel_action;
|
||||
Atom atom_gnome_panel_action_main_menu;
|
||||
Atom atom_gnome_panel_action_run_dialog;
|
||||
Atom atom_metacity_sentinel;
|
||||
Atom atom_net_wm_strut_partial;
|
||||
Atom atom_net_frame_extents;
|
||||
Atom atom_net_request_frame_extents;
|
||||
|
||||
/* This is the actual window from focus events,
|
||||
* not the one we last set
|
||||
*/
|
||||
MetaWindow *focus_window;
|
||||
|
||||
/* Previous focus window */
|
||||
MetaWindow *prev_focus_window;
|
||||
|
||||
GList *workspaces;
|
||||
/* window we are expecting a FocusIn event for
|
||||
*/
|
||||
MetaWindow *expected_focus_window;
|
||||
|
||||
guint static_gravity_works : 1;
|
||||
|
||||
/*< private-ish >*/
|
||||
guint error_trap_synced_at_last_pop : 1;
|
||||
MetaEventQueue *events;
|
||||
GSList *screens;
|
||||
GHashTable *window_ids;
|
||||
GSList *error_traps;
|
||||
int error_traps;
|
||||
int (* error_trap_handler) (Display *display,
|
||||
XErrorEvent *error);
|
||||
int server_grab_count;
|
||||
|
||||
/* This window holds the focus when we don't want to focus
|
||||
* any actual clients
|
||||
*/
|
||||
Window no_focus_window;
|
||||
|
||||
/* for double click */
|
||||
int double_click_time;
|
||||
Time last_button_time;
|
||||
Window last_button_xwindow;
|
||||
int last_button_num;
|
||||
guint is_double_click : 1;
|
||||
|
||||
/* serials of leave/unmap events that may
|
||||
* correspond to an enter event we should
|
||||
* ignore
|
||||
*/
|
||||
unsigned long ignored_serials[N_IGNORED_SERIALS];
|
||||
Window ungrab_should_not_cause_focus_window;
|
||||
|
||||
guint32 current_time;
|
||||
|
||||
/* Pings which we're waiting for a reply from */
|
||||
GSList *pending_pings;
|
||||
|
||||
/* Pending autoraise */
|
||||
guint autoraise_timeout_id;
|
||||
|
||||
/* Alt+click button grabs */
|
||||
unsigned int window_grab_modifiers;
|
||||
|
||||
/* current window operation */
|
||||
MetaGrabOp grab_op;
|
||||
MetaScreen *grab_screen;
|
||||
MetaWindow *grab_window;
|
||||
Window grab_xwindow;
|
||||
gulong grab_start_serial;
|
||||
int grab_button;
|
||||
int grab_root_x;
|
||||
int grab_root_y;
|
||||
int grab_anchor_root_x;
|
||||
int grab_anchor_root_y;
|
||||
MetaRectangle grab_anchor_window_pos;
|
||||
int grab_latest_motion_x;
|
||||
int grab_latest_motion_y;
|
||||
gulong grab_mask;
|
||||
guint grab_have_pointer : 1;
|
||||
guint grab_have_keyboard : 1;
|
||||
guint grab_wireframe_active : 1;
|
||||
guint grab_was_cancelled : 1;
|
||||
MetaRectangle grab_wireframe_rect;
|
||||
MetaRectangle grab_initial_window_pos;
|
||||
MetaResizePopup *grab_resize_popup;
|
||||
GTimeVal grab_last_moveresize_time;
|
||||
Time grab_motion_notify_time;
|
||||
|
||||
/* we use property updates as sentinels for certain window focus events
|
||||
* to avoid some race conditions on EnterNotify events
|
||||
*/
|
||||
int sentinel_counter;
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
int xkb_base_event_type;
|
||||
#endif
|
||||
#ifdef HAVE_XSYNC
|
||||
/* alarm monitoring client's _METACITY_UPDATE_COUNTER */
|
||||
XSyncAlarm grab_update_alarm;
|
||||
#endif
|
||||
|
||||
/* Keybindings stuff */
|
||||
MetaKeyBinding *screen_bindings;
|
||||
int n_screen_bindings;
|
||||
MetaKeyBinding *window_bindings;
|
||||
int n_window_bindings;
|
||||
unsigned int min_keycode;
|
||||
unsigned int max_keycode;
|
||||
KeySym *keymap;
|
||||
int keysyms_per_keycode;
|
||||
XModifierKeymap *modmap;
|
||||
unsigned int ignored_modifier_mask;
|
||||
unsigned int num_lock_mask;
|
||||
unsigned int scroll_lock_mask;
|
||||
unsigned int hyper_mask;
|
||||
unsigned int super_mask;
|
||||
unsigned int meta_mask;
|
||||
|
||||
/* Xinerama cache */
|
||||
unsigned int xinerama_cache_invalidated : 1;
|
||||
|
||||
/* Closing down the display */
|
||||
int closing;
|
||||
|
||||
/* Managed by group.c */
|
||||
GHashTable *groups_by_leader;
|
||||
|
||||
/* currently-active window menu if any */
|
||||
MetaWindowMenu *window_menu;
|
||||
MetaWindow *window_with_menu;
|
||||
|
||||
/* Managed by window-props.c */
|
||||
MetaWindowPropHooks *prop_hooks;
|
||||
|
||||
/* Managed by group-props.c */
|
||||
MetaGroupPropHooks *group_prop_hooks;
|
||||
|
||||
/* Managed by compositor.c */
|
||||
MetaCompositor *compositor;
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
SnDisplay *sn_display;
|
||||
#endif
|
||||
#ifdef HAVE_XSYNC
|
||||
int xsync_event_base;
|
||||
int xsync_error_base;
|
||||
#define META_DISPLAY_HAS_XSYNC(display) ((display)->xsync_event_base != 0)
|
||||
#else
|
||||
#define META_DISPLAY_HAS_XSYNC(display) FALSE
|
||||
#endif
|
||||
#ifdef HAVE_SHAPE
|
||||
int shape_event_base;
|
||||
int shape_error_base;
|
||||
#define META_DISPLAY_HAS_SHAPE(display) ((display)->shape_event_base != 0)
|
||||
#else
|
||||
#define META_DISPLAY_HAS_SHAPE(display) FALSE
|
||||
#endif
|
||||
};
|
||||
|
||||
gboolean meta_display_open (const char *name);
|
||||
@@ -138,10 +326,18 @@ MetaScreen* meta_display_screen_for_root (MetaDisplay *display,
|
||||
Window xroot);
|
||||
MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display,
|
||||
Screen *screen);
|
||||
MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display,
|
||||
Window xindow);
|
||||
void meta_display_grab (MetaDisplay *display);
|
||||
void meta_display_ungrab (MetaDisplay *display);
|
||||
gboolean meta_display_is_double_click (MetaDisplay *display);
|
||||
|
||||
void meta_display_unmanage_screen (MetaDisplay *display,
|
||||
MetaScreen *screen);
|
||||
|
||||
void meta_display_unmanage_windows_for_screen (MetaDisplay *display,
|
||||
MetaScreen *screen);
|
||||
|
||||
/* A given MetaWindow may have various X windows that "belong"
|
||||
* to it, such as the frame window.
|
||||
*/
|
||||
@@ -158,19 +354,22 @@ GSList* meta_display_list_windows (MetaDisplay *display);
|
||||
MetaDisplay* meta_display_for_x_display (Display *xdisplay);
|
||||
GSList* meta_displays_list (void);
|
||||
|
||||
MetaWorkspace* meta_display_get_workspace_by_index (MetaDisplay *display,
|
||||
int index);
|
||||
MetaWorkspace* meta_display_get_workspace_by_screen_index (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
int index);
|
||||
|
||||
Cursor meta_display_create_x_cursor (MetaDisplay *display,
|
||||
MetaCursor cursor);
|
||||
|
||||
void meta_display_set_grab_op_cursor (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaGrabOp op,
|
||||
gboolean change_pointer,
|
||||
Window grab_xwindow,
|
||||
Time timestamp);
|
||||
|
||||
gboolean meta_display_begin_grab_op (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
MetaGrabOp op,
|
||||
gboolean pointer_already_grabbed,
|
||||
int event_serial,
|
||||
int button,
|
||||
gulong modmask,
|
||||
Time timestamp,
|
||||
@@ -184,5 +383,76 @@ void meta_display_grab_window_buttons (MetaDisplay *display,
|
||||
void meta_display_ungrab_window_buttons (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
|
||||
void meta_display_grab_focus_window_button (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
void meta_display_ungrab_focus_window_button (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
|
||||
/* make a request to ensure the event serial has changed */
|
||||
void meta_display_increment_event_serial (MetaDisplay *display);
|
||||
|
||||
void meta_display_update_active_window_hint (MetaDisplay *display);
|
||||
|
||||
guint32 meta_display_get_current_time (MetaDisplay *display);
|
||||
|
||||
/* utility goo */
|
||||
const char* meta_event_mode_to_string (int m);
|
||||
const char* meta_event_detail_to_string (int d);
|
||||
|
||||
void meta_display_queue_retheme_all_windows (MetaDisplay *display);
|
||||
void meta_display_retheme_all (void);
|
||||
|
||||
void meta_display_ping_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
Time timestamp,
|
||||
MetaWindowPingFunc ping_reply_func,
|
||||
MetaWindowPingFunc ping_timeout_func,
|
||||
void *user_data);
|
||||
gboolean meta_display_window_has_pending_pings (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_TAB_LIST_NORMAL,
|
||||
META_TAB_LIST_DOCKS
|
||||
|
||||
|
||||
} MetaTabList;
|
||||
|
||||
GList* meta_display_get_tab_list (MetaDisplay *display,
|
||||
MetaTabList type,
|
||||
MetaScreen *screen,
|
||||
MetaWorkspace *workspace);
|
||||
|
||||
MetaWindow* meta_display_get_tab_next (MetaDisplay *display,
|
||||
MetaTabList type,
|
||||
MetaScreen *screen,
|
||||
MetaWorkspace *workspace,
|
||||
MetaWindow *window,
|
||||
gboolean backward);
|
||||
|
||||
MetaWindow* meta_display_get_tab_current (MetaDisplay *display,
|
||||
MetaTabList type,
|
||||
MetaScreen *screen,
|
||||
MetaWorkspace *workspace);
|
||||
|
||||
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
|
||||
|
||||
gboolean meta_grab_op_is_moving (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_resizing (MetaGrabOp op);
|
||||
|
||||
gboolean meta_rectangle_intersect (MetaRectangle *src1,
|
||||
MetaRectangle *src2,
|
||||
MetaRectangle *dest);
|
||||
gboolean meta_rectangle_equal (const MetaRectangle *src1,
|
||||
const MetaRectangle *src2);
|
||||
|
||||
void meta_display_devirtualize_modifiers (MetaDisplay *display,
|
||||
MetaVirtualModifier modifiers,
|
||||
unsigned int *mask);
|
||||
|
||||
void meta_display_increment_focus_sentinel (MetaDisplay *display);
|
||||
void meta_display_decrement_focus_sentinel (MetaDisplay *display);
|
||||
gboolean meta_display_focus_sentinel_clear (MetaDisplay *display);
|
||||
|
||||
#endif
|
||||
|
218
src/draw-workspace.c
Normal file
218
src/draw-workspace.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/* Draw a workspace */
|
||||
|
||||
/* This file should not be modified to depend on other files in
|
||||
* libwnck or metacity, since it's used in both of them
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "draw-workspace.h"
|
||||
|
||||
|
||||
static void
|
||||
get_window_rect (const WnckWindowDisplayInfo *win,
|
||||
int screen_width,
|
||||
int screen_height,
|
||||
const GdkRectangle *workspace_rect,
|
||||
GdkRectangle *rect)
|
||||
{
|
||||
double width_ratio, height_ratio;
|
||||
int x, y, width, height;
|
||||
|
||||
width_ratio = (double) workspace_rect->width / (double) screen_width;
|
||||
height_ratio = (double) workspace_rect->height / (double) screen_height;
|
||||
|
||||
x = win->x;
|
||||
y = win->y;
|
||||
width = win->width;
|
||||
height = win->height;
|
||||
|
||||
x *= width_ratio;
|
||||
y *= height_ratio;
|
||||
width *= width_ratio;
|
||||
height *= height_ratio;
|
||||
|
||||
x += workspace_rect->x;
|
||||
y += workspace_rect->y;
|
||||
|
||||
if (width < 3)
|
||||
width = 3;
|
||||
if (height < 3)
|
||||
height = 3;
|
||||
|
||||
rect->x = x;
|
||||
rect->y = y;
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_window (GtkWidget *widget,
|
||||
GdkDrawable *drawable,
|
||||
const WnckWindowDisplayInfo *win,
|
||||
const GdkRectangle *winrect)
|
||||
{
|
||||
GdkPixbuf *icon;
|
||||
int icon_x, icon_y, icon_w, icon_h;
|
||||
|
||||
gdk_draw_rectangle (drawable,
|
||||
win->is_active ?
|
||||
widget->style->bg_gc[GTK_STATE_SELECTED] :
|
||||
widget->style->bg_gc[GTK_STATE_NORMAL],
|
||||
TRUE,
|
||||
winrect->x + 1, winrect->y + 1,
|
||||
winrect->width - 2, winrect->height - 2);
|
||||
|
||||
icon = win->icon;
|
||||
|
||||
icon_w = icon_h = 0;
|
||||
|
||||
if (icon)
|
||||
{
|
||||
icon_w = gdk_pixbuf_get_width (icon);
|
||||
icon_h = gdk_pixbuf_get_height (icon);
|
||||
|
||||
/* If the icon is too big, fall back to mini icon.
|
||||
* We don't arbitrarily scale the icon, because it's
|
||||
* just too slow on my Athlon 850.
|
||||
*/
|
||||
if (icon_w > (winrect->width - 2) ||
|
||||
icon_h > (winrect->height - 2))
|
||||
{
|
||||
icon = win->mini_icon;
|
||||
if (icon)
|
||||
{
|
||||
icon_w = gdk_pixbuf_get_width (icon);
|
||||
icon_h = gdk_pixbuf_get_height (icon);
|
||||
|
||||
/* Give up. */
|
||||
if (icon_w > (winrect->width - 2) ||
|
||||
icon_h > (winrect->height - 2))
|
||||
icon = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (icon)
|
||||
{
|
||||
icon_x = winrect->x + (winrect->width - icon_w) / 2;
|
||||
icon_y = winrect->y + (winrect->height - icon_h) / 2;
|
||||
|
||||
{
|
||||
/* render_to_drawable should take a clip rect to save
|
||||
* us this mess...
|
||||
*/
|
||||
GdkRectangle pixbuf_rect;
|
||||
GdkRectangle draw_rect;
|
||||
|
||||
pixbuf_rect.x = icon_x;
|
||||
pixbuf_rect.y = icon_y;
|
||||
pixbuf_rect.width = icon_w;
|
||||
pixbuf_rect.height = icon_h;
|
||||
|
||||
if (gdk_rectangle_intersect ((GdkRectangle *)winrect, &pixbuf_rect,
|
||||
&draw_rect))
|
||||
{
|
||||
gdk_pixbuf_render_to_drawable_alpha (icon,
|
||||
drawable,
|
||||
draw_rect.x - pixbuf_rect.x,
|
||||
draw_rect.y - pixbuf_rect.y,
|
||||
draw_rect.x, draw_rect.y,
|
||||
draw_rect.width,
|
||||
draw_rect.height,
|
||||
GDK_PIXBUF_ALPHA_FULL,
|
||||
128,
|
||||
GDK_RGB_DITHER_NORMAL,
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rectangle (drawable,
|
||||
win->is_active ?
|
||||
widget->style->fg_gc[GTK_STATE_SELECTED] :
|
||||
widget->style->fg_gc[GTK_STATE_NORMAL],
|
||||
FALSE,
|
||||
winrect->x, winrect->y,
|
||||
winrect->width - 1, winrect->height - 1);
|
||||
}
|
||||
|
||||
void
|
||||
wnck_draw_workspace (GtkWidget *widget,
|
||||
GdkDrawable *drawable,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
int screen_width,
|
||||
int screen_height,
|
||||
GdkPixbuf *workspace_background,
|
||||
gboolean is_active,
|
||||
const WnckWindowDisplayInfo *windows,
|
||||
int n_windows)
|
||||
{
|
||||
int i;
|
||||
GdkRectangle workspace_rect;
|
||||
|
||||
workspace_rect.x = x;
|
||||
workspace_rect.y = y;
|
||||
workspace_rect.width = width;
|
||||
workspace_rect.height = height;
|
||||
|
||||
|
||||
if (is_active)
|
||||
gdk_draw_rectangle (drawable,
|
||||
GTK_WIDGET (widget)->style->dark_gc[GTK_STATE_SELECTED],
|
||||
TRUE,
|
||||
x, y, width, height);
|
||||
else if (workspace_background)
|
||||
{
|
||||
gdk_pixbuf_render_to_drawable (workspace_background,
|
||||
drawable,
|
||||
GTK_WIDGET (widget)->style->dark_gc[GTK_STATE_SELECTED],
|
||||
0, 0,
|
||||
x, y,
|
||||
-1, -1,
|
||||
GDK_RGB_DITHER_MAX,
|
||||
0, 0);
|
||||
}
|
||||
else
|
||||
gdk_draw_rectangle (drawable,
|
||||
GTK_WIDGET (widget)->style->dark_gc[GTK_STATE_NORMAL],
|
||||
TRUE,
|
||||
x, y, width, height);
|
||||
|
||||
|
||||
i = 0;
|
||||
while (i < n_windows)
|
||||
{
|
||||
const WnckWindowDisplayInfo *win = &windows[i];
|
||||
GdkRectangle winrect;
|
||||
|
||||
get_window_rect (win, screen_width, screen_height, &workspace_rect, &winrect);
|
||||
|
||||
draw_window (widget,
|
||||
drawable,
|
||||
win,
|
||||
&winrect);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
59
src/draw-workspace.h
Normal file
59
src/draw-workspace.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Draw a workspace */
|
||||
|
||||
/* This file should not be modified to depend on other files in
|
||||
* libwnck or metacity, since it's used in both of them
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef WNCK_DRAW_WORKSPACE_H
|
||||
#define WNCK_DRAW_WORKSPACE_H
|
||||
|
||||
#include <gdk/gdkdrawable.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdkPixbuf *icon;
|
||||
GdkPixbuf *mini_icon;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
guint is_active : 1;
|
||||
|
||||
} WnckWindowDisplayInfo;
|
||||
|
||||
void wnck_draw_workspace (GtkWidget *widget,
|
||||
GdkDrawable *drawable,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
int screen_width,
|
||||
int screen_height,
|
||||
GdkPixbuf *workspace_background,
|
||||
gboolean is_active,
|
||||
const WnckWindowDisplayInfo *windows,
|
||||
int n_windows);
|
||||
|
||||
#endif
|
516
src/effects.c
Normal file
516
src/effects.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/* Metacity animation effects */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Anders Carlsson, Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "effects.h"
|
||||
#include "display.h"
|
||||
#include "ui.h"
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_ANIMATION_DRAW_ROOT,
|
||||
META_ANIMATION_WINDOW_WIREFRAME,
|
||||
META_ANIMATION_WINDOW_OPAQUE
|
||||
|
||||
} MetaAnimationStyle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
double millisecs_duration;
|
||||
GTimeVal start_time;
|
||||
|
||||
gboolean first_time;
|
||||
|
||||
MetaRectangle start_rect;
|
||||
MetaRectangle end_rect;
|
||||
|
||||
/* rect to erase */
|
||||
MetaRectangle last_rect;
|
||||
|
||||
/* used instead of the global flag, since
|
||||
* we don't want to change midstream.
|
||||
*/
|
||||
MetaAnimationStyle style;
|
||||
|
||||
/* For wireframe drawn on root window */
|
||||
GC gc;
|
||||
|
||||
/* For wireframe window */
|
||||
Window wireframe_xwindow;
|
||||
|
||||
/* For opaque */
|
||||
MetaImageWindow *image_window;
|
||||
GdkPixbuf *orig_pixbuf;
|
||||
|
||||
MetaBoxAnimType anim_type;
|
||||
|
||||
} BoxAnimationContext;
|
||||
|
||||
static void
|
||||
update_wireframe_window (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
const MetaRectangle *rect)
|
||||
{
|
||||
XMoveResizeWindow (display->xdisplay,
|
||||
xwindow,
|
||||
rect->x, rect->y,
|
||||
rect->width, rect->height);
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
|
||||
#define OUTLINE_WIDTH 3
|
||||
|
||||
if (rect->width > OUTLINE_WIDTH * 2 &&
|
||||
rect->height > OUTLINE_WIDTH * 2)
|
||||
{
|
||||
XRectangle xrect;
|
||||
Region inner_xregion;
|
||||
Region outer_xregion;
|
||||
|
||||
inner_xregion = XCreateRegion ();
|
||||
outer_xregion = XCreateRegion ();
|
||||
|
||||
xrect.x = 0;
|
||||
xrect.y = 0;
|
||||
xrect.width = rect->width;
|
||||
xrect.height = rect->height;
|
||||
|
||||
XUnionRectWithRegion (&xrect, outer_xregion, outer_xregion);
|
||||
|
||||
xrect.x += OUTLINE_WIDTH;
|
||||
xrect.y += OUTLINE_WIDTH;
|
||||
xrect.width -= OUTLINE_WIDTH * 2;
|
||||
xrect.height -= OUTLINE_WIDTH * 2;
|
||||
|
||||
XUnionRectWithRegion (&xrect, inner_xregion, inner_xregion);
|
||||
|
||||
XSubtractRegion (outer_xregion, inner_xregion, outer_xregion);
|
||||
|
||||
XShapeCombineRegion (display->xdisplay, xwindow,
|
||||
ShapeBounding, 0, 0, outer_xregion, ShapeSet);
|
||||
|
||||
XDestroyRegion (outer_xregion);
|
||||
XDestroyRegion (inner_xregion);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unset the shape */
|
||||
XShapeCombineMask (display->xdisplay, xwindow,
|
||||
ShapeBounding, 0, 0, None, ShapeSet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
effects_draw_box_animation_timeout (BoxAnimationContext *context)
|
||||
{
|
||||
double elapsed;
|
||||
GTimeVal current_time;
|
||||
MetaRectangle draw_rect;
|
||||
double fraction;
|
||||
|
||||
if (!context->first_time)
|
||||
{
|
||||
if (context->style == META_ANIMATION_DRAW_ROOT)
|
||||
{
|
||||
/* Restore the previously drawn background */
|
||||
XDrawRectangle (context->screen->display->xdisplay,
|
||||
context->screen->xroot,
|
||||
context->gc,
|
||||
context->last_rect.x, context->last_rect.y,
|
||||
context->last_rect.width, context->last_rect.height);
|
||||
}
|
||||
}
|
||||
|
||||
context->first_time = FALSE;
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
|
||||
/* We use milliseconds for all times */
|
||||
elapsed =
|
||||
((((double)current_time.tv_sec - context->start_time.tv_sec) * G_USEC_PER_SEC +
|
||||
(current_time.tv_usec - context->start_time.tv_usec))) / 1000.0;
|
||||
|
||||
if (elapsed < 0)
|
||||
{
|
||||
/* Probably the system clock was set backwards? */
|
||||
meta_warning ("System clock seemed to go backwards?\n");
|
||||
elapsed = G_MAXDOUBLE; /* definitely done. */
|
||||
}
|
||||
|
||||
if (elapsed > context->millisecs_duration)
|
||||
{
|
||||
/* All done */
|
||||
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
||||
{
|
||||
g_object_unref (G_OBJECT (context->orig_pixbuf));
|
||||
meta_image_window_free (context->image_window);
|
||||
}
|
||||
else if (context->style == META_ANIMATION_DRAW_ROOT)
|
||||
{
|
||||
meta_display_ungrab (context->screen->display);
|
||||
meta_ui_pop_delay_exposes (context->screen->ui);
|
||||
XFreeGC (context->screen->display->xdisplay,
|
||||
context->gc);
|
||||
}
|
||||
else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
||||
{
|
||||
XDestroyWindow (context->screen->display->xdisplay,
|
||||
context->wireframe_xwindow);
|
||||
}
|
||||
|
||||
g_free (context);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert (context->millisecs_duration > 0.0);
|
||||
fraction = elapsed / context->millisecs_duration;
|
||||
|
||||
draw_rect = context->start_rect;
|
||||
|
||||
/* Now add a delta proportional to elapsed time. */
|
||||
draw_rect.x += (context->end_rect.x - context->start_rect.x) * fraction;
|
||||
draw_rect.y += (context->end_rect.y - context->start_rect.y) * fraction;
|
||||
draw_rect.width += (context->end_rect.width - context->start_rect.width) * fraction;
|
||||
draw_rect.height += (context->end_rect.height - context->start_rect.height) * fraction;
|
||||
|
||||
/* don't confuse X or gdk-pixbuf with bogus rectangles */
|
||||
if (draw_rect.width < 1)
|
||||
draw_rect.width = 1;
|
||||
if (draw_rect.height < 1)
|
||||
draw_rect.height = 1;
|
||||
|
||||
context->last_rect = draw_rect;
|
||||
|
||||
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
||||
{
|
||||
GdkPixbuf *scaled;
|
||||
|
||||
scaled = NULL;
|
||||
switch (context->anim_type)
|
||||
{
|
||||
case META_BOX_ANIM_SCALE:
|
||||
scaled = gdk_pixbuf_scale_simple (context->orig_pixbuf,
|
||||
draw_rect.width,
|
||||
draw_rect.height,
|
||||
GDK_INTERP_BILINEAR);
|
||||
break;
|
||||
case META_BOX_ANIM_SLIDE_UP:
|
||||
{
|
||||
int x, y;
|
||||
|
||||
x = context->start_rect.width - draw_rect.width;
|
||||
y = context->start_rect.height - draw_rect.height;
|
||||
|
||||
/* paranoia */
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
|
||||
scaled = gdk_pixbuf_new_subpixbuf (context->orig_pixbuf,
|
||||
x, y,
|
||||
draw_rect.width,
|
||||
draw_rect.height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle out-of-memory */
|
||||
if (scaled != NULL)
|
||||
{
|
||||
meta_image_window_set (context->image_window,
|
||||
scaled,
|
||||
draw_rect.x, draw_rect.y);
|
||||
|
||||
g_object_unref (G_OBJECT (scaled));
|
||||
}
|
||||
}
|
||||
else if (context->style == META_ANIMATION_DRAW_ROOT)
|
||||
{
|
||||
/* Draw the rectangle */
|
||||
XDrawRectangle (context->screen->display->xdisplay,
|
||||
context->screen->xroot,
|
||||
context->gc,
|
||||
draw_rect.x, draw_rect.y,
|
||||
draw_rect.width, draw_rect.height);
|
||||
}
|
||||
else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
||||
{
|
||||
update_wireframe_window (context->screen->display,
|
||||
context->wireframe_xwindow,
|
||||
&draw_rect);
|
||||
}
|
||||
|
||||
/* kick changes onto the server */
|
||||
XFlush (context->screen->display->xdisplay);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* I really don't want this to be a configuration option, but I think
|
||||
* the wireframe is sucky from a UI standpoint (more confusing than
|
||||
* opaque), but the opaque is definitely still too slow on some
|
||||
* systems, and also doesn't look quite right due to the mapping
|
||||
* and unmapping of windows that's going on.
|
||||
*/
|
||||
|
||||
static MetaAnimationStyle animation_style = META_ANIMATION_WINDOW_WIREFRAME;
|
||||
|
||||
void
|
||||
meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
MetaRectangle *initial_rect,
|
||||
MetaRectangle *destination_rect,
|
||||
double seconds_duration,
|
||||
MetaBoxAnimType anim_type)
|
||||
{
|
||||
BoxAnimationContext *context;
|
||||
|
||||
g_return_if_fail (seconds_duration > 0.0);
|
||||
|
||||
if (g_getenv ("METACITY_DEBUG_EFFECTS"))
|
||||
seconds_duration *= 10; /* slow things down */
|
||||
|
||||
/* Create the animation context */
|
||||
context = g_new0 (BoxAnimationContext, 1);
|
||||
|
||||
context->screen = screen;
|
||||
|
||||
context->millisecs_duration = seconds_duration * 1000.0;
|
||||
context->first_time = TRUE;
|
||||
context->start_rect = *initial_rect;
|
||||
context->end_rect = *destination_rect;
|
||||
context->anim_type = anim_type;
|
||||
|
||||
context->style = animation_style;
|
||||
|
||||
#ifndef HAVE_SHAPE
|
||||
if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
||||
context->style = META_ANIMATION_DRAW_ROOT;
|
||||
#endif
|
||||
|
||||
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
||||
{
|
||||
GdkPixbuf *pix;
|
||||
|
||||
pix = meta_gdk_pixbuf_get_from_window (NULL,
|
||||
screen->xroot,
|
||||
initial_rect->x,
|
||||
initial_rect->y,
|
||||
0, 0,
|
||||
initial_rect->width,
|
||||
initial_rect->height);
|
||||
|
||||
if (pix == NULL)
|
||||
{
|
||||
/* Fall back to wireframe */
|
||||
context->style = META_ANIMATION_WINDOW_WIREFRAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->image_window = meta_image_window_new (screen->display->xdisplay,
|
||||
screen->number,
|
||||
initial_rect->width,
|
||||
initial_rect->height);
|
||||
context->orig_pixbuf = pix;
|
||||
meta_image_window_set (context->image_window,
|
||||
context->orig_pixbuf,
|
||||
initial_rect->x,
|
||||
initial_rect->y);
|
||||
meta_image_window_set_showing (context->image_window, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not an else, so that fallback works */
|
||||
if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
||||
{
|
||||
XSetWindowAttributes attrs;
|
||||
|
||||
attrs.override_redirect = True;
|
||||
attrs.background_pixel = BlackPixel (screen->display->xdisplay,
|
||||
screen->number);
|
||||
|
||||
context->wireframe_xwindow = XCreateWindow (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
initial_rect->x,
|
||||
initial_rect->y,
|
||||
initial_rect->width,
|
||||
initial_rect->height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
CopyFromParent,
|
||||
CopyFromParent,
|
||||
CWOverrideRedirect | CWBackPixel,
|
||||
&attrs);
|
||||
|
||||
update_wireframe_window (screen->display,
|
||||
context->wireframe_xwindow,
|
||||
initial_rect);
|
||||
|
||||
XMapWindow (screen->display->xdisplay,
|
||||
context->wireframe_xwindow);
|
||||
}
|
||||
|
||||
if (context->style == META_ANIMATION_DRAW_ROOT)
|
||||
{
|
||||
XGCValues gc_values;
|
||||
|
||||
gc_values.subwindow_mode = IncludeInferiors;
|
||||
gc_values.function = GXinvert;
|
||||
|
||||
context->gc = XCreateGC (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
GCSubwindowMode | GCFunction,
|
||||
&gc_values);
|
||||
|
||||
/* Grab the X server to avoid screen dirt */
|
||||
meta_display_grab (context->screen->display);
|
||||
meta_ui_push_delay_exposes (context->screen->ui);
|
||||
}
|
||||
|
||||
/* Do this only after we get the pixbuf from the server,
|
||||
* so that the animation doesn't get truncated.
|
||||
*/
|
||||
g_get_current_time (&context->start_time);
|
||||
|
||||
/* Add the timeout - a short one, could even use an idle,
|
||||
* but this is maybe more CPU-friendly.
|
||||
*/
|
||||
g_timeout_add (15,
|
||||
(GSourceFunc)effects_draw_box_animation_timeout,
|
||||
context);
|
||||
|
||||
/* kick changes onto the server */
|
||||
XFlush (context->screen->display->xdisplay);
|
||||
}
|
||||
|
||||
void
|
||||
meta_effects_begin_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *rect)
|
||||
{
|
||||
/* Grab the X server to avoid screen dirt */
|
||||
meta_display_grab (screen->display);
|
||||
meta_ui_push_delay_exposes (screen->ui);
|
||||
|
||||
meta_effects_update_wireframe (screen, NULL, rect);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_xor_rect (MetaScreen *screen,
|
||||
const MetaRectangle *rect)
|
||||
{
|
||||
/* The lines in the center can't overlap the rectangle or each
|
||||
* other, or the XOR gets reversed. So we have to draw things
|
||||
* a bit oddly.
|
||||
*/
|
||||
XSegment segments[8];
|
||||
int i;
|
||||
|
||||
#define LINE_WIDTH META_WIREFRAME_XOR_LINE_WIDTH
|
||||
|
||||
XDrawRectangle (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
screen->root_xor_gc,
|
||||
rect->x, rect->y,
|
||||
rect->width, rect->height);
|
||||
|
||||
/* Don't put lines inside small rectangles where they won't fit */
|
||||
if (rect->width < (LINE_WIDTH * 4) ||
|
||||
rect->height < (LINE_WIDTH * 4))
|
||||
return;
|
||||
|
||||
/* Two vertical lines at 1/3 and 2/3 */
|
||||
segments[0].x1 = rect->x + rect->width / 3;
|
||||
segments[0].y1 = rect->y + LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
||||
segments[0].x2 = segments[0].x1;
|
||||
segments[0].y2 = rect->y + rect->height - LINE_WIDTH / 2;
|
||||
|
||||
segments[1] = segments[0];
|
||||
segments[1].x1 = rect->x + (rect->width / 3) * 2;
|
||||
segments[1].x2 = segments[1].x1;
|
||||
|
||||
/* Now make two horizontal lines at 1/3 and 2/3, but not
|
||||
* overlapping the verticals
|
||||
*/
|
||||
|
||||
segments[2].x1 = rect->x + LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
||||
segments[2].x2 = segments[0].x1 - LINE_WIDTH / 2;
|
||||
segments[2].y1 = rect->y + rect->height / 3;
|
||||
segments[2].y2 = segments[2].y1;
|
||||
|
||||
segments[3] = segments[2];
|
||||
segments[3].x1 = segments[2].x2 + LINE_WIDTH;
|
||||
segments[3].x2 = segments[1].x1 - LINE_WIDTH / 2;
|
||||
|
||||
segments[4] = segments[3];
|
||||
segments[4].x1 = segments[3].x2 + LINE_WIDTH;
|
||||
segments[4].x2 = rect->x + rect->width - LINE_WIDTH / 2;
|
||||
|
||||
/* Second horizontal line is just like the first, but
|
||||
* shifted down
|
||||
*/
|
||||
i = 5;
|
||||
while (i < 8)
|
||||
{
|
||||
segments[i] = segments[i - 3];
|
||||
segments[i].y1 = rect->y + (rect->height / 3) * 2;
|
||||
segments[i].y2 = segments[i].y1;
|
||||
++i;
|
||||
}
|
||||
|
||||
XDrawSegments (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
screen->root_xor_gc,
|
||||
segments,
|
||||
G_N_ELEMENTS (segments));
|
||||
}
|
||||
|
||||
void
|
||||
meta_effects_update_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *old_rect,
|
||||
const MetaRectangle *new_rect)
|
||||
{
|
||||
if (old_rect)
|
||||
draw_xor_rect (screen, old_rect);
|
||||
|
||||
if (new_rect)
|
||||
draw_xor_rect (screen, new_rect);
|
||||
|
||||
XFlush (screen->display->xdisplay);
|
||||
}
|
||||
|
||||
void
|
||||
meta_effects_end_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *old_rect)
|
||||
{
|
||||
meta_effects_update_wireframe (screen, old_rect, NULL);
|
||||
|
||||
meta_display_ungrab (screen->display);
|
||||
meta_ui_pop_delay_exposes (screen->ui);
|
||||
}
|
||||
|
52
src/effects.h
Normal file
52
src/effects.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Metacity animation effects */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Anders Carlsson, Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_EFFECTS_H
|
||||
#define META_EFFECTS_H
|
||||
|
||||
#include "util.h"
|
||||
#include "screen.h"
|
||||
|
||||
#define META_MINIMIZE_ANIMATION_LENGTH 0.35
|
||||
#define META_SHADE_ANIMATION_LENGTH 0.2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_BOX_ANIM_SCALE,
|
||||
META_BOX_ANIM_SLIDE_UP
|
||||
|
||||
} MetaBoxAnimType;
|
||||
|
||||
void meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
MetaRectangle *initial_rect,
|
||||
MetaRectangle *destination_rect,
|
||||
double seconds_duration,
|
||||
MetaBoxAnimType anim_type);
|
||||
|
||||
void meta_effects_begin_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *rect);
|
||||
void meta_effects_update_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *old_rect,
|
||||
const MetaRectangle *new_rect);
|
||||
void meta_effects_end_wireframe (MetaScreen *screen,
|
||||
const MetaRectangle *old_rect);
|
||||
|
||||
#endif /* META_EFFECTS_H */
|
657
src/eggaccelerators.c
Normal file
657
src/eggaccelerators.c
Normal file
@@ -0,0 +1,657 @@
|
||||
/* eggaccelerators.c
|
||||
* Copyright (C) 2002 Red Hat, Inc.; Copyright 1998, 2001 Tim Janik
|
||||
* Developed by Havoc Pennington, Tim Janik
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "eggaccelerators.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
enum
|
||||
{
|
||||
EGG_MODMAP_ENTRY_SHIFT = 0,
|
||||
EGG_MODMAP_ENTRY_LOCK = 1,
|
||||
EGG_MODMAP_ENTRY_CONTROL = 2,
|
||||
EGG_MODMAP_ENTRY_MOD1 = 3,
|
||||
EGG_MODMAP_ENTRY_MOD2 = 4,
|
||||
EGG_MODMAP_ENTRY_MOD3 = 5,
|
||||
EGG_MODMAP_ENTRY_MOD4 = 6,
|
||||
EGG_MODMAP_ENTRY_MOD5 = 7,
|
||||
EGG_MODMAP_ENTRY_LAST = 8
|
||||
};
|
||||
|
||||
#define MODMAP_ENTRY_TO_MODIFIER(x) (1 << (x))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EggVirtualModifierType mapping[EGG_MODMAP_ENTRY_LAST];
|
||||
|
||||
} EggModmap;
|
||||
|
||||
const EggModmap* egg_keymap_get_modmap (GdkKeymap *keymap);
|
||||
|
||||
static inline gboolean
|
||||
is_alt (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'a' || string[1] == 'A') &&
|
||||
(string[2] == 'l' || string[2] == 'L') &&
|
||||
(string[3] == 't' || string[3] == 'T') &&
|
||||
(string[4] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_ctl (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 't' || string[2] == 'T') &&
|
||||
(string[3] == 'l' || string[3] == 'L') &&
|
||||
(string[4] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_modx (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'm' || string[1] == 'M') &&
|
||||
(string[2] == 'o' || string[2] == 'O') &&
|
||||
(string[3] == 'd' || string[3] == 'D') &&
|
||||
(string[4] >= '1' && string[4] <= '5') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_ctrl (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 't' || string[2] == 'T') &&
|
||||
(string[3] == 'r' || string[3] == 'R') &&
|
||||
(string[4] == 'l' || string[4] == 'L') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_shft (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'h' || string[2] == 'H') &&
|
||||
(string[3] == 'f' || string[3] == 'F') &&
|
||||
(string[4] == 't' || string[4] == 'T') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_shift (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'h' || string[2] == 'H') &&
|
||||
(string[3] == 'i' || string[3] == 'I') &&
|
||||
(string[4] == 'f' || string[4] == 'F') &&
|
||||
(string[5] == 't' || string[5] == 'T') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_control (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 'o' || string[2] == 'O') &&
|
||||
(string[3] == 'n' || string[3] == 'N') &&
|
||||
(string[4] == 't' || string[4] == 'T') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == 'o' || string[6] == 'O') &&
|
||||
(string[7] == 'l' || string[7] == 'L') &&
|
||||
(string[8] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_release (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'r' || string[1] == 'R') &&
|
||||
(string[2] == 'e' || string[2] == 'E') &&
|
||||
(string[3] == 'l' || string[3] == 'L') &&
|
||||
(string[4] == 'e' || string[4] == 'E') &&
|
||||
(string[5] == 'a' || string[5] == 'A') &&
|
||||
(string[6] == 's' || string[6] == 'S') &&
|
||||
(string[7] == 'e' || string[7] == 'E') &&
|
||||
(string[8] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_meta (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'm' || string[1] == 'M') &&
|
||||
(string[2] == 'e' || string[2] == 'E') &&
|
||||
(string[3] == 't' || string[3] == 'T') &&
|
||||
(string[4] == 'a' || string[4] == 'A') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_super (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'u' || string[2] == 'U') &&
|
||||
(string[3] == 'p' || string[3] == 'P') &&
|
||||
(string[4] == 'e' || string[4] == 'E') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_hyper (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'h' || string[1] == 'H') &&
|
||||
(string[2] == 'y' || string[2] == 'Y') &&
|
||||
(string[3] == 'p' || string[3] == 'P') &&
|
||||
(string[4] == 'e' || string[4] == 'E') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_accelerator_parse_virtual:
|
||||
* @accelerator: string representing an accelerator
|
||||
* @accelerator_key: return location for accelerator keyval
|
||||
* @accelerator_mods: return location for accelerator modifier mask
|
||||
*
|
||||
* Parses a string representing a virtual accelerator. The format
|
||||
* looks like "<Control>a" or "<Shift><Alt>F1" or
|
||||
* "<Release>z" (the last one is for key release). The parser
|
||||
* is fairly liberal and allows lower or upper case, and also
|
||||
* abbreviations such as "<Ctl>" and "<Ctrl>".
|
||||
*
|
||||
* If the parse fails, @accelerator_key and @accelerator_mods will
|
||||
* be set to 0 (zero) and %FALSE will be returned. If the string contains
|
||||
* only modifiers, @accelerator_key will be set to 0 but %TRUE will be
|
||||
* returned.
|
||||
*
|
||||
* The virtual vs. concrete accelerator distinction is a relic of
|
||||
* how the X Window System works; there are modifiers Mod2-Mod5 that
|
||||
* can represent various keyboard keys (numlock, meta, hyper, etc.),
|
||||
* the virtual modifier represents the keyboard key, the concrete
|
||||
* modifier the actual Mod2-Mod5 bits in the key press event.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
egg_accelerator_parse_virtual (const gchar *accelerator,
|
||||
guint *accelerator_key,
|
||||
EggVirtualModifierType *accelerator_mods)
|
||||
{
|
||||
guint keyval;
|
||||
GdkModifierType mods;
|
||||
gint len;
|
||||
gboolean bad_keyval;
|
||||
|
||||
if (accelerator_key)
|
||||
*accelerator_key = 0;
|
||||
if (accelerator_mods)
|
||||
*accelerator_mods = 0;
|
||||
|
||||
g_return_val_if_fail (accelerator != NULL, FALSE);
|
||||
|
||||
bad_keyval = FALSE;
|
||||
|
||||
keyval = 0;
|
||||
mods = 0;
|
||||
len = strlen (accelerator);
|
||||
while (len)
|
||||
{
|
||||
if (*accelerator == '<')
|
||||
{
|
||||
if (len >= 9 && is_release (accelerator))
|
||||
{
|
||||
accelerator += 9;
|
||||
len -= 9;
|
||||
mods |= EGG_VIRTUAL_RELEASE_MASK;
|
||||
}
|
||||
else if (len >= 9 && is_control (accelerator))
|
||||
{
|
||||
accelerator += 9;
|
||||
len -= 9;
|
||||
mods |= EGG_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_shift (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= EGG_VIRTUAL_SHIFT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_shft (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= EGG_VIRTUAL_SHIFT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_ctrl (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= EGG_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_modx (accelerator))
|
||||
{
|
||||
static const guint mod_vals[] = {
|
||||
EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK,
|
||||
EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK
|
||||
};
|
||||
|
||||
len -= 6;
|
||||
accelerator += 4;
|
||||
mods |= mod_vals[*accelerator - '1'];
|
||||
accelerator += 2;
|
||||
}
|
||||
else if (len >= 5 && is_ctl (accelerator))
|
||||
{
|
||||
accelerator += 5;
|
||||
len -= 5;
|
||||
mods |= EGG_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 5 && is_alt (accelerator))
|
||||
{
|
||||
accelerator += 5;
|
||||
len -= 5;
|
||||
mods |= EGG_VIRTUAL_ALT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_meta (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= EGG_VIRTUAL_META_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_hyper (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= EGG_VIRTUAL_HYPER_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_super (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= EGG_VIRTUAL_SUPER_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar last_ch;
|
||||
|
||||
last_ch = *accelerator;
|
||||
while (last_ch && last_ch != '>')
|
||||
{
|
||||
last_ch = *accelerator;
|
||||
accelerator += 1;
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
keyval = gdk_keyval_from_name (accelerator);
|
||||
|
||||
if (keyval == 0)
|
||||
bad_keyval = TRUE;
|
||||
|
||||
accelerator += len;
|
||||
len -= len;
|
||||
}
|
||||
}
|
||||
|
||||
if (accelerator_key)
|
||||
*accelerator_key = gdk_keyval_to_lower (keyval);
|
||||
if (accelerator_mods)
|
||||
*accelerator_mods = mods;
|
||||
|
||||
return !bad_keyval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* egg_virtual_accelerator_name:
|
||||
* @accelerator_key: accelerator keyval
|
||||
* @accelerator_mods: accelerator modifier mask
|
||||
* @returns: a newly-allocated accelerator name
|
||||
*
|
||||
* Converts an accelerator keyval and modifier mask
|
||||
* into a string parseable by egg_accelerator_parse_virtual().
|
||||
* For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK,
|
||||
* this function returns "<Control>q".
|
||||
*
|
||||
* The caller of this function must free the returned string.
|
||||
*/
|
||||
gchar*
|
||||
egg_virtual_accelerator_name (guint accelerator_key,
|
||||
EggVirtualModifierType accelerator_mods)
|
||||
{
|
||||
static const gchar text_release[] = "<Release>";
|
||||
static const gchar text_shift[] = "<Shift>";
|
||||
static const gchar text_control[] = "<Control>";
|
||||
static const gchar text_mod1[] = "<Alt>";
|
||||
static const gchar text_mod2[] = "<Mod2>";
|
||||
static const gchar text_mod3[] = "<Mod3>";
|
||||
static const gchar text_mod4[] = "<Mod4>";
|
||||
static const gchar text_mod5[] = "<Mod5>";
|
||||
static const gchar text_meta[] = "<Meta>";
|
||||
static const gchar text_super[] = "<Super>";
|
||||
static const gchar text_hyper[] = "<Hyper>";
|
||||
guint l;
|
||||
gchar *keyval_name;
|
||||
gchar *accelerator;
|
||||
|
||||
accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK;
|
||||
|
||||
keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
|
||||
if (!keyval_name)
|
||||
keyval_name = "";
|
||||
|
||||
l = 0;
|
||||
if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK)
|
||||
l += sizeof (text_release) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK)
|
||||
l += sizeof (text_shift) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK)
|
||||
l += sizeof (text_control) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_ALT_MASK)
|
||||
l += sizeof (text_mod1) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK)
|
||||
l += sizeof (text_mod2) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK)
|
||||
l += sizeof (text_mod3) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK)
|
||||
l += sizeof (text_mod4) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK)
|
||||
l += sizeof (text_mod5) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_META_MASK)
|
||||
l += sizeof (text_meta) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK)
|
||||
l += sizeof (text_hyper) - 1;
|
||||
if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK)
|
||||
l += sizeof (text_super) - 1;
|
||||
l += strlen (keyval_name);
|
||||
|
||||
accelerator = g_new (gchar, l + 1);
|
||||
|
||||
l = 0;
|
||||
accelerator[l] = 0;
|
||||
if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_release);
|
||||
l += sizeof (text_release) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_shift);
|
||||
l += sizeof (text_shift) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_control);
|
||||
l += sizeof (text_control) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_ALT_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_mod1);
|
||||
l += sizeof (text_mod1) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_mod2);
|
||||
l += sizeof (text_mod2) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_mod3);
|
||||
l += sizeof (text_mod3) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_mod4);
|
||||
l += sizeof (text_mod4) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_mod5);
|
||||
l += sizeof (text_mod5) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_META_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_meta);
|
||||
l += sizeof (text_meta) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_hyper);
|
||||
l += sizeof (text_hyper) - 1;
|
||||
}
|
||||
if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK)
|
||||
{
|
||||
strcpy (accelerator + l, text_super);
|
||||
l += sizeof (text_super) - 1;
|
||||
}
|
||||
|
||||
strcpy (accelerator + l, keyval_name);
|
||||
|
||||
return accelerator;
|
||||
}
|
||||
|
||||
void
|
||||
egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
|
||||
EggVirtualModifierType virtual_mods,
|
||||
GdkModifierType *concrete_mods)
|
||||
{
|
||||
GdkModifierType concrete;
|
||||
int i;
|
||||
const EggModmap *modmap;
|
||||
|
||||
g_return_if_fail (GDK_IS_KEYMAP (keymap));
|
||||
g_return_if_fail (concrete_mods != NULL);
|
||||
|
||||
modmap = egg_keymap_get_modmap (keymap);
|
||||
|
||||
/* Not so sure about this algorithm. */
|
||||
|
||||
concrete = 0;
|
||||
i = 0;
|
||||
while (i < EGG_MODMAP_ENTRY_LAST)
|
||||
{
|
||||
if (modmap->mapping[i] & virtual_mods)
|
||||
concrete |= (1 << i);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
*concrete_mods = concrete;
|
||||
}
|
||||
|
||||
void
|
||||
egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
|
||||
GdkModifierType concrete_mods,
|
||||
EggVirtualModifierType *virtual_mods)
|
||||
{
|
||||
GdkModifierType virtual;
|
||||
int i;
|
||||
const EggModmap *modmap;
|
||||
|
||||
g_return_if_fail (GDK_IS_KEYMAP (keymap));
|
||||
g_return_if_fail (virtual_mods != NULL);
|
||||
|
||||
modmap = egg_keymap_get_modmap (keymap);
|
||||
|
||||
/* Not so sure about this algorithm. */
|
||||
|
||||
virtual = 0;
|
||||
i = 0;
|
||||
while (i < EGG_MODMAP_ENTRY_LAST)
|
||||
{
|
||||
if ((1 << i) & concrete_mods)
|
||||
{
|
||||
EggVirtualModifierType cleaned;
|
||||
|
||||
cleaned = modmap->mapping[i] & ~(EGG_VIRTUAL_MOD2_MASK |
|
||||
EGG_VIRTUAL_MOD3_MASK |
|
||||
EGG_VIRTUAL_MOD4_MASK |
|
||||
EGG_VIRTUAL_MOD5_MASK);
|
||||
|
||||
if (cleaned != 0)
|
||||
{
|
||||
virtual |= cleaned;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rather than dropping mod2->mod5 if not bound,
|
||||
* go ahead and use the concrete names
|
||||
*/
|
||||
virtual |= modmap->mapping[i];
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
*virtual_mods = virtual;
|
||||
}
|
||||
|
||||
static void
|
||||
reload_modmap (GdkKeymap *keymap,
|
||||
EggModmap *modmap)
|
||||
{
|
||||
XModifierKeymap *xmodmap;
|
||||
int map_size;
|
||||
int i;
|
||||
|
||||
/* FIXME multihead */
|
||||
xmodmap = XGetModifierMapping (gdk_x11_get_default_xdisplay ());
|
||||
|
||||
memset (modmap->mapping, 0, sizeof (modmap->mapping));
|
||||
|
||||
/* there are 8 modifiers, and the first 3 are shift, shift lock,
|
||||
* and control
|
||||
*/
|
||||
map_size = 8 * xmodmap->max_keypermod;
|
||||
i = 3 * xmodmap->max_keypermod;
|
||||
while (i < map_size)
|
||||
{
|
||||
/* get the key code at this point in the map,
|
||||
* see if its keysym is one we're interested in
|
||||
*/
|
||||
int keycode = xmodmap->modifiermap[i];
|
||||
GdkKeymapKey *keys;
|
||||
guint *keyvals;
|
||||
int n_entries;
|
||||
int j;
|
||||
EggVirtualModifierType mask;
|
||||
|
||||
keys = NULL;
|
||||
keyvals = NULL;
|
||||
n_entries = 0;
|
||||
|
||||
gdk_keymap_get_entries_for_keycode (keymap,
|
||||
keycode,
|
||||
&keys, &keyvals, &n_entries);
|
||||
|
||||
mask = 0;
|
||||
j = 0;
|
||||
while (j < n_entries)
|
||||
{
|
||||
if (keyvals[j] == GDK_Num_Lock)
|
||||
mask |= EGG_VIRTUAL_NUM_LOCK_MASK;
|
||||
else if (keyvals[j] == GDK_Scroll_Lock)
|
||||
mask |= EGG_VIRTUAL_SCROLL_LOCK_MASK;
|
||||
else if (keyvals[j] == GDK_Meta_L ||
|
||||
keyvals[j] == GDK_Meta_R)
|
||||
mask |= EGG_VIRTUAL_META_MASK;
|
||||
else if (keyvals[j] == GDK_Hyper_L ||
|
||||
keyvals[j] == GDK_Hyper_R)
|
||||
mask |= EGG_VIRTUAL_HYPER_MASK;
|
||||
else if (keyvals[j] == GDK_Super_L ||
|
||||
keyvals[j] == GDK_Super_R)
|
||||
mask |= EGG_VIRTUAL_SUPER_MASK;
|
||||
else if (keyvals[j] == GDK_Mode_switch)
|
||||
mask |= EGG_VIRTUAL_MODE_SWITCH_MASK;
|
||||
|
||||
++j;
|
||||
}
|
||||
|
||||
/* Mod1Mask is 1 << 3 for example, i.e. the
|
||||
* fourth modifier, i / keyspermod is the modifier
|
||||
* index
|
||||
*/
|
||||
modmap->mapping[i/xmodmap->max_keypermod] |= mask;
|
||||
|
||||
g_free (keyvals);
|
||||
g_free (keys);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Add in the not-really-virtual fixed entries */
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_SHIFT] |= EGG_VIRTUAL_SHIFT_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_CONTROL] |= EGG_VIRTUAL_CONTROL_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_LOCK] |= EGG_VIRTUAL_LOCK_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_MOD1] |= EGG_VIRTUAL_ALT_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_MOD2] |= EGG_VIRTUAL_MOD2_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_MOD3] |= EGG_VIRTUAL_MOD3_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_MOD4] |= EGG_VIRTUAL_MOD4_MASK;
|
||||
modmap->mapping[EGG_MODMAP_ENTRY_MOD5] |= EGG_VIRTUAL_MOD5_MASK;
|
||||
|
||||
XFreeModifiermap (xmodmap);
|
||||
}
|
||||
|
||||
const EggModmap*
|
||||
egg_keymap_get_modmap (GdkKeymap *keymap)
|
||||
{
|
||||
EggModmap *modmap;
|
||||
|
||||
/* This is all a hack, much simpler when we can just
|
||||
* modify GDK directly.
|
||||
*/
|
||||
|
||||
modmap = g_object_get_data (G_OBJECT (keymap),
|
||||
"egg-modmap");
|
||||
|
||||
if (modmap == NULL)
|
||||
{
|
||||
modmap = g_new0 (EggModmap, 1);
|
||||
|
||||
/* FIXME modify keymap change events with an event filter
|
||||
* and force a reload if we get one
|
||||
*/
|
||||
|
||||
reload_modmap (keymap, modmap);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (keymap),
|
||||
"egg-modmap",
|
||||
modmap,
|
||||
g_free);
|
||||
}
|
||||
|
||||
g_assert (modmap != NULL);
|
||||
|
||||
return modmap;
|
||||
}
|
87
src/eggaccelerators.h
Normal file
87
src/eggaccelerators.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* eggaccelerators.h
|
||||
* Copyright (C) 2002 Red Hat, Inc.
|
||||
* Developed by Havoc Pennington
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EGG_ACCELERATORS_H__
|
||||
#define __EGG_ACCELERATORS_H__
|
||||
|
||||
#include <gtk/gtkaccelgroup.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Where a value is also in GdkModifierType we coincide,
|
||||
* otherwise we don't overlap.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
EGG_VIRTUAL_SHIFT_MASK = 1 << 0,
|
||||
EGG_VIRTUAL_LOCK_MASK = 1 << 1,
|
||||
EGG_VIRTUAL_CONTROL_MASK = 1 << 2,
|
||||
|
||||
EGG_VIRTUAL_ALT_MASK = 1 << 3, /* fixed as Mod1 */
|
||||
|
||||
EGG_VIRTUAL_MOD2_MASK = 1 << 4,
|
||||
EGG_VIRTUAL_MOD3_MASK = 1 << 5,
|
||||
EGG_VIRTUAL_MOD4_MASK = 1 << 6,
|
||||
EGG_VIRTUAL_MOD5_MASK = 1 << 7,
|
||||
|
||||
#if 0
|
||||
GDK_BUTTON1_MASK = 1 << 8,
|
||||
GDK_BUTTON2_MASK = 1 << 9,
|
||||
GDK_BUTTON3_MASK = 1 << 10,
|
||||
GDK_BUTTON4_MASK = 1 << 11,
|
||||
GDK_BUTTON5_MASK = 1 << 12,
|
||||
/* 13, 14 are used by Xkb for the keyboard group */
|
||||
#endif
|
||||
|
||||
EGG_VIRTUAL_META_MASK = 1 << 24,
|
||||
EGG_VIRTUAL_SUPER_MASK = 1 << 25,
|
||||
EGG_VIRTUAL_HYPER_MASK = 1 << 26,
|
||||
EGG_VIRTUAL_MODE_SWITCH_MASK = 1 << 27,
|
||||
EGG_VIRTUAL_NUM_LOCK_MASK = 1 << 28,
|
||||
EGG_VIRTUAL_SCROLL_LOCK_MASK = 1 << 29,
|
||||
|
||||
/* Also in GdkModifierType */
|
||||
EGG_VIRTUAL_RELEASE_MASK = 1 << 30,
|
||||
|
||||
/* 28-31 24-27 20-23 16-19 12-15 8-11 4-7 0-3
|
||||
* 7 f 0 0 0 0 f f
|
||||
*/
|
||||
EGG_VIRTUAL_MODIFIER_MASK = 0x7f0000ff
|
||||
|
||||
} EggVirtualModifierType;
|
||||
|
||||
gboolean egg_accelerator_parse_virtual (const gchar *accelerator,
|
||||
guint *accelerator_key,
|
||||
EggVirtualModifierType *accelerator_mods);
|
||||
void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
|
||||
EggVirtualModifierType virtual_mods,
|
||||
GdkModifierType *concrete_mods);
|
||||
void egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
|
||||
GdkModifierType concrete_mods,
|
||||
EggVirtualModifierType *virtual_mods);
|
||||
|
||||
gchar* egg_virtual_accelerator_name (guint accelerator_key,
|
||||
EggVirtualModifierType accelerator_mods);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __EGG_ACCELERATORS_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user