2017-04-05 16:48:20 +00:00
|
|
|
#include 'Moo.moo'.
|
|
|
|
|
|
|
|
###var xxxx. ## global variables.
|
|
|
|
|
|
|
|
class X11(Object) from 'x11'
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
(* The X11 class represents a X11 display *)
|
|
|
|
|
|
|
|
dcl(#class) default_display.
|
|
|
|
|
|
|
|
dcl cid.
|
|
|
|
dcl windows. ## all windows registered
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
dcl event_loop_sem event_loop_proc.
|
|
|
|
dcl ll_event_blocks.
|
|
|
|
|
|
|
|
dcl expose_event.
|
|
|
|
dcl key_event.
|
|
|
|
dcl mouse_event.
|
|
|
|
dcl mouse_wheel_event.
|
|
|
|
|
|
|
|
method(#primitive) _connect.
|
|
|
|
method(#primitive) _disconnect.
|
|
|
|
method(#primitive) _get_fd.
|
|
|
|
method(#primitive) _get_event.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method cid { ^self.cid }
|
|
|
|
method wid { ^nil }
|
|
|
|
method display { ^self }
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class X11.Exception(System.Exception)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class X11.Rectangle(Object)
|
|
|
|
{
|
|
|
|
dcl x y width height.
|
|
|
|
|
|
|
|
method initialize
|
|
|
|
{
|
|
|
|
self.x := 0.
|
|
|
|
self.y := 0.
|
|
|
|
self.width := 0.
|
|
|
|
self.height := 0.
|
|
|
|
}
|
|
|
|
|
|
|
|
method x { ^self.x }
|
|
|
|
method y { ^self.y }
|
|
|
|
method width { ^self.width }
|
|
|
|
method height { ^self.height }
|
|
|
|
|
|
|
|
method x: x { self.x := x }
|
|
|
|
method y: y { self.y := y }
|
|
|
|
method width: width { self.width := width }
|
|
|
|
method height: height { self.height := height }
|
|
|
|
|
|
|
|
method x: x y: y width: width height: height
|
|
|
|
{
|
|
|
|
self.x := x.
|
|
|
|
self.y := y.
|
|
|
|
self.width := width.
|
|
|
|
self.height := height.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
## ---------------------------------------------------------------------------
|
|
|
|
## Event
|
|
|
|
## ---------------------------------------------------------------------------
|
|
|
|
pooldic X11.LLEvent
|
|
|
|
{
|
|
|
|
KEY_PRESS := 2.
|
|
|
|
KEY_RELEASE := 3.
|
|
|
|
BUTTON_PRESS := 4.
|
|
|
|
BUTTON_RELEASE := 5.
|
|
|
|
MOTION_NOTIFY := 6.
|
|
|
|
ENTER_NOTIFY := 7.
|
|
|
|
LEAVE_NOTIFY := 8.
|
|
|
|
EXPOSE := 12.
|
|
|
|
VISIBILITY_NOTIFY := 15.
|
2017-04-07 15:50:05 +00:00
|
|
|
CONFIGURE_NOTIFY := 22.
|
2017-04-05 16:48:20 +00:00
|
|
|
CLIENT_MESSAGE := 33.
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.Event(Object)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.InputEvent(X11.Event)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.KeyEvent(X11.InputEvent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.MouseEvent(X11.InputEvent)
|
|
|
|
{
|
|
|
|
dcl x y.
|
|
|
|
|
|
|
|
method x { ^self.x }
|
|
|
|
method y { ^self.y }
|
|
|
|
|
|
|
|
method x: x y: y
|
|
|
|
{
|
|
|
|
self.x := x.
|
|
|
|
self.y := y.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.MouseWheelEvent(X11.InputEvent)
|
|
|
|
{
|
|
|
|
dcl x y amount.
|
|
|
|
|
|
|
|
method x { ^self.x }
|
|
|
|
method y { ^self.y }
|
|
|
|
method amount { ^self.amount }
|
|
|
|
|
|
|
|
method x: x y: y amount: amount
|
|
|
|
{
|
|
|
|
self.x := x.
|
|
|
|
self.y := y.
|
|
|
|
self.amount := amount.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.ExposeEvent(X11.Event)
|
|
|
|
{
|
|
|
|
dcl x y width height.
|
|
|
|
|
|
|
|
method x { ^self.x }
|
|
|
|
method y { ^self.y }
|
|
|
|
method width { ^self.width }
|
|
|
|
method height { ^self.height }
|
|
|
|
|
|
|
|
method x: x y: y width: width height: height
|
|
|
|
{
|
|
|
|
self.x := x.
|
|
|
|
self.y := y.
|
|
|
|
self.width := width.
|
|
|
|
self.height := height.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.WindowEvent(X11.Event)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
class X11.FrameEvent(X11.Event)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
## ---------------------------------------------------------------------------
|
|
|
|
## Graphics Context
|
|
|
|
## ---------------------------------------------------------------------------
|
2017-04-07 15:50:05 +00:00
|
|
|
pooldic X11.GCAttr
|
|
|
|
{
|
|
|
|
(* see xcb/xproto.h *)
|
|
|
|
GC_FOREGROUND := 4.
|
|
|
|
GC_BACKGROUND := 8.
|
|
|
|
GC_LINE_WIDTH := 16.
|
|
|
|
GC_LINE_STYLE := 32.
|
|
|
|
GC_FONT := 16384.
|
|
|
|
}
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
class X11.GC(Object) from 'x11.gc'
|
|
|
|
{
|
|
|
|
dcl window id.
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method(#primitive) _make (display, window).
|
2017-04-05 16:48:20 +00:00
|
|
|
method(#primitive) _kill.
|
|
|
|
method(#primitive) _drawLine(x1, y1, x2, y2).
|
|
|
|
method(#primitive) _drawRect(x, y, width, height).
|
|
|
|
method(#primitive) _fillRect(x, y, width, height).
|
2017-04-07 15:50:05 +00:00
|
|
|
method(#primitive) _change(gcattr, value).
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
method(#class) new: window
|
|
|
|
{
|
|
|
|
^(super new) __open_on: window
|
|
|
|
}
|
|
|
|
|
|
|
|
method __open_on: window
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
if ((id := self _make(window display cid, window wid)) isError)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
X11.Exception signal: 'cannot make a graphic context'
|
|
|
|
}.
|
|
|
|
|
|
|
|
self.window := window.
|
|
|
|
self.id := id.
|
|
|
|
}
|
|
|
|
|
|
|
|
method close
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
if (self.id notNil)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
self _kill.
|
2017-04-07 15:50:05 +00:00
|
|
|
self.id := nil.
|
2017-04-05 16:48:20 +00:00
|
|
|
self.window := nil.
|
|
|
|
}
|
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method foreground: value
|
|
|
|
{
|
|
|
|
^self _change (X11.GCAttr.GC_FOREGROUND, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
method background: value
|
|
|
|
{
|
|
|
|
^self _change (X11.GCAttr.GC_BACKGROUND, value)
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
## ---------------------------------------------------------------------------
|
|
|
|
## ---------------------------------------------------------------------------
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
class X11.Component(Object)
|
|
|
|
{
|
|
|
|
dcl parent.
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method new
|
|
|
|
{
|
|
|
|
## you must call new: parent instead.
|
|
|
|
self cannotInstantiate
|
|
|
|
}
|
|
|
|
|
|
|
|
method new: parent
|
|
|
|
{
|
|
|
|
## you must call new: parent instead.
|
|
|
|
self cannotInstantiate
|
|
|
|
}
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
method parent
|
|
|
|
{
|
|
|
|
^self.parent
|
|
|
|
}
|
|
|
|
|
|
|
|
method parent: parent
|
|
|
|
{
|
|
|
|
self.parent := parent.
|
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method display
|
|
|
|
{
|
|
|
|
| p pp |
|
|
|
|
p := self.
|
|
|
|
while ((pp := p parent) notNil) { p := pp }.
|
|
|
|
^p display.
|
|
|
|
}
|
|
|
|
|
|
|
|
method display: display
|
|
|
|
{
|
|
|
|
## do nothing
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class X11.Canvas(Component)
|
|
|
|
{
|
|
|
|
method paint: gr
|
|
|
|
{
|
|
|
|
self subclassResponsibility: #paint
|
|
|
|
}
|
|
|
|
|
|
|
|
method update: gr
|
|
|
|
{
|
|
|
|
self subclassResponsibility: #paint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class X11.WindowedComponent(Component) from 'x11.win'
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
dcl(#class) geom.
|
|
|
|
dcl wid.
|
|
|
|
|
|
|
|
method(#primitive) _get_window_dwatom.
|
|
|
|
method(#primitive) _get_window_id.
|
|
|
|
method(#primitive) _make_window (display, x, y, width, height, parent).
|
|
|
|
method(#primitive) _kill_window.
|
|
|
|
method(#primitive) _get_window_geometry (geom).
|
|
|
|
method(#primitive) _set_window_geometry (geom).
|
|
|
|
|
|
|
|
method wid { ^self.wid }
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method(#class) new: parent
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^(super new) __open_on_window: parent
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method __open_on_window: parent
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
| id disp |
|
|
|
|
|
|
|
|
disp := parent display.
|
|
|
|
|
|
|
|
wid := self _make_window (disp cid, 5, 5, 300, 300, parent wid).
|
|
|
|
if (wid isError) { X11.Exception signal: ('cannot make a window - ' & wid asString) }.
|
|
|
|
|
|
|
|
self.wid := wid.
|
|
|
|
self display: disp.
|
|
|
|
|
|
|
|
if (disp ~= parent)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
self.parent := parent.
|
|
|
|
parent addComponent: self.
|
2017-04-05 16:48:20 +00:00
|
|
|
}.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
disp addWindow: self.
|
|
|
|
self windowOpened.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method close
|
|
|
|
{
|
|
|
|
if (self.wid notNil)
|
|
|
|
{
|
|
|
|
self windowClosing.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
self display removeWindow: self.
|
|
|
|
if (self.parent notNil) { self.parent removeComponent: self }.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
self _kill_window.
|
|
|
|
self windowClosed. ## you can't make a primitive call any more
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
self.wid := nil.
|
|
|
|
self.parent := nil.
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method bounds
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
| rect |
|
|
|
|
rect := X11.Rectangle new.
|
|
|
|
self _get_window_geometry (rect).
|
|
|
|
^rect.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method bounds: rect
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
self _set_window_geometry (rect).
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method windowOpened
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowClosing
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowClosed
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowResized
|
|
|
|
{
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method expose: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
## ('EXPOSE IN WINDOWS....' & (self.wid asString) & ' ' & (event x asString) & ' ' & (event y asString) & ' ' & (event width asString) & ' ' & (event height asString)) dump.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
(* TODO: take the followings out to a seperate mouse listener??? *)
|
|
|
|
method mouseEntered: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method mouseExited: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method mouseClicked: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method mousePressed: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
('MOUSE PRESSED' & (self.wid asString) & ' ' & (event x asString) & ' ' & (event y asString)) dump.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
method mouseReleased: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
('MOUSE RELEASED' & (self.wid asString) & ' ' & (event x asString) & ' ' & (event y asString)) dump.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
method mouseWheelMoved: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
('MOUSE WHEEL MOVED' & (self.wid asString) & ' ' & (event x asString) & ' ' & (event y asString) & ' ' & (event amount asString)) dump.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class X11.Container(WindowedComponent)
|
|
|
|
{
|
|
|
|
dcl components.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method initialize
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
super initialize.
|
|
|
|
self.components := System.Dictionary new: 128.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method addComponent: component
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
## TODO: the key is component's wid. it's only supported for WindowedCompoennt.
|
|
|
|
## what is a better key to support Component that's not linked to any window?
|
|
|
|
^self.components at: (component wid) put: component
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method removeComponent: component
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^self.components removeKey: (component wid)
|
|
|
|
}
|
|
|
|
|
|
|
|
method close
|
|
|
|
{
|
|
|
|
self.components do: [:c | c close ].
|
|
|
|
^super close
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class X11.FrameWindow(Container)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
dcl display.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method display { ^self.display }
|
|
|
|
method display: display { self.display := display }
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
method(#class) new
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
super new: X11 defaultDisplay. ## connect if X11 is not connected.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method(#class) new: display
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^super new: display.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
##method show: flag
|
|
|
|
##{
|
|
|
|
##}
|
|
|
|
|
|
|
|
(*
|
|
|
|
method windowActivated: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowDeactivated: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowIconified: event
|
|
|
|
{
|
|
|
|
}
|
|
|
|
method windowDeiconified: event
|
|
|
|
{
|
|
|
|
}*)
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class X11.Button(WindowedComponent)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
extend X11
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
method(#class) new
|
|
|
|
{
|
|
|
|
^(super new) __connect_to_display: nil.
|
|
|
|
}
|
|
|
|
|
|
|
|
method __connect_to_display: name
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
## TODO: make use of name to connect to a non-default display.
|
|
|
|
| cid |
|
|
|
|
cid := self _connect.
|
|
|
|
if (cid isError) { X11.Exception signal: 'cannot connect to display' }.
|
|
|
|
self.cid := cid.
|
|
|
|
}
|
|
|
|
|
|
|
|
method close
|
|
|
|
{
|
|
|
|
if (self.cid notNil)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
self _disconnect.
|
|
|
|
self.cid := nil.
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method(#class) defaultDisplay
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
| conn |
|
|
|
|
if (self.default_display isNil)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
conn := X11 new.
|
|
|
|
##if (conn isError) { X11.Exception signal: 'cannot connect to default display' }.
|
|
|
|
self.default_display := conn.
|
2017-04-05 16:48:20 +00:00
|
|
|
}.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
^self.default_display
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method(#class) closeDefaultDisplay
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
if (self.default_display notNil)
|
|
|
|
{
|
|
|
|
self.default_display close.
|
|
|
|
self.default_display := nil.
|
|
|
|
}
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
method(#class) enterEventLoop
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^self defaultDisplay enterEventLoop
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method initialize
|
|
|
|
{
|
|
|
|
super initialize.
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
self.windows := System.Dictionary new: 100.
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
self.expose_event := X11.ExposeEvent new.
|
|
|
|
self.key_event := X11.KeyEvent new.
|
|
|
|
self.mouse_event := X11.MouseEvent new.
|
|
|
|
self.mouse_wheel_event := X11.MouseWheelEvent new.
|
|
|
|
|
|
|
|
self.ll_event_blocks := System.Dictionary new.
|
|
|
|
self.ll_event_blocks
|
2017-04-07 15:50:05 +00:00
|
|
|
at: X11.LLEvent.KEY_PRESS put: #__handle_key_event:;
|
|
|
|
at: X11.LLEvent.KEY_RELEASE put: #__handle_key_event:;
|
|
|
|
at: X11.LLEvent.BUTTON_PRESS put: #__handle_button_event:;
|
|
|
|
at: X11.LLEvent.BUTTON_RELEASE put: #__handle_button_event:;
|
|
|
|
at: X11.LLEvent.MOTION_NOTIFY put: #__handle_notify:;
|
|
|
|
at: X11.LLEvent.ENTER_NOTIFY put: #__handle_notify:;
|
|
|
|
at: X11.LLEvent.LEAVE_NOTIFY put: #__handle_notify:;
|
|
|
|
at: X11.LLEvent.EXPOSE put: #__handle_expose:;
|
|
|
|
at: X11.LLEvent.CONFIGURE_NOTIFY put: #__handle_configure_notify;
|
|
|
|
at: X11.LLEvent.CLIENT_MESSAGE put: #__handle_client_message:.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method connect
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
| cid |
|
|
|
|
if (self.windows isNil)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
if ((cid := self _connect) isError) { ^cid }.
|
|
|
|
self.cid := cid.
|
|
|
|
self.windows := System.Dictionary new.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method disconnect
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
if (self.windows notNil)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
self.windows do: [ :frame |
|
2017-04-05 16:48:20 +00:00
|
|
|
frame close.
|
|
|
|
].
|
2017-04-07 15:50:05 +00:00
|
|
|
self.windows := nil.
|
2017-04-05 16:48:20 +00:00
|
|
|
self _disconnect.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method addWindow: window
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^self.windows at: (window wid) put: window.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
method removeWindow: window
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
^self.windows removeKey: (window wid)
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method enterEventLoop
|
|
|
|
{
|
|
|
|
if (self.event_loop_sem isNil)
|
|
|
|
{
|
|
|
|
self.event_loop_sem := Semaphore new.
|
|
|
|
Processor signal: self.event_loop_sem onInput: (self _get_fd).
|
|
|
|
self.event_loop_proc := [
|
|
|
|
| event ongoing |
|
|
|
|
|
|
|
|
ongoing := true.
|
2017-04-07 15:50:05 +00:00
|
|
|
while (self.windows size > 0)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
'Waiting for X11 event...' dump.
|
|
|
|
self.event_loop_sem wait.
|
|
|
|
if (ongoing not) { break }.
|
|
|
|
|
|
|
|
while ((event := self _get_event) notNil)
|
|
|
|
{
|
|
|
|
## XCB_EXPOSE 12
|
|
|
|
## XCB_DESTROY_WINDOW 4
|
|
|
|
('EVENT================>' & event asString) dump.
|
|
|
|
if (event isError)
|
|
|
|
{
|
|
|
|
'Error has occurred in ....' dump.
|
|
|
|
ongoing := false.
|
|
|
|
break.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
self __dispatch_event: event.
|
|
|
|
}.
|
|
|
|
}.
|
|
|
|
}.
|
|
|
|
|
|
|
|
Processor unsignal: self.event_loop_sem.
|
|
|
|
self.event_loop_sem := nil.
|
2017-04-08 07:23:31 +00:00
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
self disconnect.
|
|
|
|
] fork.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method exitEventLoop
|
|
|
|
{
|
|
|
|
if (self.event_loop_sem notNil)
|
|
|
|
{
|
|
|
|
###self.even_loop_sem ...
|
|
|
|
self.event_loop_proc terminate.
|
|
|
|
self.event_loop_proc := nil.
|
|
|
|
self.event_loop_sem := nil.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method signal_event_loop_semaphore
|
|
|
|
{
|
|
|
|
self.event_loop_sem signal.
|
|
|
|
}
|
|
|
|
|
|
|
|
method __dispatch_event: event
|
|
|
|
{
|
|
|
|
| type mthname |
|
|
|
|
|
|
|
|
##type := System _getUint8(event, 0).
|
|
|
|
type := event getUint8(0).
|
|
|
|
|
|
|
|
mthname := self.ll_event_blocks at: (type bitAnd: 16r7F).
|
|
|
|
if (mthname isError)
|
|
|
|
{
|
|
|
|
(* unknown event. ignore it *)
|
|
|
|
('IGNORING UNKNOWN LL-EVENT TYPE ' & type asString) dump.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
('Performing ...' & mthname asString) dump.
|
|
|
|
^self perform (mthname, event).
|
|
|
|
##^self perform: mthname with: event.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method __handle_notify: type
|
|
|
|
{
|
|
|
|
^9999999999
|
|
|
|
}
|
|
|
|
|
|
|
|
method __handle_expose: event
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
typedef struct xcb_expose_event_t {
|
|
|
|
uint8_t response_type;
|
|
|
|
uint8_t pad0;
|
|
|
|
uint16_t sequence;
|
|
|
|
xcb_window_t window; // uint32_t
|
|
|
|
uint16_t x;
|
|
|
|
uint16_t y;
|
|
|
|
uint16_t width;
|
|
|
|
uint16_t height;
|
|
|
|
uint16_t count;
|
|
|
|
uint8_t pad1[2];
|
|
|
|
} xcb_expose_event_t;
|
|
|
|
*)
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
| wid window |
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
##wid := System _getUint32(event, 4). ## window
|
|
|
|
wid := event getUint32(4).
|
2017-04-07 15:50:05 +00:00
|
|
|
window := self.windows at: wid.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
if (window notError)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
(*
|
|
|
|
self.expose_event
|
|
|
|
x: System _getUint16(event, 8) ## x
|
|
|
|
y: System _getUint16(event, 10) ## y
|
|
|
|
width: System _getUint16(event, 12) ## width
|
|
|
|
height: System _getUint16(event, 14). ## height
|
|
|
|
*)
|
|
|
|
self.expose_event
|
|
|
|
x: event getUint16(8) ## x
|
|
|
|
y: event getUint16(10) ## y
|
|
|
|
width: event getUint16(12) ## width
|
|
|
|
height: event getUint16(14). ## height
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
window expose: self.expose_event.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System logNl: ('Expose event on unknown window - ' & wid asString).
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method __handle_button_event: event
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
typedef struct xcb_button_press_event_t {
|
|
|
|
uint8_t response_type;
|
|
|
|
xcb_button_t detail; // uint8_t
|
|
|
|
uint16_t sequence;
|
|
|
|
xcb_timestamp_t time; // uint32_t
|
|
|
|
xcb_window_t root; // uint32_t
|
|
|
|
xcb_window_t event;
|
|
|
|
xcb_window_t child;
|
|
|
|
int16_t root_x;
|
|
|
|
int16_t root_y;
|
|
|
|
int16_t event_x;
|
|
|
|
int16_t event_y;
|
|
|
|
uint16_t state;
|
|
|
|
uint8_t same_screen;
|
|
|
|
uint8_t pad0;
|
|
|
|
} xcb_button_press_event_t;
|
|
|
|
typedef xcb_button_press_event_t xcb_button_release_event_t;
|
|
|
|
*)
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
| type wid window detail |
|
2017-04-05 16:48:20 +00:00
|
|
|
type := System _getUint8(event, 0) bitAnd: 16r7F. ## lower 7 bits of response_type
|
|
|
|
wid := System _getUint32(event, 12). ## event
|
|
|
|
##type := event getUint8(0) bitAnd: 16r7F. ## lower 7 bits of response_type
|
|
|
|
##wid := event getUint32(12). ## event
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
window := self.windows at: wid.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
if (window notError)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
##detail := System _getUint8(event, 1).
|
|
|
|
detail := event getUint8(1).
|
|
|
|
if (detail >= 1 and: [detail <= 3])
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
self.mouse_event
|
|
|
|
## TODO: encode detail also..
|
|
|
|
x: System _getUint16(event, 24) ## event_x
|
|
|
|
y: System _getUint16(event, 26). ## event_y
|
|
|
|
*)
|
|
|
|
self.mouse_event
|
|
|
|
## TODO: encode detail also..
|
|
|
|
x: event getUint16(24) ## event_x
|
|
|
|
y: event getUint16(26). ## event_y
|
|
|
|
|
|
|
|
if (type == X11.LLEvent.BUTTON_PRESS)
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
window mousePressed: self.mouse_event
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
window mouseReleased: self.mouse_event
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
elsif (detail == 4 or: [detail == 5])
|
|
|
|
{
|
|
|
|
if (type == X11.LLEvent.BUTTON_RELEASE)
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
self.mouse_wheel_event
|
|
|
|
x: System _getUint16(event, 24) ## event_x
|
|
|
|
y: System _getUint16(event, 26) ## event_y
|
|
|
|
amount: (if (detail == 4) { -1 } else { 1 }).
|
|
|
|
*)
|
|
|
|
self.mouse_wheel_event
|
|
|
|
x: event getUint16(24) ## event_x
|
|
|
|
y: event getUint16(26) ## event_y
|
|
|
|
amount: (if (detail == 4) { -1 } else { 1 }).
|
2017-04-07 15:50:05 +00:00
|
|
|
window mouseWheelMoved: self.mouse_wheel_event
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System logNl: ('Button event on unknown window - ' & wid asString).
|
|
|
|
}
|
|
|
|
}
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
method __handle_configure_notify: event
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
typedef struct xcb_configure_notify_event_t {
|
|
|
|
uint8_t response_type;
|
|
|
|
uint8_t pad0;
|
|
|
|
uint16_t sequence;
|
|
|
|
xcb_window_t event;
|
|
|
|
xcb_window_t window;
|
|
|
|
xcb_window_t above_sibling;
|
|
|
|
int16_t x;
|
|
|
|
int16_t y;
|
|
|
|
uint16_t width;
|
|
|
|
uint16_t height;
|
|
|
|
uint16_t border_width;
|
|
|
|
uint8_t override_redirect;
|
|
|
|
uint8_t pad1;
|
|
|
|
} xcb_configure_notify_event_t;
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
method __handle_client_message: event
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
typedef union xcb_client_message_data_t {
|
|
|
|
uint8_t data8[20];
|
|
|
|
uint16_t data16[10];
|
|
|
|
uint32_t data32[5];
|
|
|
|
} xcb_client_message_data_t;
|
|
|
|
|
|
|
|
typedef struct xcb_client_message_event_t {
|
|
|
|
uint8_t response_type;
|
|
|
|
uint8_t format;
|
|
|
|
uint16_t sequence;
|
|
|
|
xcb_window_t window; // uint32_t
|
|
|
|
xcb_atom_t type; // uint32_t
|
|
|
|
xcb_client_message_data_t data;
|
|
|
|
} xcb_client_message_event_t;
|
|
|
|
*)
|
2017-04-07 15:50:05 +00:00
|
|
|
| type wid window dw |
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
##wid := System _getUint32(event, 4). ## window
|
|
|
|
wid := event getUint32(4). ## window
|
2017-04-07 15:50:05 +00:00
|
|
|
window := self.windows at: wid.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
if (window notError)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
##dw := System _getUint32(event, 12). ## data.data32[0]
|
|
|
|
dw := event getUint32(12). ## data.data32[0]
|
2017-04-07 15:50:05 +00:00
|
|
|
if (dw == window _get_window_dwatom)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
## TODO: call close query callback???
|
2017-04-07 15:50:05 +00:00
|
|
|
window close.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
## TODO: handle other client messages
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System logNl: ('Client message on unknown window - ' & wid asString).
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method __handle_key_event: type
|
|
|
|
{
|
|
|
|
(*
|
|
|
|
typedef struct xcb_key_press_event_t {
|
|
|
|
uint8_t response_type;
|
|
|
|
xcb_keycode_t detail;
|
|
|
|
uint16_t sequence;
|
|
|
|
xcb_timestamp_t time;
|
|
|
|
xcb_window_t root;
|
|
|
|
xcb_window_t event;
|
|
|
|
xcb_window_t child;
|
|
|
|
int16_t root_x;
|
|
|
|
int16_t root_y;
|
|
|
|
int16_t event_x;
|
|
|
|
int16_t event_y;
|
|
|
|
uint16_t state;
|
|
|
|
uint8_t same_screen;
|
|
|
|
uint8_t pad0;
|
|
|
|
} xcb_key_press_event_t;
|
|
|
|
typedef xcb_key_press_event_t xcb_key_release_event_t;
|
|
|
|
*)
|
|
|
|
|
|
|
|
if (type = X11.LLEvent.KEY_PRESS)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class MyButton(X11.Button)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
method expose: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
|gc|
|
2017-04-05 16:48:20 +00:00
|
|
|
super expose: event.
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXx' dump.
|
2017-04-05 16:48:20 +00:00
|
|
|
gc := X11.GC new: self.
|
2017-04-07 15:50:05 +00:00
|
|
|
gc foreground: 16rFF8877.
|
2017-04-05 16:48:20 +00:00
|
|
|
gc _fillRect(0, 0, 50, 50).
|
|
|
|
gc close.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
class MyFrame(X11.FrameWindow)
|
2017-04-05 16:48:20 +00:00
|
|
|
{
|
|
|
|
dcl gc.
|
|
|
|
dcl b1.
|
|
|
|
dcl b2.
|
|
|
|
|
|
|
|
method windowOpened
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
super windowOpened.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
if (self.gc isNil)
|
|
|
|
{
|
|
|
|
self.gc := X11.GC new: self.
|
2017-04-07 15:50:05 +00:00
|
|
|
self.gc foreground: 10.
|
2017-04-05 16:48:20 +00:00
|
|
|
self.gc _drawLine(10, 20, 30, 40).
|
|
|
|
self.gc _drawRect(10, 20, 30, 40).
|
2017-04-07 15:50:05 +00:00
|
|
|
self.gc foreground: 20.
|
2017-04-05 16:48:20 +00:00
|
|
|
self.gc _drawRect(100, 100, 200, 200).
|
|
|
|
}.
|
|
|
|
|
2017-04-07 15:50:05 +00:00
|
|
|
self.b1 := MyButton new: self.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method windowClosing
|
|
|
|
{
|
|
|
|
super windowClosing.
|
|
|
|
(*if (self.gc notNil)
|
|
|
|
{
|
|
|
|
self.gc close.
|
|
|
|
self.gc := nil.
|
|
|
|
}*)
|
|
|
|
}
|
|
|
|
|
|
|
|
method expose: event
|
|
|
|
{
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
| rect |
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
super expose: event.
|
|
|
|
|
|
|
|
(*
|
|
|
|
('EXPOSE....' & (self.id asString) & ' ' & (event x asString) & ' ' & (event y asString) & ' ' & (event width asString) & ' ' & (event height asString)) dump.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
self.gc foreground: 2.
|
2017-04-05 16:48:20 +00:00
|
|
|
##self.gc drawLine: (10@20) to: (30@40).
|
|
|
|
self.gc _drawLine(10, 20, 300, 400).
|
|
|
|
self.gc _drawRect(10, 20, 30, 40).
|
2017-04-07 15:50:05 +00:00
|
|
|
self.gc foreground: 20.
|
2017-04-05 16:48:20 +00:00
|
|
|
self.gc _drawRect(100, 100, 200, 200).*)
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
rect := self bounds.
|
|
|
|
rect x: 0; y: 0; height: ((rect height) quo: 2); width: ((rect width) - 2).
|
|
|
|
self.b1 bounds: rect;
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyObject(Object)
|
|
|
|
{
|
|
|
|
method(#class) abc
|
|
|
|
{
|
|
|
|
^9234554123489129038123908123908312908
|
|
|
|
}
|
|
|
|
|
|
|
|
method(#class) main
|
|
|
|
{
|
2017-04-08 07:23:31 +00:00
|
|
|
| f q p disp1 disp2 disp3 |
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
f := 20.
|
|
|
|
(q:=:{ 10 -> 20, 20 -> 30, f + 40 -> self abc, (Association key: 10 value: 49), f -> f })dump.
|
|
|
|
(q at: 60) dump.
|
|
|
|
(q at: 10) dump.
|
|
|
|
|
|
|
|
|
|
|
|
#( #a:y: #b #c) dump.
|
|
|
|
f := LinkedList new.
|
|
|
|
f addLast: 10.
|
|
|
|
f addLast: 20.
|
|
|
|
q := f addLast: 30.
|
|
|
|
f addLast: 40.
|
|
|
|
f removeLink: q.
|
|
|
|
f addLastLink: q.
|
|
|
|
(f findLink: 30) prev value dump.
|
|
|
|
|
|
|
|
f do: [:v | v dump ].
|
|
|
|
(f size asString & ' elements in list') dump.
|
|
|
|
|
2017-04-08 07:23:31 +00:00
|
|
|
disp1 := X11 new.
|
|
|
|
disp2 := X11 new.
|
|
|
|
disp3 := X11 new.
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
##X11 connect.
|
2017-04-08 07:23:31 +00:00
|
|
|
f := MyFrame new: disp2.
|
|
|
|
q := MyFrame new: disp1.
|
|
|
|
p := MyFrame new: disp3.
|
|
|
|
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
## MyButton new: q.
|
|
|
|
## MyButton new: f.
|
|
|
|
|
|
|
|
(*
|
|
|
|
f add: X11.Button new: 'click me'.
|
|
|
|
f width: 200 height: 200.
|
|
|
|
f show.
|
|
|
|
*)
|
|
|
|
|
2017-04-08 07:23:31 +00:00
|
|
|
disp1 enterEventLoop. ## this is not a blocking call. it spawns another process.
|
|
|
|
disp2 enterEventLoop.
|
|
|
|
disp3 enterEventLoop.
|
2017-04-05 16:48:20 +00:00
|
|
|
|
|
|
|
(*while (true)
|
|
|
|
{
|
|
|
|
'111' dump.
|
|
|
|
##x signal_event_loop_semaphore.
|
|
|
|
Processor sleepFor: 5.
|
|
|
|
}.*)
|
|
|
|
## [ while (true) { '111' dump. Processor sleepFor: 1. } ] fork.
|
|
|
|
|
|
|
|
##X11 disconnect.
|
2017-04-07 15:50:05 +00:00
|
|
|
|
|
|
|
##X11 closeDefaultDisplay.
|
2017-04-05 16:48:20 +00:00
|
|
|
}
|
|
|
|
}
|