Summary: | 1c81 - фокус самопроизвольно переходит в другое окно | ||
---|---|---|---|
Product: | WINE@Etersoft | Reporter: | Svetlana Zhukova <svzhu> |
Component: | Окна / фокус / перерисовка | Assignee: | Konstantin Artyushkin <akv> |
Status: | DEFERRED --- | QA Contact: | Vitaly Lipatov <lav> |
Severity: | minor | ||
Priority: | P4 | CC: | akv, dtimoshkov, dtr, lav |
Version: | 2.0 | ||
Target Milestone: | --- | ||
Hardware: | PC | ||
OS: | All | ||
Whiteboard: | |||
Заявки RT: | 24727 | Связано с: | |
Дата напоминания: | |||
Attachments: | Программа, повторяющая проблему |
Пытаюсь написать программу, которая воспроизведет проблему. В некоторых случаях видно, что на мгновение активным становится "Подбор" а затем происходит моментальное переключение на главное окно 1С. При эмулировании рабочего стола активируется нужное окно, но при этом оно опускается в zorder'e Created attachment 2518 [details]
Программа, повторяющая проблему
Сделал приложение, повторяющее проблему. Замечено, что проблема возникает при наличии более чем одного owned-окна у happroot. Тест ведет себя несколько по-разному для ww и wwo. Нужное окно в любом случае не получает фокус, а вот GetActiveWindow() для wwo дает правильный результат (окно с edit'ом, хотя драйвер не активировал его) в то время как для ww возвращается корневое окно программы. Скорее всего это побочное действие какого-то хака. Проблемы нет, если не вызывать DestroyWindow() для второго owned-окна. Фокус ставится на указываемый контрол, хотя его родитель и не активируется. В обратном случае система делает активным корневое окно, что соответствует указанному в https://bugs.etersoft.ru/show_bug.cgi?id=8488#c1 (В ответ на comment #2) > При эмулировании рабочего стола активируется нужное окно, но при этом оно > опускается в zorder'e Это происходит из-за commit ce93b63fa0f491fbe770600f2df24661fd2a680d Author: Ilya Shpigor <shpigor@etersoft.ru> Date: Tue Nov 24 16:25:43 2009 +0300 user32: Don't call set_active_window from SetFocus (eterbug #4382) Для wine-pure zorder остается в порядке. Сейчас в задаче видны две независимые части: 1. При программном переключении активного окна не всегда подсвечивается заголовок у текущего активного окна (Хотя GetActiveWindow() дает правильный результат). 2. SetFocus() не ставит фокус на контрол если предварительно было уничтожено окно того же уровня, что и родитель контрола. Вайн успешно ставит фокус на контрол, но затем родитель окна удаленного с помощью DestroyWindow() получает WM_ACTIVATE, что ведет к ненужной передаче фокуса. для Windows никакого WM_ACTIVATE не наблюдается. В тестовой программе удается избежать проблемы поставив цикл выборки сообщений на PeekMessage(). Ненужное переключение фокуса отрабатывается в цикле не искажая результат SetFocus() Вероятнее всего, что проблема заключается в следующем. Во время работы DestroyWindow() в иксовую очередь сообщений ставится ClientMessage WM_PROTOCOL WM_TAKE_FOCUS. Последующий вызов SetFocus()работает корректно, что можно определить по логам. Далее при вхождении программы в цикл сообщений указанное ранее ClientMessage вынуждает перевести фокус на родителя или хозянина уничтоженного окна. Это объясняет https://bugs.etersoft.ru/show_bug.cgi?id=8488#c1 Пытаюсь отыскать нужное ClientMessage при работе X11DRV_SetFocus() с помощью XIfEvent(). Пока продвижение незначительное, возможно стоит подумать о другом решении. ClientMessage оказывается в очереди уже после вызова X11DRV_SetFocus(). Т.к. перебор с помощью XCheckIfEvent() ничего не показал. Это сильно затрудняет решение, т.к. в этом случае необходимо найти способ отличить нужное сообщение от лишнего в handle_wm_protocols() или изменять свойство WM_PROTOCOLS непосредственно перед уничтожением окна (хотя это может повлечь ряд нежелательных последствий. (В ответ на comment #9) > В тестовой программе удается избежать проблемы поставив цикл выборки сообщений > на PeekMessage(). Ненужное переключение фокуса отрабатывается в цикле не > искажая результат SetFocus() Это возможно если перед циклом будет вызов Sleep() с ненулевым таймаутом. Очевидно при ее работе ClientMessage попадает в очередь. Оттуда удается его удалить используя XCheckIfEvent(). Пытаюсь сделать тест для winehq. Проблема усложняется тем, что теряется Х-фокус, в то время как wineserver корректно оперирует своим внутренним фокусом, т.е. GetFocus или GetActiveWindow здесь мало чем помогут. Сделал тест по этой проблеме для winehq: http://www.winehq.org/pipermail/wine-patches/2012-July/115959.html Пока удалось удержать активным окно с таблицей на которой должен быть фокус. Механизм удержания фокуса уточняется, вероятно он сложнее, чем ранее предполагаемый. В качестве попытки подтвердить идею с ненужным ClientMessage попытался поставить flush_events() из dlls/user32/tests/msg.c в начало SetFofus(). Фокус продолжает уходить. Фокус уводится с нужного окна обычным вызовом SetFocus, т.е. вероятно ClientMessage здесь не участвует. Нужно выяснить кто обращается к SetFocus. Возможно SetFocus вызывается самим приложением. Работаю над тестом, который должен повторить проблему. (В ответ на comment #20) > Возможно SetFocus вызывается самим приложением. Работаю над тестом, который > должен повторить проблему. Кажется источник проблемы найден. SetFocus действительно вызывается самой 1С как результат обработки WM_MOUSEACTIVATE. Очевидно это сообщение используется приложением для управления фокусом окон. Wine использует его чтобы определять возможность активации/передачи фокуса в некоторых ситуациях (причем совершенно не ожидается, что приложение может по своему манипулировать фокусом и активацией окон во время SendMessage(..., WM_MOUSEACTIVATE, ..., ...) ). В результате происходит ненужный переход фокуса. Следующий хак устраняет проблему: diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 7f9f0bf..934ec3c 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -648,9 +648,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEv { /* simulate a mouse click on the caption to find out * whether the window wants to be activated */ - LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE, - (WPARAM)GetAncestor( hwnd, GA_ROOT ), - MAKELONG(HTCAPTION,WM_LBUTTONDOWN) ); + LRESULT ma = MA_NOACTIVATE; if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) { set_focus( event->display, hwnd, event_time ); (В ответ на comment #21) > Wine использует его чтобы определять > возможность активации/передачи фокуса в некоторых ситуациях (причем совершенно > не ожидается, что приложение может по своему манипулировать фокусом и > активацией окон во время SendMessage(..., WM_MOUSEACTIVATE, ..., ...) ). В > результате происходит ненужный переход фокуса. Заменить это сообщение на что-то другое представляется маловероятным, поэтому придется искать способы "вытягивания" ClientMessage из очереди внутри SetFocus. Хотя это скорее всего заметно повлияет на быстродействие. Прежний тест для winehq не торопятся принимать, поэтому решил его несколько расширить. Но при этом оказалось, что результаты теста весьма нестабильны. Работаю над устранением этой нестабильности. (В ответ на comment #23) > Прежний тест для winehq не торопятся принимать, поэтому решил его несколько > расширить. Но при этом оказалось, что результаты теста весьма нестабильны. > Работаю над устранением этой нестабильности. Тест доработал, но пока не отправляю, т.к., по словам Дмитрия Тимошкова, Julliard временно отсутствует. Как мне кажется у патча больше шансов проЙти если он будет в числе 10 - 15 патчей приходящих за день, а не в пачке собравшейся за всю неделю. Думаю в этом случае патч от малоизвестного разработчика получит чуть больше внимания. (В ответ на comment #24) > Тест доработал, но пока не отправляю... Отправил, патч в очереди. Ищу способ обработать ClientMessage перед установкой фокуса. Пока со скрипом. (В ответ на comment #25) > (В ответ на comment #24) > > Тест доработал, но пока не отправляю... > > Отправил, патч в очереди. Отправил напоминание об этом патче в wine-devel (В ответ на comment #27) > (В ответ на comment #25) > > (В ответ на comment #24) > > > Тест доработал, но пока не отправляю... > > > > Отправил, патч в очереди. > > Отправил напоминание об этом патче в wine-devel Этот патч считают ненужным, пытаюсь объяснить свою точку зрения. (В ответ на comment #28) > (В ответ на comment #27) > > (В ответ на comment #25) > > > (В ответ на comment #24) > > > > Тест доработал, но пока не отправляю... > > > > > > Отправил, патч в очереди. > > > > Отправил напоминание об этом патче в wine-devel > > Этот патч считают ненужным, пытаюсь объяснить свою точку зрения. Джуллиард говорит, что такое поведение есть политика оконного менеджера, поэтому нет смысла пытаться решить эту проблему изменением кода вайна. Пытаюсь наити какое-нибудь приемлемое обходное решение, а не Sleep(). Очевидно решение будет неприемлемо для winehq. Откладываем задачи, к которым не обращались более 100 дней. (Ответ Сергей Гуральник на комментарий21)
> Кажется источник проблемы найден. SetFocus действительно вызывается самой 1С
> как результат обработки WM_MOUSEACTIVATE. Очевидно это сообщение
> используется приложением для управления фокусом окон. Wine использует его
> чтобы определять возможность активации/передачи фокуса в некоторых ситуациях
> (причем совершенно не ожидается, что приложение может по своему
> манипулировать фокусом и активацией окон во время SendMessage(...,
> WM_MOUSEACTIVATE, ..., ...) ). В результате происходит ненужный переход
> фокуса.
>
> Следующий хак устраняет проблему:
> diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
> index 7f9f0bf..934ec3c 100644
> --- a/dlls/winex11.drv/event.c
> +++ b/dlls/winex11.drv/event.c
> @@ -648,9 +648,7 @@ static void handle_wm_protocols( HWND hwnd,
> XClientMessageEv
> {
> /* simulate a mouse click on the caption to find out
> * whether the window wants to be activated */
> - LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
> - (WPARAM)GetAncestor( hwnd, GA_ROOT ),
> - MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
> + LRESULT ma = MA_NOACTIVATE;
> if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
> {
> set_focus( event->display, hwnd, event_time );
После анализа кода winex11.drv и предложенного Сергеем решения появилась
идея проверять, что если после отправки приложению сообщения WM_MOUSEACTIVATE
фокус уже находится на самом окне или одном из его потомков, то set_focus()
вызывать не нужно.
В каком префиксе можно увидеть проблему и протестировать возможное решение?
Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
(Ответ Dmitry Timoshkov на комментарий32)
> В каком префиксе можно увидеть проблему и протестировать возможное решение?
> Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
А программа приложенная к данной баге( написанная С.Гуральник ) не воспроизводит проблемы?
(Ответ Konstantin Artyushkin на комментарий33)
> (Ответ Dmitry Timoshkov на комментарий32)
>
> > В каком префиксе можно увидеть проблему и протестировать возможное решение?
> > Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
>
> А программа приложенная к данной баге( написанная С.Гуральник ) не
> воспроизводит проблемы?
Добавил в репозиторий с тестами (увы, Гуральник про него не знал?) в каталог
focus-bug2518 собирающуюся командой make эту программу:
git.office:/projects/wine/wine-etersoft-devel.git
(Ответ Vitaly Lipatov на комментарий34) > > > В каком префиксе можно увидеть проблему и протестировать возможное решение? > > > Лучше всего написать пошаговую инструкцию по воспроизведению проблемы. > > > > А программа приложенная к данной баге( написанная С.Гуральник ) не > > воспроизводит проблемы? > Добавил в репозиторий с тестами (увы, Гуральник про него не знал?) в каталог > focus-bug2518 собирающуюся командой make эту программу: > > git.office:/projects/wine/wine-etersoft-devel.git Эта программа проблему не воспроизводит ни под eter-2.1 ни под winehq. Написал свою тестовую программу, которая создает два дочерних окна и при получении сообщений WM_ACTIVATE/WM_MOUSEACTIVATE устанавливает фокус с помощью SetFocus() на второе дочернее окно, а при получении сообщения WM_SETFOCUS устанавливает фокус на первое дочернее окно. Моя тестовая программа так же ведет себя корректно под eter-2.1 и под winehq: фокус всегда устанавливается на второе дочернее окно. Поэтому мой вопрос остается в силе: > В каком префиксе можно увидеть проблему и протестировать возможное решение? > Лучше всего написать пошаговую инструкцию по воспроизведению проблемы. Поиск бутылок с УТ и 1с81 не увенчался успехом. Создал 2.1 bugs/8488. Но установить какую-либо из имеющихся у нас УТ не смог. Откладываем, пока не появится жалоба от клиентов. |
Воспроизведение: > Открываю УТ 10.3 демо на 8.1 платформе > Иду в "заказы"-"заказы покупателей" > открываю любой заказ > в товарах выбираю кнопку "подбор", так чтоб появилось отдельное окно. > ставлю в окне галку "Запрашивать кол-во" > далее выбираю позицию, которая уходит в заказ, нажимаю ентер > появляется окно с количеством, нажимаю ентер > и вместо того чтоб вернуться в окно подбора, фокус уходит в окно с заказом wine@eter-2 bottle rt/24727 WINE@Etersoft SQL 2.0.1-eter15/6 на windows фокус остается в текущем окне - в данном случае это "подбор".