Я использую расширение XShm для рисования и управления изображениями в Linux.
Чтобы не мерцать экран, я передаю send_event = TRUE
в XShmPutImage
, а затем жду события с XIfEvent сразу после вызова XScmPutImage.
Таким образом, я делаю блокировку изображения, чтобы не изменять изображение до тех пор, пока оно не будет отображаться на поверхности окна.
Обычно все работает нормально. Но иногда, когда у меня интенсивный рисунок рисунка, кажется, что событие никогда не приходит и процедура рисования висит.
Где искать проблему? Используется ли XIfEvent для этой задачи? Как событие может исчезнуть из очереди сообщений?
Возможно ли, что XShmPutImage не отправит событие (если send_event = TRUE) или отправить событие, отличное от ShmCompletion
, при некоторых обстоятельствах? (например, при некоторой внутренней ошибке или что-то в этом роде)
EDIT:
После еще нескольких исследований я обнаружил, что такие зависания происходят только тогда, когда оконный менеджер интенсивно генерирует события в окне. Например, когда я изменяю размер окна, перетаскивая его углы.
EDIT2:
Я пробовал несколько способов решить эту проблему, но безуспешно. В конце я был вынужден использовать некоторый тайм-аут и отменить ожидание через некоторое время. Но, конечно, это грязный хак, и я все равно хочу его исправить.
Итак, что может быть причиной того, что XShmPutImage не отправляет событие, если send_event = TRUE или возможно, что это событие исчезнет из очереди сообщений?
EDIT3:
Вот сомнительный код (FASM):
cinvoke XShmPutImage, ......, TRUE
.loop:
lea eax, [.event]
cinvoke XCheckTypedEvent, [Display], [ShmCompletionEvent], eax
test eax, eax
jz .loop ; there is no message
NB: XShmPutImage всегда возвращает TRUE, независимо от того, зависает ли проверка события или нет, поэтому я не выполнил проверку ошибок после нее.
EDIT4:
Из-за запроса я отправляю весь код функции рисования. В коде используются некоторые макро-библиотеки FASM, но, по крайней мере, идеи ясны (надеюсь)
Обратите внимание, что этот код содержит обходной код, который ограничивает событие, ожидающее только 20 мс. Без этого таймаута цикл ожидания просто висит навсегда. Номер события XShm получен путем вызова XShmGetEventBase
, как рекомендовано в документации Xshm.
; Draws the image on a OS provided window surface.
proc DrawImageRect, .where, .pImage, .xDst, .yDst, .xSrc, .ySrc, .width, .height
.event XEvent
rb 256
begin
pushad
mov esi, [.pImage]
test esi, esi
jz .exit
mov ebx, [esi+TImage.ximage]
cinvoke XCreateGC, [hApplicationDisplay], [.where], 0, 0
mov edi, eax
cinvoke XShmPutImage, [hApplicationDisplay], [.where], edi, [esi+TImage.ximage], [.xSrc], [.ySrc], [.xDst], [.yDst], [.width], [.height], TRUE
stdcall GetTimestamp
lea esi, [eax+20] ; 20ms timeout
.loop:
lea eax, [.event]
cinvoke XCheckTypedEvent, [hApplicationDisplay], [ShmCompletionEvent], eax
test eax, eax
jnz .finish
stdcall GetTimestamp
cmp eax, esi
jb .loop
.finish:
cinvoke XFreeGC, [hApplicationDisplay], edi
.exit:
popad
return
endp
И вот код основного цикла событий приложения.
Процедура __ProcessOneSystemEvent
просто отправляет события в объекты GUI и игнорирует все события, которые она не использует. Он не обрабатывает ShmCompletionEvent
вообще.
Все окна, созданные в приложении, имеют маску событий:
ExposureMask+FocusChangeMask+KeyPressMask+KeyReleaseMask+ButtonPressMask+ButtonReleaseMask+EnterWindowMask+LeaveWindowMask+PointerMotionMask+StructureNotifyMask
proc ProcessSystemEvents
.event XEvent
rb 256
begin
push ebx ecx edx
.event_loop:
; check for quit
get eax, [pApplication], TApplication:MainWindow
test eax, eax
jz .continue
cmp dword [eax], 0
jne .continue
cinvoke XFlush, [hApplicationDisplay]
xor eax, eax
mov [fGlobalTerminate], 1
stc
pop edx ecx ebx
return
.continue:
cinvoke XPending, [hApplicationDisplay]
test eax, eax
jz .noevents
push edi ecx
lea edi, [.event]
mov ecx, sizeof.XEvent/4
xor eax, eax
rep stosd
pop ecx edi
lea ebx, [.event]
cinvoke XNextEvent, [hApplicationDisplay], ebx
stdcall __ProcessOneSystemEvent, ebx
jmp .event_loop
.noevents:
clc
pop edx ecx ebx
return
endp
Полный исходный код доступен в репозитории, но это очень большой проект, который нелегкий для навигации. Рассматриваемый источник находится в режиме регистрации 8453c99b1283def8
.
Файлы: "freshlib/graphics/images.asm" и "freshlib/graphics/Linux/images.asm" относятся к графическому изображению.
Файлы: "freshlib/gui/Main.asm" и "freshlib/gui/Linux/Main.asm" относятся к общей обработке событий в приложении.