sync-event.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. ;; Thread-safe event queue *******************************************
  2. (define-record-type sync-x-event :sync-x-event
  3. (really-make-sync-x-event event next)
  4. sync-x-event?
  5. (event sync-x-event-event)
  6. (next really-next-sync-x-event really-set-next-sync-x-event))
  7. (define (make-sync-x-event event)
  8. (really-make-sync-x-event event (make-placeholder)))
  9. (define (next-sync-x-event sync-x-event pred)
  10. (let ((next (placeholder-value (really-next-sync-x-event sync-x-event))))
  11. (if (pred (sync-x-event-event next))
  12. next
  13. (next-sync-x-event next pred))))
  14. (define (set-next-sync-x-event! sync-x-event next-sync-x-event)
  15. (placeholder-set!
  16. (really-next-sync-x-event sync-x-event)
  17. next-sync-x-event))
  18. (define *most-recent-sync-x-event* (make-sync-x-event 'no-event))
  19. (define *most-recent-lock* (make-lock))
  20. (define (init-sync-x-events dpy)
  21. (spawn
  22. (lambda ()
  23. (let lp ()
  24. (let ((next (wait-event dpy)))
  25. (if next
  26. (with-lock *most-recent-lock*
  27. (lambda ()
  28. (set-next-sync-x-event! *most-recent-sync-x-event*
  29. (make-sync-x-event next))
  30. (set! *most-recent-sync-x-event*
  31. (placeholder-value (really-next-sync-x-event
  32. *most-recent-sync-x-event*))))))
  33. (lp)))) "sync-x-events-loop")
  34. 'init-sync-x-events)
  35. (define (most-recent-sync-x-event)
  36. *most-recent-sync-x-event*)
  37. ;; High-Level Event-Dispatcher ***************************************
  38. ;; contains (display window event-mask) triples
  39. (define *event-requests* '())
  40. (define *event-requests-lock* (make-lock))
  41. (define (make-request display window event-mask)
  42. (list display window event-mask))
  43. (define (add-request! req)
  44. (with-lock *event-requests-lock*
  45. (lambda ()
  46. (set! *event-requests*
  47. (cons req *event-requests*))
  48. (select-requests))))
  49. (define (remove-request! req)
  50. (with-lock *event-requests-lock*
  51. (lambda ()
  52. (set! *event-requests*
  53. (filter (lambda (r) (not (eq? r req))) *event-requests*))
  54. (select-requests))))
  55. (define request:display car)
  56. (define request:window cadr)
  57. (define request:event-mask caddr)
  58. (define (event-masks-union masks)
  59. (fold-right (lambda (m res)
  60. (enum-set-union m res))
  61. (event-mask)
  62. masks))
  63. (define (select-requests)
  64. (let loop ((rest *event-requests*))
  65. (if (not (null? rest))
  66. (let ((r (car rest)))
  67. (call-with-values
  68. (lambda ()
  69. (partition (lambda (r2)
  70. ;; find all with the same display and window
  71. (and (eq? (request:display r2) (request:display r))
  72. (eq? (request:window r2) (request:window r))))
  73. (cdr rest)))
  74. (lambda (same rest)
  75. (let ((mask (event-masks-union (map request:event-mask
  76. (cons r same)))))
  77. (if (window-exists? (request:display r) (request:window r))
  78. (display-select-input (request:display r) (request:window r)
  79. mask)))
  80. (loop rest)))))))
  81. (define (call-with-event-channel display window event-mask fun)
  82. (let ((r (make-request display window event-mask))
  83. (x-event-channel (make-channel))
  84. (filter-control-channel (make-channel))
  85. (dead?-box (cons #f #f)))
  86. (spawn-event-filter x-event-channel filter-control-channel
  87. display window event-mask fun dead?-box)
  88. ;; we send the first sync-event to the thread to really have the
  89. ;; most recent one, without keeping it in an environment.
  90. (send filter-control-channel (most-recent-sync-x-event))
  91. (let ((first? #t))
  92. (dynamic-wind
  93. (lambda ()
  94. (add-request! r)
  95. (if first?
  96. (set! first? #f)
  97. (warn "throwing back into call-with-event-channel")))
  98. (lambda () (call-with-values
  99. (lambda () (fun x-event-channel))
  100. (lambda args
  101. (apply values args))))
  102. (lambda ()
  103. (set-car! dead?-box #t)
  104. (remove-request! r))))))
  105. (define (true x) #t)
  106. (define (spawn-event-filter out-channel control-channel display window event-mask fun dead?-box)
  107. (let ((pred (lambda (e)
  108. (and (eq? (any-event-display e) display)
  109. (matches-event-mask? window event-mask e)))))
  110. (spawn (lambda ()
  111. ;; the first sync-event is send to us through the channel
  112. (let loop ((se (receive control-channel)))
  113. (if (not (car dead?-box))
  114. (let ((nse (next-sync-x-event se true)))
  115. (if (not (car dead?-box))
  116. (if (pred (sync-x-event-event nse))
  117. (begin (send out-channel (sync-x-event-event nse))
  118. (loop nse))
  119. (loop nse)))))))
  120. (cons 'spawn-event-filter fun))))
  121. (define (matches-event-mask? window event-mask event)
  122. (let ((type (any-event-type event)))
  123. (cond
  124. ;; keymap-event has no window element
  125. ((eq? type (event-type keymap-notify))
  126. (enum-set-member? event-mask (event-mask-item keymap-state)))
  127. ;; other events must have at least the correct window
  128. ((not (eq? window (any-event-window event)))
  129. #f)
  130. ;; these event are send always because they do not depend on a mask
  131. ((or (eq? type (event-type client-message))
  132. (eq? type (event-type mapping-notify))
  133. (eq? type (event-type selection-clear))
  134. (eq? type (event-type selection-notify))
  135. (eq? type (event-type selection-request)))
  136. #t)
  137. ;; these do not depend an an event-mask too, but on a flag in GC,
  138. ;; so we sent it too
  139. ((or (eq? type (event-type graphics-expose))
  140. (eq? type (event-type no-expose)))
  141. #t)
  142. ;; OwnerGrabButtonMask only generates extra events between a
  143. ;; ButtonPress and ButtonRelease event and does not be respected
  144. ;; here
  145. ;; PointerMotionHintMask only has an effect if one of the
  146. ;; ButtonMotion Masks or PointerMotionMask is selected, so we
  147. ;; don't have to take a look at it here.
  148. ;; for the rest one of the event-mask items must match the type
  149. ((any (lambda (mask-item)
  150. (matches-event-mask-2? type window event mask-item))
  151. (enum-set->list event-mask))
  152. #t)
  153. (else #f))))
  154. (define (matches-event-mask-2? type window event mask-item)
  155. (cond
  156. ((or (eq? mask-item (event-mask-item button-motion))
  157. (eq? mask-item (event-mask-item button-1-motion))
  158. (eq? mask-item (event-mask-item button-2-motion))
  159. (eq? mask-item (event-mask-item button-3-motion))
  160. (eq? mask-item (event-mask-item button-4-motion))
  161. (eq? mask-item (event-mask-item button-5-motion)))
  162. (eq? type (event-type motion-notify)))
  163. ((eq? mask-item (event-mask-item button-press))
  164. (eq? type (event-type button-press)))
  165. ((eq? mask-item (event-mask-item button-release))
  166. (eq? type (event-type button-release)))
  167. ((eq? mask-item (event-mask-item colormap-change))
  168. (eq? type (event-type colormap-notify)))
  169. ((eq? mask-item (event-mask-item enter-window))
  170. (eq? type (event-type enter-notify)))
  171. ((eq? mask-item (event-mask-item leave-window))
  172. (eq? type (event-type leave-notify)))
  173. ((eq? mask-item (event-mask-item exposure))
  174. (eq? type (event-type expose)))
  175. ((eq? mask-item (event-mask-item focus-change))
  176. (or (eq? type (event-type focus-in))
  177. (eq? type (event-type focus-out))))
  178. ((eq? mask-item (event-mask-item keymap-state))
  179. (eq? type (event-type keymap-notify)))
  180. ((eq? mask-item (event-mask-item key-press))
  181. (eq? type (event-type key-press)))
  182. ((eq? mask-item (event-mask-item key-release))
  183. (eq? type (event-type key-release)))
  184. ((eq? mask-item (event-mask-item pointer-motion))
  185. (eq? type (event-type motion-notify)))
  186. ((eq? mask-item (event-mask-item property-change))
  187. (eq? type (event-type property-notify)))
  188. ((eq? mask-item (event-mask-item resize-redirect))
  189. (eq? type (event-type resize-request)))
  190. ((eq? mask-item (event-mask-item structure-notify))
  191. (or (and (eq? type (event-type circulate-notify))
  192. (eq? window (circulate-event-event event))
  193. (eq? window (circulate-event-window event)))
  194. (and (eq? type (event-type configure-notify))
  195. (eq? window (configure-event-event event))
  196. (eq? window (configure-event-window event)))
  197. (and (eq? type (event-type destroy-notify))
  198. (eq? window (destroy-window-event-event event))
  199. (eq? window (destroy-window-event-window event)))
  200. (and (eq? type (event-type gravity-notify))
  201. (eq? window (gravity-event-event event))
  202. (eq? window (gravity-event-window event)))
  203. (and (eq? type (event-type map-notify))
  204. (eq? window (map-event-event event))
  205. (eq? window (map-event-window event)))
  206. (and (eq? type (event-type reparent-notify))
  207. (eq? window (reparent-event-event event))
  208. (eq? window (reparent-event-window event)))
  209. (and (eq? type (event-type unmap-notify))
  210. (eq? window (unmap-event-event event))
  211. (eq? window (unmap-event-window event)))))
  212. ((eq? mask-item (event-mask-item substructure-notify))
  213. (or (and (eq? type (event-type circulate-notify))
  214. (eq? window (circulate-event-event event))
  215. (not (eq? window (circulate-event-window event))))
  216. (and (eq? type (event-type configure-notify))
  217. (eq? window (configure-event-event event))
  218. (not (eq? window (configure-event-window event))))
  219. (and (eq? type (event-type create-notify))
  220. (eq? window (create-window-event-parent event))
  221. (not (eq? window (create-window-event-window event))))
  222. (and (eq? type (event-type destroy-notify))
  223. (eq? window (destroy-window-event-event event))
  224. (not (eq? window (destroy-window-event-window event))))
  225. (and (eq? type (event-type gravity-notify))
  226. (eq? window (gravity-event-event event))
  227. (not (eq? window (gravity-event-window event))))
  228. (and (eq? type (event-type map-notify))
  229. (eq? window (map-event-event event))
  230. (not (eq? window (map-event-window event))))
  231. (and (eq? type (event-type reparent-notify))
  232. (eq? window (reparent-event-event event))
  233. (not (eq? window (reparent-event-window event))))
  234. (and (eq? type (event-type unmap-notify))
  235. (eq? window (unmap-event-event event))
  236. (not (eq? window (unmap-event-window event))))))
  237. ((eq? mask-item (event-mask-item substructure-redirect))
  238. (or (eq? type (event-type circulate-request))
  239. (eq? type (event-type configure-request))
  240. (eq? type (event-type map-request))))
  241. ((eq? mask-item (event-mask-item visibility-change))
  242. (eq? type (event-type visibility-notify)))
  243. (else #f)))