#include <config.h>
#include "Fl_Posix_System_Driver.H"
#include "../../flstring.h"
#include <FL/Fl_File_Icon.H>
#include <FL/filename.H>
#include <FL/fl_string_functions.h>
#include <FL/Fl.H>
#include <locale.h>
#include <stdio.h>
#if HAVE_DLFCN_H
# include <dlfcn.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <pwd.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#ifndef S_ISDIR
# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif
#if HAVE_DLFCN_H
void *Fl_Posix_System_Driver::load(const char *filename) {
return ::dlopen(filename, RTLD_LAZY);
}
#endif
int Fl_Posix_System_Driver::file_type(const char *filename)
{
int filetype;
struct stat fileinfo; if (!::stat(filename, &fileinfo))
{
if (S_ISDIR(fileinfo.st_mode))
filetype = Fl_File_Icon::DIRECTORY;
# ifdef S_ISFIFO
else if (S_ISFIFO(fileinfo.st_mode))
filetype = Fl_File_Icon::FIFO;
# endif # if defined(S_ISCHR) && defined(S_ISBLK)
else if (S_ISCHR(fileinfo.st_mode) || S_ISBLK(fileinfo.st_mode))
filetype = Fl_File_Icon::DEVICE;
# endif # ifdef S_ISLNK
else if (S_ISLNK(fileinfo.st_mode))
filetype = Fl_File_Icon::LINK;
# endif else
filetype = Fl_File_Icon::PLAIN;
}
else
filetype = Fl_File_Icon::PLAIN;
return filetype;
}
const char *Fl_Posix_System_Driver::getpwnam(const char *login) {
struct passwd *pwd;
pwd = ::getpwnam(login);
return pwd ? pwd->pw_dir : NULL;
}
void Fl_Posix_System_Driver::gettime(time_t *sec, int *usec) {
struct timeval tv;
gettimeofday(&tv, NULL);
*sec = tv.tv_sec;
*usec = tv.tv_usec;
}
int Fl_Posix_System_Driver::run_program(const char *program, char **argv, char *msg, int msglen) {
pid_t pid; int status; sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, &oldset);
if ((pid = fork()) == 0) {
if (!fork()) {
close(0);
::open("/dev/null", O_RDONLY);
close(1);
::open("/dev/null", O_WRONLY);
close(2);
::open("/dev/null", O_WRONLY);
setsid();
execv(program, argv);
_exit(0);
} else {
_exit(0);
}
} else if (pid < 0) {
sigprocmask(SIG_SETMASK, &oldset, NULL);
return 0;
}
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
if (msg) snprintf(msg, msglen, "waitpid(%ld) failed: %s", (long)pid,
strerror(errno));
sigprocmask(SIG_SETMASK, &oldset, NULL);
return 0;
}
}
sigprocmask(SIG_SETMASK, &oldset, NULL);
return 1;
}
#if HAVE_DLSYM && HAVE_DLFCN_H && !defined (__APPLE_CC__)
static void* quadruple_dlopen(const char *libname)
{
char filename2[FL_PATH_MAX];
snprintf(filename2, FL_PATH_MAX, "%s.so", libname);
void *ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
if (!ptr) {
snprintf(filename2, FL_PATH_MAX, "%s.so.2", libname);
ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
if (!ptr) {
snprintf(filename2, FL_PATH_MAX, "%s.so.1", libname);
ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
if (!ptr) {
snprintf(filename2, FL_PATH_MAX, "%s.so.0", libname);
ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
}
}
}
return ptr;
}
#endif
void *Fl_Posix_System_Driver::dlopen_or_dlsym(const char *lib_name, const char *func_name)
{
void *lib_address = NULL;
#if HAVE_DLSYM && HAVE_DLFCN_H
void *func_ptr = NULL;
if (func_name) {
#ifdef RTLD_DEFAULT
func_ptr = dlsym(RTLD_DEFAULT, func_name);
#else
void *p = dlopen(NULL, RTLD_LAZY);
func_ptr = dlsym(p, func_name);
#endif
if (func_ptr) return func_ptr;
}
#ifdef __APPLE_CC__
if (lib_name) {
char path[FL_PATH_MAX];
snprintf(path, FL_PATH_MAX, "/opt/X11/lib/%s.dylib", lib_name);
lib_address = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!lib_address) {
snprintf(path, FL_PATH_MAX, "/opt/homebrew/lib/%s.dylib", lib_name);
lib_address = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!lib_address) {
snprintf(path, FL_PATH_MAX, "/opt/sw/lib/%s.dylib", lib_name);
lib_address = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!lib_address) {
snprintf(path, FL_PATH_MAX, "/sw/lib/%s.dylib", lib_name);
lib_address = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!lib_address && !strcmp(lib_name, "libgtk-x11-2.0")) {
lib_address = dlopen("/opt/homebrew/lib/libgtkmacintegration-gtk2.dylib", RTLD_LAZY | RTLD_GLOBAL);
}
}
}
}
}
#else
if (lib_name) lib_address = quadruple_dlopen(lib_name);
#endif if (func_name && lib_address) return ::dlsym(lib_address, func_name);
#endif return lib_address;
}
#if HAVE_DLSYM && HAVE_DLFCN_H
void *Fl_Posix_System_Driver::ptr_gtk = NULL;
bool Fl_Posix_System_Driver::probe_for_GTK(int major, int minor, void **p_ptr_gtk) {
typedef int (*init_t)(int*, char***);
init_t init_f = NULL;
if (Fl_Posix_System_Driver::ptr_gtk) { *p_ptr_gtk = Fl_Posix_System_Driver::ptr_gtk;
return true;
}
Fl_Posix_System_Driver::ptr_gtk = Fl_Posix_System_Driver::dlopen_or_dlsym("libgtk-3");
if (Fl_Posix_System_Driver::ptr_gtk) {
#ifdef DEBUG
puts("selected GTK-3\n");
#endif
} else {
Fl_Posix_System_Driver::ptr_gtk = Fl_Posix_System_Driver::dlopen_or_dlsym("libgtk-x11-2.0");
#ifdef DEBUG
if (Fl_Posix_System_Driver::ptr_gtk) {
puts("selected GTK-2\n");
}
#endif
}
if (!Fl_Posix_System_Driver::ptr_gtk) {
#ifdef DEBUG
puts("Failure to load libgtk");
#endif
return false;
}
init_f = (init_t)dlsym(Fl_Posix_System_Driver::ptr_gtk, "gtk_init_check");
if (!init_f) return false;
*p_ptr_gtk = Fl_Posix_System_Driver::ptr_gtk;
char *before = NULL;
char *p = setlocale(LC_ALL, NULL);
if (p) before = fl_strdup(p);
int ac = 0;
if ( !init_f(&ac, NULL) ) { free(before);
return false;
}
if (before) {
setlocale(LC_ALL, before); free(before);
}
if (dlsym(Fl_Posix_System_Driver::ptr_gtk, "gtk_get_major_version") == NULL) { typedef const char* (*check_t)(int, int, int);
check_t check_f = (check_t)dlsym(Fl_Posix_System_Driver::ptr_gtk, "gtk_check_version");
if (!check_f || check_f(major, minor, 0) ) return false;
}
return true;
}
#endif
int Fl_Posix_System_Driver::close_fd(int fd) { return close(fd); }
#if defined(HAVE_PTHREAD)
# include <unistd.h>
# include <fcntl.h>
# include <pthread.h>
static int thread_filedes[2];
static pthread_mutex_t fltk_mutex;
static pthread_t owner;
static int counter;
static void lock_function_init_std() {
pthread_mutex_init(&fltk_mutex, NULL);
}
static void lock_function_std() {
if (!counter || owner != pthread_self()) {
pthread_mutex_lock(&fltk_mutex);
owner = pthread_self();
}
counter++;
}
static void unlock_function_std() {
if (!--counter) pthread_mutex_unlock(&fltk_mutex);
}
# ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
static bool lock_function_init_rec() {
pthread_mutexattr_t attrib;
pthread_mutexattr_init(&attrib);
if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) {
pthread_mutexattr_destroy(&attrib);
return true;
}
pthread_mutex_init(&fltk_mutex, &attrib);
return false;
}
static void lock_function_rec() {
pthread_mutex_lock(&fltk_mutex);
}
static void unlock_function_rec() {
pthread_mutex_unlock(&fltk_mutex);
}
# endif
void Fl_Posix_System_Driver::awake(void* msg) {
if (thread_filedes[1]) {
if (write(thread_filedes[1], &msg, sizeof(void*))==0) { }
}
}
static void* thread_message_;
void* Fl_Posix_System_Driver::thread_message() {
void* r = thread_message_;
thread_message_ = 0;
return r;
}
static void thread_awake_cb(int fd, void*) {
if (read(fd, &thread_message_, sizeof(void*))==0) {
}
Fl_Awake_Handler func;
void *data;
while (Fl::get_awake_handler_(func, data)==0) {
(*func)(data);
}
}
extern void (*fl_lock_function)();
extern void (*fl_unlock_function)();
int Fl_Posix_System_Driver::lock() {
if (!thread_filedes[1]) {
if (pipe(thread_filedes)==-1) {
}
fcntl(thread_filedes[1], F_SETFL,
fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK);
Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb);
# ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
if (!lock_function_init_rec()) {
fl_lock_function = lock_function_rec;
fl_unlock_function = unlock_function_rec;
} else {
# endif lock_function_init_std();
fl_lock_function = lock_function_std;
fl_unlock_function = unlock_function_std;
# ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
}
# endif }
fl_lock_function();
return 0;
}
void Fl_Posix_System_Driver::unlock() {
fl_unlock_function();
}
static pthread_mutex_t *ring_mutex;
void Fl_Posix_System_Driver::unlock_ring() {
pthread_mutex_unlock(ring_mutex);
}
void Fl_Posix_System_Driver::lock_ring() {
if (!ring_mutex) {
ring_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(ring_mutex, NULL);
}
pthread_mutex_lock(ring_mutex);
}
#else
void Fl_Posix_System_Driver::awake(void*) {}
int Fl_Posix_System_Driver::lock() { return 1; }
void Fl_Posix_System_Driver::unlock() {}
void* Fl_Posix_System_Driver::thread_message() { return NULL; }
#endif