как победить плаванье onMouseMove

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

как победить плаванье onMouseMove

Сообщение zub » 25.08.2010 11:45:27

В графическом приложении по onMouseMove нужно перерисовывать экран.
Под виндой всё работает нормально - виндовс не добавляет новых сообщений от мышки если старые еще не обработаны.
Под линуксом сообщения добавляются всегда, даже если приложение занято (нуспело перерисоваться) - сообщения копятся, мышка плавает.

Попробовал в onMouseMove только запоминать координаты, а перерисовывать в onIdle - курсор чуток подергивается - это конечно лучше чем плавает, но тоже негодится.

Как правильно организовать onMouseMove в моем случае? или как попросить GTK чтоб он вел себя как WIN?
Последний раз редактировалось zub 02.09.2010 01:35:29, всего редактировалось 1 раз.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить торможение onMouseMove

Сообщение hinst » 26.08.2010 20:55:24

ну это надо сильно извратиться, чтобы GTK о ТАКОМ попросить.
попробуйте GTK2, к примеру.
или же перерисовывайте по таймеру.
или же по IdleTimer'у, что в вашем случае имхо больше подходит, чем по просто-таймеру.
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: как победить торможение onMouseMove

Сообщение zub » 26.08.2010 22:12:09

>>попробуйте GTK2, к примеру.
да, я имел ввиду GTK2. можно подробнее про возможность настройки обработки мыши?

>>или же перерисовывайте по таймеру.
В смысле по таймеру смотреть было ли движение мышки и рисовать? помоеему всеравно будет дергаться
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить торможение onMouseMove

Сообщение zub » 31.08.2010 12:49:51

Таймер ИМХО тут будет лишним.
как я понял мне должно помочь вот это: http://mirror.linuxiso.kz/linfoline.hom ... x2447.html
Для нашей программмы рисования, мы должны знать, когда кнопка мыши нажата и мышь перемещена, таким образом мы определяем GDK_POINTER_MOTION_MASK и GDK_BUTTON_PRESS_MASK. Мы также должны знать, когда перерисовать наше окно, таким образом мы определяем GDK_EXPOSURE_MASK. Хотя нам необходимо уведомление об изменении размера нашего окна через конфигурацию события, мы не должны определять передачу флага GDK_STRUCTURE_MASK, потому что это автоматически определено для всех окон.

Однако, как оказывается есть проблема с определением GDK_POINTER_MOTION_MASK. Это заставит сервер добавлять новое событие передвижения в очередь событий каждый раз, когда пользователь перемещает мышь. Вообразите, что нам требуется 0.1 секунды, чтобы обработать событие движения, но в очередь X сервера поступает новое событие передвижения каждые 0.05 секунды. Если пользователь рисовал в течении 5 секунд, нам потребуется ещё 5 секунд для перехвата после освобождения кнопки мышки! Но нам нужно получить только одно событие движения для каждого случая, который мы обрабатываем. Это можно сделать определив GDK_POINTER_MOTION_HINT_MASK.

Мы определяем GDK_POINTER_MOTION_HINT_MASK, когда сервер в первый раз сообщает нам о передвижении указателя после входа в наше окно, или после нажатия или освобождения кнопки. Последующие события движения будут подавлены, пока мы явно не спросим положение указателя, используя функцию:
Код: Выделить всё
GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
                                          gint            *x,
                                          gint            *y,
                                          GdkModifierType *mask);


и сам обработчик:
Код: Выделить всё
static gint
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
{
  int x, y;
  GdkModifierType state;
  if (event->is_hint)
    gdk_window_get_pointer (event->window, &x, &y, &state);
  else
    {
      x = event->x;
      y = event->y;
      state = event->state;
    }
   
  if (state & GDK_BUTTON1_MASK && pixmap != NULL)
    draw_brush (widget, x, y);
 
  return TRUE;
}



Как это будет выглядеть на LCL?
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить торможение onMouseMove

Сообщение zub » 02.09.2010 00:27:13

попробовал перерисовывать мышку по таймеру - на интервале >10 - дергается, на интервале <10 начинает плавать.

попробовал в обычном onMouseMove запускать перерисовку только если XPending возвращает 0 - тоже дергается, хотя меньше чем перерисовка в onIdle

>>Как это будет выглядеть на LCL?
следов GDK_POINTER_MOTION_HINT_MASK в LCL мои ковыряния (в исходниках и в гугле) не выявили... неужели никто не сталкивался с этой проблемой? как прикрутить GDK_POINTER_MOTION_HINT_MASK к TOpenGLControl не лазя в исходники LCL?
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить торможение onMouseMove

Сообщение Odyssey » 02.09.2010 00:36:06

zub писал(а):неужели никто не сталкивался с этой проблемой? как прикрутить GDK_POINTER_MOTION_HINT_MASK к TOpenGLControl не лазя в исходники LCL?

