]> gitweb.factorcode.org Git - factor.git/blob - basis/ui/ui.factor
no-word-errors now print better
[factor.git] / basis / ui / ui.factor
1 ! Copyright (C) 2006, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays assocs io kernel math models namespaces make dlists
4 deques sequences threads sequences words continuations init
5 combinators hashtables concurrency.flags sets accessors calendar fry
6 ui.gadgets ui.gadgets.private ui.gadgets.worlds ui.gadgets.tracks
7 ui.gestures ui.backend ui.render ui.text ui.text.private ;
8 IN: ui
9
10 ! Assoc mapping aliens to gadgets
11 SYMBOL: windows
12
13 : window ( handle -- world ) windows get-global at ;
14
15 : window-focus ( handle -- gadget ) window world-focus ;
16
17 : register-window ( world handle -- )
18     #! Add the new window just below the topmost window. Why?
19     #! So that if the new window doesn't actually receive focus
20     #! (eg, we're using focus follows mouse and the mouse is not
21     #! in the new window when it appears) Factor doesn't get
22     #! confused and send workspace operations to the new window,
23     #! etc.
24     swap 2array windows get-global push
25     windows get-global dup length 1 >
26     [ [ length 1- dup 1- ] keep exchange ] [ drop ] if ;
27
28 : unregister-window ( handle -- )
29     windows global [ [ first = not ] with filter ] change-at ;
30
31 : raised-window ( world -- )
32     windows get-global
33     [ [ second eq? ] with find drop ] keep
34     [ nth ] [ delete-nth ] [ nip ] 2tri push ;
35
36 : focus-gestures ( new old -- )
37     drop-prefix <reversed>
38     lose-focus swap each-gesture
39     gain-focus swap each-gesture ;
40
41 : focus-world ( world -- )
42     t >>focused?
43     dup raised-window
44     focus-path f focus-gestures ;
45
46 : unfocus-world ( world -- )
47     f >>focused?
48     focus-path f swap focus-gestures ;
49
50 M: world graft*
51     [ (open-window) ]
52     [ [ title>> ] keep set-title ]
53     [ request-focus ] tri ;
54
55 : reset-world ( world -- )
56     #! This is used when a window is being closed, but also
57     #! when restoring saved worlds on image startup.
58     [ fonts>> clear-assoc ]
59     [ unfocus-world ]
60     [ f >>handle drop ] tri ;
61
62 : (ungraft-world) ( world -- )
63     {
64         [ handle>> select-gl-context ]
65         [ fonts>> free-fonts ]
66         [ hand-clicked close-global ]
67         [ hand-gadget close-global ]
68     } cleave ;
69
70 M: world ungraft*
71     [ (ungraft-world) ]
72     [ handle>> (close-window) ]
73     [ reset-world ] tri ;
74
75 : find-window ( quot -- world )
76     windows get values
77     [ gadget-child swap call ] with find-last nip ; inline
78
79 : init-ui ( -- )
80     <dlist> \ graft-queue set-global
81     <dlist> \ layout-queue set-global
82     <dlist> \ gesture-queue set-global
83     V{ } clone windows set-global ;
84
85 : restore-gadget-later ( gadget -- )
86     dup graft-state>> {
87         { { f f } [ ] }
88         { { f t } [ ] }
89         { { t t } [ { f f } >>graft-state ] }
90         { { t f } [ dup unqueue-graft { f f } >>graft-state ] }
91     } case graft-later ;
92
93 : restore-gadget ( gadget -- )
94     dup restore-gadget-later
95     children>> [ restore-gadget ] each ;
96
97 : restore-world ( world -- )
98     dup reset-world restore-gadget ;
99
100 : update-hand ( world -- )
101     dup hand-world get-global eq?
102     [ hand-loc get-global swap move-hand ] [ drop ] if ;
103
104 : layout-queued ( -- seq )
105     [
106         in-layout? on
107         layout-queue [
108             dup layout find-world [ , ] when*
109         ] slurp-deque
110     ] { } make prune ;
111
112 : redraw-worlds ( seq -- )
113     [ dup update-hand draw-world ] each ;
114
115 : send-queued-gestures ( -- )
116     gesture-queue [ send-queued-gesture notify-queued ] slurp-deque ;
117
118 : update-ui ( -- )
119     [
120         [
121             notify-queued
122             layout-queued
123             redraw-worlds
124             send-queued-gestures
125         ] assert-depth
126     ] [ ui-error ] recover ;
127
128 SYMBOL: ui-thread
129
130 : ui-running ( quot -- )
131     t \ ui-running set-global
132     [ f \ ui-running set-global ] [ ] cleanup ; inline
133
134 : ui-running? ( -- ? )
135     \ ui-running get-global ;
136
137 : update-ui-loop ( -- )
138     [ ui-running? ui-thread get-global self eq? and ]
139     [ ui-notify-flag get lower-flag update-ui ]
140     [ ] while ;
141
142 : start-ui-thread ( -- )
143     [ self ui-thread set-global update-ui-loop ]
144     "UI update" spawn drop ;
145
146 : open-world-window ( world -- )
147     dup pref-dim >>dim dup relayout graft ;
148
149 : open-window ( gadget title -- )
150     f <world> open-world-window ;
151
152 : set-fullscreen? ( ? gadget -- )
153     find-world set-fullscreen* ;
154
155 : fullscreen? ( gadget -- ? )
156     find-world fullscreen* ;
157
158 : raise-window ( gadget -- )
159     find-world raise-window* ;
160
161 HOOK: close-window ui-backend ( gadget -- )
162
163 M: object close-window
164     find-world [ ungraft ] when* ;
165
166 : start-ui ( quot -- )
167     call notify-ui-thread start-ui-thread ;
168
169 [
170     f \ ui-running set-global
171     <flag> ui-notify-flag set-global
172 ] "ui" add-init-hook
173
174 HOOK: (with-ui) ui-backend ( quot -- )
175
176 : restore-windows ( -- )
177     [
178         windows get [ values ] [ delete-all ] bi
179         [ restore-world ] each
180         forget-rollover
181     ] (with-ui) ;
182
183 : restore-windows? ( -- ? )
184     windows get empty? not ;
185
186 : with-ui ( quot -- )
187     ui-running? [ call ] [ '[ init-ui @ ] (with-ui) ] if ;
188
189 HOOK: beep ui-backend ( -- )