@@ -25,7 +25,7 @@ include makedefs LUADIR = luajit2 -INCLUDES += -I. $(GSL_INCLUDES) +INCLUDES += -I. $(GSL_INCLUDES) -Iagg-plot -Ilua-gsl GSL_SHELL = gsl-shell$(EXE_EXT) LUA_CFLAGS = -I$(LUADIR)/src @@ -43,9 +43,9 @@ else endif endif -SUBDIRS = $(LUADIR) +SUBDIRS = $(LUADIR) lua-gsl -C_SRC_FILES = str.c gs-types.c lua-utils.c lua-graph.c lua-gsl.c +C_SRC_FILES = ifeq ($(strip $(USE_READLINE)),yes) C_SRC_FILES += completion.c @@ -59,7 +59,8 @@ LUA_TEMPLATES = gauss-kronrod-x-wgs qag rk8pd lmfit qng rkf45 ode-defs rk4 sf-de LUA_BASE_FILES += $(DEMOS_LIST:%=demos/%.lua) LUA_BASE_FILES += $(LUA_TEMPLATES:%=templates/%.lua.in) -LUAGSL_LIBS = $(LUADIR)/src/libluajit.a +LUAGSL_LIBS += $(LUADIR)/src/libluajit.a + C_SRC_FILES += gsl-shell-jit.c TARGETS = $(GSL_SHELL) @@ -71,18 +72,13 @@ SUBDIRS += agg-plot LUAGSL_LIBS += agg-plot/libaggplot.a LIBS += $(AGG_LIBS) $(FREETYPE_LIBS) $(PTHREADS_LIBS) -COMPILE = $(CC) $(CFLAGS) $(LUA_CFLAGS) $(DEFS) $(INCLUDES) -CXXCOMPILE = $(CXX) $(CXXFLAGS) -c +LUAGSL_LIBS += lua-gsl/libluagsl.a -ifeq ($(HOST_SYS),Darwin) - LINK_EXE = $(CXX) $(LDFLAGS) -else - LINK_EXE = $(CC) $(LDFLAGS) -endif +COMPILE = $(CC) $(CFLAGS) $(LUA_CFLAGS) $(DEFS) $(INCLUDES) -LUAGSL_OBJ_FILES = $(C_SRC_FILES:%.c=%.o) $(CXX_SRC_FILES:%.cpp=%.o) +LUAGSL_OBJ_FILES = $(C_SRC_FILES:%.c=%.o) -DEP_FILES := $(C_SRC_FILES:%.c=.deps/%.P) $(CXX_SRC_FILES:%.cpp=.deps/%.P) +DEP_FILES := $(C_SRC_FILES:%.c=.deps/%.P) DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) LIBS_MAGIC := $(shell mkdir .libs > /dev/null 2>&1 || :) diff --git a/agg-plot/Makefile b/agg-plot/Makefile index 519d8b5d..e7888409 100644 --- a/agg-plot/Makefile +++ b/agg-plot/Makefile @@ -34,9 +34,9 @@ else PLATSUP_SRC_FILES = support_x11.cpp agg_platform_support_x11.cpp endif -INCLUDES += $(AGG_INCLUDES) $(FREETYPE_INCLUDES) -I$(GSH_BASE_DIR) -I$(LUADIR)/src +INCLUDES += $(FREETYPE_INCLUDES) $(AGG_INCLUDES) -I$(GSH_BASE_DIR) -I$(GSH_BASE_DIR)/lua-gsl -I$(LUADIR)/src -I$(GSH_BASE_DIR)/cpp-utils -AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp +AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp lua-graph.cpp AGGPLOT_OBJ_FILES := $(AGGPLOT_SRC_FILES:%.cpp=%.o) diff --git a/agg-plot/agg_platform_support_win32.cpp b/agg-plot/agg_platform_support_win32.cpp index a4361e69..506f3c5a 100644 --- a/agg-plot/agg_platform_support_win32.cpp +++ b/agg-plot/agg_platform_support_win32.cpp @@ -24,8 +24,8 @@ #include <windows.h> #include <string.h> -#include <pthread.h> #include <new> +#include "pthreadpp.h" #include "agg-pixfmt-config.h" #include "platform_support_ext.h" #include "platform/win32/agg_win32_bmp.h" @@ -87,7 +87,7 @@ namespace agg bool m_is_mapped; bool m_is_ready; - pthread_mutex_t m_mutex[1]; + pthread::mutex m_mutex; static void bitmap_info_resize (BITMAPINFO* bmp, unsigned w, unsigned h); }; @@ -112,15 +112,11 @@ namespace agg { ::QueryPerformanceFrequency(&m_sw_freq); ::QueryPerformanceCounter(&m_sw_start); - - pthread_mutex_init (m_mutex, NULL); } //------------------------------------------------------------------------ platform_specific::~platform_specific() { - pthread_mutex_destroy (m_mutex); - if (m_bmp_draw) delete [] (unsigned char*) m_bmp_draw; } @@ -461,9 +457,9 @@ namespace agg if (m_specific->m_is_ready) { - pthread_mutex_unlock (m_specific->m_mutex); + m_specific->m_mutex.unlock(); status = ::GetMessage(&msg, 0, 0, 0); - pthread_mutex_lock (m_specific->m_mutex); + m_specific->m_mutex.lock(); } else { @@ -628,13 +624,13 @@ platform_support_ext::prepare() void platform_support_ext::lock() { - pthread_mutex_lock (m_specific->m_mutex); + m_specific->m_mutex.lock(); } void platform_support_ext::unlock() { - pthread_mutex_unlock (m_specific->m_mutex); + m_specific->m_mutex.unlock(); } bool diff --git a/agg-plot/agg_platform_support_x11.cpp b/agg-plot/agg_platform_support_x11.cpp index 24f978a7..69181ecd 100644 --- a/agg-plot/agg_platform_support_x11.cpp +++ b/agg-plot/agg_platform_support_x11.cpp @@ -32,8 +32,9 @@ #include <X11/Xutil.h> #include <X11/Xatom.h> #include <X11/keysym.h> -#include <pthread.h> #include <new> + +#include "pthreadpp.h" #include "agg_basics.h" #include "util/agg_color_conv_rgb8.h" #include "agg-pixfmt-config.h" @@ -164,7 +165,7 @@ namespace agg public: platform_specific(pix_format_e format, bool flip_y); - ~platform_specific(); + ~platform_specific() {}; void free_x_resources(); @@ -199,7 +200,7 @@ namespace agg bool m_is_mapped; clock_t m_sw_start; - pthread_mutex_t m_mutex[1]; + pthread::mutex m_mutex; static bool initialized; }; @@ -252,14 +253,6 @@ namespace agg break; } m_sw_start = clock(); - - pthread_mutex_init (m_mutex, NULL); - } - - //------------------------------------------------------------------------ - platform_specific::~platform_specific() - { - pthread_mutex_destroy (m_mutex); } void platform_specific::close_connections() @@ -728,9 +721,9 @@ namespace agg XEvent x_event; if (ps->m_is_mapped) { - pthread_mutex_unlock (ps->m_mutex); + ps->m_mutex.unlock(); XNextEvent(xc->display, &x_event); - pthread_mutex_lock (ps->m_mutex); + ps->m_mutex.lock(); } else { @@ -1069,13 +1062,13 @@ platform_support_ext::prepare() void platform_support_ext::lock() { - pthread_mutex_lock (m_specific->m_mutex); + m_specific->m_mutex.lock(); } void platform_support_ext::unlock() { - pthread_mutex_unlock (m_specific->m_mutex); + m_specific->m_mutex.unlock(); } bool diff --git a/agg-plot/canvas-window-cpp.h b/agg-plot/canvas-window-cpp.h index d7eb5b77..2d29fef5 100644 --- a/agg-plot/canvas-window-cpp.h +++ b/agg-plot/canvas-window-cpp.h @@ -17,6 +17,7 @@ extern "C" { #include "defs.h" #include "canvas.h" #include "utils.h" +#include "lua-gsl.h" class canvas_window : public platform_support_ext { protected: @@ -26,6 +27,7 @@ protected: agg::trans_affine m_matrix; pthread_t m_thread; + gsl_shell_state* m_gsl_shell; public: @@ -41,9 +43,10 @@ public: enum win_status_e status; - canvas_window(agg::rgba8 bgcol) : - platform_support_ext(gslshell::pixel_format, true), - m_canvas(NULL), m_bgcolor(bgcol), m_matrix(), status(not_ready) + canvas_window(gsl_shell_state* gs, agg::rgba8 bgcol): + platform_support_ext(gslshell::pixel_format, true), + m_canvas(NULL), m_bgcolor(bgcol), m_matrix(), m_gsl_shell(gs), + status(not_ready) { }; virtual ~canvas_window() @@ -56,6 +59,7 @@ public: virtual void on_resize(int sx, int sy); void shutdown_close(); + gsl_shell_state* state() { return m_gsl_shell; } bool start_new_thread (std::auto_ptr<thread_info>& inf); diff --git a/agg-plot/canvas-window.cpp b/agg-plot/canvas-window.cpp index 11270616..bcec7ac7 100644 --- a/agg-plot/canvas-window.cpp +++ b/agg-plot/canvas-window.cpp @@ -21,7 +21,7 @@ #include "defs.h" #include "canvas-window-cpp.h" #include "resource-manager.h" -#include "gsl-shell.h" +#include "lua-gsl.h" #include "agg-parse-trans.h" #include "lua-cpp-utils.h" #include "lua-utils.h" @@ -105,14 +105,16 @@ canvas_thread_function (void *_inf) win->unlock(); - pthread_mutex_lock (gsl_shell_shutdown_mutex); - if (!gsl_shell_shutting_down) + gsl_shell_state* gs = win->state(); + + pthread_mutex_lock (&gs->shutdown_mutex); + if (!gs->is_shutting_down) { - GSL_SHELL_LOCK(); - window_index_remove (inf->L, inf->window_id); - GSL_SHELL_UNLOCK(); + pthread_mutex_lock(&gs->exec_mutex); + window_index_remove (gs->L, inf->window_id); + pthread_mutex_unlock(&gs->exec_mutex); } - pthread_mutex_unlock (gsl_shell_shutdown_mutex); + pthread_mutex_unlock (&gs->shutdown_mutex); return NULL; } @@ -125,9 +127,11 @@ canvas_window::shutdown_close() { close_request(); unlock(); - pthread_mutex_unlock (gsl_shell_shutdown_mutex); + + gsl_shell_state* gs = this->m_gsl_shell; + pthread_mutex_unlock (&gs->shutdown_mutex); pthread_join(m_thread, NULL); - pthread_mutex_lock (gsl_shell_shutdown_mutex); + pthread_mutex_lock (&gs->shutdown_mutex); } else { diff --git a/agg-plot/canvas_svg.cpp b/agg-plot/canvas_svg.cpp index fc5a859e..e5ef6d88 100644 --- a/agg-plot/canvas_svg.cpp +++ b/agg-plot/canvas_svg.cpp @@ -17,6 +17,6 @@ void canvas_svg::draw_outline<sg_object>(sg_object& vs, agg::rgba8 c) str path; svg_property_list* ls = vs.svg_path(path, m_height); str s = svg_stroke_path(path, canvas_svg::default_stroke_width, id, c, ls); - list::free(ls); + svg_property_list::free(ls); canvas_svg::writeln(m_output, s, " "); } diff --git a/agg-plot/draw_svg.h b/agg-plot/draw_svg.h index 34f6f681..2ceb2169 100644 --- a/agg-plot/draw_svg.h +++ b/agg-plot/draw_svg.h @@ -3,7 +3,7 @@ #include "agg_basics.h" #include "agg_color_rgba.h" -#include "my_list.h" +#include "list.h" #include "strpp.h" enum svg_path_property_e { @@ -33,7 +33,7 @@ vertex_flip(VertexSource* vs, double* x, double* y, double h) return cmd; } -typedef pod_list<svg_property_item> svg_property_list; +typedef list<svg_property_item> svg_property_list; template <typename VertexSource> void svg_coords_from_vs(VertexSource* vs, str& s, double h) diff --git a/agg-plot/lua-draw.cpp b/agg-plot/lua-draw.cpp index e8fba890..f7a458ae 100644 --- a/agg-plot/lua-draw.cpp +++ b/agg-plot/lua-draw.cpp @@ -26,16 +26,14 @@ extern "C" { } #include "lua-draw.h" +#include "lua-graph.h" #include "text-shape.h" -#include "gsl-shell.h" #include "lua-cpp-utils.h" #include "gs-types.h" #include "trans.h" #include "colors.h" #include "sg_marker.h" -pthread_mutex_t agg_mutex[1]; - enum path_cmd_e { CMD_ERROR = -1, CMD_MOVE_TO = 0, @@ -313,8 +311,6 @@ marker_free (lua_State *L) void draw_register (lua_State *L) { - pthread_mutex_init (agg_mutex, NULL); - luaL_newmetatable (L, GS_METATABLE(GS_DRAW_PATH)); luaL_register (L, NULL, agg_path_methods); lua_pop (L, 1); diff --git a/agg-plot/lua-draw.h b/agg-plot/lua-draw.h index 4213a003..a858b73c 100644 --- a/agg-plot/lua-draw.h +++ b/agg-plot/lua-draw.h @@ -1,11 +1,8 @@ #ifndef LUA_DRAW_H #define LUA_DRAW_H - #include "defs.h" -#include <pthread.h> - __BEGIN_DECLS #include "lua.h" __END_DECLS @@ -26,17 +23,6 @@ extern draw::path* check_agg_path (lua_State *L, int index); __BEGIN_DECLS -extern pthread_mutex_t agg_mutex[1]; - -#define AGG_LOCK() pthread_mutex_lock (agg_mutex); -#define AGG_UNLOCK() pthread_mutex_unlock (agg_mutex); - -#define AGG_PROTECT(op) { \ - pthread_mutex_lock (agg_mutex); \ - op; \ - pthread_mutex_unlock (agg_mutex); \ - } - extern void draw_register (lua_State *L); __END_DECLS diff --git a/lua-graph.c b/agg-plot/lua-graph.cpp index d592b720..c056a10b 100644 --- a/lua-graph.c +++ b/agg-plot/lua-graph.cpp @@ -18,18 +18,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +extern "C" { #include <lua.h> #include <lauxlib.h> +} #include "lua-graph.h" +#include "lua-gsl.h" #include "window_registry.h" #include "lua-draw.h" #include "lua-text.h" #include "window.h" #include "lua-plot.h" +#include "window_hooks.h" + +#ifndef MLUA_GRAPHLIBNAME +#define MLUA_GRAPHLIBNAME "graph" +#endif static const struct luaL_Reg methods_dummy[] = {{NULL, NULL}}; +pthread_mutex_t agg_mutex[1]; + void graph_close_windows (lua_State *L) { @@ -39,16 +49,30 @@ graph_close_windows (lua_State *L) void register_graph (lua_State *L) { + pthread_mutex_init (agg_mutex, NULL); + window_registry_prepare (L); luaL_register (L, MLUA_GRAPHLIBNAME, methods_dummy); draw_register (L); text_register (L); - window_register (L); + app_window_hooks->register_module (L); plot_register (L); initialize_fonts (L); lua_pop(L, 1); } + +void +gsl_shell_close_with_graph (struct gsl_shell_state* gs) +{ + pthread_mutex_lock (&gs->shutdown_mutex); + gs->is_shutting_down = 1; + pthread_mutex_lock(&gs->exec_mutex); + graph_close_windows(gs->L); + lua_close(gs->L); + pthread_mutex_unlock(&gs->shutdown_mutex); + pthread_mutex_unlock(&gs->exec_mutex); +} diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp index 9812668b..9f6ce209 100644 --- a/agg-plot/lua-plot.cpp +++ b/agg-plot/lua-plot.cpp @@ -25,10 +25,10 @@ extern "C" { #include "lua-plot.h" #include "lua-plot-cpp.h" +#include "window_hooks.h" +#include "lua-graph.h" #include "lua-cpp-utils.h" #include "bitmap-plot.h" -#include "window.h" -#include "window-cpp.h" #include "gs-types.h" #include "lua-utils.h" #include "window_registry.h" @@ -488,7 +488,7 @@ plot_newindex (lua_State *L) void plot_update_raw (lua_State *L, sg_plot *p, int plot_index) { - window_refs_lookup_apply (L, plot_index, window_slot_update); + window_refs_lookup_apply (L, plot_index, app_window_hooks->update); p->commit_pending_draw(); } @@ -504,7 +504,7 @@ int plot_flush (lua_State *L) { sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); - window_refs_lookup_apply (L, 1, window_slot_refresh); + window_refs_lookup_apply (L, 1, app_window_hooks->refresh); p->commit_pending_draw(); return 0; } @@ -512,19 +512,11 @@ plot_flush (lua_State *L) int plot_show (lua_State *L) { - sg_plot* plot = object_check<sg_plot>(L, 1, GS_PLOT); - window* win = push_new_object<window>(L, GS_WINDOW, colors::white); - - int slot_id = win->attach (plot, ""); - assert(slot_id >= 0); - window_refs_add (L, slot_id, -1, 1); - - gslshell::ret_status st; - win->start(L, st); - - if (st.error_msg()) - return luaL_error (L, "%s (reported during %s)", st.error_msg(), st.context()); - + lua_pushcfunction (L, app_window_hooks->attach); + (*app_window_hooks->create)(L); + lua_pushvalue (L, 1); + lua_pushstring (L, ""); + lua_call (L, 3, 0); return 0; } @@ -551,13 +543,13 @@ plot_push_layer (lua_State *L) { sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); - window_refs_lookup_apply (L, 1, window_slot_refresh); + window_refs_lookup_apply (L, 1, app_window_hooks->refresh); AGG_LOCK(); p->push_layer(); AGG_UNLOCK(); - window_refs_lookup_apply (L, 1, window_save_slot_image); + window_refs_lookup_apply (L, 1, app_window_hooks->save_image); return 0; } @@ -597,7 +589,7 @@ plot_clear (lua_State *L) p->clear_current_layer(); AGG_UNLOCK(); - window_refs_lookup_apply (L, 1, window_restore_slot_image); + window_refs_lookup_apply (L, 1, app_window_hooks->restore_image); if (p->sync_mode()) plot_update_raw (L, p, 1); diff --git a/agg-plot/my_list.h b/agg-plot/my_list.h deleted file mode 100644 index 34e7cf0d..00000000 --- a/agg-plot/my_list.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef AGGPLOT_LIST_H -#define AGGPLOT_LIST_H - -template <class T> -class pod_list { - T m_content; - pod_list *m_next; - -public: - pod_list(const T& c, pod_list* next = 0) : m_content(c), m_next(next) { }; - - T& content() { return m_content; }; - const T& content() const { return m_content; }; - - static pod_list* push_back(pod_list* head, pod_list* n) - { - pod_list* k = head; - - if (! k) - return n; - - while (k->m_next) - k = k->m_next; - k->m_next = n; - - return head; - } - - pod_list* next() { return m_next; }; -}; - -namespace list { - - template <class T> - int length(pod_list<T> *ls) - { - int n = 0; - for ( ; ls; ls = ls->next()) - n++; - return n; - } - - template <class T> - void free(pod_list<T> *p) - { - pod_list<T> *n; - for (/* */; p; p = n) - { - n = p->next(); - delete p; - } - } - - template <class T> - pod_list<T> * pop(pod_list<T> *p) - { - pod_list<T> *tail = p->next(); - delete p; - return tail; - } - - template <class T, class f> - void apply(pod_list<T> *p) - { - pod_list<T> *n; - for ( ; p; p = n) - { - n = p->m_next; - T& val = p->content(); - f::func(val); - } - } -} - -#endif diff --git a/agg-plot/platform_support_ext.h b/agg-plot/platform_support_ext.h index f58c03f9..8b601763 100644 --- a/agg-plot/platform_support_ext.h +++ b/agg-plot/platform_support_ext.h @@ -3,6 +3,7 @@ #include "agg_basics.h" #include "platform/agg_platform_support.h" +#include "rendering_buffer_utils.h" class platform_support_ext : public agg::platform_support { public: @@ -24,120 +25,4 @@ public: agg::pix_format_e src_pixfmt_tag); }; -template<class RenBufDst, class RenBufSrc, class CopyRow> -void my_color_conv(RenBufDst* dst, const RenBufSrc* src, CopyRow copy_row_functor) -{ - unsigned int width = src->width(); - unsigned int height = src->height(); - - for(unsigned int y = 0; y < height; y++) - { - copy_row_functor(dst->row_ptr(0, y, width), src->row_ptr(y), width); - } -} - -template<class RenBufDst, class RenBufSrc> -void rendering_buffer_get_region (RenBufDst& dst, RenBufSrc& src, agg::rect_base<int>& r, - unsigned pixel_width) -{ - int w = r.x2 - r.x1, h = r.y2 - r.y1; - for (int y = 0; y < h; y++) - { - unsigned char *drow = dst.row_ptr(y); - unsigned char *srow = src.row_ptr(r.y1 + y); - srow += r.x1 * pixel_width; - memcpy (drow, srow, pixel_width * w); - } -} - -template<class RenBufDst, class RenBufSrc> -void rendering_buffer_get_const_view (RenBufDst& view, const RenBufSrc& src, - const agg::rect_base<int>& r, - unsigned pixel_width, bool flip_y) -{ - int x = r.x1, y = r.y1, w = r.x2 - r.x1, h = r.y2 - r.y1; - const unsigned char *buf_start = src.row_ptr(y); - if (src.stride() < 0) - buf_start += src.stride() * (h - 1); - view.attach(buf_start + pixel_width * x, w, h, src.stride()); -} - -template<class RenBufDst, class RenBufSrc> -void rendering_buffer_get_view (RenBufDst& view, RenBufSrc& src, - const agg::rect_base<int>& r, - unsigned pixel_width, bool flip_y) -{ - int x = r.x1, y = r.y1, w = r.x2 - r.x1, h = r.y2 - r.y1; - unsigned char *buf_start = src.row_ptr(y); - if (src.stride() < 0) - buf_start += src.stride() * (h - 1); - view.attach(buf_start + pixel_width * x, w, h, src.stride()); -} - -template<class RenBufDst, class RenBufSrc> -void rendering_buffer_put_region (RenBufDst& dst, RenBufSrc& src, agg::rect_base<int>& r, - unsigned pixel_width) -{ - int w = r.x2 - r.x1, h = r.y2 - r.y1; - for (int y = 0; y < h; y++) - { - unsigned char *drow = dst.row_ptr(r.y1 + y); - unsigned char *srow = src.row_ptr(y); - drow += r.x1 * pixel_width; - memcpy (drow, srow, pixel_width * w); - } -} - -template<class T> class row_accessor_ro -{ -public: - //-------------------------------------------------------------------- - row_accessor_ro() : m_buf(0), m_width(0), m_height(0), m_stride(0), m_start(0) {}; - - row_accessor_ro(const T* buf, unsigned width, unsigned height, int stride) : - m_buf(buf), m_width(width), m_height(height), m_stride(stride) - { - if(stride < 0) - m_start = m_buf - int(height - 1) * stride; - else - m_start = m_buf; - } - - void attach(const T* buf, unsigned width, unsigned height, int stride) - { - m_buf = m_start = buf; - m_width = width; - m_height = height; - m_stride = stride; - if(stride < 0) - { - m_start = m_buf - int(height - 1) * stride; - } - }; - - //-------------------------------------------------------------------- - const T* buf() const { return m_buf; } - unsigned width() const { return m_width; } - unsigned height() const { return m_height; } - int stride() const { return m_stride; } - unsigned stride_abs() const - { - return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); - } - - //-------------------------------------------------------------------- - const T* row_ptr(int, int y, unsigned) const { return m_start + y * m_stride; } - const T* row_ptr(int y) const { return m_start + y * m_stride; } - -private: - //-------------------------------------------------------------------- - const T* m_buf; // Pointer to renrdering buffer - unsigned m_width; // Width in pixels - unsigned m_height; // Height in pixels - int m_stride; // Number of bytes per row. Can be < 0 - const T* m_start; // Pointer to first pixel depending on stride -}; - -typedef row_accessor_ro<unsigned char> rendering_buffer_ro; - #endif diff --git a/agg-plot/plot-auto.h b/agg-plot/plot-auto.h index 20b590ad..4701c12f 100644 --- a/agg-plot/plot-auto.h +++ b/agg-plot/plot-auto.h @@ -77,8 +77,8 @@ void plot_auto<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) this->m_enlarged_layer = true; } - pod_list<item> *nn = new pod_list<item>(d); - this->m_drawing_queue = pod_list<item>::push_back(this->m_drawing_queue, nn); + list<item> *nn = new list<item>(d); + this->m_drawing_queue = list<item>::push_back(this->m_drawing_queue, nn); RM::acquire(vs); } @@ -117,8 +117,7 @@ void plot_auto<RM>::calc_bounding_box() } calc_layer_bounding_box(this->get_layer(n-1), box); - - for (pod_list<item> *t = this->m_drawing_queue; t; t = t->next()) + for (list<item> *t = this->m_drawing_queue; t; t = t->next()) { const item& d = t->content(); agg::rect_base<double> r; diff --git a/agg-plot/plot.h b/agg-plot/plot.h index 9abb7444..fbc6707c 100644 --- a/agg-plot/plot.h +++ b/agg-plot/plot.h @@ -24,7 +24,7 @@ #include <new> #include "utils.h" -#include "my_list.h" +#include "list.h" #include "strpp.h" #include "canvas.h" #include "units.h" @@ -106,7 +106,7 @@ protected: }; public: - typedef pod_list<item> iterator; + typedef list<item> iterator; typedef virtual_canvas canvas_type; enum axis_e { x_axis, y_axis }; @@ -326,7 +326,7 @@ protected: } agg::trans_affine m_trans; - pod_list<item> *m_drawing_queue; + list<item> *m_drawing_queue; bool m_clip_flag; @@ -379,8 +379,8 @@ template <class RM> void plot<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) { item d(vs, color, outline); - pod_list<item> *new_node = new pod_list<item>(d); - m_drawing_queue = pod_list<item>::push_back(m_drawing_queue, new_node); + list<item> *new_node = new list<item>(d); + m_drawing_queue = list<item>::push_back(m_drawing_queue, new_node); RM::acquire(vs); } @@ -388,13 +388,13 @@ template <class RM> void plot<RM>::push_drawing_queue() { item_list* layer = current_layer(); - for (pod_list<item> *c = m_drawing_queue; c != 0; c = c->next()) + for (list<item> *c = m_drawing_queue; c != 0; c = c->next()) { layer->add(c->content()); } while (m_drawing_queue) - m_drawing_queue = list::pop(m_drawing_queue); + m_drawing_queue = list<item>::pop(m_drawing_queue); } template <class RM> @@ -404,7 +404,7 @@ void plot<RM>::clear_drawing_queue() { item& d = m_drawing_queue->content(); RM::dispose(d.vs); - m_drawing_queue = list::pop(m_drawing_queue); + m_drawing_queue = list<item>::pop(m_drawing_queue); } } diff --git a/agg-plot/rendering_buffer_utils.h b/agg-plot/rendering_buffer_utils.h new file mode 100644 index 00000000..56103e4a --- /dev/null +++ b/agg-plot/rendering_buffer_utils.h @@ -0,0 +1,120 @@ +#ifndef AGGPLOT_RBUF_UTILS_H +#define AGGPLOT_RBUF_UTILS_H + +template<class RenBufDst, class RenBufSrc, class CopyRow> +void my_color_conv(RenBufDst* dst, const RenBufSrc* src, CopyRow copy_row_functor) +{ + unsigned int width = src->width(); + unsigned int height = src->height(); + + for(unsigned int y = 0; y < height; y++) + { + copy_row_functor(dst->row_ptr(0, y, width), src->row_ptr(y), width); + } +} + +template<class RenBufDst, class RenBufSrc> +void rendering_buffer_get_region (RenBufDst& dst, RenBufSrc& src, agg::rect_base<int>& r, + unsigned pixel_width) +{ + int w = r.x2 - r.x1, h = r.y2 - r.y1; + for (int y = 0; y < h; y++) + { + unsigned char *drow = dst.row_ptr(y); + unsigned char *srow = src.row_ptr(r.y1 + y); + srow += r.x1 * pixel_width; + memcpy (drow, srow, pixel_width * w); + } +} + +template<class RenBufDst, class RenBufSrc> +void rendering_buffer_get_const_view (RenBufDst& view, const RenBufSrc& src, + const agg::rect_base<int>& r, + unsigned pixel_width, bool flip_y) +{ + int x = r.x1, y = r.y1, w = r.x2 - r.x1, h = r.y2 - r.y1; + const unsigned char *buf_start = src.row_ptr(y); + if (src.stride() < 0) + buf_start += src.stride() * (h - 1); + view.attach(buf_start + pixel_width * x, w, h, src.stride()); +} + +template<class RenBufDst, class RenBufSrc> +void rendering_buffer_get_view (RenBufDst& view, RenBufSrc& src, + const agg::rect_base<int>& r, + unsigned pixel_width, bool flip_y) +{ + int x = r.x1, y = r.y1, w = r.x2 - r.x1, h = r.y2 - r.y1; + unsigned char *buf_start = src.row_ptr(y); + if (src.stride() < 0) + buf_start += src.stride() * (h - 1); + view.attach(buf_start + pixel_width * x, w, h, src.stride()); +} + +template<class RenBufDst, class RenBufSrc> +void rendering_buffer_put_region (RenBufDst& dst, RenBufSrc& src, agg::rect_base<int>& r, + unsigned pixel_width) +{ + int w = r.x2 - r.x1, h = r.y2 - r.y1; + for (int y = 0; y < h; y++) + { + unsigned char *drow = dst.row_ptr(r.y1 + y); + unsigned char *srow = src.row_ptr(y); + drow += r.x1 * pixel_width; + memcpy (drow, srow, pixel_width * w); + } +} + +template<class T> class row_accessor_ro +{ +public: + //-------------------------------------------------------------------- + row_accessor_ro() : m_buf(0), m_width(0), m_height(0), m_stride(0), m_start(0) {}; + + row_accessor_ro(const T* buf, unsigned width, unsigned height, int stride) : + m_buf(buf), m_width(width), m_height(height), m_stride(stride) + { + if(stride < 0) + m_start = m_buf - int(height - 1) * stride; + else + m_start = m_buf; + } + + void attach(const T* buf, unsigned width, unsigned height, int stride) + { + m_buf = m_start = buf; + m_width = width; + m_height = height; + m_stride = stride; + if(stride < 0) + { + m_start = m_buf - int(height - 1) * stride; + } + }; + + //-------------------------------------------------------------------- + const T* buf() const { return m_buf; } + unsigned width() const { return m_width; } + unsigned height() const { return m_height; } + int stride() const { return m_stride; } + unsigned stride_abs() const + { + return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); + } + + //-------------------------------------------------------------------- + const T* row_ptr(int, int y, unsigned) const { return m_start + y * m_stride; } + const T* row_ptr(int y) const { return m_start + y * m_stride; } + +private: + //-------------------------------------------------------------------- + const T* m_buf; // Pointer to renrdering buffer + unsigned m_width; // Width in pixels + unsigned m_height; // Height in pixels + int m_stride; // Number of bytes per row. Can be < 0 + const T* m_start; // Pointer to first pixel depending on stride +}; + +typedef row_accessor_ro<unsigned char> rendering_buffer_ro; + +#endif diff --git a/agg-plot/sg_object.h b/agg-plot/sg_object.h index 4b3b4b8d..6001ca95 100644 --- a/agg-plot/sg_object.h +++ b/agg-plot/sg_object.h @@ -52,7 +52,7 @@ struct sg_object : public vertex_source { str path; svg_property_list* ls = this->svg_path(path, h); str s = svg_fill_path(path, id, c, ls); - list::free(ls); + svg_property_list::free(ls); return s; } diff --git a/agg-plot/split-parser.h b/agg-plot/split-parser.h index bbc9044d..feb44dd6 100644 --- a/agg-plot/split-parser.h +++ b/agg-plot/split-parser.h @@ -1,7 +1,7 @@ #ifndef AGGPLOT_SPLIT_PARSER_H #define AGGPLOT_SPLIT_PARSER_H -#include "my_tree.h" +#include "tree.h" enum direction_e { along_x, along_y }; diff --git a/agg-plot/trans.h b/agg-plot/trans.h index c3aa60c2..e0aa9ecb 100644 --- a/agg-plot/trans.h +++ b/agg-plot/trans.h @@ -39,7 +39,7 @@ struct trans { str path; svg_property_list* ls = this->m_source->svg_path(path, h); str s = svg_stroke_path(path, m_width, id, c, ls); - list::free(ls); + svg_property_list::free(ls); return s; } @@ -179,7 +179,7 @@ struct trans { ls = new svg_property_list(item3, ls); str svg = svg_marker_path(path, m_size, id, ls); - list::free(ls); + svg_property_list::free(ls); return str::print("%s\n %s", marker_def.cstr(), svg.cstr()); } diff --git a/agg-plot/window-cpp.h b/agg-plot/window-cpp.h index 4e8faa7e..20ba4744 100644 --- a/agg-plot/window-cpp.h +++ b/agg-plot/window-cpp.h @@ -10,7 +10,7 @@ extern "C" { #include "lua-cpp-utils.h" #include "plot.h" #include "rect.h" -#include "my_list.h" +#include "list.h" #include "agg_color_rgba.h" #include "agg_trans_affine.h" @@ -60,7 +60,8 @@ private: ref::node* m_tree; public: - window(agg::rgba8 bgcol) : canvas_window(bgcol), m_tree(0) + window(gsl_shell_state* gs, agg::rgba8 bgcol= colors::white): + canvas_window(gs, bgcol), m_tree(0) { this->split("."); }; diff --git a/agg-plot/window.cpp b/agg-plot/window.cpp index 71560795..4c6de7c5 100644 --- a/agg-plot/window.cpp +++ b/agg-plot/window.cpp @@ -8,6 +8,7 @@ extern "C" { #include "window-cpp.h" #include "window_registry.h" #include "lua-draw.h" +#include "lua-graph.h" #include "lua-cpp-utils.h" #include "gs-types.h" #include "colors.h" @@ -64,14 +65,14 @@ int window::ref::calculate(window::ref::node* t, const bmatrix& m, int id) r->matrix = m; } - int nb = list::length(t->tree()); + int nb = list<ref::node*>::length(t->tree()); if (nb > 0) { double frac = 1 / (double) nb; direction_e dir; - ref::node::list *ls = t->tree(dir); + list<ref::node*> *ls = t->tree(dir); if (ls) { bmatrix lm; @@ -117,7 +118,7 @@ window::ref::save_image (agg::rendering_buffer& win_buf, void window::draw_rec(ref::node *n) { - ref::node::list *ls; + list<ref::node*> *ls; for (ls = n->tree(); ls != NULL; ls = ls->next()) draw_rec(ls->content()); @@ -130,7 +131,7 @@ window::draw_rec(ref::node *n) window::ref* window::ref_lookup (ref::node *p, int slot_id) { - ref::node::list *t = p->tree(); + list<ref::node*> *t = p->tree(); for (/* */; t; t = t->next()) { ref *ref = window::ref_lookup(t->content(), slot_id); @@ -274,7 +275,7 @@ window::on_resize(int sx, int sy) void window::cleanup_tree_rec (lua_State *L, int window_index, ref::node* n) { - for (ref::node::list *ls = n->tree(); ls != NULL; ls = ls->next()) + for (list<ref::node*> *ls = n->tree(); ls != NULL; ls = ls->next()) cleanup_tree_rec(L, window_index, ls->content()); ref *ref = n->content(); @@ -332,7 +333,7 @@ int window::attach(sg_plot* plot, const char *spec) for (ptr = next_int (spec, k); ptr; ptr = next_int (ptr, k)) { - ref::node::list* list = n->tree(); + list<ref::node*>* list = n->tree(); if (! list) return -1; @@ -420,7 +421,7 @@ void window::start (lua_State *L, gslshell::ret_status& st) int window_new (lua_State *L) { - window *win = push_new_object<window>(L, GS_WINDOW, colors::white); + window *win = push_new_object<window>(L, GS_WINDOW, global_state); const char *spec = lua_tostring (L, 1); gslshell::ret_status st; diff --git a/agg-plot/window_hooks.h b/agg-plot/window_hooks.h new file mode 100644 index 00000000..e39350eb --- /dev/null +++ b/agg-plot/window_hooks.h @@ -0,0 +1,25 @@ +#ifndef AGGPLOT_WINDOW_HOOKS_H +#define AGGPLOT_WINDOW_HOOKS_H + +#include "defs.h" + +__BEGIN_DECLS + +#include "lua.h" + +struct window_hooks { + int (*create)(lua_State* L); + int (*attach)(lua_State* L); + int (*update)(lua_State* L); + int (*refresh)(lua_State* L); + int (*save_image)(lua_State* L); + int (*restore_image)(lua_State* L); + + void (*register_module)(lua_State* L); +}; + +extern struct window_hooks app_window_hooks[1]; + +__END_DECLS + +#endif diff --git a/agg-plot/window_registry.cpp b/agg-plot/window_registry.cpp index 4f324ea8..c2e6f1f1 100644 --- a/agg-plot/window_registry.cpp +++ b/agg-plot/window_registry.cpp @@ -18,14 +18,11 @@ window_registry_prepare (lua_State *L) int window_index_add(lua_State *L, int index) { - int n; - - if (index < 0) - index = lua_gettop (L) - (index+1); + INDEX_SET_ABS(L, index); lua_getfield (L, LUA_REGISTRYINDEX, registry_tname); - n = lua_objlen (L, -1); + int n = lua_objlen (L, -1); lua_pushvalue (L, index); lua_rawseti (L, -2, n+1); diff --git a/cmpl.h b/cmpl.h deleted file mode 100644 index 10f1750e..00000000 --- a/cmpl.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* cmpl.h - * - * Copyright (C) 2009 Francesco Abbate - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef CMPL_VECTOR_H -#define CMPL_VECTOR_H - -#include <math.h> - -#ifdef __cplusplus -#define complex _Complex -#else -#include <complex.h> -#endif /* C++ */ - -#include "defs.h" - -__BEGIN_DECLS - -#define CSQABS(z) (creal(z)*creal(z) + cimag(z)*cimag(z)) - -typedef double complex cmpl; - -__END_DECLS - -#endif diff --git a/cpp-utils/list.h b/cpp-utils/list.h new file mode 100644 index 00000000..95b9cb1c --- /dev/null +++ b/cpp-utils/list.h @@ -0,0 +1,58 @@ +#ifndef CPP_LIST_H +#define CPP_LIST_H + +template <class T> +class list { + T m_content; + list* m_next; + +public: + list(const T& c, list* next = 0) : m_content(c), m_next(next) { }; + list( T& c, list* next = 0) : m_content(c), m_next(next) { }; + + T& content() { return m_content; }; + const T& content() const { return m_content; }; + + static list* push_back(list* head, list* n) + { + list* k = head; + + if (! k) + return n; + + while (k->m_next) + k = k->m_next; + k->m_next = n; + + return head; + } + + static int length(list* ls) + { + int n = 0; + for ( ; ls; ls = ls->next()) + n++; + return n; + } + + static void free(list* p) + { + list* n; + for (/* */; p; p = n) + { + n = p->m_next; + delete p; + } + } + + static list* pop(list* p) + { + list* tail = p->next(); + delete p; + return tail; + } + + list* next() { return m_next; }; +}; + +#endif diff --git a/cpp-utils/pthreadpp.h b/cpp-utils/pthreadpp.h new file mode 100644 index 00000000..876cc1fd --- /dev/null +++ b/cpp-utils/pthreadpp.h @@ -0,0 +1,54 @@ +#ifndef CPP_PTHREADPP_H +#define CPP_PTHREADPP_H + +#include <pthread.h> + +/* Simple C++ wrapper around basic mutex/condition operations. + The added value of the wrapper is more clean C++ code with automatic + initialization/deallocation of resources. */ + +namespace pthread { + + class mutex { + public: + mutex() { pthread_mutex_init(&m_mutex, NULL); } + ~mutex() { pthread_mutex_destroy(&m_mutex); } + + void lock() { pthread_mutex_lock(&m_mutex); } + void unlock() { pthread_mutex_unlock(&m_mutex); } + + pthread_mutex_t* mutex_ptr() { return &m_mutex; } + + private: + mutex(const mutex&); + mutex& operator= (const mutex&); + + pthread_mutex_t m_mutex; + }; + + class auto_lock { + public: + auto_lock(mutex& m): m_mutex(m) { m_mutex.lock(); } + ~auto_lock() { m_mutex.unlock(); } + private: + mutex& m_mutex; + }; + + /* Since the official documentation recommend to use pthread conditions + always in pair with a mutex we let a condtion inherit from a mutex. + In this way a C++ "cond" instance can perform both mutex and condition + operations. */ + class cond : public mutex { + public: + cond() { pthread_cond_init(&m_cond, NULL); } + ~cond() { pthread_cond_destroy(&m_cond); } + + void signal() { pthread_cond_signal(&m_cond); } + void wait() { pthread_cond_wait(&m_cond, mutex_ptr()); } + + private: + pthread_cond_t m_cond; + }; +} + +#endif diff --git a/agg-plot/my_tree.h b/cpp-utils/tree.h index 97bc65a9..4d546615 100644 --- a/agg-plot/my_tree.h +++ b/cpp-utils/tree.h @@ -1,16 +1,14 @@ -#ifndef AGGPLOT_MY_TREE_H -#define AGGPLOT_MY_TREE_H +#ifndef CPP_TREE_H +#define CPP_TREE_H -#include "my_list.h" +#include "list.h" namespace tree { template <class base_type, class tree_data_type> struct node { - typedef pod_list<node*> list; - - virtual list* tree() { return 0; }; - virtual list* tree(tree_data_type& data) { return 0; }; + virtual list<node*>* tree() { return 0; }; + virtual list<node*>* tree(tree_data_type& data) { return 0; }; virtual base_type* content() = 0; virtual void content(const base_type& src) = 0; @@ -33,7 +31,7 @@ namespace tree { class tree_node : public node<base_type, tree_data_type> { typedef node<base_type, tree_data_type> node_type; - typedef typename node<base_type, tree_data_type>::list node_list; + typedef list<node_type*> node_list; node_list *m_head; tree_data_type m_data; @@ -79,7 +77,8 @@ namespace tree { if (c) f::func(*c); - typename node<base_type, tree_data_type>::list *ls = t->tree(); + typedef node<base_type, tree_data_type> node_type; + list<node_type*>* ls = t->tree(); if (ls) { for ( ; ls; ls = ls->next()) @@ -46,4 +46,7 @@ typedef int bool; #include <stdbool.h> #endif +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + #endif diff --git a/fox-gui/Makefile b/fox-gui/Makefile new file mode 100644 index 00000000..c1c9fbbb --- /dev/null +++ b/fox-gui/Makefile @@ -0,0 +1,62 @@ + +# Makefile +# +# Copyright (C) 2009 Francesco Abbate +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +GSH_BASE_DIR = .. + +include $(GSH_BASE_DIR)/makeconfig +include $(GSH_BASE_DIR)/make-system-detect +include $(GSH_BASE_DIR)/makepackages +include $(GSH_BASE_DIR)/makedefs + +GSL_SHELL_GUI = gsl-shell-fox.exe + +LUADIR = $(GSH_BASE_DIR)/luajit2 + +INCLUDES += $(AGG_INCLUDES) $(FOX_INCLUDES) -I$(GSH_BASE_DIR) -I$(GSH_BASE_DIR)/lua-gsl -I$(GSH_BASE_DIR)/agg-plot -I$(LUADIR)/src -I$(GSH_BASE_DIR)/cpp-utils +LIBS += $(LUADIR)/src/libluajit.a $(GSH_BASE_DIR)/agg-plot/libaggplot.a $(GSH_BASE_DIR)/lua-gsl/libluagsl.a $(FOX_LIBS) $(PTHREADS_LIBS) -lsupc++ + +INCLUDES += $(FREETYPE_INCLUDES) $(PTHREADS_CFLAGS) +LIBS += $(AGG_LIBS) $(FREETYPE_LIBS) $(PTHREADS_LIBS) $(GSL_LIBS) + +FOXGUI_SRC_FILES = io_thread.cpp fx_console.cpp redirect.cpp gsl_shell_interp.cpp gsl_shell_thread.cpp fox_gsl_shell.cpp gsl_shell_window.cpp fx_plot_canvas.cpp fx_plot_window.cpp lua_plot_window.cpp gsl_shell_app.cpp gsl-shell-fox.cpp +FOXGUI_OBJ_FILES := $(FOXGUI_SRC_FILES:%.cpp=%.o) + +DEP_FILES := $(FOXGUI_SRC_FILES:%.cpp=.deps/%.P) + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +CXXCOMPILE = $(CC) $(CXXFLAGS) $(DEFS) $(INCLUDES) + +TARGETS = $(GSL_SHELL_GUI) + +all: $(TARGETS) + +$(GSL_SHELL_GUI): $(FOXGUI_OBJ_FILES) + @echo Linking $@ + @$(LINK_EXE) -o $@ $(FOXGUI_OBJ_FILES) $(LIBS) + +include $(GSH_BASE_DIR)/makerules + +.PHONY: clean all + +clean: + $(HOST_RM) *.o *.lo *.la *.so *.dll $(TARGETS) + +-include $(DEP_FILES) diff --git a/fox-gui/fox_gsl_shell.cpp b/fox-gui/fox_gsl_shell.cpp new file mode 100644 index 00000000..46a985df --- /dev/null +++ b/fox-gui/fox_gsl_shell.cpp @@ -0,0 +1,36 @@ + +#include "fox_gsl_shell.h" +#include "lua_plot_window.h" +#include "window_registry.h" + +void fox_gsl_shell::init() +{ + gsl_shell_thread::init(); +} + +void +fox_gsl_shell::before_eval() +{ + unsigned n = m_window_close_queue.size(); + for (unsigned k = 0; k < n; k++) + { + window_index_remove (L, m_window_close_queue[k]); + } + m_window_close_queue.clear(); +} + +void +fox_gsl_shell::quit_callback() +{ + if (m_close) + m_close->signal(); +} + +void +fox_gsl_shell::window_close_notify(int window_id) +{ + pthread::mutex& eval = eval_mutex(); + eval.lock(); + m_window_close_queue.add(window_id); + eval.unlock(); +} diff --git a/fox-gui/fox_gsl_shell.h b/fox-gui/fox_gsl_shell.h new file mode 100644 index 00000000..66379665 --- /dev/null +++ b/fox-gui/fox_gsl_shell.h @@ -0,0 +1,30 @@ +#ifndef FOX_GSL_SHELL_H +#define FOX_GSL_SHELL_H + +#include <fx.h> +#include "agg_array.h" + +#include "gsl_shell_thread.h" + +class fox_gsl_shell : public gsl_shell_thread +{ +public: + fox_gsl_shell(FXApp* app): m_app(app), m_close(0) { } + + ~fox_gsl_shell() { delete m_close; } + + virtual void init(); + virtual void before_eval(); + virtual void quit_callback(); + + void set_closing_signal(FXGUISignal* s) { m_close = s; } + + void window_close_notify(int window_id); + +private: + FXApp* m_app; + FXGUISignal* m_close; + agg::pod_bvector<int> m_window_close_queue; +}; + +#endif diff --git a/fox-gui/fx_console.cpp b/fox-gui/fx_console.cpp new file mode 100644 index 00000000..fe30fc75 --- /dev/null +++ b/fox-gui/fx_console.cpp @@ -0,0 +1,133 @@ + +#include <fxkeys.h> + +#include "luajit.h" + +#include "fx_console.h" +#include "gsl_shell_app.h" +#include "gsl_shell_thread.h" +#include "fx_plot_window.h" + +FXDEFMAP(fx_console) fx_console_map[]= +{ + FXMAPFUNC(SEL_KEYPRESS, 0, fx_console::on_key_press), + FXMAPFUNC(SEL_IO_READ, fx_console::ID_LUA_OUTPUT, fx_console::on_lua_output), +}; + +FXIMPLEMENT(fx_console,FXText,fx_console_map,ARRAYNUMBER(fx_console_map)) + +char const * const fx_console::prompt = "> "; + +fx_console::fx_console(gsl_shell_thread* gs, FXComposite *p, FXObject* tgt, FXSelector sel, FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb): + FXText(p, tgt, sel, opts, x, y, w, h, pl, pr, pt, pb), + m_status(not_ready), m_engine(gs) +{ + FXApp* app = getApp(); + m_lua_io_signal = new FXGUISignal(app, this, ID_LUA_OUTPUT); + m_lua_io_thread = new lua_io_thread(m_engine, m_lua_io_signal, &m_lua_io_mutex, &m_lua_io_buffer); +} + +fx_console::~fx_console() +{ + delete m_lua_io_thread; + delete m_lua_io_signal; +} + +void fx_console::prepare_input() +{ + appendText(prompt, strlen(prompt)); + m_status = input_mode; + m_input_begin = getCursorPos(); +} + +void fx_console::show_errors() +{ + if (m_engine->eval_status() == gsl_shell::eval_error) + { + appendText("Error reported: "); + appendText(m_engine->error_msg()); + appendText("\n"); + makePositionVisible(getCursorPos()); + } +} + +void fx_console::create() +{ + FXText::create(); + FXString msg; + msg.format("GSL Shell %s, Copyright (C) 2009-2012 Francesco Abbate\n" + "GNU Scientific Library, Copyright (C) The GSL Team\n" + "%s -- %s\n", + GSL_SHELL_RELEASE, LUAJIT_VERSION, LUAJIT_COPYRIGHT); + init(msg); + setFocus(); + m_lua_io_thread->start(); +} + +void fx_console::init(const FXString& greeting) +{ + appendText(greeting); + prepare_input(); +} + +long fx_console::on_key_press(FXObject* obj, FXSelector sel, void* ptr) +{ + FXEvent* event = (FXEvent*)ptr; + if (event->code == KEY_Return && m_status == input_mode) + { + FXint pos = getCursorPos(); + FXint line_end = lineEnd(pos), line_start = m_input_begin; + extractText(m_input, line_start, line_end - line_start); + appendText("\n"); + + this->m_status = output_mode; + m_engine->input(m_input.text()); + + return 1; + } + + return FXText::onKeyPress(obj, sel, ptr); +} + +long fx_console::on_lua_output(FXObject* obj, FXSelector sel, void* ptr) +{ + bool eot = false; + + m_lua_io_mutex.lock(); + FXint len = m_lua_io_buffer.length(); + if (len > 0) + { + if (m_lua_io_buffer[len-1] == gsl_shell_thread::eot_character) + { + eot = true; + m_lua_io_buffer.trunc(len-1); + } + } + appendText(m_lua_io_buffer); + makePositionVisible(getCursorPos()); + + m_lua_io_buffer.clear(); + m_lua_io_mutex.unlock(); + + if (eot) + { + int status = m_engine->eval_status(); + + if (status == gsl_shell::incomplete_input) + { + m_status = input_mode; + } + else if (status == gsl_shell::exit_request) + { + FXApp* app = getApp(); + app->handle(this, FXSEL(SEL_COMMAND,FXApp::ID_QUIT), NULL); + } + else + { + show_errors(); + prepare_input(); + } + } + + return 1; +} diff --git a/fox-gui/fx_console.h b/fox-gui/fx_console.h new file mode 100644 index 00000000..4c40cb22 --- /dev/null +++ b/fox-gui/fx_console.h @@ -0,0 +1,58 @@ +#ifndef FOXGUI_FX_CONSOLE_H +#define FOXGUI_FX_CONSOLE_H + +#include <new> +#include <fx.h> +#include <FXArray.h> + +#include "gsl_shell_thread.h" +#include "io_thread.h" + +class fx_console : public FXText +{ + FXDECLARE(fx_console) + +private: + enum status_e { not_ready, input_mode, output_mode }; + + static char const * const prompt; + +public: + fx_console(gsl_shell_thread* gs, FXComposite *p,FXObject* tgt=NULL,FXSelector sel=0,FXuint opts=0,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=3,FXint pr=3,FXint pt=2,FXint pb=2); + + ~fx_console(); + + // prepare to accept input + void init(const FXString& greeting); + void prepare_input(); + void show_errors(); + +public: + virtual void create(); + + long on_key_press(FXObject*,FXSelector,void*); + long on_lua_output(FXObject*,FXSelector,void*); + + enum + { + ID_READ_INPUT = FXText::ID_LAST, + ID_LUA_OUTPUT, + ID_LAST, + }; + +protected: + fx_console() {} + +private: + FXint m_input_begin; + FXString m_input; + status_e m_status; + gsl_shell_thread* m_engine; + + lua_io_thread* m_lua_io_thread; + FXGUISignal* m_lua_io_signal; + FXMutex m_lua_io_mutex; + FXString m_lua_io_buffer; +}; + +#endif diff --git a/fox-gui/fx_plot_canvas.cpp b/fox-gui/fx_plot_canvas.cpp new file mode 100644 index 00000000..f7ecf21e --- /dev/null +++ b/fox-gui/fx_plot_canvas.cpp @@ -0,0 +1,178 @@ +#include "util/agg_color_conv_rgb8.h" + +#include "fx_plot_canvas.h" +#include "rendering_buffer_utils.h" +#include "fatal.h" +#include "lua-graph.h" + +FXDEFMAP(fx_plot_canvas) fx_plot_canvas_map[]= +{ + FXMAPFUNC(SEL_PAINT, 0, fx_plot_canvas::on_cmd_paint), + FXMAPFUNC(SEL_UPDATE, 0, fx_plot_canvas::on_update), +}; + +FXIMPLEMENT(fx_plot_canvas,FXCanvas,fx_plot_canvas_map,ARRAYNUMBER(fx_plot_canvas_map)); + +fx_plot_canvas::fx_plot_canvas(FXComposite* p, FXObject* tgt, FXSelector sel, FXuint opts, FXint x, FXint y, FXint w, FXint h): + FXCanvas(p, tgt, sel, opts, x, y, w, h), + m_plot(0), m_canvas(0), m_dirty_flag(true), m_dirty_img(true) +{ +} + +fx_plot_canvas::~fx_plot_canvas() +{ + delete m_canvas; +} + +void fx_plot_canvas::prepare_image_buffer(unsigned ww, unsigned hh) +{ + m_img.resize(ww, hh); + m_canvas = new canvas(m_img, ww, hh, colors::white); + m_dirty_img = true; +} + +void fx_plot_canvas::ensure_canvas_size(unsigned ww, unsigned hh) +{ + if (m_img.width() != ww || m_img.height() != hh) + { + m_area_mtx.sx = ww; + m_area_mtx.sy = hh; + prepare_image_buffer(ww, hh); + } +} + +void fx_plot_canvas::plot_render(agg::trans_affine& m) +{ + m_canvas->clear(colors::white); + AGG_LOCK(); + m_plot->draw(*m_canvas, m); + AGG_UNLOCK(); + m_dirty_img = false; +} + +void fx_plot_canvas::plot_draw(agg::trans_affine& m) +{ + FXDCWindow dc(this); + int ww = getWidth(), hh = getHeight(); + + ensure_canvas_size(ww, hh); + + if (m_canvas && m_plot) + { + if (m_dirty_img) + plot_render(m); + + FXImage img(getApp(), NULL, IMAGE_OWNED|IMAGE_SHMI|IMAGE_SHMP, ww, hh); + agg::int8u* data = (agg::int8u*) img.getData(); + agg::rendering_buffer rbuf_tmp(data, ww, hh, - ww * 4); + my_color_conv(&rbuf_tmp, &m_img, color_conv_rgb24_to_rgba32()); + img.create(); + + dc.drawImage(&img, 0, 0); + } + else + { + dc.setForeground(FXRGB(255,255,255)); + dc.fillRectangle(0, 0, ww, hh); + } + + m_dirty_flag = false; +} + +void fx_plot_canvas::update_region(const agg::rect_base<int>& _r) +{ + int iw = m_img.width(), ih = m_img.height(); + const agg::rect_base<int> b(0, 0, iw, ih); + agg::rect_base<int> r = agg::intersect_rectangles(_r, b); + + FXshort ww = r.x2 - r.x1, hh= r.y2 - r.y1; + FXImage img(getApp(), NULL, IMAGE_OWNED|IMAGE_SHMI|IMAGE_SHMP, ww, hh); + + const unsigned bpp = 32; + const unsigned pixel_size = bpp / 8; + + agg::rendering_buffer dest; + dest.attach((agg::int8u*) img.getData(), ww, hh, -ww * pixel_size); + + rendering_buffer_ro src; + rendering_buffer_get_const_view(src, m_img, r, gslshell::bpp / 8, true); + + my_color_conv(&dest, &src, color_conv_rgb24_to_rgba32()); + + img.create(); + + FXDCWindow dc(this); + dc.drawImage(&img, r.x1, getHeight() - r.y2); +} + +opt_rect<double> fx_plot_canvas::plot_render_queue(agg::trans_affine& m) +{ + opt_rect<double> r, draw_rect; + AGG_LOCK(); + m_plot->draw_queue(*m_canvas, m, draw_rect); + AGG_UNLOCK(); + r.add<rect_union>(draw_rect); + r.add<rect_union>(m_dirty_rect); + m_dirty_rect = draw_rect; + return r; +} + +void fx_plot_canvas::plot_draw_queue(agg::trans_affine& m, bool draw_all) +{ + if (!m_canvas || !m_plot) return; + + opt_rect<double> rect = plot_render_queue(m); + + if (draw_all) + { + const agg::rect_base<int> ri(0, 0, getWidth(), getHeight()); + update_region(ri); + } + else if (rect.is_defined()) + { + const int pd = 4; + const agg::rect_base<double>& r = rect.rect(); + const agg::rect_base<int> ri(r.x1 - pd, r.y1 - pd, r.x2 + pd, r.y2 + pd); + update_region(ri); + } +} + +bool fx_plot_canvas::save_image() +{ + int ww = getWidth(), hh = getHeight(); + if (!m_img.defined() || !m_save_img.resize(ww, hh)) return false; + if (m_dirty_img) + plot_render(m_area_mtx); + m_save_img.copy_from(m_img); + return true; +} + +bool fx_plot_canvas::restore_image() +{ + if (!image::match(m_img, m_save_img)) + return false; + m_img.copy_from(m_save_img); + return true; +} + +void fx_plot_canvas::attach(plot_type* p) +{ + m_plot = p; + m_dirty_flag = true; + m_dirty_img = true; +} + +long fx_plot_canvas::on_cmd_paint(FXObject *, FXSelector, void *ptr) +{ + FXEvent* ev = (FXEvent*) ptr; + plot_draw(m_area_mtx); + return 1; +} + +long fx_plot_canvas::on_update(FXObject *, FXSelector, void *) +{ + bool need_upd = m_dirty_flag; + if (need_upd) + plot_draw(m_area_mtx); + return (need_upd ? 1 : 0); +} diff --git a/fox-gui/fx_plot_canvas.h b/fox-gui/fx_plot_canvas.h new file mode 100644 index 00000000..5a0d3524 --- /dev/null +++ b/fox-gui/fx_plot_canvas.h @@ -0,0 +1,73 @@ +#ifndef FOXGUI_FX_PLOT_CANVAS_H +#define FOXGUI_FX_PLOT_CANVAS_H + +#include <new> +#include <fx.h> +#include <agg_rendering_buffer.h> + +#include "image_buf.h" +#include "sg_object.h" +#include "plot-auto.h" +#include "canvas.h" +#include "rect.h" + +class fx_plot_canvas : public FXCanvas +{ + FXDECLARE(fx_plot_canvas) + + typedef image_gen<3, true> image; + +public: + typedef plot<manage_owner> plot_type; + + fx_plot_canvas(FXComposite* p, FXObject* tgt=NULL, FXSelector sel=0, + FXuint opts=FRAME_NORMAL, + FXint x=0, FXint y=0, FXint w=0, FXint h=0); + + ~fx_plot_canvas(); + + void attach(plot_type* p); + void update_region(const agg::rect_base<int>& r); + + plot_type* get_plot() + { + return m_plot; + } + + void plot_render(agg::trans_affine& m); + void plot_draw(agg::trans_affine& m); + opt_rect<double> plot_render_queue(agg::trans_affine& m); + void plot_draw_queue(agg::trans_affine& m, bool draw_all); + + agg::trans_affine& plot_matrix() + { + return m_area_mtx; + } + bool is_ready() const + { + return m_canvas && m_plot; + } + + bool save_image(); + bool restore_image(); + + long on_cmd_paint(FXObject *, FXSelector, void *); + long on_update(FXObject *, FXSelector, void *); + +protected: + fx_plot_canvas() {} + +private: + void prepare_image_buffer(unsigned ww, unsigned hh); + void ensure_canvas_size(unsigned ww, unsigned hh); + + image m_img; + image m_save_img; + plot_type* m_plot; + canvas* m_canvas; + bool m_dirty_flag, m_dirty_img; + opt_rect<double> m_dirty_rect; + agg::trans_affine m_area_mtx; +}; + +#endif diff --git a/fox-gui/fx_plot_window.cpp b/fox-gui/fx_plot_window.cpp new file mode 100644 index 00000000..b75e42d4 --- /dev/null +++ b/fox-gui/fx_plot_window.cpp @@ -0,0 +1,31 @@ + +#include "fx_plot_window.h" + +FXDEFMAP(fx_plot_window) fx_plot_window_map[]= +{ +}; + +FXIMPLEMENT(fx_plot_window,FXMainWindow,fx_plot_window_map,ARRAYNUMBER(fx_plot_window_map)) + +fx_plot_window::fx_plot_window(FXApp* app, const FXString& name, FXIcon *ic, FXIcon *mi, FXint w, FXint h): + FXMainWindow(app, name, ic, mi, DECOR_ALL, 0, 0, w, h) +{ + m_menu_bar = new FXMenuBar(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X); + + m_plot_menu = new FXMenuPane(this); + new FXMenuCommand(m_plot_menu, "&Close\tCtl-C", NULL, app, FXApp::ID_QUIT); + new FXMenuTitle(m_menu_bar, "&Plot", NULL, m_plot_menu); + + FXVerticalFrame* frame = new FXVerticalFrame(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y); + + // Sunken border for text widget + FXHorizontalFrame *cbox = new FXHorizontalFrame(frame, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0); + + m_canvas = new fx_plot_canvas(cbox, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y); +} + +fx_plot_window::~fx_plot_window() +{ + delete m_canvas; + delete m_plot_menu; +} diff --git a/fox-gui/fx_plot_window.h b/fox-gui/fx_plot_window.h new file mode 100644 index 00000000..a016b248 --- /dev/null +++ b/fox-gui/fx_plot_window.h @@ -0,0 +1,37 @@ +#ifndef FOXGUI_FX_PLOT_WINDOW_H +#define FOXGUI_FX_PLOT_WINDOW_H + +#include <fx.h> + +#include "gsl_shell_app.h" +#include "fx_plot_canvas.h" + +class fx_plot_window : public FXMainWindow +{ + FXDECLARE(fx_plot_window) +public: + fx_plot_window(FXApp* a, const FXString& name, FXIcon *ic=NULL, FXIcon *mi=NULL, FXint w=0, FXint h=0); + + ~fx_plot_window(); + + fx_plot_canvas* canvas() + { + return m_canvas; + } + gsl_shell_app* get_app() + { + return (gsl_shell_app*) getApp(); + } + + int lua_id; // the following is used by Lua to keep trace of the window + +protected: + fx_plot_window() {} + +private: + FXMenuBar* m_menu_bar; + FXMenuPane* m_plot_menu; + fx_plot_canvas* m_canvas; +}; + +#endif diff --git a/fox-gui/gsl-shell-fox.cpp b/fox-gui/gsl-shell-fox.cpp new file mode 100644 index 00000000..1064819c --- /dev/null +++ b/fox-gui/gsl-shell-fox.cpp @@ -0,0 +1,22 @@ +#include <fx.h> +#include "gsl_shell_window.h" +#include "gsl_shell_app.h" +#include "window_hooks.h" +#include "lua_plot_window.h" + +struct window_hooks app_window_hooks[1] = {{ + fox_window_new, fox_window_attach, + fox_window_slot_update, fox_window_slot_refresh, + fox_window_save_slot_image, fox_window_restore_slot_image, + fox_window_register, + } +}; + +int +main (int argc, char *argv[]) +{ + gsl_shell_app app; + app.init(argc, argv); + app.create(); + return app.run(); +} diff --git a/fox-gui/gsl_shell_app.cpp b/fox-gui/gsl_shell_app.cpp new file mode 100644 index 00000000..b32d2878 --- /dev/null +++ b/fox-gui/gsl_shell_app.cpp @@ -0,0 +1,84 @@ + +#include <unistd.h> + +#include "gsl_shell_app.h" +#include "gsl_shell_window.h" +#include "fx_plot_window.h" +#include "lua_plot_window.h" +#include "fatal.h" + +FXDEFMAP(gsl_shell_app) gsl_shell_app_map[]= +{ + FXMAPFUNC(SEL_IO_READ, gsl_shell_app::ID_LUA_REQUEST, gsl_shell_app::on_lua_request), + FXMAPFUNC(SEL_IO_READ, gsl_shell_app::ID_LUA_QUIT, gsl_shell_app::on_lua_quit), + FXMAPFUNC(SEL_COMMAND, gsl_shell_app::ID_CONSOLE_CLOSE, gsl_shell_app::on_console_close), + FXMAPFUNC(SEL_CLOSE, 0, gsl_shell_app::on_window_close), +}; + +FXIMPLEMENT(gsl_shell_app,FXApp,gsl_shell_app_map,ARRAYNUMBER(gsl_shell_app_map)) + +gsl_shell_app* global_app; + +gsl_shell_app::gsl_shell_app() : FXApp("GSL Shell", "GSL Shell"), + m_engine(this) +{ + m_lua_request = new FXGUISignal(this, this, ID_LUA_REQUEST); + + FXGUISignal* quit = new FXGUISignal(this, this, ID_LUA_QUIT); + m_engine.set_closing_signal(quit); + + global_app = this; + m_engine.start(); + + new gsl_shell_window(&m_engine, this, "GSL Shell Console", NULL, NULL, 600, 500); +} + +gsl_shell_app::~gsl_shell_app() +{ + delete m_lua_request; +} + +long gsl_shell_app::on_lua_request(FXObject*, FXSelector, void*) +{ + for (unsigned k = 0; k < m_win_queue.size(); k++) + { + FXMainWindow* win = m_win_queue[k]; + win->create(); + win->show(PLACEMENT_SCREEN); + } + m_win_queue.clear(); + m_window_mapping.signal(); + return 1; +} + +long gsl_shell_app::on_lua_quit(FXObject*, FXSelector, void*) +{ + m_engine.close(); + exit(0); + return 1; +} + +void gsl_shell_app::window_create_request(FXMainWindow* win) +{ + m_win_queue.add(win); + m_lua_request->signal(); +} + +long gsl_shell_app::on_console_close(FXObject* sender, FXSelector, void*) +{ + m_engine.stop(); + return 1; +} + +long gsl_shell_app::on_window_close(FXObject* sender, FXSelector, void*) +{ + fx_plot_window* win = (fx_plot_window*) sender; + m_engine.window_close_notify(win->lua_id); + return 0; +} + +void gsl_shell_app::wait_window_mapping() +{ + FXMutex& app_mutex = mutex(); + m_window_mapping.wait(app_mutex); +} diff --git a/fox-gui/gsl_shell_app.h b/fox-gui/gsl_shell_app.h new file mode 100644 index 00000000..f33e9a77 --- /dev/null +++ b/fox-gui/gsl_shell_app.h @@ -0,0 +1,50 @@ +#ifndef FOXGUI_GSL_SHELL_APP_H +#define FOXGUI_GSL_SHELL_APP_H + +#include <fx.h> + +#include "agg_array.h" +#include "fox_gsl_shell.h" + +class gsl_shell_app : public FXApp +{ + FXDECLARE(gsl_shell_app) +public: + gsl_shell_app(); + ~gsl_shell_app(); + + void lock() + { + mutex().lock(); + } + void unlock() + { + mutex().unlock(); + } + + void window_create_request(FXMainWindow* win); + void wait_window_mapping(); + + long on_lua_request(FXObject*,FXSelector,void*); + long on_window_close(FXObject*,FXSelector,void*); + long on_console_close(FXObject*,FXSelector,void*); + long on_lua_quit(FXObject*,FXSelector,void*); + + enum + { + ID_LUA_REQUEST = FXApp::ID_LAST, + ID_CONSOLE_CLOSE, + ID_LUA_QUIT, + ID_LAST + }; + +private: + fox_gsl_shell m_engine; + FXGUISignal* m_lua_request; + agg::pod_bvector<FXMainWindow*> m_win_queue; + FXCondition m_window_mapping; +}; + +extern gsl_shell_app* global_app; + +#endif diff --git a/fox-gui/gsl_shell_interp.cpp b/fox-gui/gsl_shell_interp.cpp new file mode 100644 index 00000000..6cd077e5 --- /dev/null +++ b/fox-gui/gsl_shell_interp.cpp @@ -0,0 +1,202 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define luajit_c + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include "luajit.h" +} + +#include "gsl_shell_interp.h" +#include "lua-gsl.h" +#include "lua-graph.h" +#include "fatal.h" + +static void stderr_message(const char *pname, const char *msg) +{ + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); + fflush(stderr); +} + +static int stderr_report(lua_State *L, int status) +{ + if (status && !lua_isnil(L, -1)) + { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; + stderr_message("gsl-shell", msg); + lua_pop(L, 1); + } + return status; +} + +static int traceback(lua_State *L) +{ + if (!lua_isstring(L, 1)) /* 'message' not a string? */ + return 1; /* keep it intact */ + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) + { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + return 1; +} + +static int docall(lua_State *L, int narg, int clear) +{ + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, traceback); /* push traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection in case of errors */ + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + +static int dolibrary(lua_State *L, const char *name) +{ + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return stderr_report(L, docall(L, 1, 1)); +} + +static int pinit(lua_State *L) +{ + LUAJIT_VERSION_SYM(); /* linker-enforced version check */ + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + luaopen_gsl (L); + register_graph (L); + lua_gc(L, LUA_GCRESTART, -1); + dolibrary (L, "gslext"); + return 0; +} + +/* If the input is an expression we load it preceded by "return" so + that the value is returned as a result of the evaluation. + If the value is not an expression leave the stack as before and + returns a non zero value. */ +static int yield_expr(lua_State* L, const char* line, size_t len) +{ + const char *p; + int status; + + for (p = line + len - 1; p >= line; p--) + { + const char c = *p; + if (c == ';') + return 1; + if (c != ' ') + break; + } + + str mline = str::print("return %s", line); + status = luaL_loadbuffer(L, mline.cstr(), len+7, "=stdin"); + if (status != 0) lua_pop(L, 1); // remove the error message + return status; +} + +static int incomplete(lua_State *L, int status) +{ + if (status == LUA_ERRSYNTAX) + { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); + if (strstr(msg, LUA_QL("<eof>")) == tp) + { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + +void gsl_shell::init() +{ + gsl_shell_open(this); + + int status = lua_cpcall(this->L, pinit, NULL); + + if (unlikely(stderr_report(this->L, status))) + { + lua_close(this->L); + fatal_exception("cannot initialize Lua state"); + } +} + +void gsl_shell::close() +{ + lua_close(this->L); + this->L = NULL; +} + +int gsl_shell::error_report(int status) +{ + lua_State* L = this->L; + if (status && !lua_isnil(L, -1)) + { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; + m_error_msg = msg; + lua_pop(L, 1); + } + return status; +} + +int gsl_shell::exec(const char *line) +{ + lua_State* L = this->L; + size_t len = strlen(line); + + if (strcmp (line, "exit") == 0) + return exit_request; + + /* try to load the string as an expression */ + int status = yield_expr(L, line, len); + + if (status != 0) + { + status = luaL_loadbuffer(L, line, len, "=<user input>"); + + if (incomplete(L, status)) + return incomplete_input; + } + + if (status == 0) + { + status = docall(L, 0, 0); + error_report(status); + if (status == 0 && lua_gettop(L) > 0) /* any result to print? */ + { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_GLOBALSINDEX, "_"); + + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + fprintf(stderr, "error calling print function"); + } + } + + error_report(status); + + return (status == 0 ? eval_success : eval_error); +} diff --git a/fox-gui/gsl_shell_interp.h b/fox-gui/gsl_shell_interp.h new file mode 100644 index 00000000..c61a5373 --- /dev/null +++ b/fox-gui/gsl_shell_interp.h @@ -0,0 +1,46 @@ +#ifndef GSL_SHELL_INTERP_H +#define GSL_SHELL_INTERP_H + +extern "C" { +#include <lua.h> +} + +#include "defs.h" +#include "pthreadpp.h" +#include "lua-gsl.h" +#include "strpp.h" +#include "fatal.h" + +class gsl_shell : public gsl_shell_state +{ +public: + enum eval_result_e { eval_success, eval_error, incomplete_input, exit_request }; + + gsl_shell() + { + gsl_shell_init(this); + } + + virtual ~gsl_shell() + { + if (unlikely(this->L != NULL)) + fatal_exception("warning: attempt to dispose an open Lua state"); + gsl_shell_free(this); + } + + virtual void init(); + virtual void close(); + + int exec(const char* line); + const char* error_msg() const + { + return m_error_msg.cstr(); + } + +private: + int error_report(int status); + + str m_error_msg; +}; + +#endif diff --git a/fox-gui/gsl_shell_thread.cpp b/fox-gui/gsl_shell_thread.cpp new file mode 100644 index 00000000..1d2a452d --- /dev/null +++ b/fox-gui/gsl_shell_thread.cpp @@ -0,0 +1,106 @@ +#include <pthread.h> +#include <stdio.h> + +#include "gsl_shell_thread.h" + +extern "C" void * luajit_eval_thread (void *userdata); + +void * +luajit_eval_thread (void *userdata) +{ + gsl_shell_thread* eng = (gsl_shell_thread*) userdata; + eng->lock(); + eng->init(); + eng->run(); + pthread_exit(NULL); + return NULL; +} + +gsl_shell_thread::gsl_shell_thread(): + m_status(starting), m_redirect(4096), m_exit_request(false) +{ +} + +gsl_shell_thread::~gsl_shell_thread() +{ + m_redirect.stop(); +} + +void gsl_shell_thread::start() +{ + m_redirect.start(); + + pthread_attr_t attr[1]; + + pthread_attr_init (attr); + pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED); + + if (pthread_create (&m_thread, attr, luajit_eval_thread, (void*)this)) + { + fprintf(stderr, "error creating thread"); + } +} + +void +gsl_shell_thread::run() +{ + while (!m_exit_request) + { + m_eval.lock(); + m_status = ready; + + this->unlock(); + m_eval.wait(); + this->lock(); + + before_eval(); + + if (m_exit_request) + { + m_eval.unlock(); + break; + } + + m_status = busy; + m_eval.unlock(); + + // here m_line_pending cannot be modified by the other thread + // because we declared above m_status to "busy" befor unlocking m_eval + const char* line = m_line_pending.cstr(); + m_eval_status = this->exec(line); + + fputc(eot_character, stdout); + fflush(stdout); + } + + this->unlock(); + quit_callback(); +} + +void +gsl_shell_thread::stop() +{ + m_eval.lock(); + m_exit_request = true; + m_eval.signal(); + m_eval.unlock(); + sched_yield(); +} + +void +gsl_shell_thread::input(const char* line) +{ + pthread::auto_lock lock(m_eval); + + if (m_status == ready) + { + m_line_pending = line; + m_eval.signal(); + } +} + +int +gsl_shell_thread::read(char* buffer, unsigned buffer_size) +{ + return m_redirect.read(buffer, buffer_size); +} diff --git a/fox-gui/gsl_shell_thread.h b/fox-gui/gsl_shell_thread.h new file mode 100644 index 00000000..06678183 --- /dev/null +++ b/fox-gui/gsl_shell_thread.h @@ -0,0 +1,60 @@ +#ifndef FOXGUI_LUA_ENGINE_H +#define FOXGUI_LUA_ENGINE_H + +extern "C" { +#include "lua.h" +} + +#include "gsl_shell_interp.h" +#include "pthreadpp.h" +#include "redirect.h" +#include "str.h" + +class gsl_shell_thread : public gsl_shell +{ +public: + enum engine_status_e { starting, ready, busy, terminated }; + enum { eot_character = 0x04 }; + + gsl_shell_thread(); + ~gsl_shell_thread(); + + void input(const char* line); + void start(); + void run(); + void stop(); + + virtual void before_eval() { } + virtual void quit_callback() { } + + void lock() + { + pthread_mutex_lock(&this->exec_mutex); + } + void unlock() + { + pthread_mutex_unlock(&this->exec_mutex); + } + + int read(char* buffer, unsigned buffer_size); + + int eval_status() const + { + return m_eval_status; + } + pthread::mutex& eval_mutex() + { + return m_eval; + } + +private: + pthread_t m_thread; + engine_status_e m_status; + stdout_redirect m_redirect; + pthread::cond m_eval; + str m_line_pending; + int m_eval_status; + bool m_exit_request; +}; + +#endif diff --git a/fox-gui/gsl_shell_window.cpp b/fox-gui/gsl_shell_window.cpp new file mode 100644 index 00000000..49e69db1 --- /dev/null +++ b/fox-gui/gsl_shell_window.cpp @@ -0,0 +1,49 @@ +#include "gsl_shell_window.h" +#include "gsl_shell_app.h" + +#ifdef WIN32 +#define CONSOLE_FONT "lucida console" +#else +#define CONSOLE_FONT "monospace" +#endif + +FXDEFMAP(gsl_shell_window) gsl_shell_window_map[]= +{ + FXMAPFUNC(SEL_CLOSE, 0, gsl_shell_window::on_close), + FXMAPFUNC(SEL_COMMAND, FXTopWindow::ID_CLOSE, gsl_shell_window::on_close), +}; + +FXIMPLEMENT(gsl_shell_window,FXMainWindow,gsl_shell_window_map,ARRAYNUMBER(gsl_shell_window_map)) + +gsl_shell_window::gsl_shell_window(gsl_shell_thread* gs, FXApp* app, const FXString& name, FXIcon *ic, FXIcon *mi, FXint w, FXint h): + FXMainWindow(app, name, ic, mi, DECOR_ALL, 0, 0, w, h) +{ + m_menu_bar = new FXMenuBar(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X); + m_status_bar = new FXStatusBar(this, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|FRAME_RAISED|STATUSBAR_WITH_DRAGCORNER); + + m_file_menu = new FXMenuPane(this); + new FXMenuCommand(m_file_menu, "&Quit\tCtl-Q", NULL, this, FXTopWindow::ID_CLOSE); + new FXMenuTitle(m_menu_bar, "&File", NULL, m_file_menu); + + FXVerticalFrame* frame = new FXVerticalFrame(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y); + + // Sunken border for text widget + FXHorizontalFrame *textbox = new FXHorizontalFrame(frame, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0); + + m_text_font = new FXFont(app, CONSOLE_FONT, 10); + m_text = new fx_console(gs, textbox, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y); + m_text->setFont(m_text_font); +} + +void gsl_shell_window::create() +{ + FXMainWindow::create(); + show(PLACEMENT_SCREEN); +} + +long gsl_shell_window::on_close(FXObject* obj, FXSelector sel, void* ptr) +{ + FXApp* app = getApp(); + app->handle(this, FXSEL(SEL_COMMAND, gsl_shell_app::ID_CONSOLE_CLOSE), NULL); + return 0; +} diff --git a/fox-gui/gsl_shell_window.h b/fox-gui/gsl_shell_window.h new file mode 100644 index 00000000..c9d5c1e3 --- /dev/null +++ b/fox-gui/gsl_shell_window.h @@ -0,0 +1,36 @@ +#ifndef FOXGUI_GSL_SHELL_WINDOW_H +#define FOXGUI_GSL_SHELL_WINDOW_H + +#include <fx.h> + +#include "gsl_shell_thread.h" +#include "fx_console.h" + +class gsl_shell_window : public FXMainWindow +{ + FXDECLARE(gsl_shell_window) +public: + gsl_shell_window(gsl_shell_thread* gs, FXApp* a, const FXString& name, FXIcon *ic=NULL, FXIcon *mi=NULL, FXint w=0, FXint h=0); + + virtual ~gsl_shell_window() + { + delete m_file_menu; + delete m_text_font; + } + + virtual void create(); + + long on_close(FXObject* obj, FXSelector sel, void* ptr); + +protected: + gsl_shell_window() {} + +private: + fx_console* m_text; + FXStatusBar* m_status_bar; + FXMenuBar* m_menu_bar; + FXMenuPane* m_file_menu; + FXFont* m_text_font; +}; + +#endif diff --git a/fox-gui/image_buf.h b/fox-gui/image_buf.h new file mode 100644 index 00000000..ecca662d --- /dev/null +++ b/fox-gui/image_buf.h @@ -0,0 +1,60 @@ +#ifndef FOXGUI_IMAGE_BUF_H +#define FOXGUI_IMAGE_BUF_H + +#include <agg_rendering_buffer.h> + +template <unsigned PixelSize, bool FlipY> +struct image_gen : agg::rendering_buffer +{ + image_gen() { } + image_gen(unsigned w, unsigned h) + { + init(w, h); + } + + ~image_gen() + { + dispose(); + } + + bool defined() const + { + return (buf() != 0); + } + + bool resize(unsigned w, unsigned h) + { + dispose(); + return init(w, h); + } + + void clear() + { + dispose(); + attach(NULL, 0, 0, 0); + } + + static bool match(const image_gen& a, const image_gen& b) + { + if (!a.defined() || !b.defined()) + return false; + return (a.width() == b.width() && a.height() == b.height()); + } + +private: + bool init(unsigned w, unsigned h) + { + agg::int8u* data = new(std::nothrow) agg::int8u[w * h * PixelSize]; + int stride = (FlipY ? - w * PixelSize : w * PixelSize); + attach(data, w, h, stride); + return (data != 0); + } + + void dispose() + { + agg::int8u* data = buf(); + delete[] data; + } +}; + +#endif diff --git a/fox-gui/io_thread.cpp b/fox-gui/io_thread.cpp new file mode 100644 index 00000000..f9b4062f --- /dev/null +++ b/fox-gui/io_thread.cpp @@ -0,0 +1,49 @@ +#include <pthread.h> +#include <errno.h> + +#include "io_thread.h" + +static void* io_thread_run(void* data) +{ + lua_io_thread* thread = (lua_io_thread*) data; + thread->run(); + return 0; +} + +void lua_io_thread::run() +{ + char buffer[128]; + + while (1) + { + int nr = m_engine->read(buffer, 127); + if (nr < 0) + { + fprintf(stderr, "ERROR on read: %d.\n", errno); + break; + } + if (nr == 0) + break; + + buffer[nr] = 0; + + m_io_protect->lock(); + m_io_buffer->append((const FXchar*)buffer); + m_io_protect->unlock(); + + m_io_ready->signal(); + } +} + +void lua_io_thread::start() +{ + pthread_attr_t attr[1]; + + pthread_attr_init (attr); + pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED); + + if (pthread_create (&m_thread, attr, io_thread_run, (void*)this)) + { + fprintf(stderr, "error creating thread"); + } +} diff --git a/fox-gui/io_thread.h b/fox-gui/io_thread.h new file mode 100644 index 00000000..682999f7 --- /dev/null +++ b/fox-gui/io_thread.h @@ -0,0 +1,25 @@ +#ifndef FOXGUI_IO_THREAD_H +#define FOXGUI_IO_THREAD_H + +#include <fx.h> + +#include "gsl_shell_thread.h" + +class lua_io_thread { +public: + lua_io_thread(gsl_shell_thread* eng, FXGUISignal* sig, FXMutex* mut, FXString* buf): + m_engine(eng), m_io_ready(sig), m_io_protect(mut), m_io_buffer(buf) + { } + + void run(); + void start(); + +private: + pthread_t m_thread; + gsl_shell_thread* m_engine; + FXGUISignal* m_io_ready; + FXMutex* m_io_protect; + FXString* m_io_buffer; +}; + +#endif diff --git a/fox-gui/lua_plot_window.cpp b/fox-gui/lua_plot_window.cpp new file mode 100644 index 00000000..9a3d3230 --- /dev/null +++ b/fox-gui/lua_plot_window.cpp @@ -0,0 +1,169 @@ + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +} + +#include "lua_plot_window.h" +#include "gsl_shell_app.h" +#include "window_registry.h" +#include "fx_plot_window.h" +#include "lua-cpp-utils.h" +#include "lua-graph.h" +#include "gs-types.h" +#include "plot.h" + +__BEGIN_DECLS + +static int fox_window_close (lua_State *L); + +static const struct luaL_Reg fox_window_functions[] = +{ + {"window", fox_window_new}, + {NULL, NULL} +}; + +static const struct luaL_Reg fox_window_methods[] = +{ + {"attach", fox_window_attach }, + {"close", fox_window_close }, + {"refresh", fox_window_slot_refresh }, + {"update", fox_window_slot_update }, + {NULL, NULL} +}; + + +struct lua_fox_window +{ + fx_plot_window* window; +}; + +__END_DECLS + +typedef plot<manage_owner> sg_plot; + +int +fox_window_new (lua_State *L) +{ + gsl_shell_app* app = global_app; + app->lock(); + + lua_fox_window* bwin = new(L, GS_FOX_WINDOW) lua_fox_window(); + fx_plot_window* win = new fx_plot_window(app, "GSL Shell FX plot", NULL, NULL, 480, 480); + bwin->window = win; + + win->setTarget(app); + app->window_create_request(win); + + win->lua_id = window_index_add (L, -1); + + do + app->wait_window_mapping(); + while (!win->shown()); + + app->unlock(); + return 1; +} + +int +fox_window_attach (lua_State *L) +{ + fx_plot_window *win = object_check<lua_fox_window>(L, 1, GS_FOX_WINDOW)->window; + sg_plot* p = object_check<sg_plot>(L, 2, GS_PLOT); + gsl_shell_app* app = win->get_app(); + app->lock(); + win->canvas()->attach(p); + app->unlock(); + int slot_id = 1; + window_refs_add (L, slot_id, 1, 2); + return 0; +} + +int +fox_window_close (lua_State *L) +{ + return 0; +} + +int +fox_window_slot_refresh (lua_State *L) +{ + fx_plot_window *win = object_check<lua_fox_window>(L, 1, GS_FOX_WINDOW)->window; + fx_plot_canvas* canvas = win->canvas(); + gsl_shell_app* app = win->get_app(); + + app->lock(); + + if (canvas->is_ready()) + { + agg::trans_affine& m = canvas->plot_matrix(); + bool redraw = canvas->get_plot()->need_redraw(); + if (redraw) + canvas->plot_render(m); + canvas->plot_draw_queue(m, redraw); + } + + app->unlock(); + return 0; +} + +int +fox_window_slot_update (lua_State *L) +{ + fx_plot_window *win = object_check<lua_fox_window>(L, 1, GS_FOX_WINDOW)->window; + fx_plot_canvas* canvas = win->canvas(); + gsl_shell_app* app = win->get_app(); + + app->lock(); + + if (canvas->is_ready()) + { + agg::trans_affine& m = canvas->plot_matrix(); + canvas->plot_render(m); + canvas->plot_draw_queue(m, true); + } + + app->unlock(); + return 0; +} + +int +fox_window_save_slot_image (lua_State *L) +{ + fx_plot_window *win = object_check<lua_fox_window>(L, 1, GS_FOX_WINDOW)->window; + fx_plot_canvas* canvas = win->canvas(); + gsl_shell_app* app = win->get_app(); + app->lock(); + canvas->save_image(); + app->unlock(); + return 0; +} + +int +fox_window_restore_slot_image (lua_State *L) +{ + fx_plot_window *win = object_check<lua_fox_window>(L, 1, GS_FOX_WINDOW)->window; + fx_plot_canvas* canvas = win->canvas(); + gsl_shell_app* app = win->get_app(); + app->lock(); + if (!canvas->restore_image()) + { + agg::trans_affine& m = canvas->plot_matrix(); + canvas->plot_render(m); + canvas->save_image(); + } + app->unlock(); + return 0; +} + +void +fox_window_register (lua_State *L) +{ + luaL_newmetatable (L, GS_METATABLE(GS_FOX_WINDOW)); + lua_pushvalue (L, -1); + lua_setfield (L, -2, "__index"); + luaL_register (L, NULL, fox_window_methods); + lua_pop (L, 1); + + luaL_register (L, NULL, fox_window_functions); +} diff --git a/fox-gui/lua_plot_window.h b/fox-gui/lua_plot_window.h new file mode 100644 index 00000000..3ae8d18c --- /dev/null +++ b/fox-gui/lua_plot_window.h @@ -0,0 +1,21 @@ +#ifndef FOXGUI_FOX_WINDOW_H +#define FOXGUI_FOX_WINDOW_H + +#include "defs.h" + +__BEGIN_DECLS + +#include "lua.h" + +extern void fox_window_register (lua_State *L); + +extern int fox_window_new (lua_State *L); +extern int fox_window_attach (lua_State *L); +extern int fox_window_slot_refresh (lua_State *L); +extern int fox_window_slot_update (lua_State *L); +extern int fox_window_save_slot_image (lua_State *L); +extern int fox_window_restore_slot_image (lua_State *L); + +__END_DECLS + +#endif diff --git a/fox-gui/redirect.cpp b/fox-gui/redirect.cpp new file mode 100644 index 00000000..3df2c94b --- /dev/null +++ b/fox-gui/redirect.cpp @@ -0,0 +1,54 @@ + +#ifdef WIN32 +#include <windows.h> +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <assert.h> + +#include "redirect.h" + +#define READ_FD 0 +#define WRITE_FD 1 + +#define CHECK(a) if ((a)!= 0) return -1; + +stdout_redirect::stdout_redirect(int bufferSize) +{ + int status; + +#ifdef WIN32 + status = _pipe(fd_pipe, bufferSize, O_TEXT); +#else + status = pipe(fd_pipe); +#endif + + assert(status == 0); + + fd_stdout = dup(fileno(stdout)); +} + +int stdout_redirect::start() +{ + fflush(stdout); + CHECK(dup2(fd_pipe[WRITE_FD], fileno(stdout))); + setvbuf( stdout, NULL, _IONBF, 0 ); // absolutely needed + return 0; +} + +int stdout_redirect::stop() +{ + CHECK(dup2(fd_stdout, fileno(stdout))); + close(fd_stdout); + close(fd_pipe[WRITE_FD]); + close(fd_pipe[READ_FD]); + return 0; +} + +int stdout_redirect::read(char *buffer, int size) +{ + int nOutRead = ::read(fd_pipe[READ_FD], buffer, size); + return nOutRead; +} diff --git a/fox-gui/redirect.h b/fox-gui/redirect.h new file mode 100644 index 00000000..eef56343 --- /dev/null +++ b/fox-gui/redirect.h @@ -0,0 +1,18 @@ +#ifndef FOXGUI_REDIRECT_H +#define FOXGUI_REDIRECT_H + +class stdout_redirect +{ +public: + stdout_redirect(int buffer_size); + + int start(); + int stop(); + int read(char *buffer, int size); + +private: + int fd_pipe[2]; + int fd_stdout; +}; + +#endif diff --git a/gsl-shell-jit.c b/gsl-shell-jit.c index bea6611a..7def3915 100644 --- a/gsl-shell-jit.c +++ b/gsl-shell-jit.c @@ -41,6 +41,8 @@ #include "gsl-shell.h" #include "completion.h" #include "lua-graph.h" +#include "window_hooks.h" +#include "window.h" #if defined(USE_READLINE) #include <stdio.h> @@ -98,15 +100,21 @@ static void my_freeline (lua_State *L, char *b) { } #endif lua_State *globalL = NULL; +struct gsl_shell_state gsl_shell[1]; static const char *progname = LUA_PROGNAME; -pthread_mutex_t gsl_shell_mutex[1]; -pthread_mutex_t gsl_shell_shutdown_mutex[1]; -volatile int gsl_shell_shutting_down = 0; +struct window_hooks app_window_hooks[1] = {{ + window_new, window_attach, + window_slot_update, window_slot_refresh, + window_save_slot_image, window_restore_slot_image, + window_register, + } +}; static void gsl_shell_openlibs(lua_State *L) { luaopen_gsl (L); + register_graph (L); } static void lstop(lua_State *L, lua_Debug *ar) @@ -289,9 +297,9 @@ static int pushline (lua_State *L, int firstline) { size_t l; const char *prmt = get_prompt(L, firstline); - GSL_SHELL_UNLOCK(); + pthread_mutex_unlock(&gsl_shell->exec_mutex); b = my_readline(L, buffer, prmt); - GSL_SHELL_LOCK(); + pthread_mutex_lock(&gsl_shell->exec_mutex); if (b == NULL) return 0; /* no input */ @@ -654,31 +662,20 @@ int main(int argc, char **argv) #ifdef USE_READLINE initialize_readline(); #endif - pthread_mutex_init (gsl_shell_mutex, NULL); - pthread_mutex_init (gsl_shell_shutdown_mutex, NULL); - - GSL_SHELL_LOCK(); - lua_State *L = lua_open(); /* create state */ - if (L == NULL) { - l_message(argv[0], "cannot create state: not enough memory"); - return EXIT_FAILURE; - } + gsl_shell_init(gsl_shell); + gsl_shell_open(gsl_shell); + + pthread_mutex_lock(&gsl_shell->exec_mutex); + s.argc = argc; s.argv = argv; - status = lua_cpcall(L, pmain, &s); - report(L, status); - - GSL_SHELL_UNLOCK(); - pthread_mutex_lock (gsl_shell_shutdown_mutex); - gsl_shell_shutting_down = 1; - GSL_SHELL_LOCK(); - graph_close_windows(L); - lua_close(L); - pthread_mutex_unlock (gsl_shell_shutdown_mutex); - GSL_SHELL_UNLOCK(); - - pthread_mutex_destroy (gsl_shell_mutex); - pthread_mutex_destroy (gsl_shell_shutdown_mutex); + status = lua_cpcall(gsl_shell->L, pmain, &s); + report(gsl_shell->L, status); + + pthread_mutex_unlock(&gsl_shell->exec_mutex); + + gsl_shell_close_with_graph(gsl_shell); + gsl_shell_free(gsl_shell); return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/gsl-shell.h b/gsl-shell.h index 67058d30..92a1d8a5 100644 --- a/gsl-shell.h +++ b/gsl-shell.h @@ -2,19 +2,12 @@ #define GSL_SHELL_INCLUDED #include "defs.h" -#include <pthread.h> #include <lua.h> __BEGIN_DECLS extern lua_State *globalL; -extern pthread_mutex_t gsl_shell_mutex[1]; -extern pthread_mutex_t gsl_shell_shutdown_mutex[1]; -extern volatile int gsl_shell_shutting_down; __END_DECLS -#define GSL_SHELL_LOCK() pthread_mutex_lock (gsl_shell_mutex) -#define GSL_SHELL_UNLOCK() pthread_mutex_unlock (gsl_shell_mutex) - #endif @@ -20,7 +20,12 @@ local cat = table.concat local fmt = string.format -local gsl_type = gslsh.type + +local gsl_type +do + local reg = debug.getregistry() + gsl_typename = reg.__gsl_type +end function math.divmod(n, p) local r = n % p @@ -61,8 +66,8 @@ tos = function (t, maxdepth) local mt = getmetatable(t) local ftostr = mt and mt.__tostring if ftostr then return ftostr(t) else - if gsl_type then - return fmt('<%s: %p>', gsl_type(t), t) + if gsl_typename then + return fmt('<%s: %p>', gsl_typename(t), t) else return fmt('<userdata: %p>', t) end diff --git a/lua-graph.h b/lua-graph.h index 636f3f76..f7477a8b 100644 --- a/lua-graph.h +++ b/lua-graph.h @@ -1,12 +1,25 @@ #ifndef LUA_GRAPH_H #define LUA_GRAPH_H -#ifndef MLUA_GRAPHLIBNAME -#define MLUA_GRAPHLIBNAME "graph" -#endif +#include <pthread.h> + +#include "defs.h" + +__BEGIN_DECLS + +#include <lua.h> extern void graph_close_windows (lua_State *L); extern void register_graph (lua_State *L); +extern void gsl_shell_close_with_graph (struct gsl_shell_state* gs); + extern int initialize_fonts(lua_State* L); +extern pthread_mutex_t agg_mutex[1]; + +#define AGG_LOCK() pthread_mutex_lock (agg_mutex); +#define AGG_UNLOCK() pthread_mutex_unlock (agg_mutex); + +__END_DECLS + #endif @@ -1,6 +1,29 @@ #ifndef LUA_GSL_H #define LUA_GSL_H +#include <pthread.h> + +#include "defs.h" + +__BEGIN_DECLS + +#include <lua.h> + +struct gsl_shell_state { + lua_State *L; + pthread_mutex_t exec_mutex; + pthread_mutex_t shutdown_mutex; + int is_shutting_down; +}; + +extern void gsl_shell_open (struct gsl_shell_state *gs); +extern void gsl_shell_free (struct gsl_shell_state *gs); +extern void gsl_shell_init (struct gsl_shell_state *gs); + extern int luaopen_gsl (lua_State *L); +extern struct gsl_shell_state* global_state; + +__END_DECLS + #endif diff --git a/lua-gsl/Makefile b/lua-gsl/Makefile new file mode 100644 index 00000000..386803f8 --- /dev/null +++ b/lua-gsl/Makefile @@ -0,0 +1,57 @@ + +# Makefile +# +# Copyright (C) 2009 Francesco Abbate +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +GSH_BASE_DIR = .. + +include $(GSH_BASE_DIR)/makeconfig +include $(GSH_BASE_DIR)/make-system-detect +include $(GSH_BASE_DIR)/makepackages +include $(GSH_BASE_DIR)/makedefs + +LUADIR = $(GSH_BASE_DIR)/luajit2 + +INCLUDES += -I$(LUADIR)/src -I$(GSH_BASE_DIR) + +LUAGSL_SRC_FILES = gs-types.c lua-utils.c lua-gsl.c str.c fatal.c +LUAGSL_OBJ_FILES := $(LUAGSL_SRC_FILES:%.c=%.o) + +DEP_FILES := $(LUAGSL_SRC_FILES:%.c=.deps/%.P) + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +COMPILE = $(CC) $(CFLAGS) $(LUA_CFLAGS) $(DEFS) $(INCLUDES) + +TARGETS = libluagsl.a + +all: $(TARGETS) + +libluagsl.a: $(LUAGSL_OBJ_FILES) + @echo Archive $@ + @$(AR) $@ $? + @$(RANLIB) $@ + +include $(GSH_BASE_DIR)/makerules + +.PHONY: clean all + +clean: + $(HOST_RM) *.o *.lo *.la *.so *.dll $(TARGETS) + +-include $(DEP_FILES) diff --git a/lua-gsl/fatal.c b/lua-gsl/fatal.c new file mode 100644 index 00000000..da739527 --- /dev/null +++ b/lua-gsl/fatal.c @@ -0,0 +1,13 @@ + +#include <stdio.h> +#include <stdlib.h> + +#include "fatal.h" + +void +fatal_exception(const char* msg) +{ + fputs(msg, stderr); + fputs("\n", stderr); + abort(); +} diff --git a/lua-gsl/fatal.h b/lua-gsl/fatal.h new file mode 100644 index 00000000..27814349 --- /dev/null +++ b/lua-gsl/fatal.h @@ -0,0 +1,12 @@ +#ifndef MY_FATAL_H +#define MY_FATAL_H + +#include "defs.h" + +__BEGIN_DECLS + +extern void fatal_exception(const char* msg) __attribute__ ((noreturn)); + +__END_DECLS + +#endif diff --git a/gs-types.c b/lua-gsl/gs-types.c index e6167fca..3f6b68a6 100644 --- a/gs-types.c +++ b/lua-gsl/gs-types.c @@ -8,9 +8,8 @@ #include <gsl/gsl_errno.h> #include <math.h> -static int gs_type_string (lua_State *L); - #define GS_WINDOW_NAME_DEF "GSL.window" +#define GS_FOX_WINDOW_NAME_DEF "GSL.FOXwindow" #define GS_DRAW_SCALABLE_NAME_DEF NULL #define GS_DRAW_PATH_NAME_DEF "GSL.path" #define GS_DRAW_ELLIPSE_NAME_DEF "GSL.ellipse" @@ -29,6 +28,7 @@ static int gs_type_string (lua_State *L); #define MY_EXPAND_DER(NM,DESCR,BASE) {MYCAT2(GS,NM), MYCAT3(GS,NM,NAME_DEF), DESCR, MYCAT2(GS,BASE)} const struct gs_type gs_type_table[] = { + MY_EXPAND(FOX_WINDOW, "FOX graphical window"), MY_EXPAND(WINDOW, "graphical window"), MY_EXPAND(DRAW_SCALABLE, "graphical object"), MY_EXPAND_DER(DRAW_PATH, "geometric line", DRAW_SCALABLE), @@ -48,11 +48,6 @@ const struct gs_type gs_type_table[] = { #undef MY_EXPAND #undef MY_EXPAND_DER -const struct luaL_Reg gs_type_functions[] = { - {"type", gs_type_string}, - {NULL, NULL} -}; - const char * type_qualified_name (int typeid) { diff --git a/gs-types.h b/lua-gsl/gs-types.h index 94e961f6..5437696f 100644 --- a/gs-types.h +++ b/lua-gsl/gs-types.h @@ -11,6 +11,7 @@ __BEGIN_DECLS enum gs_type_e { GS_NO_TYPE = -1, GS_WINDOW = 0, + GS_FOX_WINDOW, GS_DRAW_SCALABLE, /* derived types are declared only after their base class */ GS_DRAW_PATH, GS_DRAW_ELLIPSE, @@ -48,7 +49,7 @@ extern const struct gs_type gs_type_table[]; #define GS_METATABLE(id) gs_type_table[(id)].mt_name -extern const struct luaL_Reg gs_type_functions[]; +extern int gs_type_string (lua_State *L); __END_DECLS diff --git a/lua-defs.h b/lua-gsl/lua-defs.h index a637aada..a637aada 100644 --- a/lua-defs.h +++ b/lua-gsl/lua-defs.h diff --git a/lua-gsl.c b/lua-gsl/lua-gsl.c index 98d979cc..004dba16 100644 --- a/lua-gsl.c +++ b/lua-gsl/lua-gsl.c @@ -27,18 +27,44 @@ #include "lua-gsl.h" #include "gs-types.h" #include "lua-utils.h" +#include "fatal.h" -#include "lua-graph.h" +struct gsl_shell_state* global_state; + +void +gsl_shell_open (struct gsl_shell_state *gs) +{ + gs->L = lua_open(); /* create state */ + + if (unlikely(gs->L == NULL)) + fatal_exception("cannot create state: not enough memory"); + + global_state = gs; +} + +void +gsl_shell_init (struct gsl_shell_state *gs) +{ + pthread_mutex_init (&gs->exec_mutex, NULL); + pthread_mutex_init (&gs->shutdown_mutex, NULL); + gs->is_shutting_down = 0; + gs->L = NULL; +} + +void +gsl_shell_free (struct gsl_shell_state *gs) +{ + pthread_mutex_destroy (&gs->exec_mutex); + pthread_mutex_destroy (&gs->shutdown_mutex); +} int luaopen_gsl (lua_State *L) { gsl_set_error_handler_off (); - luaL_register (L, "gslsh", gs_type_functions); - lua_pop (L, 1); - - register_graph (L); + lua_pushcfunction (L, gs_type_string); + lua_setfield (L, LUA_REGISTRYINDEX, "__gsl_type"); - return 1; + return 0; } diff --git a/lua-utils.c b/lua-gsl/lua-utils.c index 095cac89..095cac89 100644 --- a/lua-utils.c +++ b/lua-gsl/lua-utils.c diff --git a/lua-utils.h b/lua-gsl/lua-utils.h index 333b7a49..333b7a49 100644 --- a/lua-utils.h +++ b/lua-gsl/lua-utils.h diff --git a/agg-plot/strpp.h b/lua-gsl/strpp.h index bcc54a73..9bd9e67d 100644 --- a/agg-plot/strpp.h +++ b/lua-gsl/strpp.h @@ -11,11 +11,18 @@ public: ~str() { str_free(this); } - const str& operator = (const str& s) { + const str& operator= (const str& s) + { str_copy(this, &s); return *this; } + const str& operator= (const char* s) + { + str_copy_c(this, s); + return *this; + } + const char* cstr() const { return CSTR(this); } unsigned len() const { return this->length; } @@ -15,6 +15,12 @@ RANLIB= ranlib CC = gcc CXX = g++ +ifeq ($(HOST_SYS),Darwin) + LINK_EXE = $(CXX) $(LDFLAGS) +else + LINK_EXE = $(CC) $(LDFLAGS) +endif + ifeq ($(strip $(LUA_BUILD)), yes) PACKAGE_NAME = lua PACKAGE_VERSION = 5.1 @@ -39,6 +45,8 @@ ifeq ($(HOST_SYS),Windows) EXE_EXT = .exe else EXE_EXT = + DEFS += -pthread + LIBS += -pthread endif ifeq ($(strip $(DEBUG)), yes) diff --git a/makepackages b/makepackages index 7c9dc4b8..a21da6ec 100644 --- a/makepackages +++ b/makepackages @@ -9,13 +9,17 @@ ifeq ($(HOST_SYS),Windows) USER_LIBS_HOME = C:/fra/sviluppo + USER_INCLUDE = $(USER_LIBS_HOME)/include - INCLUDES += -I$(USER_LIBS_HOME)/include + INCLUDES += -I$(USER_INCLUDE) LIBS += -L$(USER_LIBS_HOME)/lib - AGG_INCLUDES = -I$(USER_LIBS_HOME)/include/agg2 + AGG_INCLUDES = -I$(USER_INCLUDE)/agg2 AGG_LIBS = -lagg -lgdi32 + FOX_INCLUDES = -I$(USER_INCLUDE)/fox-1.6 + FOX_LIBS = -lfox -lgdi32 + GSL_INCLUDES = GSL_LIBS = -lgsl -lgslcblas -lm @@ -30,6 +34,9 @@ else GSL_INCLUDES = GSL_LIBS = -lgsl -lgslcblas -lm + FOX_INCLUDES := $(shell pkg-config fox --cflags) + FOX_LIBS = $(shell pkg-config fox --libs) + FREETYPE_INCLUDES = -I/usr/include/freetype2 FREETYPE_LIBS = -lfreetype |