API for requesting user to grant new file capabilities #78
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -215,3 +215,12 @@ void oc_window_set_frame_size(oc_window window, oc_vec2 size)
 | 
			
		|||
    frame.h = size.y;
 | 
			
		||||
    oc_window_set_frame_rect(window, frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
// dialogs
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
oc_file_dialog_result oc_file_dialog(oc_arena* arena, oc_file_dialog_desc* desc)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_file_dialog_for_table(arena, desc, oc_file_table_get_global()));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -389,6 +389,60 @@ ORCA_API oc_str8 oc_save_dialog(oc_arena* arena,
 | 
			
		|||
                                oc_str8 defaultPath,
 | 
			
		||||
                                oc_str8_list filters);
 | 
			
		||||
 | 
			
		||||
#endif // !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
 | 
			
		||||
 | 
			
		||||
#include "platform/platform_io.h"
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
    OC_FILE_DIALOG_SAVE,
 | 
			
		||||
    OC_FILE_DIALOG_OPEN,
 | 
			
		||||
} oc_file_dialog_kind;
 | 
			
		||||
 | 
			
		||||
typedef u32 oc_file_dialog_flags;
 | 
			
		||||
 | 
			
		||||
enum _oc_file_dialog_flags
 | 
			
		||||
{
 | 
			
		||||
    OC_FILE_DIALOG_FILES = 1,
 | 
			
		||||
    OC_FILE_DIALOG_DIRECTORIES = 1 << 1,
 | 
			
		||||
    OC_FILE_DIALOG_MULTIPLE = 1 << 2,
 | 
			
		||||
    OC_FILE_DIALOG_CREATE_DIRECTORIES = 1 << 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct oc_file_dialog_desc
 | 
			
		||||
{
 | 
			
		||||
    oc_file_dialog_kind kind;
 | 
			
		||||
    oc_file_dialog_flags flags;
 | 
			
		||||
    oc_str8 title;
 | 
			
		||||
    oc_str8 okLabel;
 | 
			
		||||
    oc_file startAt;
 | 
			
		||||
    oc_str8 startPath;
 | 
			
		||||
    oc_str8_list filters;
 | 
			
		||||
 | 
			
		||||
    //... later customization options with checkboxes / radiobuttons
 | 
			
		||||
} oc_file_dialog_desc;
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
    OC_FILE_DIALOG_CANCEL = 0,
 | 
			
		||||
    OC_FILE_DIALOG_OK,
 | 
			
		||||
} oc_file_dialog_button;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_file_dialog_result
 | 
			
		||||
{
 | 
			
		||||
    oc_file_dialog_button button;
 | 
			
		||||
    oc_str8 path;
 | 
			
		||||
    oc_str8_list selection;
 | 
			
		||||
 | 
			
		||||
} oc_file_dialog_result;
 | 
			
		||||
 | 
			
		||||
#if !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file_dialog_result oc_file_dialog(oc_arena* arena, oc_file_dialog_desc* desc);
 | 
			
		||||
 | 
			
		||||
typedef struct oc_file_table oc_file_table;
 | 
			
		||||
ORCA_API oc_file_dialog_result oc_file_dialog_for_table(oc_arena* arena, oc_file_dialog_desc* desc, oc_file_table* table);
 | 
			
		||||
 | 
			
		||||
ORCA_API int oc_alert_popup(oc_str8 title,
 | 
			
		||||
                            oc_str8 message,
 | 
			
		||||
                            oc_str8_list options);
 | 
			
		||||
| 
						 | 
				
			
			@ -404,9 +458,7 @@ ORCA_API int oc_directory_create(oc_str8 path);
 | 
			
		|||
#else
 | 
			
		||||
 | 
			
		||||
void ORCA_IMPORT(oc_request_quit)(void);
 | 
			
		||||
 | 
			
		||||
void ORCA_IMPORT(oc_runtime_window_set_title)(oc_str8 title);
 | 
			
		||||
 | 
			
		||||
void ORCA_IMPORT(oc_runtime_window_set_size)(oc_vec2 size);
 | 
			
		||||
 | 
			
		||||
#endif // !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@
 | 
			
		|||
#include "app.h"
 | 
			
		||||
 | 
			
		||||
#include "platform/platform.h"
 | 
			
		||||
#include "platform/platform_io_internal.h"
 | 
			
		||||
#include "util/ringbuffer.h"
 | 
			
		||||
 | 
			
		||||
#if OC_PLATFORM_WINDOWS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,3 +2,8 @@
 | 
			
		|||
 | 
			
		||||
//This is used to pass raw events from the runtime
 | 
			
		||||
ORCA_EXPORT oc_event oc_rawEvent;
 | 
			
		||||
 | 
			
		||||
ORCA_EXPORT void* oc_arena_push_stub(oc_arena* arena, u64 size)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_arena_push(arena, size));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
#include "platform_clock.h"
 | 
			
		||||
#include "platform_debug.h"
 | 
			
		||||
#include "ringbuffer.h"
 | 
			
		||||
 | 
			
		||||
#include "platform/platform_path.h"
 | 
			
		||||
