From 16ff8460136e15a9c19a64e1dab4877b4976305c Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Sun, 18 Jun 2017 17:29:32 +0000 Subject: [PATCH] ongoing x11 experiment --- moo/kernel/X11.moo | 372 +++++++++++++++++++++++---------------------- moo/mod/_x11.h | 7 - moo/mod/x11.c | 280 ++++++++++++++++++++++++++-------- 3 files changed, 407 insertions(+), 252 deletions(-) diff --git a/moo/kernel/X11.moo b/moo/kernel/X11.moo index 875cc6e..c950540 100644 --- a/moo/kernel/X11.moo +++ b/moo/kernel/X11.moo @@ -2,6 +2,9 @@ class X11(Object) from 'x11' { + var display_base := nil. + var shell_container := nil. + var windows. ## all windows registered var event_loop_sem, event_loop_proc. @@ -12,15 +15,13 @@ class X11(Object) from 'x11' var mouse_event. var mouse_wheel_event. - method(#primitive,#liberal) _connect(name). - method(#primitive) _disconnect. - method(#primitive) _get_base. - method(#primitive) _get_fd. - method(#primitive) _get_event. + method(#class,#primitive,#liberal) _open_display(name). + method(#class,#primitive) _close_display(display). + method(#class,#primitive) _get_fd(display). + method(#class,#primitive) _get_event(display, event). + method(#class,#primitive) _create_window(display, window, x, y, width, height, fgcolor, bgcolor). - method server { ^self } - method serverBase { ^self _get_base } - method windowBase { ^nil } + method(#primitive) _get_evtbuf. } class X11.Exception(System.Exception) @@ -107,99 +108,147 @@ class X11.ExposeEvent(X11.Event) } + ## --------------------------------------------------------------------------- -## Window +## X11 Widgets ## --------------------------------------------------------------------------- + class X11.Widget(Object) { - var(#get,#set) parent. + var(#get,#set) + parent := nil, + x := 0, + y := 0, + width := 0, + height := 0, + fgcolor := 0, + bgcolor := 0, + realized := false. - method server + method displayOn: grctx { - | p pp | - p := self. - while ((pp := p parent) notNil) { p := pp }. - ^p server. } - method serverBase { ^self server serverBase } - method windowBase { ^nil} - - - ##method displayOn: gc { } -} - -class X11.Window(selfns.Widget) from 'x11.win' -{ - var bounds. - - method(#primitive) _make_window(server, x, y, width, height, parent). - method(#primitive) _kill_window. - method(#primitive) _get_base. - method(#primitive) _get_bounds(rect). - method(#primitive) _set_bounds(rect). - - method(#class) new: parent + method displayBase { - ^(super new) __open_on: parent. + if (self.parent isNil) { ^nil }. + ^self.parent displayBase. } - method initialize + method realize { - self.bounds := selfns.Rectangle new. - } - - method __open_on: parent - { - | server winbase | - - server := parent server. - winbase := self _make_window (server serverBase, 5, 5, 400, 400, parent windowBase). - - (* - if (server _make_window (5, 5, 400, 400, parent, self) isError) - { - X11.Exception signal: 'cannot make a window' - }. - *) - - if (server ~= parent) - { - self.parent := parent. - self.parent addWidget: self. - }. - - server addWindow: self. - - self _get_bounds(self.bounds). - self windowOpened. } method dispose { - if (self windowBase notNil) + } +} + +class X11.Label(X11.Widget) +{ + var(#get) text := ''. + + method text: text + { + self.text := text. + self displayOn: nil. + } + + method displayOn: grctx + { + ## grctx _fillRectangle (). + ## grctx _drawText (...). + ## TODO Draw Text... + } + + method realize + { + ## if i want to use a window to represent it, it must create window here. + ## otherwise, do other works in displayOn??? + } + + method dispose + { + } +} + +class X11.Composite(X11.Widget) +{ + var children. + + method initialize + { + self.children := LinkedList new. + } + + method add: widget + { + if (widget parent notNil) { - self windowClosing. + selfns.Exception signal: 'Cannot add an already added widget'. + }. - self server removeWindow: self. - if (self.parent notNil) { self.parent removeWidget: self }. + self.children addLast: widget. + widget parent: self. + } - self _dispose_window. - self windowClosed. ## you can't make a primitive call any more + method remove: widget + { + | link | + if (widget parent =~ self) + { + selfns.Exception sinal: 'Cannot remove a foreign widget' + }. - ##self.wid := nil. - self.parent := nil. + ## TODO: unmap and destroy... + link := self.children findLink: widget. + self.children removeLink: link. + widget parent: nil. + } + + method childrenCount + { + ^self.children size + } + + method dispose + { + self.children do: [:child | child dispose ] + } +} + +class X11.Shell(X11.Composite) +{ + var(#get) title. + var(#get,#set) displayBase. + + method new: title + { + self.title := title. + } + + method title: title + { + self.title := title. + if (self.realized) + { + ## set window title of this window. } } - method windowBase { ^self _get_base } -} - -class X11.FrameWindow(selfns.Window) -{ - method(#class) new: server + method realize { - ^super new: server. + | wind | + if (self.realized) { ^self }. + + wind := X11 _create_window(self.displayBase, nil, self.x, self.y, self.width, self.height, self.fgcolor, self.bgcolor). + if (wind isError) + { + self.Exception signal: ('Cannot create shell ' & self.title). + }. + + self.children do: [:child | child realize ]. + self.realized := true. } } @@ -210,30 +259,46 @@ extend X11 { method(#class) new { - ^(super new) __connect_to_server: nil. + ^(super new) __connect_to: nil. } - method __connect_to_server: name + method __connect_to: name { | base | - base := self _connect(name). - if (base isError) { X11.Exception signal: 'cannot connect to server' }. - ##self.base := base. + base := X11 _open_display(name). + if (base isError) { self.Exception signal: 'cannot open display' }. + self.display_base := base. } - method close + method dispose { - if (self _get_base notNil) + if (self.display_event notNil) { - self _disconnect. - ##self.cid := nil. - } + X11 _free_event. + self.display_event := nil. + }. + + if (self.shell_container notNil) + { + self.shell_container dispose. + self.shell_container := nil. + }. + + if (self.display_base notNil) + { + + X11 _close_display (self.display_base). + self.display_base := nil. + }l } method initialize { super initialize. + self.shell_container := self.Composite new. + self.display_event := self _alloc_event. + self.windows := System.Dictionary new: 100. self.expose_event := self.ExposeEvent new. @@ -271,30 +336,25 @@ extend X11 }. } - method connect + method addShell: shell { - | cid | - if (self.windows isNil) + if (shell displayBase isNil) { - if ((cid := self _connect) isError) { ^cid }. - ##self.cid := cid. - self.windows := System.Dictionary new. + self.shell_container add: shell. + shell displayBase: self.display_base. } } - method disconnect + method removeShell: shell { - if (self.windows notNil) + if (shell displayBase notNil) { - self.windows do: [ :frame | - frame close. - ]. - self.windows := nil. - self _disconnect. + self.shell_container remove: shell. + shell displayBase: nil. } } - method addWindow: window + method registerWindow: window { ^self.windows at: (window windowBase) put: window. } @@ -309,18 +369,18 @@ extend X11 if (self.event_loop_sem isNil) { self.event_loop_sem := Semaphore new. - Processor signal: self.event_loop_sem onInput: (self _get_fd). + Processor signal: self.event_loop_sem onInput: (X11 _get_fd(self.display_base)). self.event_loop_proc := [ | event ongoing | ongoing := true. - while (self.windows size > 0) + while (self.shell_container childrenCount > 0) { ###'Waiting for X11 event...' dump. self.event_loop_sem wait. if (ongoing not) { break }. - while ((event := self _get_event) notNil) + while (self _get_event(self.display_base, self.display_event)) { if (event isError) { @@ -338,7 +398,8 @@ extend X11 Processor unsignal: self.event_loop_sem. self.event_loop_sem := nil. - self disconnect. + self dispose. +'CLOSING X11 EVENT LOOP' dump. ] fork. } } @@ -408,91 +469,36 @@ extend X11 } } -class MyWidget(Window) -{ -} - -class MyFrame(X11.FrameWindow) -{ - var gc. - method windowOpened - { - super windowOpened. - - (* - if (self.gc isNil) - { - self.gc := X11.GC new: self. -self.gc foreground: 10. -self.gc _drawLine(10, 20, 30, 40). -self.gc _drawRect(10, 20, 30, 40). -self.gc foreground: 20. -self.gc _drawRect(100, 100, 200, 200). - }. - - self.b1 := MyWidget new: self.*) - - self windowResized. - } - - method windowClosing - { - super windowClosing. - (*if (self.gc notNil) - { - self.gc close. - self.gc := nil. - }*) - } - - method windowResized - { - (* - | rect | - - super windowResized. - - rect := self bounds. - rect x: 0; y: 0; height: ((rect height) quo: 2); width: ((rect width) - 2). - self.b1 bounds: rect;*) - } - - method expose: event - { - super expose: event. - } -} class MyObject(Object) { + var disp1, shell1, shell2. + + method main1 + { + self.disp1 := X11 new. + + shell1 := (X11.Shell new title: 'Shell 1'). + shell2 := (X11.Shell new title: 'Shell 2'). + + shell1 x: 10; y: 20; width: 100; height: 100. + shell2 x: 200; y: 200; width: 200; height: 200. + + self.disp1 addShell: shell1. + self.disp1 addShell: shell2. + + self.shell1 add: (X11.Label new text: 'xxxxxxxx'). + self.shell1 realize. + self.shell2 realize. + + self.disp1 enterEventLoop. ## this is not a blocking call. it spawns another process. + } method(#class) main { - | disp1 disp2 disp3 f q p | - - disp1 := X11 new. - disp2 := X11 new. - disp3 := X11 new. - - f := MyFrame new: disp2. - q := MyFrame new: disp1. - p := MyFrame new: disp3. - - disp1 enterEventLoop. ## this is not a blocking call. it spawns another process. - disp2 enterEventLoop. - disp3 enterEventLoop. - - ##disp1 := X11 new. - ##f := MyFrame new. - ##f add: Button new. - ##f add: Button new. - ##g := MyFrame new. - ##g add: (b := Button new). - ##disp1 add: f. - ##disp1 add: g. - ##disp1 enterEventLoop. + ^self new main1 } - } + diff --git a/moo/mod/_x11.h b/moo/mod/_x11.h index acb7579..c037280 100644 --- a/moo/mod/_x11.h +++ b/moo/mod/_x11.h @@ -38,13 +38,6 @@ #define MC MOO_METHOD_CLASS #define MI MOO_METHOD_INSTANCE -typedef struct x11_t x11_t; -struct x11_t -{ - Display* disp; - XEvent* curevt; -}; - typedef struct x11_win_t x11_win_t; struct x11_win_t { diff --git a/moo/mod/x11.c b/moo/mod/x11.c index ef51c91..0682904 100644 --- a/moo/mod/x11.c +++ b/moo/mod/x11.c @@ -39,21 +39,36 @@ struct x11_modctx_t /* ------------------------------------------------------------------------ */ -static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) +#if 0 +static moo_pfrc_t pf_get_base (moo_t* moo, moo_ooi_t nargs) { x11_trailer_t* x11; - Display* disp = MOO_NULL; - XEvent* curevt = MOO_NULL; - char* dispname = MOO_NULL; x11 = (x11_trailer_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); if (x11->disp) { - MOO_DEBUG0 (moo, " Unable to open a display multiple times\n"); - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EEXIST); - goto oops; + MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP (x11->disp)); } + else + { + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ENOAVAIL); + } + + return MOO_PF_SUCCESS; +} + + +#endif + +/* ------------------------------------------------------------------------ */ + +static moo_pfrc_t pf_open_display (moo_t* moo, moo_ooi_t nargs) +{ + x11_trailer_t* x11; + Display* disp = MOO_NULL; + XEvent* curevt = MOO_NULL; + char* dispname = MOO_NULL; if (nargs >= 1) { @@ -96,9 +111,6 @@ static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) goto oops; } - x11->disp = disp; - x11->curevt = curevt; - MOO_ASSERT (moo, MOO_IN_SMPTR_RANGE(disp)); MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(disp)); @@ -112,57 +124,40 @@ oops: return MOO_PF_SUCCESS; } -static moo_pfrc_t pf_disconnect (moo_t* moo, moo_ooi_t nargs) +static moo_pfrc_t pf_close_display (moo_t* moo, moo_ooi_t nargs) { - x11_trailer_t* x11; + moo_oop_t a0; + + a0 = MOO_STACK_GETARG(moo, nargs, 0); - x11 = (x11_trailer_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - - if (x11->curevt) + if (!MOO_OOP_IS_SMPTR(a0)) { - moo_freemem (moo, x11->curevt); - x11->curevt = MOO_NULL; - } - - if (x11->disp) - { - XCloseDisplay (x11->disp); - x11->disp = MOO_NULL; - } - - MOO_STACK_SETRETTORCV (moo, nargs); - return MOO_PF_SUCCESS; -} - -static moo_pfrc_t pf_get_base (moo_t* moo, moo_ooi_t nargs) -{ - x11_trailer_t* x11; - - x11 = (x11_trailer_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - - if (x11->disp) - { - MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP (x11->disp)); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); } else { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ENOAVAIL); + XCloseDisplay (MOO_OOP_TO_SMPTR(a0)); + MOO_STACK_SETRETTORCV (moo, nargs); } - return MOO_PF_SUCCESS; } + static moo_pfrc_t pf_get_fd (moo_t* moo, moo_ooi_t nargs) { - x11_trailer_t* x11; + moo_oop_t a0; - x11 = (x11_trailer_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + a0 = MOO_STACK_GETARG(moo, nargs, 0); - if (x11->disp) + if (!MOO_OOP_IS_SMPTR(a0)) { - int c; + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + } + else + { + moo_ooi_t c; + c = ConnectionNumber(MOO_OOP_TO_SMPTR(a0)); - c = ConnectionNumber(x11->disp); if (!MOO_IN_SMOOI_RANGE(c)) { MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ERANGE); @@ -172,48 +167,210 @@ static moo_pfrc_t pf_get_fd (moo_t* moo, moo_ooi_t nargs) MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(c)); } } - else - { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ENOAVAIL); - } return MOO_PF_SUCCESS; } static moo_pfrc_t pf_get_event (moo_t* moo, moo_ooi_t nargs) { - x11_trailer_t* x11; + + moo_oop_t a0, a1; - x11 = (x11_trailer_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - if (XPending(x11->disp)) + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* display - SmallPointer (Display*) */ + a1 = MOO_STACK_GETARG(moo, nargs, 1); /* event to return - SmallPointer (XEvent*) */ + + + if (!MOO_OOP_IS_SMPTR(a0) || !MOO_OOP_IS_SMPTR(a1)) { - XNextEvent (x11->disp, x11->curevt); - MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(x11->curevt)); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); } else { - /* nil if there is no event */ - MOO_STACK_SETRET (moo, nargs, moo->_nil); + Display* disp; + XEvent* event; + + disp = MOO_OOP_TO_SMPTR(a0); + event = MOO_OOP_TO_SMPTR(a1); + if (XPending(disp)) + { + XNextEvent (disp, event); + MOO_STACK_SETRET (moo, nargs, moo->_true); + } + else + { + /* nil if there is no event */ + MOO_STACK_SETRET (moo, nargs, moo->_false); + } } return MOO_PF_SUCCESS; } + +static moo_pfrc_t pf_get_evtbuf (moo_t* moo, moo_ooi_t nargs) +{ + x11_trailer_t* tr; + + tr = moo_getobjtrailer (moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + + + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_create_window (moo_t* moo, moo_ooi_t nargs) +{ + Window wind; /* Window -> XID, unsigned long */ + + Display* disp; + int scrn; + Window parent; + XSetWindowAttributes attrs; + + moo_oop_t a0, a1, a2, a3, a4, a5, a6, a7; + + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* display - SmallPointer (Display*) */ + a1 = MOO_STACK_GETARG(moo, nargs, 1); /* parent window - Integer or nil (Window) */ + a2 = MOO_STACK_GETARG(moo, nargs, 2); /* x - SmallInteger */ + a3 = MOO_STACK_GETARG(moo, nargs, 3); /* y - SmallInteger */ + a4 = MOO_STACK_GETARG(moo, nargs, 4); /* width - SmallInteger */ + a5 = MOO_STACK_GETARG(moo, nargs, 5); /* height - SmallInteger */ + a6 = MOO_STACK_GETARG(moo, nargs, 6); /* fgcolor - SmallInteger */ + a7 = MOO_STACK_GETARG(moo, nargs, 7); /* bgcolor - SmallInteger */ + + if (!MOO_OOP_IS_SMPTR(a0) || + !MOO_OOP_IS_SMOOI(a2) || !MOO_OOP_IS_SMOOI(a3) || !MOO_OOP_IS_SMOOI(a4) || + !MOO_OOP_IS_SMOOI(a5) || !MOO_OOP_IS_SMOOI(a6) || !MOO_OOP_IS_SMOOI(a7)) + { + einval: + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + goto done; + } + + disp = MOO_OOP_TO_SMPTR(a0); + + if (a1 == moo->_nil) + { + scrn = DefaultScreen (disp); + parent = RootWindow (disp, scrn); + } + else + { + moo_oow_t tmpoow; + XWindowAttributes wa; + if (moo_inttooow(moo, a1, &tmpoow) <= 0) goto einval; + + parent = tmpoow; + XGetWindowAttributes (disp, parent, &wa); + MOO_ASSERT (moo, XRootWindowOfScreen(wa.screen) == parent); + scrn = XScreenNumberOfScreen(wa.screen); + } + + attrs.event_mask = ExposureMask; /* TODO: accept it as a parameter??? */ + attrs.border_pixel = BlackPixel (disp, scrn); /* TODO: use a6 */ + attrs.background_pixel = WhitePixel (disp, scrn);/* TODO: use a7 */ + + wind = XCreateWindow ( + disp, + parent, + MOO_OOP_TO_SMOOI(a2), /* x */ + MOO_OOP_TO_SMOOI(a3), /* y */ + MOO_OOP_TO_SMOOI(a4), /* width */ + MOO_OOP_TO_SMOOI(a5), /* height */ + 1, /* border width */ + CopyFromParent, /* depth */ + InputOutput, /* class */ + CopyFromParent, /* visual */ + CWEventMask | CWBackPixel | CWBorderPixel, &attrs); + if (!wind) + { + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ESYSERR); + goto done; + } + + a0 = moo_oowtoint (moo, wind); + if (!a0) + { + MOO_STACK_SETRETTOERRNUM (moo, nargs); + goto done; + } + +/* TODO: remvoe this */ +XMapWindow (disp, wind); +XFlush (disp); + +#if 0 + if (parent == screen->root) + { + cookie = xcb_intern_atom(c, 1, 12, "WM_PROTOCOLS"); + reply = xcb_intern_atom_reply(c, cookie, 0); + + cookie = xcb_intern_atom(c, 0, 16, "WM_DELETE_WINDOW"); + win->dwar = xcb_intern_atom_reply(c, cookie, 0); + + xcb_change_property(c, XCB_PROP_MODE_REPLACE, wid, reply->atom, 4, 32, 1, &win->dwar->atom); + } +#endif + + MOO_STACK_SETRET (moo, nargs, a0); +done: + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_destroy_window (moo_t* moo, moo_ooi_t nargs) +{ + moo_oop_t a0, a1; + + + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* display - SmallPointer (Display*) */ + a1 = MOO_STACK_GETARG(moo, nargs, 1); /* window - Integer (Window) */ + + if (!MOO_OOP_IS_SMPTR(a0)) + + { + einval: + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + } + else + { + Display* disp; + moo_oow_t wind; + + disp = MOO_OOP_TO_SMPTR(a0); + if (moo_inttooow(moo, a1, &wind) <= 0) goto einval; + + XUnmapWindow (disp, (Window)wind); + XDestroyWindow (disp, (Window)wind); +XFlush (disp); + + MOO_STACK_SETRETTORCV (moo, nargs); + } + return MOO_PF_SUCCESS; +} + + /* ------------------------------------------------------------------------ */ static moo_pfinfo_t x11_pfinfo[] = { + { MC, { '_','c','l','o','s','e','_','d','i','s','p','l','a','y','\0' }, 0, { pf_close_display, 1, 1 } }, + { MC, { '_','c','r','e','a','t','e','_','w','i','n','d','o','w','\0' }, 0, { pf_create_window, 8, 8 } }, + { MC, { '_','d','e','s','t','r','o','y','_','w','i','n','d','o','w','\0' }, 0, { pf_destroy_window, 2, 2 } }, + { MC, { '_','g','e','t','_','e','v','e','n','t','\0'}, 0, { pf_get_event, 2, 2 } }, + { MI, { '_','g','e','t','_','e','v','t','b','u','f','\0'}, 0, { pf_get_evtbuf, 0, 0 } }, + { MC, { '_','g','e','t','_','f','d','\0' }, 0, { pf_get_fd, 1, 1 } }, + { MC, { '_','o','p','e','n','_','d','i','s','p','l','a','y','\0' }, 0, { pf_open_display, 0, 1 } } + - { MI, { '_','c','o','n','n','e','c','t','\0' }, 0, { pf_connect, 0, 1 } }, - { MI, { '_','d','i','s','c','o','n','n','e','c','t','\0' }, 0, { pf_disconnect, 0, 0 } }, +#if 0 { MI, { '_','g','e','t','_','b','a','s','e','\0' }, 0, { pf_get_base, 0, 0 } }, - { MI, { '_','g','e','t','_','e','v','e','n','t','\0'}, 0, { pf_get_event, 0, 0 } }, - { MI, { '_','g','e','t','_','f','d','\0' }, 0, { pf_get_fd, 0, 0 } } + + +#endif }; static int x11_import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) { - if (moo_setclasstrsize(moo, _class, MOO_SIZEOF(x11_t), MOO_NULL) <= -1) return -1; + if (moo_setclasstrsize(moo, _class, MOO_SIZEOF(x11_trailer_t), MOO_NULL) <= -1) return -1; return 0; } @@ -273,4 +430,3 @@ int moo_mod_x11 (moo_t* moo, moo_mod_t* mod) } /* ------------------------------------------------------------------------ */ -