MacOS X: Sierra scrolling
После последнего обновления MacOS до версии 10.12 люди стали жаловаться на очень быструю прокрутку. В связи с тем, что я практически полностью переписал прокрутку в ИДЕЕ, мне выпала честь разобрать что происходит.
After MacOS was updated to 10.12 (Sierra) people started to complain about the very fast scrolling in every our IDE. Because I rewrote scroll bars in the IDEA platform, I became the chosen one. I was chosen to investigate what is going on.
Задача осложнялась тем, что её можно было воспроизвести не на каждом оборудовании. Но как только в моём расположении оказался Mac, на котором она воспроизводится, я написал простейший Test.java, показавший, что проблема не в IDEA, а в JDK. Я даже нашёл соответствующий рапорт и выяснил, что проблему мог вызвать фикс этого бага. Но что самое удивительное, у меня получилось воспроизвести проблему со стандартным Terminal, входящим в систему.
The investigation was complicated by the fact that the issue is not reproducible on every Mac. For now I suspect that you need to scroll with a trackpad on Retina display to see fast scrolling. When I got such computer, I created a simple Swing application. It showed that the problem is in the JDK, not in the IDEA. Then I found the corresponding bug and the bug, which fix was a reason of fast scrolling. What is most surprising, I reproduced the same issue in the Terminal application, which is included in the operating system.
В процессе анализа я обнаружил новое свойство preciseWheelRotation класса MouseWheelEvent, добавленное в JDK 7 для поддержки точной прокрутке на Mac. Я про него не знал, несмотря на то, что в то время работал в Swing/AWT team. Именно оно содержит правильные значения прокрутки на любом Mac, включая Sierra. Но нигде в JDK оно не используется и даже Swing не знает о его существовании. Поэтому осталось найти и исправить вычисление свойства wheelRotation, которое используется для прокрутки в JScrollPane.
During this investigation I found out that to support gesture scrolling the preciseWheelRotation property was added into the MouseWheelEvent class since Java 7. I never heard about it, despite the fact that I worked in the Swing/AWT team at that time. This property contains correct values on any Mac, including Sierra, but it is not used in the JDK. Even Swing components are not aware of its existence! Therefore, I need to find and correct the calculation of the wheelRotation property, which is used to do scrolling.
КАРТИНКА
Sierra генерирует гораздо больше событий прокрутки, чем El Capitan. И поэтому значение от операционной системы, стало гораздо меньше 1, но Swing всё равно округляет его до 1. Предложенный мной вариант уже добавлен в OpenJDK, разрабатываемое JetBrains, и успешно решает возникшую проблему с чересчур быстрой прокруткой. Однако, я вижу, что решение не идеальное, так как лишает смысла свойство preciseWheelRotation, так как оно теперь равно свойству wheelRotation.
Sierra generates much more scroll events than El Capitan. So the native delta from the operating system became close to 0, but Swing still converts it to 1. This makes scrolling too harsh. The proposed fix is already added to the JetBrains JDK. It successfully solves the fast scrolling problem. However, I understand that my solution is not ideal, because the preciseWheelRotation property is equal to the wheelRotation property. It makes first property completely useless.
В связи с этим у меня возникла идея модифицировать свой фикс так, чтобы у пользователя снова появилась бы возможность использовать точные значения прокрутки. Причём одним из требований является то, что сумма значений wheelRotation за продолжительный период должна быть приблизительно равна сумме значений preciseWheelRotation за тот же период. Это означает, что мы вынуждены будем иногда генерировать события, для которых значение wheelRotation=0.
Because of this I want to modify my fixed so that an user would be able to use the precise scrolling again. But we have the following constraint: the sum of all wheelRotation values during long period must be close to the sum of all preciseWheelRotation values during the same period. This means that sometimes we have to generate events with wheelRotation = 0.
Однако, это может привести к возвращению уже исправленного бага 7141296. Более того, люди не ожидают, что значение wheelRotation может быть 0. Например, BasicScrollPaneUI does not consume mouse wheel event в этом случае (this is a true reason of 7141296).
However, people do not expect that the wheelRotation may be 0. For example, the BasicScrollPaneUI class does not consume mouse wheel event in this case, what is a true cause of the 7141296 bug. But I believe that Oracle can fix all such places in JDK.
Другие проблемы могут возникнуть и у пользователей. Например, IDEA использует следующий код для масштабирования, который будет работать не так, как ожидается.
Other problems may arise in user's code. For example, IDEA uses the following code for scaling:
if (e.getWheelRotation() < 0) { zoomModel.zoomOut(); } else { zoomModel.zoomIn(); }
This code will not work as expected, because zero wheelRotation may have negative or positive preciseWheelRotation. I know we can fix the IDEA platform, but what's about other UI developers?
Я предложу оба решения моим коллегам из Swing/AWT team. Ваши мысли по поводу возможного решения указанных проблем вы можете оставлять здесь или присоединиться к почтовой рассылке awt-dev@openjdk.java.net
I will suggest my solutions to colleagues from the Swing/AWT team. You can post here your thoughts about these problems, or you can join the mailing list: awt-dev@openjdk.java.net