1 ! Copyright (C) 2005, 2008 Eduardo Cavazos and Slava Pestov
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.c-types arrays ui ui.gadgets
4 ui.gestures ui.backend ui.clipboards ui.gadgets.worlds ui.render
5 assocs kernel math namespaces opengl sequences strings x11.xlib
6 x11.events x11.xim x11.glx x11.clipboard x11.constants
7 x11.windows io.encodings.string io.encodings.ascii
8 io.encodings.utf8 combinators debugger command-line qualified
9 math.vectors classes.tuple opengl.gl threads math.geometry.rect ;
13 SINGLETON: x11-ui-backend
15 : XA_NET_WM_NAME ( -- atom ) "_NET_WM_NAME" x-atom ;
17 TUPLE: x11-handle window glx xic ;
19 C: <x11-handle> x11-handle
21 M: world expose-event nip relayout ;
23 M: world configure-event
24 over configured-loc >>window-loc
25 swap configured-dim >>dim
26 ! In case dimensions didn't change
38 { HEX: FF08 "BACKSPACE" }
43 { HEX: FFFF "DELETE" }
49 { HEX: FF55 "PAGE_UP" }
50 { HEX: FF56 "PAGE_DOWN" }
64 : key-code ( keysym -- keycode action? )
65 dup key-codes at [ t ] [ 1string f ] ?if ;
67 : event-modifiers ( event -- seq )
68 XKeyEvent-state modifiers modifier ;
70 : key-down-event>gesture ( event world -- string gesture )
72 handle>> xic>> lookup-string
73 >r swap event-modifiers r> key-code <key-down> ;
75 M: world key-down-event
76 [ key-down-event>gesture ] keep world-focus
77 [ send-gesture ] keep swap [ user-input ] [ 2drop ] if ;
79 : key-up-event>gesture ( event -- gesture )
80 dup event-modifiers swap 0 XLookupKeysym key-code <key-up> ;
83 >r key-up-event>gesture r> world-focus send-gesture drop ;
85 : mouse-event>gesture ( event -- modifiers button loc )
86 dup event-modifiers over XButtonEvent-button
89 M: world button-down-event
90 >r mouse-event>gesture >r <button-down> r> r>
93 M: world button-up-event
94 >r mouse-event>gesture >r <button-up> r> r>
97 : mouse-event>scroll-direction ( event -- pair )
106 >r dup mouse-event>scroll-direction swap mouse-event-loc r>
109 M: world enter-event motion-event ;
111 M: world leave-event 2drop forget-rollover ;
113 M: world motion-event
114 >r dup XMotionEvent-x swap XMotionEvent-y 2array r>
115 move-hand fire-motion ;
117 M: world focus-in-event
119 dup handle>> xic>> XSetICFocus focus-world ;
121 M: world focus-out-event
123 dup handle>> xic>> XUnsetICFocus unfocus-world ;
125 M: world selection-notify-event
126 [ handle>> window>> selection-from-event ] keep
127 world-focus user-input ;
129 : supported-type? ( atom -- ? )
130 { "UTF8_STRING" "STRING" "TEXT" }
131 [ x-atom = ] with contains? ;
133 : clipboard-for-atom ( atom -- clipboard )
135 { [ dup XA_PRIMARY = ] [ drop selection get ] }
136 { [ dup XA_CLIPBOARD = ] [ drop clipboard get ] }
140 : encode-clipboard ( string type -- bytes )
141 XSelectionRequestEvent-target
142 XA_UTF8_STRING = utf8 ascii ? encode ;
144 : set-selection-prop ( evt -- )
146 [ XSelectionRequestEvent-requestor ] keep
147 [ XSelectionRequestEvent-property ] keep
148 [ XSelectionRequestEvent-target ] keep
149 >r 8 PropModeReplace r>
151 XSelectionRequestEvent-selection
152 clipboard-for-atom contents>>
153 ] keep encode-clipboard dup length XChangeProperty drop ;
155 M: world selection-request-event
156 drop dup XSelectionRequestEvent-target {
157 { [ dup supported-type? ] [ drop dup set-selection-prop send-notify-success ] }
158 { [ dup "TARGETS" x-atom = ] [ drop dup set-targets-prop send-notify-success ] }
159 { [ dup "TIMESTAMP" x-atom = ] [ drop dup set-timestamp-prop send-notify-success ] }
160 [ drop send-notify-failure ]
163 M: x11-ui-backend (close-window) ( handle -- )
165 dup glx>> destroy-glx
166 window>> dup unregister-window
169 M: world client-event
170 swap close-box? [ ungraft ] [ drop ] if ;
172 : gadget-window ( world -- )
173 dup window-loc>> over rect-dim glx-window
174 over "Factor" create-xic <x11-handle>
175 2dup window>> register-window
178 : wait-event ( -- event )
179 QueuedAfterFlush events-queued 0 > [
181 None XFilterEvent zero? [ drop wait-event ] unless
186 M: x11-ui-backend do-events
187 wait-event dup XAnyEvent-window window dup
188 [ [ 2dup handle-event ] assert-depth ] when 2drop ;
190 : x-clipboard@ ( gadget clipboard -- prop win )
192 find-world handle>> window>> ;
194 M: x-clipboard copy-clipboard
195 [ x-clipboard@ own-selection ] keep
198 M: x-clipboard paste-clipboard
199 >r find-world handle>> window>>
200 r> atom>> convert-selection ;
202 : init-clipboard ( -- )
203 XA_PRIMARY <x-clipboard> selection set-global
204 XA_CLIPBOARD <x-clipboard> clipboard set-global ;
206 : set-title-old ( dpy window string -- )
207 dup [ 127 <= ] all? [ XStoreName drop ] [ 3drop ] if ;
209 : set-title-new ( dpy window string -- )
211 XA_NET_WM_NAME XA_UTF8_STRING 8 PropModeReplace
212 r> utf8 encode dup length XChangeProperty drop ;
214 M: x11-ui-backend set-title ( string world -- )
215 handle>> window>> swap dpy get -rot
216 3dup set-title-old set-title-new ;
218 M: x11-ui-backend set-fullscreen* ( ? world -- )
219 handle>> window>> "XClientMessageEvent" <c-object>
220 tuck set-XClientMessageEvent-window
221 swap _NET_WM_STATE_ADD _NET_WM_STATE_REMOVE ?
222 over set-XClientMessageEvent-data0
223 ClientMessage over set-XClientMessageEvent-type
224 dpy get over set-XClientMessageEvent-display
225 "_NET_WM_STATE" x-atom over set-XClientMessageEvent-message_type
226 32 over set-XClientMessageEvent-format
227 "_NET_WM_STATE_FULLSCREEN" x-atom over set-XClientMessageEvent-data1
228 >r dpy get root get 0 SubstructureNotifyMask r> XSendEvent drop ;
231 M: x11-ui-backend (open-window) ( world -- )
233 handle>> window>> dup set-closable map-window ;
235 M: x11-ui-backend raise-window* ( world -- )
237 dpy get swap window>> XRaiseWindow drop
240 M: x11-ui-backend select-gl-context ( handle -- )
242 dup window>> swap glx>> glXMakeCurrent
243 [ "Failed to set current GLX context" throw ] unless ;
245 M: x11-ui-backend flush-gl-context ( handle -- )
246 dpy get swap window>> glXSwapBuffers ;
248 M: x11-ui-backend ui ( -- )
252 stop-after-last-window? on
260 M: x11-ui-backend beep ( -- )
261 dpy get 100 XBell drop ;
263 x11-ui-backend ui-backend set-global
265 [ "DISPLAY" system:os-env "ui" "listener" ? ]
266 main-vocab-hook set-global