From 246662220f188b30c4aa3d0cfd3d20dfe86fd990 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Fri, 23 Jun 2017 16:09:07 +0000 Subject: [PATCH] interim commit of ongoing X11 works --- moo/kernel/X11.moo | 296 ++++++++++++++++++++++----------- moo/lib/main.c | 52 +++--- moo/mod/_x11.h | 23 ++- moo/mod/x11.c | 406 +++++++++++++++++++++++++++------------------ 4 files changed, 494 insertions(+), 283 deletions(-) diff --git a/moo/kernel/X11.moo b/moo/kernel/X11.moo index c950540..eace872 100644 --- a/moo/kernel/X11.moo +++ b/moo/kernel/X11.moo @@ -2,26 +2,49 @@ class X11(Object) from 'x11' { + ## ===================================================================== + ## this part of the class must match the internal + ## definition struct x11_t defined in _x11.h + ## --------------------------------------------------------------------- var display_base := nil. - var shell_container := nil. - - var windows. ## all windows registered - - var event_loop_sem, event_loop_proc. - var ll_event_blocks. - + var llevent. var expose_event. var key_event. var mouse_event. var mouse_wheel_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). + var shell_container := nil. + var window_registrar. ## all windows registered - method(#primitive) _get_evtbuf. + var event_loop_sem, event_loop_proc. + var llevent_blocks. + + method(#primitive,#liberal) _open_display(name). + method(#primitive) _close_display. + method(#primitive) _get_fd. + method(#primitive) _get_event. + + method(#primitive) _create_window(parent_window, x, y, width, height, fgcolor, bgcolor). + method(#primitive) _destroy_window(window). + + ##method(#primitive) _fill_rectangle(window, gc, x, y, width, height). + method(#primitive) _draw_rectangle(window, gc, x, y, width, height). + + method __create_window(parent_window, x, y, width, height, fgcolor, bgcolor, owner) + { + | w | + w := self _create_window(parent_window, x, y, width, height, fgcolor, bgcolor). + if (w notError) { self.window_registrar at: w put: owner }. + ^w + } + + method __close_window(window_handle) + { + | w | + w := self _destroy_window(window_handle). + if (w notError) { self.window_registrar removeKey: window_handle } + } } class X11.Exception(System.Exception) @@ -50,7 +73,7 @@ class X11.Rectangle(Object) ## --------------------------------------------------------------------------- ## Event ## --------------------------------------------------------------------------- -pooldic X11.LLEvent +pooldic X11.LLEventType { KEY_PRESS := 2. KEY_RELEASE := 3. @@ -66,6 +89,11 @@ pooldic X11.LLEvent CLIENT_MESSAGE := 33. } +class X11.LLEvent(Object) +{ + var(#get) type := 0, window := 0, x := 0, y := 0, width := 0, height := 0. +} + class X11.Event(Object) { } @@ -109,6 +137,45 @@ class X11.ExposeEvent(X11.Event) +## --------------------------------------------------------------------------- +## X11 Context +## --------------------------------------------------------------------------- +class X11.GraphicsContext(Object) +{ + var(#get) widget := nil, gcHandle := nil. + + var(#get,#set) + foreground := 0, + background := 0, + lineWidth := 1, + lineStyle := 0, + fillStyle := 0. + + method(#class) new: widget + { + ^(super new) __make_gc_on: widget + } + + method __make_gc_on: widget + { + | gc | + gc := widget displayServer _create_gc (widget windowHandle). + if (gc isError) { selfns.Exception signal: 'Cannot create a graphics context' }. + self.gcHandle := gc. + self.widget := widget. + } + + method fillRectangle(x, y, width, height) + { + ^self.widget displayServer _fill_rectangle (self.widget windowHandle, self.gcHandle, x, y, width, height). + } + + method drawRectangle(x, y, width, height) + { + ^self.widget displayServer _draw_rectangle (self.widget windowHandle, self.gcHandle, x, y, width, height). + } +} + ## --------------------------------------------------------------------------- ## X11 Widgets ## --------------------------------------------------------------------------- @@ -125,23 +192,41 @@ class X11.Widget(Object) bgcolor := 0, realized := false. - method displayOn: grctx - { - } - method displayBase + method displayServer { if (self.parent isNil) { ^nil }. - ^self.parent displayBase. + ^self.parent displayServer. + } + + method windowHandle + { + (* i assume that a widget doesn't' with a low-level window by default. + * if a widget maps to a window, the widget class must implement the + * windowHandle method to return the low-level window handle. + * if it doesn't map to a window, it piggybacks on the parent's window *) + if (self.parent isNil) { ^nil }. + ^self.parent windowHandle. + } + + method paint: paint_event + { } method realize { + ## super realize chaining required??? } method dispose { - } + ## what should be done first? remvoe from container? should dispose be called? + ## super dispose chaining required? + ##if (self.parent notNil) + ##{ + ## self.parent remove: self. + ##} + } } class X11.Label(X11.Widget) @@ -151,24 +236,28 @@ class X11.Label(X11.Widget) method text: text { self.text := text. - self displayOn: nil. + if (self windowHandle notNil) { self paint: nil } } - method displayOn: grctx + method paint: paint_event { - ## grctx _fillRectangle (). - ## grctx _drawText (...). - ## TODO Draw Text... + | gc | +System logNl: 'LABEL GC.......'. + gc := selfns.GraphicsContext new: self. + gc foreground: 100. + gc drawRectangle (self.x, self.y, self.width, self.height). + ###gc.drawText (self.title) } method realize { ## if i want to use a window to represent it, it must create window here. - ## otherwise, do other works in displayOn??? + ## otherwise, do other works in paint:??? } method dispose { + } } @@ -197,7 +286,7 @@ class X11.Composite(X11.Widget) | link | if (widget parent =~ self) { - selfns.Exception sinal: 'Cannot remove a foreign widget' + selfns.Exception sinal: 'Cannot remove an unknown widget' }. ## TODO: unmap and destroy... @@ -213,14 +302,15 @@ class X11.Composite(X11.Widget) method dispose { - self.children do: [:child | child dispose ] + self.children do: [:child | child dispose ] } } class X11.Shell(X11.Composite) { - var(#get) title. - var(#get,#set) displayBase. + var(#get) title := ''. + var(#get,#set) displayServer := nil. + var(#get) windowHandle := nil. method new: title { @@ -230,7 +320,7 @@ class X11.Shell(X11.Composite) method title: title { self.title := title. - if (self.realized) + if (self.windowHandle notNil) { ## set window title of this window. } @@ -239,16 +329,36 @@ class X11.Shell(X11.Composite) method realize { | wind | - if (self.realized) { ^self }. + if (self.windowHandle notNil) { ^self }. - wind := X11 _create_window(self.displayBase, nil, self.x, self.y, self.width, self.height, self.fgcolor, self.bgcolor). + wind := self.displayServer __create_window(nil, self.x, self.y, self.width, self.height, self.fgcolor, self.bgcolor, self). if (wind isError) { self.Exception signal: ('Cannot create shell ' & self.title). }. - self.children do: [:child | child realize ]. - self.realized := true. + self.windowHandle := wind. + + [ + self.children do: [:child | child realize ]. + ] on: System.Exception do: [:ex | + self.displayServer _destroy_window(wind). + self.windowHandle := nil. + ex pass + ]. + +### call displayOn: from the exposure handler... +self paint: nil. + } + + method dispose + { + super dispose. + if (self.windowHandle notNil) + { + self.displayServer _destroy_window (self.windowHandle). + self.windowHandle := nil. + } } } @@ -264,20 +374,16 @@ extend X11 method __connect_to: name { - | base | - base := X11 _open_display(name). - if (base isError) { self.Exception signal: 'cannot open display' }. - self.display_base := base. + if (self _open_display(name) isError) + { + self.Exception signal: 'cannot open display' + } +. + self.display_base dump. } method dispose { - if (self.display_event notNil) - { - X11 _free_event. - self.display_event := nil. - }. - if (self.shell_container notNil) { self.shell_container dispose. @@ -286,101 +392,95 @@ extend X11 if (self.display_base notNil) { + self _close_display. + ##self.display_base := nil. + }. - X11 _close_display (self.display_base). - self.display_base := nil. - }l + ## TODO: check if _fini_trailer is not called for some exception throwing... + ##self _fini_trailer. } method initialize { super initialize. - self.shell_container := self.Composite new. - self.display_event := self _alloc_event. - - self.windows := System.Dictionary new: 100. - + self.llevent := self.LLEvent new. self.expose_event := self.ExposeEvent new. self.key_event := self.KeyEvent new. self.mouse_event := self.MouseEvent new. self.mouse_wheel_event := self.MouseWheelEvent new. + self.shell_container := self.Composite new. + self.window_registrar := System.Dictionary new: 100. + (* - self.ll_event_blocks := System.Dictionary new. - self.ll_event_blocks - at: self.LLEvent.KEY_PRESS put: #__handle_key_event:; - at: self.LLEvent.KEY_RELEASE put: #__handle_key_event:; - at: self.LLEvent.BUTTON_PRESS put: #__handle_button_event:; - at: self.LLEvent.BUTTON_RELEASE put: #__handle_button_event:; - at: self.LLEvent.MOTION_NOTIFY put: #__handle_notify:; - at: self.LLEvent.ENTER_NOTIFY put: #__handle_notify:; - at: self.LLEvent.LEAVE_NOTIFY put: #__handle_notify:; - at: self.LLEvent.EXPOSE put: #__handle_expose:; - at: self.LLEvent.DESTROY_NOTIFY put: #__handle_destroy_notify:; - at: self.LLEvent.CONFIGURE_NOTIFY put: #__handle_configure_notify:; - at: self.LLEvent.CLIENT_MESSAGE put: #__handle_client_message:. + + self.llevent_blocks := System.Dictionary new. + self.llevent_blocks + at: self.LLEventType.KEY_PRESS put: #__handle_key_event:; + at: self.LLEventType.KEY_RELEASE put: #__handle_key_event:; + at: self.LLEventType.BUTTON_PRESS put: #__handle_button_event:; + at: self.LLEventType.BUTTON_RELEASE put: #__handle_button_event:; + at: self.LLEventType.MOTION_NOTIFY put: #__handle_notify:; + at: self.LLEventType.ENTER_NOTIFY put: #__handle_notify:; + at: self.LLEventType.LEAVE_NOTIFY put: #__handle_notify:; + at: self.LLEventType.EXPOSE put: #__handle_expose:; + at: self.LLEventType.DESTROY_NOTIFY put: #__handle_destroy_notify:; + at: self.LLEventType.CONFIGURE_NOTIFY put: #__handle_configure_notify:; + at: self.LLEventType.CLIENT_MESSAGE put: #__handle_client_message:. *) - self.ll_event_blocks := %{ - self.LLEvent.KEY_PRESS -> #__handle_key_event:, - self.LLEvent.KEY_RELEASE -> #__handle_key_event:, - self.LLEvent.BUTTON_PRESS -> #__handle_button_event:, - self.LLEvent.BUTTON_RELEASE -> #__handle_button_event:, - self.LLEvent.MOTION_NOTIFY -> #__handle_notify:, - self.LLEvent.ENTER_NOTIFY -> #__handle_notify:, - self.LLEvent.LEAVE_NOTIFY -> #__handle_notify:, - self.LLEvent.EXPOSE -> #__handle_expose:, - self.LLEvent.DESTROY_NOTIFY -> #__handle_destroy_notify:, - self.LLEvent.CONFIGURE_NOTIFY -> #__handle_configure_notify:, - self.LLEvent.CLIENT_MESSAGE -> #__handle_client_message: + self.llevent_blocks := %{ + self.LLEventType.KEY_PRESS -> #__handle_key_event:, + self.LLEventType.KEY_RELEASE -> #__handle_key_event:, + self.LLEventType.BUTTON_PRESS -> #__handle_button_event:, + self.LLEventType.BUTTON_RELEASE -> #__handle_button_event:, + self.LLEventType.MOTION_NOTIFY -> #__handle_notify:, + self.LLEventType.ENTER_NOTIFY -> #__handle_notify:, + self.LLEventType.LEAVE_NOTIFY -> #__handle_notify:, + self.LLEventType.EXPOSE -> #__handle_expose:, + self.LLEventType.DESTROY_NOTIFY -> #__handle_destroy_notify:, + self.LLEventType.CONFIGURE_NOTIFY -> #__handle_configure_notify:, + self.LLEventType.CLIENT_MESSAGE -> #__handle_client_message: }. + } method addShell: shell { - if (shell displayBase isNil) + if (shell displayServer isNil) { self.shell_container add: shell. - shell displayBase: self.display_base. + shell displayServer: self. } } method removeShell: shell { - if (shell displayBase notNil) + if (shell displayServer notNil) { self.shell_container remove: shell. - shell displayBase: nil. + shell displayServer: nil. } } - method registerWindow: window - { - ^self.windows at: (window windowBase) put: window. - } - - method removeWindow: window - { - ^self.windows removeKey: (window windowBase) - } method enterEventLoop { if (self.event_loop_sem isNil) { self.event_loop_sem := Semaphore new. - Processor signal: self.event_loop_sem onInput: (X11 _get_fd(self.display_base)). + Processor signal: self.event_loop_sem onInput: (self _get_fd). self.event_loop_proc := [ - | event ongoing | + | evtbuf event ongoing | ongoing := true. while (self.shell_container childrenCount > 0) { -###'Waiting for X11 event...' dump. +'Waiting for X11 event...' dump. self.event_loop_sem wait. if (ongoing not) { break }. - while (self _get_event(self.display_base, self.display_event)) + while ((event := self _get_event) notNil) { if (event isError) { @@ -421,15 +521,16 @@ extend X11 method __dispatch_event: event { + (* | type mthname | + ##type := System _getUint8(event, 0). type := event getUint8(0). - mthname := self.ll_event_blocks at: (type bitAnd: 16r7F). + mthname := self.llevent_blocks at: (type bitAnd: 16r7F). if (mthname isError) { - (* unknown event. ignore it *) ('IGNORING UNKNOWN LL-EVENT TYPE ' & type asString) dump. } else @@ -437,6 +538,7 @@ extend X11 ^self perform (mthname, event). ##^self perform: mthname with: event. } + *) } method __handle_notify: type diff --git a/moo/lib/main.c b/moo/lib/main.c index 38cf474..376f4b6 100644 --- a/moo/lib/main.c +++ b/moo/lib/main.c @@ -166,28 +166,30 @@ typedef struct xtn_t xtn_t; struct xtn_t { const char* source_path; /* main source file */ + int vm_running; + #if defined(_WIN32) HANDLE waitable_timer; #else -#if defined(USE_DEVPOLL) || defined(USE_EPOLL) + #if defined(USE_DEVPOLL) || defined(USE_EPOLL) int ep; /* /dev/poll or epoll */ -#endif + #endif -#if defined(USE_DEVPOLL) || defined(USE_POLL) + #if defined(USE_DEVPOLL) || defined(USE_POLL) struct { moo_oow_t capa; moo_ooi_t* ptr; } epd; -#endif + #endif -#if defined(USE_THREAD) + #if defined(USE_THREAD) int p[2]; /* pipe for signaling */ pthread_t iothr; int iothr_up; int iothr_abort; -#endif + #endif struct { @@ -210,14 +212,12 @@ struct xtn_t #endif moo_oow_t len; -#if defined(USE_THREAD) + #if defined(USE_THREAD) pthread_mutex_t mtx; pthread_cond_t cnd; pthread_cond_t cnd2; -#endif + #endif } ev; - - #endif }; @@ -749,7 +749,6 @@ static void log_write (moo_t* moo, moo_oow_t mask, const moo_ooch_t* msg, moo_oo #endif } - /* ========================================================================= */ #if defined(USE_DEVPOLL) || defined(USE_POLL) static int secure_poll_data_space (moo_t* moo, int fd) @@ -1005,7 +1004,8 @@ static void* iothr_main (void* arg) if (n <= -1) { /* TODO: don't use MOO_DEBUG2. it's not thread safe... */ - MOO_DEBUG2 (moo, "Warning: epoll_wait failure - %d, %hs\n", errno, strerror(errno)); + /* the following call has a race-condition issue when called in this separate thread */ + /*MOO_DEBUG2 (moo, "Warning: epoll_wait failure - %d, %hs\n", errno, strerror(errno));*/ } else if (n > 0) { @@ -1094,18 +1094,19 @@ static int vm_startup (moo_t* moo) } pcount = 2; -#if defined(O_CLOEXEC) + #if defined(O_CLOEXEC) flag = fcntl (xtn->p[0], F_GETFD); if (flag >= 0) fcntl (xtn->p[0], F_SETFD, flag | FD_CLOEXEC); flag = fcntl (xtn->p[1], F_GETFD); if (flag >= 0) fcntl (xtn->p[1], F_SETFD, flag | FD_CLOEXEC); -#endif -#if defined(O_NONBLOCK) + #endif + + #if defined(O_NONBLOCK) flag = fcntl (xtn->p[0], F_GETFL); if (flag >= 0) fcntl (xtn->p[0], F_SETFL, flag | O_NONBLOCK); flag = fcntl (xtn->p[1], F_GETFL); if (flag >= 0) fcntl (xtn->p[1], F_SETFL, flag | O_NONBLOCK); -#endif + #endif if (_add_poll_fd (moo, xtn->p[0], XPOLLIN, MOO_TYPE_MAX(moo_oow_t)) <= -1) goto oops; @@ -1116,8 +1117,11 @@ static int vm_startup (moo_t* moo) xtn->iothr_abort = 0; xtn->iothr_up = 0; /*pthread_create (&xtn->iothr, MOO_NULL, iothr_main, moo);*/ -#endif + +#endif /* USE_THREAD */ + + xtn->vm_running = 1; return 0; oops: @@ -1155,6 +1159,7 @@ static void vm_cleanup (moo_t* moo) #else xtn_t* xtn = (xtn_t*)moo_getxtn(moo); + xtn->vm_running = 0; #if defined(USE_THREAD) if (xtn->iothr_up) @@ -1690,7 +1695,7 @@ static void handle_term (int sig) } } -static void setup_term (void) +static void setup_sigterm (void) { #if defined(_WIN32) SetConsoleCtrlHandler (handle_term, TRUE); @@ -1707,7 +1712,7 @@ static void setup_term (void) #endif } -static void clear_term (void) +static void clear_sigterm (void) { #if defined(_WIN32) SetConsoleCtrlHandler (handle_term, FALSE); @@ -1778,8 +1783,6 @@ int main (int argc, char* argv[]) moo_setoption (moo, MOO_SYSDIC_SIZE, &tab_size); tab_size = 600; moo_setoption (moo, MOO_PROCSTK_SIZE, &tab_size); - - } { @@ -1796,7 +1799,7 @@ int main (int argc, char* argv[]) if (moo_ignite(moo) <= -1) { - moo_logbfmt (moo, MOO_LOG_ERROR, "cannot ignite moo - [%d] %js\n", moo_geterrnum(moo), moo_geterrstr(moo)); + moo_logbfmt (moo, MOO_LOG_ERROR, "ERROR: cannot ignite moo - [%d] %js\n", moo_geterrnum(moo), moo_geterrstr(moo)); moo_close (moo); return -1; } @@ -1872,6 +1875,7 @@ int main (int argc, char* argv[]) } printf ("\n"); + fflush (stdout); } else { @@ -1889,7 +1893,7 @@ int main (int argc, char* argv[]) xret = 0; g_moo = moo; setup_tick (); - setup_term (); + setup_sigterm (); objname.ptr = str_my_object; objname.len = 8; @@ -1902,7 +1906,7 @@ int main (int argc, char* argv[]) } cancel_tick (); - clear_term (); + clear_sigterm (); g_moo = MOO_NULL; /*moo_dumpsymtab(moo); diff --git a/moo/mod/_x11.h b/moo/mod/_x11.h index c037280..dc57f98 100644 --- a/moo/mod/_x11.h +++ b/moo/mod/_x11.h @@ -45,19 +45,38 @@ struct x11_win_t Window wind; }; +typedef struct x11_llevent_t* oop_x11_llevent_t; +struct x11_llevent_t +{ + MOO_OBJ_HEADER; + moo_oop_t type; + moo_oop_t window; + moo_oop_t x, y, width, height; +}; typedef struct x11_t* oop_x11_t; struct x11_t { - Display* disp; + MOO_OBJ_HEADER; + + moo_oop_t display; /* SMPTR of Display */ + oop_x11_llevent_t llevent; + moo_oop_t key_event; + moo_oop_t mouse_event; + + /* in fact, there are more fields */ }; typedef struct x11_trailer_t x11_trailer_t; struct x11_trailer_t { - XEvent* curevt; + XEvent* event; + moo_ooi_t connection_number; + Atom wm_delete_window; }; + + #if defined(__cplusplus) extern "C" { #endif diff --git a/moo/mod/x11.c b/moo/mod/x11.c index 0682904..18ef60e 100644 --- a/moo/mod/x11.c +++ b/moo/mod/x11.c @@ -38,37 +38,17 @@ struct x11_modctx_t }; /* ------------------------------------------------------------------------ */ - -#if 0 -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)); - } - 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; + oop_x11_t x11; + x11_trailer_t* tr; + Display* disp = MOO_NULL; - XEvent* curevt = MOO_NULL; + XEvent* event = MOO_NULL; char* dispname = MOO_NULL; + moo_ooi_t connno; + +// TODO: CHECK if the receiver is an X11 object if (nargs >= 1) { @@ -96,8 +76,8 @@ static moo_pfrc_t pf_open_display (moo_t* moo, moo_ooi_t nargs) } } - curevt = moo_allocmem (moo, MOO_SIZEOF(*x11->curevt)); - if (!curevt) + event = moo_allocmem (moo, MOO_SIZEOF(*event)); + if (!event) { MOO_STACK_SETRETTOERRNUM (moo, nargs); goto oops; @@ -106,149 +86,173 @@ static moo_pfrc_t pf_open_display (moo_t* moo, moo_ooi_t nargs) disp = XOpenDisplay(dispname); if (!disp) { - MOO_DEBUG1 (moo, " Cannot connect to X11 server %hs\n", XDisplayName(dispname)); + MOO_DEBUG1 (moo, " Cannot connect to X11 server %hs\n", XDisplayName(dispname)); MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ESYSERR); goto oops; } - MOO_ASSERT (moo, MOO_IN_SMPTR_RANGE(disp)); + if (!MOO_IN_SMPTR_RANGE(disp)) + { + MOO_DEBUG1 (moo, " Display pointer to %hs not in small pointer range\n", XDisplayName(dispname)); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ERANGE); + goto oops; + } + + connno = ConnectionNumber(disp); + if (!MOO_IN_SMOOI_RANGE(connno)) + { + MOO_DEBUG1 (moo, " Connection number to %hs out of small integer range\n", XDisplayName(dispname)); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ERANGE); + goto oops; + } + + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); + + tr = (x11_trailer_t*)moo_getobjtrailer (moo, (moo_oop_t)x11, MOO_NULL); + tr->event = event; + tr->connection_number = connno; + tr->wm_delete_window = XInternAtom (disp, "WM_DELETE_WINDOW", False); + + MOO_ASSERT (moo, MOO_IN_SMPTR_RANGE(disp)); + x11->display = MOO_SMPTR_TO_OOP(disp); + MOO_STACK_SETRETTORCV (moo, nargs); - MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(disp)); if (dispname) moo_freemem (moo, dispname); return MOO_PF_SUCCESS; oops: if (disp) XCloseDisplay (disp); - if (curevt) moo_freemem (moo, curevt); + if (event) moo_freemem (moo, event); if (dispname) moo_freemem (moo, dispname); return MOO_PF_SUCCESS; } static moo_pfrc_t pf_close_display (moo_t* moo, moo_ooi_t nargs) { - moo_oop_t a0; - - a0 = MOO_STACK_GETARG(moo, nargs, 0); + oop_x11_t x11; - if (!MOO_OOP_IS_SMPTR(a0)) +// TODO: CHECK if the receiver is an X11 object + + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); + if (x11->display != moo->_nil) { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); - } - else - { - XCloseDisplay (MOO_OOP_TO_SMPTR(a0)); - MOO_STACK_SETRETTORCV (moo, nargs); + MOO_ASSERT (moo, MOO_OOP_IS_SMPTR(x11->display)); + XCloseDisplay (MOO_OOP_TO_SMPTR(x11->display)); + x11->display = moo->_nil; } + + MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; } - static moo_pfrc_t pf_get_fd (moo_t* moo, moo_ooi_t nargs) { - moo_oop_t a0; - - a0 = MOO_STACK_GETARG(moo, nargs, 0); - - if (!MOO_OOP_IS_SMPTR(a0)) - { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); - } - else - { - moo_ooi_t c; - c = ConnectionNumber(MOO_OOP_TO_SMPTR(a0)); - - if (!MOO_IN_SMOOI_RANGE(c)) - { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ERANGE); - } - else - { - MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(c)); - } - } - + x11_trailer_t* tr; +// TODO: CHECK if the receiver is an X11 object + tr = moo_getobjtrailer (moo, MOO_STACK_GETRCV(moo,nargs), MOO_NULL); + MOO_STACK_SETRET(moo, nargs, MOO_SMOOI_TO_OOP(tr->connection_number)); return MOO_PF_SUCCESS; } static moo_pfrc_t pf_get_event (moo_t* moo, moo_ooi_t nargs) { - - moo_oop_t a0, a1; + oop_x11_t x11; + x11_trailer_t* tr; - a0 = MOO_STACK_GETARG(moo, nargs, 0); /* display - SmallPointer (Display*) */ - a1 = MOO_STACK_GETARG(moo, nargs, 1); /* event to return - SmallPointer (XEvent*) */ + Display* disp; + XEvent* event; - - if (!MOO_OOP_IS_SMPTR(a0) || !MOO_OOP_IS_SMPTR(a1)) +// TODO: CHECK if the receiver is an X11 object + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); +//MOO_ASSERT (moo, MOO_CLASSOF(moo,x11) == modctx->x11_class); + tr = moo_getobjtrailer (moo, (moo_oop_t)x11, MOO_NULL); + + disp = MOO_OOP_TO_SMPTR(x11->display); + event = tr->event; + if (XPending(disp)) { - MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + oop_x11_llevent_t e; + + XNextEvent (disp, event); + + e = x11->llevent; + e->type = MOO_SMOOI_TO_OOP(event->type); + e->window = MOO_SMOOI_TO_OOP(0); + + /* [NOTE] When creating the low-level event object, ensure not to + * trigger GC directly or indirectly as the GC might be a + * copying collector which move objects around during collection */ + switch (event->type) + { + case ClientMessage: + if (event->xclient.data.l[0] == tr->wm_delete_window) + { + e->window = MOO_SMOOI_TO_OOP(event->xclient.window); + /* WINDOW CLSOE EVENT */ + } + + break; + + case Expose: + { + e->window = MOO_SMOOI_TO_OOP(event->xexpose.window); + e->x = MOO_SMOOI_TO_OOP(event->xexpose.x); + e->y = MOO_SMOOI_TO_OOP(event->xexpose.y); + e->width = MOO_SMOOI_TO_OOP(event->xexpose.width); + e->height = MOO_SMOOI_TO_OOP(event->xexpose.height); + break; + } + + } + + MOO_STACK_SETRET (moo, nargs, (moo_oop_t)e); } else { - 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); - } + /* nil if there is no event */ + MOO_STACK_SETRET (moo, nargs, moo->_nil); } 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; + Window wind; /* Window -> XID, unsigned long */ int scrn; Window parent; XSetWindowAttributes attrs; - moo_oop_t a0, a1, a2, a3, a4, a5, a6, a7; + oop_x11_t x11; + x11_trailer_t* tr; + moo_oop_t a0, a1, a2, a3, a4, a5, a6; - 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 */ + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); - 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)) + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* parent window - Integer or nil (Window) */ + a1 = MOO_STACK_GETARG(moo, nargs, 1); /* x - SmallInteger */ + a2 = MOO_STACK_GETARG(moo, nargs, 2); /* y - SmallInteger */ + a3 = MOO_STACK_GETARG(moo, nargs, 3); /* width - SmallInteger */ + a4 = MOO_STACK_GETARG(moo, nargs, 4); /* height - SmallInteger */ + a5 = MOO_STACK_GETARG(moo, nargs, 5); /* fgcolor - SmallInteger */ + a6 = MOO_STACK_GETARG(moo, nargs, 6); /* bgcolor - SmallInteger */ + + if (!MOO_OOP_IS_SMOOI(a1) || !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)) { einval: + MOO_DEBUG0 (moo, " Invalid parameters\n"); MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); goto done; } - disp = MOO_OOP_TO_SMPTR(a0); + tr = moo_getobjtrailer (moo, (moo_oop_t)x11, MOO_NULL); + disp = MOO_OOP_TO_SMPTR(x11->display); - if (a1 == moo->_nil) + /* ScreenCount (disp); -> the number of screens available in this display server */ + + if (a0 == moo->_nil) { scrn = DefaultScreen (disp); parent = RootWindow (disp, scrn); @@ -257,7 +261,7 @@ static moo_pfrc_t pf_create_window (moo_t* moo, moo_ooi_t nargs) { moo_oow_t tmpoow; XWindowAttributes wa; - if (moo_inttooow(moo, a1, &tmpoow) <= 0) goto einval; + if (moo_inttooow(moo, a0, &tmpoow) <= 0) goto einval; parent = tmpoow; XGetWindowAttributes (disp, parent, &wa); @@ -265,18 +269,18 @@ static moo_pfrc_t pf_create_window (moo_t* moo, moo_ooi_t nargs) scrn = XScreenNumberOfScreen(wa.screen); } - attrs.event_mask = ExposureMask; /* TODO: accept it as a parameter??? */ + attrs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; /* 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 */ + MOO_OOP_TO_SMOOI(a1), /* x */ + MOO_OOP_TO_SMOOI(a2), /* y */ + MOO_OOP_TO_SMOOI(a3), /* width */ + MOO_OOP_TO_SMOOI(a4), /* height */ + 0, /* border width */ CopyFromParent, /* depth */ InputOutput, /* class */ CopyFromParent, /* visual */ @@ -287,6 +291,11 @@ static moo_pfrc_t pf_create_window (moo_t* moo, moo_ooi_t nargs) goto done; } + if (parent == RootWindow(disp, scrn)) + { + XSetWMProtocols (disp, wind, &tr->wm_delete_window, 1); + } + a0 = moo_oowtoint (moo, wind); if (!a0) { @@ -298,19 +307,6 @@ static moo_pfrc_t pf_create_window (moo_t* moo, moo_ooi_t nargs) 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; @@ -318,54 +314,144 @@ done: static moo_pfrc_t pf_destroy_window (moo_t* moo, moo_ooi_t nargs) { - moo_oop_t a0, a1; + oop_x11_t x11; + moo_oop_t a0; + moo_oow_t wind; - a0 = MOO_STACK_GETARG(moo, nargs, 0); /* display - SmallPointer (Display*) */ - a1 = MOO_STACK_GETARG(moo, nargs, 1); /* window - Integer (Window) */ + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); + a0 = MOO_STACK_GETARG(moo, nargs, 1); /* window - Integer (Window) */ - if (!MOO_OOP_IS_SMPTR(a0)) - + if (moo_inttooow(moo, a0, &wind) <= 0) { - einval: + MOO_DEBUG0 (moo, " Invalid parameters\n"); 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; + disp = MOO_OOP_TO_SMPTR(x11->display); XUnmapWindow (disp, (Window)wind); XDestroyWindow (disp, (Window)wind); -XFlush (disp); +XFlush (disp); /* TODO: is XFlush() needed here? */ MOO_STACK_SETRETTORCV (moo, nargs); } return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_create_gc (moo_t* moo, moo_ooi_t nargs) +{ + Display* disp; + moo_oow_t wind; + + oop_x11_t x11; + moo_oop_t a0; + + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); + disp = MOO_OOP_TO_SMPTR(x11); + + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* parent window - Integer or nil (Window) */ + + if (moo_inttooow(moo, a0, &wind) <= 0) + { + MOO_DEBUG0 (moo, " Invalid parameters\n"); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + } + else + { + GC gc; + +/* TODO: copy from default GC(DefaultGC...) explicitly??? */ + gc = XCreateGC (disp, wind, 0, MOO_NULL); + if (!MOO_IN_SMPTR_RANGE(gc)) + { + MOO_DEBUG0 (moo, " GC pointer not in small pointer range\n"); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ERANGE); + } + else + { + MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(gc)); + } + } + + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_destroy_gc (moo_t* moo, moo_ooi_t nargs) +{ + oop_x11_t x11; + moo_oop_t a0; + + x11 = (oop_x11_t)MOO_STACK_GETRCV(moo, nargs); + a0 = MOO_STACK_GETARG(moo, nargs, 1); /* GC */ + + if (!MOO_OOP_IS_SMPTR(a0)) + { + MOO_DEBUG0 (moo, " Invalid parameters\n"); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + } + else + { + Display* disp; + GC gc; + + disp = MOO_OOP_TO_SMPTR(x11->display); + gc = MOO_OOP_TO_SMPTR(a0); + + XFreeGC (disp, gc); + MOO_STACK_SETRETTORCV (moo, nargs); + } + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_draw_rectangle (moo_t* moo, moo_ooi_t nargs) +{ + Display* disp; + moo_oow_t wind, gc; + moo_oop_t a0, a1, a2, a3, a4, a5; + + a0 = MOO_STACK_GETARG(moo, nargs, 0); /* Window */ + a1 = MOO_STACK_GETARG(moo, nargs, 1); /* GC */ + 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 */ + + if (!MOO_OOP_IS_SMOOI(a2) || !MOO_OOP_IS_SMOOI(a3) || + !MOO_OOP_IS_SMOOI(a4) || !MOO_OOP_IS_SMOOI(a5) || + moo_inttooow(moo, a0, &wind) <= 0 || + moo_inttooow(moo, a1, &gc) <= 0) + { + MOO_DEBUG0 (moo, " Invalid parameters\n"); + MOO_STACK_SETRETTOERROR (moo, nargs, MOO_EINVAL); + return MOO_PF_SUCCESS; + } + + disp = MOO_OOP_TO_SMPTR(MOO_STACK_GETRCV(moo,nargs)); + XDrawRectangle (disp, (Window)wind, (GC)gc, + MOO_OOP_TO_SMOOI(a2), MOO_OOP_TO_SMOOI(a3), + MOO_OOP_TO_SMOOI(a4), MOO_OOP_TO_SMOOI(a5)); + + 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','l','o','s','e','_','d','i','s','p','l','a','y','\0' }, 0, { pf_close_display, 0, 0 } }, + { MI, { '_','c','r','e','a','t','e','_','g','c','\0' }, 0, { pf_create_gc, 1, 1 } }, + { MI, { '_','c','r','e','a','t','e','_','w','i','n','d','o','w','\0' }, 0, { pf_create_window, 7, 7 } }, + { MI, { '_','d','e','s','t','r','o','y','_','g','c','\0' }, 0, { pf_destroy_gc, 1, 1 } }, + { MI, { '_','d','e','s','t','r','o','y','_','w','i','n','d','o','w','\0' }, 0, { pf_destroy_window, 1, 1 } }, + { MI, { '_','d','r','a','w','_','r','e','c','t','a','n','g','l','e','\0' }, 0, { pf_draw_rectangle, 6, 6 } }, + //{ MI, { '_','f','i','l','l','_','r','e','c','t','a','n','g','l','e','\0' }, 0, { pf_fill_rectangle, 6, 6 } }, + { 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 } }, + { MI, { '_','o','p','e','n','_','d','i','s','p','l','a','y','\0' }, 0, { pf_open_display, 0, 1 } } - -#if 0 - { MI, { '_','g','e','t','_','b','a','s','e','\0' }, 0, { pf_get_base, 0, 0 } }, - - -#endif }; static int x11_import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class)