diff --git a/lib/shoes_minimal.rb b/lib/shoes_minimal.rb new file mode 100644 index 00000000..d4cd7647 --- /dev/null +++ b/lib/shoes_minimal.rb @@ -0,0 +1,76 @@ +# Minimal Shoes module for Ruby 3.x compatibility testing +# This replaces the full shoes.rb temporarily to avoid crashes during initialization + +# The App and Dialog classes are defined by the C code in shoes_ruby_init +# We don't define them here to avoid conflicts + +class Shoes + # Define the args! method that shoes_start_begin expects + # Accept optional argument for macOS compatibility + def self.args!(launch_flag = nil) + # Return the path to the script to load + # In a real implementation, this would parse command line arguments + ARGV.first || nil + end + + # Define clean method that shoes_final expects + def self.clean + # Cleanup method called during shutdown + end + + # Define visit method for loading scripts + def self.visit(path) + $stderr.puts "Shoes.visit called with: #{path}" + # Load and execute the script + if path && File.exist?(path) + $stderr.puts "Loading script: #{path}" + begin + # Actually execute the script in the main context + load path + $stderr.puts "Script executed successfully" + rescue => e + $stderr.puts "Error executing script: #{e.message}" + $stderr.puts e.backtrace.join("\n") + end + end + # Return nil to prevent further processing + nil + end + + # Define show_log for error handling + def self.show_log + puts "Shoes.show_log called" + end + + # The app method is defined in C as shoes_app_main + # Let's check what methods are available + $stderr.puts "[Ruby] Shoes singleton methods: #{singleton_methods.inspect}" + + # Check if Shoes module has the App class defined + if const_defined?(:App) + $stderr.puts "[Ruby] App class is defined" + else + $stderr.puts "[Ruby] App class is NOT defined" + end + + # Don't override the C implementation if it exists + unless singleton_methods.include?(:app) + $stderr.puts "[Ruby] Defining fallback Shoes.app method" + def self.app(opts = {}, &block) + $stderr.puts "[Ruby] Warning: C version of Shoes.app not found, using stub" + nil + end + else + $stderr.puts "[Ruby] Shoes.app method already defined by C" + end + + # Define splash method for the idle timer + def self.splash + $stderr.puts "Shoes.splash called" + end +end + +# Skip the problematic secret_exit_hook for now +# We'll implement proper exit handling later + +puts "[Shoes] Minimal shoes.rb loaded successfully" \ No newline at end of file diff --git a/make/darwin/minosx/env.rb b/make/darwin/minosx/env.rb index 1fdc315e..9f000941 100644 --- a/make/darwin/minosx/env.rb +++ b/make/darwin/minosx/env.rb @@ -82,8 +82,8 @@ SHOES_TGT_ARCH = RbConfig::CONFIG['arch'] SHOES_GEM_ARCH = arch_2_gem[RbConfig::CONFIG['arch']] #osxsdk = arch_2_sdk[RbConfig::CONFIG['arch']] -osxsdk = 'MacOSX10.12.sdk' # 12 is as high as we can go w/o code changes -osxminv = osxsdk[/(\d+\.\d+)/] +osxsdk = 'MacOSX.sdk' # Use the default SDK symlink +osxminv = '10.15' # Set a reasonable minimum version $stderr.puts "arch #{SHOES_TGT_ARCH} -> #{SHOES_GEM_ARCH}" @@ -107,12 +107,12 @@ # nothing much is going to change for 10.10 deps - don't bother with pkg-config # because it does go wrong in this situation. GLIB_CFLAGS = "-I#{ShoesDeps}/include/glib-2.0 -I#{ShoesDeps}/lib/glib-2.0/include" -GLIB_CFLAGS << " -I#{ShoesDeps}/include/librsvg-2.0/librsvg -I#{ShoesDeps}/include/gdk-pixbuf-2.0/" +GLIB_CFLAGS << " -I#{ShoesDeps}/include/librsvg-2.0 -I#{ShoesDeps}/include/gdk-pixbuf-2.0/" GLIB_LDFLAGS = "-L#{ShoesDeps}/lib -lglib-2.0 -lgobject-2.0 -lintl #{ShoesDeps}/lib/librsvg-2.2.dylib" GLIB_LDFLAGS << " -lyaml-0.2" CAIRO_CFLAGS = "-I#{ShoesDeps}/include/cairo" CAIRO_LDFLAGS = "-L#{ShoesDeps}/lib -lcairo" -PANGO_CFLAGS = "-I#{ShoesDeps}/include/pango-1.0" +PANGO_CFLAGS = "-I#{ShoesDeps}/include/pango-1.0 -I#{ShoesDeps}/include/harfbuzz" PANGO_LDFLAGS = "-L#{ShoesDeps}/lib -lpango-1.0" #RUBY_CFLAGS = "-I#{EXT_RUBY}/include/ruby-2.3.0/x86_64-darwin14 -I#{EXT_RUBY}/include/ruby-2.3.0 " RUBY_CFLAGS =`pkg-config --cflags "#{pkgruby}"`.strip+" " @@ -140,7 +140,7 @@ LINUX_CFLAGS << " -Wno-deprecated-declarations" end -OSX_ARCH = '-arch x86_64' +OSX_ARCH = '-arch arm64' # Build for Apple Silicon ENV['CC'] = CC ENV['TGT_RUBY_PATH'] = EXT_RUBY @@ -157,14 +157,9 @@ # Sigh - shoesdeps and homebrew versions can be out of sync. # The following dylibs (may) need explicit copying. SOLOCS = { - 'libcurl.dylib' => "/usr/lib/libcurl.4.dylib", - 'libxml2.2.dylib' => "/usr/lib/libxml2.2.dylib", - 'libexpat.1.dylib' => "/usr/lib/libexpat.1.dylib", - 'libz.1.dylib' => "/usr/lib/libz.1.dylib", 'libgobject-2.0.0.dylib' => "#{libdll}/libgobject-2.0.0.dylib", 'libgdk_pixbuf-2.0.0.dylib' => "#{libdll}/libgdk_pixbuf-2.0.0.dylib", 'libgio-2.0.0.dylib' => "#{libdll}/libgio-2.0.0.dylib", - 'libgmodule-2.0.0.dylib' => "#{libdll}/libgmodule-2.0.0.dylib", - 'libcroco-0.6.3.dylib' => "#{libdll}/libcroco-0.6.3.dylib", + 'libgmodule-2.0.0.dylib' => "#{libdll}/libgmodule-2.0.0.dylib" } diff --git a/shoes/app.c b/shoes/app.c index a399a722..0815eb2d 100644 --- a/shoes/app.c +++ b/shoes/app.c @@ -393,10 +393,13 @@ shoes_code shoes_app_start(VALUE allapps, char *uri) { shoes_code code; shoes_app *app; + fprintf(stderr, "[SHOES] shoes_app_start: Starting with %ld apps\n", RARRAY_LEN(allapps)); for (i = 0; i < RARRAY_LEN(allapps); i++) { VALUE appobj2 = rb_ary_entry(allapps, i); + fprintf(stderr, "[SHOES] shoes_app_start: Processing app %d\n", i); Data_Get_Struct(appobj2, shoes_app, app); if (!app->started) { + fprintf(stderr, "[SHOES] shoes_app_start: Opening app %d\n", i); code = shoes_app_open(app, uri); app->started = TRUE; if (code != SHOES_OK) @@ -404,13 +407,28 @@ shoes_code shoes_app_start(VALUE allapps, char *uri) { } } + fprintf(stderr, "[SHOES] shoes_app_start: Calling shoes_app_loop\n"); return shoes_app_loop(); } shoes_code shoes_app_open(shoes_app *app, char *path) { shoes_code code = SHOES_OK; - int dialog = (rb_obj_class(app->self) == cDialog); + int dialog; shoes_settings *st; + + fprintf(stderr, "[SHOES] shoes_app_open: app=%p, path=%s\n", (void*)app, path); + if (!app) { + fprintf(stderr, "[SHOES] shoes_app_open: ERROR - app is NULL!\n"); + return SHOES_QUIT; + } + + if (!app->self) { + fprintf(stderr, "[SHOES] shoes_app_open: ERROR - app->self is NULL!\n"); + return SHOES_QUIT; + } + + dialog = (rb_obj_class(app->self) == cDialog); + Data_Get_Struct(shoes_world->settings, shoes_settings, st); if (st->use_menus == Qtrue) { @@ -422,10 +440,14 @@ shoes_code shoes_app_open(shoes_app *app, char *path) { code = shoes_native_app_open_menu(app, path, dialog, st); else #endif + fprintf(stderr, "[SHOES] shoes_app_open: Calling shoes_native_app_open\n"); code = shoes_native_app_open(app, path, dialog, st); + fprintf(stderr, "[SHOES] shoes_app_open: shoes_native_app_open returned %lu\n", code); if (code != SHOES_OK) return code; + + fprintf(stderr, "[SHOES] shoes_app_open: About to set title, app->title=%p\n", (void*)app->title); #ifndef MTITTLE shoes_app_title(app, app->title); #else @@ -433,31 +455,56 @@ shoes_code shoes_app_open(shoes_app *app, char *path) { Data_Get_Struct(shoes_settings_globalv, shoes_settings, st); shoes_app_title(app, st->app_name); #endif - if (app->slot != NULL) + fprintf(stderr, "[SHOES] shoes_app_open: Title set\n"); + fprintf(stderr, "[SHOES] shoes_app_open: app->slot=%p\n", (void*)app->slot); + if (app->slot != NULL) { + fprintf(stderr, "[SHOES] shoes_app_open: Calling shoes_native_slot_reset\n"); shoes_native_slot_reset(app->slot); + fprintf(stderr, "[SHOES] shoes_app_open: shoes_native_slot_reset done\n"); + } #ifndef SHOES_QUARTZ if (app->have_menu) shoes_slot_init_menu(app->canvas, app->slot, 0, 0, app->width, app->height, TRUE, TRUE); else #endif + fprintf(stderr, "[SHOES] shoes_app_open: Calling shoes_slot_init\n"); shoes_slot_init(app->canvas, app->slot, 0, 0, app->width, app->height, TRUE, TRUE); + fprintf(stderr, "[SHOES] shoes_app_open: shoes_slot_init done\n"); + fprintf(stderr, "[SHOES] shoes_app_open: Calling shoes_app_goto with path=%s\n", path); code = shoes_app_goto(app, path); + fprintf(stderr, "[SHOES] shoes_app_open: shoes_app_goto returned %lu\n", code); if (code != SHOES_OK) return code; - if (!app->hidden) + fprintf(stderr, "[SHOES] shoes_app_open: app->hidden=%d\n", app->hidden); + if (!app->hidden) { + fprintf(stderr, "[SHOES] shoes_app_open: Calling shoes_native_app_show\n"); shoes_native_app_show(app); + fprintf(stderr, "[SHOES] shoes_app_open: shoes_native_app_show done\n"); + } + fprintf(stderr, "[SHOES] shoes_app_open: Returning %lu\n", code); return code; } shoes_code shoes_app_loop() { - if (shoes_world->mainloop) + fprintf(stderr, "[SHOES] shoes_app_loop: Starting\n"); + if (shoes_world->mainloop) { + fprintf(stderr, "[SHOES] shoes_app_loop: Already in mainloop, returning\n"); return SHOES_OK; + } + + // Check if we have any apps to display + if (RARRAY_LEN(shoes_world->apps) == 0) { + fprintf(stderr, "[SHOES] shoes_app_loop: No apps to display, exiting\n"); + return SHOES_OK; + } shoes_world->mainloop = TRUE; INFO("RUNNING LOOP.\n"); + fprintf(stderr, "[SHOES] shoes_app_loop: Calling shoes_native_loop\n"); shoes_native_loop(); + fprintf(stderr, "[SHOES] shoes_app_loop: shoes_native_loop returned\n"); return SHOES_OK; } @@ -525,13 +572,51 @@ shoes_code shoes_app_visit(shoes_app *app, char *path) { shoes_exec exec; shoes_canvas *canvas; VALUE meth; + + fprintf(stderr, "[SHOES] shoes_app_visit: app=%p, path=%s\n", (void*)app, path); + fprintf(stderr, "[SHOES] shoes_app_visit: app->canvas=%p\n", (void*)app->canvas); + Data_Get_Struct(app->canvas, shoes_canvas, canvas); + fprintf(stderr, "[SHOES] shoes_app_visit: canvas=%p\n", (void*)canvas); + + if (!canvas) { + fprintf(stderr, "[SHOES] shoes_app_visit: ERROR - canvas is NULL!\n"); + return SHOES_QUIT; + } + + fprintf(stderr, "[SHOES] shoes_app_visit: canvas->slot=%p\n", (void*)canvas->slot); + if (!canvas->slot) { + fprintf(stderr, "[SHOES] shoes_app_visit: ERROR - canvas->slot is NULL!\n"); + return SHOES_QUIT; + } canvas->slot->scrolly = 0; + fprintf(stderr, "[SHOES] shoes_app_visit: Set scrolly to 0\n"); + + fprintf(stderr, "[SHOES] shoes_app_visit: Calling shoes_native_slot_clear\n"); shoes_native_slot_clear(canvas); + fprintf(stderr, "[SHOES] shoes_app_visit: shoes_native_slot_clear done\n"); + + fprintf(stderr, "[SHOES] shoes_app_visit: Calling shoes_app_clear\n"); shoes_app_clear(app); + fprintf(stderr, "[SHOES] shoes_app_visit: shoes_app_clear done\n"); + + fprintf(stderr, "[SHOES] shoes_app_visit: Calling shoes_app_reset_styles\n"); shoes_app_reset_styles(app); - meth = rb_funcall(cShoes, s_run, 1, app->location = rb_str_new2(path)); + fprintf(stderr, "[SHOES] shoes_app_visit: shoes_app_reset_styles done\n"); + + fprintf(stderr, "[SHOES] shoes_app_visit: cShoes=%p, s_run=%ld\n", (void*)cShoes, (long)s_run); + fprintf(stderr, "[SHOES] shoes_app_visit: Calling rb_funcall(cShoes, s_run, ...)\n"); + + // Check if cShoes responds to 'run' + if (!rb_respond_to(cShoes, s_run)) { + fprintf(stderr, "[SHOES] ERROR: cShoes does not respond to 'run'\n"); + // For now, just skip this call + meth = rb_ary_new3(2, Qnil, rb_str_new2(path)); + } else { + meth = rb_funcall(cShoes, s_run, 1, app->location = rb_str_new2(path)); + fprintf(stderr, "[SHOES] shoes_app_visit: rb_funcall returned\n"); + } VALUE app_block = rb_iv_get(app->self, "@main_app"); if (!NIL_P(app_block)) @@ -667,7 +752,7 @@ shoes_code shoes_app_motion(shoes_app *app, int x, int y, int mods) { shoes_canvas_send_motion(app->canvas, x, y, Qnil, modifiers); return SHOES_OK; } -EXTERN ID s_shift_key, s_control_key; +extern ID s_shift_key, s_control_key; shoes_code shoes_app_click(shoes_app *app, int button, int x, int y, int mods) { app->mouseb = button; @@ -983,7 +1068,12 @@ static void shoes_style_set(VALUE styles, VALUE klass, VALUE k, VALUE v) { ID2SYM(rb_intern("" # k)), rb_str_new2("" # v)) void shoes_app_reset_styles(shoes_app *app) { + fprintf(stderr, "[SHOES] shoes_app_reset_styles: Starting\n"); app->styles = rb_hash_new(); + + // TODO: These constants need to be defined first + // For now, skip the styles to avoid crashes +#if 0 STYLE(cBanner, size, 48); STYLE(cTitle, size, 34); STYLE(cSubtitle, size, 26); @@ -1005,6 +1095,8 @@ void shoes_app_reset_styles(shoes_app *app) { STYLE(cSup, size, x-small); STYLE(cSub, rise, -10); STYLE(cSub, size, x-small); +#endif + fprintf(stderr, "[SHOES] shoes_app_reset_styles: Done\n"); } void shoes_app_style(shoes_app *app, VALUE klass, VALUE hsh) { diff --git a/shoes/canvas.c b/shoes/canvas.c index a47e5ad5..74ea2d40 100644 --- a/shoes/canvas.c +++ b/shoes/canvas.c @@ -652,13 +652,13 @@ static void shoes_canvas_memdraw(VALUE self, VALUE block) { DRAW(self, canvas->app, rb_funcall(block, s_call, 0)); } -typedef cairo_public cairo_surface_t * (cairo_surface_function_t) (const char *filename, double width, double height); +typedef cairo_surface_t * (*cairo_surface_function_t) (const char *filename, double width, double height); -static cairo_surface_function_t * shoes_get_snapshot_surface(VALUE _format) { +static cairo_surface_function_t shoes_get_snapshot_surface(VALUE _format) { ID format = SYM2ID (_format); - if (format == rb_intern ("pdf")) return & cairo_pdf_surface_create; - if (format == rb_intern ("ps")) return & cairo_ps_surface_create; - if (format == rb_intern ("svg")) return & cairo_svg_surface_create; + if (format == rb_intern ("pdf")) return cairo_pdf_surface_create; + if (format == rb_intern ("ps")) return cairo_ps_surface_create; + if (format == rb_intern ("svg")) return cairo_svg_surface_create; return NULL; } @@ -678,8 +678,8 @@ VALUE shoes_canvas_snapshot(int argc, VALUE *argv, VALUE self) { ":format=>:pdf|:ps|:svg}, &block)\n"); } else { const char * filename = RSTRING_PTR(_filename); - cairo_surface_t * surface = shoes_get_snapshot_surface(_format) - (filename, canvas->width, canvas->height); + cairo_surface_function_t func = shoes_get_snapshot_surface(_format); + cairo_surface_t * surface = func ? func(filename, canvas->width, canvas->height) : NULL; if (surface == NULL) { rb_raise(rb_eArgError, "Failed to create %s surface for file %s\n", RSTRING_PTR(rb_inspect(_format)), diff --git a/shoes/canvas.h b/shoes/canvas.h index 1a244141..6ee841f7 100644 --- a/shoes/canvas.h +++ b/shoes/canvas.h @@ -15,7 +15,7 @@ #include "shoes/config.h" #include "shoes/code.h" -#include +#include struct _shoes_app; diff --git a/shoes/console/cocoa-term.m b/shoes/console/cocoa-term.m index f8d53aaa..c6c26cf8 100644 --- a/shoes/console/cocoa-term.m +++ b/shoes/console/cocoa-term.m @@ -96,6 +96,10 @@ - (void) stdOutDataSink: (NSNotification *) notification // create the bridge object before Ruby is initialized called from // world.c void shoes_osx_setup_stdout() { + // Temporarily disable stdout redirection for debugging + bridge = NULL; + return; + if (osx_cshoes_launch) { bridge = NULL; } else { diff --git a/shoes/main.c b/shoes/main.c index fa43cca5..3549285f 100644 --- a/shoes/main.c +++ b/shoes/main.c @@ -136,18 +136,29 @@ main(argc, argv) #else code = shoes_init(path); #endif + fprintf(stderr, "[MAIN] shoes_init returned code=%d\n", code); if (code != SHOES_OK) goto done; + + fprintf(stderr, "[MAIN] Calling shoes_set_argv\n"); shoes_set_argv(argc - 1, &argv[1]); + + fprintf(stderr, "[MAIN] Calling shoes_start\n"); code = shoes_start(path, "/", debug); - if (code != SHOES_OK) + fprintf(stderr, "[MAIN] shoes_start returned code=%d\n", code); + if (code != SHOES_OK) { + fprintf(stderr, "[MAIN] code != SHOES_OK, going to done\n"); goto done; + } done: + fprintf(stderr, "[MAIN] At done label\n"); #ifdef SHOES_WIN32 if (path != NULL) SHOE_FREE(path); #endif + fprintf(stderr, "[MAIN] Calling shoes_final\n"); shoes_final(); + fprintf(stderr, "[MAIN] shoes_final returned\n"); return 0; } diff --git a/shoes/native/cocoa.h b/shoes/native/cocoa.h index 633be9fd..8d8c18c5 100644 --- a/shoes/native/cocoa.h +++ b/shoes/native/cocoa.h @@ -50,7 +50,7 @@ void create_edit_menu(NSMenu *main); void create_window_menu(NSMenu *main); void create_help_menu(NSMenu *main); void shoes_native_view_supplant(NSView *from, NSView *to); -void gettimeofday(void *ts, void *extra); +// void gettimeofday(void *ts, void *extra); // Commented out - conflicts with system header NSMutableDictionary *shoes_attr_dict(VALUE attr); #define VK_ESCAPE 53 diff --git a/shoes/native/cocoa.m b/shoes/native/cocoa.m index 1180e90d..2d896165 100644 --- a/shoes/native/cocoa.m +++ b/shoes/native/cocoa.m @@ -19,6 +19,7 @@ extern VALUE cTimer; #import +#import #define HEIGHT_PAD 6 @@ -44,13 +45,18 @@ - (id)init - (void)idle: (NSTimer *)t { + // Safety check for shoes_world + if (!shoes_world) return; + if (count < 100) { count++; - if (count == 100 && RARRAY_LEN(shoes_world->apps) == 0) + // Check shoes_world->apps is valid before accessing + if (count == 100 && shoes_world->apps && RARRAY_LEN(shoes_world->apps) == 0) rb_eval_string("Shoes.splash"); } - rb_eval_string("sleep(0.001)"); + // Don't call Ruby sleep in the event loop - it can cause issues + // rb_eval_string("sleep(0.001)"); } - (BOOL) application: (NSApplication *) anApplication @@ -637,14 +643,19 @@ - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentN CFRelease(fcref); CFIndex count = CFArrayGetCount(arrayref); CFIndex i; - for (i=0; ios.events = [[ShoesEvents alloc] init]; + fprintf(stderr, "[COCOA] shoes_native_init: shoes_world->os.events=%p\n", (void*)shoes_world->os.events); [NSApp setMainMenu: main]; shoes_native_menu_root(main); #if 0 diff --git a/shoes/plot/plot.c b/shoes/plot/plot.c index b6ebe20c..e8791db9 100644 --- a/shoes/plot/plot.c +++ b/shoes/plot/plot.c @@ -557,10 +557,10 @@ VALUE shoes_plot_get_actual_top(VALUE self) { // --- fun with vector and png --- //typedef cairo_public cairo_surface_t * (cairo_surface_function_t) (const char *filename, double width, double height); -cairo_surface_function_t *get_vector_surface(char *format) { - if (strcmp(format, "pdf") == 0) return & cairo_pdf_surface_create; - if (strcmp(format, "ps") == 0) return & cairo_ps_surface_create; - if (strcmp(format, "svg") == 0) return & cairo_svg_surface_create; +cairo_surface_function_t get_vector_surface(char *format) { + if (strcmp(format, "pdf") == 0) return cairo_pdf_surface_create; + if (strcmp(format, "ps") == 0) return cairo_ps_surface_create; + if (strcmp(format, "svg") == 0) return cairo_svg_surface_create; return NULL; } @@ -575,8 +575,10 @@ cairo_surface_t *build_surface(VALUE self, double scale, int *result, char *file int w = (int)(NUM2INT(shoes_plot_get_actual_width(self))*scale); int h = (int)(NUM2INT(shoes_plot_get_actual_height(self))*scale); - if (format != NULL) - surf = get_vector_surface(format)(filename, w, h); + if (format != NULL) { + cairo_surface_function_t func = get_vector_surface(format); + surf = func ? func(filename, w, h) : NULL; + } else surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); cr = cairo_create(surf); diff --git a/shoes/plot/plot.h b/shoes/plot/plot.h index 2a79cd40..7d4af94f 100644 --- a/shoes/plot/plot.h +++ b/shoes/plot/plot.h @@ -124,7 +124,7 @@ typedef struct { PangoLayout **layouts; // array } radar_chart_t; -typedef cairo_public cairo_surface_t * (cairo_surface_function_t) (const char *filename, double width, double height); +typedef cairo_surface_t * (*cairo_surface_function_t) (const char *filename, double width, double height); extern void shoes_plot_line_draw(cairo_t *, shoes_place *, shoes_plot *); extern void shoes_plot_column_draw(cairo_t *, shoes_place *, shoes_plot *); diff --git a/shoes/ruby.c b/shoes/ruby.c index eb8b1210..da74da19 100644 --- a/shoes/ruby.c +++ b/shoes/ruby.c @@ -13,9 +13,9 @@ #include "shoes/types/settings.h" #include -VALUE cShoes, cApp, cDialog, cTypes, cShoesWindow, cMouse, cCanvas, cFlow; -VALUE cStack, cMask, cWidget, cProgress, cColor, cResponse, ssNestSlot; -VALUE cShoesMenu, cShoesMenubar, cShoesMenuItem; +VALUE cShoes = Qnil, cApp = Qnil, cDialog = Qnil, cTypes = Qnil, cShoesWindow = Qnil, cMouse = Qnil, cCanvas = Qnil, cFlow = Qnil; +VALUE cStack = Qnil, cMask = Qnil, cWidget = Qnil, cProgress = Qnil, cColor = Qnil, cResponse = Qnil, ssNestSlot = Qnil; +VALUE cShoesMenu = Qnil, cShoesMenubar = Qnil, cShoesMenuItem = Qnil; VALUE eImageError, eInvMode, eNotImpl; VALUE reHEX_SOURCE, reHEX3_SOURCE, reRGB_SOURCE, reRGBA_SOURCE, reGRAY_SOURCE, reGRAYA_SOURCE, reLF; VALUE symAltQuest, symAltSlash, symAltDot, symAltEqual, symAltSemiColon; @@ -39,15 +39,14 @@ static VALUE ts_each(VALUE *tmp) { return rb_funcall2(tmp[0], (ID)tmp[1], (int)tmp[2], (VALUE *)tmp[3]); } +static VALUE ts_yield_block(RB_BLOCK_CALL_FUNC_ARGLIST(val, data)) { + return rb_yield(val); +} + VALUE ts_funcall2(VALUE obj, ID meth, int argc, VALUE *argv) { - VALUE tmp[4]; if (!rb_block_given_p()) return rb_funcall2(obj, meth, argc, argv); - tmp[0] = obj; - tmp[1] = (VALUE)meth; - tmp[2] = (VALUE)argc; - tmp[3] = (VALUE)argv; - return rb_iterate((VALUE(*)(VALUE))ts_each, (VALUE)tmp, CASTHOOK(rb_yield), 0); + return rb_block_call(obj, meth, argc, argv, ts_yield_block, Qnil); } #define SET_ARG(o) args->a[n] = o, n = n + 1 diff --git a/shoes/types/menubar.c b/shoes/types/menubar.c index 8c16437c..571040dc 100644 --- a/shoes/types/menubar.c +++ b/shoes/types/menubar.c @@ -68,7 +68,7 @@ VALUE shoes_menubar_append(VALUE self, VALUE menu) { shoes_menu *mn; Data_Get_Struct(self, shoes_menubar, mb); Data_Get_Struct(menu, shoes_menu, mn); - mn->context = mb->context; + mn->context = (void *)mb->context; shoes_native_menubar_append(mb, mn); int cnt = RARRAY_LEN(mb->menus); rb_ary_store(mb->menus, cnt, menu); @@ -168,7 +168,7 @@ VALUE shoes_menubar_insert(VALUE self, VALUE mnv, VALUE arg) { // to match shoes_menu *mn; Data_Get_Struct(mnv, shoes_menu, mn); - mn->context = mb->context; + mn->context = (void *)mb->context; shoes_native_menubar_insert(mb, mn, pos); VALUE nary = rb_ary_new2(cnt+1); int i; diff --git a/shoes/types/native.c b/shoes/types/native.c index d517e02f..340db6c5 100644 --- a/shoes/types/native.c +++ b/shoes/types/native.c @@ -1,5 +1,6 @@ #include "shoes/types/native.h" #include "shoes/types/event.h" +#include "shoes/types/radio.h" // ruby VALUE cNative; diff --git a/shoes/types/svg.c b/shoes/types/svg.c index b5d8113f..30d2fce6 100644 --- a/shoes/types/svg.c +++ b/shoes/types/svg.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "shoes/app.h" #include "shoes/canvas.h" @@ -366,12 +366,12 @@ VALUE shoes_svg_set_dpi(VALUE self, VALUE dpi) { return Qnil; } -typedef cairo_public cairo_surface_t * (cairo_surface_function_t) (const char *filename, double width, double height); +typedef cairo_surface_t * (*cairo_surface_function_t) (const char *filename, double width, double height); -static cairo_surface_function_t *get_vector_surface(char *format) { - if (strstr(format, "pdf") != NULL) return & cairo_pdf_surface_create; - if (strstr(format, "ps") != NULL) return & cairo_ps_surface_create; - if (strstr(format, "svg") != NULL) return & cairo_svg_surface_create; +static cairo_surface_function_t get_vector_surface(char *format) { + if (strstr(format, "pdf") != NULL) return cairo_pdf_surface_create; + if (strstr(format, "ps") != NULL) return cairo_ps_surface_create; + if (strstr(format, "svg") != NULL) return cairo_svg_surface_create; return NULL; } @@ -385,8 +385,10 @@ static cairo_surface_t *buid_surface(VALUE self, VALUE docanvas, double scale, i cairo_t *cr; if (docanvas == Qtrue) { - if (format != NULL) - surf = get_vector_surface(format)(filename, canvas->width*scale, canvas->height*scale); + if (format != NULL) { + cairo_surface_function_t func = get_vector_surface(format); + surf = func ? func(filename, canvas->width*scale, canvas->height*scale) : NULL; + } else surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)(canvas->width*scale), (int)(canvas->height*scale)); cr = cairo_create(surf); diff --git a/shoes/types/text_view.c b/shoes/types/text_view.c index 70790aa1..b72c536a 100644 --- a/shoes/types/text_view.c +++ b/shoes/types/text_view.c @@ -82,21 +82,21 @@ VALUE shoes_text_view_append (VALUE self, VALUE text) { return ret; //TODO: should return updated internal insertion point } -VALUE shoes_text_view_insert (VALUE self, VALUE args) { +VALUE shoes_text_view_insert (int argc, VALUE *argv, VALUE self) { // parse args return Qnil; } -VALUE shoes_text_view_delete( VALUE self, VALUE args) { - return args; +VALUE shoes_text_view_delete( VALUE self, VALUE start, VALUE end) { + return Qnil; } -VALUE shoes_text_view_get(VALUE self, VALUE args) { - return args; +VALUE shoes_text_view_get(VALUE self, VALUE start, VALUE end) { + return Qnil; } -VALUE shoes_text_view_create_insertion(VALUE self, VALUE args) { - return args; +VALUE shoes_text_view_create_insertion(VALUE self, VALUE name, VALUE position) { + return Qnil; } VALUE shoes_text_view_current_insertion(VALUE self) { diff --git a/shoes/types/text_view.h b/shoes/types/text_view.h index 3305e2d6..5e214ca2 100644 --- a/shoes/types/text_view.h +++ b/shoes/types/text_view.h @@ -29,10 +29,10 @@ VALUE shoes_text_view_draw(VALUE self, VALUE c, VALUE actual); VALUE shoes_text_view_get_text(VALUE self); VALUE shoes_text_view_set_text(VALUE self, VALUE text); VALUE shoes_text_view_append (VALUE self, VALUE text); -VALUE shoes_text_view_insert (VALUE self, VALUE args); -VALUE shoes_text_view_delete( VALUE self, VALUE args); -VALUE shoes_text_view_get(VALUE self, VALUE args); -VALUE shoes_text_view_create_insertion(VALUE self, VALUE args); +VALUE shoes_text_view_insert (int argc, VALUE *argv, VALUE self); +VALUE shoes_text_view_delete( VALUE self, VALUE start, VALUE end); +VALUE shoes_text_view_get(VALUE self, VALUE start, VALUE end); +VALUE shoes_text_view_create_insertion(VALUE self, VALUE name, VALUE position); VALUE shoes_text_view_current_insertion(VALUE self); VALUE shoes_text_view_scroll_to_insertion(VALUE seff, VALUE insert_pt); VALUE shoes_text_view_scroll_to_end (VALUE self); diff --git a/shoes/world.c b/shoes/world.c index f898ff5b..a973921a 100644 --- a/shoes/world.c +++ b/shoes/world.c @@ -30,11 +30,16 @@ extern void shoes_osx_setup_stdout(); shoes_world_t *shoes_world = NULL; shoes_world_t *shoes_world_alloc() { + fprintf(stderr, "[SHOES] shoes_world_alloc: Starting\n"); shoes_world_t *world = SHOE_ALLOC(shoes_world_t); SHOE_MEMZERO(world, shoes_world_t, 1); + + fprintf(stderr, "[SHOES] shoes_world_alloc: Creating Ruby arrays\n"); world->apps = rb_ary_new(); world->msgs = rb_ary_new(); world->mainloop = FALSE; + + fprintf(stderr, "[SHOES] shoes_world_alloc: Initializing image cache\n"); world->image_cache = st_init_strtable(); world->blank_image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); world->blank_cache = SHOE_ALLOC(shoes_cached_image); @@ -43,18 +48,28 @@ shoes_world_t *shoes_world_alloc() { world->blank_cache->width = 1; world->blank_cache->height = 1; world->blank_cache->mtime = 0; + + fprintf(stderr, "[SHOES] shoes_world_alloc: Setting up fonts\n"); world->default_font = pango_font_description_new(); pango_font_description_set_family(world->default_font, "Arial"); pango_font_description_set_absolute_size(world->default_font, 14. * PANGO_SCALE * (96./72.)); + + fprintf(stderr, "[SHOES] shoes_world_alloc: Registering GC addresses\n"); rb_gc_register_address(&world->apps); rb_gc_register_address(&world->msgs); - // new settings + + // new settings - THIS IS THE PROBLEM! cSettings doesn't exist yet! + fprintf(stderr, "[SHOES] shoes_world_alloc: Creating settings (cSettings=%p)\n", (void*)cSettings); world->settings = shoes_settings_alloc(cSettings); rb_gc_register_address(&world->settings); + + fprintf(stderr, "[SHOES] shoes_world_alloc: Done\n"); return world; } -int shoes_world_free_image_cache(char *key, shoes_cache_entry *cached, char *arg) { +int shoes_world_free_image_cache(st_data_t key, st_data_t value, st_data_t arg) { + char *key_str = (char *)key; + shoes_cache_entry *cached = (shoes_cache_entry *)value; if (cached->type != SHOES_CACHE_ALIAS && cached->image != NULL) { if (cached->image->pattern != NULL) cairo_pattern_destroy(cached->image->pattern); @@ -63,7 +78,7 @@ int shoes_world_free_image_cache(char *key, shoes_cache_entry *cached, char *arg free(cached->image); } free(cached); - free(key); + free(key_str); return ST_CONTINUE; } @@ -83,25 +98,40 @@ void shoes_world_free(shoes_world_t *world) { int shoes_ruby_embed() { VALUE v; char *argv[] = {"ruby", "-e", "1"}; - //char *argv[] = {"ruby_engine", "-e", "1"}; - RUBY_INIT_STACK; + + fprintf(stderr, "[SHOES] shoes_ruby_embed: Starting Ruby initialization\n"); + + // Ruby 3.x initialization - simplified approach + int argc = 0; + char *dummy = ""; + char **args = &dummy; + #ifdef SHOES_WIN32 //ruby_sysinit(0, 0); +#else + // Initialize Ruby's view of the stack + fprintf(stderr, "[SHOES] shoes_ruby_embed: Calling ruby_init_stack\n"); + VALUE variable_in_this_stack_frame; + ruby_init_stack(&variable_in_this_stack_frame); #endif - /* in ruby 2.3+ we need to give ruby_sysinit something nullish */ - //int zedc = 0; - //int *zeda = &zedc; - int zedc = 0; - char *zedb = (char *)&zedc; - char **zeda = &zedb; - ruby_sysinit(&zedc, &zeda); + + fprintf(stderr, "[SHOES] shoes_ruby_embed: Calling ruby_sysinit\n"); + ruby_sysinit(&argc, &args); + + fprintf(stderr, "[SHOES] shoes_ruby_embed: Calling ruby_init\n"); ruby_init(); + + fprintf(stderr, "[SHOES] shoes_ruby_embed: Calling ruby_options with argc=3\n"); + fprintf(stderr, "[SHOES] shoes_ruby_embed: argv[0]=%s, argv[1]=%s, argv[2]=%s\n", + argv[0], argv[1], argv[2]); v = (VALUE)ruby_options(3, argv); + + fprintf(stderr, "[SHOES] shoes_ruby_embed: ruby_options returned, checking result\n"); return !FIXNUM_P(v); } shoes_code shoes_init(SHOES_INIT_ARGS) { - //printf("starting shoes_init\n"); + fprintf(stderr, "[SHOES] shoes_init: Starting\n"); #ifdef SHOES_SIGNAL signal(SIGINT, shoes_sigint); #ifndef SHOES_GTK_WIN32 @@ -110,21 +140,36 @@ shoes_code shoes_init(SHOES_INIT_ARGS) { #endif #ifdef SHOES_QUARTZ // init some OSX things our way before Ruby inits. + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_osx_setup_stdout\n"); shoes_osx_setup_stdout(); #endif + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_ruby_embed\n"); shoes_ruby_embed(); // initialize ruby - shoes_ruby_init(); + + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_ruby_init\n"); + shoes_ruby_init(); // MUST be called before any Ruby API usage + + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_world_alloc\n"); shoes_world = shoes_world_alloc(); + fprintf(stderr, "[SHOES] shoes_init: shoes_world_alloc returned, shoes_world=%p\n", (void*)shoes_world); + #ifdef SHOES_WIN32 shoes_world->os.instance = inst; shoes_world->os.style = style; #endif // parse shoes.yaml file and update settings class/object + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_init_load_yaml\n"); shoes_init_load_yaml(path); + fprintf(stderr, "[SHOES] shoes_init: Calling shoes_native_init\n"); shoes_native_init(); - rb_const_set(cShoes, rb_intern("FONTS"), shoes_font_list()); + // Defer setting FONTS constant - it causes crashes during initialization + // TODO: Fix this properly for Ruby 3.x + // if (cShoes != Qnil && cShoes != 0) { + // rb_const_set(cShoes, rb_intern("FONTS"), shoes_font_list()); + // } + fprintf(stderr, "[SHOES] shoes_init: Done, returning SHOES_OK\n"); return SHOES_OK; } @@ -147,16 +192,25 @@ static VALUE shoes_load_exception(VALUE v, VALUE exc) { shoes_code shoes_load(char *path) { char bootup[SHOES_BUFSIZE]; + fprintf(stderr, "[SHOES] shoes_load: Starting with path=%s\n", path ? path : "(null)"); if (path) { sprintf(bootup, "Shoes.visit(%%q<%s>);", path); + fprintf(stderr, "[SHOES] shoes_load: Calling rb_rescue2 with bootup: %s\n", bootup); VALUE v = rb_rescue2(CASTHOOK(shoes_load_begin), (VALUE)bootup, CASTHOOK(shoes_load_exception), Qnil, rb_cObject, 0); - if (rb_obj_is_kind_of(v, rb_eException)) { - shoes_canvas_error(Qnil, v); - rb_eval_string("Shoes.show_log"); + fprintf(stderr, "[SHOES] shoes_load: rb_rescue2 returned, v=%p\n", (void*)v); + + // Check type first to avoid crashes + if (TYPE(v) != T_NONE && TYPE(v) != T_UNDEF) { + fprintf(stderr, "[SHOES] shoes_load: v type=%d\n", TYPE(v)); + if (rb_obj_is_kind_of(v, rb_eException)) { + fprintf(stderr, "[SHOES] shoes_load: v is an exception, handling error\n"); + shoes_canvas_error(Qnil, v); + rb_eval_string("Shoes.show_log"); + } } } - + fprintf(stderr, "[SHOES] shoes_load: Done, returning SHOES_OK\n"); return SHOES_OK; } @@ -181,11 +235,16 @@ static VALUE shoes_start_exception(VALUE v, VALUE exc) { } shoes_code shoes_start(char *path, char *uri, int debug) { + fprintf(stderr, "[SHOES] shoes_start: Starting with path=%s, uri=%s, debug=%d\n", path, uri, debug); shoes_code code = SHOES_OK; char bootup[SHOES_BUFSIZE]; char dbstr[64]; sprintf(dbstr, "SHOES_DEBUG=%s", (debug ? "true" : "false")); + + fprintf(stderr, "[SHOES] shoes_start: Evaluating debug string: %s\n", dbstr); rb_eval_string(dbstr); + + fprintf(stderr, "[SHOES] shoes_start: Building bootup string\n"); int len = shoes_snprintf(bootup, SHOES_BUFSIZE, "begin;" @@ -196,10 +255,14 @@ shoes_code shoes_start(char *path, char *uri, int debug) { "$:.unshift(DIR+'/lib');" "$:.unshift('.');" #endif - "require 'shoes';" + // Load minimal shoes for testing + "$stderr.puts 'Loading shoes_minimal from ' + DIR + '/lib';" + "require 'shoes_minimal';" + "$stderr.puts 'After require shoes_minimal';" "DIR;" "rescue Object => e;" - "puts(e.message);" + "$stderr.puts('Error: ' + e.message);" + "$stderr.puts(e.backtrace.join(\"\\n\"));" "end", path); @@ -207,36 +270,86 @@ shoes_code shoes_start(char *path, char *uri, int debug) { QUIT("Path to script is too long."); } + fprintf(stderr, "[SHOES] shoes_start: Evaluating bootup string (len=%d)\n", len); + // Don't print the bootup string itself - it's too verbose VALUE str = rb_eval_string(bootup); - if (NIL_P(str)) + fprintf(stderr, "[SHOES] shoes_start: rb_eval_string returned, str=%p\n", (void*)str); + + fprintf(stderr, "[SHOES] shoes_start: Checking if str is NIL\n"); + if (NIL_P(str)) { + fprintf(stderr, "[SHOES] shoes_start: str is NIL, returning SHOES_QUIT\n"); return SHOES_QUIT; + } + fprintf(stderr, "[SHOES] shoes_start: str is not NIL, converting to string\n"); StringValue(str); + fprintf(stderr, "[SHOES] shoes_start: Copying to shoes_world->path\n"); strcpy(shoes_world->path, RSTRING_PTR(str)); + fprintf(stderr, "[SHOES] shoes_start: Calling rb_rescue2 for shoes_start_begin\n"); char *load_uri_str = NULL; VALUE load_uri = rb_rescue2(CASTHOOK(shoes_start_begin), Qnil, CASTHOOK(shoes_start_exception), Qnil, rb_cObject, 0); - if (!RTEST(load_uri)) + fprintf(stderr, "[SHOES] shoes_start: rb_rescue2 returned, load_uri=%p\n", (void*)load_uri); + if (!RTEST(load_uri)) { + fprintf(stderr, "[SHOES] shoes_start: load_uri is false/nil, returning SHOES_QUIT\n"); return SHOES_QUIT; - if (rb_obj_is_kind_of(load_uri, rb_eException)) { - QUIT_ALERT(load_uri); } - - if (rb_obj_is_kind_of(load_uri, rb_cString)) + + // Check if it's a string first (the normal case) + if (TYPE(load_uri) == T_STRING) { + fprintf(stderr, "[SHOES] shoes_start: load_uri is a string\n"); load_uri_str = RSTRING_PTR(load_uri); + } else { + fprintf(stderr, "[SHOES] shoes_start: load_uri type=%d, checking if exception\n", TYPE(load_uri)); + // Only check for exception if it's not a string + fprintf(stderr, "[SHOES] shoes_start: Checking if load_uri is exception (rb_eException=%p)\n", (void*)rb_eException); + if (rb_obj_is_kind_of(load_uri, rb_eException)) { + fprintf(stderr, "[SHOES] shoes_start: load_uri is an exception\n"); + // QUIT_ALERT macro causes crashes in Ruby 3.x, use simpler approach + VALUE msg = rb_funcall(load_uri, rb_intern("message"), 0); + if (TYPE(msg) == T_STRING) { + fprintf(stderr, "Shoes Error: %s\n", RSTRING_PTR(msg)); + } else { + fprintf(stderr, "Shoes Error: (unable to get error message)\n"); + } + return SHOES_QUIT; + } + } code = shoes_load(load_uri_str); + fprintf(stderr, "[SHOES] shoes_start: shoes_load returned code=%d\n", code); if (code != SHOES_OK) goto quit; + fprintf(stderr, "[SHOES] shoes_start: Calling shoes_app_start with apps=%p, uri=%s\n", + (void*)shoes_world->apps, uri); code = shoes_app_start(shoes_world->apps, uri); + fprintf(stderr, "[SHOES] shoes_start: shoes_app_start returned code=%d\n", code); quit: return code; } shoes_code shoes_final() { - rb_funcall(cShoes, rb_intern("clean"), 0); - shoes_world_free(shoes_world); + fprintf(stderr, "[SHOES] shoes_final: Starting cleanup\n"); + + // Check if Ruby and cShoes were properly initialized before calling + fprintf(stderr, "[SHOES] shoes_final: cShoes=%p, Qnil=%p\n", (void*)cShoes, (void*)Qnil); + if (cShoes != Qnil && cShoes != 0) { + fprintf(stderr, "[SHOES] shoes_final: Checking if cShoes responds to 'clean'\n"); + if (rb_respond_to(cShoes, rb_intern("clean"))) { + fprintf(stderr, "[SHOES] shoes_final: Calling Shoes.clean\n"); + rb_funcall(cShoes, rb_intern("clean"), 0); + } else { + fprintf(stderr, "[SHOES] shoes_final: cShoes doesn't respond to 'clean', skipping\n"); + } + } + + fprintf(stderr, "[SHOES] shoes_final: Freeing shoes_world\n"); + if (shoes_world != NULL) { + shoes_world_free(shoes_world); + } + + fprintf(stderr, "[SHOES] shoes_final: Done\n"); return SHOES_OK; }