Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / swell / swell.cpp
blobe6a57cc019f869123d6bade6a86deefd2794add2
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
28 #include "swell.h"
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <sys/stat.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>
42 #endif
44 #ifdef __APPLE__
45 #include <sched.h>
46 #include <sys/errno.h>
47 #endif
49 #ifdef __linux__
50 #include <linux/sched.h>
51 #endif
53 #include <pthread.h>
56 #include "../wdlatomic.h"
57 #include "../mutex.h"
58 #include "../assocarray.h"
60 void Sleep(int ms)
62 usleep(ms?ms*1000:100);
65 DWORD GetTickCount()
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;
86 struct stat st;
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);
93 return 1;
96 BOOL SWELL_PtInRect(const RECT *r, POINT p)
98 if (!r) return FALSE;
99 int tp=r->top;
100 int bt=r->bottom;
101 if (tp>bt)
103 bt=tp;
104 tp=r->bottom;
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)
112 if(c == 0) return 0;
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__)
119 unsigned short ret;
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);
127 #else
128 return 0;
129 #endif
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))
141 switch (hdr->type)
143 case INTERNAL_OBJECT_FILE:
145 SWELL_InternalObjectHeader_File *file = (SWELL_InternalObjectHeader_File*)hdr;
146 if (file->fp) fclose(file->fp);
148 break;
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]);
156 break;
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);
163 break;
164 case INTERNAL_OBJECT_THREAD:
166 SWELL_InternalObjectHeader_Thread *thr = (SWELL_InternalObjectHeader_Thread*)hdr;
167 void *tmp;
168 pthread_join(thr->pt,&tmp);
169 pthread_detach(thr->pt);
171 break;
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);
179 break;
180 #endif
182 free(hdr);
184 return TRUE;
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;
191 buf->hdr.count=1;
192 buf->autoReset = !manualReset;
193 buf->socket[0]=buf->socket[1]=-1;
194 if (socketpair(AF_UNIX,SOCK_STREAM,0,buf->socket)<0)
196 free(buf);
197 return 0;
199 fcntl(buf->socket[0], F_SETFL, fcntl(buf->socket[0],F_GETFL) | O_NONBLOCK); // nonblocking
201 char c=0;
202 if (initialSig&&buf->socket[1]>=0) write(buf->socket[1],&c,1);
204 return buf;
207 DWORD WaitForAnySocketObject(int numObjs, HANDLE *objs, DWORD msTO) // only supports special (socket) handles at the moment
209 int max_s=0;
210 fd_set s;
211 FD_ZERO(&s);
212 int x;
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];
223 if (max_s>0)
225 again:
226 struct timeval tv;
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)
238 char buf[128];
239 if (read(se->socket[0],buf,sizeof(buf))<1) goto again;
241 return WAIT_OBJECT_0 + x;
247 return WAIT_TIMEOUT;
250 DWORD WaitForSingleObject(HANDLE hand, DWORD msTO)
252 SWELL_InternalObjectHeader *hdr=(SWELL_InternalObjectHeader*)hand;
253 if (!hdr) return WAIT_FAILED;
255 switch (hdr->type)
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);
264 break;
265 #endif
266 case INTERNAL_OBJECT_THREAD:
268 SWELL_InternalObjectHeader_Thread *thr = (SWELL_InternalObjectHeader_Thread*)hdr;
269 void *tmp;
270 if (!thr->done)
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;
283 break;
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);
289 else
291 fd_set s;
292 FD_ZERO(&s);
293 again:
294 FD_SET(se->socket[0],&s);
295 struct timeval tv;
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)
302 char buf[128];
303 if (read(se->socket[0],buf,sizeof(buf))<1) goto again;
305 return WAIT_OBJECT_0;
307 return WAIT_TIMEOUT;
310 break;
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);
316 if (msTO == 0)
318 if (!evt->isSignal) rv=WAIT_TIMEOUT;
320 else if (msTO == INFINITE)
322 while (!evt->isSignal) pthread_cond_wait(&evt->cond,&evt->mutex);
324 else
326 // timed wait
327 #ifdef __APPLE__
328 struct timespec ts;
329 ts.tv_sec = msTO/1000;
330 ts.tv_nsec = (msTO%1000)*1000000;
331 #endif
332 while (!evt->isSignal)
334 #ifdef __APPLE__
335 if (pthread_cond_timedwait_relative_np(&evt->cond,&evt->mutex,&ts)==ETIMEDOUT)
337 rv = WAIT_TIMEOUT;
338 break;
340 #else
341 struct timeval tm={0,};
342 gettimeofday(&tm,NULL);
343 struct timespec ts;
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;
349 ts.tv_sec+=n;
350 ts.tv_nsec -= ((long long)n * (long long)1000000000);
352 if (pthread_cond_timedwait(&evt->cond,&evt->mutex,&ts))
354 rv = WAIT_TIMEOUT;
355 break;
357 #endif
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);
364 return rv;
366 break;
369 return WAIT_FAILED;
372 static void *__threadproc(void *parm)
374 #ifdef SWELL_TARGET_OSX
375 void *arp=SWELL_InitAutoRelease();
376 #endif
378 SWELL_InternalObjectHeader_Thread *t=(SWELL_InternalObjectHeader_Thread*)parm;
379 t->retv=t->threadProc(t->threadParm);
380 t->done=1;
381 CloseHandle(parm);
383 #ifdef SWELL_TARGET_OSX
384 SWELL_QuitAutoRelease(arp);
385 #endif
387 pthread_exit(0);
388 return 0;
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;
400 buf->hdr.count=1;
401 buf->isSignal = !!initialSig;
402 buf->isManualReset = !!manualReset;
404 pthread_mutex_init(&buf->mutex,NULL);
405 pthread_cond_init(&buf->cond,NULL);
407 return (HANDLE)buf;
410 HANDLE CreateThread(void *TA, DWORD stackSize, DWORD (*ThreadProc)(LPVOID), LPVOID parm, DWORD cf, DWORD *tidOut)
412 #ifdef SWELL_TARGET_OSX
413 SWELL_EnsureMultithreadedCocoa();
414 #endif
415 SWELL_InternalObjectHeader_Thread *buf = (SWELL_InternalObjectHeader_Thread *)malloc(sizeof(SWELL_InternalObjectHeader_Thread));
416 buf->hdr.type=INTERNAL_OBJECT_THREAD;
417 buf->hdr.count=2;
418 buf->threadProc=ThreadProc;
419 buf->threadParm = parm;
420 buf->retv=0;
421 buf->pt=0;
422 buf->done=0;
423 pthread_create(&buf->pt,NULL,__threadproc,buf);
425 if (tidOut) *tidOut=(DWORD)(INT_PTR)buf->pt; // incorrect on x64
427 return (HANDLE)buf;
431 BOOL SetThreadPriority(HANDLE hand, int prio)
433 SWELL_InternalObjectHeader_Thread *evt=(SWELL_InternalObjectHeader_Thread*)hand;
435 #ifdef __linux__
436 static int s_rt_max;
437 if (!evt && prio >= 0x10000 && prio < 0x10000 + 100)
439 s_rt_max = prio - 0x10000;
440 return TRUE;
442 #endif
444 if (!evt || evt->hdr.type != INTERNAL_OBJECT_THREAD) return FALSE;
446 if (evt->done) return FALSE;
448 int pol;
449 struct sched_param param;
450 memset(&param,0,sizeof(param));
452 #ifdef __linux__
453 // linux only has meaningful priorities if using realtime threads,
454 // for this to be enabled the caller should use:
455 // #ifdef __linux__
456 // SetThreadPriority(NULL,0x10000 + max_thread_priority (0..99));
457 // #endif
458 if (s_rt_max < 1 || prio <= THREAD_PRIORITY_NORMAL)
460 pol = SCHED_NORMAL;
461 param.sched_priority=0;
463 else
465 int lb = s_rt_max;
466 if (prio < THREAD_PRIORITY_TIME_CRITICAL)
468 lb--;
469 if (prio < THREAD_PRIORITY_HIGHEST)
471 lb--;
472 if (prio < THREAD_PRIORITY_ABOVE_NORMAL) lb--;
475 param.sched_priority = lb < 1 ? 1 : lb;
476 pol = SCHED_RR;
478 return !pthread_setschedparam(evt->pt,pol,&param);
479 #else
480 if (!pthread_getschedparam(evt->pt,&pol,&param))
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,&param))
490 return TRUE;
493 return FALSE;
494 #endif
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);
504 if (!evt->isSignal)
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);
511 return TRUE;
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)
520 fd_set s;
521 FD_ZERO(&s);
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
526 char c=0;
527 write(se->socket[1],&c,1);
529 return TRUE;
531 return FALSE;
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)
539 evt->isSignal=false;
540 return TRUE;
542 if (evt->hdr.type == INTERNAL_OBJECT_SOCKETEVENT)
544 SWELL_InternalObjectHeader_SocketEvent *se=(SWELL_InternalObjectHeader_SocketEvent*)hand;
545 if (se->socket[0]>=0)
547 char buf[128];
548 read(se->socket[0],buf,sizeof(buf));
550 return TRUE;
552 return FALSE;
555 BOOL WinOffsetRect(LPRECT lprc, int dx, int dy)
557 if(!lprc) return 0;
558 lprc->left+=dx;
559 lprc->top+=dy;
560 lprc->right+=dx;
561 lprc->bottom+=dy;
562 return TRUE;
565 BOOL WinSetRect(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom)
567 if(!lprc) return 0;
568 lprc->left = xLeft;
569 lprc->top = yTop;
570 lprc->right = xRight;
571 lprc->bottom = yBottom;
572 return TRUE;
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)
597 *out = *in2;
599 else if (in2->left == in2->right && in2->top == in2->bottom)
601 *out = *in1;
603 else
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);
613 typedef struct
615 int sz;
616 int refcnt;
617 } GLOBAL_REC;
620 void *GlobalLock(HANDLE h)
622 if (!h) return 0;
623 GLOBAL_REC *rec=((GLOBAL_REC*)h)-1;
624 rec->refcnt++;
625 return h;
627 int GlobalSize(HANDLE h)
629 if (!h) return 0;
630 GLOBAL_REC *rec=((GLOBAL_REC*)h)-1;
631 return rec->sz;
634 void GlobalUnlock(HANDLE h)
636 if (!h) return;
637 GLOBAL_REC *rec=((GLOBAL_REC*)h)-1;
638 rec->refcnt--;
640 void GlobalFree(HANDLE h)
642 if (!h) return;
643 GLOBAL_REC *rec=((GLOBAL_REC*)h)-1;
644 if (rec->refcnt)
646 // note error freeing locked ram
648 free(rec);
651 HANDLE GlobalAlloc(int flags, int sz)
653 if (sz<0)sz=0;
654 GLOBAL_REC *rec=(GLOBAL_REC*)malloc(sizeof(GLOBAL_REC)+sz);
655 if (!rec) return 0;
656 rec->sz=sz;
657 rec->refcnt=0;
658 if (flags&GMEM_FIXED) memset(rec+1,0,sz);
659 return rec+1;
662 char *lstrcpyn(char *dest, const char *src, int l)
664 if (l<1) return dest;
666 char *dsrc=dest;
667 while (--l > 0)
669 char p=*src++;
670 if (!p) break;
671 *dest++=p;
673 *dest++=0;
675 return dsrc;
678 static WDL_Mutex s_libraryMutex;
679 static int libkeycomp(void **p1, void **p2)
681 INT_PTR a=(INT_PTR)(*p1) - (INT_PTR)(*p2);
682 if (a<0)return -1;
683 if (a>0) return 1;
684 return 0;
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
699 struct stat ss;
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);
704 CFRelease(str);
706 bundleinst=(void *)CFBundleCreate(NULL,r);
707 CFRelease(r);
709 if (bundleinst)
711 if (!CFBundleLoadExecutable((CFBundleRef)bundleinst))
713 CFRelease((CFBundleRef)bundleinst);
714 bundleinst=NULL;
718 #endif
720 #ifdef SWELL_TARGET_OSX
721 if (!bundleinst)
722 #endif
724 inst=dlopen(fn,RTLD_NOW|(symbolsAsGlobals?RTLD_GLOBAL:RTLD_LOCAL));
725 if (!inst) return 0;
728 WDL_MutexLock lock(&s_libraryMutex);
730 SWELL_HINSTANCE *rec = s_loadedLibs.Get(bundleinst ? bundleinst : inst);
731 if (!rec)
733 rec = (SWELL_HINSTANCE *)calloc(sizeof(SWELL_HINSTANCE),1);
734 rec->instptr = inst;
735 #ifdef __APPLE__
736 rec->bundleinstptr = bundleinst;
737 #endif
738 rec->refcnt = 1;
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");
744 if (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?
750 FreeLibrary(rec);
751 return 0;
753 *(void **)&dllMain = GetProcAddress(rec,"DllMain");
754 if (dllMain)
756 if (!dllMain(rec,DLL_PROCESS_ATTACH,NULL))
758 SWELL_dllMain(rec,DLL_PROCESS_DETACH,(void*)NULL);
759 FreeLibrary(rec);
760 return 0;
764 rec->SWELL_dllMain = SWELL_dllMain;
765 rec->dllMain = dllMain;
767 else rec->refcnt++;
769 return rec;
772 void *GetProcAddress(HINSTANCE hInst, const char *procName)
774 if (!hInst) return 0;
776 SWELL_HINSTANCE *rec=(SWELL_HINSTANCE*)hInst;
778 void *ret = NULL;
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;
785 CFRelease(str);
786 return ret;
788 #endif
789 if (rec->instptr) ret=(void *)dlsym(rec->instptr, procName);
790 if (ret) rec->lastSymbolRequested=ret;
791 return ret;
794 BOOL FreeLibrary(HINSTANCE hInst)
796 if (!hInst) return FALSE;
798 WDL_MutexLock lock(&s_libraryMutex);
800 bool dofree=false;
801 SWELL_HINSTANCE *rec=(SWELL_HINSTANCE*)hInst;
802 if (--rec->refcnt<=0)
804 dofree=true;
805 #ifdef SWELL_TARGET_OSX
806 s_loadedLibs.Delete(rec->bundleinstptr ? rec->bundleinstptr : rec->instptr);
807 #else
808 s_loadedLibs.Delete(rec->instptr);
809 #endif
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);
823 #endif
824 if (rec->instptr) dlclose(rec->instptr);
826 if (dofree) free(rec);
827 return TRUE;
830 void* SWELL_GetBundle(HINSTANCE hInst)
832 SWELL_HINSTANCE* rec=(SWELL_HINSTANCE*)hInst;
833 #ifdef SWELL_TARGET_OSX
834 if (rec) return rec->bundleinstptr;
835 #else
836 if (rec) return rec->instptr;
837 #endif
838 return NULL;
841 DWORD GetModuleFileName(HINSTANCE hInst, char *fn, DWORD nSize)
843 *fn=0;
845 void *instptr = NULL, *lastSymbolRequested=NULL;
846 #ifdef SWELL_TARGET_OSX
847 void *bundleinstptr=NULL;
848 #endif
849 if (hInst)
851 SWELL_HINSTANCE *p = (SWELL_HINSTANCE*)hInst;
852 instptr = p->instptr;
853 #ifdef SWELL_TARGET_OSX
854 bundleinstptr = p->bundleinstptr;
855 #endif
856 lastSymbolRequested=p->lastSymbolRequested;
858 #ifdef SWELL_TARGET_OSX
859 if (!instptr || bundleinstptr)
861 CFBundleRef bund=bundleinstptr ? (CFBundleRef)bundleinstptr : CFBundleGetMainBundle();
862 if (bund)
864 CFURLRef url=CFBundleCopyBundleURL(bund);
865 if (url)
867 char buf[8192];
868 if (CFURLGetFileSystemRepresentation(url,true,(UInt8*)buf,sizeof(buf))) lstrcpyn(fn,buf,nSize);
869 CFRelease(url);
872 return (DWORD)strlen(fn);
874 #elif defined(__linux__)
875 if (!instptr) // get exe file name
877 char tmp[64];
878 sprintf(tmp,"/proc/%d/exe",getpid());
879 int sz=readlink(tmp,fn,nSize);
880 if (sz<0)sz=0;
881 else if ((DWORD)sz>=nSize)sz=nSize-1;
882 fn[sz]=0;
883 return sz;
885 #endif
887 if (instptr && lastSymbolRequested)
889 Dl_info inf={0,};
890 dladdr(lastSymbolRequested,&inf);
891 if (inf.dli_fname)
893 lstrcpyn(fn,inf.dli_fname,nSize);
894 return (DWORD)strlen(fn);
897 return 0;
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);
908 CFRelease(r);
909 return true;
910 #else
911 int f = open("/dev/urandom",O_RDONLY);
912 if (f<0) return false;
914 int v = read(f,g,sizeof(GUID));
915 close(f);
916 return v == sizeof(GUID);
917 #endif
922 void GetTempPath(int bufsz, char *buf)
924 if (bufsz<2)
926 if (bufsz>0) *buf=0;
927 return;
930 #ifdef __APPLE__
931 const char *p = getenv("TMPDIR");
932 #else
933 const char *p = getenv("TEMP");
934 #endif
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;
943 buf[len] = '/';
944 buf[len+1]=0;
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
961 char buf[128];
962 GetPrivateProfileString(".swell","max_open_files","",buf,sizeof(buf),"");
963 if (!buf[0])
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))
974 rl.rlim_cur = n;
975 setrlimit(RLIMIT_NOFILE,&rl);
976 #ifdef _DEBUG
977 getrlimit(RLIMIT_NOFILE,&rl);
978 printf("applied rlimit %d/%d\n",(int)rl.rlim_cur,(int)rl.rlim_max);
979 #endif
981 #endif
983 #ifdef SWELL_TARGET_GDK
984 GetPrivateProfileString(".swell","ui_scale","",buf,sizeof(buf),"");
985 if (buf[0])
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)
992 #undef __scale
993 g_swell_ui_scale = (int) (256 * sc + 0.5);
996 else
998 WritePrivateProfileString(".swell","ui_scale","1.0 // scales the sizes in libSwell.colortheme","");
1000 #endif
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] != '-');
1012 #endif
1013 return NULL;
1017 #endif