Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions src/macosx/osxgl.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
#define MINIMUM_WIDTH 48
#define MINIMUM_HEIGHT 48

/* by MAREK */
#define FILE_URL_SIZE 254
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry, no, is not used anymore, there was another concept in my mind to send 1 single message and receive the event as a bunch of file names separated by \r\n so exactly like MacOS is doing, but eventually i changed minds and did at exactly like xdnd function for X11 in Allegro 5 is doing, so there is single message for each file name. So that definition is not used anymore. Remove it please.

/* end by MAREK */

/* Unsigned integer; data type only avaliable for OS X >= 10.5 */
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
typedef unsigned int NSUInteger;
Expand Down Expand Up @@ -212,6 +216,9 @@ @interface ALOpenGLView : NSOpenGLView
/* This is passed onto the event functions so we know where the event came from */
ALLEGRO_DISPLAY* dpy_ptr;
}
/* by MAREK */
- (id)initWithFrame:(NSRect)frameRect;
/* end by MAREK */
-(void)setAllegroDisplay: (ALLEGRO_DISPLAY*) ptr;
-(ALLEGRO_DISPLAY*) allegroDisplay;
-(void) reshape;
Expand Down Expand Up @@ -292,8 +299,119 @@ void _al_osx_mouse_was_installed(BOOL install) {
});
}

/* by MAREK */
@implementation NSString (Char)

/*
* Convert a NSString to a char pointer
*/
-(char *)toChar{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as in my previous comment, this comes from previous concept, and NSString now is converted directly to char array, no need to use that function. Delete it please.

const char* strUtf8 = [self UTF8String];
size_t len = strlen(strUtf8) + 1;
char *toChar = malloc(len);
memcpy(toChar, strUtf8, len);
return toChar;
}
@end
/* end by MAREK */

@implementation ALOpenGLView

/*by MAREK*/
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self) {
// Register for file URL drops (e.g., images)
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL]];
// Or other types like NSStringPboardType, NSFileContentsPboardType, etc.
}

NSString *cachesDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this variable used?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm really sorry, it should be remarked with // like next rows below, what was a part of my tests i needed to divert errout to the file, originally in cachesDirectory, to check how events are received. so those 3 rows:

NSString *cachesDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];

// NSString *logPath = @"allegro5.log";
// freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);

can be freely removed.


// NSString *logPath = @"allegro5.log";
// freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);

return self;
}

// Drag-and-drop methods

- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
NSPasteboard *pasteboard = [sender draggingPasteboard];
if ([[pasteboard types] containsObject:NSPasteboardTypeFileURL]) {
return NSDragOperationCopy; // Accept copy operation for files
}
return NSDragOperationNone;
}

- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)sender {
return YES; // Prepare to accept the drop
}

- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
NSPasteboard *pasteboard = [sender draggingPasteboard];
NSArray *classes = @[NSURL.class];
NSDictionary *options = @{NSPasteboardURLReadingFileURLsOnlyKey: @YES};

int n=0;

