-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdemo15
executable file
·1279 lines (1078 loc) · 40.5 KB
/
demo15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
# -*- scheme -*-
#|
# demo15 - wayland client in fibers, targeted for V0.15.0
#
# usage:
# $ ./demo15
# runs for 10 seconds : hit Return key to see different text
# or
# $ ./demo15 1
# $ telnet localhost 37146
# scheme@(guile-user)> (done)
TOP=`pwd`
LD_LIBRARY_PATH=$TOP:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
GUILE_LOAD_PATH=$TOP:$GUILE_LOAD_PATH
export GUILE_LOAD_PATH
# Fibers uses some deprecated bit ops:
export GUILE_WARN_DEPRECATED=no
GDB_PFX=""
if [ $# -gt 0 ]; then
case "$1" in
--debug) GDB_PFX="gdb --args"; shift ;;
esac
fi
#export PATH=/opt/guile-rel/3.0.8/bin:$PATH
guild compile -O0 $0
exec $GDB_PFX guile $0 "$@"
|#
!#
;; Copyright (C) 2022-2023 Matthew Wette
;;
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
;; License as published by the Free Software Foundation; either
;; version 3 of the License, or (at your option) any later version.
;;
;; This library is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public License
;; along with this library; if not, see <http://www.gnu.org/licenses/>.
;; NOTES
;; 1 wayland reserved obj-id's 0 and 1, this adds 2 for registry
;; 2 registry: interface-string-name => #(name interface version)
;; 3 globals-dict: interface-symbol-name => client-id
;; 4 globals: list of globals
;; 5 potential race-condition between allocating id's, as servers wants
;; to see them in sequence (so odd)
;; TODO
;; 2 figure out how to really use polling so we don't need
;; to call sleep or watch guile run at 100% all the time
;; 3 think about add sync / done (see sync-and-wait)
;; 5 think about context and how we update
;; keyboard, pointer, buffer
;; a) maybe dispatch generates an event stream
;; event stream = (event . (
;; send to model!
;; b) fold state-trans state events
;; c) named-let loop with high-volatility state as args <= in-work
;; DONE
;; 1 add a layer somehow so callers don't need to pass rq-iobuf 0
;; need a way to block the sender until a number of messages have
;; built up
;; 4 scan .xml enums
;; if mman not in guile:
(use-modules (rnrs bytevectors))
(use-modules (system foreign))
(use-modules (ice-9 atomic))
(use-modules (srfi srfi-9))
(use-modules (extras))
(use-modules (wl-client))
(use-modules (kbd-parse))
(use-modules (system repl server))
(use-modules (system repl coop-server))
(use-modules ((fibers) #:renamer (lambda (s) (if (eq? s 'sleep) 'fsleep s))))
(use-modules (fibers scheduler))
(use-modules (fibers conditions))
(use-modules (fibers channels))
(use-modules (ice-9 format))
(use-modules (ice-9 pretty-print))
(define (fferr fmt . args)
(apply format (current-error-port) fmt args))
(define (sferr fmt . args)
(apply simple-format (current-error-port) fmt args)
(force-output (current-error-port)))
(define (pperr exp) (pretty-print exp (current-error-port)))
;; ============================================================================
(define wl-debug #f)
;; per-interface vectors of handlers by opcode
(define my-handler-vec-vec (make-wl-handler-vec-vec))
(define obj-vec-sz 1000)
;; vector of object-id => ref into wl-decoder-vec (decoder by opcode)
(define object-decoders-vec (make-vector obj-vec-sz #f))
;; vector of object-id => ref into wl-handler-vec (handler by opcode)
(define object-handlers-vec (make-vector obj-vec-sz #f))
;; vector of objec-id => user-defined value
(define object-value-vec (make-vector obj-vec-sz #f))
(define alloc-id
(let* ((box (make-atomic-box 2))
(inc (lambda (id) (let ((id (1+ id))) (if (>= id obj-vec-sz) 2 id))))
(ret (lambda (id) (vector-set! object-value-vec id #t) id)))
(vector-set! object-value-vec 0 #t)
(vector-set! object-value-vec 1 #t)
(lambda ()
(let loop ((exp (atomic-box-ref box)))
(let* ((cur (atomic-box-compare-and-swap! box exp (inc exp))))
(if (eq? cur exp)
(if (vector-ref object-value-vec cur) (alloc-id) (ret cur))
(loop (atomic-box-ref box))))))))
(define globals-dict (make-hash-table 97))
;; pre-defined object ids
(define null-id 0)
(define display-id 1)
(define registry-id 2)
;; interface-name => #(name interface version)
(define registry (make-hash-table))
;; set-object!
(define* (set-object! obj-id obj-iface #:optional (obj-value #t))
(let* ((ob-indx obj-id) (if-name obj-iface)
(if-name (if (string? if-name) (string->symbol if-name) if-name))
(if-indx (assq-ref wl-index-dict if-name))
(if-decoders (vector-ref wl-decoder-vec-vec if-indx))
(if-handlers (vector-ref my-handler-vec-vec if-indx)))
(when wl-debug (sferr "object: ~S is ~S\n" obj-id obj-iface))
(vector-set! object-decoders-vec ob-indx if-decoders)
(vector-set! object-handlers-vec ob-indx if-handlers)
(vector-set! object-value-vec ob-indx obj-value)))
(define (set-object-value! obj-id obj-value)
(vector-set! object-value-vec obj-id obj-value))
(define (doc-str obj-id opcode)
(let* ((dec-vec (vector-ref object-decoders-vec obj-id))
(decoder (and dec-vec (vector-ref dec-vec opcode))))
(and (procedure? decoder) (procedure-documentation decoder))))
;; set-event-handler! 'wl_displaly 'get_registry proc => prev-proc
(define (set-event-handler! interface event proc)
(let* ((if-indx (assq-ref wl-index-dict interface))
(opcode (assq-ref (vector-ref wl-opcode-dict-vec if-indx) event))
(if-handlers (vector-ref my-handler-vec-vec if-indx))
(evt-handler (vector-ref if-handlers opcode)))
(vector-set! if-handlers opcode proc)
evt-handler))
(define (dispatch obj-id opcode bv ix cm)
(let* ((dec-vec (vector-ref object-decoders-vec obj-id))
(decoder (and dec-vec (vector-ref dec-vec opcode)))
(hlr-vec (vector-ref object-handlers-vec obj-id))
(handler (and hlr-vec (vector-ref hlr-vec opcode))))
(if (and decoder handler)
(call-with-values (lambda () (decoder obj-id bv ix cm)) handler)
(begin
(sferr "dispatch: missing decoder or handler: id=~S op=~S\n"
obj-id opcode)
(sferr " dec-vec?=~S decoder?=~S hlr-vec?=~S handler?=~S\n"
(and dec-vec #t) (and decoder #t)
(and hlr-vec #t) (and handler #t))))))
;; ====================================
(eval-when (expand load eval)
(define (gen-id x . args)
(define (any->str obj)
(if (string? obj) obj (symbol->string (syntax->datum obj))))
(datum->syntax x (string->symbol (string-join (map any->str args) "")))))
(define-syntax define-wl-request
(lambda (x)
(syntax-case x ()
((_ iface meth arg ...)
#`(define (#,(gen-id x #'iface ":" #'meth) obj-id arg ...)
(when wl-debug (sferr "=> ~S:~S ...\n" 'iface 'meth))
(put-message rq-chan
(lambda ()
(#,(gen-id x "encode-" #'iface ":" #'meth)
obj-id rq-iobuf 0 arg ...))))))))
(define-syntax wl-event
(lambda (x)
(syntax-case x ()
((_ iface meth)
#`(set-event-handler!
'iface 'meth
(lambda args
(when wl-debug (sferr "<= ~S:~S\n" 'iface 'meth))
(apply #,(gen-id x "handle-" #'iface ":" #'meth) args)))))))
(define-syntax fix-arg
(syntax-rules (<>)
((_ id <>) id)
((_ id ex) ex)))
(define-syntax gen-id-using
(syntax-rules (<>)
((_ (proc arg ...))
(let ((id (alloc-id)))
(proc (fix-arg id arg) ...) id))))
(define-syntax add-id
(syntax-rules (<>)
((_ iface (proc arg ...))
(let ((id (alloc-id)))
(set-object! id iface)
(proc (fix-arg id arg) ...)
id))
((_ iface value (proc arg ...))
(let ((id (alloc-id)))
(set-object! id iface value)
(proc (fix-arg id arg) ...)
id))
))
;; ====================================
;; order of lifetime: shortest to longest
;; cursor cursor
;; ro-wo dpy-ix drw-x dpy-cr drw-cr <bufr>
;; ro-ws ft-asc ft-dsc ft-hei ft-wid <font>
;; ro-wn smp-id srf-id
;; rs-wn xrf-id top-id *seat-id*
;; ro-ws width height format
;; rs-wn port
;; may want closure for
;; (create_buffer smp-id <> drw-ix width height stride format) => id
;; (set-ctx-mkbuf! (lambda () ...)) ;; => (values buf-id drw-ix)
;;
;; or [changed? drw-ix drw-cr dpy-ix dpy-cr rest]
#|
(define-record-type <ctx>
changed
rest)
(define-record-type
|#
(display "add seat-id\n")
(define-record-type <ctx>
(%make-ctx changed
port bvec
width height format
smp-id srf-id xrf-id top-id
dpy-ix drw-ix dpy-cr drw-cr
ft-asc ft-dsc ft-hei ft-wid)
ctx?
(changed ctx-changed? set-ctx-changed!)
;;
(dpy-ix ctx-dpy-ix set-ctx-dpy-ix!)
(drw-ix ctx-drw-ix set-ctx-drw-ix!)
(dpy-cr ctx-dpy-cr set-ctx-dpy-cr!)
(drw-cr ctx-drw-cr set-ctx-drw-cr!)
;;
(ft-asc ctx-ft-asc)
(ft-dsc ctx-ft-dsc)
(ft-hei ctx-ft-hei)
(ft-wid ctx-ft-wid)
;;
(smp-id ctx-smp-id set-ctx-smp-id!)
(srf-id ctx-srf-id set-ctx-srf-id!)
(xrf-id ctx-xrf-id set-ctx-xrf-id!)
(top-id ctx-top-id set-ctx-top-id!)
;;
(width ctx-width set-ctx-width!)
(height ctx-height set-ctx-height!)
(format ctx-format set-ctx-format!)
(port ctx-port)
(bvec ctx-bvec)
)
(define (make-ctx . args)
(apply %make-ctx #t args))
(define (ctx-changed! ctx)
(set-ctx-changed! ctx #t))
(define (ctx-committed! ctx)
(set-ctx-changed! ctx #f))
;; ====================================
(define rq-chan #f) ; channel for requests to sender
(define ev-chan #f) ; channel for events to model
(define rq-iobuf #f)
(define ev-iobuf #f)
;; --- wl_display
(define-wl-request wl_display sync callback)
(define-wl-request wl_display get_registry registry)
;; wl_display:error
(define (handle-wl_display:error obj-id object_id code message)
(sferr "wl-error:~A:~A: ~A\n" object_id code message))
;; wl_display:delete_id
(define (handle-wl_display:delete_id obj-id id)
;;(sferr "delete_id ~S\n" id)
;;(vector-set! object-handlers-vec id #f)
(vector-set! object-value-vec id #f)
#f)
;; --- wl_registry
(define globals '())
(define-wl-request wl_registry bind name interface version id)
(define (bind-global interface)
(unless (string? interface) (error "bind-global wants string argument"))
(let* ((info (hash-ref registry interface)))
(cond
(info
(let* ((name (vector-ref info 0))
(version (vector-ref info 2))
(id (alloc-id))
(iface (string->symbol interface)))
(hashq-set! globals-dict iface id)
(set-object! id iface)
(wl_registry:bind registry-id name interface version id)
id))
(else
(sferr "no info for interface ~S\n" interface)
#f))))
(define (handle-wl_registry:global obj-id name interface version)
(set! globals (cons interface globals))
(hash-set! registry interface (vector name interface version)))
(define (handle-wl_registry:global_remove obj-id name)
;;(sferr "global_removed: ~S\n" name)
(if #f #f))
;; --- wl_callback
(define (handle-wl_callback:done obj-id callback-data)
;; callback-data is event serial generated by compositor
(let ((val (vector-ref object-value-vec obj-id)))
(if (condition? val) (signal-condition! val))
(vector-set! object-value-vec obj-id #f))
;;(sferr "got callback for obj-id ~S w/ data ~S\n" obj-id callback-data)
(if #f #f))
;; --- wl_compositor
(define-wl-request wl_compositor create_surface id)
(define-wl-request wl_compositor create_region id)
;; --- wl_shm_pool
(define-wl-request wl_shm_pool create_buffer
id offset width height stride format)
(define-wl-request wl_shm_pool destroy)
(define-wl-request wl_shm_pool resize size)
;; --- wl_shm
(define-wl-request wl_shm create_pool id fd size)
;; informs of allowed formats (argb8888 = 0, xrgb8888 = 1)
(define formats '())
(define (handle-wl_shm:format obj-id format)
(set! formats (cons format formats)))
;; --- wl_buffer
(define-wl-request wl_buffer destroy)
(define (handle-wl_buffer:release obj-id)
;;(sferr "wl_buffer:release ~s\n" obj-id)
;; actually, once released, we can reuse (i.e., assign back to dpy-id)
;; FIXME: We should reuse and not destroy:
(wl_buffer:destroy obj-id)
(vector-set! object-value-vec obj-id #f))
;; --- wl_data_offer
;; --- wl_data_source
;; --- wl_data_device
;; --- wl_data_device_manager
;; --- wl_shell
;; --- wl_shell_surface
;; --- wl_surface
(define-wl-request wl_surface destroy)
(define-wl-request wl_surface attach buffer x y)
;;(define-wl-request wl_surface damage x y width height) deprecated
(define-wl-request wl_surface frame callback)
(define-wl-request wl_surface set_opaque_region region)
(define-wl-request wl_surface set_input_region region)
(define-wl-request wl_surface commit)
(define-wl-request wl_surface set_buffer_transform transform)
(define-wl-request wl_surface set_buffer_scale scale)
(define-wl-request wl_surface damage_buffer x y width height)
(define-wl-request wl_surface offset x y)
(define (handle-wl_surface:enter obj-id output)
;;(sferr "wl_surface:enter\n")
(if #f #f))
(define (handle-wl_surface:leave obj-id output)
(sferr "wl_surface:leave\n")
(if #f #f))
;; --- wl_seat
(define-wl-request wl_seat get_pointer id)
(define-wl-request wl_seat get_keyboard id)
(define-wl-request wl_seat get_touch id)
(define-wl-request wl_seat release)
(define (handle-wl_seat:capabilities obj-id capabilities)
(define (cap? caps key)
(positive? (logior caps (assq-ref wl_seat:capability-enum key))))
(if (not (cap? capabilities 'keyboard)) (sferr "warning: no keyboard\n"))
(if (not (cap? capabilities 'pointer)) (sferr "warning: no pointer\n"))
(if (cap? capabilities 'touch) (sferr "got touch\n"))
(if #f #f))
(define (handle-wl_seat:name obj-id name)
;;(sferr "wl_seat:name ~S\n" name)
(if #f #f))
;; --- wl_pointer
;; on my laptop see lots of (motion,frame) sequences
;; only get these events when pointer is in window
(define mouse-x 0)
(define mouse-y 0)
(define mouse-b 0)
(define-wl-request wl_pointer set_cursor serial surface hotspot_x hotspot_y)
(define-wl-request wl_pointer release)
(define (handle-wl_pointer:enter obj-id serial surface surface_x surface_y)
(sferr "pointer:enter\n")
(if #f #f))
(define (handle-wl_pointer:leave obj-id serial surface)
(sferr "pointer:leave\n")
(if #f #f))
(display "motion will be scaled down by factor of 250\n")
;; ^ This seems undocumented and not something to be retrived from
;; the compositor. I wonder if we should just set it. ??
(define (handle-wl_pointer:motion obj-id time surface_x surface_y)
;;(sferr "pointer:motion\n")
(set! mouse-x (quotient surface_x 250))
(set! mouse-y (quotient surface_y 250))
;;(put-message ev-chan `(motion ,mouse-x ,mouse-y))
(if #f #f))
(define (handle-wl_pointer:button obj-id serial time button state)
;;(sferr "pointer:button ~S ~S\n" button state)
(put-message ev-chan (vector 'click mouse-x mouse-y))
(if #f #f))
(define (handle-wl_pointer:axis obj-id time axis value)
(sferr "pointer:axis\n")
(if #f #f))
(define (handle-wl_pointer:frame obj-id)
;;(sferr "pointer:frame\n")
(if #f #f))
(define (handle-wl_pointer:axis_source obj-id axis_source)
(sferr "pointer:axis_source\n")
(if #f #f))
(define (handle-wl_pointer:axis_stop obj-id time axis)
(sferr "pointer:axis_stop\n")
(if #f #f))
(define (handle-wl_pointer:axis_discrete obj-id axis discrete)
(sferr "pointer:axis_discrete\n")
(if #f #f))
;; --- wl_keyboard
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Keymaps.html
;; emacs:
;; key : shift control meta alt hyper super
;; mouse: click drag down
(define kbd-mods 0)
(define kbd-base-v #f)
(define kbd-shft-v #f)
;; (define (kbd-levels #f)
;; (define (kbd-nlevel #f)
(define (set-mod key)
(case key
((S-) (set! kbd-mods (logior kbd-mods #x1000000))) ;; 2^25, shift
((C-) (set! kbd-mods (logior kbd-mods #x2000000))) ;; 2^26, control
((M-) (set! kbd-mods (logior kbd-mods #x4000000))) ;; 2^27, meta
((A-) (set! kbd-mods (logior kbd-mods #x0200000))) ;; 2^22, alt
((H-) (set! kbd-mods (logior kbd-mods #x0800000))) ;; 2^24, hyper
((Z-) (set! kbd-mods (logior kbd-mods #x0400000))) ;; 2^23, super
(else #f)))
(define (clr-mod key)
(case key
((S-) (set! kbd-mods (logand kbd-mods #x6FFFFFF))) ;; 2^25, shift
((C-) (set! kbd-mods (logand kbd-mods #x5FFFFFF))) ;; 2^26, control
((M-) (set! kbd-mods (logand kbd-mods #x3FFFFFF))) ;; 2^27, meta
((A-) (set! kbd-mods (logand kbd-mods #x7DFFFFF))) ;; 2^22, alt
((H-) (set! kbd-mods (logand kbd-mods #x77FFFFF))) ;; 2^24, hyper
((Z-) (set! kbd-mods (logand kbd-mods #x7BFFFFF))) ;; 2^23, super
(else #f)))
(define mod-syms '(alt super hyper shift control meta))
(define (uncap-mods mods)
(logand mods #x6FFFFFF))
;; #\b #\B =>
;; (control #\b) on control+b
;; (#\B) on shift+b
(define (encase/mods base shft)
(define (doit ksym mods)
(let loop ((seq (list ksym)) (mask #x0200000) (syms mod-syms))
(if (null? syms) (list->vector seq)
(loop (if (positive? (logand mask mods)) (cons (car syms) seq) seq)
(* 2 mask) (cdr syms)))))
(if (and (char? base) shft (positive? (logand kbd-mods #x1000000)))
(doit shft (uncap-mods kbd-mods))
(doit base kbd-mods)))
(define-wl-request wl_keyboard release)
(define (handle-wl_keyboard:keymap obj-id format fd size)
;;(sferr "got keymap obj ~A format ~A fd ~A size ~A\n" obj-id format fd size)
;; ASSUME format is xkb
(let* ((size (1- size)) ;; trim trailing nul
(mem (mmap 0 size PROT_READ MAP_PRIVATE fd 0))
(kmpair (get-keymaps (utf8->string mem))))
(set! kbd-base-v (car kmpair))
(set! kbd-shft-v (cdr kmpair))
(close-fdes fd))
(if #f #f))
(define (handle-wl_keyboard:enter obj-id serial surface keys)
;; modifiers coming ...
(sferr "kb enter, keys = ~S\n" keys)
(if #f #f))
(define (handle-wl_keyboard:leave obj-id serial surface)
(sferr "kb leave\n")
(if #f #f))
(define (handle-wl_keyboard:key obj-id serial time key state)
;;(fferr "mods: ~x\n" kbd-mods)
(let ((base (or (vector-ref kbd-base-v key) key))
(shft (or (vector-ref kbd-shft-v key) key)))
(if (zero? state)
(or (and (symbol? base) (clr-mod base))
(put-message ev-chan (encase/mods base shft)))
(or (and (symbol? base) (set-mod base))))
;;(if (and (positive? state) (equal? base #\return)) (doit))
;;(sferr "key ~A: ~S => ~S, ~A\n"(if (zero? state) "rel" "prs") key base)
(if #f #f)))
(define (handle-wl_keyboard:modifiers obj-id serial
mods_depressed mods_latched mods_locked
group)
(unless (and (zero? mods_depressed) (zero? mods_latched))
(fferr "modifiers: prsd=0x~x lchd=0x~x grp=~s\n"
mods_depressed mods_latched group))
(if #f #f))
(define (handle-wl_keyboard:repeat_info obj-id rate delay)
(if #f #f))
;; --- wl_touch
(define (handle-wl_touch:down obj-id serial time surface id x y)
(sferr "touch:down \n")
(if #f #f))
(define (handle-wl_touch:up obj-id serial time id)
(sferr "touch:up \n")
(if #f #f))
(define (handle-wl_touch:motion obj-id time id x y)
(sferr "touch:motion \n")
(if #f #f))
(define (handle-wl_touch:frame obj-id id x y)
(sferr "touch:frame \n")
(if #f #f))
(define (handle-wl_touch:cancel obj-id)
(sferr "touch:cancel \n")
(if #f #f))
(define-wl-request wl_touch release)
(define (handle-wl_touch:shape obj-id id major minor)
(sferr "touch:shape \n")
(if #f #f))
(define (handle-wl_touch:orientation obj-id id orientation)
(sferr "touch:orientation \n")
(if #f #f))
;; --- wl_output
(define (handle-wl_output:geometry obj-id x y physical_width physical_height
subpixel make model transform)
;;(sferr "output::geometry called\n")
(if #f #f))
(define (handle-wl_output:mode obj-id flags width height refresh)
;;(sferr "output::mode called\n")
(if #f #f))
(define (handle-wl_output:done . args)
;;(sferr "output::done called\n")
(if #f #f))
(define (handle-wl_output:scale . args)
;;(sferr "output::scale called\n")
(if #f #f))
(define-wl-request wl_output release)
(define (handle-wl_output:name . args)
;;(sferr "output::name called\n")
(if #f #f))
(define (handle-wl_output:description . args)
;;(sferr "output::description called\n")
(if #f #f))
;; --- wl_region
;; --- wl_subcompositor
;; --- wl_subsurface
;; --- xdg_wm_base
(define-wl-request xdg_wm_base destroy)
(define-wl-request xdg_wm_base create_positioner id)
(define-wl-request xdg_wm_base get_xdg_surface id surface)
(define-wl-request xdg_wm_base pong serial)
(define (handle-xdg_wm_base:ping obj-id serial)
;;(sferr "xdg_wm_base:ping -> pong\n")
(xdg_wm_base:pong obj-id serial))
;; --- xdg_positioner
(define-wl-request xdg_positioner destroy)
(define-wl-request xdg_positioner set_size width height)
(define-wl-request xdg_positioner set_anchor_rect x y width height)
(define-wl-request xdg_positioner set_gravity gravity)
(define-wl-request xdg_positioner set_constraint_adjustment
constraint_adjustment)
(define-wl-request xdg_positioner set_offset x y)
(define-wl-request xdg_positioner set_reactive)
(define-wl-request xdg_positioner set_parent_size parent_width parent_height)
(define-wl-request xdg_positioner set_parent_configure serial)
;; --- xdg_surface
(define-wl-request xdg_surface destroy)
(define-wl-request xdg_surface get_toplevel id)
(define-wl-request xdg_surface get_popup id parent positioner)
(define-wl-request xdg_surface set_window_geometry x y width height)
(define-wl-request xdg_surface ack_configure serial)
(define (handle-xdg_surface:configure obj-id serial)
(xdg_surface:ack_configure obj-id serial) ; before or after?
(let ((obj (vector-ref object-value-vec obj-id)))
(cond
((ctx? obj) (xrf-config obj))
((procedure? obj) (obj obj-id))
(else #f))))
;; --- xdg_toplevel
(define-wl-request xdg_toplevel destroy)
(define-wl-request xdg_toplevel set_parent parent)
(define-wl-request xdg_toplevel set_title title)
(define-wl-request xdg_toplevel set_app_id app_id)
(define-wl-request xdg_toplevel show_window_menu seat serial x y)
(define-wl-request xdg_toplevel move seat serial)
(define-wl-request xdg_toplevel resize seat serial edges)
(define-wl-request xdg_toplevel set_max_size width height)
(define-wl-request xdg_toplevel set_min_size width height)
(define-wl-request xdg_toplevel set_maximized)
(define-wl-request xdg_toplevel unset_maximized)
(define-wl-request xdg_toplevel set_fullscreen output)
(define-wl-request xdg_toplevel unset_fullscreen)
(define-wl-request xdg_toplevel set_minimized)
(define (handle-xdg_toplevel:configure obj-id width height states)
;; states in an array:
;;(sferr "FIXME! toplevel:configure wid=~S hei=~S\n" width height)
;;(sferr " states=~S\n" states)
(if #f #f))
(define (handle-xdg_toplevel:close obj-id width height states)
(sferr "FIXME! toplevel:close ~S ~S\n" width height)
(sferr " states=~S\n" states)
(if #f #f))
(define (handle-xdg_toplevel:configure_bounds obj-id width height)
;; hint for largest area : sent before configure event
;;(sferr "toplevel:configure_bounds wid=~S hei=~S\n" width height)
(if #f #f))
;; --- xdg_popup
;; --- install
(define (install-handlers)
(wl-event wl_display error)
(wl-event wl_display delete_id)
(wl-event wl_registry global)
(wl-event wl_registry global_remove)
(wl-event wl_callback done)
(wl-event wl_shm format)
(wl-event wl_buffer release)
(wl-event wl_surface enter)
(wl-event wl_surface leave)
(wl-event wl_seat capabilities)
(wl-event wl_seat name)
(wl-event wl_pointer enter)
(wl-event wl_pointer leave)
(wl-event wl_pointer motion)
(wl-event wl_pointer button)
(wl-event wl_pointer axis)
(wl-event wl_pointer frame)
(wl-event wl_pointer axis_source)
(wl-event wl_pointer axis_stop)
(wl-event wl_pointer axis_discrete)
(wl-event wl_keyboard keymap)
(wl-event wl_keyboard enter)
(wl-event wl_keyboard leave)
(wl-event wl_keyboard key)
(wl-event wl_keyboard modifiers)
(wl-event wl_keyboard repeat_info)
(wl-event wl_touch down)
(wl-event wl_touch up)
(wl-event wl_touch motion)
(wl-event wl_touch frame)
(wl-event wl_touch cancel)
(wl-event wl_touch shape)
(wl-event wl_touch orientation)
(wl-event wl_output geometry)
(wl-event wl_output mode)
(wl-event wl_output done)
(wl-event wl_output scale)
(wl-event wl_output name)
(wl-event wl_output description)
(wl-event xdg_wm_base ping)
(wl-event xdg_surface configure)
(wl-event xdg_toplevel configure)
(wl-event xdg_toplevel close)
(wl-event xdg_toplevel configure_bounds)
(if #f #f))
(define (init-object-pool)
(set-object! display-id 'wl_display)
(set-object! registry-id 'wl_registry))
(define (sync-and-wait)
(let ((id (alloc-id)) (cd (make-condition)))
(set-object! id 'wl_callback cd)
(wl_display:sync display-id id)
(wait cd)))
;; (define-syntax atomic-sequence ...
;; (encode-foo x y z) (encode-
;; (put-message rq-chan msgs)
;;; (sync)
;;; (wait)
(define shm-id #f)
(define comp-id #f)
(define seat-id #f)
(define base-id #f)
(define (get-registry)
(wl_display:get_registry display-id registry-id))
(define (init-globals)
(unless comp-id (set! comp-id (bind-global "wl_compositor")))
(unless shm-id (set! shm-id (bind-global "wl_shm")))
(unless seat-id (set! seat-id (bind-global "wl_seat")))
(unless base-id (set! base-id (bind-global "xdg_wm_base")))
#t)
;; === agents ========================
(define wl-sock #f)
(define io-debug #f)
(define socket-path
(let ((dir (getenv "XDG_RUNTIME_DIR"))
(dpy (getenv "WAYLAND_DISPLAY")))
(and dir dpy (string-append dir "/" dpy))))
(define (connect-display)
(let* ((path socket-path)
(style (logior SOCK_STREAM SOCK_CLOEXEC))
(sock (socket PF_UNIX style 0))
(conn (connect sock AF_UNIX path)))
;;(setvbuf sock 'none)
(fcntl sock F_SETFL (logior O_NONBLOCK (fcntl sock F_GETFL)))
(set! rq-iobuf (make-bytevector 1024))
(set! ev-iobuf (make-bytevector 1024))
sock))
(define (sender)
(sferr "sender starting ...\n")
(let loop ((n-sent 0) (n-left 0) (cm #f) (rqq '()))
(fsleep 0.01)
(cond
((positive? n-left)
(when io-debug
(if cm
(sferr "S: sending ~S bytes w/ fd=~A:\n" n-left (dec-fd cm))
(sferr "S: sending ~S bytes:\n" n-left))
(if (<= n-left 32)
(sferr " ~A\n" (fmtbv/x rq-iobuf n-sent n-left 4))
(sferr " ~A ...\n" (fmtbv/x rq-iobuf n-sent 32 4))))
(let ((n (sendmsg wl-sock rq-iobuf n-sent n-left cm)))
(when io-debug " n-sent:~S n-left:~S n:~S\n" n-sent n-left n)
(loop (+ n-sent n) (- n-left n) #f rqq)))
((pair? rqq)
(call-with-values (car rqq)
(lambda (ln cm)
(when io-debug (sferr "S: stage msg ln ~S cm ~S\n" ln cm))
(loop 0 ln cm (cdr rqq)))))
((get-message rq-chan) =>
(lambda (req)
(when io-debug (sferr "S: queue msg ~S queued\n" (1+ (length rqq))))
(loop n-sent n-left cm (cons req rqq))))
(else
(sferr "sender says wtf\n")))))
(define (receiver)
(sferr "receiver starting ...\n")
(let loop ((n-have 0) (object-id #f) (msg-size 8) (opcode #f) (control #f))
(cond
((< n-have msg-size)
(let* ((res (recvmsg! wl-sock ev-iobuf n-have))
(n-read (vector-ref res 0))
(control (or control (vector-ref res 1)))
(flags (vector-ref res 2)))
;;(when io-debug (if (positive? n-read) (sferr "recv ~S B\n" n-read)))
(when (zero? n-read) (fsleep 0.1)) ; SLEEP HERE
(loop (+ n-have n-read) object-id msg-size opcode control)))
((not object-id)
(let* ((object-id (bytevector-u32-native-ref ev-iobuf 0))
(word1 (bytevector-u32-native-ref ev-iobuf 4))
(msg-size (bytevector-u16-native-ref ev-iobuf msg-size-offset))
(opcode (bytevector-u16-native-ref ev-iobuf opcode-offset)))
(loop n-have object-id msg-size opcode control)))
(else
(when io-debug (sferr "R: dispatch ~S ~S\n" object-id opcode))
(dispatch object-id opcode ev-iobuf 8 control)
(cond
((> n-have msg-size)
(bytevector-copy! ev-iobuf msg-size ev-iobuf 0 (- n-have msg-size))
(loop (- n-have msg-size) #f 8 opcode control))
(else
(loop (- n-have msg-size) #f 8 opcode #f)))))))
(define (monitor)
(sferr "monitor starting ...\n")
(let* ((server (spawn-coop-repl-server)))
(let loop ()
(poll-coop-repl-server server)
(yield-current-task)
(fsleep 0.1)
(loop))))
(define done-cond #f)
(define (done)
(and done-cond (signal-condition! done-cond)))
;; === appl ===========================
;; move starts with xdg_toplevel:move
(use-modules (ffi ffi-help-rt))
(use-modules (ffi cairo))
(define appl-ctx #f)
(define appl-kbd-id #f)
(define appl-ptr-id #f)
(define appl-tch-id #f)
(define (wl-format->cairo wlf)
(case wlf
((0 argb8888) 'CAIRO_FORMAT_ARGB32)
((1 xrgb8888) 'CAIRO_FORMAT_RGB24)))
(define argb8888 0)
(define xrgb8888 1)
(define gran #x100000) ; bufsize granularity
(define deg (/ M_PI 180.0))
(define (draw-pane-1 cr wid hei)
(let* ((lw/2 1.0) (bar 44.0) (rad 16.0))
(cairo_save cr)
;; bottom
(cairo_move_to cr lw/2 bar)
(cairo_line_to cr (- wid lw/2) bar)
(cairo_line_to cr (- wid lw/2) (- hei lw/2))
(cairo_line_to cr lw/2 (- hei lw/2))
(cairo_close_path cr)
(cairo_set_source_rgb cr 0.9 0.9 0.9)
(cairo_fill_preserve cr)
(cairo_set_line_width cr (* 2 lw/2))
(cairo_set_source_rgb cr 0.1 0.1 0.1)
(cairo_stroke cr)
;; top
(cairo_move_to cr lw/2 bar)
(cairo_line_to cr lw/2 (+ rad lw/2))
(cairo_arc cr (+ rad lw/2) (+ rad lw/2) rad (* -180.0 deg) (* -90.0 deg))
(cairo_line_to cr (- wid rad lw/2) lw/2)
(cairo_arc cr (- wid rad lw/2) (+ rad lw/2) rad (* -90.0 deg) (* 0.0 deg))
(cairo_line_to cr (- wid lw/2) bar)
(cairo_close_path cr)
(cairo_set_source_rgb cr 0.6 0.6 0.6)
(cairo_fill_preserve cr)
(cairo_set_line_width cr (* 2 lw/2))
(cairo_set_source_rgb cr 0.1 0.1 0.1)
(cairo_stroke cr)
;; text
(let* ((title "geemacs")
(face "serif")
(slant 'CAIRO_FONT_SLANT_NORMAL)
(weight 'CAIRO_FONT_WEIGHT_NORMAL)
(ftsize 20.0)
(extents (make-cairo_text_extents_t))
(wid/2 (/ wid 2.0))
(bar/2 (/ bar 2.0))
)
(cairo_select_font_face cr face slant weight)
(cairo_set_font_size cr ftsize)
(cairo_text_extents cr title (pointer-to extents))
;; bearing is vector from start of text on baseline
;; to upper left corner of bounding box
(cairo_move_to cr
(+ wid/2 (fh-object-ref extents 'x_bearing)
(- (/ (fh-object-ref extents 'width) 2.0)))
(+ bar/2