Bug 8488

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: Программа, повторяющая проблему

Description Svetlana Zhukova 2012-05-24 17:50:12 MSK
Воспроизведение:
> Открываю УТ 10.3 демо на 8.1 платформе
> Иду в "заказы"-"заказы покупателей"
> открываю любой заказ
> в товарах выбираю кнопку "подбор", так чтоб появилось отдельное окно.
> ставлю в окне галку "Запрашивать кол-во"
> далее выбираю позицию, которая уходит в заказ, нажимаю ентер
> появляется окно с количеством, нажимаю ентер
> и вместо того чтоб вернуться в окно подбора, фокус уходит в окно с заказом

wine@eter-2 bottle rt/24727
WINE@Etersoft SQL 2.0.1-eter15/6
на windows фокус остается в текущем окне - в данном случае это "подбор".
Comment 1 Сергей Гуральник 2012-06-05 18:05:53 MSK
Пытаюсь написать программу, которая воспроизведет проблему. В некоторых случаях видно, что на мгновение активным становится "Подбор" а затем происходит моментальное переключение на главное окно 1С.
Comment 2 Сергей Гуральник 2012-06-06 17:43:19 MSK
При эмулировании рабочего стола активируется нужное окно, но при этом оно опускается в zorder'e
Comment 3 Сергей Гуральник 2012-06-07 13:25:18 MSK
Created attachment 2518 [details]
Программа, повторяющая проблему
Comment 4 Сергей Гуральник 2012-06-07 13:28:35 MSK
Сделал приложение, повторяющее проблему. Замечено, что проблема возникает при наличии более чем одного owned-окна у happroot.
Comment 5 Сергей Гуральник 2012-06-07 14:51:00 MSK
Тест ведет себя несколько по-разному для ww и wwo. Нужное окно в любом случае не получает фокус, а вот GetActiveWindow() для wwo дает правильный результат (окно с edit'ом, хотя драйвер не активировал его) в то время как для ww возвращается корневое окно программы. Скорее всего это побочное действие какого-то хака.
Comment 6 Сергей Гуральник 2012-06-08 13:21:30 MSK
Проблемы нет, если не вызывать DestroyWindow() для второго owned-окна. Фокус ставится на указываемый контрол, хотя его родитель и не активируется. В обратном случае система делает активным корневое окно, что соответствует указанному в https://bugs.etersoft.ru/show_bug.cgi?id=8488#c1
Comment 7 Сергей Гуральник 2012-06-11 12:28:12 MSK
(В ответ на 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() не ставит фокус на контрол если предварительно было уничтожено окно того же уровня, что и родитель контрола.
Comment 8 Сергей Гуральник 2012-06-11 15:58:48 MSK
Вайн успешно ставит фокус на контрол, но затем родитель окна удаленного с помощью DestroyWindow() получает WM_ACTIVATE, что ведет к ненужной передаче фокуса. для Windows никакого WM_ACTIVATE не наблюдается.
Comment 9 Сергей Гуральник 2012-06-12 21:17:35 MSK
В тестовой программе удается избежать проблемы поставив цикл выборки сообщений на PeekMessage(). Ненужное переключение фокуса отрабатывается в цикле не искажая результат SetFocus()
Comment 10 Сергей Гуральник 2012-06-14 13:36:23 MSK
Вероятнее всего, что проблема заключается в следующем. Во время работы DestroyWindow() в иксовую очередь сообщений ставится ClientMessage WM_PROTOCOL WM_TAKE_FOCUS. Последующий вызов SetFocus()работает корректно, что можно определить по логам. Далее при вхождении программы в цикл сообщений указанное ранее ClientMessage вынуждает перевести фокус на родителя или хозянина уничтоженного окна. Это объясняет https://bugs.etersoft.ru/show_bug.cgi?id=8488#c1
Comment 11 Сергей Гуральник 2012-06-15 16:41:02 MSK
Пытаюсь отыскать нужное ClientMessage при работе X11DRV_SetFocus() с помощью XIfEvent(). Пока продвижение незначительное, возможно стоит подумать о другом решении.
Comment 12 Сергей Гуральник 2012-06-18 19:08:31 MSK
ClientMessage оказывается в очереди уже после вызова X11DRV_SetFocus(). Т.к. перебор с помощью XCheckIfEvent() ничего не показал. Это сильно затрудняет решение, т.к. в этом случае необходимо найти способ отличить нужное сообщение от лишнего в handle_wm_protocols() или изменять свойство WM_PROTOCOLS непосредственно перед уничтожением окна (хотя это может повлечь ряд нежелательных последствий.
Comment 13 Сергей Гуральник 2012-06-19 18:35:37 MSK
(В ответ на comment #9)
> В тестовой программе удается избежать проблемы поставив цикл выборки сообщений
> на PeekMessage(). Ненужное переключение фокуса отрабатывается в цикле не
> искажая результат SetFocus()

Это возможно если перед циклом будет вызов Sleep() с ненулевым таймаутом. Очевидно при ее работе ClientMessage попадает в очередь. Оттуда удается его удалить используя XCheckIfEvent().
Comment 14 Сергей Гуральник 2012-06-29 15:47:05 MSK
Пытаюсь сделать тест для winehq. Проблема усложняется тем, что теряется Х-фокус, в то время как wineserver корректно оперирует своим внутренним фокусом, т.е. GetFocus или GetActiveWindow здесь мало чем помогут.
Comment 15 Сергей Гуральник 2012-07-10 14:37:03 MSK
Сделал тест по этой проблеме для winehq:
http://www.winehq.org/pipermail/wine-patches/2012-July/115959.html
Comment 16 Сергей Гуральник 2012-07-23 11:19:54 MSK
Пока удалось удержать активным окно с таблицей на которой должен быть фокус.
Comment 17 Сергей Гуральник 2012-07-26 17:04:26 MSK
Механизм удержания фокуса уточняется, вероятно он сложнее, чем ранее предполагаемый.
Comment 18 Сергей Гуральник 2012-07-27 16:52:43 MSK
В качестве попытки подтвердить идею с ненужным ClientMessage попытался поставить flush_events() из dlls/user32/tests/msg.c в начало SetFofus(). Фокус продолжает уходить.
Comment 19 Сергей Гуральник 2012-07-28 14:34:16 MSK
Фокус уводится с нужного окна обычным вызовом SetFocus, т.е. вероятно ClientMessage здесь не участвует. Нужно выяснить кто обращается к SetFocus.
Comment 20 Сергей Гуральник 2012-08-01 19:50:43 MSK
Возможно SetFocus  вызывается самим приложением. Работаю над тестом, который должен повторить проблему.
Comment 21 Сергей Гуральник 2012-08-03 18:17:26 MSK
(В ответ на 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 22 Сергей Гуральник 2012-08-07 17:08:53 MSK
(В ответ на comment #21)
> Wine использует его чтобы определять
> возможность активации/передачи фокуса в некоторых ситуациях (причем совершенно
> не ожидается, что приложение может по своему манипулировать фокусом и
> активацией окон во время SendMessage(..., WM_MOUSEACTIVATE, ..., ...) ). В
> результате происходит ненужный переход фокуса.

Заменить это сообщение на что-то другое представляется маловероятным, поэтому придется искать способы "вытягивания" ClientMessage из очереди внутри SetFocus. Хотя это скорее всего заметно повлияет на быстродействие.
Comment 23 Сергей Гуральник 2012-08-08 14:28:18 MSK
Прежний тест для winehq не торопятся принимать, поэтому решил его несколько расширить. Но при этом оказалось, что результаты теста весьма нестабильны. Работаю над устранением этой нестабильности.
Comment 24 Сергей Гуральник 2012-08-09 17:21:24 MSK
(В ответ на comment #23)
> Прежний тест для winehq не торопятся принимать, поэтому решил его несколько
> расширить. Но при этом оказалось, что результаты теста весьма нестабильны.
> Работаю над устранением этой нестабильности.

Тест доработал, но пока не отправляю, т.к., по словам Дмитрия Тимошкова, Julliard временно отсутствует. Как мне кажется у патча больше шансов проЙти если он будет в числе 10 - 15 патчей приходящих за день, а не в пачке собравшейся за всю неделю. Думаю в этом случае патч от малоизвестного разработчика получит чуть больше внимания.
Comment 25 Сергей Гуральник 2012-08-14 14:56:50 MSK
(В ответ на comment #24)
> Тест доработал, но пока не отправляю...

Отправил, патч в очереди.
Comment 26 Сергей Гуральник 2012-09-05 16:23:11 MSK
Ищу способ обработать ClientMessage перед установкой фокуса. Пока со скрипом.
Comment 27 Сергей Гуральник 2012-09-14 09:45:01 MSK
(В ответ на comment #25)
> (В ответ на comment #24)
> > Тест доработал, но пока не отправляю...
> 
> Отправил, патч в очереди.

Отправил напоминание об этом патче в wine-devel
Comment 28 Сергей Гуральник 2012-09-17 12:23:45 MSK
(В ответ на comment #27)
> (В ответ на comment #25)
> > (В ответ на comment #24)
> > > Тест доработал, но пока не отправляю...
> > 
> > Отправил, патч в очереди.
> 
> Отправил напоминание об этом патче в wine-devel

Этот патч считают ненужным, пытаюсь объяснить свою точку зрения.
Comment 29 Сергей Гуральник 2012-09-18 17:48:00 MSK
(В ответ на comment #28)
> (В ответ на comment #27)
> > (В ответ на comment #25)
> > > (В ответ на comment #24)
> > > > Тест доработал, но пока не отправляю...
> > > 
> > > Отправил, патч в очереди.
> > 
> > Отправил напоминание об этом патче в wine-devel
> 
> Этот патч считают ненужным, пытаюсь объяснить свою точку зрения.

Джуллиард говорит, что такое поведение есть политика оконного менеджера, поэтому нет смысла пытаться решить эту проблему изменением кода вайна.
Comment 30 Сергей Гуральник 2012-12-13 17:17:48 MSK
Пытаюсь наити какое-нибудь приемлемое обходное решение, а не Sleep(). Очевидно решение будет неприемлемо для winehq.
Comment 31 Vitaly Lipatov 2014-09-11 18:53:09 MSK
Откладываем задачи, к которым не обращались более 100 дней.
Comment 32 Dmitry Timoshkov 2015-08-20 13:55:40 MSK
(Ответ Сергей Гуральник на комментарий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()
вызывать не нужно.

В каком префиксе можно увидеть проблему и протестировать возможное решение?
Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
Comment 33 Konstantin Artyushkin 2015-08-20 15:29:09 MSK
(Ответ Dmitry Timoshkov на комментарий32)

> В каком префиксе можно увидеть проблему и протестировать возможное решение?
> Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.

А программа приложенная к данной баге( написанная С.Гуральник ) не воспроизводит проблемы?
Comment 34 Vitaly Lipatov 2015-08-20 15:33:01 MSK
(Ответ Konstantin Artyushkin на комментарий33)
> (Ответ Dmitry Timoshkov на комментарий32)
> 
> > В каком префиксе можно увидеть проблему и протестировать возможное решение?
> > Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
> 
> А программа приложенная к данной баге( написанная С.Гуральник ) не
> воспроизводит проблемы?
Добавил в репозиторий с тестами (увы, Гуральник про него не знал?) в каталог
focus-bug2518 собирающуюся командой make эту программу:

git.office:/projects/wine/wine-etersoft-devel.git
Comment 35 Dmitry Timoshkov 2015-08-21 09:07:11 MSK
(Ответ 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: фокус
всегда устанавливается на второе дочернее окно.

Поэтому мой вопрос остается в силе:

> В каком префиксе можно увидеть проблему и протестировать возможное решение?
> Лучше всего написать пошаговую инструкцию по воспроизведению проблемы.
Comment 36 Konstantin Artyushkin 2015-08-24 16:14:59 MSK
Поиск бутылок с УТ и 1с81 не увенчался успехом. 
Создал 2.1 bugs/8488. Но установить какую-либо из имеющихся у нас УТ не смог.
Comment 37 Vitaly Lipatov 2015-08-25 23:37:36 MSK
Откладываем, пока не появится жалоба от клиентов.