#include "app.c"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -2133,73 +2133,87 @@ oc_str8 oc_open_dialog(oc_arena* arena,
 | 
			
		|||
                       oc_str8_list filters,
 | 
			
		||||
                       bool directory)
 | 
			
		||||
{
 | 
			
		||||
    @autoreleasepool
 | 
			
		||||
    __block oc_str8 path = { 0 };
 | 
			
		||||
 | 
			
		||||
    dispatch_block_t block = ^{
 | 
			
		||||
      @autoreleasepool
 | 
			
		||||
      {
 | 
			
		||||
          NSWindow* keyWindow = [NSApp keyWindow];
 | 
			
		||||
 | 
			
		||||
          NSOpenPanel* dialog = [NSOpenPanel openPanel];
 | 
			
		||||
 | 
			
		||||
          NSString* nsTitle = [[NSString alloc] initWithBytes:title.ptr length:title.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
          //NOTE: title is not displayed since OS X 10.11, now use setMessage instead.
 | 
			
		||||
          //      see https://stackoverflow.com/questions/36879212/title-bar-missing-in-nsopenpanel
 | 
			
		||||
          [dialog setMessage:nsTitle];
 | 
			
		||||
 | 
			
		||||
          [dialog setLevel:NSModalPanelWindowLevel];
 | 
			
		||||
 | 
			
		||||
          if(filters.eltCount)
 | 
			
		||||
          {
 | 
			
		||||
              NSMutableArray* fileTypesArray = [NSMutableArray array];
 | 
			
		||||
 | 
			
		||||
              oc_list_for((oc_list*)&filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
              {
 | 
			
		||||
                  oc_str8 string = elt->string;
 | 
			
		||||
                  NSString* filter = [[NSString alloc] initWithBytes:string.ptr length:string.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
                  [fileTypesArray addObject:filter];
 | 
			
		||||
              }
 | 
			
		||||
              [dialog setAllowedFileTypes:fileTypesArray];
 | 
			
		||||
          }
 | 
			
		||||
          // Enable options in the dialog.
 | 
			
		||||
          if(directory)
 | 
			
		||||
          {
 | 
			
		||||
              [dialog setCanChooseDirectories:YES];
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              [dialog setCanChooseFiles:YES];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          [dialog setAllowsMultipleSelection:FALSE];
 | 
			
		||||
 | 
			
		||||
          NSString* nsPath = 0;
 | 
			
		||||
          ;
 | 
			
		||||
          if(defaultPath.len)
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [[NSString alloc] initWithBytes:defaultPath.ptr length:defaultPath.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [NSString stringWithUTF8String:"~"];
 | 
			
		||||
          }
 | 
			
		||||
          nsPath = [nsPath stringByExpandingTildeInPath];
 | 
			
		||||
 | 
			
		||||
          [dialog setDirectoryURL:[NSURL fileURLWithPath:nsPath]];
 | 
			
		||||
 | 
			
		||||
          // Display the dialog box. If the OK pressed,
 | 
			
		||||
          // process the files.
 | 
			
		||||
 | 
			
		||||
          if([dialog runModal] == NSModalResponseOK)
 | 
			
		||||
          {
 | 
			
		||||
              // Gets list of all files selected
 | 
			
		||||
              NSArray* files = [dialog URLs];
 | 
			
		||||
              //TODO: Loop through the files and process them.
 | 
			
		||||
 | 
			
		||||
              const char* result = [[[files objectAtIndex:0] path] UTF8String];
 | 
			
		||||
 | 
			
		||||
              path = oc_str8_push_cstring(arena, result);
 | 
			
		||||
          }
 | 
			
		||||
          [keyWindow makeKeyWindow];
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if([NSThread isMainThread])
 | 
			
		||||
    {
 | 
			
		||||
        NSWindow* keyWindow = [NSApp keyWindow];
 | 
			
		||||
 | 
			
		||||
        NSOpenPanel* dialog = [NSOpenPanel openPanel];
 | 
			
		||||
        [dialog setLevel:CGShieldingWindowLevel()];
 | 
			
		||||
 | 
			
		||||
        if(filters.eltCount)
 | 
			
		||||
        {
 | 
			
		||||
            NSMutableArray* fileTypesArray = [NSMutableArray array];
 | 
			
		||||
 | 
			
		||||
            oc_list_for(&filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
            {
 | 
			
		||||
                oc_str8 string = elt->string;
 | 
			
		||||
                NSString* filter = [[NSString alloc] initWithBytes:string.ptr length:string.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
                [fileTypesArray addObject:filter];
 | 
			
		||||
            }
 | 
			
		||||
            [dialog setAllowedFileTypes:fileTypesArray];
 | 
			
		||||
        }
 | 
			
		||||
        // Enable options in the dialog.
 | 
			
		||||
        if(directory)
 | 
			
		||||
        {
 | 
			
		||||
            [dialog setCanChooseDirectories:YES];
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            [dialog setCanChooseFiles:YES];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [dialog setAllowsMultipleSelection:FALSE];
 | 
			
		||||
 | 
			
		||||
        NSString* nsPath = 0;
 | 
			
		||||
        ;
 | 
			
		||||
        if(defaultPath.len)
 | 
			
		||||
        {
 | 
			
		||||
            nsPath = [[NSString alloc] initWithBytes:defaultPath.ptr length:defaultPath.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            nsPath = [NSString stringWithUTF8String:"~"];
 | 
			
		||||
        }
 | 
			
		||||
        nsPath = [nsPath stringByExpandingTildeInPath];
 | 
			
		||||
 | 
			
		||||
        [dialog setDirectoryURL:[NSURL fileURLWithPath:nsPath]];
 | 
			
		||||
 | 
			
		||||
        // Display the dialog box. If the OK pressed,
 | 
			
		||||
        // process the files.
 | 
			
		||||
 | 
			
		||||
        if([dialog runModal] == NSModalResponseOK)
 | 
			
		||||
        {
 | 
			
		||||
            // Gets list of all files selected
 | 
			
		||||
            NSArray* files = [dialog URLs];
 | 
			
		||||
            //TODO: Loop through the files and process them.
 | 
			
		||||
 | 
			
		||||
            const char* result = [[[files objectAtIndex:0] path] UTF8String];
 | 
			
		||||
 | 
			
		||||
            oc_str8 path = oc_str8_push_cstring(arena, result);
 | 
			
		||||
            [keyWindow makeKeyWindow];
 | 
			
		||||
 | 
			
		||||
            return (path);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            [keyWindow makeKeyWindow];
 | 
			
		||||
            return ((oc_str8){ 0, 0 });
 | 
			
		||||
        }
 | 
			
		||||
        block();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        dispatch_sync(dispatch_get_main_queue(), block);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_str8 oc_save_dialog(oc_arena* arena,
 | 
			
		||||
| 
						 | 
				
			
			@ -2207,61 +2221,221 @@ oc_str8 oc_save_dialog(oc_arena* arena,
 | 
			
		|||
                       oc_str8 defaultPath,
 | 
			
		||||
                       oc_str8_list filters)
 | 
			
		||||
{
 | 
			
		||||
    @autoreleasepool
 | 
			
		||||
    __block oc_str8 path = { 0 };
 | 
			
		||||
 | 
			
		||||
    dispatch_block_t block = ^{
 | 
			
		||||
      @autoreleasepool
 | 
			
		||||
      {
 | 
			
		||||
          NSWindow* keyWindow = [NSApp keyWindow];
 | 
			
		||||
 | 
			
		||||
          NSSavePanel* dialog = [NSSavePanel savePanel];
 | 
			
		||||
          [dialog setLevel:CGShieldingWindowLevel()];
 | 
			
		||||
 | 
			
		||||
          if(filters.eltCount)
 | 
			
		||||
          {
 | 
			
		||||
              NSMutableArray* fileTypesArray = [NSMutableArray array];
 | 
			
		||||
 | 
			
		||||
              oc_list_for((oc_list*)&filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
              {
 | 
			
		||||
                  oc_str8 string = elt->string;
 | 
			
		||||
                  NSString* filter = [[NSString alloc] initWithBytes:string.ptr length:string.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
                  [fileTypesArray addObject:filter];
 | 
			
		||||
              }
 | 
			
		||||
              [dialog setAllowedFileTypes:fileTypesArray];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          NSString* nsPath = 0;
 | 
			
		||||
          ;
 | 
			
		||||
          if(defaultPath.len)
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [[NSString alloc] initWithBytes:defaultPath.ptr length:defaultPath.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [NSString stringWithUTF8String:"~"];
 | 
			
		||||
          }
 | 
			
		||||
          nsPath = [nsPath stringByExpandingTildeInPath];
 | 
			
		||||
 | 
			
		||||
          [dialog setDirectoryURL:[NSURL fileURLWithPath:nsPath]];
 | 
			
		||||
 | 
			
		||||
          // Display the dialog box. If the OK pressed,
 | 
			
		||||
          // process the files.
 | 
			
		||||
 | 
			
		||||
          if([dialog runModal] == NSModalResponseOK)
 | 
			
		||||
          {
 | 
			
		||||
              // Gets list of all files selected
 | 
			
		||||
              NSURL* files = [dialog URL];
 | 
			
		||||
              // Loop through the files and process them.
 | 
			
		||||
 | 
			
		||||
              const char* result = [[files path] UTF8String];
 | 
			
		||||
 | 
			
		||||
              path = oc_str8_push_cstring(arena, result);
 | 
			
		||||
          }
 | 
			
		||||
          [keyWindow makeKeyWindow];
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if([NSThread isMainThread])
 | 
			
		||||
    {
 | 
			
		||||
        NSWindow* keyWindow = [NSApp keyWindow];
 | 
			
		||||
 | 
			
		||||
        NSSavePanel* dialog = [NSSavePanel savePanel];
 | 
			
		||||
        [dialog setLevel:CGShieldingWindowLevel()];
 | 
			
		||||
 | 
			
		||||
        if(filters.eltCount)
 | 
			
		||||
        {
 | 
			
		||||
            NSMutableArray* fileTypesArray = [NSMutableArray array];
 | 
			
		||||
 | 
			
		||||
            oc_list_for(&filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
            {
 | 
			
		||||
                oc_str8 string = elt->string;
 | 
			
		||||
                NSString* filter = [[NSString alloc] initWithBytes:string.ptr length:string.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
                [fileTypesArray addObject:filter];
 | 
			
		||||
            }
 | 
			
		||||
            [dialog setAllowedFileTypes:fileTypesArray];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        NSString* nsPath = 0;
 | 
			
		||||
        ;
 | 
			
		||||
        if(defaultPath.len)
 | 
			
		||||
        {
 | 
			
		||||
            nsPath = [[NSString alloc] initWithBytes:defaultPath.ptr length:defaultPath.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            nsPath = [NSString stringWithUTF8String:"~"];
 | 
			
		||||
        }
 | 
			
		||||
        nsPath = [nsPath stringByExpandingTildeInPath];
 | 
			
		||||
 | 
			
		||||
        [dialog setDirectoryURL:[NSURL fileURLWithPath:nsPath]];
 | 
			
		||||
 | 
			
		||||
        // Display the dialog box. If the OK pressed,
 | 
			
		||||
        // process the files.
 | 
			
		||||
 | 
			
		||||
        if([dialog runModal] == NSModalResponseOK)
 | 
			
		||||
        {
 | 
			
		||||
            // Gets list of all files selected
 | 
			
		||||
            NSURL* files = [dialog URL];
 | 
			
		||||
            // Loop through the files and process them.
 | 
			
		||||
 | 
			
		||||
            const char* result = [[files path] UTF8String];
 | 
			
		||||
 | 
			
		||||
            oc_str8 path = oc_str8_push_cstring(arena, result);
 | 
			
		||||
            [keyWindow makeKeyWindow];
 | 
			
		||||
            return (path);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            [keyWindow makeKeyWindow];
 | 
			
		||||
            return ((oc_str8){ 0, 0 });
 | 
			
		||||
        }
 | 
			
		||||
        block();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        dispatch_sync(dispatch_get_main_queue(), block);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file_dialog_result oc_file_dialog_for_table(oc_arena* arena, oc_file_dialog_desc* desc, oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    __block oc_file_dialog_result result = { 0 };
 | 
			
		||||
 | 
			
		||||
    dispatch_block_t block = ^{
 | 
			
		||||
      @autoreleasepool
 | 
			
		||||
      {
 | 
			
		||||
          oc_arena_scope scratch = oc_scratch_begin_next(arena);
 | 
			
		||||
 | 
			
		||||
          NSWindow* keyWindow = [NSApp keyWindow];
 | 
			
		||||
 | 
			
		||||
          NSSavePanel* dialog = 0;
 | 
			
		||||
          if(desc->kind == OC_FILE_DIALOG_OPEN)
 | 
			
		||||
          {
 | 
			
		||||
              NSOpenPanel* openPanel = [NSOpenPanel openPanel];
 | 
			
		||||
              dialog = (NSSavePanel*)openPanel;
 | 
			
		||||
 | 
			
		||||
              openPanel.canChooseFiles = (desc->flags & OC_FILE_DIALOG_FILES) ? YES : NO;
 | 
			
		||||
              openPanel.canChooseDirectories = (desc->flags & OC_FILE_DIALOG_DIRECTORIES) ? YES : NO;
 | 
			
		||||
              openPanel.allowsMultipleSelection = (desc->flags & OC_FILE_DIALOG_MULTIPLE) ? YES : NO;
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              dialog = [NSSavePanel savePanel];
 | 
			
		||||
 | 
			
		||||
              dialog.canCreateDirectories = (desc->flags & OC_FILE_DIALOG_CREATE_DIRECTORIES) ? YES : NO;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          //NOTE: set title. "title" property is not displayed since OS X 10.11, now use setMessage instead.
 | 
			
		||||
          //      see https://stackoverflow.com/questions/36879212/title-bar-missing-in-nsopenpanel
 | 
			
		||||
          NSString* nsTitle = [[NSString alloc] initWithBytes:desc->title.ptr
 | 
			
		||||
                                                       length:desc->title.len
 | 
			
		||||
                                                     encoding:NSUTF8StringEncoding];
 | 
			
		||||
          [dialog setMessage:nsTitle];
 | 
			
		||||
 | 
			
		||||
          //NOTE: set ok button
 | 
			
		||||
          if(desc->okLabel.len)
 | 
			
		||||
          {
 | 
			
		||||
              NSString* label = [[NSString alloc] initWithBytes:desc->okLabel.ptr
 | 
			
		||||
                                                         length:desc->okLabel.len
 | 
			
		||||
                                                       encoding:NSUTF8StringEncoding];
 | 
			
		||||
 | 
			
		||||
              [dialog setPrompt:label];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          //NOTE: set starting path
 | 
			
		||||
          oc_str8 startPath = { 0 };
 | 
			
		||||
          {
 | 
			
		||||
              oc_str8_list list = { 0 };
 | 
			
		||||
              if(!oc_file_is_nil(desc->startAt))
 | 
			
		||||
              {
 | 
			
		||||
                  oc_file_slot* slot = oc_file_slot_from_handle(table, desc->startAt);
 | 
			
		||||
                  if(slot)
 | 
			
		||||
                  {
 | 
			
		||||
                      char path[PATH_MAX];
 | 
			
		||||
                      if(fcntl(slot->fd, F_GETPATH, path) != -1)
 | 
			
		||||
                      {
 | 
			
		||||
                          oc_str8 string = oc_str8_push_cstring(scratch.arena, path);
 | 
			
		||||
                          oc_str8_list_push(scratch.arena, &list, string);
 | 
			
		||||
                      }
 | 
			
		||||
                  }
 | 
			
		||||
              }
 | 
			
		||||
              if(desc->startPath.len)
 | 
			
		||||
              {
 | 
			
		||||
                  oc_str8_list_push(scratch.arena, &list, desc->startPath);
 | 
			
		||||
              }
 | 
			
		||||
              startPath = oc_path_join(scratch.arena, list);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          NSString* nsPath = 0;
 | 
			
		||||
          if(startPath.len)
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [[NSString alloc] initWithBytes:startPath.ptr
 | 
			
		||||
                                                length:startPath.len
 | 
			
		||||
                                              encoding:NSUTF8StringEncoding];
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              nsPath = [NSString stringWithUTF8String:"~"];
 | 
			
		||||
          }
 | 
			
		||||
          nsPath = [nsPath stringByExpandingTildeInPath];
 | 
			
		||||
          [dialog setDirectoryURL:[NSURL fileURLWithPath:nsPath]];
 | 
			
		||||
 | 
			
		||||
          //NOTE: set filters
 | 
			
		||||
          if(desc->filters.eltCount)
 | 
			
		||||
          {
 | 
			
		||||
              NSMutableArray* fileTypesArray = [NSMutableArray array];
 | 
			
		||||
 | 
			
		||||
              oc_list_for((oc_list*)&desc->filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
              {
 | 
			
		||||
                  oc_str8 string = elt->string;
 | 
			
		||||
                  NSString* filter = [[NSString alloc] initWithBytes:string.ptr length:string.len encoding:NSUTF8StringEncoding];
 | 
			
		||||
                  [fileTypesArray addObject:filter];
 | 
			
		||||
              }
 | 
			
		||||
              [dialog setAllowedFileTypes:fileTypesArray];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // Display the dialog box. If the OK pressed,
 | 
			
		||||
          // process the files.
 | 
			
		||||
 | 
			
		||||
          [dialog validateVisibleColumns];
 | 
			
		||||
          [dialog setLevel:NSModalPanelWindowLevel];
 | 
			
		||||
 | 
			
		||||
          if([dialog runModal] == NSModalResponseOK)
 | 
			
		||||
          {
 | 
			
		||||
              if(desc->kind == OC_FILE_DIALOG_OPEN && (desc->flags & OC_FILE_DIALOG_MULTIPLE))
 | 
			
		||||
              {
 | 
			
		||||
                  // Gets list of all files selected
 | 
			
		||||
                  NSArray* files = [((NSOpenPanel*)dialog) URLs];
 | 
			
		||||
 | 
			
		||||
                  const char* path = [[[files objectAtIndex:0] path] UTF8String];
 | 
			
		||||
                  result.path = oc_str8_push_cstring(arena, path);
 | 
			
		||||
 | 
			
		||||
                  for(int i = 0; i < [files count]; i++)
 | 
			
		||||
                  {
 | 
			
		||||
                      const char* path = [[[files objectAtIndex:i] path] UTF8String];
 | 
			
		||||
                      oc_str8 string = oc_str8_push_cstring(arena, path);
 | 
			
		||||
                      oc_str8_list_push(arena, &result.selection, string);
 | 
			
		||||
                  }
 | 
			
		||||
              }
 | 
			
		||||
              else
 | 
			
		||||
              {
 | 
			
		||||
                  const char* path = [[[dialog URL] path] UTF8String];
 | 
			
		||||
                  result.path = oc_str8_push_cstring(arena, path);
 | 
			
		||||
 | 
			
		||||
                  oc_str8_list_push(arena, &result.selection, result.path);
 | 
			
		||||
              }
 | 
			
		||||
              result.button = OC_FILE_DIALOG_OK;
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
              result.button = OC_FILE_DIALOG_CANCEL;
 | 
			
		||||
          }
 | 
			
		||||
          [keyWindow makeKeyWindow];
 | 
			
		||||
 | 
			
		||||
          oc_scratch_end(scratch);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if([NSThread isMainThread])
 | 
			
		||||
    {
 | 
			
		||||
        block();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        dispatch_sync(dispatch_get_main_queue(), block);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int oc_alert_popup(oc_str8 title,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1189,16 +1189,16 @@ void oc_win32_surface_set_hidden(oc_surface_data* surface, bool hidden)
 | 
			
		|||
 | 
			
		||||
void oc_win32_surface_bring_to_front(oc_surface_data* surface)
 | 
			
		||||
{
 | 
			
		||||
	oc_list_remove(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
	oc_list_push(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
	oc_win32_update_child_layers_zorder(surface->layer.parent);
 | 
			
		||||
    oc_list_remove(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
    oc_list_push(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
    oc_win32_update_child_layers_zorder(surface->layer.parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void oc_win32_surface_send_to_back(oc_surface_data* surface)
 | 
			
		||||
{
 | 
			
		||||
	oc_list_remove(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
	oc_list_push_back(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
	oc_win32_update_child_layers_zorder(surface->layer.parent);
 | 
			
		||||
    oc_list_remove(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
    oc_list_push_back(&surface->layer.parent->win32.layers, &surface->layer.listElt);
 | 
			
		||||
    oc_win32_update_child_layers_zorder(surface->layer.parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* oc_win32_surface_native_layer(oc_surface_data* surface)
 | 
			
		||||
| 
						 | 
				
			
			@ -1565,6 +1565,207 @@ oc_str8 oc_save_dialog(oc_arena* arena,
 | 
			
		|||
    return (res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "platform/platform_io_internal.h"
 | 
			
		||||
 | 
			
		||||
oc_str16 win32_path_from_handle_null_terminated(oc_arena* arena, HANDLE handle); // defined in win32_io.c
 | 
			
		||||
 | 
			
		||||
oc_file_dialog_result oc_file_dialog_for_table(oc_arena* arena, oc_file_dialog_desc* desc, oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin_next(arena);
 | 
			
		||||
    oc_file_dialog_result result = { 0 };
 | 
			
		||||
 | 
			
		||||
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 | 
			
		||||
    if(SUCCEEDED(hr))
 | 
			
		||||
    {
 | 
			
		||||
        IFileDialog* dialog = 0;
 | 
			
		||||
 | 
			
		||||
        if(desc->kind == OC_FILE_DIALOG_OPEN)
 | 
			
		||||
        {
 | 
			
		||||
            hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_ALL, &IID_IFileOpenDialog, (void**)&dialog);
 | 
			
		||||
            if(SUCCEEDED(hr))
 | 
			
		||||
            {
 | 
			
		||||
                FILEOPENDIALOGOPTIONS opt;
 | 
			
		||||
                dialog->lpVtbl->GetOptions(dialog, &opt);
 | 
			
		||||
 | 
			
		||||
                //NOTE: OC_FILE_DIALOG_FILES is always implied, since IFileDialog offers no way to pick _only_ folders
 | 
			
		||||
                if(desc->flags & OC_FILE_DIALOG_DIRECTORIES)
 | 
			
		||||
                {
 | 
			
		||||
                    opt |= FOS_PICKFOLDERS;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    opt &= ~FOS_PICKFOLDERS;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(desc->flags & OC_FILE_DIALOG_MULTIPLE)
 | 
			
		||||
                {
 | 
			
		||||
                    opt |= FOS_ALLOWMULTISELECT;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    opt &= ~FOS_ALLOWMULTISELECT;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                dialog->lpVtbl->SetOptions(dialog, opt);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, CLSCTX_ALL, &IID_IFileSaveDialog, (void**)&dialog);
 | 
			
		||||
 | 
			
		||||
            //NOTE: OC_FILE_DIALOG_CREATE_DIRECTORIES is implied, IFileSaveDialog offers no way of disabling it...
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(SUCCEEDED(hr))
 | 
			
		||||
        {
 | 
			
		||||
            //NOTE set title
 | 
			
		||||
            if(desc->title.len)
 | 
			
		||||
            {
 | 
			
		||||
                oc_str16 titleWide = oc_win32_utf8_to_wide(scratch.arena, desc->title);
 | 
			
		||||
                dialog->lpVtbl->SetTitle(dialog, (LPCWSTR)titleWide.ptr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //NOTE set ok button
 | 
			
		||||
            if(desc->okLabel.len)
 | 
			
		||||
            {
 | 
			
		||||
                oc_str16 okLabelWide = oc_win32_utf8_to_wide(scratch.arena, desc->okLabel);
 | 
			
		||||
                dialog->lpVtbl->SetOkButtonLabel(dialog, (LPCWSTR)okLabelWide.ptr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //NOTE: set starting path
 | 
			
		||||
            oc_str8 startPath = { 0 };
 | 
			
		||||
            {
 | 
			
		||||
                oc_str8_list list = { 0 };
 | 
			
		||||
                if(!oc_file_is_nil(desc->startAt))
 | 
			
		||||
                {
 | 
			
		||||
                    oc_file_slot* slot = oc_file_slot_from_handle(table, desc->startAt);
 | 
			
		||||
                    if(slot)
 | 
			
		||||
                    {
 | 
			
		||||
                        oc_str16 pathWide = win32_path_from_handle_null_terminated(scratch.arena, slot->fd);
 | 
			
		||||
                        oc_str8 path = oc_win32_wide_to_utf8(scratch.arena, pathWide);
 | 
			
		||||
                        //NOTE: remove potential \\?\ prefix which doesn't work with SHCreateItemFromParsingName()
 | 
			
		||||
                        if(!oc_str8_cmp(oc_str8_slice(path, 0, 4), OC_STR8("\\\\?\\")))
 | 
			
		||||
                        {
 | 
			
		||||
                            path = oc_str8_slice(path, 4, path.len);
 | 
			
		||||
                        }
 | 
			
		||||
                        oc_str8_list_push(scratch.arena, &list, path);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if(desc->startPath.len)
 | 
			
		||||
                {
 | 
			
		||||
                    oc_str8_list_push(scratch.arena, &list, desc->startPath);
 | 
			
		||||
                }
 | 
			
		||||
                startPath = oc_path_join(scratch.arena, list);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(startPath.len)
 | 
			
		||||
            {
 | 
			
		||||
                oc_str16 pathWide = oc_win32_utf8_to_wide(scratch.arena, startPath);
 | 
			
		||||
 | 
			
		||||
                IShellItem* item = 0;
 | 
			
		||||
                hr = SHCreateItemFromParsingName((LPCWSTR)pathWide.ptr, NULL, &IID_IShellItem, (void**)&item);
 | 
			
		||||
                if(SUCCEEDED(hr))
 | 
			
		||||
                {
 | 
			
		||||
                    hr = dialog->lpVtbl->SetFolder(dialog, item);
 | 
			
		||||
                    item->lpVtbl->Release(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //NOTE: set filters
 | 
			
		||||
            if(desc->filters.eltCount)
 | 
			
		||||
            {
 | 
			
		||||
                COMDLG_FILTERSPEC* filterSpecs = oc_arena_push_array(scratch.arena, COMDLG_FILTERSPEC, desc->filters.eltCount);
 | 
			
		||||
 | 
			
		||||
                int i = 0;
 | 
			
		||||
                oc_list_for(&desc->filters.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
                {
 | 
			
		||||
                    oc_str8_list list = { 0 };
 | 
			
		||||
                    oc_str8_list_push(scratch.arena, &list, OC_STR8("*."));
 | 
			
		||||
                    oc_str8_list_push(scratch.arena, &list, elt->string);
 | 
			
		||||
                    oc_str8 filter = oc_str8_list_join(scratch.arena, list);
 | 
			
		||||
 | 
			
		||||
                    int filterWideSize = 1 + MultiByteToWideChar(CP_UTF8, 0, filter.ptr, filter.len, NULL, 0);
 | 
			
		||||
                    filterSpecs[i].pszSpec = oc_arena_push_array(scratch.arena, wchar_t, filterWideSize);
 | 
			
		||||
                    MultiByteToWideChar(CP_UTF8, 0, filter.ptr, filter.len, (LPWSTR)filterSpecs[i].pszSpec, filterWideSize);
 | 
			
		||||
                    ((LPWSTR)(filterSpecs[i].pszSpec))[filterWideSize - 1] = 0;
 | 
			
		||||
 | 
			
		||||
                    filterSpecs[i].pszName = filterSpecs[i].pszSpec;
 | 
			
		||||
                    i++;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                hr = dialog->lpVtbl->SetFileTypes(dialog, i, filterSpecs);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            hr = dialog->lpVtbl->Show(dialog, NULL);
 | 
			
		||||
 | 
			
		||||
            if(SUCCEEDED(hr))
 | 
			
		||||
            {
 | 
			
		||||
                if(desc->kind == OC_FILE_DIALOG_OPEN && (desc->flags & OC_FILE_DIALOG_MULTIPLE))
 | 
			
		||||
                {
 | 
			
		||||
                    IShellItemArray* array = 0;
 | 
			
		||||
                    hr = ((IFileOpenDialog*)dialog)->lpVtbl->GetResults((IFileOpenDialog*)dialog, &array);
 | 
			
		||||
                    if(SUCCEEDED(hr))
 | 
			
		||||
                    {
 | 
			
		||||
                        int count = 0;
 | 
			
		||||
                        array->lpVtbl->GetCount(array, &count);
 | 
			
		||||
                        for(int i = 0; i < count; i++)
 | 
			
		||||
                        {
 | 
			
		||||
                            IShellItem* item = 0;
 | 
			
		||||
                            hr = array->lpVtbl->GetItemAt(array, i, &item);
 | 
			
		||||
                            if(SUCCEEDED(hr))
 | 
			
		||||
                            {
 | 
			
		||||
                                PWSTR pathWCStr = 0;
 | 
			
		||||
                                hr = item->lpVtbl->GetDisplayName(item, SIGDN_FILESYSPATH, &pathWCStr);
 | 
			
		||||
                                if(SUCCEEDED(hr))
 | 
			
		||||
                                {
 | 
			
		||||
                                    oc_str16 pathWide = oc_str16_from_buffer(lstrlenW(pathWCStr), pathWCStr);
 | 
			
		||||
                                    oc_str8 path = oc_win32_wide_to_utf8(arena, pathWide);
 | 
			
		||||
                                    oc_str8_list_push(arena, &result.selection, path);
 | 
			
		||||
 | 
			
		||||
                                    if(i == 0)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        result.path = path;
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    CoTaskMemFree(pathWCStr);
 | 
			
		||||
                                }
 | 
			
		||||
                                item->lpVtbl->Release(item);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        result.button = OC_FILE_DIALOG_OK;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    IShellItem* item;
 | 
			
		||||
                    hr = dialog->lpVtbl->GetResult(dialog, &item);
 | 
			
		||||
                    if(SUCCEEDED(hr))
 | 
			
		||||
                    {
 | 
			
		||||
                        PWSTR pathWCStr;
 | 
			
		||||
                        hr = item->lpVtbl->GetDisplayName(item, SIGDN_FILESYSPATH, &pathWCStr);
 | 
			
		||||
 | 
			
		||||
                        if(SUCCEEDED(hr))
 | 
			
		||||
                        {
 | 
			
		||||
                            oc_str16 pathWide = oc_str16_from_buffer(lstrlenW(pathWCStr), pathWCStr);
 | 
			
		||||
                            result.path = oc_win32_wide_to_utf8(arena, pathWide);
 | 
			
		||||
                            oc_str8_list_push(arena, &result.selection, result.path);
 | 
			
		||||
 | 
			
		||||
                            CoTaskMemFree(pathWCStr);
 | 
			
		||||
                        }
 | 
			
		||||
                        item->lpVtbl->Release(item);
 | 
			
		||||
                        result.button = OC_FILE_DIALOG_OK;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        dialog->lpVtbl->Release(dialog);
 | 
			
		||||
    }
 | 
			
		||||
    CoUninitialize();
 | 
			
		||||
 | 
			
		||||
    oc_scratch_end(scratch);
 | 
			
		||||
    return (result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <commctrl.h>
 | 
			
		||||
 | 
			
		||||
int oc_alert_popup(oc_str8 title,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
#include "platform/platform.h"
 | 
			
		||||
#include "platform/platform_clock.h"
 | 
			
		||||
#include "platform/platform_io.h"
 | 
			
		||||
#include "platform/platform_io_dialog.h"
 | 
			
		||||
#include "platform/platform_path.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,4 +222,10 @@ ORCA_API u64 oc_file_size(oc_file file);
 | 
			
		|||
 | 
			
		||||
//TODO: Complete as needed...
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
// Acquiring new file capabilities through user interaction
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file oc_file_open_with_request(oc_str8 path, oc_file_access rights, oc_file_open_flags flags);
 | 
			
		||||
 | 
			
		||||
#endif //__PLATFORM_IO_H_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
*****************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "platform_io.h"
 | 
			
		||||
#include "platform_io_dialog.h"
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// File stream read/write API
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
/************************************************************/ /**
 | 
			
		||||
*
 | 
			
		||||
*	@file: platform_io_dialog.h
 | 
			
		||||
*	@author: Martin Fouilleul
 | 
			
		||||
*	@date: 01/09/2023
 | 
			
		||||
*
 | 
			
		||||
*****************************************************************/
 | 
			
		||||
#ifndef __PLATFORM_IO_DIALOG_H_
 | 
			
		||||
#define __PLATFORM_IO_DIALOG_H_
 | 
			
		||||
 | 
			
		||||
#include "platform_io.h"
 | 
			
		||||
#include "app/app.h"
 | 
			
		||||
 | 
			
		||||
typedef struct oc_file_open_with_dialog_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt listElt;
 | 
			
		||||
    oc_file file;
 | 
			
		||||
} oc_file_open_with_dialog_elt;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_file_open_with_dialog_result
 | 
			
		||||
{
 | 
			
		||||
    oc_file_dialog_button button;
 | 
			
		||||
    oc_file file;
 | 
			
		||||
    oc_list selection;
 | 
			
		||||
} oc_file_open_with_dialog_result;
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file_open_with_dialog_result oc_file_open_with_dialog(oc_arena* arena, oc_file_access rights, oc_file_open_flags flags, oc_file_dialog_desc* desc);
 | 
			
		||||
 | 
			
		||||
#endif //__PLATFORM_IO_DIALOG_H_
 | 
			
		||||
| 
						 | 
				
			
			@ -5,12 +5,17 @@
 | 
			
		|||
*	@date: 11/06/2023
 | 
			
		||||
*
 | 
			
		||||
*****************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "platform_io_internal.h"
 | 
			
		||||
#include "platform_path.h"
 | 
			
		||||
#include "app/app.h"
 | 
			
		||||
#include "platform/platform_io_internal.h"
 | 
			
		||||
#include "platform/platform_path.h"
 | 
			
		||||
 | 
			
		||||
oc_file_table oc_globalFileTable = { 0 };
 | 
			
		||||
 | 
			
		||||
oc_file_table* oc_file_table_get_global()
 | 
			
		||||
{
 | 
			
		||||
    return (&oc_globalFileTable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file_slot* oc_file_slot_alloc(oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_file_slot* slot = oc_list_pop_entry(&table->freeList, oc_file_slot, freeListElt);
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +67,7 @@ oc_file_slot* oc_file_slot_from_handle(oc_file_table* table, oc_file handle)
 | 
			
		|||
 | 
			
		||||
oc_io_cmp oc_io_wait_single_req(oc_io_req* req)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_io_wait_single_req_with_table(req, &oc_globalFileTable));
 | 
			
		||||
    return (oc_io_wait_single_req_for_table(req, &oc_globalFileTable));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -341,3 +346,100 @@ oc_io_cmp oc_io_open_at(oc_file_slot* atSlot, oc_io_req* req, oc_file_table* tab
 | 
			
		|||
    }
 | 
			
		||||
    return (cmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file oc_file_open_with_request_for_table(oc_str8 path, oc_file_access rights, oc_file_open_flags flags, oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin();
 | 
			
		||||
    oc_str8 msg = oc_str8_pushf(scratch.arena, "Application wants to access file '%.*s'.", (int)path.len, path.ptr);
 | 
			
		||||
 | 
			
		||||
    oc_str8_list options = { 0 };
 | 
			
		||||
    oc_str8_list_push(scratch.arena, &options, OC_STR8("Deny"));
 | 
			
		||||
    oc_str8_list_push(scratch.arena, &options, OC_STR8("Accept"));
 | 
			
		||||
 | 
			
		||||
    int res = oc_alert_popup(OC_STR8("File Access"), msg, options);
 | 
			
		||||
 | 
			
		||||
    oc_file file = oc_file_nil();
 | 
			
		||||
    if(res == 1)
 | 
			
		||||
    {
 | 
			
		||||
        oc_io_cmp cmp = { 0 };
 | 
			
		||||
 | 
			
		||||
        oc_io_req req = {
 | 
			
		||||
            .op = OC_IO_OPEN_AT,
 | 
			
		||||
            .size = path.len,
 | 
			
		||||
            .buffer = path.ptr,
 | 
			
		||||
            .open.rights = rights,
 | 
			
		||||
            .open.flags = flags
 | 
			
		||||
        };
 | 
			
		||||
        cmp = oc_io_open_at(0, &req, table);
 | 
			
		||||
        if(cmp.error == OC_IO_OK)
 | 
			
		||||
        {
 | 
			
		||||
            file = cmp.handle;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    oc_scratch_end(scratch);
 | 
			
		||||
 | 
			
		||||
    return (file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file oc_file_open_with_request(oc_str8 path, oc_file_access rights, oc_file_open_flags flags)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_file_open_with_request_for_table(path, rights, flags, &oc_globalFileTable));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file_open_with_dialog_result oc_file_open_with_dialog_for_table(oc_arena* arena,
 | 
			
		||||
                                                                   oc_file_access rights,
 | 
			
		||||
                                                                   oc_file_open_flags flags,
 | 
			
		||||
                                                                   oc_file_dialog_desc* desc,
 | 
			
		||||
                                                                   oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin_next(arena);
 | 
			
		||||
 | 
			
		||||
    oc_file_dialog_result dialogResult = oc_file_dialog_for_table(scratch.arena, desc, table);
 | 
			
		||||
 | 
			
		||||
    oc_file_open_with_dialog_result result = {
 | 
			
		||||
        .button = dialogResult.button
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if(dialogResult.button == OC_FILE_DIALOG_OK)
 | 
			
		||||
    {
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        oc_list_for(&dialogResult.selection.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
        {
 | 
			
		||||
            oc_file file = oc_file_nil();
 | 
			
		||||
            if(elt->string.len)
 | 
			
		||||
            {
 | 
			
		||||
                oc_io_req req = {
 | 
			
		||||
                    .op = OC_IO_OPEN_AT,
 | 
			
		||||
                    .size = elt->string.len,
 | 
			
		||||
                    .buffer = elt->string.ptr,
 | 
			
		||||
                    .open.rights = rights,
 | 
			
		||||
                    .open.flags = flags
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                oc_io_cmp cmp = oc_io_wait_single_req_for_table(&req, table);
 | 
			
		||||
                file = cmp.handle;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            oc_file_open_with_dialog_elt* resElt = oc_arena_push_type(arena, oc_file_open_with_dialog_elt);
 | 
			
		||||
            memset(resElt, 0, sizeof(*resElt));
 | 
			
		||||
            resElt->file = file;
 | 
			
		||||
            oc_list_push_back(&result.selection, &resElt->listElt);
 | 
			
		||||
 | 
			
		||||
            if(i == 0)
 | 
			
		||||
            {
 | 
			
		||||
                result.file = file;
 | 
			
		||||
                i++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    oc_scratch_end(scratch);
 | 
			
		||||
 | 
			
		||||
    return (result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file_open_with_dialog_result oc_file_open_with_dialog(oc_arena* arena, oc_file_access rights, oc_file_open_flags flags, oc_file_dialog_desc* desc)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_file_open_with_dialog_for_table(arena, rights, flags, desc, &oc_globalFileTable));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "platform_io.h"
 | 
			
		||||
#include "platform_io_dialog.h"
 | 
			
		||||
 | 
			
		||||
#if OC_PLATFORM_MACOS || PLATFORM_LINUX
 | 
			
		||||
typedef int oc_file_desc;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,12 +47,22 @@ typedef struct oc_file_table
 | 
			
		|||
    oc_list freeList;
 | 
			
		||||
} oc_file_table;
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file_table* oc_file_table_get_global();
 | 
			
		||||
 | 
			
		||||
oc_file_slot* oc_file_slot_alloc(oc_file_table* table);
 | 
			
		||||
void oc_file_slot_recycle(oc_file_table* table, oc_file_slot* slot);
 | 
			
		||||
oc_file oc_file_from_slot(oc_file_table* table, oc_file_slot* slot);
 | 
			
		||||
oc_file_slot* oc_file_slot_from_handle(oc_file_table* table, oc_file handle);
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table);
 | 
			
		||||
ORCA_API oc_io_cmp oc_io_wait_single_req_for_table(oc_io_req* req, oc_file_table* table);
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file oc_file_open_with_request_for_table(oc_str8 path, oc_file_access rights, oc_file_open_flags flags, oc_file_table* table);
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_file_open_with_dialog_result oc_file_open_with_dialog_for_table(oc_arena* arena,
 | 
			
		||||
                                                                            oc_file_access rights,
 | 
			
		||||
                                                                            oc_file_open_flags flags,
 | 
			
		||||
                                                                            oc_file_dialog_desc* desc,
 | 
			
		||||
                                                                            oc_file_table* table);
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------
 | 
			
		||||
// raw io primitives
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ oc_str8_list oc_path_split(oc_arena* arena, oc_str8 path)
 | 
			
		|||
oc_str8 oc_path_join(oc_arena* arena, oc_str8_list elements)
 | 
			
		||||
{
 | 
			
		||||
    //TODO: check if elements have ending/begining '/' ?
 | 
			
		||||
    oc_str8 res = oc_str8_list_collate(arena, elements, OC_STR8("/"), OC_STR8("/"), (oc_str8){ 0 });
 | 
			
		||||
    oc_str8 res = oc_str8_list_collate(arena, elements, OC_STR8(""), OC_STR8("/"), (oc_str8){ 0 });
 | 
			
		||||
    return (res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -518,7 +518,7 @@ oc_io_cmp oc_io_get_error(oc_file_slot* slot, oc_io_req* req)
 | 
			
		|||
    return (cmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table)
 | 
			
		||||
oc_io_cmp oc_io_wait_single_req_for_table(oc_io_req* req, oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_io_cmp cmp = { 0 };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ oc_io_error oc_io_raw_last_error()
 | 
			
		|||
    return (error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static oc_str16 win32_path_from_handle_null_terminated(oc_arena* arena, HANDLE handle)
 | 
			
		||||
oc_str16 win32_path_from_handle_null_terminated(oc_arena* arena, HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
    oc_str16 res = { 0 };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ static oc_str16 win32_get_path_at_null_terminated(oc_arena* arena, oc_file_desc
 | 
			
		|||
    oc_arena_scope scratch = oc_scratch_begin_next(arena);
 | 
			
		||||
 | 
			
		||||
    oc_str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirFd);
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide(scratch.arena, path);
 | 
			
		||||
 | 
			
		||||
    if(dirPathW.len && pathW.len)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +194,7 @@ oc_file_desc oc_io_raw_open_at(oc_file_desc dirFd, oc_str8 path, oc_file_access
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin();
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide(scratch.arena, path);
 | 
			
		||||
 | 
			
		||||
    if(dirFd == NULL || dirFd == INVALID_HANDLE_VALUE)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +505,7 @@ static oc_io_cmp oc_io_get_error(oc_file_slot* slot, oc_io_req* req)
 | 
			
		|||
    return (cmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table)
 | 
			
		||||
oc_io_cmp oc_io_wait_single_req_for_table(oc_io_req* req, oc_file_table* table)
 | 
			
		||||
{
 | 
			
		||||
    oc_io_cmp cmp = { 0 };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@
 | 
			
		|||
bool oc_path_is_absolute(oc_str8 path)
 | 
			
		||||
{
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin();
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
 | 
			
		||||
    oc_str16 pathW = oc_win32_utf8_to_wide(scratch.arena, path);
 | 
			
		||||
    bool result = !PathIsRelativeW(pathW.ptr);
 | 
			
		||||
 | 
			
		||||
    oc_scratch_end(scratch);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
 | 
			
		||||
#include "win32_string_helpers.h"
 | 
			
		||||
 | 
			
		||||
oc_str16 oc_win32_utf8_to_wide_null_terminated(oc_arena* arena, oc_str8 s)
 | 
			
		||||
oc_str16 oc_win32_utf8_to_wide(oc_arena* arena, oc_str8 s)
 | 
			
		||||
{
 | 
			
		||||
    oc_str16 res = { 0 };
 | 
			
		||||
    res.len = 1 + MultiByteToWideChar(CP_UTF8, 0, s.ptr, s.len, NULL, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
 | 
			
		||||
#include "util/strings.h"
 | 
			
		||||
 | 
			
		||||
oc_str16 oc_win32_utf8_to_wide_null_terminated(oc_arena* arena, oc_str8 s);
 | 
			
		||||
oc_str16 oc_win32_utf8_to_wide(oc_arena* arena, oc_str8 s);
 | 
			
		||||
oc_str8 oc_win32_wide_to_utf8(oc_arena* arena, oc_str16 s);
 | 
			
		||||
 | 
			
		||||
#endif // __WIN32_STRING_HELPERS_H_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										156
									
								
								src/runtime.c
								
								
								
								
							
							
						
						
									
										156
									
								
								src/runtime.c
								
								
								
								
							| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
 | 
			
		||||
oc_font orca_font_create(const char* resourcePath)
 | 
			
		||||
{
 | 
			
		||||
    //NOTE(martin): create default font
 | 
			
		||||
    //NOTE(martin): create default fonts
 | 
			
		||||
    oc_str8 fontPath = oc_path_executable_relative(oc_scratch(), OC_STR8(resourcePath));
 | 
			
		||||
 | 
			
		||||
    FILE* fontFile = fopen(fontPath.ptr, "r");
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +49,6 @@ oc_font orca_font_create(const char* resourcePath)
 | 
			
		|||
    return (font);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_font oc_font_create_default()
 | 
			
		||||
{
 | 
			
		||||
    return (orca_font_create("../resources/OpenSansLatinSubset.ttf"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_runtime __orcaApp = { 0 };
 | 
			
		||||
 | 
			
		||||
oc_runtime* oc_runtime_get()
 | 
			
		||||
| 
						 | 
				
			
			@ -63,26 +58,69 @@ oc_runtime* oc_runtime_get()
 | 
			
		|||
 | 
			
		||||
oc_runtime_env* oc_runtime_env_get()
 | 
			
		||||
{
 | 
			
		||||
    return (&__orcaApp.runtime);
 | 
			
		||||
    return (&__orcaApp.env);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* oc_runtime_ptr_to_native(oc_runtime* orca, void* wasmPtr, u32 length)
 | 
			
		||||
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
 | 
			
		||||
{
 | 
			
		||||
    M3ErrorInfo errInfo = { 0 };
 | 
			
		||||
    m3_GetErrorInfo(runtime, &errInfo);
 | 
			
		||||
    if(errInfo.message && res == errInfo.result)
 | 
			
		||||
    {
 | 
			
		||||
        oc_abort_ext(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        oc_abort_ext(file, function, line, "%s: %s", msg, res);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ORCA_WASM3_ABORT(runtime, err, msg) orca_wasm3_abort(runtime, err, __FILE__, __FUNCTION__, __LINE__, msg)
 | 
			
		||||
 | 
			
		||||
void* oc_runtime_env_ptr_to_native(oc_runtime_env* env, void* wasmPtr, u32 length)
 | 
			
		||||
{
 | 
			
		||||
    // We can't use the runtime's memory pointer directly because wasm3 embeds a
 | 
			
		||||
    // header at the beginning of the block we give it.
 | 
			
		||||
    u64 bufferIndex = (u64)wasmPtr & 0xffffffff;
 | 
			
		||||
    u32 memSize = 0;
 | 
			
		||||
    char* memory = (char*)m3_GetMemory(orca->runtime.m3Runtime, &memSize, 0);
 | 
			
		||||
    char* memory = (char*)m3_GetMemory(env->m3Runtime, &memSize, 0);
 | 
			
		||||
 | 
			
		||||
    if(bufferIndex + length < memSize)
 | 
			
		||||
    {
 | 
			
		||||
        char* nativePtr = memory + bufferIndex;
 | 
			
		||||
        return nativePtr;
 | 
			
		||||
    }
 | 
			
		||||
    //TODO directly abort here?
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* oc_runtime_ptr_to_native(oc_runtime* orca, void* wasmPtr, u32 length)
 | 
			
		||||
{
 | 
			
		||||
    return (oc_runtime_env_ptr_to_native(&orca->env, wasmPtr, length));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* oc_wasm_arena_push(oc_runtime_env* env, i32 arenaIndex, u64 size)
 | 
			
		||||
{
 | 
			
		||||
    void* retValues[1] = { 0 };
 | 
			
		||||
    const void* retPointers[1] = { &retValues[0] };
 | 
			
		||||
    const void* args[2] = { &arenaIndex, &size };
 | 
			
		||||
 | 
			
		||||
    M3Result res = m3_Call(env->exports[OC_EXPORT_ARENA_PUSH], 2, args);
 | 
			
		||||
    if(res)
 | 
			
		||||
    {
 | 
			
		||||
        ORCA_WASM3_ABORT(env->m3Runtime, res, "Runtime error");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res = m3_GetResults(env->exports[OC_EXPORT_ARENA_PUSH], 1, retPointers);
 | 
			
		||||
    if(res)
 | 
			
		||||
    {
 | 
			
		||||
        ORCA_WASM3_ABORT(env->m3Runtime, res, "Runtime error");
 | 
			
		||||
    }
 | 
			
		||||
    void* ptr = oc_runtime_env_ptr_to_native(env, retValues[0], size);
 | 
			
		||||
    return (ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void oc_runtime_window_set_title(oc_str8 title)
 | 
			
		||||
{
 | 
			
		||||
    title.ptr = oc_runtime_ptr_to_native(oc_runtime_get(), title.ptr, title.len);
 | 
			
		||||
| 
						 | 
				
			
			@ -231,8 +269,8 @@ void orca_surface_render_commands(oc_surface surface,
 | 
			
		|||
{
 | 
			
		||||
    oc_runtime* app = &__orcaApp;
 | 
			
		||||
 | 
			
		||||
    char* memBase = app->runtime.wasmMemory.ptr;
 | 
			
		||||
    u32 memSize = app->runtime.wasmMemory.committed;
 | 
			
		||||
    char* memBase = app->env.wasmMemory.ptr;
 | 
			
		||||
    u32 memSize = app->env.wasmMemory.committed;
 | 
			
		||||
    if(((char*)primitives > memBase)
 | 
			
		||||
       && ((char*)primitives + primitiveCount * sizeof(oc_primitive) - memBase <= memSize)
 | 
			
		||||
       && ((char*)elements > memBase)
 | 
			
		||||
| 
						 | 
				
			
			@ -350,27 +388,11 @@ void oc_runtime_env_init(oc_runtime_env* runtime)
 | 
			
		|||
#include "wasmbind/io_api_bind_gen.c"
 | 
			
		||||
#include "wasmbind/surface_api_bind_gen.c"
 | 
			
		||||
 | 
			
		||||
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
 | 
			
		||||
{
 | 
			
		||||
    M3ErrorInfo errInfo = { 0 };
 | 
			
		||||
    m3_GetErrorInfo(runtime, &errInfo);
 | 
			
		||||
    if(errInfo.message && res == errInfo.result)
 | 
			
		||||
    {
 | 
			
		||||
        oc_abort_ext(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        oc_abort_ext(file, function, line, "%s: %s", msg, res);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ORCA_WASM3_ABORT(runtime, err, msg) orca_wasm3_abort(runtime, err, __FILE__, __FUNCTION__, __LINE__, msg)
 | 
			
		||||
 | 
			
		||||
i32 orca_runloop(void* user)
 | 
			
		||||
{
 | 
			
		||||
    oc_runtime* app = &__orcaApp;
 | 
			
		||||
 | 
			
		||||
    oc_runtime_env_init(&app->runtime);
 | 
			
		||||
    oc_runtime_env_init(&app->env);
 | 
			
		||||
 | 
			
		||||
    //NOTE: loads wasm module
 | 
			
		||||
    const char* bundleNameCString = "module";
 | 
			
		||||
| 
						 | 
				
			
			@ -386,42 +408,42 @@ i32 orca_runloop(void* user)
 | 
			
		|||
    u64 wasmSize = ftell(file);
 | 
			
		||||
    rewind(file);
 | 
			
		||||
 | 
			
		||||
    app->runtime.wasmBytecode.len = wasmSize;
 | 
			
		||||
    app->runtime.wasmBytecode.ptr = oc_malloc_array(char, wasmSize);
 | 
			
		||||
    fread(app->runtime.wasmBytecode.ptr, 1, app->runtime.wasmBytecode.len, file);
 | 
			
		||||
    app->env.wasmBytecode.len = wasmSize;
 | 
			
		||||
    app->env.wasmBytecode.ptr = oc_malloc_array(char, wasmSize);
 | 
			
		||||
    fread(app->env.wasmBytecode.ptr, 1, app->env.wasmBytecode.len, file);
 | 
			
		||||
    fclose(file);
 | 
			
		||||
 | 
			
		||||
    u32 stackSize = 65536;
 | 
			
		||||
    app->runtime.m3Env = m3_NewEnvironment();
 | 
			
		||||
    app->env.m3Env = m3_NewEnvironment();
 | 
			
		||||
 | 
			
		||||
    app->runtime.m3Runtime = m3_NewRuntime(app->runtime.m3Env, stackSize, NULL);
 | 
			
		||||
    app->env.m3Runtime = m3_NewRuntime(app->env.m3Env, stackSize, NULL);
 | 
			
		||||
    //NOTE: host memory will be freed when runtime is freed.
 | 
			
		||||
    m3_RuntimeSetMemoryCallbacks(app->runtime.m3Runtime, wasm_memory_resize_callback, wasm_memory_free_callback, &app->runtime.wasmMemory);
 | 
			
		||||
    m3_RuntimeSetMemoryCallbacks(app->env.m3Runtime, wasm_memory_resize_callback, wasm_memory_free_callback, &app->env.wasmMemory);
 | 
			
		||||
 | 
			
		||||
    M3Result res = m3_ParseModule(app->runtime.m3Env, &app->runtime.m3Module, (u8*)app->runtime.wasmBytecode.ptr, app->runtime.wasmBytecode.len);
 | 
			
		||||
    M3Result res = m3_ParseModule(app->env.m3Env, &app->env.m3Module, (u8*)app->env.wasmBytecode.ptr, app->env.wasmBytecode.len);
 | 
			
		||||
    if(res)
 | 
			
		||||
    {
 | 
			
		||||
        ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't parse its web assembly module");
 | 
			
		||||
        ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't parse its web assembly module");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res = m3_LoadModule(app->runtime.m3Runtime, app->runtime.m3Module);
 | 
			
		||||
    res = m3_LoadModule(app->env.m3Runtime, app->env.m3Module);
 | 
			
		||||
    if(res)
 | 
			
		||||
    {
 | 
			
		||||
        ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't load its web assembly module into the runtime");
 | 
			
		||||
        ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't load its web assembly module into the runtime");
 | 
			
		||||
    }
 | 
			
		||||
    m3_SetModuleName(app->runtime.m3Module, bundleNameCString);
 | 
			
		||||
    m3_SetModuleName(app->env.m3Module, bundleNameCString);
 | 
			
		||||
 | 
			
		||||
    oc_arena_clear(oc_scratch());
 | 
			
		||||
 | 
			
		||||
    //NOTE: bind orca APIs
 | 
			
		||||
    {
 | 
			
		||||
        int err = 0;
 | 
			
		||||
        err |= bindgen_link_core_api(app->runtime.m3Module);
 | 
			
		||||
        err |= bindgen_link_surface_api(app->runtime.m3Module);
 | 
			
		||||
        err |= bindgen_link_clock_api(app->runtime.m3Module);
 | 
			
		||||
        err |= bindgen_link_io_api(app->runtime.m3Module);
 | 
			
		||||
        err |= bindgen_link_gles_api(app->runtime.m3Module);
 | 
			
		||||
        err |= manual_link_gles_api(app->runtime.m3Module);
 | 
			
		||||
        err |= bindgen_link_core_api(app->env.m3Module);
 | 
			
		||||
        err |= bindgen_link_surface_api(app->env.m3Module);
 | 
			
		||||
        err |= bindgen_link_clock_api(app->env.m3Module);
 | 
			
		||||
        err |= bindgen_link_io_api(app->env.m3Module);
 | 
			
		||||
        err |= bindgen_link_gles_api(app->env.m3Module);
 | 
			
		||||
        err |= manual_link_gles_api(app->env.m3Module);
 | 
			
		||||
 | 
			
		||||
        if(err)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -429,10 +451,10 @@ i32 orca_runloop(void* user)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //NOTE: compile
 | 
			
		||||
    res = m3_CompileModule(app->runtime.m3Module);
 | 
			
		||||
    res = m3_CompileModule(app->env.m3Module);
 | 
			
		||||
    if(res)
 | 
			
		||||
    {
 | 
			
		||||
        ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't compile its web assembly module");
 | 
			
		||||
        ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't compile its web assembly module");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //NOTE: Find and type check event handlers.
 | 
			
		||||
| 
						 | 
				
			
			@ -440,7 +462,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
    {
 | 
			
		||||
        const oc_export_desc* desc = &OC_EXPORT_DESC[i];
 | 
			
		||||
        IM3Function handler = 0;
 | 
			
		||||
        m3_FindFunction(&handler, app->runtime.m3Runtime, desc->name.ptr);
 | 
			
		||||
        m3_FindFunction(&handler, app->env.m3Runtime, desc->name.ptr);
 | 
			
		||||
 | 
			
		||||
        if(handler)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -481,7 +503,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
 | 
			
		||||
            if(checked)
 | 
			
		||||
            {
 | 
			
		||||
                app->runtime.exports[i] = handler;
 | 
			
		||||
                app->env.exports[i] = handler;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -491,8 +513,8 @@ i32 orca_runloop(void* user)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    //NOTE: get location of the raw event slot
 | 
			
		||||
    IM3Global rawEventGlobal = m3_FindGlobal(app->runtime.m3Module, "oc_rawEvent");
 | 
			
		||||
    app->runtime.rawEventOffset = (u32)rawEventGlobal->intValue;
 | 
			
		||||
    IM3Global rawEventGlobal = m3_FindGlobal(app->env.m3Module, "oc_rawEvent");
 | 
			
		||||
    app->env.rawEventOffset = (u32)rawEventGlobal->intValue;
 | 
			
		||||
 | 
			
		||||
    //NOTE: preopen the app local root dir
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -502,11 +524,11 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                          .open.rights = OC_FILE_ACCESS_READ | OC_FILE_ACCESS_WRITE,
 | 
			
		||||
                          .size = localRootPath.len,
 | 
			
		||||
                          .buffer = localRootPath.ptr };
 | 
			
		||||
        oc_io_cmp cmp = oc_io_wait_single_req_with_table(&req, &app->fileTable);
 | 
			
		||||
        oc_io_cmp cmp = oc_io_wait_single_req_for_table(&req, &app->fileTable);
 | 
			
		||||
        app->rootDir = cmp.handle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IM3Function* exports = app->runtime.exports;
 | 
			
		||||
    IM3Function* exports = app->env.exports;
 | 
			
		||||
 | 
			
		||||
    //NOTE: call init handler
 | 
			
		||||
    if(exports[OC_EXPORT_ON_INIT])
 | 
			
		||||
| 
						 | 
				
			
			@ -514,7 +536,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
        M3Result res = m3_Call(exports[OC_EXPORT_ON_INIT], 0, 0);
 | 
			
		||||
        if(res)
 | 
			
		||||
        {
 | 
			
		||||
            ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
            ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -527,7 +549,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
        M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
 | 
			
		||||
        if(res)
 | 
			
		||||
        {
 | 
			
		||||
            ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
            ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -547,14 +569,14 @@ i32 orca_runloop(void* user)
 | 
			
		|||
            if(exports[OC_EXPORT_RAW_EVENT])
 | 
			
		||||
            {
 | 
			
		||||
#ifndef M3_BIG_ENDIAN
 | 
			
		||||
                oc_event* eventPtr = (oc_event*)wasm_memory_offset_to_ptr(&app->runtime.wasmMemory, app->runtime.rawEventOffset);
 | 
			
		||||
                oc_event* eventPtr = (oc_event*)wasm_memory_offset_to_ptr(&app->env.wasmMemory, app->env.rawEventOffset);
 | 
			
		||||
                memcpy(eventPtr, event, sizeof(*event));
 | 
			
		||||
 | 
			
		||||
                const void* args[1] = { &app->runtime.rawEventOffset };
 | 
			
		||||
                const void* args[1] = { &app->env.rawEventOffset };
 | 
			
		||||
                M3Result res = m3_Call(exports[OC_EXPORT_RAW_EVENT], 1, args);
 | 
			
		||||
                if(res)
 | 
			
		||||
                {
 | 
			
		||||
                    ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                    ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                }
 | 
			
		||||
#else
 | 
			
		||||
                oc_log_error("oc_on_raw_event() is not supported on big endian platforms");
 | 
			
		||||
| 
						 | 
				
			
			@ -565,7 +587,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
            {
 | 
			
		||||
                case OC_EVENT_WINDOW_CLOSE:
 | 
			
		||||
                {
 | 
			
		||||
					oc_request_quit();
 | 
			
		||||
                    oc_request_quit();
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -581,7 +603,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                        M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
 | 
			
		||||
                        if(res)
 | 
			
		||||
                        {
 | 
			
		||||
                            ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -598,7 +620,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                            M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_DOWN], 1, args);
 | 
			
		||||
                            if(res)
 | 
			
		||||
                            {
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -611,7 +633,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                            M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_UP], 1, args);
 | 
			
		||||
                            if(res)
 | 
			
		||||
                            {
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -626,7 +648,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                        M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_MOVE], 4, args);
 | 
			
		||||
                        if(res)
 | 
			
		||||
                        {
 | 
			
		||||
                            ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -649,7 +671,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                            M3Result res = m3_Call(exports[OC_EXPORT_KEY_DOWN], 1, args);
 | 
			
		||||
                            if(res)
 | 
			
		||||
                            {
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -661,7 +683,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
                            M3Result res = m3_Call(exports[OC_EXPORT_KEY_UP], 1, args);
 | 
			
		||||
                            if(res)
 | 
			
		||||
                            {
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                                ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -680,7 +702,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
            M3Result res = m3_Call(exports[OC_EXPORT_FRAME_REFRESH], 0, 0);
 | 
			
		||||
            if(res)
 | 
			
		||||
            {
 | 
			
		||||
                ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
                ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -837,7 +859,7 @@ i32 orca_runloop(void* user)
 | 
			
		|||
        M3Result res = m3_Call(exports[OC_EXPORT_TERMINATE], 0, 0);
 | 
			
		||||
        if(res)
 | 
			
		||||
        {
 | 
			
		||||
            ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
 | 
			
		||||
            ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,8 @@
 | 
			
		|||
    X(OC_EXPORT_FRAME_REFRESH, "oc_on_frame_refresh", "", "") \
 | 
			
		||||
    X(OC_EXPORT_FRAME_RESIZE, "oc_on_resize", "", "ii")       \
 | 
			
		||||
    X(OC_EXPORT_RAW_EVENT, "oc_on_raw_event", "", "i")        \
 | 
			
		||||
    X(OC_EXPORT_TERMINATE, "oc_on_terminate", "", "")
 | 
			
		||||
    X(OC_EXPORT_TERMINATE, "oc_on_terminate", "", "")         \
 | 
			
		||||
    X(OC_EXPORT_ARENA_PUSH, "oc_arena_push_stub", "i", "iI")
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -111,13 +112,13 @@ typedef struct oc_debug_overlay
 | 
			
		|||
 | 
			
		||||
typedef struct oc_runtime
 | 
			
		||||
{
 | 
			
		||||
	bool quit;
 | 
			
		||||
    bool quit;
 | 
			
		||||
    oc_window window;
 | 
			
		||||
 | 
			
		||||
    oc_file_table fileTable;
 | 
			
		||||
    oc_file rootDir;
 | 
			
		||||
 | 
			
		||||
    oc_runtime_env runtime;
 | 
			
		||||
    oc_runtime_env env;
 | 
			
		||||
 | 
			
		||||
    oc_debug_overlay debugOverlay;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,5 +128,6 @@ oc_runtime* oc_runtime_get();
 | 
			
		|||
oc_runtime_env* oc_runtime_env_get();
 | 
			
		||||
 | 
			
		||||
void* oc_runtime_ptr_to_native(oc_runtime* runtime, void* wasmPtr, u32 length);
 | 
			
		||||
void* oc_wasm_arena_push(oc_runtime_env* env, i32 arenaIndex, u64 size);
 | 
			
		||||
 | 
			
		||||
#endif //__RUNTIME_H_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										157
									
								
								src/runtime_io.c
								
								
								
								
							
							
						
						
									
										157
									
								
								src/runtime_io.c
								
								
								
								
							| 
						 | 
				
			
			@ -30,7 +30,7 @@ oc_io_cmp oc_runtime_io_wait_single_req(oc_io_req* wasmReq)
 | 
			
		|||
                req.open.flags |= OC_FILE_OPEN_RESTRICT;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        cmp = oc_io_wait_single_req_with_table(&req, &orca->fileTable);
 | 
			
		||||
        cmp = oc_io_wait_single_req_for_table(&req, &orca->fileTable);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,3 +39,158 @@ oc_io_cmp oc_runtime_io_wait_single_req(oc_io_req* wasmReq)
 | 
			
		|||
 | 
			
		||||
    return (cmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oc_file oc_file_open_with_request_bridge(oc_str8 path, oc_file_access rights, oc_file_open_flags flags)
 | 
			
		||||
{
 | 
			
		||||
    oc_file file = oc_file_nil();
 | 
			
		||||
    oc_runtime* orca = oc_runtime_get();
 | 
			
		||||
 | 
			
		||||
    path.ptr = oc_runtime_ptr_to_native(orca, path.ptr, path.len);
 | 
			
		||||
    if(path.ptr)
 | 
			
		||||
    {
 | 
			
		||||
        file = oc_file_open_with_request_for_table(path, rights, flags, &orca->fileTable);
 | 
			
		||||
    }
 | 
			
		||||
    return (file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_list
 | 
			
		||||
{
 | 
			
		||||
    u32 first;
 | 
			
		||||
    u32 last;
 | 
			
		||||
} oc_wasm_list;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_list_elt
 | 
			
		||||
{
 | 
			
		||||
    u32 prev;
 | 
			
		||||
    u32 next;
 | 
			
		||||
} oc_wasm_list_elt;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_str8
 | 
			
		||||
{
 | 
			
		||||
    u64 len;
 | 
			
		||||
    u32 ptr;
 | 
			
		||||
} oc_wasm_str8;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_str8_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_wasm_list_elt listElt;
 | 
			
		||||
    oc_wasm_str8 string;
 | 
			
		||||
 | 
			
		||||
} oc_wasm_str8_elt;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_str8_list
 | 
			
		||||
{
 | 
			
		||||
    oc_wasm_list list;
 | 
			
		||||
    u64 eltCount;
 | 
			
		||||
    u64 len;
 | 
			
		||||
} oc_wasm_str8_list;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_file_dialog_desc
 | 
			
		||||
{
 | 
			
		||||
    oc_file_dialog_kind kind;
 | 
			
		||||
    oc_file_dialog_flags flags;
 | 
			
		||||
    oc_wasm_str8 title;
 | 
			
		||||
    oc_wasm_str8 okLabel;
 | 
			
		||||
    oc_file startAt;
 | 
			
		||||
    oc_wasm_str8 startPath;
 | 
			
		||||
    oc_wasm_str8_list filters;
 | 
			
		||||
 | 
			
		||||
} oc_wasm_file_dialog_desc;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_file_open_with_dialog_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_wasm_list_elt listElt;
 | 
			
		||||
    oc_file file;
 | 
			
		||||
} oc_wasm_file_open_with_dialog_elt;
 | 
			
		||||
 | 
			
		||||
typedef struct oc_wasm_file_open_with_dialog_result
 | 
			
		||||
{
 | 
			
		||||
    oc_file_dialog_button button;
 | 
			
		||||
    oc_file file;
 | 
			
		||||
    oc_wasm_list selection;
 | 
			
		||||
 | 
			
		||||
} oc_wasm_file_open_with_dialog_result;
 | 
			
		||||
 | 
			
		||||
oc_wasm_file_open_with_dialog_result oc_file_open_with_dialog_bridge(i32 wasmArenaIndex,
 | 
			
		||||
                                                                     oc_file_access rights,
 | 
			
		||||
                                                                     oc_file_open_flags flags,
 | 
			
		||||
                                                                     oc_wasm_file_dialog_desc* desc)
 | 
			
		||||
{
 | 
			
		||||
    oc_runtime* orca = oc_runtime_get();
 | 
			
		||||
    oc_arena_scope scratch = oc_scratch_begin();
 | 
			
		||||
 | 
			
		||||
    oc_file_dialog_desc nativeDesc = {
 | 
			
		||||
        .kind = desc->kind,
 | 
			
		||||
        .flags = desc->flags
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    nativeDesc.title.ptr = oc_runtime_ptr_to_native(orca, (char*)(uintptr_t)desc->title.ptr, desc->title.len);
 | 
			
		||||
    nativeDesc.title.len = desc->title.len;
 | 
			
		||||
 | 
			
		||||
    nativeDesc.okLabel.ptr = oc_runtime_ptr_to_native(orca, (char*)(uintptr_t)desc->okLabel.ptr, desc->okLabel.len);
 | 
			
		||||
    nativeDesc.okLabel.len = desc->okLabel.len;
 | 
			
		||||
 | 
			
		||||
    if(oc_file_is_nil(desc->startAt) && desc->startPath.len)
 | 
			
		||||
    {
 | 
			
		||||
        nativeDesc.startAt = orca->rootDir;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        nativeDesc.startAt = desc->startAt;
 | 
			
		||||
    }
 | 
			
		||||
    nativeDesc.startPath.ptr = oc_runtime_ptr_to_native(orca, (char*)(uintptr_t)desc->startPath.ptr, desc->startPath.len);
 | 
			
		||||
    nativeDesc.startPath.len = desc->startPath.len;
 | 
			
		||||
 | 
			
		||||
    u32 eltIndex = desc->filters.list.first;
 | 
			
		||||
    while(eltIndex)
 | 
			
		||||
    {
 | 
			
		||||
        oc_wasm_str8_elt* elt = oc_runtime_ptr_to_native(orca, (char*)(uintptr_t)eltIndex, sizeof(oc_wasm_str8_elt));
 | 
			
		||||
 | 
			
		||||
        oc_str8 filter = { 0 };
 | 
			
		||||
        filter.ptr = oc_runtime_ptr_to_native(orca, (char*)(uintptr_t)elt->string.ptr, elt->string.len);
 | 
			
		||||
        filter.len = elt->string.len;
 | 
			
		||||
 | 
			
		||||
        oc_str8_list_push(scratch.arena, &nativeDesc.filters, filter);
 | 
			
		||||
 | 
			
		||||
        oc_log_info("filter: %.*s\n", (int)filter.len, filter.ptr);
 | 
			
		||||
 | 
			
		||||
        eltIndex = elt->listElt.next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    oc_file_open_with_dialog_result nativeResult = oc_file_open_with_dialog_for_table(scratch.arena, rights, flags, &nativeDesc, &orca->fileTable);
 | 
			
		||||
 | 
			
		||||
    oc_wasm_file_open_with_dialog_result result = {
 | 
			
		||||
        .button = nativeResult.button,
 | 
			
		||||
        .file = nativeResult.file
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    u32 memSize;
 | 
			
		||||
    char* wasmMemory = (char*)m3_GetMemory(orca->env.m3Runtime, &memSize, 0);
 | 
			
		||||
    oc_wasm_file_open_with_dialog_elt* lastElt = 0;
 | 
			
		||||
 | 
			
		||||
    oc_list_for(&nativeResult.selection, elt, oc_file_open_with_dialog_elt, listElt)
 | 
			
		||||
    {
 | 
			
		||||
        oc_wasm_file_open_with_dialog_elt* wasmElt = oc_wasm_arena_push(&orca->env, wasmArenaIndex, sizeof(oc_wasm_file_open_with_dialog_elt));
 | 
			
		||||
        wasmElt->file = elt->file;
 | 
			
		||||
 | 
			
		||||
        if(result.selection.last == 0)
 | 
			
		||||
        {
 | 
			
		||||
            result.selection.first = ((char*)wasmElt - wasmMemory);
 | 
			
		||||
            result.selection.last = result.selection.first;
 | 
			
		||||
            wasmElt->listElt.prev = 0;
 | 
			
		||||
            wasmElt->listElt.next = 0;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            wasmElt->listElt.prev = result.selection.last;
 | 
			
		||||
            wasmElt->listElt.next = 0;
 | 
			
		||||
            lastElt->listElt.next = ((char*)wasmElt - wasmMemory);
 | 
			
		||||
 | 
			
		||||
            result.selection.last = ((char*)wasmElt - wasmMemory);
 | 
			
		||||
        }
 | 
			
		||||
        lastElt = wasmElt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    oc_scratch_end(scratch);
 | 
			
		||||
    return (result);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										275
									
								
								src/util/lists.h
								
								
								
								
							
							
						
						
									
										275
									
								
								src/util/lists.h
								
								
								
								
							| 
						 | 
				
			
			@ -14,13 +14,12 @@
 | 
			
		|||
#include "util/debug.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    //-------------------------------------------------------------------------
 | 
			
		||||
    // Intrusive linked lists
 | 
			
		||||
    //-------------------------------------------------------------------------
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// Intrusive linked lists
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#define oc_list_entry(ptr, type, member) \
 | 
			
		||||
    oc_container_of(ptr, type, member)
 | 
			
		||||
| 
						 | 
				
			
			@ -62,162 +61,162 @@ extern "C"
 | 
			
		|||
 | 
			
		||||
#define oc_list_pop_entry(list, type, member) (oc_list_empty(list) ? 0 : oc_list_entry(oc_list_pop(list), type, member))
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_list_elt oc_list_elt;
 | 
			
		||||
typedef struct oc_list_elt oc_list_elt;
 | 
			
		||||
 | 
			
		||||
    struct oc_list_elt
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt* next;
 | 
			
		||||
        oc_list_elt* prev;
 | 
			
		||||
    };
 | 
			
		||||
struct oc_list_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt* prev;
 | 
			
		||||
    oc_list_elt* next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_list
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt* first;
 | 
			
		||||
        oc_list_elt* last;
 | 
			
		||||
    } oc_list;
 | 
			
		||||
typedef struct oc_list
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt* first;
 | 
			
		||||
    oc_list_elt* last;
 | 
			
		||||
} oc_list;
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_init(oc_list* list)
 | 
			
		||||
static inline void oc_list_init(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    list->first = list->last = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline oc_list_elt* oc_list_begin(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    return (list->first);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline oc_list_elt* oc_list_end(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline oc_list_elt* oc_list_last(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    return (list->last);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void oc_list_insert(oc_list* list, oc_list_elt* afterElt, oc_list_elt* elt)
 | 
			
		||||
{
 | 
			
		||||
    elt->prev = afterElt;
 | 
			
		||||
    elt->next = afterElt->next;
 | 
			
		||||
    if(afterElt->next)
 | 
			
		||||
    {
 | 
			
		||||
        list->first = list->last = 0;
 | 
			
		||||
        afterElt->next->prev = elt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline oc_list_elt* oc_list_begin(oc_list* list)
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return (list->first);
 | 
			
		||||
        list->last = elt;
 | 
			
		||||
    }
 | 
			
		||||
    afterElt->next = elt;
 | 
			
		||||
 | 
			
		||||
    static inline oc_list_elt* oc_list_end(oc_list* list)
 | 
			
		||||
    OC_DEBUG_ASSERT(elt->next != elt, "oc_list_insert(): can't insert an element into itself");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void oc_list_insert_before(oc_list* list, oc_list_elt* beforeElt, oc_list_elt* elt)
 | 
			
		||||
{
 | 
			
		||||
    elt->next = beforeElt;
 | 
			
		||||
    elt->prev = beforeElt->prev;
 | 
			
		||||
 | 
			
		||||
    if(beforeElt->prev)
 | 
			
		||||
    {
 | 
			
		||||
        beforeElt->prev->next = elt;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        list->first = elt;
 | 
			
		||||
    }
 | 
			
		||||
    beforeElt->prev = elt;
 | 
			
		||||
 | 
			
		||||
    OC_DEBUG_ASSERT(elt->next != elt, "oc_list_insert_before(): can't insert an element into itself");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void oc_list_remove(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
{
 | 
			
		||||
    if(elt->prev)
 | 
			
		||||
    {
 | 
			
		||||
        elt->prev->next = elt->next;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        OC_DEBUG_ASSERT(list->first == elt);
 | 
			
		||||
        list->first = elt->next;
 | 
			
		||||
    }
 | 
			
		||||
    if(elt->next)
 | 
			
		||||
    {
 | 
			
		||||
        elt->next->prev = elt->prev;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        OC_DEBUG_ASSERT(list->last == elt);
 | 
			
		||||
        list->last = elt->prev;
 | 
			
		||||
    }
 | 
			
		||||
    elt->prev = elt->next = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void oc_list_push(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
{
 | 
			
		||||
    elt->next = list->first;
 | 
			
		||||
    elt->prev = 0;
 | 
			
		||||
    if(list->first)
 | 
			
		||||
    {
 | 
			
		||||
        list->first->prev = elt;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        list->last = elt;
 | 
			
		||||
    }
 | 
			
		||||
    list->first = elt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline oc_list_elt* oc_list_pop(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt* elt = oc_list_begin(list);
 | 
			
		||||
    if(elt != oc_list_end(list))
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_remove(list, elt);
 | 
			
		||||
        return (elt);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return (0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    static inline oc_list_elt* oc_list_last(oc_list* list)
 | 
			
		||||
static inline void oc_list_push_back(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
{
 | 
			
		||||
    elt->prev = list->last;
 | 
			
		||||
    elt->next = 0;
 | 
			
		||||
    if(list->last)
 | 
			
		||||
    {
 | 
			
		||||
        return (list->last);
 | 
			
		||||
        list->last->next = elt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_insert(oc_list* list, oc_list_elt* afterElt, oc_list_elt* elt)
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        elt->prev = afterElt;
 | 
			
		||||
        elt->next = afterElt->next;
 | 
			
		||||
        if(afterElt->next)
 | 
			
		||||
        {
 | 
			
		||||
            afterElt->next->prev = elt;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            list->last = elt;
 | 
			
		||||
        }
 | 
			
		||||
        afterElt->next = elt;
 | 
			
		||||
 | 
			
		||||
        OC_DEBUG_ASSERT(elt->next != elt, "oc_list_insert(): can't insert an element into itself");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_insert_before(oc_list* list, oc_list_elt* beforeElt, oc_list_elt* elt)
 | 
			
		||||
    {
 | 
			
		||||
        elt->next = beforeElt;
 | 
			
		||||
        elt->prev = beforeElt->prev;
 | 
			
		||||
 | 
			
		||||
        if(beforeElt->prev)
 | 
			
		||||
        {
 | 
			
		||||
            beforeElt->prev->next = elt;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            list->first = elt;
 | 
			
		||||
        }
 | 
			
		||||
        beforeElt->prev = elt;
 | 
			
		||||
 | 
			
		||||
        OC_DEBUG_ASSERT(elt->next != elt, "oc_list_insert_before(): can't insert an element into itself");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_remove(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
    {
 | 
			
		||||
        if(elt->prev)
 | 
			
		||||
        {
 | 
			
		||||
            elt->prev->next = elt->next;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            OC_DEBUG_ASSERT(list->first == elt);
 | 
			
		||||
            list->first = elt->next;
 | 
			
		||||
        }
 | 
			
		||||
        if(elt->next)
 | 
			
		||||
        {
 | 
			
		||||
            elt->next->prev = elt->prev;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            OC_DEBUG_ASSERT(list->last == elt);
 | 
			
		||||
            list->last = elt->prev;
 | 
			
		||||
        }
 | 
			
		||||
        elt->prev = elt->next = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_push(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
    {
 | 
			
		||||
        elt->next = list->first;
 | 
			
		||||
        elt->prev = 0;
 | 
			
		||||
        if(list->first)
 | 
			
		||||
        {
 | 
			
		||||
            list->first->prev = elt;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            list->last = elt;
 | 
			
		||||
        }
 | 
			
		||||
        list->first = elt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline oc_list_elt* oc_list_pop(oc_list* list)
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt* elt = oc_list_begin(list);
 | 
			
		||||
        if(elt != oc_list_end(list))
 | 
			
		||||
        {
 | 
			
		||||
            oc_list_remove(list, elt);
 | 
			
		||||
            return (elt);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return (0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void oc_list_push_back(oc_list* list, oc_list_elt* elt)
 | 
			
		||||
    {
 | 
			
		||||
        elt->prev = list->last;
 | 
			
		||||
        elt->next = 0;
 | 
			
		||||
        if(list->last)
 | 
			
		||||
        {
 | 
			
		||||
            list->last->next = elt;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            list->first = elt;
 | 
			
		||||
        }
 | 
			
		||||
        list->last = elt;
 | 
			
		||||
    }
 | 
			
		||||
    list->last = elt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define oc_list_append(a, b) oc_list_push_back(a, b)
 | 
			
		||||
 | 
			
		||||
    static inline oc_list_elt* oc_list_pop_back(oc_list* list)
 | 
			
		||||
static inline oc_list_elt* oc_list_pop_back(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt* elt = oc_list_last(list);
 | 
			
		||||
    if(elt != oc_list_end(list))
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt* elt = oc_list_last(list);
 | 
			
		||||
        if(elt != oc_list_end(list))
 | 
			
		||||
        {
 | 
			
		||||
            oc_list_remove(list, elt);
 | 
			
		||||
            return (elt);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return (0);
 | 
			
		||||
        }
 | 
			
		||||
        oc_list_remove(list, elt);
 | 
			
		||||
        return (elt);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return (0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    static inline bool oc_list_empty(oc_list* list)
 | 
			
		||||
    {
 | 
			
		||||
        return (list->first == 0 || list->last == 0);
 | 
			
		||||
    }
 | 
			
		||||
static inline bool oc_list_empty(oc_list* list)
 | 
			
		||||
{
 | 
			
		||||
    return (list->first == 0 || list->last == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} // extern "C"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -241,7 +241,7 @@ ORCA_API oc_arena* oc_scratch_next(oc_arena* used)
 | 
			
		|||
    return (res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ORCA_API oc_arena_scope oc_scratch_begin()
 | 
			
		||||
ORCA_API oc_arena_scope oc_scratch_begin(void)
 | 
			
		||||
{
 | 
			
		||||
    oc_arena* scratch = oc_scratch();
 | 
			
		||||
    oc_arena_scope scope = oc_arena_scope_begin(scratch);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,94 +14,93 @@
 | 
			
		|||
#include "util/typedefs.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
    //NOTE(martin): memory arena
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
//NOTE(martin): memory arena
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_arena_chunk
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt listElt;
 | 
			
		||||
        char* ptr;
 | 
			
		||||
        u64 offset;
 | 
			
		||||
        u64 committed;
 | 
			
		||||
        u64 cap;
 | 
			
		||||
    } oc_arena_chunk;
 | 
			
		||||
typedef struct oc_arena_chunk
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt listElt;
 | 
			
		||||
    char* ptr;
 | 
			
		||||
    u64 offset;
 | 
			
		||||
    u64 committed;
 | 
			
		||||
    u64 cap;
 | 
			
		||||
} oc_arena_chunk;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_arena
 | 
			
		||||
    {
 | 
			
		||||
        oc_base_allocator* base;
 | 
			
		||||
        oc_list chunks;
 | 
			
		||||
        oc_arena_chunk* currentChunk;
 | 
			
		||||
typedef struct oc_arena
 | 
			
		||||
{
 | 
			
		||||
    oc_base_allocator* base;
 | 
			
		||||
    oc_list chunks;
 | 
			
		||||
    oc_arena_chunk* currentChunk;
 | 
			
		||||
 | 
			
		||||
    } oc_arena;
 | 
			
		||||
} oc_arena;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_arena_scope
 | 
			
		||||
    {
 | 
			
		||||
        oc_arena* arena;
 | 
			
		||||
        oc_arena_chunk* chunk;
 | 
			
		||||
        u64 offset;
 | 
			
		||||
    } oc_arena_scope;
 | 
			
		||||
typedef struct oc_arena_scope
 | 
			
		||||
{
 | 
			
		||||
    oc_arena* arena;
 | 
			
		||||
    oc_arena_chunk* chunk;
 | 
			
		||||
    u64 offset;
 | 
			
		||||
} oc_arena_scope;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_arena_options
 | 
			
		||||
    {
 | 
			
		||||
        oc_base_allocator* base;
 | 
			
		||||
        u64 reserve;
 | 
			
		||||
    } oc_arena_options;
 | 
			
		||||
typedef struct oc_arena_options
 | 
			
		||||
{
 | 
			
		||||
    oc_base_allocator* base;
 | 
			
		||||
    u64 reserve;
 | 
			
		||||
} oc_arena_options;
 | 
			
		||||
 | 
			
		||||
    ORCA_API void oc_arena_init(oc_arena* arena);
 | 
			
		||||
    ORCA_API void oc_arena_init_with_options(oc_arena* arena, oc_arena_options* options);
 | 
			
		||||
    ORCA_API void oc_arena_cleanup(oc_arena* arena);
 | 
			
		||||
ORCA_API void oc_arena_init(oc_arena* arena);
 | 
			
		||||
ORCA_API void oc_arena_init_with_options(oc_arena* arena, oc_arena_options* options);
 | 
			
		||||
ORCA_API void oc_arena_cleanup(oc_arena* arena);
 | 
			
		||||
 | 
			
		||||
    ORCA_API void* oc_arena_push(oc_arena* arena, u64 size);
 | 
			
		||||
    ORCA_API void oc_arena_clear(oc_arena* arena);
 | 
			
		||||
ORCA_API void* oc_arena_push(oc_arena* arena, u64 size);
 | 
			
		||||
ORCA_API void oc_arena_clear(oc_arena* arena);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_arena_scope oc_arena_scope_begin(oc_arena* arena);
 | 
			
		||||
    ORCA_API void oc_arena_scope_end(oc_arena_scope scope);
 | 
			
		||||
ORCA_API oc_arena_scope oc_arena_scope_begin(oc_arena* arena);
 | 
			
		||||
ORCA_API void oc_arena_scope_end(oc_arena_scope scope);
 | 
			
		||||
 | 
			
		||||
#define oc_arena_push_type(arena, type) ((type*)oc_arena_push(arena, sizeof(type)))
 | 
			
		||||
#define oc_arena_push_array(arena, type, count) ((type*)oc_arena_push(arena, sizeof(type) * (count)))
 | 
			
		||||
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
    //NOTE(martin): memory pool
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
//NOTE(martin): memory pool
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
    //TODO: we could probably remove pool. Most of the time we construct pool on top of
 | 
			
		||||
    //      arenas "manually" with different free lists per object types...
 | 
			
		||||
//TODO: we could probably remove pool. Most of the time we construct pool on top of
 | 
			
		||||
//      arenas "manually" with different free lists per object types...
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_pool
 | 
			
		||||
    {
 | 
			
		||||
        oc_arena arena;
 | 
			
		||||
        oc_list freeList;
 | 
			
		||||
        u64 blockSize;
 | 
			
		||||
    } oc_pool;
 | 
			
		||||
typedef struct oc_pool
 | 
			
		||||
{
 | 
			
		||||
    oc_arena arena;
 | 
			
		||||
    oc_list freeList;
 | 
			
		||||
    u64 blockSize;
 | 
			
		||||
} oc_pool;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_pool_options
 | 
			
		||||
    {
 | 
			
		||||
        oc_base_allocator* base;
 | 
			
		||||
        u64 reserve;
 | 
			
		||||
    } oc_pool_options;
 | 
			
		||||
typedef struct oc_pool_options
 | 
			
		||||
{
 | 
			
		||||
    oc_base_allocator* base;
 | 
			
		||||
    u64 reserve;
 | 
			
		||||
} oc_pool_options;
 | 
			
		||||
 | 
			
		||||
    ORCA_API void oc_pool_init(oc_pool* pool, u64 blockSize);
 | 
			
		||||
    ORCA_API void oc_pool_init_with_options(oc_pool* pool, u64 blockSize, oc_pool_options* options);
 | 
			
		||||
    ORCA_API void oc_pool_cleanup(oc_pool* pool);
 | 
			
		||||
ORCA_API void oc_pool_init(oc_pool* pool, u64 blockSize);
 | 
			
		||||
ORCA_API void oc_pool_init_with_options(oc_pool* pool, u64 blockSize, oc_pool_options* options);
 | 
			
		||||
ORCA_API void oc_pool_cleanup(oc_pool* pool);
 | 
			
		||||
 | 
			
		||||
    ORCA_API void* oc_pool_alloc(oc_pool* pool);
 | 
			
		||||
    ORCA_API void oc_pool_recycle(oc_pool* pool, void* ptr);
 | 
			
		||||
    ORCA_API void oc_pool_clear(oc_pool* pool);
 | 
			
		||||
ORCA_API void* oc_pool_alloc(oc_pool* pool);
 | 
			
		||||
ORCA_API void oc_pool_recycle(oc_pool* pool, void* ptr);
 | 
			
		||||
ORCA_API void oc_pool_clear(oc_pool* pool);
 | 
			
		||||
 | 
			
		||||
#define oc_pool_alloc_type(arena, type) ((type*)oc_pool_alloc(arena))
 | 
			
		||||
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
    //NOTE(martin): per-thread implicit scratch arena
 | 
			
		||||
    //--------------------------------------------------------------------------------
 | 
			
		||||
    ORCA_API oc_arena* oc_scratch();
 | 
			
		||||
    ORCA_API oc_arena* oc_scratch_next(oc_arena* used);
 | 
			
		||||
    ORCA_API oc_arena_scope oc_scratch_begin();
 | 
			
		||||
    ORCA_API oc_arena_scope oc_scratch_begin_next(oc_arena* used);
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
//NOTE(martin): per-thread implicit scratch arena
 | 
			
		||||
//--------------------------------------------------------------------------------
 | 
			
		||||
ORCA_API oc_arena* oc_scratch();
 | 
			
		||||
ORCA_API oc_arena* oc_scratch_next(oc_arena* used);
 | 
			
		||||
ORCA_API oc_arena_scope oc_scratch_begin(void);
 | 
			
		||||
ORCA_API oc_arena_scope oc_scratch_begin_next(oc_arena* used);
 | 
			
		||||
 | 
			
		||||
#define oc_scratch_end(scope) oc_arena_scope_end(scope)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,10 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /*NOTE:
 | 
			
		||||
/*NOTE:
 | 
			
		||||
	By convention, functions that take an arena and return a string slice allocated on
 | 
			
		||||
	this arena, always allocate one more element and null-terminate the string. This is
 | 
			
		||||
	done so we can pass those strings directly to C APIs that requires C strings without
 | 
			
		||||
| 
						 | 
				
			
			@ -31,14 +30,14 @@ extern "C"
 | 
			
		|||
	into the original string. Only the _list nodes_ are allocated on the arena.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    // u8 strings
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    typedef struct oc_str8
 | 
			
		||||
    {
 | 
			
		||||
        u64 len;
 | 
			
		||||
        char* ptr;
 | 
			
		||||
    } oc_str8;
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
// u8 strings
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
typedef struct oc_str8
 | 
			
		||||
{
 | 
			
		||||
    u64 len;
 | 
			
		||||
    char* ptr;
 | 
			
		||||
} oc_str8;
 | 
			
		||||
 | 
			
		||||
#define OC_STR8(s) ((oc_str8){ .len = (s) ? strlen(s) : 0, .ptr = (char*)s })
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,109 +50,109 @@ extern "C"
 | 
			
		|||
#define oc_str8_lp(s) ((s).len), ((s).ptr)
 | 
			
		||||
#define oc_str8_ip(s) (int)oc_str8_lp(s)
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_from_buffer(u64 len, char* buffer);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_slice(oc_str8 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_from_buffer(u64 len, char* buffer);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_slice(oc_str8 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_push_buffer(oc_arena* arena, u64 len, char* buffer);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_push_cstring(oc_arena* arena, const char* str);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_push_copy(oc_arena* arena, oc_str8 s);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_push_slice(oc_arena* arena, oc_str8 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_push_buffer(oc_arena* arena, u64 len, char* buffer);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_push_cstring(oc_arena* arena, const char* str);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_push_copy(oc_arena* arena, oc_str8 s);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_push_slice(oc_arena* arena, oc_str8 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_pushfv(oc_arena* arena, const char* format, va_list args);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_pushf(oc_arena* arena, const char* format, ...);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_pushfv(oc_arena* arena, const char* format, va_list args);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_pushf(oc_arena* arena, const char* format, ...);
 | 
			
		||||
 | 
			
		||||
    ORCA_API int oc_str8_cmp(oc_str8 s1, oc_str8 s2);
 | 
			
		||||
ORCA_API int oc_str8_cmp(oc_str8 s1, oc_str8 s2);
 | 
			
		||||
 | 
			
		||||
    ORCA_API char* oc_str8_to_cstring(oc_arena* arena, oc_str8 string);
 | 
			
		||||
ORCA_API char* oc_str8_to_cstring(oc_arena* arena, oc_str8 string);
 | 
			
		||||
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    // string lists
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    typedef struct oc_str8_elt
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt listElt;
 | 
			
		||||
        oc_str8 string;
 | 
			
		||||
    } oc_str8_elt;
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
// string lists
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
typedef struct oc_str8_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt listElt;
 | 
			
		||||
    oc_str8 string;
 | 
			
		||||
} oc_str8_elt;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_str8_list
 | 
			
		||||
    {
 | 
			
		||||
        oc_list list;
 | 
			
		||||
        u64 eltCount;
 | 
			
		||||
        u64 len;
 | 
			
		||||
    } oc_str8_list;
 | 
			
		||||
typedef struct oc_str8_list
 | 
			
		||||
{
 | 
			
		||||
    oc_list list;
 | 
			
		||||
    u64 eltCount;
 | 
			
		||||
    u64 len;
 | 
			
		||||
} oc_str8_list;
 | 
			
		||||
 | 
			
		||||
    ORCA_API void oc_str8_list_push(oc_arena* arena, oc_str8_list* list, oc_str8 str);
 | 
			
		||||
    ORCA_API void oc_str8_list_pushf(oc_arena* arena, oc_str8_list* list, const char* format, ...);
 | 
			
		||||
ORCA_API void oc_str8_list_push(oc_arena* arena, oc_str8_list* list, oc_str8 str);
 | 
			
		||||
ORCA_API void oc_str8_list_pushf(oc_arena* arena, oc_str8_list* list, const char* format, ...);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_list_collate(oc_arena* arena, oc_str8_list list, oc_str8 prefix, oc_str8 separator, oc_str8 postfix);
 | 
			
		||||
    ORCA_API oc_str8 oc_str8_list_join(oc_arena* arena, oc_str8_list list);
 | 
			
		||||
    ORCA_API oc_str8_list oc_str8_split(oc_arena* arena, oc_str8 str, oc_str8_list separators);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_list_collate(oc_arena* arena, oc_str8_list list, oc_str8 prefix, oc_str8 separator, oc_str8 postfix);
 | 
			
		||||
ORCA_API oc_str8 oc_str8_list_join(oc_arena* arena, oc_str8_list list);
 | 
			
		||||
ORCA_API oc_str8_list oc_str8_split(oc_arena* arena, oc_str8 str, oc_str8_list separators);
 | 
			
		||||
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    // u16 strings
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    typedef struct oc_str16
 | 
			
		||||
    {
 | 
			
		||||
        u64 len;
 | 
			
		||||
        u16* ptr;
 | 
			
		||||
    } oc_str16;
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
// u16 strings
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
typedef struct oc_str16
 | 
			
		||||
{
 | 
			
		||||
    u64 len;
 | 
			
		||||
    u16* ptr;
 | 
			
		||||
} oc_str16;
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_from_buffer(u64 len, u16* buffer);
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_slice(oc_str16 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_from_buffer(u64 len, u16* buffer);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_slice(oc_str16 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_push_buffer(oc_arena* arena, u64 len, u16* buffer);
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_push_copy(oc_arena* arena, oc_str16 s);
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_push_slice(oc_arena* arena, oc_str16 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_push_buffer(oc_arena* arena, u64 len, u16* buffer);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_push_copy(oc_arena* arena, oc_str16 s);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_push_slice(oc_arena* arena, oc_str16 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_str16_elt
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt listElt;
 | 
			
		||||
        oc_str16 string;
 | 
			
		||||
    } oc_str16_elt;
 | 
			
		||||
typedef struct oc_str16_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt listElt;
 | 
			
		||||
    oc_str16 string;
 | 
			
		||||
} oc_str16_elt;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_str16_list
 | 
			
		||||
    {
 | 
			
		||||
        oc_list list;
 | 
			
		||||
        u64 eltCount;
 | 
			
		||||
        u64 len;
 | 
			
		||||
    } oc_str16_list;
 | 
			
		||||
typedef struct oc_str16_list
 | 
			
		||||
{
 | 
			
		||||
    oc_list list;
 | 
			
		||||
    u64 eltCount;
 | 
			
		||||
    u64 len;
 | 
			
		||||
} oc_str16_list;
 | 
			
		||||
 | 
			
		||||
    ORCA_API void oc_str16_list_push(oc_arena* arena, oc_str16_list* list, oc_str16 str);
 | 
			
		||||
    ORCA_API oc_str16 oc_str16_list_join(oc_arena* arena, oc_str16_list list);
 | 
			
		||||
    ORCA_API oc_str16_list oc_str16_split(oc_arena* arena, oc_str16 str, oc_str16_list separators);
 | 
			
		||||
ORCA_API void oc_str16_list_push(oc_arena* arena, oc_str16_list* list, oc_str16 str);
 | 
			
		||||
ORCA_API oc_str16 oc_str16_list_join(oc_arena* arena, oc_str16_list list);
 | 
			
		||||
ORCA_API oc_str16_list oc_str16_split(oc_arena* arena, oc_str16 str, oc_str16_list separators);
 | 
			
		||||
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    // u32 strings
 | 
			
		||||
    //----------------------------------------------------------------------------------
 | 
			
		||||
    typedef struct oc_str32
 | 
			
		||||
    {
 | 
			
		||||
        u64 len;
 | 
			
		||||
        u32* ptr;
 | 
			
		||||
    } oc_str32;
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
// u32 strings
 | 
			
		||||
//----------------------------------------------------------------------------------
 | 
			
		||||
typedef struct oc_str32
 | 
			
		||||
{
 | 
			
		||||
    u64 len;
 | 
			
		||||
    u32* ptr;
 | 
			
		||||
} oc_str32;
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_from_buffer(u64 len, u32* buffer);
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_slice(oc_str32 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_from_buffer(u64 len, u32* buffer);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_slice(oc_str32 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_push_buffer(oc_arena* arena, u64 len, u32* buffer);
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_push_copy(oc_arena* arena, oc_str32 s);
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_push_slice(oc_arena* arena, oc_str32 s, u64 start, u64 end);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_push_buffer(oc_arena* arena, u64 len, u32* buffer);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_push_copy(oc_arena* arena, oc_str32 s);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_push_slice(oc_arena* arena, oc_str32 s, u64 start, u64 end);
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_str32_elt
 | 
			
		||||
    {
 | 
			
		||||
        oc_list_elt listElt;
 | 
			
		||||
        oc_str32 string;
 | 
			
		||||
    } oc_str32_elt;
 | 
			
		||||
typedef struct oc_str32_elt
 | 
			
		||||
{
 | 
			
		||||
    oc_list_elt listElt;
 | 
			
		||||
    oc_str32 string;
 | 
			
		||||
} oc_str32_elt;
 | 
			
		||||
 | 
			
		||||
    typedef struct oc_str32_list
 | 
			
		||||
    {
 | 
			
		||||
        oc_list list;
 | 
			
		||||
        u64 eltCount;
 | 
			
		||||
        u64 len;
 | 
			
		||||
    } oc_str32_list;
 | 
			
		||||
typedef struct oc_str32_list
 | 
			
		||||
{
 | 
			
		||||
    oc_list list;
 | 
			
		||||
    u64 eltCount;
 | 
			
		||||
    u64 len;
 | 
			
		||||
} oc_str32_list;
 | 
			
		||||
 | 
			
		||||
    ORCA_API void oc_str32_list_push(oc_arena* arena, oc_str32_list* list, oc_str32 str);
 | 
			
		||||
    ORCA_API oc_str32 oc_str32_list_join(oc_arena* arena, oc_str32_list list);
 | 
			
		||||
    ORCA_API oc_str32_list oc_str32_split(oc_arena* arena, oc_str32 str, oc_str32_list separators);
 | 
			
		||||
ORCA_API void oc_str32_list_push(oc_arena* arena, oc_str32_list* list, oc_str32 str);
 | 
			
		||||
ORCA_API oc_str32 oc_str32_list_join(oc_arena* arena, oc_str32_list list);
 | 
			
		||||
ORCA_API oc_str32_list oc_str32_split(oc_arena* arena, oc_str32 str, oc_str32_list separators);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} // extern "C"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,5 +5,33 @@
 | 
			
		|||
	"ret": {"name": "oc_io_cmp", "tag": "S"},
 | 
			
		||||
	"args": [ {"name": "req",
 | 
			
		||||
	           "type": {"name": "oc_io_req*", "tag": "p"}}]
 | 
			
		||||
},
 | 
			
		||||
{
 | 
			
		||||
    "name": "oc_file_open_with_request",
 | 
			
		||||
    "cname": "oc_file_open_with_request_bridge",
 | 
			
		||||
    "ret": {"name": "oc_file", "tag": "S"},
 | 
			
		||||
    "args": [
 | 
			
		||||
        {"name": "path",
 | 
			
		||||
         "type": {"name": "oc_str8", "tag": "S"}},
 | 
			
		||||
        {"name": "rights",
 | 
			
		||||
         "type": {"name": "oc_file_access", "tag": "i"}},
 | 
			
		||||
        {"name": "flags",
 | 
			
		||||
         "type": {"name": "oc_file_open_flags", "tag": "i"}}
 | 
			
		||||
    ]
 | 
			
		||||
},
 | 
			
		||||
{
 | 
			
		||||
    "name": "oc_file_open_with_dialog",
 | 
			
		||||
    "cname": "oc_file_open_with_dialog_bridge",
 | 
			
		||||
    "ret": {"name": "oc_file_open_with_dialog_result", "cname": "oc_wasm_file_open_with_dialog_result", "tag": "S"},
 | 
			
		||||
    "args": [
 | 
			
		||||
        {"name": "arena",
 | 
			
		||||
         "type": {"name": "oc_arena*", "cname": "i32", "tag": "i"}},
 | 
			
		||||
        {"name": "rights",
 | 
			
		||||
         "type": {"name": "oc_file_access", "tag": "i"}},
 | 
			
		||||
        {"name": "flags",
 | 
			
		||||
         "type": {"name": "oc_file_open_flags", "tag": "i"}},
 | 
			
		||||
        {"name": "desc",
 | 
			
		||||
         "type": {"name": "oc_file_dialog_desc*", "cname": "oc_wasm_file_dialog_desc*", "tag": "p"}}
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
 | 
			
		||||
set INCLUDES=/I ..\..\src /I ..\..\ext
 | 
			
		||||
 | 
			
		||||
mkdir bin
 | 
			
		||||
 | 
			
		||||
cl /we4013 /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% main.c /link /LIBPATH:../../build/bin orca.dll.lib /out:bin/test_file_dialog.exe
 | 
			
		||||
copy ..\..\build\bin\orca.dll bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
LIBDIR=../../build/bin
 | 
			
		||||
SRCDIR=../../src
 | 
			
		||||
 | 
			
		||||
INCLUDES="-I$SRCDIR"
 | 
			
		||||
LIBS="-L$LIBDIR -lorca"
 | 
			
		||||
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
 | 
			
		||||
 | 
			
		||||
if [ ! \( -e bin \) ] ; then
 | 
			
		||||
	mkdir ./bin
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
clang -g $FLAGS $LIBS $INCLUDES -o ./bin/test_file_dialog main.c
 | 
			
		||||
 | 
			
		||||
cp $LIBDIR/liborca.dylib ./bin/
 | 
			
		||||
 | 
			
		||||
install_name_tool -add_rpath "@executable_path" ./bin/test_file_dialog
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/************************************************************/ /**
 | 
			
		||||
*
 | 
			
		||||
*	@file: main.c
 | 
			
		||||
*	@author: Martin Fouilleul
 | 
			
		||||
*	@date: 26/05/2023
 | 
			
		||||
*
 | 
			
		||||
*****************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "orca.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    oc_init();
 | 
			
		||||
 | 
			
		||||
    oc_str8 path = oc_path_executable_relative(oc_scratch(), OC_STR8("../"));
 | 
			
		||||
    oc_file dir = oc_file_open(path, OC_FILE_ACCESS_READ, 0);
 | 
			
		||||
 | 
			
		||||
    oc_file_dialog_desc desc = {
 | 
			
		||||
        .kind = OC_FILE_DIALOG_OPEN,
 | 
			
		||||
        .flags = OC_FILE_DIALOG_FILES | OC_FILE_DIALOG_MULTIPLE,
 | 
			
		||||
        .title = OC_STR8("Select Files"),
 | 
			
		||||
        .okLabel = OC_STR8("Select"),
 | 
			
		||||
        .startAt = dir,
 | 
			
		||||
        .startPath = OC_STR8(".."),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    oc_str8_list_push(oc_scratch(), &desc.filters, OC_STR8("txt"));
 | 
			
		||||
 | 
			
		||||
    oc_file_dialog_result res = oc_file_dialog(oc_scratch(), &desc);
 | 
			
		||||
 | 
			
		||||
    if(res.button == OC_FILE_DIALOG_CANCEL)
 | 
			
		||||
    {
 | 
			
		||||
        oc_log_error("Cancel\n");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        oc_log_info("Selected files:\n");
 | 
			
		||||
        oc_list_for(&res.selection.list, elt, oc_str8_elt, listElt)
 | 
			
		||||
        {
 | 
			
		||||
            oc_log_info("\t%.*s\n", (int)elt->string.len, elt->string.ptr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
The quick brown fox jumps over the lazy dog
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
 | 
			
		||||
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
 | 
			
		||||
 | 
			
		||||
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/test_open_dialog.exe
 | 
			
		||||
copy ..\..\build\bin\orca.dll bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
LIBDIR=../../build/bin
 | 
			
		||||
SRCDIR=../../src
 | 
			
		||||
 | 
			
		||||
INCLUDES="-I$SRCDIR"
 | 
			
		||||
LIBS="-L$LIBDIR -lorca"
 | 
			
		||||
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
 | 
			
		||||
 | 
			
		||||
if [ ! \( -e bin \) ] ; then
 | 
			
		||||
	mkdir ./bin
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
clang -g $FLAGS $LIBS $INCLUDES -o ./bin/test_open_dialog main.c
 | 
			
		||||
 | 
			
		||||
cp $LIBDIR/liborca.dylib ./bin/
 | 
			
		||||
 | 
			
		||||
install_name_tool -add_rpath "@executable_path" ./bin/test_open_dialog
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
/************************************************************/ /**
 | 
			
		||||
*
 | 
			
		||||
*	@file: main.c
 | 
			
		||||
*	@author: Martin Fouilleul
 | 
			
		||||
*	@date: 26/05/2023
 | 
			
		||||
*
 | 
			
		||||
*****************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "orca.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    oc_init();
 | 
			
		||||
 | 
			
		||||
    oc_file_dialog_desc desc = {
 | 
			
		||||
        .kind = OC_FILE_DIALOG_OPEN,
 | 
			
		||||
        .flags = OC_FILE_DIALOG_FILES,
 | 
			
		||||
        .title = OC_STR8("Select Files"),
 | 
			
		||||
        .okLabel = OC_STR8("Select")
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    oc_str8_list_push(oc_scratch(), &desc.filters, OC_STR8("txt"));
 | 
			
		||||
 | 
			
		||||
    oc_file file = oc_file_open_with_dialog(OC_FILE_ACCESS_READ, 0, &desc);
 | 
			
		||||
    if(oc_file_is_nil(file))
 | 
			
		||||
    {
 | 
			
		||||
        oc_log_error("Couldn't open file\n");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        char buffer[1024];
 | 
			
		||||
        u64 len = oc_file_read(file, 1024, buffer);
 | 
			
		||||
        oc_log_info("file contents: %.*s\n", (int)len, buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
The quick brown fox jumps over the lazy dog
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
 | 
			
		||||
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
 | 
			
		||||
 | 
			
		||||
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/test_open_request.exe
 | 
			
		||||
copy ..\..\build\bin\orca.dll bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
LIBDIR=../../build/bin
 | 
			
		||||
SRCDIR=../../src
 | 
			
		||||
 | 
			
		||||
INCLUDES="-I$SRCDIR"
 | 
			
		||||
LIBS="-L$LIBDIR -lorca"
 | 
			
		||||
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
 | 
			
		||||
 | 
			
		||||
if [ ! \( -e bin \) ] ; then
 | 
			
		||||
	mkdir ./bin
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
clang -g $FLAGS $LIBS $INCLUDES -o ./bin/test_open_request main.c
 | 
			
		||||
 | 
			
		||||
cp $LIBDIR/liborca.dylib ./bin/
 | 
			
		||||
 | 
			
		||||
install_name_tool -add_rpath "@executable_path" ./bin/test_open_request
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/************************************************************/ /**
 | 
			
		||||
*
 | 
			
		||||
*	@file: main.c
 | 
			
		||||
*	@author: Martin Fouilleul
 | 
			
		||||
*	@date: 26/05/2023
 | 
			
		||||
*
 | 
			
		||||
*****************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "orca.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    oc_init();
 | 
			
		||||
 | 
			
		||||
    oc_file file = oc_file_open_with_request(OC_STR8("./test.txt"), OC_FILE_ACCESS_READ, 0);
 | 
			
		||||
    if(oc_file_is_nil(file))
 | 
			
		||||
    {
 | 
			
		||||
        oc_log_error("Couldn't open file\n");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        char buffer[1024];
 | 
			
		||||
        u64 len = oc_file_read(file, 1024, buffer);
 | 
			
		||||
        oc_log_info("file contents: %.*s\n", (int)len, buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
The quick brown fox jumps over the lazy dog
 | 
			
		||||
		Loading…
	
		Reference in New Issue