Это нетиповая задача. Если она и решается, то в обход принципов работы LCL. Т.е. вряд ли кто-то даст гарантии, что найденный способ не сломается через несколько десятков ревизий. LCL разрабатывалась именно для того, чтобы изолировать разработчика от GTK/Qt/WinAPI. Поэтому без погружения в её исходники тут вряд ли получится обойтись.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: как победить торможение onMouseMove

Сообщение zub » 02.09.2010 01:17:06

Qt версия работает точно также, насколько понял это особенность X Window. Это дело учтено даже в GTK примере к FPC - scribble, странно (ИМХО) что в LCL момент остался без внимания.
>>Т.е. вряд ли кто-то даст гарантии, что найденный способ не сломается через несколько десятков ревизий
>>Поэтому без погружения в её исходники тут вряд ли получится обойтись.
Собственно гарантий ненадо, и погрузиться я не против, лишбы без их изменения. Ну и ткнуться носом куда копать

Добавлено спустя 17 часов 38 минут 24 секунды:
Re: как победить плаванье onMouseMove
странно, но оказалось достаточно подписать окно на GDK_POINTER_MOTION_HINT_MASK
Код: Выделить всё
gtk_widget_add_events (Widget,GDK_POINTER_MOTION_HINT_MASK);

и всё заработало рово
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить плаванье onMouseMove

Сообщение zub » 05.09.2010 11:56:30

>>и всё заработало рово

Блин, не заработало ровно... Подергивания всеравно присутствуют, просто стали поменьше. Визуально при скролинге мышью в линуксе видны рывки, в винде всё идеально...

В программе рисуется свой курсор (вертикальное перекрестие во всю рабочую область), для теста я отключил стирание фона - неровная обработка мышки (выподение сообщений - отсутствие вертикальных полос) явно видна на линуксовом скриншоте:
linmouse.png

а вот в винде:
winmouse.gif


Добавлено спустя 13 минут 50 секунд:
Мышку двигал с приблизительно одинаковой скоростью (быстро), комп один и тотже, но в линуксе почемуто события от мышки приходят гораздо чаще. Видимо вся эта беда связана с нестабильным временем затраченым на обновлением экрана средствами OpenGL, под виндой это стабильно 10-15мсек (очень редко 0.5мсек), под линуксом всегда прыгает 0.2-1мсек. замерено rdtsc на одноядерном проце.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить плаванье onMouseMove

Сообщение zub » 17.09.2010 13:26:01

Совершенно случайно обнаружил - мышку подергивает когда фоном запущена опера... и почемута эта подлая опера отъедает 10-20-30% cpu даже ничего не отображая...
если запускать программу в гордом одиночестве - всё нормально! надо завязывать лазать на freepascal.ru во время отладки))
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить плаванье onMouseMove

Сообщение B4rr4cuda » 18.09.2010 04:37:31

надо завязывать лазать на freepascal.ru во время отладки))

можно заюзать фаерфокс, который будет жрать память, а не цпу, что положительно скажется на тестах :lol:
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: как победить торможение onMouseMove

Сообщение frost_asm » 24.10.2010 23:25:55

zub писал(а):странно, но оказалось достаточно подписать окно на GDK_POINTER_MOTION_HINT_MASK
Код: Выделить всё
gtk_widget_add_events (Widget,GDK_POINTER_MOTION_HINT_MASK);

и всё заработало ровно

многоуважаемый zub не могли бы вы привести пример использования этой функции именно для проекта в lazarus.
frost_asm
новенький
 
Сообщения: 26
Зарегистрирован: 28.12.2008 22:40:36

Re: как победить плаванье onMouseMove

Сообщение zub » 24.10.2010 23:37:43

У меня так:
Код: Выделить всё
uses
  ......
  x,xlib,
  gtk2,gdk2,
  ......

gtk_widget_add_events (PGtkWidget(PtrUInt(Handle)),GDK_POINTER_MOTION_HINT_MASK);


возможно в uses чтото лишнее, не проверял. Вызываю один раз при инициализации OpenGL
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: как победить плаванье onMouseMove

Сообщение frost_asm » 25.10.2010 00:06:47

Спасибо))
frost_asm
новенький
 
Сообщения: 26
Зарегистрирован: 28.12.2008 22:40:36

Re: как победить плаванье onMouseMove

Сообщение zub » 26.10.2010 22:46:29

Незачто))
наконецто допер окончательно в чем дело
плаванье мышки полечилось gtk_widget_add_events (или асинхронной перерисовкой, вне onMouseMove - оба варианта работают хорошо), а дерганость отключением эффектов рабочего стола
Сами конкретные эффекты были все выключены, стояла лишь общая галка "использовать эффекты раб.стола", что нехило придушивало мое приложение. Теперь мышиноопенгльный тест под линуксом выглядит так: короткий разбег, ровная беготня, торможение об противоположную стенку монитора. Юзать программу в линуксе стало приятней чем в винде, независимо от того сколько опер и прочей лабуды запущено фоном)), осталось ее дописать.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 59

Рейтинг@Mail.ru