NSArray<NSURL *> *fileURLs = [pasteboard readObjectsForClasses:classes options:options];
if (fileURLs.count > 0)
{
// Handle multiple dropped files here

for (NSURL *fileURL in fileURLs)
{
NSString *filePath = [fileURL path];
unsigned long ul=[filePath length];
NSLog(@"Dropped file: %@ len:%d", filePath, (int)ul);
const char *cfileURL= [filePath cStringUsingEncoding:NSUTF8StringEncoding];

// Process the file: e.g., load as texture, model, or data into OpenGL
// Example: If it's an image, use NSImage to load and upload to GL texture
// NSImage *image = [[NSImage alloc] initWithContentsOfURL:fileURL];
// Then convert to OpenGL texture...
ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr;
NSWindow *window = dpy->win;

NSPoint mousePos = [window mouseLocationOutsideOfEventStream];
// mousePos.x and mousePos.y now contain the cursor's coordinates relative to the window's bottom-left corner.

NSRect rc = [window frame];
NSRect content = [window contentRectForFrameRect: rc];
content = [self convertRectToBacking: content];
ALLEGRO_EVENT_SOURCE *es = &dpy->parent.es;

_al_event_source_lock(es);
ALLEGRO_EVENT event;

event.drop.type = ALLEGRO_EVENT_DROP;
event.drop.timestamp = al_get_time();
event.drop.x = (int)mousePos.x;
event.drop.y = (int)mousePos.y;
NSLog(@"Event with file (%d/%d) : %@", n+1, (int)fileURLs.count, filePath);
event.drop.text = (char*) cfileURL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cFileURL will get invalidated when filePath is released, which may happen when fileURLs is released. From the docs I'm not sure if it will happen at a time which could cause a problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Allegro docs I think you need to copy cFileURL into allocated memory, which the user program must free.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my thought as well, but I made detail tests, on many files in one drop, and before filePath is released, in the function which takes the event message (which is listening to _al_event_source_emit_event(es, &event), the tile name, so event.drop.text is copied to internal buffer, independent from event.drop.text pointer. It works, because is is not released before the function finishes it's work, so until the very last filename. I will think about that, and maybe that would make sense to declare extra global variable for that, allocate in create_display_fs or create_display_win, and free it in destroy_display(ALLEGRO_DISPLAY* d) what basically I was doing when i created big buffer for all file names, to get independence from fileURLs pointer. But after experiments, eventually I resigned from it, because it is simply working. That's why I asked all of you guys to check it out and make it more safe, if it is not safe enough. But yes, if you like to copy cFileURL into allocated memory, please do that change.
Like always, disadvantage of extra text variable is necessity to copy it, but this is not a big deal. We are dealing with dozens (on top) string up to 254 characters or so (URL path length), not thousand of them.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, i'm taking your suggestion seriously, and will do that change in my branch, to test it, even intentionally delaying message receiving, letting this module to smear the fileURLs pointer.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, receiving the message sent from that osxgl.m file, is executed in the same thread, so I believe when loop is finished, all is already received and copied into internal buffer - in my case - in my program. But it's right, that could be in different thread, and message can wait for recipient, while loop is already over. Either way, we need to pick them up as soon as possible, as the next batch of files will probably arrive soon. Then even that variable would be modified. As far as I know, sending a message doesn't require waiting for a confirmation of receipt; the message remains in the message buffer. So we don't know if the last message received will be the one received. What we do know is who will receive the message, and there are other features for that, which is why dragged files or their icons with the + symbol are visible against the background of the listening window. Ok, that's what I know, please anyone correct me iff I'm wrong. I mostly base on me experience, and this is example:
https://nextcloud.vurplex.com/s/9GFBqmbRYD7X3pz
The last file name is also taken.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you just need to al_malloc each individual dropped file name, and it is the application's responsibility to al_free it; see the ex_drag_and_drop.c for example:

al_free(event.drop.text);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that's right, so in next my commit i'm allocating memory, freeing and allocating again what is needed to keep pointers working, to free them completely when display is closing. Yes, it can be replaced with al_malloc and al_free, actually just to save one or 3 lines of code, so instead of freeing those variables when display is closing, rather doing nothing because allegro would do that when its architecture is closing. I used malloc because i'm new in allegro 5, i come from the fading world of allegro4. Just let me know if I should change it again, so change the file in my fork, then pull commit to main branch, or you guys would do that as should be in official branch. Thanks.

event.drop.is_file = true;
event.drop.row = n;
if ((n+1)<(int)fileURLs.count) event.drop.is_complete = false;
else event.drop.is_complete = true;
_al_event_source_emit_event(es, &event);
_al_event_source_unlock(es);
n++;
}

return YES;
}
return NO;
}

- (void)concludeDragOperation:(id<NSDraggingInfo>)sender {
// Optional: Any cleanup after drop
}

/* end by MAREK*/

-(void) prepareOpenGL
{
[super prepareOpenGL];
Expand Down