1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2 Copyright (C) 2006 and later, Cockos, Inc.
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
21 This file implements a few Windows calls using their posix equivilents
25 #ifndef SWELL_PROVIDED_BY_APP
29 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/fcntl.h>
34 #include <sys/resource.h>
37 #include "swell-internal.h"
40 #ifdef SWELL_TARGET_OSX
41 #include <Carbon/Carbon.h>
46 #include <sys/errno.h>
50 #include <linux/sched.h>
56 #include "../wdlatomic.h"
58 #include "../assocarray.h"
62 usleep(ms
?ms
*1000:100);
67 struct timeval tm
={0,};
68 gettimeofday(&tm
,NULL
);
69 return (DWORD
) (tm
.tv_sec
*1000 + tm
.tv_usec
/1000);
73 static void intToFileTime(time_t t
, FILETIME
*out
)
75 // see WDL_DirScan::GetCurrentLastWriteTime and similar
76 unsigned long long a
=(unsigned long long)t
; // seconds since january 1st, 1970
77 a
+= 11644473600ull; // 1601-1970
78 a
*= 10000000; // seconds to 1/10th microseconds (100 nanoseconds)
79 out
->dwLowDateTime
=a
& 0xffffffff;
80 out
->dwHighDateTime
=a
>>32;
83 BOOL
GetFileTime(int filedes
, FILETIME
*lpCreationTime
, FILETIME
*lpLastAccessTime
, FILETIME
*lpLastWriteTime
)
85 if (filedes
<0) return 0;
87 if (fstat(filedes
,&st
)) return 0;
89 if (lpCreationTime
) intToFileTime(st
.st_ctime
,lpCreationTime
);
90 if (lpLastAccessTime
) intToFileTime(st
.st_atime
,lpLastAccessTime
);
91 if (lpLastWriteTime
) intToFileTime(st
.st_mtime
,lpLastWriteTime
);
96 BOOL
SWELL_PtInRect(const RECT
*r
, POINT p
)
106 return p
.x
>=r
->left
&& p
.x
<r
->right
&& p
.y
>= tp
&& p
.y
< bt
;
110 int MulDiv(int a
, int b
, int c
)
113 return (int)((double)a
*(double)b
/c
);
116 unsigned int _controlfp(unsigned int flag
, unsigned int mask
)
118 #if !defined(__ppc__) && !defined(__LP64__) && !defined(__arm__)
120 mask
&= _MCW_RC
; // don't let the caller set anything other than round control for now
121 __asm__
__volatile__("fnstcw %0\n\t":"=m"(ret
));
122 ret
=(ret
&~(mask
<<2))|(flag
<<2);
124 if (mask
) __asm__
__volatile__(
125 "fldcw %0\n\t"::"m"(ret
));
126 return (unsigned int) (ret
>>2);
133 BOOL
CloseHandle(HANDLE hand
)
135 SWELL_InternalObjectHeader
*hdr
=(SWELL_InternalObjectHeader
*)hand
;
136 if (!hdr
) return FALSE
;
137 if (hdr
->type
<= INTERNAL_OBJECT_START
|| hdr
->type
>= INTERNAL_OBJECT_END
) return FALSE
;
139 if (!wdl_atomic_decr(&hdr
->count
))
143 case INTERNAL_OBJECT_FILE
:
145 SWELL_InternalObjectHeader_File
*file
= (SWELL_InternalObjectHeader_File
*)hdr
;
146 if (file
->fp
) fclose(file
->fp
);
149 case INTERNAL_OBJECT_EXTERNALSOCKET
: return FALSE
; // pure sockets are not to be closed this way;
150 case INTERNAL_OBJECT_SOCKETEVENT
:
152 SWELL_InternalObjectHeader_SocketEvent
*se
= (SWELL_InternalObjectHeader_SocketEvent
*)hdr
;
153 if (se
->socket
[0]>=0) close(se
->socket
[0]);
154 if (se
->socket
[1]>=0) close(se
->socket
[1]);
157 case INTERNAL_OBJECT_EVENT
:
159 SWELL_InternalObjectHeader_Event
*evt
=(SWELL_InternalObjectHeader_Event
*)hdr
;
160 pthread_cond_destroy(&evt
->cond
);
161 pthread_mutex_destroy(&evt
->mutex
);
164 case INTERNAL_OBJECT_THREAD
:
166 SWELL_InternalObjectHeader_Thread
*thr
= (SWELL_InternalObjectHeader_Thread
*)hdr
;
168 pthread_join(thr
->pt
,&tmp
);
169 pthread_detach(thr
->pt
);
172 #ifdef SWELL_TARGET_OSX
173 case INTERNAL_OBJECT_NSTASK
:
175 SWELL_InternalObjectHeader_NSTask
*nst
= (SWELL_InternalObjectHeader_NSTask
*)hdr
;
176 extern void SWELL_ReleaseNSTask(void *);
177 if (nst
->task
) SWELL_ReleaseNSTask(nst
->task
);
187 HANDLE
CreateEventAsSocket(void *SA
, BOOL manualReset
, BOOL initialSig
, const char *ignored
)
189 SWELL_InternalObjectHeader_SocketEvent
*buf
= (SWELL_InternalObjectHeader_SocketEvent
*)malloc(sizeof(SWELL_InternalObjectHeader_SocketEvent
));
190 buf
->hdr
.type
=INTERNAL_OBJECT_SOCKETEVENT
;
192 buf
->autoReset
= !manualReset
;
193 buf
->socket
[0]=buf
->socket
[1]=-1;
194 if (socketpair(AF_UNIX
,SOCK_STREAM
,0,buf
->socket
)<0)
199 fcntl(buf
->socket
[0], F_SETFL
, fcntl(buf
->socket
[0],F_GETFL
) | O_NONBLOCK
); // nonblocking
202 if (initialSig
&&buf
->socket
[1]>=0) write(buf
->socket
[1],&c
,1);
207 DWORD
WaitForAnySocketObject(int numObjs
, HANDLE
*objs
, DWORD msTO
) // only supports special (socket) handles at the moment
213 for (x
= 0; x
< numObjs
; x
++)
215 SWELL_InternalObjectHeader_SocketEvent
*se
= (SWELL_InternalObjectHeader_SocketEvent
*)objs
[x
];
216 if ((se
->hdr
.type
== INTERNAL_OBJECT_EXTERNALSOCKET
|| se
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
) && se
->socket
[0]>=0)
218 FD_SET(se
->socket
[0],&s
);
219 if (se
->socket
[0] > max_s
) max_s
= se
->socket
[0];
227 tv
.tv_sec
= msTO
/1000;
228 tv
.tv_usec
= (msTO
%1000)*1000;
229 if (select(max_s
+1,&s
,NULL
,NULL
,msTO
==INFINITE
?NULL
:&tv
)>0) for (x
= 0; x
< numObjs
; x
++)
231 SWELL_InternalObjectHeader_SocketEvent
*se
= (SWELL_InternalObjectHeader_SocketEvent
*)objs
[x
];
232 if ((se
->hdr
.type
== INTERNAL_OBJECT_EXTERNALSOCKET
|| se
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
) && se
->socket
[0]>=0)
234 if (FD_ISSET(se
->socket
[0],&s
))
236 if (se
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
&& se
->autoReset
)
239 if (read(se
->socket
[0],buf
,sizeof(buf
))<1) goto again
;
241 return WAIT_OBJECT_0
+ x
;
250 DWORD
WaitForSingleObject(HANDLE hand
, DWORD msTO
)
252 SWELL_InternalObjectHeader
*hdr
=(SWELL_InternalObjectHeader
*)hand
;
253 if (!hdr
) return WAIT_FAILED
;
257 #ifdef SWELL_TARGET_OSX
258 case INTERNAL_OBJECT_NSTASK
:
260 SWELL_InternalObjectHeader_NSTask
*nst
= (SWELL_InternalObjectHeader_NSTask
*)hdr
;
261 extern DWORD
SWELL_WaitForNSTask(void *,DWORD
);
262 if (nst
->task
) return SWELL_WaitForNSTask(nst
->task
,msTO
);
266 case INTERNAL_OBJECT_THREAD
:
268 SWELL_InternalObjectHeader_Thread
*thr
= (SWELL_InternalObjectHeader_Thread
*)hdr
;
272 if (!msTO
) return WAIT_TIMEOUT
;
273 if (msTO
!= INFINITE
)
275 DWORD d
=GetTickCount()+msTO
;
276 while (GetTickCount()<d
&& !thr
->done
) Sleep(1);
277 if (!thr
->done
) return WAIT_TIMEOUT
;
281 if (!pthread_join(thr
->pt
,&tmp
)) return WAIT_OBJECT_0
;
284 case INTERNAL_OBJECT_EXTERNALSOCKET
:
285 case INTERNAL_OBJECT_SOCKETEVENT
:
287 SWELL_InternalObjectHeader_SocketEvent
*se
= (SWELL_InternalObjectHeader_SocketEvent
*)hdr
;
288 if (se
->socket
[0]<0) Sleep(msTO
!=INFINITE
?msTO
:1);
294 FD_SET(se
->socket
[0],&s
);
296 tv
.tv_sec
= msTO
/1000;
297 tv
.tv_usec
= (msTO
%1000)*1000;
298 if (select(se
->socket
[0]+1,&s
,NULL
,NULL
,msTO
==INFINITE
?NULL
:&tv
)>0 && FD_ISSET(se
->socket
[0],&s
))
300 if (se
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
&& se
->autoReset
)
303 if (read(se
->socket
[0],buf
,sizeof(buf
))<1) goto again
;
305 return WAIT_OBJECT_0
;
311 case INTERNAL_OBJECT_EVENT
:
313 SWELL_InternalObjectHeader_Event
*evt
= (SWELL_InternalObjectHeader_Event
*)hdr
;
314 int rv
=WAIT_OBJECT_0
;
315 pthread_mutex_lock(&evt
->mutex
);
318 if (!evt
->isSignal
) rv
=WAIT_TIMEOUT
;
320 else if (msTO
== INFINITE
)
322 while (!evt
->isSignal
) pthread_cond_wait(&evt
->cond
,&evt
->mutex
);
329 ts
.tv_sec
= msTO
/1000;
330 ts
.tv_nsec
= (msTO
%1000)*1000000;
332 while (!evt
->isSignal
)
335 if (pthread_cond_timedwait_relative_np(&evt
->cond
,&evt
->mutex
,&ts
)==ETIMEDOUT
)
341 struct timeval tm
={0,};
342 gettimeofday(&tm
,NULL
);
344 ts
.tv_sec
= msTO
/1000 + tm
.tv_sec
;
345 ts
.tv_nsec
= (tm
.tv_usec
+ (msTO
%1000)*1000) * 1000;
346 if (ts
.tv_nsec
>=1000000000)
348 int n
= ts
.tv_nsec
/1000000000;
350 ts
.tv_nsec
-= ((long long)n
* (long long)1000000000);
352 if (pthread_cond_timedwait(&evt
->cond
,&evt
->mutex
,&ts
))
358 // we should track/correct the timeout amount here since in theory we could end up waiting a bit longer!
361 if (!evt
->isManualReset
&& rv
==WAIT_OBJECT_0
) evt
->isSignal
=false;
362 pthread_mutex_unlock(&evt
->mutex
);
372 static void *__threadproc(void *parm
)
374 #ifdef SWELL_TARGET_OSX
375 void *arp
=SWELL_InitAutoRelease();
378 SWELL_InternalObjectHeader_Thread
*t
=(SWELL_InternalObjectHeader_Thread
*)parm
;
379 t
->retv
=t
->threadProc(t
->threadParm
);
383 #ifdef SWELL_TARGET_OSX
384 SWELL_QuitAutoRelease(arp
);
391 DWORD
GetCurrentThreadId()
393 return (DWORD
)(INT_PTR
)pthread_self(); // this is incorrect on x64
396 HANDLE
CreateEvent(void *SA
, BOOL manualReset
, BOOL initialSig
, const char *ignored
)
398 SWELL_InternalObjectHeader_Event
*buf
= (SWELL_InternalObjectHeader_Event
*)malloc(sizeof(SWELL_InternalObjectHeader_Event
));
399 buf
->hdr
.type
=INTERNAL_OBJECT_EVENT
;
401 buf
->isSignal
= !!initialSig
;
402 buf
->isManualReset
= !!manualReset
;
404 pthread_mutex_init(&buf
->mutex
,NULL
);
405 pthread_cond_init(&buf
->cond
,NULL
);
410 HANDLE
CreateThread(void *TA
, DWORD stackSize
, DWORD (*ThreadProc
)(LPVOID
), LPVOID parm
, DWORD cf
, DWORD
*tidOut
)
412 #ifdef SWELL_TARGET_OSX
413 SWELL_EnsureMultithreadedCocoa();
415 SWELL_InternalObjectHeader_Thread
*buf
= (SWELL_InternalObjectHeader_Thread
*)malloc(sizeof(SWELL_InternalObjectHeader_Thread
));
416 buf
->hdr
.type
=INTERNAL_OBJECT_THREAD
;
418 buf
->threadProc
=ThreadProc
;
419 buf
->threadParm
= parm
;
423 pthread_create(&buf
->pt
,NULL
,__threadproc
,buf
);
425 if (tidOut
) *tidOut
=(DWORD
)(INT_PTR
)buf
->pt
; // incorrect on x64
431 BOOL
SetThreadPriority(HANDLE hand
, int prio
)
433 SWELL_InternalObjectHeader_Thread
*evt
=(SWELL_InternalObjectHeader_Thread
*)hand
;
437 if (!evt
&& prio
>= 0x10000 && prio
< 0x10000 + 100)
439 s_rt_max
= prio
- 0x10000;
444 if (!evt
|| evt
->hdr
.type
!= INTERNAL_OBJECT_THREAD
) return FALSE
;
446 if (evt
->done
) return FALSE
;
449 struct sched_param param
;
450 memset(¶m
,0,sizeof(param
));
453 // linux only has meaningful priorities if using realtime threads,
454 // for this to be enabled the caller should use:
456 // SetThreadPriority(NULL,0x10000 + max_thread_priority (0..99));
458 if (s_rt_max
< 1 || prio
<= THREAD_PRIORITY_NORMAL
)
461 param
.sched_priority
=0;
466 if (prio
< THREAD_PRIORITY_TIME_CRITICAL
)
469 if (prio
< THREAD_PRIORITY_HIGHEST
)
472 if (prio
< THREAD_PRIORITY_ABOVE_NORMAL
) lb
--;
475 param
.sched_priority
= lb
< 1 ? 1 : lb
;
478 return !pthread_setschedparam(evt
->pt
,pol
,¶m
);
480 if (!pthread_getschedparam(evt
->pt
,&pol
,¶m
))
482 // this is for darwin, but might work elsewhere
483 param
.sched_priority
= 31 + prio
;
485 int mt
=sched_get_priority_min(pol
);
486 if (param
.sched_priority
<mt
||param
.sched_priority
> (mt
=sched_get_priority_max(pol
)))param
.sched_priority
=mt
;
488 if (!pthread_setschedparam(evt
->pt
,pol
,¶m
))
497 BOOL
SetEvent(HANDLE hand
)
499 SWELL_InternalObjectHeader_Event
*evt
=(SWELL_InternalObjectHeader_Event
*)hand
;
500 if (!evt
) return FALSE
;
501 if (evt
->hdr
.type
== INTERNAL_OBJECT_EVENT
)
503 pthread_mutex_lock(&evt
->mutex
);
506 evt
->isSignal
= true;
507 if (evt
->isManualReset
) pthread_cond_broadcast(&evt
->cond
);
508 else pthread_cond_signal(&evt
->cond
);
510 pthread_mutex_unlock(&evt
->mutex
);
513 if (evt
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
)
515 SWELL_InternalObjectHeader_SocketEvent
*se
=(SWELL_InternalObjectHeader_SocketEvent
*)hand
;
516 if (se
->socket
[1]>=0)
518 if (se
->socket
[0]>=0)
522 FD_SET(se
->socket
[0],&s
);
523 struct timeval tv
={0,};
524 if (select(se
->socket
[0]+1,&s
,NULL
,NULL
,&tv
)>0 && FD_ISSET(se
->socket
[0],&s
)) return TRUE
; // already set
527 write(se
->socket
[1],&c
,1);
533 BOOL
ResetEvent(HANDLE hand
)
535 SWELL_InternalObjectHeader_Event
*evt
=(SWELL_InternalObjectHeader_Event
*)hand
;
536 if (!evt
) return FALSE
;
537 if (evt
->hdr
.type
== INTERNAL_OBJECT_EVENT
)
542 if (evt
->hdr
.type
== INTERNAL_OBJECT_SOCKETEVENT
)
544 SWELL_InternalObjectHeader_SocketEvent
*se
=(SWELL_InternalObjectHeader_SocketEvent
*)hand
;
545 if (se
->socket
[0]>=0)
548 read(se
->socket
[0],buf
,sizeof(buf
));
555 BOOL
WinOffsetRect(LPRECT lprc
, int dx
, int dy
)
565 BOOL
WinSetRect(LPRECT lprc
, int xLeft
, int yTop
, int xRight
, int yBottom
)
570 lprc
->right
= xRight
;
571 lprc
->bottom
= yBottom
;
576 int WinIntersectRect(RECT
*out
, const RECT
*in1
, const RECT
*in2
)
578 RECT tmp
= *in1
; in1
= &tmp
;
579 memset(out
,0,sizeof(RECT
));
580 if (in1
->right
<= in1
->left
) return false;
581 if (in2
->right
<= in2
->left
) return false;
582 if (in1
->bottom
<= in1
->top
) return false;
583 if (in2
->bottom
<= in2
->top
) return false;
585 // left is maximum of minimum of right edges and max of left edges
586 out
->left
= wdl_max(in1
->left
,in2
->left
);
587 out
->right
= wdl_min(in1
->right
,in2
->right
);
588 out
->top
=wdl_max(in1
->top
,in2
->top
);
589 out
->bottom
= wdl_min(in1
->bottom
,in2
->bottom
);
591 return out
->right
>out
->left
&& out
->bottom
>out
->top
;
593 void WinUnionRect(RECT
*out
, const RECT
*in1
, const RECT
*in2
)
595 if (in1
->left
== in1
->right
&& in1
->top
== in1
->bottom
)
599 else if (in2
->left
== in2
->right
&& in2
->top
== in2
->bottom
)
605 out
->left
= wdl_min(in1
->left
,in2
->left
);
606 out
->top
= wdl_min(in1
->top
,in2
->top
);
607 out
->right
=wdl_max(in1
->right
,in2
->right
);
608 out
->bottom
=wdl_max(in1
->bottom
,in2
->bottom
);
620 void *GlobalLock(HANDLE h
)
623 GLOBAL_REC
*rec
=((GLOBAL_REC
*)h
)-1;
627 int GlobalSize(HANDLE h
)
630 GLOBAL_REC
*rec
=((GLOBAL_REC
*)h
)-1;
634 void GlobalUnlock(HANDLE h
)
637 GLOBAL_REC
*rec
=((GLOBAL_REC
*)h
)-1;
640 void GlobalFree(HANDLE h
)
643 GLOBAL_REC
*rec
=((GLOBAL_REC
*)h
)-1;
646 // note error freeing locked ram
651 HANDLE
GlobalAlloc(int flags
, int sz
)
654 GLOBAL_REC
*rec
=(GLOBAL_REC
*)malloc(sizeof(GLOBAL_REC
)+sz
);
658 if (flags
&GMEM_FIXED
) memset(rec
+1,0,sz
);
662 char *lstrcpyn(char *dest
, const char *src
, int l
)
664 if (l
<1) return dest
;
678 static WDL_Mutex s_libraryMutex
;
679 static int libkeycomp(void **p1
, void **p2
)
681 INT_PTR a
=(INT_PTR
)(*p1
) - (INT_PTR
)(*p2
);
686 static WDL_AssocArray
<void *, SWELL_HINSTANCE
*> s_loadedLibs(libkeycomp
); // index by OS-provided handle (rather than filename since filenames could be relative etc)
688 HINSTANCE
LoadLibrary(const char *fn
)
690 return LoadLibraryGlobals(fn
,false);
692 HINSTANCE
LoadLibraryGlobals(const char *fn
, bool symbolsAsGlobals
)
694 if (!fn
|| !*fn
) return NULL
;
696 void *inst
= NULL
, *bundleinst
=NULL
;
698 #ifdef SWELL_TARGET_OSX
700 if (stat(fn
,&ss
) || (ss
.st_mode
&S_IFDIR
))
702 CFStringRef str
=(CFStringRef
)SWELL_CStringToCFString(fn
);
703 CFURLRef r
=CFURLCreateWithFileSystemPath(NULL
,str
,kCFURLPOSIXPathStyle
,true);
706 bundleinst
=(void *)CFBundleCreate(NULL
,r
);
711 if (!CFBundleLoadExecutable((CFBundleRef
)bundleinst
))
713 CFRelease((CFBundleRef
)bundleinst
);
720 #ifdef SWELL_TARGET_OSX
724 inst
=dlopen(fn
,RTLD_NOW
|(symbolsAsGlobals
?RTLD_GLOBAL
:RTLD_LOCAL
));
728 WDL_MutexLock
lock(&s_libraryMutex
);
730 SWELL_HINSTANCE
*rec
= s_loadedLibs
.Get(bundleinst
? bundleinst
: inst
);
733 rec
= (SWELL_HINSTANCE
*)calloc(sizeof(SWELL_HINSTANCE
),1);
736 rec
->bundleinstptr
= bundleinst
;
739 s_loadedLibs
.Insert(bundleinst
? bundleinst
: inst
,rec
);
741 int (*SWELL_dllMain
)(HINSTANCE
, DWORD
, LPVOID
) = 0;
742 BOOL (*dllMain
)(HINSTANCE
, DWORD
, LPVOID
) = 0;
743 *(void **)&SWELL_dllMain
= GetProcAddress(rec
,"SWELL_dllMain");
746 void *SWELLAPI_GetFunc(const char *name
);
748 if (!SWELL_dllMain(rec
,DLL_PROCESS_ATTACH
,(void*)NULL
)) // todo: eventually pass SWELLAPI_GetFunc, maybe?
753 *(void **)&dllMain
= GetProcAddress(rec
,"DllMain");
756 if (!dllMain(rec
,DLL_PROCESS_ATTACH
,NULL
))
758 SWELL_dllMain(rec
,DLL_PROCESS_DETACH
,(void*)NULL
);
764 rec
->SWELL_dllMain
= SWELL_dllMain
;
765 rec
->dllMain
= dllMain
;
772 void *GetProcAddress(HINSTANCE hInst
, const char *procName
)
774 if (!hInst
) return 0;
776 SWELL_HINSTANCE
*rec
=(SWELL_HINSTANCE
*)hInst
;
779 #ifdef SWELL_TARGET_OSX
780 if (rec
->bundleinstptr
)
782 CFStringRef str
=(CFStringRef
)SWELL_CStringToCFString(procName
);
783 ret
= (void *)CFBundleGetFunctionPointerForName((CFBundleRef
)rec
->bundleinstptr
, str
);
784 if (ret
) rec
->lastSymbolRequested
=ret
;
789 if (rec
->instptr
) ret
=(void *)dlsym(rec
->instptr
, procName
);
790 if (ret
) rec
->lastSymbolRequested
=ret
;
794 BOOL
FreeLibrary(HINSTANCE hInst
)
796 if (!hInst
) return FALSE
;
798 WDL_MutexLock
lock(&s_libraryMutex
);
801 SWELL_HINSTANCE
*rec
=(SWELL_HINSTANCE
*)hInst
;
802 if (--rec
->refcnt
<=0)
805 #ifdef SWELL_TARGET_OSX
806 s_loadedLibs
.Delete(rec
->bundleinstptr
? rec
->bundleinstptr
: rec
->instptr
);
808 s_loadedLibs
.Delete(rec
->instptr
);
811 if (rec
->SWELL_dllMain
)
813 rec
->SWELL_dllMain(rec
,DLL_PROCESS_DETACH
,NULL
);
814 if (rec
->dllMain
) rec
->dllMain(rec
,DLL_PROCESS_DETACH
,NULL
);
818 #ifdef SWELL_TARGET_OSX
819 if (rec
->bundleinstptr
)
821 CFRelease((CFBundleRef
)rec
->bundleinstptr
);
824 if (rec
->instptr
) dlclose(rec
->instptr
);
826 if (dofree
) free(rec
);
830 void* SWELL_GetBundle(HINSTANCE hInst
)
832 SWELL_HINSTANCE
* rec
=(SWELL_HINSTANCE
*)hInst
;
833 #ifdef SWELL_TARGET_OSX
834 if (rec
) return rec
->bundleinstptr
;
836 if (rec
) return rec
->instptr
;
841 DWORD
GetModuleFileName(HINSTANCE hInst
, char *fn
, DWORD nSize
)
845 void *instptr
= NULL
, *lastSymbolRequested
=NULL
;
846 #ifdef SWELL_TARGET_OSX
847 void *bundleinstptr
=NULL
;
851 SWELL_HINSTANCE
*p
= (SWELL_HINSTANCE
*)hInst
;
852 instptr
= p
->instptr
;
853 #ifdef SWELL_TARGET_OSX
854 bundleinstptr
= p
->bundleinstptr
;
856 lastSymbolRequested
=p
->lastSymbolRequested
;
858 #ifdef SWELL_TARGET_OSX
859 if (!instptr
|| bundleinstptr
)
861 CFBundleRef bund
=bundleinstptr
? (CFBundleRef
)bundleinstptr
: CFBundleGetMainBundle();
864 CFURLRef url
=CFBundleCopyBundleURL(bund
);
868 if (CFURLGetFileSystemRepresentation(url
,true,(UInt8
*)buf
,sizeof(buf
))) lstrcpyn(fn
,buf
,nSize
);
872 return (DWORD
)strlen(fn
);
874 #elif defined(__linux__)
875 if (!instptr
) // get exe file name
878 sprintf(tmp
,"/proc/%d/exe",getpid());
879 int sz
=readlink(tmp
,fn
,nSize
);
881 else if ((DWORD
)sz
>=nSize
)sz
=nSize
-1;
887 if (instptr
&& lastSymbolRequested
)
890 dladdr(lastSymbolRequested
,&inf
);
893 lstrcpyn(fn
,inf
.dli_fname
,nSize
);
894 return (DWORD
)strlen(fn
);
901 bool SWELL_GenerateGUID(void *g
)
903 #ifdef SWELL_TARGET_OSX
904 CFUUIDRef r
= CFUUIDCreate(NULL
);
905 if (!r
) return false;
906 CFUUIDBytes a
= CFUUIDGetUUIDBytes(r
);
907 if (g
) memcpy(g
,&a
,16);
911 int f
= open("/dev/urandom",O_RDONLY
);
912 if (f
<0) return false;
914 int v
= read(f
,g
,sizeof(GUID
));
916 return v
== sizeof(GUID
);
922 void GetTempPath(int bufsz
, char *buf
)
931 const char *p
= getenv("TMPDIR");
933 const char *p
= getenv("TEMP");
935 if (!p
|| !*p
) p
="/tmp/";
936 lstrcpyn(buf
, p
, bufsz
);
938 size_t len
= strlen(buf
);
939 if (!len
|| buf
[len
-1] != '/')
941 if (len
> (size_t)bufsz
-2) len
= bufsz
-2;
948 const char *g_swell_appname
;
949 char *g_swell_defini
;
950 const char *g_swell_fontpangram
;
952 void *SWELL_ExtendedAPI(const char *key
, void *v
)
954 if (!strcmp(key
,"APPNAME")) g_swell_appname
= (const char *)v
;
955 else if (!strcmp(key
,"INIFILE"))
957 free(g_swell_defini
);
958 g_swell_defini
= v
? strdup((const char *)v
) : NULL
;
960 #ifndef SWELL_TARGET_OSX
962 GetPrivateProfileString(".swell","max_open_files","",buf
,sizeof(buf
),"");
964 WritePrivateProfileString(".swell","max_open_files","auto // (default is max of default or 16384)","");
966 struct rlimit rl
= {0,};
967 getrlimit(RLIMIT_NOFILE
,&rl
);
969 const int orig_n
= atoi(buf
);
970 rlim_t n
= orig_n
> 0 ? (rlim_t
) orig_n
: 16384;
971 if (n
> rl
.rlim_max
) n
= rl
.rlim_max
;
972 if (orig_n
> 0 ? (n
!= rl
.rlim_cur
) : (n
> rl
.rlim_cur
))
975 setrlimit(RLIMIT_NOFILE
,&rl
);
977 getrlimit(RLIMIT_NOFILE
,&rl
);
978 printf("applied rlimit %d/%d\n",(int)rl
.rlim_cur
,(int)rl
.rlim_max
);
983 #ifdef SWELL_TARGET_GDK
984 GetPrivateProfileString(".swell","ui_scale","",buf
,sizeof(buf
),"");
987 double sc
= atof(buf
);
988 if (sc
> 0.01 && sc
< 10.0 && sc
!= 1.0)
990 #define __scale(x,c) g_swell_ctheme.x = (int) (g_swell_ctheme.x * sc + 0.5);
991 SWELL_GENERIC_THEMESIZEDEFS(__scale
,__scale
)
993 g_swell_ui_scale
= (int) (256 * sc
+ 0.5);
998 WritePrivateProfileString(".swell","ui_scale","1.0 // scales the sizes in libSwell.colortheme","");
1002 else if (!strcmp(key
,"FONTPANGRAM"))
1004 g_swell_fontpangram
= (const char *)v
;
1006 #ifndef SWELL_TARGET_OSX
1007 else if (!strcmp(key
,"FULLSCREEN") || !strcmp(key
,"-FULLSCREEN"))
1009 int swell_fullscreenWindow(HWND
, BOOL
);
1010 return (void*)(INT_PTR
)swell_fullscreenWindow((HWND
)v
, key
[0] != '-');