1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; UrForth level
1: self
-hosting
32-bit Forth compiler
3 ;; Copyright
(C
) 2020 Ketmar Dark
// Invisible Vector
5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6 ;; X11 OOF GUI
-- BaseWindow class implementation
7 ;; (included from
"xog-base-window.f")
8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 ;; we need locals
for rounded rect drawing methods
14 false value
(basewin
-debug
-show
-events?
)
16 false constant xog
-window
-debug
-child
-delete?
17 false constant xog
-window
-debug
-child
-create?
18 false constant xog
-window
-debug
-dispatch?
19 false constant xog
-window
-debug
-kbfocus?
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;; destroy all windows when X11 display is closed
25 ..: (xog
-dpy
-before
-close
) ( -- )
26 BaseWindow
::invoke BaseWindow
(display
-closing
)
30 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 BaseWindow method
: (debug
-id
.) ( -- )
32 ." <" class
-name type
." :" self
.hex8
." :" winid
.hex8
." :" get
-caption safe
-type
." >"
35 BaseWindow method
: (debug
-dump
-children
) ( indent
-- )
36 dup spaces
(debug
-id
.) cr
37 first
-child begin ?dup
while
38 over
2+ over invoke
(debug
-dump
-children
) invoke next
-sibling repeat
43 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 ;; global window list management
46 BaseWindow method
: (register
) ( -- )
47 (winlist
-tail
) to (prev
-win
) self
to (winlist
-tail
)
48 \
." registered window " win
. ." self=0x" self
.hex8
." winlist-tail=0x" (winlist
-tail
) .hex8 cr
51 BaseWindow method
: (unregister
) ( -- )
52 (winlist
-tail
) self
= if
53 (prev
-win
) to (winlist
-tail
)
56 (winlist
-tail
) begin dup invoke
(prev
-win
) dup
while dup self
= not
-while nip repeat
57 not
-?abort
" cannot find previous window"
58 (prev
-win
) swap var^
(prev
-win
) !
62 BaseWindow method
: find
-by
-wid
( wid
-- ptr
//0 )
63 dup ifnot exit
endif ;; just in case
64 (winlist
-tail
) begin dup
while 2dup invoke winid
= not
-while invoke
(prev
-win
) repeat nip
68 ;; destroy all windows when X11 display is closed
69 BaseWindow method
: (display
-closing
) ( -- )
70 \
." killing all windows...\n"
71 begin
(winlist
-tail
) ?dup
while (winlist
-tail
) invoke
(destroy
) repeat
75 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
76 ;; find window and dispatch the event
78 ;; this calls parent sink
, then does self
79 BaseWindow method
: (dispatch
-event
-sink
) ( event
-- )
81 [ xog
-window
-debug
-dispatch?
] [IF]
82 ." going up; curr is " (debug
-id
.) cr
84 parent ?dup
if (event
) swap invoke
(dispatch
-event
-sink
) endif
85 [ xog
-window
-debug
-dispatch?
] [IF]
86 ." calling \`(sink-event)\`; curr is " (debug
-id
.) cr
88 (event
) @
if (sink
-event
) endif
92 BaseWindow method
: (dispatch
-event
-internal
) ( event
-- )
95 parent ?dup
if (event
) swap invoke
(dispatch
-event
-sink
) endif
97 [ xog
-window
-debug
-dispatch?
] [IF]
98 ." calling \`(process-event)\`; curr is " (debug
-id
.) cr
100 (event
) @ ifnot exit
endif (process
-event
)
102 parent begin dup
while (event
) @
while
103 [ xog
-window
-debug
-dispatch?
] [IF]
104 ." calling \`(bubble-event)\`; curr is " dup invoke
(debug
-id
.) cr
106 (event
) over var^
(event
) ! ;; hack
: set
(event
) in current instptr
107 dup invoke
(bubble
-event
)
108 dup var^
(event
) 0! ;; and clear it
, why not
109 invoke parent repeat drop
112 BaseWindow method
: dispatch
-event
( event
-- dispatch
-success
-flag
)
113 dup XAnyEvent display @ xog
-dpy
= ifnot drop false exit
endif
114 dup XAnyEvent window @ find
-by
-wid dup
if
115 [ xog
-window
-debug
-dispatch?
] [IF]
116 endcr
." *********** dispatching winid " over XAnyEvent window @
.hex8
." to " dup invoke
(debug
-id
.) cr
117 ." EVENT: type=" over @
. over @ get
-x11
-event
-type
-name type cr
119 invoke
(dispatch
-event
-internal
) true
121 [ xog
-window
-debug
-dispatch?
] [IF]
122 endcr
." cannot dispatch winid " over XAnyEvent window @
.hex8 cr
123 ." EVENT: type=" over @
. over @ get
-x11
-event
-type
-name type cr
130 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131 ;; various helper methods
134 BaseWindow method
: prev
-sibling
( -- childobj
// 0 )
136 invoke first
-child
0 swap begin
( prev curr
) dup
while
137 dup self
= if drop exit
endif
138 nip dup invoke next
-sibling repeat nip
142 BaseWindow method
: top
-parent
( -- obj
)
143 parent ?dup
if invoke top
-parent
else self
endif
147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148 ;; children list management
151 ;; simple assign
, no checks
, no nothing
152 BaseWindow method
: (focused
-child
!) ( childobj
-- ) to focused
-child
;
155 BaseWindow method
: (remove
-child
) ( childobj
-- )
156 \ ?dup ifnot exit
endif
157 dup not
-?abort
" cannot orphan already orphan window"
158 dup invoke parent self
<> ?abort
" cannot orphan alien window"
159 dup focused
-child
= if 0 to focused
-child
endif ;; just in case
160 dup invoke prev
-sibling
( childobj prevchildobj
/0 )
161 over var^ parent
0! ;; orphan it
162 ?dup
if over invoke next
-sibling swap var^ next
-sibling
! ;; remove from the list
163 else dup invoke next
-sibling
to first
-child
endif ;; first one
168 BaseWindow method
: (append
-child
) ( childobj
-- )
169 ?dup ifnot exit
endif
170 dup invoke parent ?abort
" cannot parent already parented window"
171 dup invoke next
-sibling ?abort
" cannot parent already parented window"
172 self over var^ parent
! ;; adopt it
174 begin dup invoke next
-sibling ?dup
while nip repeat
176 else to first
-child
endif ;; first child
179 BaseWindow method
: append
-child
( childobj
-- )
181 focused
-child ifnot dup invoke can
-focus?
if dup
to focused
-child
endif endif drop
185 ;; called from MapNotify
186 BaseWindow method
: (map
-children
) ( -- )
187 is
-valid? ifnot exit
endif
188 first
-child begin ?dup
while
189 dup invoke visible? over invoke mapped? or
if
190 [ xog
-window
-debug
-child
-create?
] [IF]
191 endcr
." mapchild: " dup invoke
(debug
-id
.) cr
195 dup invoke
(map
-children
)
197 invoke next
-sibling repeat
201 BaseWindow method
: (create
-children
) ( -- )
202 is
-valid? ifnot exit
endif
203 first
-child begin ?dup
while
204 dup invoke visible? over invoke mapped? or
if
205 [ xog
-window
-debug
-child
-create?
] [IF]
206 endcr
." createchild: " dup invoke
(debug
-id
.) cr
208 self over invoke create
-ex not
-?abort
" cannot create child window"
210 invoke next
-sibling repeat
214 BaseWindow method
: (focus
-child
) ( -- )
215 focused
-child ?dup
if
216 \ endcr
." ---self " (debug
-id
.) ." is going to focus child " dup invoke
(debug
-id
.) cr
219 \ endcr
." ***FOCUSING: " (debug
-id
.) cr
225 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
226 ;; children traversal
229 ;; this does depth
-first traversal
230 ;; cfa
: ( -- stopflag
)
231 ;; self is set
to the corresponding window
232 BaseWindow method
: foreach
-child
( cfa
-- exitcode
)
233 first
-child begin ?dup
while ( cfa childobj
)
234 2dup
2>r invoke foreach
-child ?dup
if 2rdrop exit
endif
235 2r
> invoke next
-sibling repeat
236 execute
-tail
;; self is last
240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
241 ;; default window class and title
243 BaseWindow method
: (get
-class
) ( -- addr count
) " UrForth BaseWindow" ;
244 BaseWindow method
: get
-caption
( -- addr count
) " UrForth Window" ;
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;; send various internal events
250 BaseWindow method
: (send
-close
-event
) ( -- )
251 XEvent @sizeof ralloca
>r
252 r@ XEvent @sizeof erase
253 ClientMessage r@ XClientMessageEvent type
!
254 r@ XClientMessageEvent send_event
1!
255 winid r@ XClientMessageEvent window
!
256 XOF_INTERNAL_CLOSE r@ XClientMessageEvent message_type
!
257 32 r@ XClientMessageEvent
format !
258 r@
0 true winid xog
-dpy XSendEvent drop
259 rdrop XEvent @sizeof rdealloca
263 BaseWindow method
: (send
-expose
-event
) ( -- )
264 XEvent @sizeof ralloca
>r
265 r@ XEvent @sizeof erase
266 Expose r@ XExposeEvent type
!
267 r@ XExposeEvent send_event
1!
268 winid r@ XExposeEvent window
!
271 width r@ XExposeEvent width
!
272 height r@ XExposeEvent height
!
273 r@
0 true winid xog
-dpy XSendEvent drop
274 rdrop XEvent @sizeof rdealloca
278 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
279 ;; reset all internal fields
281 BaseWindow method
: init
( -- )
289 0 to min
-width
0 to min
-height
290 0 to max
-width
0 to max
-height
291 false
to motion
-events?
295 512 to width
256 to height
297 0 to winid
0 to wingc
0 to winpixmap
299 false
to invalidate
-sent?
304 true
to double-buffered?
305 true
to (first
-paint?
)
307 0 to current
-fg
-color
0 to current
-bg
-color
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 ;; low
-level window methods
314 BaseWindow method
: (get
-keysym
) ( event
-- keysym
)
315 0 swap XKeyEvent keycode @ xog
-dpy XKeycodeToKeysym
318 BaseWindow method
: (destroy
-cleanup
) ( -- )
319 (deinit
-gc
) (deinit
-pixmap
) (unregister
) on
-destroyed init
322 BaseWindow method
: (init
-gc
) ( -- )
323 0 0 my
-drawable xog
-dpy XCreateGC
to wingc drop
;; "drop" due
to "..."
326 xog
-black
-color
1+ to current
-bg
-color
327 xog
-white
-color
1+ to current
-fg
-color
328 ;; background is black
, foreground is white
329 xog
-black
-color set
-bg
-color
330 xog
-white
-color set
-color
333 BaseWindow method
: (deinit
-gc
) ( -- )
334 wingc ?dup
if xog
-dpy XFreeGC
0 to wingc
endif
337 BaseWindow method
: (init
-pixmap
) ( -- )
338 (deinit
-pixmap
) xog
-dpy
if
339 xog
-dpy DefaultScreen xog
-dpy XDefaultDepth height
1 max width
1 max winid xog
-dpy XCreatePixmap
344 BaseWindow method
: (deinit
-pixmap
) ( -- )
345 winpixmap
if xog
-dpy
if winpixmap xog
-dpy XFreePixmap
endif 0 to winpixmap
endif
348 BaseWindow method
: (set
-xhints
) ( -- )
349 (get
-class
) ensure
-asciiz
>r
351 XClassHint @sizeof ralloca
>r
352 r@ XClassHint @sizeof erase
353 dup r@ XClassHint res_name
! r@ XClassHint res_class
!
354 r@
;; class hints address
356 XWMHints @sizeof ralloca
>r
357 r@ XWMHints @sizeof erase
358 InputHint r@ XWMHints flags
!
359 true r@ XWMHints input
!
360 r@
;; WM hints address
362 XSizeHints @sizeof ralloca
>r
363 r@ XSizeHints @sizeof erase
364 min
-width
0 max min
-height
0 max or
if
365 PMinSize r@ XSizeHints flags or
!
366 min
-width r@ XSizeHints min_width
!
367 min
-height r@ XSizeHints min_height
!
369 max
-width
0 max max
-height
0 max or
if
370 PMaxSize r@ XSizeHints flags or
!
371 max
-width r@ XSizeHints max_width
!
372 max
-height r@ XSizeHints max_height
!
374 r@
;; size hints address
375 0 0 0 0 ;; argc
, argv
, iconname windowname
376 winid xog
-dpy XSetWMProperties drop
378 rdrop XSizeHints @sizeof rdealloca
379 rdrop XWMHints @sizeof rdealloca
380 rdrop XClassHint @sizeof rdealloca
385 ;; destroy child windows
, and this window
386 BaseWindow method
: (destroy
) ( -- )
387 [ xog
-window
-debug
-child
-delete?
] [IF]
388 endcr
." removing chldren of " (debug
-id
.) cr
391 begin first
-child ?dup
while invoke
(destroy
) repeat
392 ;; remove ourself from the parent list
394 [ xog
-window
-debug
-child
-delete?
] [IF]
395 endcr
." removing " (debug
-id
.) ." from the parent\n"
396 ." parent is " dup invoke
(debug
-id
.) cr
398 self swap invoke
(remove
-child
)
400 [ xog
-window
-debug
-child
-delete?
] [IF]
401 endcr
." removing " (debug
-id
.) ." from the parent\n"
405 [ xog
-window
-debug
-child
-delete?
] [IF]
406 endcr
." destroying xwin of " (debug
-id
.) cr
408 xog
-dpy XDestroyWindow drop
412 [ xog
-window
-debug
-child
-delete?
] [IF]
413 endcr
." calling \`(destroy-cleanup)\` of " (debug
-id
.) cr
415 0 to winid
(destroy
-cleanup
)
420 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
421 ;; high
-level window creation
423 BaseWindow method
: create
-ex
( parentobj
-- successflag
)
424 xog
-dpy
0= winid
0<> or
if drop false exit
endif
425 ;; check
for valid parent
427 dup invoke winid ifnot drop false exit
endif
428 parent ?dup
if over
<> if drop false exit
endif endif
430 >r
;; save parent object
431 ;; XCreateSimpleWindow arguments
432 bg
-color
;; background color
433 xog
-black
-color
;; border color
435 ;; position
(we cannot create windows with zero dimensions
)
436 height
1 max dup
to height
437 width
1 max dup
to width
439 [ xog
-window
-debug
-child
-create?
] [IF]
440 endcr
." creating " (debug
-id
.) 2dup
." x=" . ." y=" . 2over
." w=" . ." h=" . cr
442 r@
if r@ invoke winid
else xog
-dpy XDefaultRootWindow
endif ;; parent
443 xog
-dpy XCreateSimpleWindow dup
to winid ifnot rdrop false exit
endif ;; oops
, cannot create a window
444 ;; register in global window list
448 get
-caption
0 255 clamp
449 ensure
-asciiz
>r winid xog
-dpy XStoreName r
> free
-asciiz
450 ;; set WM protocols
(only
for top
-level windows
)
451 WM_TAKE_FOCUS
>r WM_DELETE_WINDOW
>r
452 2 rp@ winid xog
-dpy XSetWMProtocols drop
2rdrop
454 NET_WM_WINDOW_TYPE_NORMAL
>r
455 1 rp@
0 ( PropModeReplace
) 32 ( bits
) XA_ATOM NET_WM_WINDOW_TYPE winid xog
-dpy XChangeProperty drop rdrop
457 ;; append
to parent
(this also sets
"parent" field
)
458 parent
if drop
else self swap invoke
(append
-child
) endif
468 \ PointerMotionMask or
469 \ PointerMotionHintMask or
470 \ Button1MotionMask or
471 \ Button2MotionMask or
472 \ Button3MotionMask or
473 \ Button4MotionMask or
474 \ Button5MotionMask or
475 \ ButtonMotionMask or
478 VisibilityChangeMask or
479 StructureNotifyMask or
480 \ ResizeRedirectMask or
481 \ SubstructureNotifyMask or
482 \ SubstructureRedirectMask or
484 PropertyChangeMask or
485 \ ColormapChangeMask or
486 \ OwnerGrabButtonMask or
487 ] literal motion
-events?
if PointerMotionMask or
endif
488 winid xog
-dpy XSelectInput
489 parent ifnot
(set
-xhints
) endif
493 ;; replace window background with empty one
-pixel pixmap
496 xog
-dpy DefaultScreen xog
-dpy XDefaultDepth
1 1 winid xog
-dpy XCreatePixmap
497 dup winid xog
-dpy XSetWindowBackgroundPixmap drop
500 None winid xog
-dpy XSetWindowBackgroundPixmap drop
506 parent visible? logand
if false
to visible? false
to mapped? show true
to visible?
endif ;; always map children
510 BaseWindow method
: create
( -- ) 0 create
-ex not
-?abort
" cannot create X11 window" ;
513 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
516 BaseWindow method
: is
-valid?
( -- flag
) winid notnot
;
517 BaseWindow method
: can
-focus?
( -- flag
) (can
-focus?
) ;
518 BaseWindow method
: bg
-color
( -- color
) xog
-black
-color
;
520 BaseWindow method
: dirty
! ( -- ) true
to dirty?
;
521 BaseWindow method
: non
-dirty
! ( -- ) false
to dirty?
;
523 ;; returns either window
, or a pixmap
524 ;; checks both
"double-buffered?" and
"winpixmap"
525 BaseWindow method
: my
-drawable
( -- drw
)
526 double-buffered? winpixmap logand
if winpixmap
else winid
endif
529 BaseWindow method
: realize
-part
( x y w h
-- )
530 winid
double-buffered? logand winpixmap logand
if
531 over
0> over
0> and
if
532 swap
2swap swap
2swap
2over
( y x h w y x
)
533 wingc winid winpixmap xog
-dpy XCopyArea
539 ;; call this when you finish painting
, to copy window pixmap
to the screen
540 BaseWindow method
: realize
( -- )
541 winid
double-buffered? logand winpixmap logand
if
545 wingc winid winpixmap xog
-dpy XCopyArea
550 BaseWindow method
: (need
-focus?
) ( -- flag
)
551 parent
if ;; has parent
552 parent invoke focused
-child self
= if ;; parent focused child is this one
553 parent invoke
(need
-focus?
) exit
559 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
560 ;; X11 event handlers
562 BaseWindow method
: KeyPress
-Handler
( -- ) (event
) (get
-keysym
) on
-keydown
;
563 BaseWindow method
: KeyRelease
-Handler
( -- ) (event
) (get
-keysym
) on
-keyup
;
564 BaseWindow method
: ButtonPress
-Handler
( -- ) (event
) XButtonEvent button @ on
-button
-down
;
565 BaseWindow method
: ButtonRelease
-Handler
( -- ) (event
) XButtonEvent button @ on
-button
-up
;
566 BaseWindow method
: MotionNotify
-Handler
( -- ) ;
567 BaseWindow method
: EnterNotify
-Handler
( -- ) ;
568 BaseWindow method
: LeaveNotify
-Handler
( -- ) ;
569 BaseWindow method
: KeymapNotify
-Handler
( -- ) ;
570 BaseWindow method
: GraphicsExpose
-Handler
( -- ) ;
571 BaseWindow method
: NoExpose
-Handler
( -- ) ;
572 BaseWindow method
: VisibilityNotify
-Handler
( -- ) (event
) XVisibilityEvent state @ VisibilityFullyObscured
<> on
-visibility
;
573 BaseWindow method
: CreateNotify
-Handler
( -- ) ;
574 BaseWindow method
: DestroyNotify
-Handler
( -- ) 0 to winid
(destroy
-cleanup
) ;
575 BaseWindow method
: MapRequest
-Handler
( -- ) ;
576 BaseWindow method
: ReparentNotify
-Handler
( -- ) ;
577 BaseWindow method
: ConfigureRequest
-Handler
( -- ) ;
578 BaseWindow method
: GravityNotify
-Handler
( -- ) ;
579 BaseWindow method
: ResizeRequest
-Handler
( -- ) ;
580 BaseWindow method
: CirculateNotify
-Handler
( -- ) ;
581 BaseWindow method
: CirculateRequest
-Handler
( -- ) ;
582 \ BaseWindow method
: PropertyNotify
-Handler
( -- ) ;
583 BaseWindow method
: SelectionClear
-Handler
( -- ) ;
584 BaseWindow method
: SelectionRequest
-Handler
( -- ) ;
585 BaseWindow method
: SelectionNotify
-Handler
( -- ) ;
586 BaseWindow method
: ColormapNotify
-Handler
( -- ) ;
587 BaseWindow method
: MappingNotify
-Handler
( -- ) ;
588 BaseWindow method
: GenericEvent
-Handler
( -- ) ;
589 BaseWindow method
: UnknownEvent
-Handler
( -- ) ;
591 BaseWindow method
: FocusIn
-Handler
( -- )
592 (event
) XFocusChangeEvent detail @ \ dup
. cr
593 dup NotifyNonlinear
= if drop NotifyAncestor
endif
595 NotifyAncestor of on
-focus true
to focused? endof
596 NotifyPointer of focus endof
599 \ endcr
." going to focus a child...\n"
602 self parent begin dup
while ( child parent
)
603 \ endcr
." +++child " over invoke
(debug
-id
.) ." is focused child for " dup invoke
(debug
-id
.) cr
604 2dup invoke
(focused
-child
!)
605 nip dup invoke parent repeat
2drop
609 BaseWindow method
: FocusOut
-Handler
( -- )
610 (event
) XFocusChangeEvent detail @ \ dup
. cr
611 dup NotifyNonlinear
= if drop NotifyAncestor
endif
612 NotifyAncestor
= if on
-blur false
to focused?
endif
615 BaseWindow method
: MapNotify
-Handler
( -- ) true
to (first
-paint?
) true
to visible?
(map
-children
) on
-show
;
616 BaseWindow method
: UnmapNotify
-Handler
( -- ) true
to (first
-paint?
) false
to visible? on
-hide
;
618 BaseWindow method
: Expose
-Handler
( -- )
619 false
to invalidate
-sent?
620 (event
) dup
>r XExposeEvent x @ r@ XExposeEvent y @
621 r@ XExposeEvent width @ dup
-0if drop width
endif
622 r@ XExposeEvent height @ dup
-0if drop height
endif
623 (first
-paint?
) if dirty
!
624 false
to (first
-paint?
)
625 2drop
2drop
0 0 width height
0 ;; paint the whole thing
627 r@ XExposeEvent count @
629 winid
double-buffered? logand winpixmap logand ifnot dirty
! endif
631 r@ XExposeEvent x @ r@ XExposeEvent y @
632 r@ XExposeEvent width @ dup
-0if drop width
endif
633 r@ XExposeEvent height @ dup
-0if drop height
endif
634 \ endcr
." Expose: x=" 2over swap
. ." y=" . ." w=" 2dup swap
. ." h=" . ." count=" r@ XExposeEvent count @
. cr
639 BaseWindow method
: ConfigureNotify
-Handler
( -- )
640 (event
) dup XConfigureEvent width @
641 swap XConfigureEvent height @
642 2dup height
= swap width
= and ifnot
643 width height
;; old size
644 2swap
to height
to width
;; set new size
645 winpixmap
if (deinit
-pixmap
) (init
-pixmap
) else dirty
! endif
651 BaseWindow method
: ClientMessage
-Handler
( -- )
652 (event
) XClientMessageEvent message_type @ case
654 (event
) XClientMessageEvent data @ case
655 WM_DELETE_WINDOW of on
-close
-query
if close
endif endof
656 ;; this is rarely used
(at least FluxBox doesn
't send it)
657 WM_TAKE_FOCUS of (event) XClientMessageEvent data cell+ @ (debug-id.) ." WM_TAKE_FOCUS: " . cr endof
660 XOF_INTERNAL_CLOSE of (destroy) endof
661 \ WM_CHANGE_STATE of (event) XClientMessageEvent data @ on-state-change endof
665 BaseWindow method: PropertyNotify-Handler-WM_STATE ( -- )
668 r@ ( prop_return) r@ cell+ ( bytes_after_return)
669 r@ 2 +cells ( nitems_return)
670 r@ 3 +cells ( actual_format_return)
671 r@ 4 +cells ( actual_type_return)
672 AnyPropertyType false 1 0 WM_STATE winid xog-dpy XGetWindowProperty ifnot
673 r@ @ @ on-state-change
676 rdrop 5 cells rdealloca
679 BaseWindow method: PropertyNotify-Handler ( -- )
680 (event) XPropertyEvent atom @ xog-dpy XGetAtomName >r
681 endcr (debug-id.) ." PROPERTY \`" r@ zcount type ." \` is "
682 (event) XPropertyEvent state @ PropertyDelete = if ." deleted" else ." set" endif
685 (event) XPropertyEvent state @ PropertyNewValue = if
686 (event) XPropertyEvent atom @ case
687 WM_STATE of PropertyNotify-Handler-WM_STATE endof
693 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
694 ;; X11 event processor
695 ;; calls "*-Handler" by name
698 ;; call this to stop event propagation
699 BaseWindow method: event-eat ( -- ) (event) ?dup if 0! endif ;
701 ;; this is called with KeyPress event
702 BaseWindow method: check-hotkey ( keyevent -- boolflag ) drop false ;
705 ;; can be called in any event handler, does all the checks it needs
706 BaseWindow method: (kb-broadcast-hotkey) ( -- )
707 parent if exit endif ;; only top-level window does this
708 (event) ?dup ifnot exit endif
709 dup @ KeyPress = ifnot drop exit endif
710 [: ( keyevent -- stopflag )
711 dup (self@) BaseWindow:: check-hotkey
712 ;] foreach-child 2drop
716 BaseWindow method: (is-kb-focus-forward-event?) ( event -- flag )
717 dup if dup @ KeyPress = if (get-keysym) XK_Tab = else drop false endif endif
720 BaseWindow method: (gain-focus) ( -- successflag )
722 first-child begin dup while
723 dup invoke (gain-focus) if drop true break endif
724 invoke next-sibling repeat
725 ?dup ifnot focus true endif
730 BaseWindow method: (kb-focus-first) ( -- successflag )
731 [ xog-window-debug-kbfocus? ] [IF]
732 ." FFIRST " (debug-id.) cr
737 BaseWindow method: (kb-focus-forward) ( -- successflag )
738 [ xog-window-debug-kbfocus? ] [IF]
739 endcr ." FFORWARD at " (debug-id.)
740 next-sibling if ." with next sibling as " next-sibling invoke (debug-id.) endif
743 next-sibling begin dup while
744 dup invoke (gain-focus) if drop true break endif
745 invoke next-sibling repeat
748 BaseWindow method: (check-do-kb-focus) ( -- )
749 (event) (is-kb-focus-forward-event?) if
750 (kb-focus-forward) if event-eat
751 else parent ifnot (kb-focus-first) if event-eat endif endif
756 BaseWindow method: (sink-event) ( -- )
757 (basewin-debug-show-events?) if
758 ." SINK EVENT: destwinid=" (event) XAnyEvent window @ .hex8 ." type=" (event) @ . (event) @ get-x11-event-type-name type cr
762 BaseWindow method: (bubble-event) ( -- )
763 (basewin-debug-show-events?) if
764 ." BUBBLE EVENT: destwinid=" (event) XAnyEvent window @ .hex8 ." type=" (event) @ . (event) @ get-x11-event-type-name type cr
767 (kb-broadcast-hotkey)
770 BaseWindow method: (process-event) ( -- )
771 (basewin-debug-show-events?) if
772 ." HANDLE EVENT: winid=" (event) XAnyEvent window @ .hex8 ." type=" (event) @ . (event) @ get-x11-event-type-name type cr
775 (event) @ get-x11-event-handler-name dispatch-str
778 (kb-broadcast-hotkey)
782 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
783 ;; high-level window control methods
785 BaseWindow method: close ( -- )
786 is-valid? if close-sent? ifnot true to close-sent? (send-close-event) endif endif
789 BaseWindow method: weak-invalidate ( -- )
790 is-valid? if invalidate-sent? ifnot true to invalidate-sent? (send-expose-event) endif endif
793 BaseWindow method: invalidate ( -- )
794 is-valid? if dirty! weak-invalidate endif
797 BaseWindow method: sync ( -- )
798 xog-dpy if false xog-dpy XSync endif
801 BaseWindow method: flush ( -- )
802 xog-dpy if xog-dpy XFlush endif
805 BaseWindow method: show ( -- )
806 is-valid? if mapped? ifnot true to mapped? winid xog-dpy XMapWindow endif endif
809 BaseWindow method: hide ( -- )
810 is-valid? if mapped? if false to mapped? false to visible? winid xog-dpy XUnmapWindow endif endif
813 BaseWindow method: focus ( -- )
814 visible? if is-valid? if CurrentTime RevertToParent winid xog-dpy XSetInputFocus endif endif
817 BaseWindow method: set-min-size ( minwidth minheight -- )
818 0 max to min-height 0 max to min-width is-valid? if (set-xhints) endif
821 BaseWindow method: set-max-size ( maxwidth maxheight -- )
822 0 max to max-height 0 max to max-width is-valid? if (set-xhints) endif
825 BaseWindow method: set-pos ( x y -- )
826 over posx - over posy - or if
827 to posy to posx is-valid? if posy posx winid xog-dpy XMoveWindow endif
831 BaseWindow method: set-size ( width height -- )
833 over height - over width - or if
834 to width to height is-valid? if height width winid xog-dpy XResizeWindow endif
839 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
840 ;; high-level event handlers
842 BaseWindow method: on-created ( -- ) ;
843 BaseWindow method: on-destroyed ( -- ) ;
844 BaseWindow method: on-visibility ( visible-flag -- ) drop ;
845 BaseWindow method: on-show ( -- ) ;
846 BaseWindow method: on-hide ( -- ) ;
847 BaseWindow method: on-focus ( -- ) ;
848 BaseWindow method: on-blur ( -- ) ;
849 BaseWindow method: on-draw-part ( x y width height count -- ) >r 2drop 2drop r> ifnot on-draw endif ;
850 BaseWindow method: on-draw ( -- ) ;
851 BaseWindow method: on-resize ( oldwidth oldheight -- ) 2drop ;
852 BaseWindow method: on-keydown ( keysym -- ) drop ;
853 BaseWindow method: on-keyup ( keysym -- ) drop ;
854 BaseWindow method: on-button-down ( bnum -- ) drop ;
855 BaseWindow method: on-button-up ( bnum -- ) drop ;
856 BaseWindow method: on-close-query ( -- allow-close-flag ) true ;
857 BaseWindow method: on-state-change ( newstate -- ) drop ;
860 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
863 BaseWindow method: set-color ( color -- ) dup to current-fg-color wingc xog-dpy XSetForeground ;
864 BaseWindow method: set-named-color ( addr count -- ) xog-get-color set-color ;
866 BaseWindow method: set-bg-color ( color -- ) dup to current-bg-color wingc xog-dpy XSetBackground ;
867 BaseWindow method: set-named-bg-color ( addr count -- ) xog-get-color set-bg-color ;
869 BaseWindow method: set-line-style ( style -- ) JoinMiter CapButt rot 0 wingc xog-dpy XSetLineAttributes drop ;
870 BaseWindow method: set-line-solid ( -- ) LineSolid set-line-style ;
871 BaseWindow method: set-line-dashed ( -- ) LineOnOffDash set-line-style ;
873 BaseWindow method: draw-point ( x y -- ) swap wingc my-drawable xog-dpy XDrawPoint ;
874 BaseWindow method: draw-line ( x0 y0 x1 y1 -- ) swap 2swap swap wingc my-drawable xog-dpy XDrawLine ;
875 BaseWindow method: fill-rect ( x y w h -- ) swap 2swap swap wingc my-drawable xog-dpy XFillRectangle ;
876 BaseWindow method: draw-rect ( x y w h -- ) swap 2swap swap wingc my-drawable xog-dpy XDrawRectangle ;
877 BaseWindow method: draw-ellipse ( x0 y0 w h -- ) swap 2swap swap 23040 0 2nrot wingc my-drawable xog-dpy XDrawArc ;
878 BaseWindow method: fill-ellipse ( x0 y0 w h -- ) swap 2swap swap 23040 0 2nrot wingc my-drawable xog-dpy XFillArc ;
881 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
882 ;; draw rounded rectangles
884 BaseWindow method: draw-rounded-rect {{ x y w h ew eh | arcs curarc ew2 eh2 -- }}
885 XArc @sizeof 8 * ralloca dup to arcs to curarc
890 ew 1 lshift dup to ew2 w > if 0 dup to ew2 to ew endif
891 eh 1 lshift dup to eh2 h > if 0 dup to eh2 to eh endif
896 ew2 curarc XArc width w!
897 eh2 curarc XArc height w!
898 [ 180 64 * ] literal curarc XArc angle1 w!
899 [ -90 64 * ] literal curarc XArc angle2 w!
900 curarc XArc @sizeof + to curarc
903 x ew + curarc XArc x w!
905 w ew2 - curarc XArc width w!
906 0 curarc XArc height w!
907 [ 180 64 * ] literal curarc XArc angle1 w!
908 [ -180 64 * ] literal curarc XArc angle2 w!
909 curarc XArc @sizeof + to curarc
912 x w + ew2 - curarc XArc x w!
914 ew2 curarc XArc width w!
915 eh2 curarc XArc height w!
916 [ 90 64 * ] literal curarc XArc angle1 w!
917 [ -90 64 * ] literal curarc XArc angle2 w!
918 curarc XArc @sizeof + to curarc
921 x w + curarc XArc x w!
922 y eh + curarc XArc y w!
923 0 curarc XArc width w!
924 h eh2 - curarc XArc height w!
925 [ 90 64 * ] literal curarc XArc angle1 w!
926 [ -180 64 * ] literal curarc XArc angle2 w!
927 curarc XArc @sizeof + to curarc
930 x w + ew2 - curarc XArc x w!
931 y h + eh2 - curarc XArc y w!
932 ew2 curarc XArc width w!
933 eh2 curarc XArc height w!
934 [ 0 64 * ] literal curarc XArc angle1 w!
935 [ -90 64 * ] literal curarc XArc angle2 w!
936 curarc XArc @sizeof + to curarc
939 x ew + curarc XArc x w!
940 y h + curarc XArc y w!
941 w ew2 - curarc XArc width w!
942 0 curarc XArc height w!
943 [ 0 64 * ] literal curarc XArc angle1 w!
944 [ -180 64 * ] literal curarc XArc angle2 w!
945 curarc XArc @sizeof + to curarc
949 y h + eh2 - curarc XArc y w!
950 ew2 curarc XArc width w!
951 eh2 curarc XArc height w!
952 [ 270 64 * ] literal curarc XArc angle1 w!
953 [ -90 64 * ] literal curarc XArc angle2 w!
954 curarc XArc @sizeof + to curarc
958 y eh + curarc XArc y w!
959 0 curarc XArc width w!
960 h eh2 - curarc XArc height w!
961 [ 270 64 * ] literal curarc XArc angle1 w!
962 [ -180 64 * ] literal curarc XArc angle2 w!
964 8 arcs wingc my-drawable xog-dpy XDrawArcs
966 XArc @sizeof 8 * rdealloca
970 BaseWindow method: fill-rounded-rect {{ x y w h ew eh | arcs curarc rects currect gcvals ew2 eh2 -- }}
971 XArc @sizeof 4 * ralloca dup to arcs to curarc
972 XRectangle @sizeof 3 * ralloca dup to rects to currect
973 XGCValues @sizeof ralloca to gcvals
975 gcvals GCArcMode wingc xog-dpy XGetGCValues drop
976 gcvals XGCValues arc_mode @ ArcPieSlice <> if
977 ArcPieSlice wingc xog-dpy XSetArcMode drop
983 ew 1 lshift dup to ew2 w > if 0 dup to ew2 to ew endif
984 eh 1 lshift dup to eh2 h > if 0 dup to eh2 to eh endif
989 ew2 curarc XArc width w!
990 eh2 curarc XArc height w!
991 [ 180 64 * ] literal curarc XArc angle1 w!
992 [ -90 64 * ] literal curarc XArc angle2 w!
993 curarc XArc @sizeof + to curarc
996 x w + ew2 - 1- curarc XArc x w!
998 ew2 curarc XArc width w!
999 eh2 curarc XArc height w!
1000 [ 90 64 * ] literal curarc XArc angle1 w!
1001 [ -90 64 * ] literal curarc XArc angle2 w!
1002 curarc XArc @sizeof + to curarc
1005 x w + ew2 - 1- curarc XArc x w!
1006 y h + eh2 - 1- curarc XArc y w!
1007 ew2 curarc XArc width w!
1008 eh2 curarc XArc height w!
1009 [ 0 64 * ] literal curarc XArc angle1 w!
1010 [ -90 64 * ] literal curarc XArc angle2 w!
1011 curarc XArc @sizeof + to curarc
1015 y h + eh2 - 1- curarc XArc y w!
1016 ew2 curarc XArc width w!
1017 eh2 curarc XArc height w!
1018 [ 270 64 * ] literal curarc XArc angle1 w!
1019 [ -90 64 * ] literal curarc XArc angle2 w!
1021 4 arcs wingc my-drawable xog-dpy XFillArcs
1024 x ew + currect XRectangle x w!
1025 y currect XRectangle y w!
1026 w ew2 - currect XRectangle width w!
1027 h currect XRectangle height w!
1028 currect XRectangle @sizeof + to currect
1031 x currect XRectangle x w!
1032 y eh + currect XRectangle y w!
1033 ew currect XRectangle width w!
1034 h eh2 - currect XRectangle height w!
1035 currect XRectangle @sizeof + to currect
1038 x w + ew - currect XRectangle x w!
1039 y eh + currect XRectangle y w!
1040 ew currect XRectangle width w!
1041 h eh2 - currect XRectangle height w!
1043 3 rects wingc my-drawable xog-dpy XFillRectangles
1045 gcvals XGCValues arc_mode @ ArcPieSlice <> if
1046 gcvals XGCValues arc_mode @ wingc xog-dpy XSetArcMode drop
1049 XGCValues @sizeof rdealloca
1050 XRectangle @sizeof 3 * rdealloca
1051 XArc @sizeof 4 * rdealloca
1055 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;