Merge lp:~ksamak/compiz/ezoom_focus_tracking into lp:compiz/0.9.13
- ezoom_focus_tracking
- Merge into 0.9.13
Status: | Needs review |
---|---|
Proposed branch: | lp:~ksamak/compiz/ezoom_focus_tracking |
Merge into: | lp:compiz/0.9.13 |
Diff against target: |
1617 lines (+1252/-39) 17 files modified
debian/compiz-dev.install (+1/-0) debian/compiz-plugins-default.install (+2/-0) debian/control (+1/-0) plugins/ezoom/CMakeLists.txt (+1/-1) plugins/ezoom/ezoom.xml.in (+35/-8) plugins/ezoom/src/ezoom.cpp (+123/-28) plugins/ezoom/src/ezoom.h (+22/-2) plugins/focuspoll/CMakeLists.txt (+9/-0) plugins/focuspoll/compiz-focuspoll.pc.in (+12/-0) plugins/focuspoll/focuspoll.xml.in (+34/-0) plugins/focuspoll/include/accessibilitywatcher/accessibilitywatcher.h (+82/-0) plugins/focuspoll/include/accessibilitywatcher/focusinfo.h (+76/-0) plugins/focuspoll/include/focuspoll/focuspoll.h (+50/-0) plugins/focuspoll/src/accessibilitywatcher.cpp (+506/-0) plugins/focuspoll/src/focuspoll.cpp (+220/-0) plugins/focuspoll/src/private.h (+75/-0) plugins/showmouse/showmouse.xml.in (+3/-0) |
To merge this branch: | bzr merge lp:~ksamak/compiz/ezoom_focus_tracking |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
ksamak (community) | Needs Resubmitting | ||
Andrea Azzarone | Pending | ||
Marco Trevisan (TreviƱo) | Pending | ||
Sam Spilsbury | code, style | Pending | |
Review via email: mp+321643@code.launchpad.net |
This proposal supersedes a proposal from 2017-02-24.
Commit message
Description of the change
ezoom: added focus tracking based on at-spi a11y events.
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
Ok this is the first part of the review. I'll continue later.
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Thanks for all the hard work in implementing this. There's a fair bit of work to be done before this can be integrated. In particular, this cannot be merged whilst it opens a separate display connection - that is a recipe for deadlocks.
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Relevant prior art, if interested: https:/
ksamak (ksamak) wrote : Posted in a previous version of this proposal | # |
well, this plugin would indeed have been helpful.
Sam Spilsbury (smspillaz) wrote 18 hours ago:
I like the fact that this is a separate library, but this absolutely doesn't belong in the mousepoll plugin. The mouse poll plugin is supposed to do one thing and one thing only - update the position of the mouse every N milliseconds. Move all this into either a separate plugin or library.
I originally made a copy of the mousePoll plugin (called focusPoll), but for some unknown reason it... deadlocked, or froze at runtime. I couldn't find why, and no one had time to look at it, so I merged both logics in mousepoll, cause then, with sensibly the same methods, it didn't freeze.
I agree an additional plugin would serve better, so I'd appreciate some input on that problem.
there's a readyish branch on http://
question: how would you circumvent the problem of the call to XOpenDisplay, if the whole a11ywatcher was a library? Is there a better way to get the screen info? that is without causing all those problems.
I will meditate on these ideas, and weight the pros and cons of the different solutions, and i'll then continue the work.
thank you for all the advice and corrections, including those pending below. I am available to discuss these matters further, or if you have more insight.
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
> Maybe you would have some insights as to what is blocking here. It
> might be, as you pointed, the call to open the display.
> question: how would you circumvent the problem of the call to XOpenDisplay, if
> the whole a11ywatcher was a library? Is there a better way to get the screen
> info? that is without causing all those problems.
Yes, there's a global variable called 'screen' and you can access the current connection from there (screen->dpy()). If your library needs a reference to it, I'd suggest having the caller pass it in.
ksamak (ksamak) wrote : Posted in a previous version of this proposal | # |
I've answered some of the following, and will superseed the merge request with the new version from the branch.
i thank you for your time, advice, and corrections.
ksamak (ksamak) : Posted in a previous version of this proposal | # |
ksamak (ksamak) wrote : Posted in a previous version of this proposal | # |
call for help on the matter of binding C callback to c++ member function.
thx
ksamak (ksamak) wrote : Posted in a previous version of this proposal | # |
just a ping, i changed coding style again, on request from 3v1n0.
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
I reviews part of the code. Fix it before I going on.
ksamak (ksamak) wrote : Posted in a previous version of this proposal | # |
I fixed the code according to your specifications, i changed the whole coding style of my editor, thanks to the few lines i (finally) found here:
http://
Sorry again for my misunderstanding tabs and coding style, i'll try my best to respect that from initial coding on, event though i find it less readable.
I thank you for your patience.
ksamak (ksamak) wrote : | # |
created lp:~ksamak/compiz/correct_mousetheme_targetting_for_ezoom, although i think it wasn't necessary. I'll delete it.
I add the update for the rebranding of icedove into thunderbird.
thank you.
Samuel thibault (samuel-thibault) wrote : | # |
Hello,
I have gone through the previous review from azzar1, and commented further.
Samuel
Samuel thibault (samuel-thibault) wrote : Posted in a previous version of this proposal | # |
I have commented on the callback issue, to avoid the singleton.
Unmerged revisions
- 4124. By ksamak <ksamak@ksalaptop>
-
added rebranding of icedove to thunderbird support
- 4123. By ksamak <ksamak@ksalaptop>
-
coding style
- 4122. By ksamak <ksamak@ksalaptop>
-
added precedence relation to start showmouse before ezoom
- 4121. By ksamak <ksamak@ksalaptop>
-
modifications of code according to azzar's request
- 4120. By ksamak <ksamak@ksalaptop>
-
coding style modifs. changed if format on 3v1n0's request
- 4119. By ksamak <ksamak@ksalaptop>
-
coding style modifs
- 4118. By ksamak <ksamak@ksalaptop>
-
coding style modifs
- 4117. By ksamak <ksamak@ksalaptop>
-
minors code modifs
- 4116. By ksamak <ksamak@ksalaptop>
-
minors code modifs
- 4115. By ksamak <ksamak@ksalaptop>
-
corrected segfault, minors code modifs
Preview Diff
1 | === modified file 'debian/compiz-dev.install' | |||
2 | --- debian/compiz-dev.install 2016-07-14 15:21:59 +0000 | |||
3 | +++ debian/compiz-dev.install 2017-04-28 09:59:04 +0000 | |||
4 | @@ -7,6 +7,7 @@ | |||
5 | 7 | debian/tmp/usr/lib/*/pkgconfig/compiz-composite.pc | 7 | debian/tmp/usr/lib/*/pkgconfig/compiz-composite.pc |
6 | 8 | debian/tmp/usr/lib/*/pkgconfig/compiz-cube.pc | 8 | debian/tmp/usr/lib/*/pkgconfig/compiz-cube.pc |
7 | 9 | debian/tmp/usr/lib/*/pkgconfig/compiz-mousepoll.pc | 9 | debian/tmp/usr/lib/*/pkgconfig/compiz-mousepoll.pc |
8 | 10 | debian/tmp/usr/lib/*/pkgconfig/compiz-focuspoll.pc | ||
9 | 10 | debian/tmp/usr/lib/*/pkgconfig/compiz-opengl.pc | 11 | debian/tmp/usr/lib/*/pkgconfig/compiz-opengl.pc |
10 | 11 | debian/tmp/usr/lib/*/pkgconfig/compiz.pc | 12 | debian/tmp/usr/lib/*/pkgconfig/compiz.pc |
11 | 12 | debian/tmp/usr/lib/*/pkgconfig/compiz-scale.pc | 13 | debian/tmp/usr/lib/*/pkgconfig/compiz-scale.pc |
12 | 13 | 14 | ||
13 | === modified file 'debian/compiz-plugins-default.install' | |||
14 | --- debian/compiz-plugins-default.install 2015-07-24 16:28:37 +0000 | |||
15 | +++ debian/compiz-plugins-default.install 2017-04-28 09:59:04 +0000 | |||
16 | @@ -26,6 +26,8 @@ | |||
17 | 26 | usr/share/compiz/*matecompat.* | 26 | usr/share/compiz/*matecompat.* |
18 | 27 | usr/lib/*/compiz/*mousepoll.* | 27 | usr/lib/*/compiz/*mousepoll.* |
19 | 28 | usr/share/compiz/*mousepoll.* | 28 | usr/share/compiz/*mousepoll.* |
20 | 29 | usr/lib/*/compiz/*focuspoll.* | ||
21 | 30 | usr/share/compiz/*focuspoll.* | ||
22 | 29 | usr/lib/*/compiz/*move.* | 31 | usr/lib/*/compiz/*move.* |
23 | 30 | usr/share/compiz/*move.* | 32 | usr/share/compiz/*move.* |
24 | 31 | usr/lib/*/compiz/*opengl.* | 33 | usr/lib/*/compiz/*opengl.* |
25 | 32 | 34 | ||
26 | === modified file 'debian/control' | |||
27 | --- debian/control 2016-11-03 18:29:41 +0000 | |||
28 | +++ debian/control 2017-04-28 09:59:04 +0000 | |||
29 | @@ -14,6 +14,7 @@ | |||
30 | 14 | quilt (>= 0.40), | 14 | quilt (>= 0.40), |
31 | 15 | libcairo2-dev, | 15 | libcairo2-dev, |
32 | 16 | libdbus-glib-1-dev, | 16 | libdbus-glib-1-dev, |
33 | 17 | libatspi2.0-dev, | ||
34 | 17 | libgl1-mesa-dev (>= 6.5.1) [!armhf !armel] | libgl-dev [!armhf !armel], | 18 | libgl1-mesa-dev (>= 6.5.1) [!armhf !armel] | libgl-dev [!armhf !armel], |
35 | 18 | libegl1-mesa-dev [armhf armel], libgles2-mesa-dev [armhf armel], | 19 | libegl1-mesa-dev [armhf armel], libgles2-mesa-dev [armhf armel], |
36 | 19 | libboost-dev, | 20 | libboost-dev, |
37 | 20 | 21 | ||
38 | === modified file 'plugins/ezoom/CMakeLists.txt' | |||
39 | --- plugins/ezoom/CMakeLists.txt 2012-05-16 17:40:27 +0000 | |||
40 | +++ plugins/ezoom/CMakeLists.txt 2017-04-28 09:59:04 +0000 | |||
41 | @@ -2,4 +2,4 @@ | |||
42 | 2 | 2 | ||
43 | 3 | include (CompizPlugin) | 3 | include (CompizPlugin) |
44 | 4 | 4 | ||
46 | 5 | compiz_plugin (ezoom PLUGINDEPS composite opengl mousepoll) | 5 | compiz_plugin (ezoom PLUGINDEPS composite opengl mousepoll focuspoll) |
47 | 6 | 6 | ||
48 | === modified file 'plugins/ezoom/ezoom.xml.in' | |||
49 | --- plugins/ezoom/ezoom.xml.in 2016-07-01 15:37:19 +0000 | |||
50 | +++ plugins/ezoom/ezoom.xml.in 2017-04-28 09:59:04 +0000 | |||
51 | @@ -7,6 +7,7 @@ | |||
52 | 7 | <plugin>expo</plugin> | 7 | <plugin>expo</plugin> |
53 | 8 | <plugin>decor</plugin> | 8 | <plugin>decor</plugin> |
54 | 9 | <plugin>mousepoll</plugin> | 9 | <plugin>mousepoll</plugin> |
55 | 10 | <plugin>focuspoll</plugin> | ||
56 | 10 | </relation> | 11 | </relation> |
57 | 11 | <relation type="before"> | 12 | <relation type="before"> |
58 | 12 | <plugin>staticswitcher</plugin> | 13 | <plugin>staticswitcher</plugin> |
59 | @@ -15,6 +16,7 @@ | |||
60 | 15 | <requirement> | 16 | <requirement> |
61 | 16 | <plugin>opengl</plugin> | 17 | <plugin>opengl</plugin> |
62 | 17 | <plugin>mousepoll</plugin> | 18 | <plugin>mousepoll</plugin> |
63 | 19 | <plugin>focuspoll</plugin> | ||
64 | 18 | </requirement> | 20 | </requirement> |
65 | 19 | </deps> | 21 | </deps> |
66 | 20 | <_short>Enhanced Zoom Desktop</_short> | 22 | <_short>Enhanced Zoom Desktop</_short> |
67 | @@ -425,12 +427,17 @@ | |||
68 | 425 | <_short>Focus Tracking</_short> | 427 | <_short>Focus Tracking</_short> |
69 | 426 | <option type="bool" name="follow_focus"> | 428 | <option type="bool" name="follow_focus"> |
70 | 427 | <_short>Enable focus tracking</_short> | 429 | <_short>Enable focus tracking</_short> |
72 | 428 | <_long>Move the zoom area when focus changes.</_long> | 430 | <_long>Move the zoom area when focus changes. You may see the focuspoll module options for more</_long> |
73 | 429 | <default>true</default> | 431 | <default>true</default> |
74 | 430 | </option> | 432 | </option> |
75 | 433 | <option type="bool" name="follow_window_focus"> | ||
76 | 434 | <_short>Enable focus tracking when switching windows</_short> | ||
77 | 435 | <_long>Move the zoom area to the center of a newly switched window.</_long> | ||
78 | 436 | <default>false</default> | ||
79 | 437 | </option> | ||
80 | 431 | <option type="bool" name="focus_fit_window"> | 438 | <option type="bool" name="focus_fit_window"> |
83 | 432 | <_short>Fit zoom level to window on focus change</_short> | 439 | <_short>Fit zoom level to newly switched window</_short> |
84 | 433 | <_long>Fit the zoomed area to the window when the zoomed area moves as a result of focus tracking.</_long> | 440 | <_long>Fit the zoomed area to the window when it switches.</_long> |
85 | 434 | <default>false</default> | 441 | <default>false</default> |
86 | 435 | </option> | 442 | </option> |
87 | 436 | <option type="float" name="autoscale_min"> | 443 | <option type="float" name="autoscale_min"> |
88 | @@ -443,16 +450,31 @@ | |||
89 | 443 | </option> | 450 | </option> |
90 | 444 | <option type="bool" name="always_focus_fit_window"> | 451 | <option type="bool" name="always_focus_fit_window"> |
91 | 445 | <_short>Always fit to window on focus track</_short> | 452 | <_short>Always fit to window on focus track</_short> |
93 | 446 | <_long>Fit the zoomed area to the window when the zoomed area moves as a result of focus tracking. Even when not initially zoomed in. </_long> | 453 | <_long>Fit the zoomed area to the newly switched window, even when not initially zoomed in. </_long> |
94 | 447 | <default>false</default> | 454 | <default>false</default> |
95 | 448 | </option> | 455 | </option> |
96 | 449 | <option type="int" name="follow_focus_delay"> | 456 | <option type="int" name="follow_focus_delay"> |
100 | 450 | <_short>Follow Focus Delay</_short> | 457 | <_short>tracking delay between mouse/keyboard modes</_short> |
101 | 451 | <_long>Only attempt to center newly focused windows if the mouse hasn't moved in this amount of seconds. Use this to avoid jumping when using sloppy focus.</_long> | 458 | <_long>Only attempt to follow focus if the mouse hasn't moved in this amount of seconds. Use this to avoid jumping everywhere on the screen.</_long> |
102 | 452 | <default>0</default> | 459 | <default>1</default> |
103 | 453 | <min>0</min> | 460 | <min>0</min> |
104 | 454 | <max>15</max> | 461 | <max>15</max> |
105 | 455 | </option> | 462 | </option> |
106 | 463 | <option type="bool" name="always_center_mouse"> | ||
107 | 464 | <_short>Keep Mouse centered inside zoom area</_short> | ||
108 | 465 | <_long>If activated, the mouse will always be centered when in mouse sync mode, if not, it will move around the zoom area</_long> | ||
109 | 466 | <default>true</default> | ||
110 | 467 | </option> | ||
111 | 468 | <option type="bool" name="restrain_zoom_to_screen"> | ||
112 | 469 | <_short>Restrain the zoom area inside the screen</_short> | ||
113 | 470 | <_long>if enabled, zoom area will stay inside the screen, if not, zoom area can go over screen borders (it will show empty black space)</_long> | ||
114 | 471 | <default>true</default> | ||
115 | 472 | </option> | ||
116 | 473 | <option type="bool" name="warp_mouse_to_focus"> | ||
117 | 474 | <_short>when switching focus back to mouse, warp mouse inside the zoomed area</_short> | ||
118 | 475 | <_long>when following a keyboard focus, one can want the mouse to come back into the field of vision before moving it. avoids jumping to another part of the screen when switching mouse/keyboard focus.</_long> | ||
119 | 476 | <default>true</default> | ||
120 | 477 | </option> | ||
121 | 456 | </group> | 478 | </group> |
122 | 457 | <group> | 479 | <group> |
123 | 458 | <_short>Animation</_short> | 480 | <_short>Animation</_short> |
124 | @@ -461,7 +483,7 @@ | |||
125 | 461 | <_long>Zoom Speed</_long> | 483 | <_long>Zoom Speed</_long> |
126 | 462 | <default>25</default> | 484 | <default>25</default> |
127 | 463 | <min>0.1</min> | 485 | <min>0.1</min> |
129 | 464 | <max>100</max> | 486 | <max>500</max> |
130 | 465 | <precision>0.1</precision> | 487 | <precision>0.1</precision> |
131 | 466 | </option> | 488 | </option> |
132 | 467 | <option type="float" name="timestep"> | 489 | <option type="float" name="timestep"> |
133 | @@ -472,6 +494,11 @@ | |||
134 | 472 | <max>50</max> | 494 | <max>50</max> |
135 | 473 | <precision>0.1</precision> | 495 | <precision>0.1</precision> |
136 | 474 | </option> | 496 | </option> |
137 | 497 | <option type="bool" name="instant_pan"> | ||
138 | 498 | <_short>move the zoom area instantly</_short> | ||
139 | 499 | <_long>when enabled, zoom area is warped instantly to focus position. When disabled, zoom area makes a smooth move to the focus position</_long> | ||
140 | 500 | <default>false</default> | ||
141 | 501 | </option> | ||
142 | 475 | </group> | 502 | </group> |
143 | 476 | </options> | 503 | </options> |
144 | 477 | </plugin> | 504 | </plugin> |
145 | 478 | 505 | ||
146 | === modified file 'plugins/ezoom/src/ezoom.cpp' | |||
147 | --- plugins/ezoom/src/ezoom.cpp 2016-07-01 15:37:19 +0000 | |||
148 | +++ plugins/ezoom/src/ezoom.cpp 2017-04-28 09:59:04 +0000 | |||
149 | @@ -76,7 +76,6 @@ | |||
150 | 76 | 76 | ||
151 | 77 | COMPIZ_PLUGIN_20090315 (ezoom, ZoomPluginVTable) | 77 | COMPIZ_PLUGIN_20090315 (ezoom, ZoomPluginVTable) |
152 | 78 | 78 | ||
153 | 79 | |||
154 | 80 | /* | 79 | /* |
155 | 81 | * This toggles paint functions. We don't need to continually run code when we | 80 | * This toggles paint functions. We don't need to continually run code when we |
156 | 82 | * are not doing anything. | 81 | * are not doing anything. |
157 | @@ -573,18 +572,45 @@ | |||
158 | 573 | int y, | 572 | int y, |
159 | 574 | bool instant) | 573 | bool instant) |
160 | 575 | { | 574 | { |
161 | 575 | setCenter (x, y, instant, false); | ||
162 | 576 | } | ||
163 | 577 | |||
164 | 578 | void | ||
165 | 579 | EZoomScreen::setCenter (int x, | ||
166 | 580 | int y, | ||
167 | 581 | bool instant, | ||
168 | 582 | bool center) | ||
169 | 583 | { | ||
170 | 576 | int out = screen->outputDeviceForPoint (x, y); | 584 | int out = screen->outputDeviceForPoint (x, y); |
171 | 577 | CompOutput *o = &screen->outputDevs ().at (out); | 585 | CompOutput *o = &screen->outputDevs ().at (out); |
172 | 578 | 586 | ||
173 | 579 | if (zooms.at (out).locked) | 587 | if (zooms.at (out).locked) |
174 | 580 | return; | 588 | return; |
175 | 581 | 589 | ||
182 | 582 | zooms.at (out).xTranslate = (float) | 590 | // this correction allows constant centering of the mouse |
183 | 583 | ((x - o->x1 ()) - o->width () / 2) / (o->width ()); | 591 | float zoomCorrection = std::max(1.0f - zooms.at (out).newZoom, 0.1f); |
184 | 584 | zooms.at (out).yTranslate = (float) | 592 | if (!center) { |
185 | 585 | ((y - o->y1 ()) - o->height () / 2) / (o->height ()); | 593 | zoomCorrection = EZOOM_SCREEN_BORDER_OFFSET; |
186 | 586 | 594 | } | |
187 | 587 | if (instant) | 595 | |
188 | 596 | float zoom_x_inside = (float) (x - o->x1 () - o->width () / 2); | ||
189 | 597 | // We need the zoom correction to center the mouse in zoomarea | ||
190 | 598 | zoom_x_inside /= o->width () * zoomCorrection; | ||
191 | 599 | float zoom_y_inside = (float) (y - o->y1 () - o->height () / 2); | ||
192 | 600 | zoom_y_inside /= o->height () * zoomCorrection; | ||
193 | 601 | |||
194 | 602 | if (optionGetRestrainZoomToScreen ()) { | ||
195 | 603 | if (zoom_x_inside < -0.5f) { zoom_x_inside = -0.5f;} | ||
196 | 604 | if (zoom_x_inside > 0.5f) { zoom_x_inside = 0.5f;} | ||
197 | 605 | if (zoom_y_inside < -0.5f) { zoom_y_inside = -0.5f;} | ||
198 | 606 | if (zoom_y_inside > 0.5f) { zoom_y_inside = 0.5f;} | ||
199 | 607 | } | ||
200 | 608 | |||
201 | 609 | zooms.at (out).xTranslate = zoom_x_inside; | ||
202 | 610 | zooms.at (out).yTranslate = zoom_y_inside; | ||
203 | 611 | |||
204 | 612 | |||
205 | 613 | if (instant || optionGetInstantPan ()) | ||
206 | 588 | { | 614 | { |
207 | 589 | zooms.at (out).realXTranslate = zooms.at (out).xTranslate; | 615 | zooms.at (out).realXTranslate = zooms.at (out).xTranslate; |
208 | 590 | zooms.at (out).realYTranslate = zooms.at (out).yTranslate; | 616 | zooms.at (out).realYTranslate = zooms.at (out).yTranslate; |
209 | @@ -671,11 +697,23 @@ | |||
210 | 671 | void | 697 | void |
211 | 672 | EZoomScreen::enableMousePolling () | 698 | EZoomScreen::enableMousePolling () |
212 | 673 | { | 699 | { |
215 | 674 | pollHandle.start (); | 700 | pollMouseHandle.start (); |
216 | 675 | lastChange = time(NULL); | 701 | lastMouseChange = time (NULL); |
217 | 676 | mouse = MousePoller::getCurrentPosition (); | 702 | mouse = MousePoller::getCurrentPosition (); |
218 | 677 | } | 703 | } |
219 | 678 | 704 | ||
220 | 705 | /* Enables polling of focus position */ | ||
221 | 706 | void | ||
222 | 707 | EZoomScreen::enableFocusPolling () | ||
223 | 708 | { | ||
224 | 709 | if (!optionGetFollowFocus ()) | ||
225 | 710 | { | ||
226 | 711 | return; | ||
227 | 712 | } | ||
228 | 713 | pollFocusHandle.start (); | ||
229 | 714 | lastFocusChange = time (NULL); | ||
230 | 715 | } | ||
231 | 716 | |||
232 | 679 | /* Sets the zoom (or scale) level. | 717 | /* Sets the zoom (or scale) level. |
233 | 680 | * Cleans up if we are suddenly zoomed out. | 718 | * Cleans up if we are suddenly zoomed out. |
234 | 681 | */ | 719 | */ |
235 | @@ -690,9 +728,12 @@ | |||
236 | 690 | value = 1.0f; | 728 | value = 1.0f; |
237 | 691 | else | 729 | else |
238 | 692 | { | 730 | { |
240 | 693 | if (!pollHandle.active ()) | 731 | if (!pollMouseHandle.active ()) |
241 | 694 | enableMousePolling (); | 732 | enableMousePolling (); |
242 | 695 | 733 | ||
243 | 734 | if (!pollFocusHandle.active ()) | ||
244 | 735 | enableFocusPolling (); | ||
245 | 736 | |||
246 | 696 | grabbed |= (1 << zooms.at (out).output); | 737 | grabbed |= (1 << zooms.at (out).output); |
247 | 697 | cursorZoomActive (out); | 738 | cursorZoomActive (out); |
248 | 698 | } | 739 | } |
249 | @@ -738,7 +779,7 @@ | |||
250 | 738 | { | 779 | { |
251 | 739 | int out = screen->outputDeviceForPoint (mouse.x (), mouse.y ()); | 780 | int out = screen->outputDeviceForPoint (mouse.x (), mouse.y ()); |
252 | 740 | 781 | ||
254 | 741 | if (!isInMovement (out)) | 782 | if (!isInMovement (out) || nonMouseFocusTracking) |
255 | 742 | return; | 783 | return; |
256 | 743 | 784 | ||
257 | 744 | CompOutput *o = &screen->outputDevs ().at (out); | 785 | CompOutput *o = &screen->outputDevs ().at (out); |
258 | @@ -1026,7 +1067,7 @@ | |||
259 | 1026 | 1067 | ||
260 | 1027 | if (zooms.at (out).currentZoom == 1.0f) | 1068 | if (zooms.at (out).currentZoom == 1.0f) |
261 | 1028 | { | 1069 | { |
263 | 1029 | lastChange = time(NULL); | 1070 | lastMouseChange = time (NULL); |
264 | 1030 | mouse = MousePoller::getCurrentPosition (); | 1071 | mouse = MousePoller::getCurrentPosition (); |
265 | 1031 | } | 1072 | } |
266 | 1032 | 1073 | ||
267 | @@ -1097,20 +1138,57 @@ | |||
268 | 1097 | void | 1138 | void |
269 | 1098 | EZoomScreen::updateMousePosition (const CompPoint &p) | 1139 | EZoomScreen::updateMousePosition (const CompPoint &p) |
270 | 1099 | { | 1140 | { |
271 | 1141 | auto localTime = time (NULL); | ||
272 | 1100 | mouse.setX (p.x ()); | 1142 | mouse.setX (p.x ()); |
273 | 1101 | mouse.setY (p.y ()); | 1143 | mouse.setY (p.y ()); |
274 | 1102 | 1144 | ||
275 | 1103 | int out = screen->outputDeviceForPoint (mouse.x (), mouse.y ()); | 1145 | int out = screen->outputDeviceForPoint (mouse.x (), mouse.y ()); |
282 | 1104 | lastChange = time(NULL); | 1146 | |
283 | 1105 | 1147 | if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse && !isInMovement (out)) | |
284 | 1106 | if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse && | 1148 | { |
285 | 1107 | !isInMovement (out)) | 1149 | if (optionGetWarpMouseToFocus ()) { |
286 | 1108 | setCenter (mouse.x (), mouse.y (), true); | 1150 | // mouse taking back control of focus |
287 | 1109 | 1151 | if (lastMouseChange <= lastFocusChange) { | |
288 | 1152 | nonMouseFocusTracking = false; | ||
289 | 1153 | screen->warpPointer (mouse.x (), mouse.y ()); | ||
290 | 1154 | restrainCursor (out); | ||
291 | 1155 | } else { | ||
292 | 1156 | setCenter (mouse.x (), mouse.y (), true, optionGetAlwaysCenterMouse ()); | ||
293 | 1157 | } | ||
294 | 1158 | lastMouseChange = localTime; | ||
295 | 1159 | // respect a timing in case user has merely grazed his mouse | ||
296 | 1160 | } else if (localTime - lastFocusChange > optionGetFollowFocusDelay ()) { | ||
297 | 1161 | setCenter (mouse.x (), mouse.y (), true, optionGetAlwaysCenterMouse ()); | ||
298 | 1162 | lastMouseChange = localTime; | ||
299 | 1163 | } | ||
300 | 1164 | } | ||
301 | 1110 | cursorMoved (); | 1165 | cursorMoved (); |
302 | 1111 | cScreen->damageScreen (); | 1166 | cScreen->damageScreen (); |
303 | 1112 | } | 1167 | } |
304 | 1113 | 1168 | ||
305 | 1169 | void | ||
306 | 1170 | EZoomScreen::updateFocusPosition (const CompRect &rect) | ||
307 | 1171 | { | ||
308 | 1172 | auto localTime = time (NULL); | ||
309 | 1173 | int out = screen->outputDeviceForPoint (rect.x (), rect.y ()); | ||
310 | 1174 | if (localTime - lastMouseChange > optionGetFollowFocusDelay ()) { | ||
311 | 1175 | int zoom_area_width = screen->outputDevs ().at (out).width () * zooms.at (out).currentZoom; | ||
312 | 1176 | int zoom_area_height = screen->outputDevs ().at (out).height () * zooms.at (out).currentZoom; | ||
313 | 1177 | int pos_x = rect.x ()+ rect.width () / 2; | ||
314 | 1178 | int pos_y = rect.y () + rect.height () / 2; | ||
315 | 1179 | if (rect.width () > zoom_area_width) { // corrects a too big target, aims at top-left corner | ||
316 | 1180 | pos_x -= (rect.width () - zoom_area_width) / 2; | ||
317 | 1181 | } | ||
318 | 1182 | if (rect.height () > zoom_area_height) { | ||
319 | 1183 | pos_y -= (rect.height () - zoom_area_height) / 2; | ||
320 | 1184 | } | ||
321 | 1185 | setCenter (pos_x, pos_y, false, true); | ||
322 | 1186 | nonMouseFocusTracking = true; | ||
323 | 1187 | lastFocusChange = localTime; | ||
324 | 1188 | } | ||
325 | 1189 | cScreen->damageScreen (); | ||
326 | 1190 | } | ||
327 | 1191 | |||
328 | 1114 | /* Timeout handler to poll the mouse. Returns false (and thereby does not | 1192 | /* Timeout handler to poll the mouse. Returns false (and thereby does not |
329 | 1115 | * get re-added to the queue) when zoom is not active. */ | 1193 | * get re-added to the queue) when zoom is not active. */ |
330 | 1116 | void | 1194 | void |
331 | @@ -1122,11 +1200,21 @@ | |||
332 | 1122 | { | 1200 | { |
333 | 1123 | cursorMoved (); | 1201 | cursorMoved (); |
334 | 1124 | 1202 | ||
337 | 1125 | if (pollHandle.active ()) | 1203 | if (pollMouseHandle.active ()) |
338 | 1126 | pollHandle.stop (); | 1204 | pollMouseHandle.stop (); |
339 | 1127 | } | 1205 | } |
340 | 1128 | } | 1206 | } |
341 | 1129 | 1207 | ||
342 | 1208 | /* Timeout handler to focusPoll. */ | ||
343 | 1209 | void | ||
344 | 1210 | EZoomScreen::updateFocusInterval (const CompRect &rect) | ||
345 | 1211 | { | ||
346 | 1212 | updateFocusPosition (rect); | ||
347 | 1213 | |||
348 | 1214 | if (!grabbed && pollFocusHandle.active ()) | ||
349 | 1215 | pollFocusHandle.stop (); | ||
350 | 1216 | } | ||
351 | 1217 | |||
352 | 1130 | /* Free a cursor */ | 1218 | /* Free a cursor */ |
353 | 1131 | void | 1219 | void |
354 | 1132 | EZoomScreen::freeCursor (CursorTexture *cursor) | 1220 | EZoomScreen::freeCursor (CursorTexture *cursor) |
355 | @@ -1878,8 +1966,8 @@ | |||
356 | 1878 | 1966 | ||
357 | 1879 | if (w == NULL || | 1967 | if (w == NULL || |
358 | 1880 | w->id () == screen->activeWindow () || | 1968 | w->id () == screen->activeWindow () || |
361 | 1881 | time(NULL) - lastChange < optionGetFollowFocusDelay () || | 1969 | time (NULL) - lastMouseChange < optionGetFollowFocusDelay () || |
362 | 1882 | !optionGetFollowFocus ()) | 1970 | !optionGetFollowWindowFocus ()) |
363 | 1883 | return; | 1971 | return; |
364 | 1884 | 1972 | ||
365 | 1885 | int out = screen->outputDeviceForGeometry (w->geometry ()); | 1973 | int out = screen->outputDeviceForGeometry (w->geometry ()); |
366 | @@ -1972,7 +2060,9 @@ | |||
367 | 1972 | gScreen (GLScreen::get (screen)), | 2060 | gScreen (GLScreen::get (screen)), |
368 | 1973 | grabbed (0), | 2061 | grabbed (0), |
369 | 1974 | grabIndex (0), | 2062 | grabIndex (0), |
371 | 1975 | lastChange (0), | 2063 | lastMouseChange (0), |
372 | 2064 | lastFocusChange (0), | ||
373 | 2065 | nonMouseFocusTracking (false), | ||
374 | 1976 | cursorInfoSelected (false), | 2066 | cursorInfoSelected (false), |
375 | 1977 | cursorHidden (false) | 2067 | cursorHidden (false) |
376 | 1978 | { | 2068 | { |
377 | @@ -2006,8 +2096,10 @@ | |||
378 | 2006 | zooms.push_back (za); | 2096 | zooms.push_back (za); |
379 | 2007 | } | 2097 | } |
380 | 2008 | 2098 | ||
383 | 2009 | pollHandle.setCallback (boost::bind ( | 2099 | pollMouseHandle.setCallback (boost::bind(&EZoomScreen::updateMouseInterval, |
384 | 2010 | &EZoomScreen::updateMouseInterval, this, _1)); | 2100 | this, _1)); |
385 | 2101 | pollFocusHandle.setCallback (boost::bind(&EZoomScreen::updateFocusInterval, | ||
386 | 2102 | this, _1)); | ||
387 | 2011 | 2103 | ||
388 | 2012 | optionSetZoomInButtonInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1, | 2104 | optionSetZoomInButtonInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1, |
389 | 2013 | _2, _3)); | 2105 | _2, _3)); |
390 | @@ -2100,8 +2192,10 @@ | |||
391 | 2100 | 2192 | ||
392 | 2101 | EZoomScreen::~EZoomScreen () | 2193 | EZoomScreen::~EZoomScreen () |
393 | 2102 | { | 2194 | { |
396 | 2103 | if (pollHandle.active ()) | 2195 | if (pollMouseHandle.active ()) |
397 | 2104 | pollHandle.stop (); | 2196 | pollMouseHandle.stop (); |
398 | 2197 | if (pollFocusHandle.active ()) | ||
399 | 2198 | pollFocusHandle.stop (); | ||
400 | 2105 | 2199 | ||
401 | 2106 | if (zooms.size ()) | 2200 | if (zooms.size ()) |
402 | 2107 | zooms.clear (); | 2201 | zooms.clear (); |
403 | @@ -2116,7 +2210,8 @@ | |||
404 | 2116 | if (CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) && | 2210 | if (CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) && |
405 | 2117 | CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) && | 2211 | CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) && |
406 | 2118 | CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) && | 2212 | CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) && |
408 | 2119 | CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI)) | 2213 | CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI) && |
409 | 2214 | CompPlugin::checkPluginABI ("focuspoll", COMPIZ_FOCUSPOLL_ABI)) | ||
410 | 2120 | return true; | 2215 | return true; |
411 | 2121 | 2216 | ||
412 | 2122 | return false; | 2217 | return false; |
413 | 2123 | 2218 | ||
414 | === modified file 'plugins/ezoom/src/ezoom.h' | |||
415 | --- plugins/ezoom/src/ezoom.h 2016-07-01 15:37:19 +0000 | |||
416 | +++ plugins/ezoom/src/ezoom.h 2017-04-28 09:59:04 +0000 | |||
417 | @@ -43,12 +43,15 @@ | |||
418 | 43 | #include <composite/composite.h> | 43 | #include <composite/composite.h> |
419 | 44 | #include <opengl/opengl.h> | 44 | #include <opengl/opengl.h> |
420 | 45 | #include <mousepoll/mousepoll.h> | 45 | #include <mousepoll/mousepoll.h> |
421 | 46 | #include <focuspoll/focuspoll.h> | ||
422 | 46 | 47 | ||
423 | 47 | 48 | ||
424 | 48 | #include "ezoom_options.h" | 49 | #include "ezoom_options.h" |
425 | 49 | 50 | ||
426 | 50 | #include <cmath> | 51 | #include <cmath> |
427 | 51 | 52 | ||
428 | 53 | #define EZOOM_SCREEN_BORDER_OFFSET 0.92 | ||
429 | 54 | |||
430 | 52 | enum SpecificZoomTarget | 55 | enum SpecificZoomTarget |
431 | 53 | { | 56 | { |
432 | 54 | ZoomTarget1 = 0, | 57 | ZoomTarget1 = 0, |
433 | @@ -169,16 +172,19 @@ | |||
434 | 169 | CompPoint mouse; // we get this from mousepoll | 172 | CompPoint mouse; // we get this from mousepoll |
435 | 170 | unsigned long int grabbed; | 173 | unsigned long int grabbed; |
436 | 171 | CompScreen::GrabHandle grabIndex; // for zoomBox | 174 | CompScreen::GrabHandle grabIndex; // for zoomBox |
438 | 172 | time_t lastChange; | 175 | time_t lastMouseChange; |
439 | 176 | time_t lastFocusChange; | ||
440 | 173 | CursorTexture cursor; // the texture for the faux-cursor | 177 | CursorTexture cursor; // the texture for the faux-cursor |
441 | 174 | // we paint to do fake input | 178 | // we paint to do fake input |
442 | 175 | // handling | 179 | // handling |
443 | 180 | bool nonMouseFocusTracking; | ||
444 | 176 | bool cursorInfoSelected; | 181 | bool cursorInfoSelected; |
445 | 177 | bool cursorHidden; | 182 | bool cursorHidden; |
446 | 178 | CompRect box; | 183 | CompRect box; |
447 | 179 | CompPoint clickPos; | 184 | CompPoint clickPos; |
448 | 180 | 185 | ||
450 | 181 | MousePoller pollHandle; // mouse poller object | 186 | MousePoller pollMouseHandle; // mouse poller object |
451 | 187 | FocusPoller pollFocusHandle; // focus poller object | ||
452 | 182 | 188 | ||
453 | 183 | private: | 189 | private: |
454 | 184 | 190 | ||
455 | @@ -231,6 +237,11 @@ | |||
456 | 231 | setCenter (int x, | 237 | setCenter (int x, |
457 | 232 | int y, | 238 | int y, |
458 | 233 | bool instant); | 239 | bool instant); |
459 | 240 | void | ||
460 | 241 | setCenter (int x, | ||
461 | 242 | int y, | ||
462 | 243 | bool instant, | ||
463 | 244 | bool center); | ||
464 | 234 | 245 | ||
465 | 235 | void | 246 | void |
466 | 236 | setZoomArea (int x, | 247 | setZoomArea (int x, |
467 | @@ -250,6 +261,9 @@ | |||
468 | 250 | enableMousePolling (); | 261 | enableMousePolling (); |
469 | 251 | 262 | ||
470 | 252 | void | 263 | void |
471 | 264 | enableFocusPolling (); | ||
472 | 265 | |||
473 | 266 | void | ||
474 | 253 | setScale (int out, | 267 | setScale (int out, |
475 | 254 | float value); | 268 | float value); |
476 | 255 | 269 | ||
477 | @@ -295,6 +309,12 @@ | |||
478 | 295 | void | 309 | void |
479 | 296 | updateMouseInterval (const CompPoint &p); | 310 | updateMouseInterval (const CompPoint &p); |
480 | 297 | 311 | ||
481 | 312 | void | ||
482 | 313 | updateFocusPosition (const CompRect &retc); | ||
483 | 314 | |||
484 | 315 | void | ||
485 | 316 | updateFocusInterval (const CompRect &rect); | ||
486 | 317 | |||
487 | 298 | /* Make dtor */ | 318 | /* Make dtor */ |
488 | 299 | void | 319 | void |
489 | 300 | freeCursor (CursorTexture * cursor); | 320 | freeCursor (CursorTexture * cursor); |
490 | 301 | 321 | ||
491 | === added directory 'plugins/focuspoll' | |||
492 | === added file 'plugins/focuspoll/CMakeLists.txt' | |||
493 | --- plugins/focuspoll/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
494 | +++ plugins/focuspoll/CMakeLists.txt 2017-04-28 09:59:04 +0000 | |||
495 | @@ -0,0 +1,9 @@ | |||
496 | 1 | find_package (Compiz REQUIRED) | ||
497 | 2 | |||
498 | 3 | include (CompizPlugin) | ||
499 | 4 | include_directories (include/accessibilitywatcher) | ||
500 | 5 | |||
501 | 6 | pkg_search_module( ATSPI REQUIRED atspi-2 ) | ||
502 | 7 | |||
503 | 8 | compiz_plugin (focuspoll PKGDEPS atspi-2 ) | ||
504 | 9 | |||
505 | 0 | 10 | ||
506 | === added file 'plugins/focuspoll/compiz-focuspoll.pc.in' | |||
507 | --- plugins/focuspoll/compiz-focuspoll.pc.in 1970-01-01 00:00:00 +0000 | |||
508 | +++ plugins/focuspoll/compiz-focuspoll.pc.in 2017-04-28 09:59:04 +0000 | |||
509 | @@ -0,0 +1,12 @@ | |||
510 | 1 | prefix=@prefix@ | ||
511 | 2 | exec_prefix=@exec_prefix@ | ||
512 | 3 | libdir=@libdir@ | ||
513 | 4 | includedir=@includedir@ | ||
514 | 5 | |||
515 | 6 | Name: compiz-focuspoll | ||
516 | 7 | Description: Focuspoll plugin for compiz | ||
517 | 8 | Version: @VERSION@ | ||
518 | 9 | |||
519 | 10 | Requires: compiz | ||
520 | 11 | Libs: -L${libdir}/compiz -lfocuspoll | ||
521 | 12 | Cflags: @COMPIZ_CFLAGS@ -I${includedir}/compiz | ||
522 | 0 | 13 | ||
523 | === added file 'plugins/focuspoll/focuspoll.xml.in' | |||
524 | --- plugins/focuspoll/focuspoll.xml.in 1970-01-01 00:00:00 +0000 | |||
525 | +++ plugins/focuspoll/focuspoll.xml.in 2017-04-28 09:59:04 +0000 | |||
526 | @@ -0,0 +1,34 @@ | |||
527 | 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
528 | 2 | <compiz> | ||
529 | 3 | <plugin name="focuspoll" useBcop="true"> | ||
530 | 4 | <_short>Focus position polling</_short> | ||
531 | 5 | <_long>Updates the focus pointer position from the accessibility library AT-SPI through dbus</_long> | ||
532 | 6 | <category>Utility</category> | ||
533 | 7 | <options> | ||
534 | 8 | <_short>Misc</_short> | ||
535 | 9 | <option type="bool" name="track_components"> | ||
536 | 10 | <_short>track movement of components (like a menu, label, or button)</_short> | ||
537 | 11 | <_long>if enabled, focuspoll will track the movements of every component able to provide focus.</_long> | ||
538 | 12 | <default>true</default> | ||
539 | 13 | </option> | ||
540 | 14 | <option type="bool" name="track_caret"> | ||
541 | 15 | <_short>track movement of the caret (the cursor in text)</_short> | ||
542 | 16 | <_long>if enabled, focuspoll will track the movements of the caret.</_long> | ||
543 | 17 | <default>true</default> | ||
544 | 18 | </option> | ||
545 | 19 | <option type="bool" name="ignore_links"> | ||
546 | 20 | <_short>ignores link focuses</_short> | ||
547 | 21 | <_long>if enabled, focuspoll will not track the focus events of link items</_long> | ||
548 | 22 | <default>true</default> | ||
549 | 23 | </option> | ||
550 | 24 | <option type="int" name="focus_poll_interval"> | ||
551 | 25 | <_short>Focus Poll Interval</_short> | ||
552 | 26 | <_long>How often to poll DBus for focus changes, in milliseconds. Reduce this to reduce choppy behavior.</_long> | ||
553 | 27 | <default>10</default> | ||
554 | 28 | <min>1</min> | ||
555 | 29 | <max>500</max> | ||
556 | 30 | </option> | ||
557 | 31 | </options> | ||
558 | 32 | </plugin> | ||
559 | 33 | </compiz> | ||
560 | 34 | |||
561 | 0 | 35 | ||
562 | === added directory 'plugins/focuspoll/include' | |||
563 | === added directory 'plugins/focuspoll/include/accessibilitywatcher' | |||
564 | === added file 'plugins/focuspoll/include/accessibilitywatcher/accessibilitywatcher.h' | |||
565 | --- plugins/focuspoll/include/accessibilitywatcher/accessibilitywatcher.h 1970-01-01 00:00:00 +0000 | |||
566 | +++ plugins/focuspoll/include/accessibilitywatcher/accessibilitywatcher.h 2017-04-28 09:59:04 +0000 | |||
567 | @@ -0,0 +1,82 @@ | |||
568 | 1 | /* | ||
569 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
570 | 3 | * | ||
571 | 4 | * This file is part of compiz. | ||
572 | 5 | * | ||
573 | 6 | * this program is free software: you can redistribute it and/or modify | ||
574 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
575 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
576 | 9 | * later version. | ||
577 | 10 | * | ||
578 | 11 | * This program is distributed in the hope that it will be useful, but | ||
579 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
580 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
581 | 14 | * details. | ||
582 | 15 | * | ||
583 | 16 | * You should have received a copy of the GNU General Public License along | ||
584 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
585 | 18 | */ | ||
586 | 19 | |||
587 | 20 | #ifndef ACCESSIBILITY_WATCHER_H | ||
588 | 21 | #define ACCESSIBILITY_WATCHER_H | ||
589 | 22 | |||
590 | 23 | #include <deque> | ||
591 | 24 | #include <vector> | ||
592 | 25 | |||
593 | 26 | #include "focusinfo.h" | ||
594 | 27 | |||
595 | 28 | #include <atspi/atspi.h> | ||
596 | 29 | |||
597 | 30 | class AccessibilityWatcher { | ||
598 | 31 | public: | ||
599 | 32 | ~AccessibilityWatcher(); | ||
600 | 33 | static AccessibilityWatcher* getInstance(); | ||
601 | 34 | |||
602 | 35 | void init(); | ||
603 | 36 | void quit(); | ||
604 | 37 | |||
605 | 38 | void setIgnoreLinks(bool); | ||
606 | 39 | void setScreenLimits(int, int); | ||
607 | 40 | int getScreenWidth(); | ||
608 | 41 | int getScreenHeight(); | ||
609 | 42 | |||
610 | 43 | std::deque<FocusInfo> getFocusQueue(); | ||
611 | 44 | void resetFocusQueue(); | ||
612 | 45 | bool returnToPrevMenu(); | ||
613 | 46 | |||
614 | 47 | private: | ||
615 | 48 | AccessibilityWatcher(); | ||
616 | 49 | static AccessibilityWatcher* instance; | ||
617 | 50 | |||
618 | 51 | bool initialized; | ||
619 | 52 | int screenWidth; | ||
620 | 53 | int screenHeight; | ||
621 | 54 | static bool ignoreLinks; | ||
622 | 55 | std::deque<FocusInfo> focusList; | ||
623 | 56 | std::vector<FocusInfo> previouslyActiveMenus; | ||
624 | 57 | |||
625 | 58 | AtspiEventListener *focusListener; | ||
626 | 59 | AtspiEventListener *caretMoveListener; | ||
627 | 60 | AtspiEventListener *selectedListener; | ||
628 | 61 | AtspiEventListener *descendantChangedListener; | ||
629 | 62 | |||
630 | 63 | void addWatches(); | ||
631 | 64 | void removeWatches(); | ||
632 | 65 | |||
633 | 66 | static std::string getLabel(AtspiAccessible *accessible); | ||
634 | 67 | const static gchar* atspiStateGetName (gint state); | ||
635 | 68 | static std::string getStateSet (AtspiAccessible *accessible); | ||
636 | 69 | |||
637 | 70 | static void registerEvent(const AtspiEvent *event, const std::string& type); | ||
638 | 71 | static bool appSpecificFilter(FocusInfo& focusInfo, const AtspiEvent* event); | ||
639 | 72 | static bool filterBadEvents(const FocusInfo& event); | ||
640 | 73 | static void getAlternativeCaret(FocusInfo& focus, const AtspiEvent* event); | ||
641 | 74 | |||
642 | 75 | static void onFocus(const AtspiEvent *event, void *data); | ||
643 | 76 | static void onSelectedChange(const AtspiEvent *event, void *data); | ||
644 | 77 | static void onCaretMove(const AtspiEvent *event, void *data); | ||
645 | 78 | static void onDescendantChanged(const AtspiEvent *event, void *data); | ||
646 | 79 | |||
647 | 80 | }; | ||
648 | 81 | |||
649 | 82 | #endif | ||
650 | 0 | 83 | ||
651 | === added file 'plugins/focuspoll/include/accessibilitywatcher/focusinfo.h' | |||
652 | --- plugins/focuspoll/include/accessibilitywatcher/focusinfo.h 1970-01-01 00:00:00 +0000 | |||
653 | +++ plugins/focuspoll/include/accessibilitywatcher/focusinfo.h 2017-04-28 09:59:04 +0000 | |||
654 | @@ -0,0 +1,76 @@ | |||
655 | 1 | /* | ||
656 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
657 | 3 | * | ||
658 | 4 | * This file is part of compiz. | ||
659 | 5 | * | ||
660 | 6 | * this program is free software: you can redistribute it and/or modify | ||
661 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
662 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
663 | 9 | * later version. | ||
664 | 10 | * | ||
665 | 11 | * This program is distributed in the hope that it will be useful, but | ||
666 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
667 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
668 | 14 | * details. | ||
669 | 15 | * | ||
670 | 16 | * You should have received a copy of the GNU General Public License along | ||
671 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
672 | 18 | */ | ||
673 | 19 | |||
674 | 20 | #ifndef FOCUS_INFO_H | ||
675 | 21 | #define FOCUS_INFO_H | ||
676 | 22 | |||
677 | 23 | #include <tuple> | ||
678 | 24 | #include <string> | ||
679 | 25 | #include <sstream> | ||
680 | 26 | |||
681 | 27 | |||
682 | 28 | class FocusInfo { | ||
683 | 29 | public: | ||
684 | 30 | |||
685 | 31 | FocusInfo(const std::string& type, | ||
686 | 32 | const std::string& name, | ||
687 | 33 | const std::string& label, | ||
688 | 34 | const std::string& role, | ||
689 | 35 | const std::string& application, | ||
690 | 36 | int x, | ||
691 | 37 | int y, | ||
692 | 38 | int width, | ||
693 | 39 | int height); | ||
694 | 40 | |||
695 | 41 | FocusInfo(const std::string& type, | ||
696 | 42 | const std::string& name, | ||
697 | 43 | const std::string& label, | ||
698 | 44 | const std::string& role, | ||
699 | 45 | const std::string& application); | ||
700 | 46 | |||
701 | 47 | FocusInfo(); | ||
702 | 48 | |||
703 | 49 | int x, y, w, h; | ||
704 | 50 | int xAlt, yAlt, wAlt, hAlt; | ||
705 | 51 | std::string type; | ||
706 | 52 | std::string name; | ||
707 | 53 | std::string label; | ||
708 | 54 | std::string role; | ||
709 | 55 | std::string application; | ||
710 | 56 | |||
711 | 57 | // AT-SPI events that are interesting to know about the event | ||
712 | 58 | bool enabled; | ||
713 | 59 | bool active; | ||
714 | 60 | bool focusable; | ||
715 | 61 | bool focused; | ||
716 | 62 | bool selected; | ||
717 | 63 | bool showing; | ||
718 | 64 | bool visible; | ||
719 | 65 | |||
720 | 66 | std::string getType(); | ||
721 | 67 | std::string summary(); | ||
722 | 68 | std::tuple<int, int> getPosition(); | ||
723 | 69 | std::tuple<int, int> getSize(); | ||
724 | 70 | std::tuple<int, int, int, int> getBBox(); | ||
725 | 71 | |||
726 | 72 | bool operator== (const FocusInfo& other) const; | ||
727 | 73 | bool operator!= (const FocusInfo& other) const; | ||
728 | 74 | }; | ||
729 | 75 | |||
730 | 76 | #endif | ||
731 | 0 | 77 | ||
732 | === added directory 'plugins/focuspoll/include/focuspoll' | |||
733 | === added file 'plugins/focuspoll/include/focuspoll/focuspoll.h' | |||
734 | --- plugins/focuspoll/include/focuspoll/focuspoll.h 1970-01-01 00:00:00 +0000 | |||
735 | +++ plugins/focuspoll/include/focuspoll/focuspoll.h 2017-04-28 09:59:04 +0000 | |||
736 | @@ -0,0 +1,50 @@ | |||
737 | 1 | /* | ||
738 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
739 | 3 | * | ||
740 | 4 | * This file is part of compiz. | ||
741 | 5 | * | ||
742 | 6 | * this program is free software: you can redistribute it and/or modify | ||
743 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
744 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
745 | 9 | * later version. | ||
746 | 10 | * | ||
747 | 11 | * This program is distributed in the hope that it will be useful, but | ||
748 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
749 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
750 | 14 | * details. | ||
751 | 15 | * | ||
752 | 16 | * You should have received a copy of the GNU General Public License along | ||
753 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
754 | 18 | */ | ||
755 | 19 | |||
756 | 20 | #ifndef _COMPIZ_FOCUSPOLL_H | ||
757 | 21 | #define _COMPIZ_FOCUSPOLL_H | ||
758 | 22 | |||
759 | 23 | #define COMPIZ_FOCUSPOLL_ABI 1 | ||
760 | 24 | |||
761 | 25 | #include <boost/function.hpp> | ||
762 | 26 | #include <core/rect.h> | ||
763 | 27 | #include <accessibilitywatcher/focusinfo.h> | ||
764 | 28 | |||
765 | 29 | class FocusPoller | ||
766 | 30 | { | ||
767 | 31 | public: | ||
768 | 32 | typedef boost::function<void(const CompRect &)> CallBack; | ||
769 | 33 | |||
770 | 34 | FocusPoller (); | ||
771 | 35 | ~FocusPoller (); | ||
772 | 36 | |||
773 | 37 | void setCallback (CallBack callback); | ||
774 | 38 | void start (); | ||
775 | 39 | void stop (); | ||
776 | 40 | bool active (); | ||
777 | 41 | |||
778 | 42 | private: | ||
779 | 43 | bool mActive; | ||
780 | 44 | CallBack mCallback; | ||
781 | 45 | CompRect focusRect; | ||
782 | 46 | |||
783 | 47 | friend class FocuspollScreen; | ||
784 | 48 | }; | ||
785 | 49 | |||
786 | 50 | #endif | ||
787 | 0 | 51 | ||
788 | === added directory 'plugins/focuspoll/src' | |||
789 | === added file 'plugins/focuspoll/src/accessibilitywatcher.cpp' | |||
790 | --- plugins/focuspoll/src/accessibilitywatcher.cpp 1970-01-01 00:00:00 +0000 | |||
791 | +++ plugins/focuspoll/src/accessibilitywatcher.cpp 2017-04-28 09:59:04 +0000 | |||
792 | @@ -0,0 +1,506 @@ | |||
793 | 1 | /* | ||
794 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
795 | 3 | * | ||
796 | 4 | * This file is part of compiz. | ||
797 | 5 | * | ||
798 | 6 | * this program is free software: you can redistribute it and/or modify | ||
799 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
800 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
801 | 9 | * later version. | ||
802 | 10 | * | ||
803 | 11 | * This program is distributed in the hope that it will be useful, but | ||
804 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
805 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
806 | 14 | * details. | ||
807 | 15 | * | ||
808 | 16 | * You should have received a copy of the GNU General Public License along | ||
809 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
810 | 18 | */ | ||
811 | 19 | |||
812 | 20 | #include <iostream> | ||
813 | 21 | #include <functional> | ||
814 | 22 | |||
815 | 23 | #include <boost/mem_fn.hpp> | ||
816 | 24 | #include <boost/bind.hpp> | ||
817 | 25 | #include <boost/function.hpp> | ||
818 | 26 | |||
819 | 27 | #include <string.h> | ||
820 | 28 | #include <stdlib.h> | ||
821 | 29 | #include <unistd.h> | ||
822 | 30 | |||
823 | 31 | #include "accessibilitywatcher.h" | ||
824 | 32 | |||
825 | 33 | namespace { | ||
826 | 34 | const int A11YWATCHER_MAX_CARET_WIDTH = 50; | ||
827 | 35 | const int A11YWATCHER_MAX_CARET_HEIGHT = 70; | ||
828 | 36 | } | ||
829 | 37 | |||
830 | 38 | AccessibilityWatcher* AccessibilityWatcher::instance = NULL; | ||
831 | 39 | bool AccessibilityWatcher::ignoreLinks = false; | ||
832 | 40 | |||
833 | 41 | AccessibilityWatcher::AccessibilityWatcher() : | ||
834 | 42 | initialized(false), | ||
835 | 43 | screenWidth(0), | ||
836 | 44 | screenHeight(0) | ||
837 | 45 | { | ||
838 | 46 | } | ||
839 | 47 | |||
840 | 48 | AccessibilityWatcher::~AccessibilityWatcher() { | ||
841 | 49 | quit(); | ||
842 | 50 | }; | ||
843 | 51 | |||
844 | 52 | AccessibilityWatcher *AccessibilityWatcher::getInstance () { | ||
845 | 53 | if (instance == NULL) | ||
846 | 54 | { | ||
847 | 55 | instance = new AccessibilityWatcher(); | ||
848 | 56 | } | ||
849 | 57 | return instance; | ||
850 | 58 | } | ||
851 | 59 | |||
852 | 60 | std::string AccessibilityWatcher::getLabel(AtspiAccessible *accessible) { | ||
853 | 61 | GArray *relations = atspi_accessible_get_relation_set (accessible, NULL); | ||
854 | 62 | if (relations == NULL) | ||
855 | 63 | { | ||
856 | 64 | return ""; | ||
857 | 65 | } | ||
858 | 66 | |||
859 | 67 | AtspiRelation *relation; | ||
860 | 68 | for (unsigned i = 0; i < relations->len; ++i) { | ||
861 | 69 | relation = g_array_index (relations, AtspiRelation*, i); | ||
862 | 70 | if (atspi_relation_get_relation_type (relation) == ATSPI_RELATION_LABELLED_BY) | ||
863 | 71 | { | ||
864 | 72 | g_array_free (relations, true); | ||
865 | 73 | g_object_unref(relations); | ||
866 | 74 | auto res_label = atspi_accessible_get_name(atspi_relation_get_target(relation, 0), NULL); | ||
867 | 75 | g_object_unref(relation); | ||
868 | 76 | return (res_label == NULL) ? "" : res_label; | ||
869 | 77 | } | ||
870 | 78 | } | ||
871 | 79 | if (relations->len > 0) | ||
872 | 80 | { | ||
873 | 81 | g_object_unref(relations); | ||
874 | 82 | } | ||
875 | 83 | return ""; | ||
876 | 84 | } | ||
877 | 85 | |||
878 | 86 | void AccessibilityWatcher::setIgnoreLinks(bool val) { | ||
879 | 87 | ignoreLinks = val; | ||
880 | 88 | } | ||
881 | 89 | |||
882 | 90 | void AccessibilityWatcher::setScreenLimits(int x, int y) { | ||
883 | 91 | screenWidth = x; | ||
884 | 92 | screenHeight = y; | ||
885 | 93 | } | ||
886 | 94 | |||
887 | 95 | int AccessibilityWatcher::getScreenWidth () { | ||
888 | 96 | return screenWidth; | ||
889 | 97 | } | ||
890 | 98 | |||
891 | 99 | int AccessibilityWatcher::getScreenHeight () { | ||
892 | 100 | return screenHeight; | ||
893 | 101 | } | ||
894 | 102 | |||
895 | 103 | void AccessibilityWatcher::registerEvent(const AtspiEvent *event, const std::string &type) { | ||
896 | 104 | // type is registered from filter on calling event | ||
897 | 105 | FocusInfo res(type, | ||
898 | 106 | atspi_accessible_get_name (event->source, NULL), | ||
899 | 107 | getLabel (event->source), | ||
900 | 108 | atspi_accessible_get_role_name (event->source, NULL), | ||
901 | 109 | atspi_accessible_get_name(atspi_accessible_get_application (event->source, NULL), NULL)); | ||
902 | 110 | |||
903 | 111 | if (!res.active) | ||
904 | 112 | { | ||
905 | 113 | // prevents skipping events that are not designated as active. we check the parent. | ||
906 | 114 | auto parent = atspi_accessible_get_parent(event->source, NULL); | ||
907 | 115 | while (!res.active && parent) { | ||
908 | 116 | auto stateSet = atspi_accessible_get_state_set (child); | ||
909 | 117 | if (atspi_state_set_contains(stateSet, ATSPI_STATE_ACTIVE)) | ||
910 | 118 | { | ||
911 | 119 | res.active = true; | ||
912 | 120 | } | ||
913 | 121 | g_object_unref(stateSet); | ||
914 | 122 | g_object_unref(parent); | ||
915 | 123 | child = atspi_accessible_get_parent(child, NULL); | ||
916 | 124 | } | ||
917 | 125 | g_object_unref(parent); | ||
918 | 126 | } | ||
919 | 127 | |||
920 | 128 | AtspiComponent* component; | ||
921 | 129 | if (res.type == "active-descendant-changed") | ||
922 | 130 | { | ||
923 | 131 | auto accessible = atspi_accessible_get_child_at_index(event->source, event->detail1, NULL); | ||
924 | 132 | component = atspi_accessible_get_component(accessible); | ||
925 | 133 | g_object_unref(accessible); | ||
926 | 134 | } else { | ||
927 | 135 | component = atspi_accessible_get_component(event->source); | ||
928 | 136 | } | ||
929 | 137 | |||
930 | 138 | if (component) | ||
931 | 139 | { | ||
932 | 140 | AtspiRect* size = atspi_component_get_extents(component, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
933 | 141 | res.x = size->x; | ||
934 | 142 | res.y = size->y; | ||
935 | 143 | res.w = size->width; | ||
936 | 144 | res.h = size->height; | ||
937 | 145 | g_object_unref(component); | ||
938 | 146 | } | ||
939 | 147 | // let's get the caret offset, and then its position for a caret event | ||
940 | 148 | if (type == "caret") | ||
941 | 149 | { | ||
942 | 150 | auto text = atspi_accessible_get_text(event->source); | ||
943 | 151 | if (!text) | ||
944 | 152 | { | ||
945 | 153 | return; | ||
946 | 154 | } | ||
947 | 155 | auto offset = atspi_text_get_caret_offset(text, NULL); | ||
948 | 156 | // if we're at the beginning of text, let the widget pos decide | ||
949 | 157 | if (event->detail1) | ||
950 | 158 | { | ||
951 | 159 | AtspiRect *size = atspi_text_get_character_extents(text, offset, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
952 | 160 | res.x = size->x; | ||
953 | 161 | res.y = size->y; | ||
954 | 162 | res.w = size->width; | ||
955 | 163 | res.h = size->height; | ||
956 | 164 | } | ||
957 | 165 | // correcting a missing offset to a caret move event in firefox | ||
958 | 166 | if (res.x == 0 && res.y == 0 && offset > 0) | ||
959 | 167 | { | ||
960 | 168 | AtspiRect *size = atspi_text_get_character_extents(text, offset-1, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
961 | 169 | res.x = size->x; | ||
962 | 170 | res.y = size->y; | ||
963 | 171 | res.w = size->width; | ||
964 | 172 | res.h = size->height; | ||
965 | 173 | } | ||
966 | 174 | // when result is obviously not a caret size | ||
967 | 175 | if (strcmp(event->type, "object:text-caret-moved") == 0 && (res.w > A11YWATCHER_MAX_CARET_WIDTH || res.h > A11YWATCHER_MAX_CARET_HEIGHT)) | ||
968 | 176 | { | ||
969 | 177 | AtspiRect *size = atspi_text_get_character_extents(text, offset, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
970 | 178 | res.x = size->x; | ||
971 | 179 | res.y = size->y; | ||
972 | 180 | res.w = size->width; | ||
973 | 181 | res.h = size->height; | ||
974 | 182 | if (type == "caret" && strcmp(event->type, "object:text-caret-moved") == 0 && (res.w > A11YWATCHER_MAX_CARET_WIDTH || res.h > A11YWATCHER_MAX_CARET_HEIGHT)) | ||
975 | 183 | { | ||
976 | 184 | res.x = 0; | ||
977 | 185 | res.y = 0; | ||
978 | 186 | } | ||
979 | 187 | } | ||
980 | 188 | g_object_unref(text); | ||
981 | 189 | |||
982 | 190 | // still no offset, it's probably a newline and we're at bugzilla #1319273 (with new paragraph obj) | ||
983 | 191 | if (res.x == 0 && res.y == 0 && | ||
984 | 192 | (strcmp(event->type, "object:text-changed:insert") == 0 || | ||
985 | 193 | strcmp(event->type, "object:text-changed:removed") == 0 || | ||
986 | 194 | strcmp(event->type, "object:text-caret-moved") == 0)) { | ||
987 | 195 | res.x = res.xAlt; | ||
988 | 196 | res.y = res.yAlt; | ||
989 | 197 | res.w = res.wAlt; | ||
990 | 198 | res.h = res.hAlt; | ||
991 | 199 | } | ||
992 | 200 | } | ||
993 | 201 | |||
994 | 202 | // getting the states on event | ||
995 | 203 | auto stateSet = atspi_accessible_get_state_set (event->source); | ||
996 | 204 | if (atspi_state_set_contains(stateSet, ATSPI_STATE_FOCUSED)) | ||
997 | 205 | { | ||
998 | 206 | res.focused = true; | ||
999 | 207 | AccessibilityWatcher::getInstance()->previouslyActiveMenus.clear(); // reset potential menu stack | ||
1000 | 208 | } | ||
1001 | 209 | if (atspi_state_set_contains(stateSet, ATSPI_STATE_SELECTED)) | ||
1002 | 210 | { // never works, GTK Bad implem? | ||
1003 | 211 | res.selected = true; | ||
1004 | 212 | } | ||
1005 | 213 | if (res.type == "state-changed:selected" && event->detail1 == 1) | ||
1006 | 214 | { | ||
1007 | 215 | res.selected = true; | ||
1008 | 216 | AccessibilityWatcher::getInstance()->previouslyActiveMenus.push_back(res); // add to stack of menus | ||
1009 | 217 | } | ||
1010 | 218 | |||
1011 | 219 | if (appSpecificFilter(res, event)) | ||
1012 | 220 | { | ||
1013 | 221 | return; | ||
1014 | 222 | } | ||
1015 | 223 | if (filterBadEvents(res)) | ||
1016 | 224 | { | ||
1017 | 225 | return; | ||
1018 | 226 | } | ||
1019 | 227 | while (AccessibilityWatcher::getInstance()->focusList.size() >= 5) { // don't keep the whole history | ||
1020 | 228 | AccessibilityWatcher::getInstance()->focusList.erase(AccessibilityWatcher::getInstance()->focusList.begin()); | ||
1021 | 229 | } | ||
1022 | 230 | AccessibilityWatcher::getInstance()->focusList.push_back(res); | ||
1023 | 231 | } | ||
1024 | 232 | |||
1025 | 233 | bool AccessibilityWatcher::appSpecificFilter(FocusInfo& focus, const AtspiEvent* event) | ||
1026 | 234 | { | ||
1027 | 235 | if (focus.type == "state-changed:selected" && // emulates on-change:selected false behaviour. eg: for menus | ||
1028 | 236 | (focus.role == "menu item" || | ||
1029 | 237 | focus.role == "menu" || | ||
1030 | 238 | focus.role == "check menu item" || | ||
1031 | 239 | focus.role == "radio menu item") && | ||
1032 | 240 | focus.application != "mate-panel") | ||
1033 | 241 | { | ||
1034 | 242 | if (!focus.selected && AccessibilityWatcher::getInstance()->returnToPrevMenu()) | ||
1035 | 243 | { | ||
1036 | 244 | return true; | ||
1037 | 245 | } | ||
1038 | 246 | focus.active = true; | ||
1039 | 247 | } | ||
1040 | 248 | if (focus.application == "soffice" && focus.role == "paragraph") | ||
1041 | 249 | { // LO-calc: avoid spam event from main edit line | ||
1042 | 250 | auto parent = atspi_accessible_get_parent(event->source, NULL); | ||
1043 | 251 | std::string parentLabel = atspi_accessible_get_name(parent, NULL); | ||
1044 | 252 | if (parentLabel == "Input line" || | ||
1045 | 253 | parentLabel == "Ligne de saisie") { | ||
1046 | 254 | return true; | ||
1047 | 255 | } | ||
1048 | 256 | } | ||
1049 | 257 | if (focus.application == "Icedove" || focus.application == "Thunderbird") | ||
1050 | 258 | { | ||
1051 | 259 | if (focus.type == "caret") | ||
1052 | 260 | { | ||
1053 | 261 | auto text = atspi_accessible_get_text(event->source); // next if deals with a special newline char, that remained buggy. hypra issue #430 | ||
1054 | 262 | auto offset = atspi_text_get_caret_offset(text, NULL); | ||
1055 | 263 | auto string = std::string(atspi_text_get_text_at_offset(text, offset, ATSPI_TEXT_BOUNDARY_CHAR, NULL)->content); | ||
1056 | 264 | auto stringM1 = std::string(atspi_text_get_text_at_offset(text, offset -1, ATSPI_TEXT_BOUNDARY_CHAR, NULL)->content); | ||
1057 | 265 | if (offset == atspi_text_get_character_count(text, NULL) && string == "\0" && (stringM1 == "\n" || int(stringM1.c_str()[0]) == -17)) | ||
1058 | 266 | { | ||
1059 | 267 | getAlternativeCaret(focus, event); | ||
1060 | 268 | focus.x = focus.xAlt; | ||
1061 | 269 | focus.y = focus.yAlt + focus.hAlt; | ||
1062 | 270 | focus.w = focus.wAlt; | ||
1063 | 271 | focus.h = focus.hAlt; | ||
1064 | 272 | } | ||
1065 | 273 | if (!(focus.x == 0 && focus.y == 0)) | ||
1066 | 274 | { // prevents compose window loss of tracking in HTML mode (active flag ok, but no focused flag) | ||
1067 | 275 | AccessibilityWatcher::getInstance()->focusList.push_back(focus); | ||
1068 | 276 | return true; | ||
1069 | 277 | } | ||
1070 | 278 | auto component = atspi_accessible_get_component(event->source); | ||
1071 | 279 | if (component) | ||
1072 | 280 | { | ||
1073 | 281 | AtspiRect* size = atspi_component_get_extents(component, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
1074 | 282 | focus.x = size->x; | ||
1075 | 283 | focus.y = size->y; | ||
1076 | 284 | focus.w = 7; | ||
1077 | 285 | focus.h = size->height; | ||
1078 | 286 | AccessibilityWatcher::getInstance()->focusList.push_back(focus); | ||
1079 | 287 | return true; | ||
1080 | 288 | } | ||
1081 | 289 | } | ||
1082 | 290 | } | ||
1083 | 291 | if (focus.application == "Firefox") | ||
1084 | 292 | { | ||
1085 | 293 | if (ignoreLinks && focus.type != "caret" && focus.role == "link") | ||
1086 | 294 | { | ||
1087 | 295 | return true; | ||
1088 | 296 | } | ||
1089 | 297 | if (focus.type == "caret" && | ||
1090 | 298 | (static_cast<std::string>(event->type) == "object:text-changed:insert:system" || | ||
1091 | 299 | static_cast<std::string>(event->type) == "object:text-changed:delete:system")) { // prevents status bar focus in firefox | ||
1092 | 300 | return true; | ||
1093 | 301 | } | ||
1094 | 302 | if (focus.type == "focus" && focus.role == "document frame") | ||
1095 | 303 | { // general page parasite event | ||
1096 | 304 | return true; | ||
1097 | 305 | } | ||
1098 | 306 | if (focus.type == "caret" && !(focus.x == 0 && focus.y == 0)) | ||
1099 | 307 | { | ||
1100 | 308 | AccessibilityWatcher::getInstance()->focusList.push_back(focus); | ||
1101 | 309 | return true; | ||
1102 | 310 | } | ||
1103 | 311 | getAlternativeCaret(focus, event); | ||
1104 | 312 | if (focus.type == "caret" && !(focus.xAlt == 0 && focus.yAlt == 0)) | ||
1105 | 313 | { | ||
1106 | 314 | focus.x = focus.xAlt; | ||
1107 | 315 | focus.y = focus.yAlt + focus.hAlt; | ||
1108 | 316 | focus.w = focus.wAlt; | ||
1109 | 317 | focus.h = focus.hAlt; | ||
1110 | 318 | AccessibilityWatcher::getInstance()->focusList.push_back(focus); | ||
1111 | 319 | return true; | ||
1112 | 320 | } | ||
1113 | 321 | } | ||
1114 | 322 | if (focus.application == "evince" && focus.type == "state-changed:selected" && focus.role == "icon") | ||
1115 | 323 | { // LO-calc: avoid spam event from main edit line | ||
1116 | 324 | return true; // ignores the parasite event from evince icon | ||
1117 | 325 | } | ||
1118 | 326 | return false; | ||
1119 | 327 | } | ||
1120 | 328 | |||
1121 | 329 | bool AccessibilityWatcher::filterBadEvents(const FocusInfo& event) { | ||
1122 | 330 | if (event.type == "caret" && event.x ==0 && event.y == 0) | ||
1123 | 331 | { | ||
1124 | 332 | return true; | ||
1125 | 333 | } | ||
1126 | 334 | if (!event.active) | ||
1127 | 335 | { | ||
1128 | 336 | return true; | ||
1129 | 337 | } | ||
1130 | 338 | if (!event.focused && !event.selected) | ||
1131 | 339 | { | ||
1132 | 340 | return true; | ||
1133 | 341 | } | ||
1134 | 342 | if (AccessibilityWatcher::getInstance()->getScreenWidth() != 0 && AccessibilityWatcher::getInstance()->getScreenHeight() !=0 && | ||
1135 | 343 | (event.x > AccessibilityWatcher::getInstance()->getScreenWidth() || | ||
1136 | 344 | event.y > AccessibilityWatcher::getInstance()->getScreenHeight() || // TODO remove when non-singleton | ||
1137 | 345 | event.x < 0 || | ||
1138 | 346 | event.y < 0 )) { | ||
1139 | 347 | return true; | ||
1140 | 348 | } | ||
1141 | 349 | return false; | ||
1142 | 350 | } | ||
1143 | 351 | |||
1144 | 352 | /* | ||
1145 | 353 | * this is meant to emulate the missing "selected" argument in menu hierarchy. | ||
1146 | 354 | * no idea whether this is a fail in GTK, or in ATSPI | ||
1147 | 355 | */ | ||
1148 | 356 | bool AccessibilityWatcher::returnToPrevMenu() { | ||
1149 | 357 | if (previouslyActiveMenus.size() > 1) | ||
1150 | 358 | { | ||
1151 | 359 | previouslyActiveMenus.pop_back(); | ||
1152 | 360 | focusList.push_back(previouslyActiveMenus.back()); | ||
1153 | 361 | return true; | ||
1154 | 362 | } | ||
1155 | 363 | return false; | ||
1156 | 364 | } | ||
1157 | 365 | |||
1158 | 366 | /* | ||
1159 | 367 | * Tries to extrapolate a missing caret position from other text characters. | ||
1160 | 368 | * is used as last resort when application doesn't respect at-spi standarts, | ||
1161 | 369 | * or at-spi bugs. | ||
1162 | 370 | */ | ||
1163 | 371 | void AccessibilityWatcher::getAlternativeCaret(FocusInfo& focus, const AtspiEvent* event) { | ||
1164 | 372 | auto text = atspi_accessible_get_text(event->source); | ||
1165 | 373 | if (!text) { return; } | ||
1166 | 374 | auto offset = atspi_text_get_caret_offset(text, NULL); | ||
1167 | 375 | auto caretChar = std::string(atspi_text_get_string_at_offset(text, offset, ATSPI_TEXT_GRANULARITY_CHAR, NULL)->content); | ||
1168 | 376 | bool hasSeenDeviceControl1 = false; | ||
1169 | 377 | |||
1170 | 378 | // if we're at a newline, sometimes at-spi isn't giving us a caret position. unknown bug in some apps. | ||
1171 | 379 | if (caretChar == "\n" || caretChar == "\0") | ||
1172 | 380 | { | ||
1173 | 381 | // gives the last empty line the right focus. | ||
1174 | 382 | int lines = atspi_text_get_character_count(text, NULL) == offset ? 1 : 0; | ||
1175 | 383 | int charIndex = 1; | ||
1176 | 384 | bool charExtentsFound = false; | ||
1177 | 385 | |||
1178 | 386 | AtspiRect *size = atspi_text_get_character_extents(text, offset, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
1179 | 387 | // try and find the character on upper line to extrapolate position from. no more that 300 char, we risk lag. | ||
1180 | 388 | while (!charExtentsFound && charIndex <= offset && charIndex < 300) { | ||
1181 | 389 | size = atspi_text_get_character_extents(text, offset - charIndex, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
1182 | 390 | caretChar = atspi_text_get_string_at_offset(text, offset - charIndex, ATSPI_TEXT_GRANULARITY_CHAR, NULL)->content; | ||
1183 | 391 | // if we found a caret, check we're at beginning of line (or of text) to extrapolate position | ||
1184 | 392 | if ((size->x != 0 || size->y != 0) && int(caretChar[0]) != -17) | ||
1185 | 393 | { | ||
1186 | 394 | if (offset - charIndex -1 >= 0 && std::string(atspi_text_get_string_at_offset(text, offset - charIndex -1, ATSPI_TEXT_GRANULARITY_CHAR, NULL)->content) == "\n") | ||
1187 | 395 | { | ||
1188 | 396 | charExtentsFound = true; // first character of upper line has been found | ||
1189 | 397 | } | ||
1190 | 398 | else if (offset - charIndex -1 == 0) | ||
1191 | 399 | { | ||
1192 | 400 | size = atspi_text_get_character_extents(text, 0, ATSPI_COORD_TYPE_SCREEN, NULL); | ||
1193 | 401 | // first character of upper line has been found | ||
1194 | 402 | charExtentsFound = true; | ||
1195 | 403 | } | ||
1196 | 404 | } | ||
1197 | 405 | else if (caretChar == "\n" || int(caretChar[0]) == -17) | ||
1198 | 406 | { | ||
1199 | 407 | ++lines; | ||
1200 | 408 | } | ||
1201 | 409 | if (!hasSeenDeviceControl1 && int(caretChar[0]) == -17 ) | ||
1202 | 410 | { | ||
1203 | 411 | hasSeenDeviceControl1 = true; | ||
1204 | 412 | } | ||
1205 | 413 | ++charIndex; | ||
1206 | 414 | } | ||
1207 | 415 | if (!hasSeenDeviceControl1) | ||
1208 | 416 | { | ||
1209 | 417 | lines--; | ||
1210 | 418 | } | ||
1211 | 419 | focus.xAlt = size->x; | ||
1212 | 420 | focus.yAlt = size->y + (lines-1) * size->height; | ||
1213 | 421 | focus.wAlt = size->width; | ||
1214 | 422 | focus.hAlt = size->height; | ||
1215 | 423 | } | ||
1216 | 424 | } | ||
1217 | 425 | |||
1218 | 426 | |||
1219 | 427 | void AccessibilityWatcher::onCaretMove (const AtspiEvent *event, void *data) { | ||
1220 | 428 | registerEvent(event, "caret"); | ||
1221 | 429 | } | ||
1222 | 430 | |||
1223 | 431 | void AccessibilityWatcher::onSelectedChange (const AtspiEvent *event, void *data) { | ||
1224 | 432 | registerEvent(event, "state-changed:selected"); | ||
1225 | 433 | } | ||
1226 | 434 | |||
1227 | 435 | void AccessibilityWatcher::onFocus (const AtspiEvent *event, void *data) { | ||
1228 | 436 | /* We only care about focus/selection gain | ||
1229 | 437 | * there's no detail1 on focus loss in AT-SPI specs */ | ||
1230 | 438 | if (!event->detail1) {return;} | ||
1231 | 439 | |||
1232 | 440 | registerEvent(event, "focus"); | ||
1233 | 441 | } | ||
1234 | 442 | |||
1235 | 443 | void AccessibilityWatcher::onDescendantChanged (const AtspiEvent *event, void *data) { | ||
1236 | 444 | registerEvent(event, "active-descendant-changed"); | ||
1237 | 445 | } | ||
1238 | 446 | |||
1239 | 447 | /* Register to events */ | ||
1240 | 448 | void AccessibilityWatcher::addWatches() { | ||
1241 | 449 | |||
1242 | 450 | //auto callback = boost::bind (&AccessibilityWatcher::onFocus, this, _1, _2); | ||
1243 | 451 | //auto bound_fn = boost::bind<void>( boost::mem_fn(&AccessibilityWatcher::onFocus), this, _1, _2); | ||
1244 | 452 | //auto bound_fn = boost::bind( &AccessibilityWatcher::onFocus, this, _1, _2); | ||
1245 | 453 | //boost::function<void (const AtspiEvent *event, void *data)> callback(functor, this); | ||
1246 | 454 | |||
1247 | 455 | |||
1248 | 456 | //std::function<void (AtspiEvent*, void*)> bound_fn = std::bind(&AccessibilityWatcher::onFocus, this, std::placeholders::_1, std::placeholders::_2); | ||
1249 | 457 | //using sig = void (AtspiEvent*, void*); | ||
1250 | 458 | //using tamere = std::function<sig>; | ||
1251 | 459 | //AtspiEventListenerCB bound_fn = std::bind(&AccessibilityWatcher::onFocus, this, std::placeholders::_1, std::placeholders::_2); | ||
1252 | 460 | //focusListener = atspi_event_listener_new (reinterpret_cast<AtspiEventListenerCB>(bound_fn), NULL, NULL); | ||
1253 | 461 | |||
1254 | 462 | focusListener = atspi_event_listener_new (reinterpret_cast<AtspiEventListenerCB>(onFocus), NULL, NULL); | ||
1255 | 463 | caretMoveListener = atspi_event_listener_new (reinterpret_cast<AtspiEventListenerCB>(onCaretMove), NULL, NULL); | ||
1256 | 464 | selectedListener = atspi_event_listener_new (reinterpret_cast<AtspiEventListenerCB>(onSelectedChange), NULL, NULL); | ||
1257 | 465 | descendantChangedListener = atspi_event_listener_new (reinterpret_cast<AtspiEventListenerCB>(onDescendantChanged), NULL, NULL); | ||
1258 | 466 | |||
1259 | 467 | atspi_event_listener_register (focusListener, "object:state-changed:focused", NULL); | ||
1260 | 468 | atspi_event_listener_register (caretMoveListener, "object:text-caret-moved", NULL); | ||
1261 | 469 | atspi_event_listener_register (caretMoveListener, "object:text-changed:inserted", NULL); | ||
1262 | 470 | atspi_event_listener_register (caretMoveListener, "object:text-changed:removed", NULL); | ||
1263 | 471 | atspi_event_listener_register (selectedListener, "object:state-changed:selected", NULL); | ||
1264 | 472 | atspi_event_listener_register (descendantChangedListener, "object:active-descendant-changed", NULL); | ||
1265 | 473 | } | ||
1266 | 474 | |||
1267 | 475 | void AccessibilityWatcher::removeWatches() { | ||
1268 | 476 | atspi_event_listener_deregister (focusListener, "object:state-changed:focused", NULL); | ||
1269 | 477 | atspi_event_listener_deregister (caretMoveListener, "object:text-caret-moved", NULL); | ||
1270 | 478 | atspi_event_listener_deregister (caretMoveListener, "object:text-changed:inserted", NULL); | ||
1271 | 479 | atspi_event_listener_deregister (caretMoveListener, "object:text-changed:removed", NULL); | ||
1272 | 480 | atspi_event_listener_deregister (selectedListener, "object:state-changed:selected", NULL); | ||
1273 | 481 | atspi_event_listener_deregister (descendantChangedListener, "object:active-descendant-changed", NULL); | ||
1274 | 482 | } | ||
1275 | 483 | |||
1276 | 484 | void AccessibilityWatcher::init() { | ||
1277 | 485 | if (initialized) { return; } | ||
1278 | 486 | |||
1279 | 487 | atspi_init (); | ||
1280 | 488 | atspi_set_main_context(g_main_context_default()); | ||
1281 | 489 | addWatches(); | ||
1282 | 490 | |||
1283 | 491 | initialized = true; | ||
1284 | 492 | } | ||
1285 | 493 | |||
1286 | 494 | void AccessibilityWatcher::quit() { | ||
1287 | 495 | removeWatches(); | ||
1288 | 496 | initialized = false; | ||
1289 | 497 | } | ||
1290 | 498 | |||
1291 | 499 | std::deque<FocusInfo> AccessibilityWatcher::getFocusQueue() { | ||
1292 | 500 | return focusList; | ||
1293 | 501 | } | ||
1294 | 502 | |||
1295 | 503 | void AccessibilityWatcher::resetFocusQueue() { | ||
1296 | 504 | focusList.clear(); | ||
1297 | 505 | } | ||
1298 | 506 | |||
1299 | 0 | 507 | ||
1300 | === added file 'plugins/focuspoll/src/focuspoll.cpp' | |||
1301 | --- plugins/focuspoll/src/focuspoll.cpp 1970-01-01 00:00:00 +0000 | |||
1302 | +++ plugins/focuspoll/src/focuspoll.cpp 2017-04-28 09:59:04 +0000 | |||
1303 | @@ -0,0 +1,220 @@ | |||
1304 | 1 | /* | ||
1305 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
1306 | 3 | * | ||
1307 | 4 | * This file is part of compiz. | ||
1308 | 5 | * | ||
1309 | 6 | * this program is free software: you can redistribute it and/or modify | ||
1310 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
1311 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
1312 | 9 | * later version. | ||
1313 | 10 | * | ||
1314 | 11 | * This program is distributed in the hope that it will be useful, but | ||
1315 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
1316 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
1317 | 14 | * details. | ||
1318 | 15 | * | ||
1319 | 16 | * You should have received a copy of the GNU General Public License along | ||
1320 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1321 | 18 | */ | ||
1322 | 19 | |||
1323 | 20 | #include "private.h" | ||
1324 | 21 | #include <iostream> | ||
1325 | 22 | |||
1326 | 23 | COMPIZ_PLUGIN_20090315 (focuspoll, FocuspollPluginVTable); | ||
1327 | 24 | |||
1328 | 25 | bool | ||
1329 | 26 | FocuspollScreen::updatePosition () | ||
1330 | 27 | { | ||
1331 | 28 | if (!a11ywatcher->getFocusQueue().empty()) { | ||
1332 | 29 | int focusX, focusY, focusW, focusH; | ||
1333 | 30 | std::tie(focusX, focusY, focusW, focusH) = a11ywatcher->getFocusQueue().back().getBBox(); | ||
1334 | 31 | focusRect = CompRect(focusX, focusY, focusW, focusH); | ||
1335 | 32 | // for (auto poller : pollers) segfaults at focuspoller.stop, reverting TODO | ||
1336 | 33 | for (std::list<FocusPoller *>::iterator it = pollers.begin (); it != pollers.end ();) { | ||
1337 | 34 | FocusPoller *poller = *it; | ||
1338 | 35 | ++it; | ||
1339 | 36 | |||
1340 | 37 | poller->mCallback(focusRect); | ||
1341 | 38 | } | ||
1342 | 39 | } | ||
1343 | 40 | a11ywatcher->resetFocusQueue(); | ||
1344 | 41 | return true; | ||
1345 | 42 | } | ||
1346 | 43 | |||
1347 | 44 | bool | ||
1348 | 45 | FocuspollScreen::addTimer (FocusPoller *poller) | ||
1349 | 46 | { | ||
1350 | 47 | bool start = pollers.empty (); | ||
1351 | 48 | |||
1352 | 49 | std::list<FocusPoller *>::iterator it = | ||
1353 | 50 | std::find (pollers.begin (), pollers.end (), poller); | ||
1354 | 51 | |||
1355 | 52 | if (it != pollers.end ()) | ||
1356 | 53 | return false; | ||
1357 | 54 | |||
1358 | 55 | pollers.insert (it, poller); | ||
1359 | 56 | |||
1360 | 57 | if (start) | ||
1361 | 58 | { | ||
1362 | 59 | //focusHasMoved(); | ||
1363 | 60 | timer.start(); | ||
1364 | 61 | } | ||
1365 | 62 | |||
1366 | 63 | return true; | ||
1367 | 64 | } | ||
1368 | 65 | |||
1369 | 66 | void | ||
1370 | 67 | FocuspollScreen::removeTimer (FocusPoller *poller) | ||
1371 | 68 | { | ||
1372 | 69 | std::list<FocusPoller *>::iterator it = | ||
1373 | 70 | std::find (pollers.begin(), pollers.end (), poller); | ||
1374 | 71 | |||
1375 | 72 | if (it == pollers.end ()) | ||
1376 | 73 | return; | ||
1377 | 74 | |||
1378 | 75 | pollers.erase (it); | ||
1379 | 76 | |||
1380 | 77 | if (pollers.empty ()) { | ||
1381 | 78 | timer.stop (); | ||
1382 | 79 | } | ||
1383 | 80 | } | ||
1384 | 81 | |||
1385 | 82 | void | ||
1386 | 83 | FocusPoller::setCallback (FocusPoller::CallBack callback) | ||
1387 | 84 | { | ||
1388 | 85 | bool wasActive = mActive; | ||
1389 | 86 | |||
1390 | 87 | if (mActive) | ||
1391 | 88 | stop (); | ||
1392 | 89 | |||
1393 | 90 | mCallback = callback; | ||
1394 | 91 | |||
1395 | 92 | if (wasActive) | ||
1396 | 93 | start (); | ||
1397 | 94 | } | ||
1398 | 95 | |||
1399 | 96 | void | ||
1400 | 97 | FocusPoller::start () | ||
1401 | 98 | { | ||
1402 | 99 | FOCUSPOLL_SCREEN (screen); | ||
1403 | 100 | |||
1404 | 101 | if (!fs) | ||
1405 | 102 | { | ||
1406 | 103 | compLogMessage ("focuspoll", CompLogLevelWarn, | ||
1407 | 104 | "Plugin version mismatch, can't start focus poller."); | ||
1408 | 105 | |||
1409 | 106 | return; | ||
1410 | 107 | } | ||
1411 | 108 | |||
1412 | 109 | if (mCallback.empty ()) | ||
1413 | 110 | { | ||
1414 | 111 | compLogMessage ("focuspoll", CompLogLevelWarn, | ||
1415 | 112 | "Can't start focus poller without callback."); | ||
1416 | 113 | return; | ||
1417 | 114 | } | ||
1418 | 115 | |||
1419 | 116 | fs->addTimer (this); | ||
1420 | 117 | |||
1421 | 118 | mActive = true; | ||
1422 | 119 | } | ||
1423 | 120 | |||
1424 | 121 | void | ||
1425 | 122 | FocusPoller::stop () | ||
1426 | 123 | { | ||
1427 | 124 | FOCUSPOLL_SCREEN (screen); | ||
1428 | 125 | |||
1429 | 126 | /* Prevent broken plugins from calling stop () twice */ | ||
1430 | 127 | |||
1431 | 128 | if (!mActive) | ||
1432 | 129 | return; | ||
1433 | 130 | |||
1434 | 131 | if (!fs) | ||
1435 | 132 | { | ||
1436 | 133 | compLogMessage ("focuspoll", | ||
1437 | 134 | CompLogLevelWarn, | ||
1438 | 135 | "Plugin version mismatch, can't stop focus poller."); | ||
1439 | 136 | return; | ||
1440 | 137 | } | ||
1441 | 138 | |||
1442 | 139 | mActive = false; | ||
1443 | 140 | fs->removeTimer (this); | ||
1444 | 141 | } | ||
1445 | 142 | |||
1446 | 143 | bool | ||
1447 | 144 | FocusPoller::active () | ||
1448 | 145 | { | ||
1449 | 146 | return mActive; | ||
1450 | 147 | } | ||
1451 | 148 | |||
1452 | 149 | FocusPoller::FocusPoller () : | ||
1453 | 150 | mActive (false), | ||
1454 | 151 | mCallback (NULL) { | ||
1455 | 152 | } | ||
1456 | 153 | |||
1457 | 154 | std::tuple<int, int> FocuspollScreen::getScreenLimits() { | ||
1458 | 155 | int x =0, y = 0; | ||
1459 | 156 | for (auto dev : screen->outputDevs()) { | ||
1460 | 157 | x = std::max(x, dev.x() + dev.width()); | ||
1461 | 158 | y = std::max(y, dev.y() + dev.height()); | ||
1462 | 159 | } | ||
1463 | 160 | return std::make_tuple(x, y); | ||
1464 | 161 | } | ||
1465 | 162 | |||
1466 | 163 | void | ||
1467 | 164 | FocuspollScreen::updateTimer () | ||
1468 | 165 | { | ||
1469 | 166 | float timeout = optionGetFocusPollInterval (); | ||
1470 | 167 | timer.setTimes (timeout, timeout * 1.5); | ||
1471 | 168 | } | ||
1472 | 169 | |||
1473 | 170 | FocusPoller::~FocusPoller () | ||
1474 | 171 | { | ||
1475 | 172 | if (mActive) { | ||
1476 | 173 | stop(); | ||
1477 | 174 | } | ||
1478 | 175 | } | ||
1479 | 176 | |||
1480 | 177 | void | ||
1481 | 178 | FocuspollScreen::setOptions() | ||
1482 | 179 | { | ||
1483 | 180 | a11ywatcher->setIgnoreLinks(optionGetIgnoreLinks()); | ||
1484 | 181 | } | ||
1485 | 182 | |||
1486 | 183 | template class PluginClassHandler <FocuspollScreen, CompScreen, COMPIZ_FOCUSPOLL_ABI>; | ||
1487 | 184 | |||
1488 | 185 | FocuspollScreen::FocuspollScreen (CompScreen *screen) : | ||
1489 | 186 | PluginClassHandler <FocuspollScreen, CompScreen, COMPIZ_FOCUSPOLL_ABI> (screen) | ||
1490 | 187 | { | ||
1491 | 188 | a11ywatcher = AccessibilityWatcher::getInstance(); | ||
1492 | 189 | a11ywatcher->init(); | ||
1493 | 190 | |||
1494 | 191 | int screenLimitX, screenLimitY; | ||
1495 | 192 | std::tie(screenLimitX, screenLimitY) = getScreenLimits(); | ||
1496 | 193 | a11ywatcher->setScreenLimits(screenLimitX, screenLimitY); | ||
1497 | 194 | |||
1498 | 195 | updateTimer (); | ||
1499 | 196 | timer.setCallback (boost::bind (&FocuspollScreen::updatePosition, this)); | ||
1500 | 197 | optionSetFocusPollIntervalNotify (boost::bind (&FocuspollScreen::updateTimer, this)); | ||
1501 | 198 | |||
1502 | 199 | optionSetIgnoreLinksNotify (boost::bind (&FocuspollScreen::setOptions, this)); | ||
1503 | 200 | |||
1504 | 201 | } | ||
1505 | 202 | |||
1506 | 203 | bool | ||
1507 | 204 | FocuspollPluginVTable::init () | ||
1508 | 205 | { | ||
1509 | 206 | if (CompPlugin::checkPluginABI ("core", CORE_ABIVERSION)) | ||
1510 | 207 | { | ||
1511 | 208 | CompPrivate p; | ||
1512 | 209 | p.uval = COMPIZ_FOCUSPOLL_ABI; | ||
1513 | 210 | screen->storeValue ("focuspoll_ABI", p); | ||
1514 | 211 | return true; | ||
1515 | 212 | } | ||
1516 | 213 | return false; | ||
1517 | 214 | } | ||
1518 | 215 | |||
1519 | 216 | void | ||
1520 | 217 | FocuspollPluginVTable::fini () | ||
1521 | 218 | { | ||
1522 | 219 | screen->eraseValue ("focuspoll_ABI"); | ||
1523 | 220 | } | ||
1524 | 0 | 221 | ||
1525 | === added file 'plugins/focuspoll/src/private.h' | |||
1526 | --- plugins/focuspoll/src/private.h 1970-01-01 00:00:00 +0000 | |||
1527 | +++ plugins/focuspoll/src/private.h 2017-04-28 09:59:04 +0000 | |||
1528 | @@ -0,0 +1,75 @@ | |||
1529 | 1 | /* | ||
1530 | 2 | * Copyright (C) 2016 Auboyneau Vincent <ksamak@riseup.net> | ||
1531 | 3 | * | ||
1532 | 4 | * This file is part of compiz. | ||
1533 | 5 | * | ||
1534 | 6 | * this program is free software: you can redistribute it and/or modify | ||
1535 | 7 | * it under the terms of the GNU General Public License as published by the Free | ||
1536 | 8 | * Software Foundation, either version 3 of the License, or (at your option) any | ||
1537 | 9 | * later version. | ||
1538 | 10 | * | ||
1539 | 11 | * This program is distributed in the hope that it will be useful, but | ||
1540 | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
1541 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
1542 | 14 | * details. | ||
1543 | 15 | * | ||
1544 | 16 | * You should have received a copy of the GNU General Public License along | ||
1545 | 17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1546 | 18 | */ | ||
1547 | 19 | |||
1548 | 20 | #include <tuple> | ||
1549 | 21 | #include <core/core.h> | ||
1550 | 22 | #include <core/pluginclasshandler.h> | ||
1551 | 23 | #include <core/timer.h> | ||
1552 | 24 | |||
1553 | 25 | #include <focuspoll/focuspoll.h> | ||
1554 | 26 | #include <accessibilitywatcher/accessibilitywatcher.h> | ||
1555 | 27 | |||
1556 | 28 | #include "focuspoll_options.h" | ||
1557 | 29 | |||
1558 | 30 | typedef enum _FocuspollOptions | ||
1559 | 31 | { | ||
1560 | 32 | MP_DISPLAY_OPTION_FOCUS_POLL_INTERVAL, | ||
1561 | 33 | MP_DISPLAY_OPTION_NUM | ||
1562 | 34 | } FocuspollDisplayOptions; | ||
1563 | 35 | |||
1564 | 36 | class FocuspollScreen; | ||
1565 | 37 | extern template class PluginClassHandler <FocuspollScreen, CompScreen, COMPIZ_FOCUSPOLL_ABI>; | ||
1566 | 38 | |||
1567 | 39 | class FocuspollScreen : | ||
1568 | 40 | public PluginClassHandler <FocuspollScreen, CompScreen, COMPIZ_FOCUSPOLL_ABI>, | ||
1569 | 41 | public FocuspollOptions | ||
1570 | 42 | { | ||
1571 | 43 | public: | ||
1572 | 44 | FocuspollScreen (CompScreen *screen); | ||
1573 | 45 | |||
1574 | 46 | std::list<FocusPoller *> pollers; | ||
1575 | 47 | CompTimer timer; | ||
1576 | 48 | CompTimer settingsTimer; | ||
1577 | 49 | CompRect focusRect; | ||
1578 | 50 | |||
1579 | 51 | bool updatePosition (); | ||
1580 | 52 | bool addTimer (FocusPoller *poller); | ||
1581 | 53 | void removeTimer (FocusPoller *poller); | ||
1582 | 54 | void updateTimer (); | ||
1583 | 55 | |||
1584 | 56 | private: | ||
1585 | 57 | AccessibilityWatcher* a11ywatcher; | ||
1586 | 58 | |||
1587 | 59 | std::tuple<int, int> getScreenLimits(); | ||
1588 | 60 | void setOptions(); | ||
1589 | 61 | |||
1590 | 62 | }; | ||
1591 | 63 | |||
1592 | 64 | #define FOCUSPOLL_SCREEN(s) \ | ||
1593 | 65 | FocuspollScreen *fs = FocuspollScreen::get (s) | ||
1594 | 66 | |||
1595 | 67 | #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption)) | ||
1596 | 68 | |||
1597 | 69 | class FocuspollPluginVTable : | ||
1598 | 70 | public CompPlugin::VTableForScreen<FocuspollScreen, COMPIZ_FOCUSPOLL_ABI> | ||
1599 | 71 | { | ||
1600 | 72 | public: | ||
1601 | 73 | bool init (); | ||
1602 | 74 | void fini (); | ||
1603 | 75 | }; | ||
1604 | 0 | 76 | ||
1605 | === modified file 'plugins/showmouse/showmouse.xml.in' | |||
1606 | --- plugins/showmouse/showmouse.xml.in 2016-05-31 17:30:42 +0000 | |||
1607 | +++ plugins/showmouse/showmouse.xml.in 2017-04-28 09:59:04 +0000 | |||
1608 | @@ -11,6 +11,9 @@ | |||
1609 | 11 | <plugin>cube</plugin> | 11 | <plugin>cube</plugin> |
1610 | 12 | <plugin>decor</plugin> | 12 | <plugin>decor</plugin> |
1611 | 13 | </relation> | 13 | </relation> |
1612 | 14 | <relation type="before"> | ||
1613 | 15 | <plugin>ezoom</plugin> | ||
1614 | 16 | </relation> | ||
1615 | 14 | <requirement> | 17 | <requirement> |
1616 | 15 | <plugin>opengl</plugin> | 18 | <plugin>opengl</plugin> |
1617 | 16 | <plugin>mousepoll</plugin> | 19 | <plugin>mousepoll</plugin> |
Can you please link a bug to the MP?