Sun, 09 Jun 2024 15:43:08 +0200
update toolkit
--- a/application/Makefile Mon Feb 12 21:13:23 2024 +0100 +++ b/application/Makefile Sun Jun 09 15:43:08 2024 +0200 @@ -29,17 +29,23 @@ BUILD_ROOT = .. include ../config.mk -CFLAGS += -I../ui/ -I../ucx +CFLAGS += -I../ui/ -I../ucx -I.. -SRC = main.c +SRC = main.c +SRC += application.c +SRC += config.c +SRC += davcontroller.c +SRC += pwd.c +SRC += system.c +SRC += window.c OBJ = $(SRC:%.c=../build/application/%.$(OBJ_EXT)) all: ../build/bin/mk12 ../build/bin/mk12: $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a - $(LD) -o ../build/bin/mk12$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx $(LDFLAGS) $(TK_LDFLAGS) + $(CC) -o ../build/bin/mk12$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) ../build/application/%.$(OBJ_EXT): %.c - $(CC) ../ucx $(CFLAGS) $(TK_CFLAGS) -o $@ -c $< + $(CC) ../ucx $(CFLAGS) $(TK_CFLAGS) $(DAV_CFLAGS) -o $@ -c $<
--- a/configure Mon Feb 12 21:13:23 2024 +0100 +++ b/configure Sun Jun 09 15:43:08 2024 +0200 @@ -1,40 +1,53 @@ #!/bin/sh - -PREFIX=/usr -EPREFIX=$PREFIX +# create temporary directory +TEMP_DIR=".tmp-`uname -n`" +rm -Rf "$TEMP_DIR" +if mkdir -p "$TEMP_DIR"; then + : +else + echo "Cannot create tmp dir $TEMP_DIR" + echo "Abort" + exit 1 +fi +touch "$TEMP_DIR/options" +touch "$TEMP_DIR/features" -BINDIR= -SBINDIR= -LIBDIR= -LIBEXECDIR= -DATADIR= -SYSCONFDIR= -SHAREDSTATEDIR= -LOCALSTATEDIR= -INCLUDEDIR= -INFODIR= -MANDIR= +# define standard variables +# also define standard prefix (this is where we will search for config.site) +prefix=/usr +exec_prefix= +bindir= +sbindir= +libdir= +libexecdir= +datarootdir= +datadir= +sysconfdir= +sharedstatedir= +localstatedir= +runstatedir= +includedir= +infodir= +localedir= +mandir= -OS=`uname -s` -OS_VERSION=`uname -r` - -TEMP_DIR=".tmp-`uname -n`" -mkdir -p $TEMP_DIR -if [ $? -ne 0 ]; then - echo "Cannot create tmp dir" - echo "Abort" -fi -touch $TEMP_DIR/options -touch $TEMP_DIR/features +# custom variables # features +# clean abort +abort_configure() +{ + rm -Rf "$TEMP_DIR" + exit 1 +} + # help text printhelp() { - echo "Usage: $0 [OPTIONS]..." - cat << __EOF__ + echo "Usage: $0 [OPTIONS]..." + cat << __EOF__ Installation directories: --prefix=PREFIX path prefix for architecture-independent files [/usr] @@ -47,497 +60,692 @@ --sysconfdir=DIR system configuration files [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR run-time variable data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --mandir=DIR man documentation [DATAROOTDIR/man] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] Options: + --debug add extra compile flags for debug builds + --release add extra compile flags for release builds --toolkit=(gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|motif) __EOF__ } # -# parse arguments +# parse arguments # -for ARG in $@ +BUILD_TYPE="default" +for ARG in "$@" do case "$ARG" in - "--prefix="*) PREFIX=${ARG#--prefix=} ;; - "--exec-prefix="*) EPREFIX=${ARG#--exec-prefix=} ;; - "--bindir="*) BINDIR=${ARG#----bindir=} ;; - "--sbindir="*) SBINDIR=${ARG#--sbindir=} ;; - "--libdir="*) LIBDIR=${ARG#--libdir=} ;; - "--libexecdir="*) LIBEXECDIR=${ARG#--libexecdir=} ;; - "--datadir="*) DATADIR=${ARG#--datadir=} ;; - "--sysconfdir="*) SYSCONFDIR=${ARG#--sysconfdir=} ;; - "--sharedstatedir="*) SHAREDSTATEDIR=${ARG#--sharedstatedir=} ;; - "--localstatedir="*) LOCALSTATEDIR=${ARG#--localstatedir=} ;; - "--includedir="*) INCLUDEDIR=${ARG#--includedir=} ;; - "--infodir="*) INFODIR=${ARG#--infodir=} ;; - "--mandir"*) MANDIR=${ARG#--mandir} ;; - "--help"*) printhelp; exit 1 ;; - "--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;; - "-"*) echo "unknown option: $ARG"; exit 1 ;; - esac + "--prefix="*) prefix=${ARG#--prefix=} ;; + "--exec-prefix="*) exec_prefix=${ARG#--exec-prefix=} ;; + "--bindir="*) bindir=${ARG#----bindir=} ;; + "--sbindir="*) sbindir=${ARG#--sbindir=} ;; + "--libdir="*) libdir=${ARG#--libdir=} ;; + "--libexecdir="*) libexecdir=${ARG#--libexecdir=} ;; + "--datarootdir="*) datarootdir=${ARG#--datarootdir=} ;; + "--datadir="*) datadir=${ARG#--datadir=} ;; + "--sysconfdir="*) sysconfdir=${ARG#--sysconfdir=} ;; + "--sharedstatedir="*) sharedstatedir=${ARG#--sharedstatedir=} ;; + "--localstatedir="*) localstatedir=${ARG#--localstatedir=} ;; + "--includedir="*) includedir=${ARG#--includedir=} ;; + "--infodir="*) infodir=${ARG#--infodir=} ;; + "--mandir"*) mandir=${ARG#--mandir} ;; + "--localedir"*) localedir=${ARG#--localedir} ;; + "--help"*) printhelp; abort_configure ;; + "--debug") BUILD_TYPE="debug" ;; + "--release") BUILD_TYPE="release" ;; + "--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;; + "-"*) echo "unknown option: $ARG"; abort_configure ;; + esac done -# set dir variables -if [ -z "$BINDIR" ]; then - BINDIR=$EPREFIX/bin -fi -if [ -z "$SBINDIR" ]; then - SBINDIR=$EPREFIX/sbin -fi -if [ -z "$LIBDIR" ]; then - LIBDIR=$EPREFIX/lib -fi -if [ -z "$LIBEXEC" ]; then - LIBEXECDIR=$EPREFIX/libexec -fi -if [ -z "$DATADIR" ]; then - DATADIR=$PREFIX/share -fi -if [ -z "$SYSCONFDIR" ]; then - SYSCONFDIR=$PREFIX/etc -fi -if [ -z "$SHAREDSTATEDIR" ]; then - SHAREDSTATEDIR=$PREFIX/com -fi -if [ -z "$LOCALSTATEDIR" ]; then - LOCALSTATEDIR=$PREFIX/var -fi -if [ -z "$INCLUDEDIR" ]; then - INCLUDEDIR=$PREFIX/include -fi -if [ -z "$INFODIR" ]; then - INFODIR=$PREFIX/info -fi -if [ -z "$MANDIR" ]; then - MANDIR=$PREFIX/man + + +# set defaults for dir variables +: ${exec_prefix:="$prefix"} +: ${bindir:='${exec_prefix}/bin'} +: ${sbindir:='${exec_prefix}/sbin'} +: ${libdir:='${exec_prefix}/lib'} +: ${libexecdir:='${exec_prefix}/libexec'} +: ${datarootdir:='${prefix}/share'} +: ${datadir:='${datarootdir}'} +: ${sysconfdir:='${prefix}/etc'} +: ${sharedstatedir:='${prefix}/com'} +: ${localstatedir:='${prefix}/var'} +: ${runstatedir:='${localstatedir}/run'} +: ${includedir:='${prefix}/include'} +: ${infodir:='${datarootdir}/info'} +: ${mandir:='${datarootdir}/man'} +: ${localedir:='${datarootdir}/locale'} + +# check if a config.site exists and load it +if [ -n "$CONFIG_SITE" ]; then + # CONFIG_SITE may contain space separated file names + for cs in $CONFIG_SITE; do + printf "loading defaults from $cs... " + . "$cs" + echo ok + done +elif [ -f "$prefix/share/config.site" ]; then + printf "loading site defaults... " + . "$prefix/share/config.site" + echo ok +elif [ -f "$prefix/etc/config.site" ]; then + printf "loading site defaults... " + . "$prefix/etc/config.site" + echo ok fi -which pkg-config > /dev/null -if [ $? -eq 0 ]; then - PKG_CONFIG=pkg-config -else - PKG_CONFIG=false -fi +# Test for availability of pkg-config +PKG_CONFIG=`command -v pkg-config` +: ${PKG_CONFIG:="false"} # Simple uname based platform detection # $PLATFORM is used for platform dependent dependency selection +OS=`uname -s` +OS_VERSION=`uname -r` printf "detect platform... " -if [ $OS = SunOS ]; then +if [ "$OS" = "SunOS" ]; then PLATFORM="solaris sunos unix svr4" -fi -if [ $OS = Linux ]; then +elif [ "$OS" = "Linux" ]; then PLATFORM="linux unix" -fi -if [ $OS = FreeBSD ]; then +elif [ "$OS" = "FreeBSD" ]; then PLATFORM="freebsd bsd unix" -fi -if [ $OS = Darwin ]; then +elif [ "$OS" = "OpenBSD" ]; then + PLATFORM="openbsd bsd unix" +elif [ "$OS" = "NetBSD" ]; then + PLATFORM="netbsd bsd unix" +elif [ "$OS" = "Darwin" ]; then PLATFORM="macos osx bsd unix" -fi -echo $OS | grep "MINGW" > /dev/null -if [ $? -eq 0 ]; then +elif echo "$OS" | grep -i "MINGW" > /dev/null; then PLATFORM="windows mingw" fi - -if [ -z "$PLATFORM" ]; then - PLATFORM="unix" -fi +: ${PLATFORM:="unix"} -for p in $PLATFORM -do - PLATFORM_NAME=$p - break -done -echo $PLATFORM_NAME +PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -` +echo "$PLATFORM_NAME" isplatform() { for p in $PLATFORM do - if [ $p = $1 ]; then + if [ "$p" = "$1" ]; then return 0 fi done return 1 } -isnotplatform() +notisplatform() { for p in $PLATFORM do - if [ $p = $1 ]; then + if [ "$p" = "$1" ]; then + return 1 + fi + done + return 0 +} +istoolchain() +{ + for t in $TOOLCHAIN + do + if [ "$t" = "$1" ]; then + return 0 + fi + done + return 1 +} +notistoolchain() +{ + for t in $TOOLCHAIN + do + if [ "$t" = "$1" ]; then return 1 fi done return 0 } -# generate config.mk and config.h -cat > $TEMP_DIR/config.mk << __EOF__ -# -# config.mk generated by configure -# -# general vars - -PREFIX=$PREFIX -EPREFIX=$EPREFIX - -BINDIR=$BINDIR -SBINDIR=$SBINDIR -LIBDIR=$LIBDIR -LIBEXECDIR=$LIBEXECDIR -DATADIR=$DATADIR -SYSCONFDIR=$SYSCONFDIR -SHAREDSTATEDIR=$SHAREDSTATEDIR -LOCALSTATEDIR=$LOCALSTATEDIR -INCLUDEDIR=$INCLUDEDIR -INFODIR=$INFODIR -MANDIR=$MANDIR - +# generate vars.mk +cat > "$TEMP_DIR/vars.mk" << __EOF__ +prefix=$prefix +exec_prefix=$exec_prefix +bindir=$bindir +sbindir=$sbindir +libdir=$libdir +libexecdir=$libexecdir +datarootdir=$datarootdir +datadir=$datadir +sysconfdir=$sysconfdir +sharedstatedir=$sharedstatedir +localstatedir=$localstatedir +runstatedir=$runstatedir +includedir=$includedir +infodir=$infodir +mandir=$mandir +localedir=$localedir __EOF__ -echo > $TEMP_DIR/make.mk - -ENV_CFLAGS=$CFLAGS -ENV_LDFLAGS=$LDFLAGS -ENV_CXXFLAGS=$CXXFLAGS - -# Toolchain detection -# this will insert make vars to config.mk +# toolchain detection utilities . make/toolchain.sh -# add user specified flags to config.mk -echo >> $TEMP_DIR/config.mk -if [ ! -z "${ENV_CFLAGS}" ]; then - echo "CFLAGS += $ENV_CFLAGS" >> $TEMP_DIR/config.mk -fi -if [ ! -z "${ENV_CXXFLAGS}" ]; then - echo "CXXFLAGS += $ENV_CXXFLAGS" >> $TEMP_DIR/config.mk -fi -if [ ! -z "${ENV_LDFLAGS}" ]; then - echo "LDFLAGS += $ENV_LDFLAGS" >> $TEMP_DIR/config.mk -fi - # # DEPENDENCIES # -dependency_qt4() +# check languages +lang_c= +lang_cpp= +if detect_c_compiler ; then + lang_c=1 +fi + +# create buffer for make variables required by dependencies +echo > "$TEMP_DIR/make.mk" + +test_pkg_config() { - printf "checking for qt4... " - # dependency qt4 + if "$PKG_CONFIG" --exists "$1" ; then : + else return 1 ; fi + if [ -z "$2" ] || "$PKG_CONFIG" --atleast-version="$2" "$1" ; then : + else return 1 ; fi + if [ -z "$3" ] || "$PKG_CONFIG" --exact-version="$3" "$1" ; then : + else return 1 ; fi + if [ -z "$4" ] || "$PKG_CONFIG" --max-version="$4" "$1" ; then : + else return 1 ; fi + return 0 +} + +print_check_msg() +{ + if [ -z "$1" ]; then + shift + printf "$@" + fi +} + +dependency_error_gtk2legacy() +{ + print_check_msg "$dep_checked_gtk2legacy" "checking for gtk2legacy... " + # dependency gtk2legacy while true do - qmake-qt4 -o - /dev/null | grep DEFINES\ > /dev/null - if [ $? -eq 0 ]; then - CFLAGS="$CFLAGS `qmake-qt4 -o - /dev/null | grep DEFINES\ `" - else + if [ -z "$PKG_CONFIG" ]; then break fi - qmake-qt4 -o - /dev/null | grep INCPATH\ > /dev/null - if [ $? -eq 0 ]; then - CFLAGS="$CFLAGS `qmake-qt4 -o - /dev/null | grep INCPATH\ `" + if test_pkg_config "gtk+-2.0" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-2.0`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-2.0`" else break fi - > /dev/null - if [ $? -eq 0 ]; then - LDFLAGS="$LDFLAGS ``" + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK2 -DUI_GTK2LEGACY" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread" + print_check_msg "$dep_checked_gtk2legacy" "yes\n" + dep_checked_gtk2legacy=1 + return 1 + done + + print_check_msg "$dep_checked_gtk2legacy" "no\n" + dep_checked_gtk2legacy=1 + return 0 +} +dependency_error_curl() +{ + print_check_msg "$dep_checked_curl" "checking for curl... " + # dependency curl platform="macos" + while true + do + if notisplatform "macos"; then + break + fi + if tmp_flags=`curl-config --cflags` ; then + TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags" else break fi - which qmake-qt4 > /dev/null - if [ $? -ne 0 ]; then - break + if tmp_flags=`curl-config --ldflags` ; then + TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags" + else + break fi - echo yes - return 0 + print_check_msg "$dep_checked_curl" "yes\n" + dep_checked_curl=1 + return 1 done - - echo no - return 1 -} -dependency_gtk2legacy() -{ - printf "checking for gtk2legacy... " - # dependency gtk2legacy + + # dependency curl while true do if [ -z "$PKG_CONFIG" ]; then - break + break fi - $PKG_CONFIG gtk+-2.0 - if [ $? -ne 0 ] ; then + if test_pkg_config "libcurl" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags libcurl`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs libcurl`" + else break fi - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags gtk+-2.0`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs gtk+-2.0`" - CFLAGS="$CFLAGS -DUI_GTK2 -DUI_GTK2LEGACY" - LDFLAGS="$LDFLAGS -lpthread" - echo yes - return 0 + print_check_msg "$dep_checked_curl" "yes\n" + dep_checked_curl=1 + return 1 done - - echo no - return 1 -} -dependency_qt5() -{ - printf "checking for qt5... " - # dependency qt5 + + # dependency curl while true do - qmake-qt5 -o - /dev/null | grep DEFINES\ > /dev/null - if [ $? -eq 0 ]; then - CFLAGS="$CFLAGS `qmake-qt5 -o - /dev/null | grep DEFINES\ `" + if tmp_flags=`curl-config --cflags` ; then + TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags" + else + break + fi + if tmp_flags=`curl-config --libs` ; then + TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags" else break fi - qmake-qt5 -o - /dev/null | grep INCPATH\ > /dev/null - if [ $? -eq 0 ]; then - CFLAGS="$CFLAGS `qmake-qt5 -o - /dev/null | grep INCPATH\ `" + print_check_msg "$dep_checked_curl" "yes\n" + dep_checked_curl=1 + return 1 + done + + print_check_msg "$dep_checked_curl" "no\n" + dep_checked_curl=1 + return 0 +} +dependency_error_gtk2() +{ + print_check_msg "$dep_checked_gtk2" "checking for gtk2... " + # dependency gtk2 + while true + do + if [ -z "$PKG_CONFIG" ]; then + break + fi + if pkg-config --atleast-version=2.20 gtk+-2.0 > /dev/null ; then + : else break fi - > /dev/null - if [ $? -eq 0 ]; then - LDFLAGS="$LDFLAGS ``" + if test_pkg_config "gtk+-2.0" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-2.0`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-2.0`" else break fi - which qmake-qt5 > /dev/null - if [ $? -ne 0 ]; then - break - fi - echo yes - return 0 + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK2" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread" + print_check_msg "$dep_checked_gtk2" "yes\n" + dep_checked_gtk2=1 + return 1 done - - echo no - return 1 + + print_check_msg "$dep_checked_gtk2" "no\n" + dep_checked_gtk2=1 + return 0 } -dependency_gtk2() +dependency_error_gtk3() { - printf "checking for gtk2... " - # dependency gtk2 + print_check_msg "$dep_checked_gtk3" "checking for gtk3... " + # dependency gtk3 + while true + do + if [ -z "$PKG_CONFIG" ]; then + break + fi + if test_pkg_config "gtk+-3.0" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-3.0`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-3.0`" + else + break + fi + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK3" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread" + print_check_msg "$dep_checked_gtk3" "yes\n" + dep_checked_gtk3=1 + return 1 + done + + print_check_msg "$dep_checked_gtk3" "no\n" + dep_checked_gtk3=1 + return 0 +} +dependency_error_gtk4() +{ + print_check_msg "$dep_checked_gtk4" "checking for gtk4... " + # dependency gtk4 while true do if [ -z "$PKG_CONFIG" ]; then - break + break + fi + if test_pkg_config "gtk+-4.0" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-4.0`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-4.0`" + else + break fi - $PKG_CONFIG gtk+-2.0 - if [ $? -ne 0 ] ; then + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK3" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread" + print_check_msg "$dep_checked_gtk4" "yes\n" + dep_checked_gtk4=1 + return 1 + done + + print_check_msg "$dep_checked_gtk4" "no\n" + dep_checked_gtk4=1 + return 0 +} +dependency_error_openssl() +{ + print_check_msg "$dep_checked_openssl" "checking for openssl... " + # dependency openssl platform="windows" + while true + do + if notisplatform "windows"; then break fi - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags gtk+-2.0`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs gtk+-2.0`" - CFLAGS="$CFLAGS -DUI_GTK2" - LDFLAGS="$LDFLAGS -lpthread" - pkg-config --atleast-version=2.20 gtk+-2.0 > /dev/null - if [ $? -ne 0 ]; then - break - fi - echo yes - return 0 + TEMP_LDFLAGS="$TEMP_LDFLAGS -lssl -lcrypto" + print_check_msg "$dep_checked_openssl" "yes\n" + dep_checked_openssl=1 + return 1 done - - echo no - return 1 -} -dependency_gtk3() -{ - printf "checking for gtk3... " - # dependency gtk3 + + # dependency openssl platform="macos" while true do - if [ -z "$PKG_CONFIG" ]; then - break - fi - $PKG_CONFIG gtk+-3.0 - if [ $? -ne 0 ] ; then + if notisplatform "macos"; then break fi - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags gtk+-3.0`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs gtk+-3.0`" - CFLAGS="$CFLAGS -DUI_GTK3" - LDFLAGS="$LDFLAGS -lpthread" - echo yes - return 0 + TEMP_LDFLAGS="$TEMP_LDFLAGS -framework CoreFoundation" + print_check_msg "$dep_checked_openssl" "yes\n" + dep_checked_openssl=1 + return 1 done - - echo no - return 1 -} -dependency_gtk4() -{ - printf "checking for gtk4... " - # dependency gtk4 + + # dependency openssl platform="bsd" + while true + do + if notisplatform "bsd"; then + break + fi + if isplatform "macos" || istoolchain "macos"; then + break + fi + TEMP_LDFLAGS="$TEMP_LDFLAGS -lssl -lcrypto" + print_check_msg "$dep_checked_openssl" "yes\n" + dep_checked_openssl=1 + return 1 + done + + # dependency openssl while true do if [ -z "$PKG_CONFIG" ]; then - break + break fi - $PKG_CONFIG gtk+-4.0 - if [ $? -ne 0 ] ; then + if test_pkg_config "openssl" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags openssl`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs openssl`" + else break fi - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags gtk+-4.0`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs gtk+-4.0`" - CFLAGS="$CFLAGS -DUI_GTK3" - LDFLAGS="$LDFLAGS -lpthread" - echo yes - return 0 + print_check_msg "$dep_checked_openssl" "yes\n" + dep_checked_openssl=1 + return 1 done - - echo no - return 1 + + print_check_msg "$dep_checked_openssl" "no\n" + dep_checked_openssl=1 + return 0 } -dependency_motif() +dependency_error_motif() { - printf "checking for motif... " + print_check_msg "$dep_checked_motif" "checking for motif... " # dependency motif platform="bsd" while true do - if isnotplatform "bsd"; then + if notisplatform "bsd"; then break fi - CFLAGS="$CFLAGS -DUI_MOTIF -I/usr/local/include/X11" - LDFLAGS="$LDFLAGS -lXm -lXt -lX11 -lpthread" - echo yes - return 0 + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_MOTIF -I/usr/local/include/X11" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lXm -lXt -lX11 -lpthread" + print_check_msg "$dep_checked_motif" "yes\n" + dep_checked_motif=1 + return 1 + done + + # dependency motif + while true + do + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_MOTIF" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lXm -lXt -lX11 -lpthread" + print_check_msg "$dep_checked_motif" "yes\n" + dep_checked_motif=1 + return 1 done - - # dependency motif + + print_check_msg "$dep_checked_motif" "no\n" + dep_checked_motif=1 + return 0 +} +dependency_error_libxml2() +{ + print_check_msg "$dep_checked_libxml2" "checking for libxml2... " + # dependency libxml2 platform="windows" + while true + do + if notisplatform "windows"; then + break + fi + if tmp_flags=`xml2-config --cflags` ; then + TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags" + else + break + fi + if tmp_flags=`xml2-config --libs` ; then + TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags" + else + break + fi + print_check_msg "$dep_checked_libxml2" "yes\n" + dep_checked_libxml2=1 + return 1 + done + + # dependency libxml2 platform="macos" while true do - CFLAGS="$CFLAGS -DUI_MOTIF" - LDFLAGS="$LDFLAGS -lXm -lXt -lX11 -lpthread" - echo yes - return 0 + if notisplatform "macos"; then + break + fi + if tmp_flags=`xml2-config --cflags` ; then + TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags" + else + break + fi + if tmp_flags=`xml2-config --libs` ; then + TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags" + else + break + fi + print_check_msg "$dep_checked_libxml2" "yes\n" + dep_checked_libxml2=1 + return 1 + done + + # dependency libxml2 + while true + do + if [ -z "$PKG_CONFIG" ]; then + break + fi + if test_pkg_config "libxml-2.0" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags libxml-2.0`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs libxml-2.0`" + else + break + fi + print_check_msg "$dep_checked_libxml2" "yes\n" + dep_checked_libxml2=1 + return 1 done - - echo no - return 1 + + # dependency libxml2 + while true + do + if tmp_flags=`xml2-config --cflags` ; then + TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags" + else + break + fi + if tmp_flags=`xml2-config --libs` ; then + TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags" + else + break + fi + print_check_msg "$dep_checked_libxml2" "yes\n" + dep_checked_libxml2=1 + return 1 + done + + print_check_msg "$dep_checked_libxml2" "no\n" + dep_checked_libxml2=1 + return 0 } -dependency_winui() +dependency_error_cocoa() { - printf "checking for winui... " + print_check_msg "$dep_checked_cocoa" "checking for cocoa... " + # dependency cocoa platform="macos" + while true + do + if notisplatform "macos"; then + break + fi + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_COCOA" + TEMP_LDFLAGS="$TEMP_LDFLAGS -lobjc -framework Cocoa" + print_check_msg "$dep_checked_cocoa" "yes\n" + dep_checked_cocoa=1 + return 1 + done + + print_check_msg "$dep_checked_cocoa" "no\n" + dep_checked_cocoa=1 + return 0 +} +dependency_error_winui() +{ + print_check_msg "$dep_checked_winui" "checking for winui... " # dependency winui platform="windows" while true do - if isnotplatform "windows"; then + if notisplatform "windows"; then break fi - CFLAGS="$CFLAGS -DUI_WINUI" - echo yes - return 0 + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WINUI" + print_check_msg "$dep_checked_winui" "yes\n" + dep_checked_winui=1 + return 1 done - - echo no - return 1 + + print_check_msg "$dep_checked_winui" "no\n" + dep_checked_winui=1 + return 0 } -dependency_cocoa() -{ - printf "checking for cocoa... " - # dependency cocoa platform="macos" - while true - do - if isnotplatform "macos"; then - break - fi - CFLAGS="$CFLAGS -DUI_COCOA" - LDFLAGS="$LDFLAGS -lobjc -framework Cocoa" - echo yes - return 0 - done - - echo no - return 1 -} + +# start collecting dependency information +echo > "$TEMP_DIR/flags.mk" DEPENDENCIES_FAILED= ERROR=0 -# general dependencies -CFLAGS= -LDFLAGS= +# unnamed dependencies +TEMP_CFLAGS= +TEMP_CXXFLAGS= +TEMP_LDFLAGS= while true do - if isnotplatform "macos"; then + while true + do + if [ -z "$lang_c" ] ; then + ERROR=1 + break + fi + + break + done + break +done +while true +do + if notisplatform "macos"; then break fi while true do - - cat >> $TEMP_DIR/make.mk << __EOF__ -OBJ_EXT = .o + + cat >> "$TEMP_DIR/make.mk" << __EOF__ +OBJ_EXT = o LIB_EXT = .a PACKAGE_SCRIPT = package_osx.sh - __EOF__ - break done - break done while true do - if isnotplatform "unix"; then + if notisplatform "unix"; then break fi - if isplatform "macos"; then + if isplatform "macos" || istoolchain "macos"; then break fi while true do - - cat >> $TEMP_DIR/make.mk << __EOF__ -OBJ_EXT = .o + + cat >> "$TEMP_DIR/make.mk" << __EOF__ +OBJ_EXT = o LIB_EXT = .a PACKAGE_SCRIPT = package_unix.sh - __EOF__ - break done - break done while true do - if isnotplatform "bsd"; then + if notisplatform "bsd"; then break fi while true do - - CFLAGS="$CFLAGS -I/usr/local/include" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - + + TEMP_CFLAGS="$TEMP_CFLAGS -I/usr/local/include" + TEMP_LDFLAGS="$TEMP_LDFLAGS -L/usr/local/lib" break done - break done -# add general dependency flags to config.mk -echo >> $TEMP_DIR/config.mk -if [ ! -z "${CFLAGS}" ]; then - echo "CFLAGS += $CFLAGS" >> $TEMP_DIR/config.mk +# add general dependency flags to flags.mk +echo "# general flags" >> "$TEMP_DIR/flags.mk" +if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then + echo "CFLAGS += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${CXXFLAGS}" ]; then - echo "CXXFLAGS += $CXXFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then + echo "CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${LDFLAGS}" ]; then - echo "LDFLAGS += $LDFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_LDFLAGS}" ]; then + echo "LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk" fi # @@ -545,274 +753,341 @@ # checkopt_toolkit_gtk4() { - VERR=0 - dependency_gtk4 - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_gtk4 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = gtk GTKOBJ = draw_cairo.o - __EOF__ - return 0 + return 0 } checkopt_toolkit_gtk3() { - VERR=0 - dependency_gtk3 - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_gtk3 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = gtk GTKOBJ = draw_cairo.o - __EOF__ - return 0 + return 0 } checkopt_toolkit_gtk2() { - VERR=0 - dependency_gtk2 - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_gtk2 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = gtk GTKOBJ = draw_cairo.o - __EOF__ - return 0 + return 0 } checkopt_toolkit_gtk2legacy() { - VERR=0 - dependency_gtk2legacy - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_gtk2legacy ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = gtk GTKOBJ = draw_gdk.o - __EOF__ - return 0 + return 0 } checkopt_toolkit_qt5() { - VERR=0 - dependency_qt5 - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_qt5 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = qt LD = $(CXX) - __EOF__ - return 0 + return 0 } checkopt_toolkit_qt4() { - VERR=0 - dependency_qt4 - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_qt4 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = qt LD = $(CXX) - __EOF__ - return 0 + return 0 } checkopt_toolkit_motif() { - VERR=0 - dependency_motif - if [ $? -ne 0 ]; then - VERR=1 - fi - if [ $VERR -ne 0 ]; then - return 1 - fi - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + if dependency_error_motif ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ TOOLKIT = motif - __EOF__ - return 0 + return 0 } # # TARGETS # -CFLAGS= -CXXFLAGS= -LDFLAGS= + +echo >> "$TEMP_DIR/flags.mk" +echo "configuring target: dav" +echo "# flags for target dav" >> "$TEMP_DIR/flags.mk" +TEMP_CFLAGS= +TEMP_CXXFLAGS= +TEMP_LDFLAGS= + +if dependency_error_curl; then + DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED curl " + ERROR=1 +fi +if dependency_error_libxml2; then + DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED libxml2 " + ERROR=1 +fi +if dependency_error_openssl; then + DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED openssl " + ERROR=1 +fi + +# Features + -# Target: tk -CFLAGS= -LDFLAGS= -CXXFLAGS= +if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then + echo "DAV_CFLAGS += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk" +fi +if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then + echo "DAV_CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk" +fi +if [ "$BUILD_TYPE" = "debug" ]; then + if [ -n "$lang_c" ]; then + echo 'DAV_CFLAGS += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo 'DAV_CXXFLAGS += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi +fi +if [ "$BUILD_TYPE" = "release" ]; then + if [ -n "$lang_c" ]; then + echo 'DAV_CFLAGS += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo 'DAV_CXXFLAGS += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi +fi +if [ -n "${TEMP_LDFLAGS}" ]; then + echo "DAV_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk" +fi + +echo >> "$TEMP_DIR/flags.mk" +echo "configuring target: tk" +echo "# flags for target tk" >> "$TEMP_DIR/flags.mk" +TEMP_CFLAGS= +TEMP_CXXFLAGS= +TEMP_LDFLAGS= # Features # Option: --toolkit -if [ -z $OPT_TOOLKIT ]; then - SAVED_ERROR=$ERROR - SAVED_DEPENDENCIES_FAILED=$DEPENDENCIES_FAILED - ERROR=0 - while true - do - if isplatform "windows"; then - checkopt_toolkit_winui - if [ $? -eq 0 ]; then - echo " toolkit: winui" >> $TEMP_DIR/options - ERROR=0 - break - fi - fi - if isplatform "macos"; then - checkopt_toolkit_cocoa - if [ $? -eq 0 ]; then - echo " toolkit: cocoa" >> $TEMP_DIR/options - ERROR=0 - break - fi - fi - checkopt_toolkit_gtk3 - if [ $? -eq 0 ]; then - echo " toolkit: gtk3" >> $TEMP_DIR/options - ERROR=0 - break - fi - checkopt_toolkit_qt5 - if [ $? -eq 0 ]; then - echo " toolkit: qt5" >> $TEMP_DIR/options - ERROR=0 - break - fi - checkopt_toolkit_gtk2 - if [ $? -eq 0 ]; then - echo " toolkit: gtk2" >> $TEMP_DIR/options - ERROR=0 - break - fi - checkopt_toolkit_qt4 - if [ $? -eq 0 ]; then - echo " toolkit: qt4" >> $TEMP_DIR/options - ERROR=0 - break - fi - checkopt_toolkit_motif - if [ $? -eq 0 ]; then - echo " toolkit: motif" >> $TEMP_DIR/options - ERROR=0 - break - fi - break - done - if [ $ERROR -ne 0 ]; then - SAVED_ERROR=1 - fi - ERROR=$SAVED_ERROR - DEPENDENCIES_FAILED=$SAVED_DEPENDENCIES_FAILED= +if [ -z "$OPT_TOOLKIT" ]; then + echo "auto-detecting option 'toolkit'" + SAVED_ERROR="$ERROR" + SAVED_DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED" + ERROR=1 + while true + do + if isplatform "windows"; then + if checkopt_toolkit_winui ; then + echo " toolkit: winui" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + fi + if isplatform "macos"; then + if checkopt_toolkit_cocoa ; then + echo " toolkit: cocoa" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + fi + if checkopt_toolkit_gtk3 ; then + echo " toolkit: gtk3" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + if checkopt_toolkit_qt5 ; then + echo " toolkit: qt5" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + if checkopt_toolkit_gtk2 ; then + echo " toolkit: gtk2" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + if checkopt_toolkit_qt4 ; then + echo " toolkit: qt4" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + if checkopt_toolkit_motif ; then + echo " toolkit: motif" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + break + done + if [ $ERROR -ne 0 ]; then + SAVED_ERROR=1 + SAVED_DEPENDENCIES_FAILED="option 'toolkit' $SAVED_DEPENDENCIES_FAILED" + fi + ERROR="$SAVED_ERROR" + DEPENDENCIES_FAILED="$SAVED_DEPENDENCIES_FAILED" else - if false; then - false - elif [ $OPT_TOOLKIT = "gtk4" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_gtk4 - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "gtk3" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_gtk3 - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "gtk2" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_gtk2 - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "gtk2legacy" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_gtk2legacy - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "qt5" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_qt5 - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "qt4" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_qt4 - if [ $? -ne 0 ]; then - ERROR=1 - fi - elif [ $OPT_TOOLKIT = "motif" ]; then - echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options - checkopt_toolkit_motif - if [ $? -ne 0 ]; then - ERROR=1 - fi - fi + echo "checking option toolkit = $OPT_TOOLKIT" + if false; then + false + elif [ "$OPT_TOOLKIT" = "gtk4" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_gtk4 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "gtk3" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_gtk3 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "gtk2" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_gtk2 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "gtk2legacy" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_gtk2legacy ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "qt5" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_qt5 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "qt4" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_qt4 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + elif [ "$OPT_TOOLKIT" = "motif" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_motif ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi + fi fi -echo >> $TEMP_DIR/config.mk -if [ ! -z "${CFLAGS}" ]; then - echo "TK_CFLAGS += $CFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then + echo "TK_CFLAGS += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk" +fi +if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then + echo "TK_CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${CXXFLAGS}" ]; then - echo "TK_CXXFLAGS += $CXXFLAGS" >> $TEMP_DIR/config.mk +if [ "$BUILD_TYPE" = "debug" ]; then + if [ -n "$lang_c" ]; then + echo 'TK_CFLAGS += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo 'TK_CXXFLAGS += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi fi -if [ ! -z "${LDFLAGS}" ]; then - echo "TK_LDFLAGS += $LDFLAGS" >> $TEMP_DIR/config.mk +if [ "$BUILD_TYPE" = "release" ]; then + if [ -n "$lang_c" ]; then + echo 'TK_CFLAGS += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo 'TK_CXXFLAGS += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi +fi +if [ -n "${TEMP_LDFLAGS}" ]; then + echo "TK_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk" fi + +# final result if [ $ERROR -ne 0 ]; then - echo - echo "Error: Unresolved dependencies" - echo $DEPENDENCIES_FAILED - rm -Rf $TEMP_DIR - exit 1 + echo + echo "Error: Unresolved dependencies" + echo "$DEPENDENCIES_FAILED" + abort_configure fi echo "configure finished" echo echo "Build Config:" -echo " PREFIX: $PREFIX" -echo " TOOLCHAIN: $TOOLCHAIN_NAME" +echo " PREFIX: $prefix" +echo " TOOLCHAIN: $TOOLCHAIN_NAME" echo "Options:" -cat $TEMP_DIR/options +cat "$TEMP_DIR/options" echo -cat $TEMP_DIR/config.mk $TEMP_DIR/make.mk > config.mk -rm -Rf $TEMP_DIR +# generate the config.mk file +cat > "$TEMP_DIR/config.mk" << __EOF__ +# +# config.mk generated by configure +# +__EOF__ +write_toolchain_defaults "$TEMP_DIR/toolchain.mk" +cat "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk +rm -Rf "$TEMP_DIR"
--- a/make/Makefile.mk Mon Feb 12 21:13:23 2024 +0100 +++ b/make/Makefile.mk Sun Jun 09 15:43:08 2024 +0200 @@ -32,11 +32,11 @@ include config.mk BUILD_DIRS = build/bin build/lib -BUILD_DIRS += build/application build/ucx +BUILD_DIRS += build/application build/ucx build/libidav BUILD_DIRS += build/ui/common build/ui/$(TOOLKIT) -all: $(BUILD_DIRS) ucx ui application - make/$(PACKAGE_SCRIPT) +all: $(BUILD_DIRS) ucx ui libidav application + $(BUILD_DIRS): mkdir -p $@ @@ -47,7 +47,10 @@ ucx: FORCE cd ucx; $(MAKE) all -application: ui FORCE +libidav: ucx FORCE + cd libidav; $(MAKE) all + +application: ui libidav FORCE cd application; $(MAKE) FORCE:
--- a/make/configure.vm Mon Feb 12 21:13:23 2024 +0100 +++ b/make/configure.vm Sun Jun 09 15:43:08 2024 +0200 @@ -1,78 +1,65 @@ #!/bin/sh +# create temporary directory +TEMP_DIR=".tmp-`uname -n`" +rm -Rf "$TEMP_DIR" +if mkdir -p "$TEMP_DIR"; then + : +else + echo "Cannot create tmp dir $TEMP_DIR" + echo "Abort" + exit 1 +fi +touch "$TEMP_DIR/options" +touch "$TEMP_DIR/features" + +# define standard variables +# also define standard prefix (this is where we will search for config.site) +prefix=/usr +exec_prefix= +bindir= +sbindir= +libdir= +libexecdir= +datarootdir= +datadir= +sysconfdir= +sharedstatedir= +localstatedir= +runstatedir= +includedir= +infodir= +localedir= +mandir= + +# custom variables #foreach( $var in $vars ) #if( $var.exec ) -${var.name}=`${var.value}` +${var.varName}=`${var.value}` #else -${var.name}=${var.value} +${var.varName}="${var.value}" #end #end -#if ( ! $project.hasVar("PREFIX") ) -PREFIX=/usr +# features +#foreach( $feature in $features ) +#if( ${feature.auto} ) +${feature.varName}=auto #end -#if ( ! $project.hasVar("EPREFIX") ) -EPREFIX=$PREFIX #end -#if ( ! $project.hasVar("BINDIR") ) -BINDIR= -#end -#if ( ! $project.hasVar("SBINDIR") ) -SBINDIR= -#end -#if ( ! $project.hasVar("LIBDIR") ) -LIBDIR= -#end -#if ( ! $project.hasVar("LIBEXECDIR") ) -LIBEXECDIR= -#end -#if ( ! $project.hasVar("DATADIR") ) -DATADIR= -#end -#if ( ! $project.hasVar("SYSCONFDIR") ) -SYSCONFDIR= -#end -#if ( ! $project.hasVar("SHAREDSTATEDIR") ) -SHAREDSTATEDIR= -#end -#if ( ! $project.hasVar("LOCALSTATEDIR") ) -LOCALSTATEDIR= -#end -#if ( ! $project.hasVar("INCLUDEDIR") ) -INCLUDEDIR= -#end -#if ( ! $project.hasVar("INFODIR") ) -INFODIR= -#end -#if ( ! $project.hasVar("MANDIR") ) -MANDIR= -#end - -OS=`uname -s` -OS_VERSION=`uname -r` - -TEMP_DIR=".tmp-`uname -n`" -mkdir -p $TEMP_DIR -if [ $? -ne 0 ]; then - echo "Cannot create tmp dir" - echo "Abort" -fi -touch $TEMP_DIR/options -touch $TEMP_DIR/features - -# features -#foreach( $feature in $features ) -#if( ${feature.isDefault()} ) -${feature.getVarName()}=on -#end -#end +# clean abort +abort_configure() +{ + rm -Rf "$TEMP_DIR" + exit 1 +} # help text printhelp() { - echo "Usage: $0 [OPTIONS]..." - cat << __EOF__ + echo "Usage: $0 [OPTIONS]..." + cat << __EOF__ Installation directories: --prefix=PREFIX path prefix for architecture-independent files [/usr] @@ -85,28 +72,28 @@ --sysconfdir=DIR system configuration files [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR run-time variable data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --mandir=DIR man documentation [DATAROOTDIR/man] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] #if( $options.size() > 0 ) Options: + --debug add extra compile flags for debug builds + --release add extra compile flags for release builds #foreach( $opt in $options ) - --${opt.getArgument()}=${opt.getValuesString()} + --${opt.argument}=${opt.valuesString} #end #end #if( $features.size() > 0 ) Optional Features: #foreach( $feature in $features ) -#if( $feature.default ) - --disable-${feature.arg} -#else - --enable-${feature.arg} -#end +${feature.helpText} #end #end @@ -114,297 +101,328 @@ } # -# parse arguments +# parse arguments # +BUILD_TYPE="default" #set( $D = '$' ) -for ARG in $@ +for ARG in "$@" do case "$ARG" in - "--prefix="*) PREFIX=${D}{ARG#--prefix=} ;; - "--exec-prefix="*) EPREFIX=${D}{ARG#--exec-prefix=} ;; - "--bindir="*) BINDIR=${D}{ARG#----bindir=} ;; - "--sbindir="*) SBINDIR=${D}{ARG#--sbindir=} ;; - "--libdir="*) LIBDIR=${D}{ARG#--libdir=} ;; - "--libexecdir="*) LIBEXECDIR=${D}{ARG#--libexecdir=} ;; - "--datadir="*) DATADIR=${D}{ARG#--datadir=} ;; - "--sysconfdir="*) SYSCONFDIR=${D}{ARG#--sysconfdir=} ;; - "--sharedstatedir="*) SHAREDSTATEDIR=${D}{ARG#--sharedstatedir=} ;; - "--localstatedir="*) LOCALSTATEDIR=${D}{ARG#--localstatedir=} ;; - "--includedir="*) INCLUDEDIR=${D}{ARG#--includedir=} ;; - "--infodir="*) INFODIR=${D}{ARG#--infodir=} ;; - "--mandir"*) MANDIR=${D}{ARG#--mandir} ;; - "--help"*) printhelp; exit 1 ;; - #foreach( $opt in $options ) - "--${opt.getArgument()}="*) ${opt.getVarName()}=${D}{ARG#--${opt.getArgument()}=} ;; + "--prefix="*) prefix=${D}{ARG#--prefix=} ;; + "--exec-prefix="*) exec_prefix=${D}{ARG#--exec-prefix=} ;; + "--bindir="*) bindir=${D}{ARG#----bindir=} ;; + "--sbindir="*) sbindir=${D}{ARG#--sbindir=} ;; + "--libdir="*) libdir=${D}{ARG#--libdir=} ;; + "--libexecdir="*) libexecdir=${D}{ARG#--libexecdir=} ;; + "--datarootdir="*) datarootdir=${D}{ARG#--datarootdir=} ;; + "--datadir="*) datadir=${D}{ARG#--datadir=} ;; + "--sysconfdir="*) sysconfdir=${D}{ARG#--sysconfdir=} ;; + "--sharedstatedir="*) sharedstatedir=${D}{ARG#--sharedstatedir=} ;; + "--localstatedir="*) localstatedir=${D}{ARG#--localstatedir=} ;; + "--includedir="*) includedir=${D}{ARG#--includedir=} ;; + "--infodir="*) infodir=${D}{ARG#--infodir=} ;; + "--mandir"*) mandir=${D}{ARG#--mandir} ;; + "--localedir"*) localedir=${D}{ARG#--localedir} ;; + "--help"*) printhelp; abort_configure ;; + "--debug") BUILD_TYPE="debug" ;; + "--release") BUILD_TYPE="release" ;; + #foreach( $opt in $options ) + "--${opt.argument}="*) ${opt.varName}=${D}{ARG#--${opt.argument}=} ;; #end - #foreach( $feature in $features ) - "--enable-${feature.arg}") ${feature.getVarName()}=on ;; - "--disable-${feature.arg}") unset ${feature.getVarName()} ;; - #end - "-"*) echo "unknown option: $ARG"; exit 1 ;; - esac + #foreach( $feature in $features ) + "--enable-${feature.arg}") ${feature.varName}=on ;; + "--disable-${feature.arg}") unset ${feature.varName} ;; + #end + "-"*) echo "unknown option: $ARG"; abort_configure ;; + esac done -# set dir variables -if [ -z "$BINDIR" ]; then - BINDIR=$EPREFIX/bin -fi -if [ -z "$SBINDIR" ]; then - SBINDIR=$EPREFIX/sbin -fi -if [ -z "$LIBDIR" ]; then - LIBDIR=$EPREFIX/lib -fi -if [ -z "$LIBEXEC" ]; then - LIBEXECDIR=$EPREFIX/libexec -fi -if [ -z "$DATADIR" ]; then - DATADIR=$PREFIX/share -fi -if [ -z "$SYSCONFDIR" ]; then - SYSCONFDIR=$PREFIX/etc -fi -if [ -z "$SHAREDSTATEDIR" ]; then - SHAREDSTATEDIR=$PREFIX/com -fi -if [ -z "$LOCALSTATEDIR" ]; then - LOCALSTATEDIR=$PREFIX/var -fi -if [ -z "$INCLUDEDIR" ]; then - INCLUDEDIR=$PREFIX/include -fi -if [ -z "$INFODIR" ]; then - INFODIR=$PREFIX/info -fi -if [ -z "$MANDIR" ]; then - MANDIR=$PREFIX/man +## Begin unparsed content. ** +#[[ + +# set defaults for dir variables +: ${exec_prefix:="$prefix"} +: ${bindir:='${exec_prefix}/bin'} +: ${sbindir:='${exec_prefix}/sbin'} +: ${libdir:='${exec_prefix}/lib'} +: ${libexecdir:='${exec_prefix}/libexec'} +: ${datarootdir:='${prefix}/share'} +: ${datadir:='${datarootdir}'} +: ${sysconfdir:='${prefix}/etc'} +: ${sharedstatedir:='${prefix}/com'} +: ${localstatedir:='${prefix}/var'} +: ${runstatedir:='${localstatedir}/run'} +: ${includedir:='${prefix}/include'} +: ${infodir:='${datarootdir}/info'} +: ${mandir:='${datarootdir}/man'} +: ${localedir:='${datarootdir}/locale'} + +# check if a config.site exists and load it +if [ -n "$CONFIG_SITE" ]; then + # CONFIG_SITE may contain space separated file names + for cs in $CONFIG_SITE; do + printf "loading defaults from $cs... " + . "$cs" + echo ok + done +elif [ -f "$prefix/share/config.site" ]; then + printf "loading site defaults... " + . "$prefix/share/config.site" + echo ok +elif [ -f "$prefix/etc/config.site" ]; then + printf "loading site defaults... " + . "$prefix/etc/config.site" + echo ok fi -which pkg-config > /dev/null -if [ $? -eq 0 ]; then - PKG_CONFIG=pkg-config -else - PKG_CONFIG=false -fi +# Test for availability of pkg-config +PKG_CONFIG=`command -v pkg-config` +: ${PKG_CONFIG:="false"} # Simple uname based platform detection # $PLATFORM is used for platform dependent dependency selection +OS=`uname -s` +OS_VERSION=`uname -r` printf "detect platform... " -if [ $OS = SunOS ]; then +if [ "$OS" = "SunOS" ]; then PLATFORM="solaris sunos unix svr4" -fi -if [ $OS = Linux ]; then +elif [ "$OS" = "Linux" ]; then PLATFORM="linux unix" -fi -if [ $OS = FreeBSD ]; then +elif [ "$OS" = "FreeBSD" ]; then PLATFORM="freebsd bsd unix" -fi -if [ $OS = Darwin ]; then +elif [ "$OS" = "OpenBSD" ]; then + PLATFORM="openbsd bsd unix" +elif [ "$OS" = "NetBSD" ]; then + PLATFORM="netbsd bsd unix" +elif [ "$OS" = "Darwin" ]; then PLATFORM="macos osx bsd unix" -fi -echo $OS | grep "MINGW" > /dev/null -if [ $? -eq 0 ]; then +elif echo "$OS" | grep -i "MINGW" > /dev/null; then PLATFORM="windows mingw" fi - -if [ -z "$PLATFORM" ]; then - PLATFORM="unix" -fi +: ${PLATFORM:="unix"} -for p in $PLATFORM -do - PLATFORM_NAME=$p - break -done -echo $PLATFORM_NAME +PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -` +echo "$PLATFORM_NAME" isplatform() { for p in $PLATFORM do - if [ $p = $1 ]; then + if [ "$p" = "$1" ]; then return 0 fi done return 1 } -isnotplatform() +notisplatform() { for p in $PLATFORM do - if [ $p = $1 ]; then + if [ "$p" = "$1" ]; then + return 1 + fi + done + return 0 +} +istoolchain() +{ + for t in $TOOLCHAIN + do + if [ "$t" = "$1" ]; then + return 0 + fi + done + return 1 +} +notistoolchain() +{ + for t in $TOOLCHAIN + do + if [ "$t" = "$1" ]; then return 1 fi done return 0 } - -# generate config.mk and config.h -cat > $TEMP_DIR/config.mk << __EOF__ -# -# config.mk generated by configure -# - -# general vars -#foreach( $var in $vars ) -${var.name}=$${var.name} -#end +]]# +## End of unparsed content ** -#if ( ! $project.hasVar("PREFIX") ) -PREFIX=$PREFIX -#end -#if ( ! $project.hasVar("EPREFIX") ) -EPREFIX=$EPREFIX -#end - -#if ( ! $project.hasVar("BINDIR") ) -BINDIR=$BINDIR -#end -#if ( ! $project.hasVar("SBINDIR") ) -SBINDIR=$SBINDIR +# generate vars.mk +cat > "$TEMP_DIR/vars.mk" << __EOF__ +prefix=$prefix +exec_prefix=$exec_prefix +bindir=$bindir +sbindir=$sbindir +libdir=$libdir +libexecdir=$libexecdir +datarootdir=$datarootdir +datadir=$datadir +sysconfdir=$sysconfdir +sharedstatedir=$sharedstatedir +localstatedir=$localstatedir +runstatedir=$runstatedir +includedir=$includedir +infodir=$infodir +mandir=$mandir +localedir=$localedir +#foreach( $var in $vars ) +${var.varName}=${D}${var.varName} #end -#if ( ! $project.hasVar("LIBDIR") ) -LIBDIR=$LIBDIR -#end -#if ( ! $project.hasVar("LIBEXECDIR") ) -LIBEXECDIR=$LIBEXECDIR -#end -#if ( ! $project.hasVar("DATADIR") ) -DATADIR=$DATADIR -#end -#if ( ! $project.hasVar("SYSCONFDIR") ) -SYSCONFDIR=$SYSCONFDIR -#end -#if ( ! $project.hasVar("SHAREDSTATEDIR") ) -SHAREDSTATEDIR=$SHAREDSTATEDIR -#end -#if ( ! $project.hasVar("LOCALSTATEDIR") ) -LOCALSTATEDIR=$LOCALSTATEDIR -#end -#if ( ! $project.hasVar("INCLUDEDIR") ) -INCLUDEDIR=$INCLUDEDIR -#end -#if ( ! $project.hasVar("INFODIR") ) -INFODIR=$INFODIR -#end -#if ( ! $project.hasVar("MANDIR") ) -MANDIR=$MANDIR -#end - __EOF__ -echo > $TEMP_DIR/make.mk - -ENV_CFLAGS=$CFLAGS -ENV_LDFLAGS=$LDFLAGS -ENV_CXXFLAGS=$CXXFLAGS - -# Toolchain detection -# this will insert make vars to config.mk +# toolchain detection utilities . make/toolchain.sh -# add user specified flags to config.mk -echo >> $TEMP_DIR/config.mk -if [ ! -z "${ENV_CFLAGS}" ]; then - echo "CFLAGS += $ENV_CFLAGS" >> $TEMP_DIR/config.mk -fi -if [ ! -z "${ENV_CXXFLAGS}" ]; then - echo "CXXFLAGS += $ENV_CXXFLAGS" >> $TEMP_DIR/config.mk -fi -if [ ! -z "${ENV_LDFLAGS}" ]; then - echo "LDFLAGS += $ENV_LDFLAGS" >> $TEMP_DIR/config.mk -fi - # # DEPENDENCIES # -#foreach( $dependency in $namedDependencies ) -dependency_${dependency.name}() +# check languages +lang_c= +lang_cpp= +#foreach( $lang in $languages ) +if detect_${lang}_compiler ; then + lang_${lang}=1 +fi +#end + +# create buffer for make variables required by dependencies +echo > "$TEMP_DIR/make.mk" + +test_pkg_config() { - printf "checking for ${dependency.name}... " - #foreach( $sub in $dependency.getSubdependencies() ) - # dependency $sub.name $sub.getPlatformString() + if "$PKG_CONFIG" --exists "$1" ; then : + else return 1 ; fi + if [ -z "$2" ] || "$PKG_CONFIG" --atleast-version="$2" "$1" ; then : + else return 1 ; fi + if [ -z "$3" ] || "$PKG_CONFIG" --exact-version="$3" "$1" ; then : + else return 1 ; fi + if [ -z "$4" ] || "$PKG_CONFIG" --max-version="$4" "$1" ; then : + else return 1 ; fi + return 0 +} + +print_check_msg() +{ + if [ -z "$1" ]; then + shift + printf "$@" + fi +} + +#foreach( $dependency in $namedDependencies ) +dependency_error_${dependency.id}() +{ + print_check_msg "${D}dep_checked_${dependency.id}" "checking for ${dependency.name}... " + #foreach( $sub in $dependency.subdependencies ) + # dependency $sub.fullName while true do - #if( $sub.platform ) - if isnotplatform "${sub.platform}"; then + #if( $sub.platform ) + if notisplatform "${sub.platform}"; then + break + fi + #end + #if( $sub.toolchain ) + if notistoolchain "${sub.toolchain}"; then + break + fi + #end + #foreach( $np in $sub.notList ) + if isplatform "${np}" || istoolchain "${np}"; then break fi - #end - #foreach( $not in $sub.getNotList() ) - if isplatform "${not}"; then + #end + #foreach( $lang in $sub.lang ) + if [ -z "$lang_${lang}" ] ; then break fi - #end + #end #if( $sub.pkgconfig.size() > 0 ) if [ -z "$PKG_CONFIG" ]; then - break + break + fi + #end + #foreach( $test in $sub.tests ) + if $test > /dev/null ; then + : + else + break fi #end #foreach( $pkg in $sub.pkgconfig ) - $PKG_CONFIG $pkg.getPkgConfigParam() - if [ $? -ne 0 ] ; then + if test_pkg_config "$pkg.name" "$pkg.atleast" "$pkg.exact" "$pkg.max" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags $pkg.name`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs $pkg.name`" + else break fi - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags $pkg.getPkgConfigParam()`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs $pkg.getPkgConfigParam()`" #end #foreach( $flags in $sub.flags ) #if( $flags.exec ) - $flags.value > /dev/null - if [ $? -eq 0 ]; then - $flags.varName="$$flags.varName `$flags.value`" + if tmp_flags=`$flags.value` ; then + TEMP_$flags.varName="$TEMP_$flags.varName $tmp_flags" else break fi #else - $flags.varName="$$flags.varName $flags.value" + TEMP_$flags.varName="$TEMP_$flags.varName $flags.value" #end #end - #foreach( $test in $sub.tests ) - $test > /dev/null - if [ $? -ne 0 ]; then - break - fi - #end - #if ( $sub.make.length() > 0 ) - cat >> $TEMP_DIR/make.mk << __EOF__ -# Dependency: $dependency.name + #if ( $sub.make.length() > 0 ) + cat >> $TEMP_DIR/make.mk << __EOF__ +# Dependency: $dependency.name $sub.make __EOF__ #end - echo yes - return 0 + print_check_msg "${D}dep_checked_${dependency.id}" "yes\n" + dep_checked_${dependency.id}=1 + return 1 done - - #end - echo no - return 1 + + #end + print_check_msg "${D}dep_checked_${dependency.id}" "no\n" + dep_checked_${dependency.id}=1 + return 0 } #end +# start collecting dependency information +echo > "$TEMP_DIR/flags.mk" + DEPENDENCIES_FAILED= ERROR=0 #if( $dependencies.size() > 0 ) -# general dependencies -CFLAGS= -LDFLAGS= +# unnamed dependencies +TEMP_CFLAGS= +TEMP_CXXFLAGS= +TEMP_LDFLAGS= #foreach( $dependency in $dependencies ) while true do - #if( $dependency.platform ) - if isnotplatform "${dependency.platform}"; then + #if( $dependency.platform ) + if notisplatform "${dependency.platform}"; then + break + fi + #end + #if( $dependency.toolchain ) + if notistoolchain "${dependency.toolchain}"; then break fi #end - #foreach( $not in $dependency.getNotList() ) - if isplatform "${not}"; then + #foreach( $np in $dependency.notList ) + if isplatform "${np}" || istoolchain "${np}"; then break fi - #end + #end while true do + #foreach( $lang in $dependency.lang ) + if [ -z "$lang_${lang}" ] ; then + ERROR=1 + break + fi + #end #if( $dependency.pkgconfig.size() > 0 ) if [ -z "$PKG_CONFIG" ]; then ERROR=1 @@ -412,54 +430,54 @@ fi #end #foreach( $pkg in $dependency.pkgconfig ) - printf "checking for pkg-config package $pkg.getPkgConfigParam()... " - $PKG_CONFIG $pkg.getPkgConfigParam() - if [ $? -ne 0 ]; then - echo no + print_check_msg "${D}dep_pkgconfig_checked_${pkg.id}" "checking for pkg-config package $pkg.name... " + if test_pkg_config "$pkg.name" "$pkg.atleast" "$pkg.exact" "$pkg.max" ; then + print_check_msg "${D}dep_pkgconfig_checked_${pkg.id}" "yes\n" + dep_pkgconfig_checked_${pkg.id}=1 + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags $pkg.name`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs $pkg.name`" + else + print_check_msg "${D}dep_pkgconfig_checked_${pkg.id}" "no\n" + dep_pkgconfig_checked_${pkg.id}=1 ERROR=1 break fi - echo yes - CFLAGS="$CFLAGS `$PKG_CONFIG --cflags $pkg.getPkgConfigParam()`" - LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs $pkg.getPkgConfigParam()`" #end - + #foreach( $flags in $dependency.flags ) #if( $flags.exec ) $flags.value > /dev/null - if [ $? -ne 0 ]; then - $flags.varName="$$flags.varName `$flags.value`" + if tmp_flags=`$flags.value` ; then + TEMP_$flags.varName="$TEMP_$flags.varName $tmp_flags" else ERROR=1 break fi #else - $flags.varName="$$flags.varName $flags.value" + TEMP_$flags.varName="$TEMP_$flags.varName $flags.value" #end #end - #if ( $dependency.make.length() > 0 ) - cat >> $TEMP_DIR/make.mk << __EOF__ + #if ( $dependency.make.length() > 0 ) + cat >> "$TEMP_DIR/make.mk" << __EOF__ $dependency.make __EOF__ #end - break done - break done #end -# add general dependency flags to config.mk -echo >> $TEMP_DIR/config.mk -if [ ! -z "${CFLAGS}" ]; then - echo "CFLAGS += $CFLAGS" >> $TEMP_DIR/config.mk +# add general dependency flags to flags.mk +echo "# general flags" >> "$TEMP_DIR/flags.mk" +if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then + echo "CFLAGS += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${CXXFLAGS}" ]; then - echo "CXXFLAGS += $CXXFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then + echo "CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${LDFLAGS}" ]; then - echo "LDFLAGS += $LDFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_LDFLAGS}" ]; then + echo "LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk" fi #end @@ -470,25 +488,25 @@ #foreach( $val in $opt.values ) ${val.func}() { - VERR=0 - #foreach( $dep in $val.dependencies ) - dependency_$dep - if [ $? -ne 0 ]; then - VERR=1 - fi - #end - if [ $VERR -ne 0 ]; then - return 1 - fi - #foreach( $def in $val.defines ) - CFLAGS="$CFLAGS ${def.toFlags()}" - #end - #if( $val.hasMake() ) - cat >> $TEMP_DIR/make.mk << __EOF__ + VERR=0 + #foreach( $dep in $val.dependencies ) + if dependency_error_$dep ; then + VERR=1 + fi + #end + if [ $VERR -ne 0 ]; then + return 1 + fi + #foreach( $def in $val.defines ) + TEMP_CFLAGS="$TEMP_CFLAGS ${def.toFlags()}" + TEMP_CXXFLAGS="$TEMP_CXXFLAGS ${def.toFlags()}" + #end + #if( $val.hasMake() ) + cat >> "$TEMP_DIR/make.mk" << __EOF__ $val.make __EOF__ - #end - return 0 + #end + return 0 } #end #end @@ -496,120 +514,160 @@ # # TARGETS # -CFLAGS= -CXXFLAGS= -LDFLAGS= #foreach( $target in $targets ) +echo >> "$TEMP_DIR/flags.mk" #if ( $target.name ) -# Target: $target.name +echo "configuring target: $target.name" +echo "# flags for target $target.name" >> "$TEMP_DIR/flags.mk" #else -# Target +echo "configuring global target" +echo "# flags for unnamed target" >> "$TEMP_DIR/flags.mk" #end -CFLAGS= -LDFLAGS= -CXXFLAGS= +TEMP_CFLAGS= +TEMP_CXXFLAGS= +TEMP_LDFLAGS= #foreach( $dependency in $target.dependencies ) -dependency_$dependency -if [ $? -ne 0 ]; then - DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED ${dependency} " - ERROR=1 +if dependency_error_$dependency; then + DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED ${dependency} " + ERROR=1 fi #end # Features #foreach( $feature in $target.features ) -if [ ! -z "$${feature.getVarName()}" ]; then +if [ -n "${D}${feature.varName}" ]; then #foreach( $dependency in $feature.dependencies ) - # check dependency - dependency_$dependency - if [ $? -ne 0 ]; then - # "auto" features can fail and are just disabled in this case - if [ $${feature.getVarName()} != "auto" ]; then - DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED ${dependency} " - ERROR=1 - fi - fi + # check dependency + if dependency_error_$dependency ; then + # "auto" features can fail and are just disabled in this case + if [ "${D}${feature.varName}" = "auto" ]; then + DISABLE_${feature.varName}=1 + else + DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED ${dependency} " + ERROR=1 + fi + fi #end + if [ -n "$DISABLE_${feature.varName}" ]; then + unset ${feature.varName} + fi fi #end #foreach( $opt in $target.options ) # Option: --${opt.argument} -if [ -z ${D}${opt.getVarName()} ]; then - SAVED_ERROR=$ERROR - SAVED_DEPENDENCIES_FAILED=$DEPENDENCIES_FAILED - ERROR=0 - while true - do - #foreach( $optdef in $opt.defaults ) - #if( $optdef.platform ) - if isplatform "$optdef.platform"; then - #end - $optdef.func - if [ $? -eq 0 ]; then - echo " ${opt.argument}: ${optdef.valueName}" >> $TEMP_DIR/options - ERROR=0 - break - fi - #if( $optdef.platform ) - fi - #end - #end - break - done - if [ $ERROR -ne 0 ]; then - SAVED_ERROR=1 - fi - ERROR=$SAVED_ERROR - DEPENDENCIES_FAILED=$SAVED_DEPENDENCIES_FAILED= +if [ -z "${D}${opt.varName}" ]; then + echo "auto-detecting option '${opt.argument}'" + SAVED_ERROR="$ERROR" + SAVED_DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED" + ERROR=1 + while true + do + #foreach( $optdef in $opt.defaults ) + #if( $optdef.platform ) + if isplatform "$optdef.platform"; then + #end + if $optdef.func ; then + echo " ${opt.argument}: ${optdef.valueName}" >> "$TEMP_DIR/options" + ERROR=0 + break + fi + #if( $optdef.platform ) + fi + #end + #end + break + done + if [ $ERROR -ne 0 ]; then + SAVED_ERROR=1 + SAVED_DEPENDENCIES_FAILED="option '${opt.argument}' $SAVED_DEPENDENCIES_FAILED" + fi + ERROR="$SAVED_ERROR" + DEPENDENCIES_FAILED="$SAVED_DEPENDENCIES_FAILED" else - if false; then - false - #foreach( $optval in $opt.values ) - elif [ ${D}${opt.getVarName()} = "${optval.value}" ]; then - echo " ${opt.argument}: ${D}${opt.getVarName()}" >> $TEMP_DIR/options - $optval.func - if [ $? -ne 0 ]; then - ERROR=1 - fi - #end - fi + echo "checking option ${opt.argument} = ${D}${opt.varName}" + if false; then + false + #foreach( $optval in $opt.values ) + elif [ "${D}${opt.varName}" = "${optval.value}" ]; then + echo " ${opt.argument}: ${D}${opt.varName}" >> $TEMP_DIR/options + if $optval.func ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option '${opt.argument}' $DEPENDENCIES_FAILED" + fi + #end + fi fi #end -echo >> $TEMP_DIR/config.mk -if [ ! -z "${CFLAGS}" ]; then - echo "${target.getCFlags()} += $CFLAGS" >> $TEMP_DIR/config.mk +if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then + echo "${target.cFlags} += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk" +fi +if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then + echo "${target.cxxFlags} += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk" fi -if [ ! -z "${CXXFLAGS}" ]; then - echo "${target.getCXXFlags()} += $CXXFLAGS" >> $TEMP_DIR/config.mk +if [ "$BUILD_TYPE" = "debug" ]; then + if [ -n "$lang_c" ]; then + echo '${target.cFlags} += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo '${target.cxxFlags} += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi fi -if [ ! -z "${LDFLAGS}" ]; then - echo "${target.getLDFlags()} += $LDFLAGS" >> $TEMP_DIR/config.mk +if [ "$BUILD_TYPE" = "release" ]; then + if [ -n "$lang_c" ]; then + echo '${target.cFlags} += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi + if [ -n "$lang_cpp" ]; then + echo '${target.cxxFlags} += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk" + fi +fi +if [ -n "${TEMP_LDFLAGS}" ]; then + echo "${target.ldFlags} += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk" fi #end + +# final result if [ $ERROR -ne 0 ]; then - echo - echo "Error: Unresolved dependencies" - echo $DEPENDENCIES_FAILED - rm -Rf $TEMP_DIR - exit 1 + echo + echo "Error: Unresolved dependencies" + echo "$DEPENDENCIES_FAILED" + abort_configure fi echo "configure finished" echo echo "Build Config:" -echo " PREFIX: $PREFIX" -echo " TOOLCHAIN: $TOOLCHAIN_NAME" +echo " PREFIX: $prefix" +echo " TOOLCHAIN: $TOOLCHAIN_NAME" #if ( $options.size() > 0 ) echo "Options:" -cat $TEMP_DIR/options +cat "$TEMP_DIR/options" +#end +#if ( $features.size() > 0 ) +echo "Features:" +#foreach( $feature in $features ) +if [ -n "${D}${feature.varName}" ]; then +echo " $feature.name: on" +else +echo " $feature.name: off" +fi +#end #end echo -cat $TEMP_DIR/config.mk $TEMP_DIR/make.mk > config.mk -rm -Rf $TEMP_DIR +# generate the config.mk file +cat > "$TEMP_DIR/config.mk" << __EOF__ +# +# config.mk generated by configure +# +__EOF__ +write_toolchain_defaults "$TEMP_DIR/toolchain.mk" +cat "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk +rm -Rf "$TEMP_DIR"
--- a/make/osx.mk Mon Feb 12 21:13:23 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. -# -# Copyright 2011 Olaf Wintermann. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -CC = gcc -LD = gcc -AR = ar -RM = rm - -CFLAGS += -std=gnu99 -g -I/usr/include/libxml2 -LDFLAGS += -lxml2 -lz -lpthread -licucore -lm -ARFLAGS = -r -RMFLAGS = -f - -OBJ_EXT = o -LIB_EXT = a -APP_EXT = - -PACKAGE_SCRIPT = package_osx.sh
--- a/make/project.xml Mon Feb 12 21:13:23 2024 +0100 +++ b/make/project.xml Sun Jun 09 15:43:08 2024 +0200 @@ -1,5 +1,51 @@ <?xml version="1.0" encoding="UTF-8"?> -<project> +<project xmlns="http://unixwork.de/uwproj"> + <dependency> + <lang>c</lang> + </dependency> + + <dependency name="curl" platform="macos"> + <cflags exec="true">curl-config --cflags</cflags> + <ldflags exec="true">curl-config --ldflags</ldflags> + </dependency> + <dependency name="curl"> + <pkgconfig>libcurl</pkgconfig> + </dependency> + <dependency name="curl"> + <cflags exec="true">curl-config --cflags</cflags> + <ldflags exec="true">curl-config --libs</ldflags> + </dependency> + + <dependency name="libxml2" platform="windows"> + <cflags exec="true">xml2-config --cflags</cflags> + <ldflags exec="true">xml2-config --libs</ldflags> + </dependency> + <dependency name="libxml2" platform="macos"> + <cflags exec="true">xml2-config --cflags</cflags> + <ldflags exec="true">xml2-config --libs</ldflags> + </dependency> + <dependency name="libxml2"> + <pkgconfig>libxml-2.0</pkgconfig> + </dependency> + <dependency name="libxml2"> + <cflags exec="true">xml2-config --cflags</cflags> + <ldflags exec="true">xml2-config --libs</ldflags> + </dependency> + + <dependency name="openssl" platform="windows"> + <ldflags>-lssl -lcrypto</ldflags> + </dependency> + <dependency name="openssl" platform="macos"> + <ldflags>-framework CoreFoundation</ldflags> + </dependency> + <dependency name="openssl" platform="bsd" not="macos"> + <ldflags>-lssl -lcrypto</ldflags> + </dependency> + <dependency name="openssl"> + <pkgconfig>openssl</pkgconfig> + </dependency> + + <dependency name="gtk4"> <pkgconfig>gtk+-4.0</pkgconfig> <cflags>-DUI_GTK3</cflags> @@ -24,18 +70,22 @@ <dependency name="winui" platform="windows"> <cflags>-DUI_WINUI</cflags> </dependency> + + <!-- <dependency name="qt4"> <test>which qmake-qt4</test> - <cflags type="exec">qmake-qt4 -o - /dev/null | grep DEFINES\ </cflags> - <cflags type="exec">qmake-qt4 -o - /dev/null | grep INCPATH\ </cflags> - <ldflags type="exec"><cflags type="exec">qmake-qt4 -o - /dev/null | grep LIBS\ </cflags></ldflags> + <cflags exec="true">qmake-qt4 -o - /dev/null | grep DEFINES\ </cflags> + <cflags exec="true">qmake-qt4 -o - /dev/null | grep INCPATH\ </cflags> + <ldflags exec="true">qmake-qt4 -o - /dev/null | grep LIBS\ </ldflags> </dependency> + <dependency name="qt5"> <test>which qmake-qt5</test> - <cflags type="exec">qmake-qt5 -o - /dev/null | grep DEFINES\ </cflags> - <cflags type="exec">qmake-qt5 -o - /dev/null | grep INCPATH\ </cflags> - <ldflags type="exec"><cflags type="exec">qmake-qt5 -o - /dev/null | grep LIBS\ </cflags></ldflags> + <cflags exec="true">qmake-qt5 -o - /dev/null | grep DEFINES\ </cflags> + <cflags exec="true">qmake-qt5 -o - /dev/null | grep INCPATH\ </cflags> + <ldflags exec="true">qmake-qt5 -o - /dev/null | grep LIBS\ </ldflags> </dependency> + --> <dependency name="cocoa" platform="macos"> <cflags>-DUI_COCOA</cflags> <ldflags>-lobjc -framework Cocoa</ldflags> @@ -52,12 +102,12 @@ </dependency> <dependency platform="macos"> - <make>OBJ_EXT = .o</make> + <make>OBJ_EXT = o</make> <make>LIB_EXT = .a</make> <make>PACKAGE_SCRIPT = package_osx.sh</make> </dependency> <dependency platform="unix" not="macos"> - <make>OBJ_EXT = .o</make> + <make>OBJ_EXT = o</make> <make>LIB_EXT = .a</make> <make>PACKAGE_SCRIPT = package_unix.sh</make> </dependency> @@ -67,6 +117,10 @@ <ldflags>-L/usr/local/lib</ldflags> </dependency> + <target name="dav"> + <dependencies>curl,libxml2,openssl</dependencies> + </target> + <target name="tk"> <option arg="toolkit"> <value str="gtk4">
--- a/make/toolchain.sh Mon Feb 12 21:13:23 2024 +0100 +++ b/make/toolchain.sh Sun Jun 09 15:43:08 2024 +0200 @@ -3,179 +3,198 @@ # toolchain detection # -C_COMPILERS="cc gcc clang suncc" -CPP_COMPILERS="CC g++ clang++ sunCC" -unset CC_ARG_CHECKED -unset TOOLCHAIN_DETECTION_ERROR +if isplatform "bsd" && notisplatform "openbsd"; then + C_COMPILERS="clang gcc cc" + CPP_COMPILERS="clang++ g++ CC" +else + C_COMPILERS="gcc clang suncc cc" + CPP_COMPILERS="g++ clang++ sunCC CC" +fi +unset TOOLCHAIN unset TOOLCHAIN_NAME +unset TOOLCHAIN_CC +unset TOOLCHAIN_CXX check_c_compiler() { - cat > $TEMP_DIR/test.c << __EOF__ + cat > "$TEMP_DIR/test.c" << __EOF__ /* test file */ #include <stdio.h> int main(int argc, char **argv) { -#if defined(__clang__) - printf("clang\n"); +#if defined(_MSC_VER) + printf("msc\n"); +#elif defined(__clang__) + printf("clang gnuc\n"); #elif defined(__GNUC__) - printf("gcc\n"); + printf("gcc gnuc\n"); #elif defined(__sun) - printf("suncc\n"); + printf("suncc\n"); #else - printf("unknown\n"); + printf("unknown\n"); #endif - return 0; + return 0; } __EOF__ - rm -f $TEMP_DIR/checkcc - $1 -o $TEMP_DIR/checkcc $CFLAGS $LDFLAGS $TEMP_DIR/test.c 2> /dev/null - - if [ $? -ne 0 ]; then - return 1 - fi - return 0 + rm -f "$TEMP_DIR/checkcc" + $1 -o "$TEMP_DIR/checkcc" $CFLAGS $LDFLAGS "$TEMP_DIR/test.c" 2> /dev/null } check_cpp_compiler() { - cat > $TEMP_DIR/test.cpp << __EOF__ + cat > "$TEMP_DIR/test.cpp" << __EOF__ /* test file */ #include <iostream> int main(int argc, char **argv) { -#if defined(__clang__) - std::cout << "clang" << std::endl; +#if defined(_MSC_VER) + std::cout << "msc" << std::endl; +#elif defined(__clang__) + std::cout << "clang gnuc" << std::endl; #elif defined(__GNUC__) - std::cout << "gcc" << std::endl; + std::cout << "gcc gnuc" << std::endl; #elif defined(__sun) - std::cout << "suncc" << std::endl; + std::cout << "suncc" << std::endl; #else - std::cout << "unknown" << std::endl; + std::cout << "cc" << std::endl; #endif - return 0; + return 0; +} +__EOF__ + rm -f "$TEMP_DIR/checkcc" + $1 -o "$TEMP_DIR/checkcc" $CXXFLAGS $LDFLAGS "$TEMP_DIR/test.cpp" 2> /dev/null +} + +create_libtest_source() +{ + # $1: filename + # $2: optional include + cat > "$TEMP_DIR/$1" << __EOF__ +/* libtest file */ +int main(int argc, char **argv) { + return 0; } __EOF__ - rm -f $TEMP_DIR/checkcc - $1 -o $TEMP_DIR/checkcc $CXXFLAGS $LDFLAGS $TEMP_DIR/test.cpp 2> /dev/null - - if [ $? -ne 0 ]; then - return 1 - fi - return 0 + if [ -n "$2" ]; then + echo "#include <$2>" >> "$TEMP_DIR/$1" + fi +} + +check_c_lib() +{ + # $1: libname + # $2: optional include + if [ -z "$TOOLCHAIN_CC" ]; then + return 1 + fi + create_libtest_source "test.c" "$2" + rm -f "$TEMP_DIR/checklib" + $TOOLCHAIN_CC -o "$TEMP_DIR/checklib" $CFLAGS $LDFLAGS "-l$1" "$TEMP_DIR/test.c" 2> /dev/null +} + +check_cpp_lib() +{ + # $1: libname + # $2: optional include + if [ -z "$TOOLCHAIN_CXX" ]; then + return 1 + fi + create_libtest_source "test.cpp" "$2" + rm -f "$TEMP_DIR/checklib" + $TOOLCHAIN_CXX -o "$TEMP_DIR/checklib" $CXXFLAGS $LDFLAGS "-l$1" "$TEMP_DIR/test.cpp" 2> /dev/null +} + +check_lib() +{ + # $1: libname + # $2: optional include + if [ -n "$TOOLCHAIN_CC" ]; then + check_c_lib "$1" "$2" + elif [ -n "$TOOLCHAIN_CXX" ]; then + check_cpp_lib "$1" "$2" + fi } -printf "detect C compiler... " +detect_c_compiler() +{ + if [ -n "$TOOLCHAIN_CC" ]; then + return 0 + fi + printf "detect C compiler... " + if [ -n "$CC" ]; then + if check_c_compiler "$CC"; then + TOOLCHAIN_CC=$CC + TOOLCHAIN=`"$TEMP_DIR/checkcc"` + TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -` + echo "$CC" + return 0 + else + echo "$CC is not a working C compiler" + return 1 + fi + else + for COMP in $C_COMPILERS + do + if check_c_compiler "$COMP"; then + TOOLCHAIN_CC=$COMP + TOOLCHAIN=`"$TEMP_DIR/checkcc"` + TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -` + echo "$COMP" + return 0 + fi + done + echo "not found" + return 1 + fi +} -for COMP in $C_COMPILERS -do - check_c_compiler $COMP - if [ $? -ne 0 ]; then - if [ ! -z "$CC" ]; then - if [ $COMP = $CC ]; then - echo "$CC is not a working C Compiler" - TOOLCHAIN_DETECTION_ERROR="error" - break - fi - fi - else - TOOLCHAIN_NAME=`$TEMP_DIR/checkcc` - USE_TOOLCHAIN=$TOOLCHAIN_NAME - if [ $COMP = "cc" ]; then - # we have found a working compiler, but in case - # the compiler is gcc or clang, we try to use - # these commands and not 'cc' - TOOLCHAIN_NAME=`$TEMP_DIR/checkcc` - if [ $TOOLCHAIN_NAME = "gcc" ]; then - check_c_compiler "gcc" - if [ $? -eq 0 ]; then - COMP=gcc - USE_TOOLCHAIN="gcc" - fi - fi - if [ $TOOLCHAIN_NAME = "clang" ]; then - check_c_compiler "clang" - if [ $? -eq 0 ]; then - COMP=clang - USE_TOOLCHAIN="clang" - fi - fi - fi - - TOOLCHAIN_NAME=$USE_TOOLCHAIN - TOOLCHAIN_CC=$COMP - echo $COMP - break - fi -done -if [ -z $TOOLCHAIN_CC ]; then - echo "not found" -fi - -printf "detect C++ compiler... " +detect_cpp_compiler() +{ + if [ -n "$TOOLCHAIN_CXX" ]; then + return 0 + fi + printf "detect C++ compiler... " -for COMP in $CPP_COMPILERS -do - check_cpp_compiler $COMP - if [ $? -ne 0 ]; then - if [ ! -z "$CXX" ]; then - if [ $COMP = $CXX ]; then - echo "$CC is not a working C++ Compiler" - TOOLCHAIN_DETECTION_ERROR="error" - break - fi - fi - else - if [ $COMP = "CC" ]; then - # we have found a working compiler, but in case - # the compiler is gcc or clang, we try to use - # these commands and not 'cc' - TOOLCHAIN_NAME=`$TEMP_DIR/checkcc` - USE_TOOLCHAIN=$TOOLCHAIN_NAME - if [ $TOOLCHAIN_NAME = "gcc" ]; then - check_cpp_compiler "g++" - if [ $? -eq 0 ]; then - COMP=g++ - USE_TOOLCHAIN="gcc" - fi - fi - if [ $TOOLCHAIN_NAME = "clang" ]; then - check_cpp_compiler "clang++" - if [ $? -eq 0 ]; then - COMP=clang++ - USE_TOOLCHAIN="clang" - fi - fi - fi - - TOOLCHAIN_NAME=$USE_TOOLCHAIN - TOOLCHAIN_CXX=$COMP - echo $COMP - break - fi -done -if [ -z $TOOLCHAIN_CXX ]; then - echo "not found" -fi + if [ -n "$CXX" ]; then + if check_cpp_compiler "$CXX"; then + TOOLCHAIN_CXX=$CXX + TOOLCHAIN=`"$TEMP_DIR/checkcc"` + TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -` + echo "$CXX" + return 0 + else + echo "$CXX is not a working C++ compiler" + return 1 + fi + else + for COMP in $CPP_COMPILERS + do + if check_cpp_compiler "$COMP"; then + TOOLCHAIN_CXX=$COMP + TOOLCHAIN=`"$TEMP_DIR/checkcc"` + TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -` + echo "$COMP" + return 0 + fi + done + echo "${TOOLCHAIN_CXX:-"not found"}" + return 1 + fi +} -TOOLCHAIN_LD=$TOOLCHAIN_CC - -if [ -z "$TOOLCHAIN_NAME" ]; then - TOOLCHAIN_DETECTION_ERROR="error" -else - cat >> $TEMP_DIR/config.mk << __EOF__ -# toolchain -__EOF__ - echo "CC = ${TOOLCHAIN_CC}" >> $TEMP_DIR/config.mk - if [ ! -z "$TOOLCHAIN_CXX" ]; then - echo "CXX = ${TOOLCHAIN_CXX}" >> $TEMP_DIR/config.mk - fi - echo "LD = ${TOOLCHAIN_LD}" >> $TEMP_DIR/config.mk - echo >> $TEMP_DIR/config.mk - - cat "make/${TOOLCHAIN_NAME}.mk" > /dev/null 2>&1 - if [ $? -eq 0 ]; then - echo "include \$(BUILD_ROOT)/make/${TOOLCHAIN_NAME}.mk" >> $TEMP_DIR/config.mk - else - echo "SHLIB_CFLAGS = -fPIC" >> $TEMP_DIR/config.mk - echo "SHLIB_LDFLAGS = -shared" >> $TEMP_DIR/config.mk - fi -fi +write_toolchain_defaults() +{ + echo "# toolchain" >> "$1" + if [ -n "$TOOLCHAIN_CC" ]; then + echo "CC = ${TOOLCHAIN_CC}" >> "$1" + fi + if [ -n "$TOOLCHAIN_CXX" ]; then + echo "CXX = ${TOOLCHAIN_CXX}" >> "$1" + fi + echo >> "$1" + if [ -f "make/${TOOLCHAIN_NAME}.mk" ]; then + cat "make/${TOOLCHAIN_NAME}.mk" >> "$1" + elif [ -f "make/cc.mk" ]; then + cat "make/cc.mk" >> "$1" + else + echo "!!! WARNING !!! Default toolchain flags not found. Configuration might be incomplete." + fi +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/uwproj.xsd Sun Jun 09 15:43:08 2024 +0200 @@ -0,0 +1,287 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns="http://unixwork.de/uwproj" + targetNamespace="http://unixwork.de/uwproj" + elementFormDefault="qualified" + version="0.2" +> + <xs:element name="project" type="ProjectType"/> + + <xs:complexType name="ProjectType"> + <xs:annotation> + <xs:documentation> + The root element of an uwproj project. + Consists of an optional <code>config</code> element + and an arbitrary number of <code>dependency</code> + and <code>target</code> elements. + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="config" type="ConfigType" minOccurs="0"/> + <xs:element name="dependency" type="DependencyType" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="target" type="TargetType" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="ConfigType"> + <xs:annotation> + <xs:documentation> + The configuration section. + Consists of an arbitrary number of <code>var</code> elements. + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="var" type="ConfigVarType" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="ConfigVarType"> + <xs:annotation> + <xs:documentation> + The definition of a configuration variable. + <p> + Configuration variables are supposed to be used in the configure script and are also + written to the resulting config file (in contrast to make variables, which are only + written to the config file). + The <code>name</code> attribute is mandatory, the value is defined by the text body of the element. + The optional Boolean <code>exec</code> attribute (false by default) controls, whether the entire + definition is automatically executed under command substitution. + </p> + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="exec" type="xs:boolean" default="false"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + + <xs:complexType name="PkgConfigType"> + <xs:annotation> + <xs:documentation> + Instructs configure to invoke <code>pkg-config</code>, if present on the system, to determine + compiler and linker flags. The text body of this element defines the package name to search. + To constrain the allowed versions, use the attributes <code>atleast, exact, max</code>. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="atleast" type="xs:string"/> + <xs:attribute name="exact" type="xs:string"/> + <xs:attribute name="max" type="xs:string"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + + <xs:simpleType name="LangType"> + <xs:annotation> + <xs:documentation> + Requests a compiler for the specified language. Allowed values are + c, cpp. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:enumeration value="c"/> + <xs:enumeration value="cpp"/> + </xs:restriction> + </xs:simpleType> + + <xs:complexType name="DependencyType"> + <xs:annotation> + <xs:documentation> + Declares a dependency. + <p> + If the optional <code>name</code> attribute is omitted, the dependency is global + and must be satisfied, otherwise configuration shall fail. + A <em>named dependency</em> can be referenced by a target (or is implicitly referenced + by the default target, if no targets are specified). + Multiple declarations for the same named dependency may exist, in which case each declaration + is checked one after another, until one block is satisfied. The result of the first satisfied + dependency declaration is supposed to be applied to the config file. + </p> + <p> + The optional <code>platform</code> attribute may specify a <em>single</em> platform identifier and + the optional <code>toolchain</code> attribute may specify a <em>single</em> toolchain. + The optional <code>not</code> attribute may specify a comma-separated list of platform and/or + toolchain identifiers. + The configure script shall skip this dependency declaration if the detected platform and toolchain + is not matching the filter specification of these attributes. + </p> + </xs:documentation> + </xs:annotation> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="lang" type="LangType"/> + <xs:element name="cflags" type="FlagsType"/> + <xs:element name="cxxflags" type="FlagsType"/> + <xs:element name="ldflags" type="FlagsType"/> + <xs:element name="pkgconfig" type="PkgConfigType"/> + <xs:element name="test" type="xs:string"> + <xs:annotation> + <xs:documentation> + Specifies a custom command that shall be executed to test whether this dependency is satisfied. + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="make" type="MakeVarType"/> + </xs:choice> + <xs:attribute name="name" type="xs:string"/> + <xs:attribute name="platform" type="xs:string"/> + <xs:attribute name="toolchain" type="xs:string"/> + <xs:attribute name="not" type="xs:string"/> + </xs:complexType> + + <xs:complexType name="FlagsType"> + <xs:annotation> + <xs:documentation> + Instructs configure to append the contents of the element's body to the respective flags variable. + If the optional <code>exec</code> flag is set to <code>true</code>, the contents are supposed to be + executed under command substitution <em>at configuration time</em> before they are applied. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="exec" type="xs:boolean" default="false"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + + <xs:complexType name="TargetType"> + <xs:annotation> + <xs:documentation> + Declares a build target that is supposed to be configured. + <p> + If no build target is declared explicitly, an implicit default + target is generated, which has the <code>alldependencies</code> + flag set. + </p> + <p> + The optional <code>name</code> attribute is also used to generate a prefix + for the compiler and linker flags variables. + Furthermore, a target may consist of an arbitrary number of <code>feature</code>, + <code>option</code>, and <code>define</code> elements. + Named dependencies can be listed (separated by comma) in the <code>dependencies</code> + element. If this target shall use <em>all</em> available named dependencies, the empty + element <code>alldependencies</code> can be used as a shortcut. + </p> + </xs:documentation> + </xs:annotation> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="feature" type="FeatureType"/> + <xs:element name="option" type="OptionType"/> + <xs:element name="define" type="DefineType"/> + <xs:element name="dependencies" type="DependenciesType"/> + <xs:element name="alldependencies"> + <xs:complexType/> + </xs:element> + </xs:choice> + <xs:attribute name="name" type="xs:string"/> + </xs:complexType> + + <xs:complexType name="FeatureType"> + <xs:annotation> + <xs:documentation> + Declares an optional feature, that can be enabled during configuration, if all + <code>dependencies</code> are satisfied. + If a feature is enabled, all <code>define</code> and <code>make</code> definitions are + supposed to be applied to the config file. + In case the optional <code>default</code> attribute is set to true, the feature is enabled by default + and is supposed to be automatically disabled (without error) when the dependencies are not satisfied. + The name that is supposed to be used for the --enable and --disable arguments can be optionally + specified with the <code>arg</code> attribute. Otherwise, the <code>name</code> is used by default. + Optionally, a description for the help text of the resulting configure script can be specified by + adding a <code>desc</code> element. + </xs:documentation> + </xs:annotation> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="TargetDataGroup"/> + </xs:choice> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="arg" type="xs:string"/> + <xs:attribute name="default" type="xs:boolean" default="false"/> + <xs:element name="desc" type="xs:string"/> + </xs:complexType> + + <xs:complexType name="OptionType"> + <xs:annotation> + <xs:documentation> + Declares a configuration option. + The option argument name is specified with the <code>arg</code> attribute. + Then, the children of this element specify possible <code>values</code> by defining the conditions + (in terms of dependencies) and effects (in terms of defines and make variables) of each value. + Finally, a set of <code>default</code>s is specified which supposed to automagically select the most + appropriate value for a specific platform under the available dependencies (in case the option is not + explicitly specified by using the command line argument). + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="value" type="OptionValueType" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="default" type="OptionDefaultType" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="arg" type="xs:string" use="required"/> + </xs:complexType> + + <xs:complexType name="OptionValueType"> + <xs:annotation> + <xs:documentation> + Declares a possible value for the option (in the <code>str</code> attribute) and + the conditions (<code>dependencies</code>) and effects, the value has. + </xs:documentation> + </xs:annotation> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="TargetDataGroup"/> + </xs:choice> + <xs:attribute name="str" type="xs:string" use="required"/> + </xs:complexType> + + <xs:complexType name="OptionDefaultType"> + <xs:annotation> + <xs:documentation> + Specifies a default value for this option. Multiple default values can be specified, in which case + they are checked one after another for availability. With the optional <code>platform</code> attribute, + the default value can be constrained to a <em>single</em> specific platform and is supposed to be + skipped by configure, when this platform is not detected. + </xs:documentation> + </xs:annotation> + <xs:attribute name="value" type="xs:string" use="required"/> + <xs:attribute name="platform" type="xs:string"/> + </xs:complexType> + + <xs:group name="TargetDataGroup"> + <xs:choice> + <xs:element name="define" type="DefineType" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="dependencies" type="DependenciesType" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="make" type="MakeVarType" minOccurs="0" maxOccurs="unbounded"/> + </xs:choice> + </xs:group> + + <xs:complexType name="DefineType"> + <xs:annotation> + <xs:documentation> + Specifies C/C++ pre-processor definitions that are supposed to + be appended to the compiler flags, if supported. + (Note: for example, Fortran also supports C/C++ style pre-processor definitions under + certain circumstances) + </xs:documentation> + </xs:annotation> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="value" type="xs:string"/> + </xs:complexType> + + <xs:simpleType name="DependenciesType"> + <xs:annotation> + <xs:documentation>A comma-separated list of named dependencies.</xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <xs:simpleType name="MakeVarType"> + <xs:annotation> + <xs:documentation> + The text contents in the body of this element are supposed to be appended literally + to the config file without prior processing. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"/> + </xs:simpleType> +</xs:schema>
--- a/make/windows.mk Mon Feb 12 21:13:23 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. -# -# Copyright 2011 Olaf Wintermann. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -CC = gcc -LD = gcc -AR = ar -RM = rm - -CFLAGS = -std=gnu99 -LDFLAGS = -ARFLAGS = -r -RMFLAGS = -f - -OBJ_EXT = obj -LIB_EXT = lib -APP_EXT = .exe -
--- a/ucx/Makefile Mon Feb 12 21:13:23 2024 +0100 +++ b/ucx/Makefile Sun Jun 09 15:43:08 2024 +0200 @@ -32,7 +32,7 @@ # list of source files SRC = allocator.c SRC += array_list.c -SRC += basic_mempool.c +SRC += mempool.c SRC += buffer.c SRC += compare.c SRC += hash_key.c
--- a/ui/common/objs.mk Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/common/objs.mk Sun Jun 09 15:43:08 2024 +0200 @@ -38,6 +38,7 @@ COMMON_OBJ += menu.o COMMON_OBJ += toolbar.o COMMON_OBJ += ucx_properties.o +COMMON_OBJ += threadpool.o TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)%) TOOLKITSOURCE += $(COMMON_OBJ:%.o=common/%.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/common/threadpool.c Sun Jun 09 15:43:08 2024 +0200 @@ -0,0 +1,174 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "threadpool.h" + +#include <pthread.h> + +#ifndef _WIN32 + + +static threadpool_job kill_job; + +UiThreadpool* threadpool_new(int min, int max) { + UiThreadpool *pool = malloc(sizeof(UiThreadpool)); + pool->queue = NULL; + pool->queue_len = 0; + pool->num_idle = 0; + pool->min_threads = min; + pool->max_threads = max; + + pthread_mutex_init(&pool->queue_lock, NULL); + pthread_mutex_init(&pool->avlbl_lock, NULL); + pthread_cond_init(&pool->available, NULL); + + return pool; +} + +int threadpool_start(UiThreadpool *pool) { + /* create pool threads */ + for(int i=0;i<pool->min_threads;i++) { + pthread_t t; + if (pthread_create(&t, NULL, threadpool_func, pool) != 0) { + fprintf(stderr, "uic: threadpool_start: pthread_create failed: %s", strerror(errno)); + return 1; + } + } + return 0; +} + +void* threadpool_func(void *data) { + UiThreadpool *pool = (UiThreadpool*)data; + + for(;;) { + threadpool_job *job = threadpool_get_job(pool); + if(job == &kill_job) { + break; + } + + job->callback(job->data); + + free(job); + } + return NULL; +} + +threadpool_job* threadpool_get_job(UiThreadpool *pool) { + pthread_mutex_lock(&pool->queue_lock); + + threadpool_job *job = NULL; + pool->num_idle++; + while(job == NULL) { + if(pool->queue_len == 0) { + pthread_cond_wait(&pool->available, &pool->queue_lock); + continue; + } else { + pool_queue_t *q = pool->queue; + job = q->job; + pool->queue = q->next; + pool->queue_len--; + free(q); + } + } + pool->num_idle--; + + pthread_mutex_unlock(&pool->queue_lock); + return job; +} + +void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) { + // TODO: handle errors + + threadpool_job *job = malloc(sizeof(threadpool_job)); + job->callback = func; + job->data = data; + + pthread_mutex_lock(&pool->queue_lock); + threadpool_enqueue_job(pool, job); + + int create_thread = 0; + int destroy_thread = 0; + int diff = pool->queue_len - pool->num_idle; + + //if(pool->queue_len == 1) { + pthread_cond_signal(&pool->available); + //} + + pthread_mutex_unlock(&pool->queue_lock); +} + +void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) { + pool_queue_t *q = malloc(sizeof(pool_queue_t)); + q->job = job; + q->next = NULL; + + if(pool->queue == NULL) { + pool->queue = q; + } else { + pool_queue_t *last_elem = pool->queue; + while(last_elem->next != NULL) { + last_elem = last_elem->next; + } + last_elem->next = q; + } + pool->queue_len++; +} + + + + + + +UiThreadpool* ui_threadpool_create(int nthreads) { + return threadpool_new(nthreads, nthreads); +} + +void ui_threadpool_destroy(UiThreadpool* pool) { + +} + +static void* ui_threadpool_job_func(void *data) { + UiJob *job = data; + + free(job); + return NULL; +} + +void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { + UiJob* job = malloc(sizeof(UiJob)); + job->obj = obj; + job->job_func = tf; + job->job_data = td; + job->finish_callback = f; + job->finish_data = fd; + threadpool_run(pool, ui_threadpool_job_func, job); +} + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/common/threadpool.h Sun Jun 09 15:43:08 2024 +0200 @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UIC_THREADPOOL_H +#define UIC_THREADPOOL_H + +#include "../ui/toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct UiJob { + UiObject *obj; + ui_threadfunc job_func; + void *job_data; + ui_callback finish_callback; + void *finish_data; +} UiJob; + + +typedef struct _threadpool_job threadpool_job; +typedef void*(*job_callback_f)(void *data); + +typedef struct _pool_queue pool_queue_t; +struct UiThreadpool { + pthread_mutex_t queue_lock; + pthread_mutex_t avlbl_lock; + pthread_cond_t available; + pool_queue_t *queue; + uint32_t queue_len; + uint32_t num_idle; + int min_threads; + int max_threads; +}; + +struct _threadpool_job { + job_callback_f callback; + void *data; +}; + +struct _pool_queue { + threadpool_job *job; + pool_queue_t *next; +}; + +UiThreadpool* threadpool_new(int min, int max); +int threadpool_start(UiThreadpool *pool); +void* threadpool_func(void *data); +threadpool_job* threadpool_get_job(UiThreadpool *pool); +void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data); +void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job); + +#ifdef __cplusplus +} +#endif + +#endif /* UIC_THREADPOOL_H */ +
--- a/ui/gtk/button.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/button.c Sun Jun 09 15:43:08 2024 +0200 @@ -35,15 +35,41 @@ #include "../common/context.h" #include "../common/object.h" -UIWIDGET ui_button_deprecated(UiObject *obj, char *label, ui_callback f, void *data) { - GtkWidget *button = gtk_button_new_with_label(label); +void ui_button_set_icon_name(GtkWidget *button, const char *icon) { + if(!icon) { + return; + } - if(f) { +#ifdef UI_GTK4 + gtk_button_set_icon_name(GTK_BUTTON(button), icon); +#else +#if GTK_CHECK_VERSION(2, 6, 0) + GtkWidget *image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_BUTTON); + if(image) { + gtk_button_set_image(GTK_BUTTON(button), image); + } +#else + // TODO +#endif +#endif +} + +UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) { + UiObject* current = uic_current_obj(obj); + GtkWidget *button = gtk_button_new(); + if(args.label) { + gtk_button_set_label(GTK_BUTTON(button), args.label); + } + ui_button_set_icon_name(button, args.icon); + + + if(args.onclick) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; - event->userdata = data; - event->callback = f; + event->userdata = args.onclickdata; + event->callback = args.onclick; event->value = 0; + event->customdata = NULL; g_signal_connect( button, @@ -57,8 +83,8 @@ event); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, button, FALSE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, button, FALSE); return button; } @@ -98,66 +124,90 @@ ui_notify_evt(i->observers, &e); } -UIWIDGET ui_checkbox_var(UiObject *obj, char *label, UiVar *var) { - GtkWidget *button = gtk_check_button_new_with_label(label); +static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) { + UiObject* current = uic_current_obj(obj); - // bind value - if(var) { - UiInteger *value = var->value; - value->obj = GTK_TOGGLE_BUTTON(button); + if(args.label) { + gtk_button_set_label(GTK_BUTTON(widget), args.label); + } + ui_button_set_icon_name(widget, args.icon); + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); + if (var) { + UiInteger* value = (UiInteger*)var->value; + value->obj = widget; value->get = ui_toggle_button_get; value->set = ui_toggle_button_set; - gtk_toggle_button_set_active(value->obj, value->value); UiVarEventData *event = malloc(sizeof(UiVarEventData)); event->obj = obj; event->var = var; event->observers = NULL; + event->callback = NULL; + event->userdata = NULL; g_signal_connect( - button, + widget, "clicked", G_CALLBACK(ui_toggled_obs), event); g_signal_connect( - button, + widget, "destroy", G_CALLBACK(ui_destroy_vardata), event); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, button, FALSE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, widget, FALSE); - return button; + return widget; +} + +UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { + return togglebutton_create(obj, gtk_toggle_button_new(), args); } -UIWIDGET ui_checkbox_deprecated(UiObject *obj, char *label, UiInteger *value) { - UiVar *var = NULL; - if(value) { - var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - } - return ui_checkbox_var(obj, label, var); +UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { + return togglebutton_create(obj, gtk_check_button_new(), args); } -UIWIDGET ui_checkbox_nv(UiObject *obj, char *label, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_INTEGER); - return ui_checkbox_var(obj, label, var); +UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) { +#ifdef UI_GTK3 + return NULL; // TODO +#else + return ui_checkbox_create(obj, args); +#endif } -UIWIDGET ui_radiobutton_var(UiObject *obj, char *label, UiVar *var) { + + + + +UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) { + UiObject* current = uic_current_obj(obj); + GSList *rg = NULL; UiInteger *rgroup; + UiVar* var = NULL; + if (args.value) { + var = uic_create_value_var(current->ctx, args.value); + } else if (args.varname) { + var = uic_create_var(obj->ctx, args.varname, UI_VAR_INTEGER); + } + + UiBool first = FALSE; if(var) { rgroup = var->value; rg = rgroup->obj; + if(!rg) { + first = TRUE; + } } - GtkWidget *rbutton = gtk_radio_button_new_with_label(rg, label); + GtkWidget *rbutton = gtk_radio_button_new_with_label(rg, args.label ? args.label : ""); rg = gtk_radio_button_get_group(GTK_RADIO_BUTTON(rbutton)); if(rgroup) { @@ -171,17 +221,21 @@ event->obj = obj; event->var = var; event->observers = NULL; + event->callback = NULL; + event->userdata = NULL; g_signal_connect( rbutton, "clicked", G_CALLBACK(ui_radio_obs), event); - g_signal_connect( + if(first) { + g_signal_connect( rbutton, "destroy", G_CALLBACK(ui_destroy_vardata), event); + } } UiContainer *ct = uic_get_current_container(obj); @@ -190,21 +244,6 @@ return rbutton; } -UIWIDGET ui_radiobutton_deprecated(UiObject *obj, char *label, UiInteger *rgroup) { - UiVar *var = NULL; - if(rgroup) { - var = malloc(sizeof(UiVar)); - var->value = rgroup; - var->type = UI_VAR_SPECIAL; - } - return ui_radiobutton_var(obj, label, var); -} - -UIWIDGET ui_radiobutton_nv(UiObject *obj, char *label, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_INTEGER); - return ui_radiobutton_var(obj, label, var); -} - void ui_radio_obs(GtkToggleToolButton *widget, UiVarEventData *event) { UiInteger *i = event->var->value;
--- a/ui/gtk/button.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/button.h Sun Jun 09 15:43:08 2024 +0200 @@ -37,6 +37,8 @@ extern "C" { #endif +void ui_button_set_icon_name(GtkWidget *button, const char *icon_name); + // event wrapper void ui_button_clicked(GtkWidget *widget, UiEventData *event);
--- a/ui/gtk/container.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/container.c Sun Jun 09 15:43:08 2024 +0200 @@ -141,10 +141,11 @@ gtk_widget_set_vexpand(widget, TRUE); } - int gwidth = ct->layout.gridwidth > 0 ? ct->layout.gridwidth : 1; + int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1; + int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1; - gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, gwidth, 1); - grid->x += gwidth; + gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, colspan, rowspan); + grid->x += colspan; ui_reset_layout(ct->layout); ct->current = widget; @@ -171,6 +172,10 @@ GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; + int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1; + int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1; + // TODO: use colspan/rowspan + gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0); grid->x++; int nw = grid->x > grid->width ? grid->x : grid->width; @@ -254,12 +259,12 @@ UiContainer *ct = current->container; UI_APPLY_LAYOUT1(current, args); - GtkWidget *vbox = ui_gtk_vbox_new(args.spacing); - GtkWidget *widget = args.margin > 0 ? box_set_margin(vbox, args.margin) : vbox; + GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); + GtkWidget *widget = args.margin > 0 ? box_set_margin(box, args.margin) : box; ct->add(ct, widget, TRUE); - UiObject *newobj = uic_object_new(obj, vbox); - newobj->container = ui_box_container(obj, vbox); + UiObject *newobj = uic_object_new(obj, box); + newobj->container = ui_box_container(obj, box); uic_obj_add(obj, newobj); return widget; @@ -276,7 +281,8 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { - UiContainer *ct = uic_get_current_container(obj); + UiObject* current = uic_current_obj(obj); + UI_APPLY_LAYOUT1(current, args); GtkWidget *widget; #ifdef UI_GTK3 @@ -287,8 +293,8 @@ gtk_widget_set_margin_start(grid, args.margin); gtk_widget_set_margin_end(grid, args.margin); #else - gtk_widget_set_margin_left(grid, margin); - gtk_widget_set_margin_right(grid, margin); + gtk_widget_set_margin_left(grid, args.margin); + gtk_widget_set_margin_right(grid, args.margin); #endif gtk_widget_set_margin_top(grid, args.margin); gtk_widget_set_margin_bottom(grid, args.margin); @@ -309,7 +315,7 @@ widget = grid; } #endif - ct->add(ct, widget, TRUE); + current->container->add(current->container, widget, TRUE); UiObject *newobj = uic_object_new(obj, grid); newobj->container = ui_grid_container(obj, grid); @@ -319,6 +325,19 @@ } +UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) { + UiObject* current = uic_current_obj(obj); + UI_APPLY_LAYOUT1(current, args); + + GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); + UiObject *newobj = uic_object_new(obj, sw); + newobj->container = ui_scrolledwindow_container(obj, sw); + uic_obj_add(obj, newobj); + + return sw; +} + + void ui_select_tab(UIWIDGET tabview, int tab) { gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); } @@ -367,11 +386,6 @@ ct->layout.vexpand = expand; } -void ui_layout_gridwidth(UiObject *obj, int width) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.gridwidth = width; -} - void ui_layout_colspan(UiObject* obj, int cols) { UiContainer* ct = uic_get_current_container(obj); ct->layout.colspan = cols;
--- a/ui/gtk/container.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/container.h Sun Jun 09 15:43:08 2024 +0200 @@ -61,7 +61,6 @@ UiBool hexpand; UiBool vexpand; int width; - int gridwidth; int colspan; int rowspan; };
--- a/ui/gtk/display.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/display.c Sun Jun 09 15:43:08 2024 +0200 @@ -33,6 +33,7 @@ #include "container.h" #include "../common/context.h" #include "../common/object.h" +#include "../ui/display.h" static void set_alignment(GtkWidget *widget, float xalign, float yalign) { #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16 @@ -43,30 +44,60 @@ #endif } -UIWIDGET ui_label(UiObject *obj, char *label) { - GtkWidget *widget = gtk_label_new(label); +UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) { + UiObject* current = uic_current_obj(obj); + + GtkWidget *widget = gtk_label_new(args.label); + switch(args.align) { + case UI_ALIGN_DEFAULT: break; + case UI_ALIGN_LEFT: set_alignment(widget, 0, .5); break; + case UI_ALIGN_RIGHT: set_alignment(widget, 1, .5); break; + case UI_ALIGN_CENTER: break; // TODO + } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, widget, FALSE); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiString* value = (UiString*)var->value; + value->obj = widget; + value->get = ui_label_get; + value->set = ui_label_set; + } + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, widget, FALSE); return widget; } -UIWIDGET ui_llabel(UiObject *obj, char *label) { - UIWIDGET widget = ui_label(obj, label); - set_alignment(widget, 0, .5); - return widget; +UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) { + args.align = UI_ALIGN_LEFT; + return ui_label_create(obj, args); +} + +UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args) { + args.align = UI_ALIGN_RIGHT; + return ui_label_create(obj, args); } -UIWIDGET ui_rlabel(UiObject *obj, char *label) { - UIWIDGET widget = ui_label(obj, label); - //gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_RIGHT); - - set_alignment(widget, 1, .5); - return widget; +char* ui_label_get(UiString *s) { + if(s->value.ptr) { + s->value.free(s->value.ptr); + } + s->value.ptr = g_strdup(gtk_label_get_text(GTK_LABEL(s->obj))); + s->value.free = (ui_freefunc)g_free; + return s->value.ptr; } -UIWIDGET ui_space(UiObject *obj) { +void ui_label_set(UiString *s, const char *value) { + gtk_label_set_text(GTK_LABEL(s->obj), value); + if(s->value.ptr) { + s->value.free(s->value.ptr); + s->value.ptr = NULL; + s->value.free = NULL; + } +} + +UIWIDGET ui_space_deprecated(UiObject *obj) { GtkWidget *widget = gtk_label_new(""); UiContainer *ct = uic_get_current_container(obj); ct->add(ct, widget, TRUE); @@ -74,7 +105,7 @@ return widget; } -UIWIDGET ui_separator(UiObject *obj) { +UIWIDGET ui_separator_deprecated(UiObject *obj) { #if UI_GTK3 GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); #else @@ -88,20 +119,12 @@ /* ------------------------- progress bar ------------------------- */ -UIWIDGET ui_progressbar(UiObject *obj, UiDouble *value) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - return ui_progressbar_var(obj, var); -} - -UIWIDGET ui_progressbar_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_DOUBLE); - return ui_progressbar_var(obj, var); -} - -UIWIDGET ui_progressbar_var(UiObject *obj, UiVar *var) { +UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) { + UiObject* current = uic_current_obj(obj); + GtkWidget *progressbar = gtk_progress_bar_new(); + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_DOUBLE); if(var && var->value) { UiDouble *value = var->value; value->get = ui_progressbar_get; @@ -110,8 +133,8 @@ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), 0.5); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, progressbar, FALSE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, progressbar, FALSE); return progressbar; } @@ -125,3 +148,42 @@ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(d->obj), value); d->value = value; } + + +/* ------------------------- progress spinner ------------------------- */ + +UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args) { + UiObject* current = uic_current_obj(obj); + + GtkWidget *spinner = gtk_spinner_new(); + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); + if(var && var->value) { + UiInteger *value = var->value; + value->get = ui_spinner_get; + value->set = ui_spinner_set; + value->obj = spinner; + ui_spinner_set(value, value->value); + } + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, spinner, FALSE); + + return spinner; +} + +int64_t ui_spinner_get(UiInteger *i) { + return i->value; +} + +void ui_spinner_set(UiInteger *i, int64_t value) { + i->value = value; + if(i->obj) { + GtkSpinner *spinner = GTK_SPINNER(i->obj); + if(value != 0) { + gtk_spinner_start(spinner); + } else { + gtk_spinner_stop(spinner); + } + } +}
--- a/ui/gtk/display.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/display.h Sun Jun 09 15:43:08 2024 +0200 @@ -36,9 +36,14 @@ extern "C" { #endif +char* ui_label_get(UiString *s); +void ui_label_set(UiString *s, const char *value); + UIWIDGET ui_progressbar_var(UiObject *obj, UiVar *var); double ui_progressbar_get(UiDouble *d); void ui_progressbar_set(UiDouble *d, double value); +int64_t ui_spinner_get(UiInteger *i); +void ui_spinner_set(UiInteger *i, int64_t value); #ifdef __cplusplus }
--- a/ui/gtk/dnd.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/dnd.c Sun Jun 09 15:43:08 2024 +0200 @@ -101,3 +101,19 @@ return NULL; } */ + +void ui_selection_settext(UiDnD *sel, char *str, int len) { + +} + +void ui_selection_seturis(UiDnD *sel, char **uris, int nelm) { + +} + +char* ui_selection_gettext(UiDnD *sel) { + return NULL; +} + +UiFileList ui_selection_geturis(UiDnD *sel) { + return (UiFileList){NULL,0}; +}
--- a/ui/gtk/entry.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/entry.c Sun Jun 09 15:43:08 2024 +0200 @@ -35,65 +35,46 @@ #include "entry.h" -UIWIDGET ui_spinner(UiObject *obj, int step, UiInteger *i) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = i; - var->type = UI_VAR_SPECIAL; - return ui_spinner_var(obj, step, 0, var, UI_VAR_INTEGER); -} - -UIWIDGET ui_spinnerf(UiObject *obj, double step, int digits, UiDouble *d) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = d; - var->type = UI_VAR_SPECIAL; - return ui_spinner_var(obj, step, digits, var, UI_VAR_DOUBLE); -} - -UIWIDGET ui_spinnerr(UiObject *obj, UiRange *r) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = r; - var->type = UI_VAR_SPECIAL; - return ui_spinner_var(obj, r->extent, 1, var, UI_VAR_RANGE); -} - -UIWIDGET ui_spinner_nv(UiObject *obj, int step, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_INTEGER); - return ui_spinner_var(obj, step, 0, var, UI_VAR_INTEGER); -} - -UIWIDGET ui_spinnerf_nv(UiObject *obj, double step, int digits, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_DOUBLE); - return ui_spinner_var(obj, step, digits, var, UI_VAR_DOUBLE); -} - -UIWIDGET ui_spinnerr_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_RANGE); - UiRange *r = var->value; - return ui_spinner_var(obj, r->extent, 1, var, UI_VAR_RANGE); -} - -UIWIDGET ui_spinner_var(UiObject *obj, double step, int digits, UiVar *var, UiVarType type) { +UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) { double min = 0; double max = 1000; - if(type == UI_VAR_RANGE) { + + UiObject* current = uic_current_obj(obj); + + UiVar *var = NULL; + if(args.varname) { + var = uic_get_var(obj->ctx, args.varname); + } + + if(!var) { + if(args.intvalue) { + var = uic_widget_var(obj->ctx, current->ctx, args.intvalue, NULL, UI_VAR_INTEGER); + } else if(args.doublevalue) { + var = uic_widget_var(obj->ctx, current->ctx, args.doublevalue, NULL, UI_VAR_DOUBLE); + } else if(args.rangevalue) { + var = uic_widget_var(obj->ctx, current->ctx, args.rangevalue, NULL, UI_VAR_RANGE); + } + } + + if(var && var->type == UI_VAR_RANGE) { UiRange *r = var->value; min = r->min; max = r->max; } - if(step == 0) { - step = 1; + if(args.step == 0) { + args.step = 1; } #ifdef UI_GTK2LEGACY if(min == max) { max = min + 1; } #endif - GtkWidget *spin = gtk_spin_button_new_with_range(min, max, step); - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), digits); + GtkWidget *spin = gtk_spin_button_new_with_range(min, max, args.step); + gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args.digits); + UiObserver **obs = NULL; if(var) { double value = 0; - UiObserver **obs = NULL; - switch(type) { + switch(var->type) { default: break; case UI_VAR_INTEGER: { UiInteger *i = var->value; @@ -126,26 +107,28 @@ } } gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), value); - - UiVarEventData *event = malloc(sizeof(UiVarEventData)); - event->obj = obj; - event->var = var; - event->observers = obs; - - g_signal_connect( - spin, - "value-changed", - G_CALLBACK(ui_spinner_changed), - event); - g_signal_connect( - spin, - "destroy", - G_CALLBACK(ui_destroy_vardata), - event); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, spin, FALSE); + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->var = var; + event->observers = obs; + event->callback = args.onchange; + event->userdata = args.onchangedata; + + g_signal_connect( + spin, + "value-changed", + G_CALLBACK(ui_spinner_changed), + event); + g_signal_connect( + spin, + "destroy", + G_CALLBACK(ui_destroy_vardata), + event); + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, spin, FALSE); return spin; } @@ -160,15 +143,22 @@ void ui_spinner_changed(GtkSpinButton *spinner, UiVarEventData *event) { + gdouble value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinner)); UiEvent e; e.obj = event->obj; e.window = event->obj->window; e.document = event->obj->ctx->document; - e.eventdata = event->var->value; - e.intval = 0; + e.eventdata = &value; + e.intval = (int64_t)value; - UiObserver *observer = *event->observers; - ui_notify_evt(observer, &e); + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(event->observers) { + UiObserver *observer = *event->observers; + ui_notify_evt(observer, &e); + } }
--- a/ui/gtk/entry.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/entry.h Sun Jun 09 15:43:08 2024 +0200 @@ -22,7 +22,6 @@ extern "C" { #endif -UIWIDGET ui_spinner_var(UiObject *obj, double step, int digits, UiVar *var, UiVarType type); void ui_spinner_changed(GtkSpinButton *spinner, UiVarEventData *event); int64_t ui_spinbutton_getint(UiInteger *i);
--- a/ui/gtk/graphics.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/graphics.c Sun Jun 09 15:43:08 2024 +0200 @@ -104,6 +104,8 @@ event->obj = obj; event->callback = f; event->userdata = u; + event->customdata = NULL; + event->value = 0; g_signal_connect(G_OBJECT(widget), "button-press-event",
--- a/ui/gtk/image.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/image.c Sun Jun 09 15:43:08 2024 +0200 @@ -59,7 +59,7 @@ } } -// **** new functions **** +// **** deprecated2**** static UiIcon* get_icon(const char *name, int size, int scale) { #ifdef UI_SUPPORTS_SCALE @@ -70,24 +70,58 @@ if(info) { UiIcon *icon = malloc(sizeof(UiIcon)); icon->info = info; + icon->pixbuf = NULL; return icon; } return NULL; } -/* -UiIcon* ui_icon(const char *name, int size) { +UiIcon* ui_icon(const char* name, size_t size) { return get_icon(name, size, ui_get_scalefactor()); } -*/ + +UiIcon* ui_imageicon(const char* file) { + GError *error = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, &error); + if(!pixbuf) { + fprintf(stderr, "UiError: Cannot load image: %s\n", file); + return NULL; + } + + UiIcon *icon = malloc(sizeof(UiIcon)); + icon->info = NULL; + icon->pixbuf = pixbuf; + return icon; +} + +void ui_icon_free(UiIcon* icon) { + if(icon->info) { + g_object_unref(icon->info); + } + if(icon->pixbuf) { + g_object_unref(icon->pixbuf); + } + free(icon); +} + +UiIcon* ui_foldericon(size_t size) { + return ui_icon("folder", size); +} + +UiIcon* ui_fileicon(size_t size) { + return ui_icon("application-x-generic", size); +} UiIcon* ui_icon_unscaled(const char *name, int size) { return get_icon(name, size, 1); } -void ui_free_icon(UiIcon *icon) { - g_object_unref(icon->info); - free(icon); +GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { + if(!icon->pixbuf) { + GError *error = NULL; + icon->pixbuf = gtk_icon_info_load_icon(icon->info, &error); + } + return icon->pixbuf; } UiImage* ui_icon_image(UiIcon *icon) {
--- a/ui/gtk/image.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/image.h Sun Jun 09 15:43:08 2024 +0200 @@ -42,6 +42,7 @@ struct UiIcon { GtkIconInfo *info; + GdkPixbuf *pixbuf; }; struct UiImage { @@ -52,6 +53,7 @@ GdkPixbuf* ui_get_image(const char *name); +GdkPixbuf* ui_icon_pixbuf(UiIcon *icon); #ifdef __cplusplus }
--- a/ui/gtk/menu.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/menu.c Sun Jun 09 15:43:08 2024 +0200 @@ -74,6 +74,16 @@ return mb; } +void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it, obj); + it = it->next; + index++; + } +} + void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) { UiMenu *menu = (UiMenu*)item; @@ -81,14 +91,8 @@ GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget); - UiMenuItemI *it = menu->items_begin; - int index = 0; - while(it) { - createMenuItem[it->type](menu_widget, index, it, obj); - - it = it->next; - index++; - } + ui_add_menu_items(menu_widget, i, menu, obj); + gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item); } @@ -105,6 +109,7 @@ event->userdata = i->userdata; event->callback = i->callback; event->value = 0; + event->customdata = NULL; g_signal_connect( widget, @@ -121,7 +126,10 @@ gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); if(i->groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); + CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups); + cxListAddArray(groups, i->groups, i->ngroups); + uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); + cxListDestroy(groups); } } @@ -185,7 +193,8 @@ event->userdata = ci->userdata; event->callback = ci->callback; event->value = 0; - + event->customdata = NULL; + g_signal_connect( widget, "toggled", @@ -235,8 +244,8 @@ ls->index = index; ls->oldcount = 0; - // TODO: - //ls->list = il->list; + UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + ls->list = var->value; ls->callback = il->callback; ls->userdata = il->userdata; @@ -284,6 +293,7 @@ event->userdata = list->userdata; event->callback = list->callback; event->value = i - 1; + event->customdata = NULL; g_signal_connect( widget, @@ -408,6 +418,7 @@ event->userdata = userdata; event->callback = f; event->value = 0; + event->customdata = NULL; g_signal_connect( widget, @@ -462,6 +473,7 @@ event->userdata = userdata; event->callback = f; event->value = 0; + event->customdata = NULL; g_signal_connect( widget,
--- a/ui/gtk/menu.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/menu.h Sun Jun 09 15:43:08 2024 +0200 @@ -55,6 +55,8 @@ GtkWidget *ui_create_menubar(UiObject *obj); +void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj); + void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_st_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj);
--- a/ui/gtk/objs.mk Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/objs.mk Sun Jun 09 15:43:08 2024 +0200 @@ -38,7 +38,6 @@ GTKOBJ += button.o GTKOBJ += display.o GTKOBJ += text.o -GTKOBJ += model.o GTKOBJ += tree.o GTKOBJ += image.o GTKOBJ += graphics.o
--- a/ui/gtk/range.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/range.c Sun Jun 09 15:43:08 2024 +0200 @@ -61,6 +61,7 @@ event->userdata = userdata; event->callback = f; event->value = 0; + event->customdata = NULL; g_signal_connect( G_OBJECT(scrollbar),
--- a/ui/gtk/text.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/text.c Sun Jun 09 15:43:08 2024 +0200 @@ -33,6 +33,10 @@ #include "text.h" #include "container.h" +#include <cx/printf.h> + +#include <gdk/gdkkeysyms.h> + #include "../common/types.h" @@ -534,9 +538,14 @@ } -static UIWIDGET create_textfield_var(UiObject *obj, int width, UiBool frameless, UiBool password, UiVar *var) { + + +static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs args) { GtkWidget *textfield = gtk_entry_new(); + UiObject* current = uic_current_obj(obj); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING); + UiTextField *uitext = malloc(sizeof(UiTextField)); uitext->ctx = obj->ctx; uitext->var = var; @@ -547,8 +556,8 @@ G_CALLBACK(ui_textfield_destroy), uitext); - if(width > 0) { - gtk_entry_set_width_chars(GTK_ENTRY(textfield), width); + if(args.width > 0) { + gtk_entry_set_width_chars(GTK_ENTRY(textfield), args.width); } if(frameless) { // TODO: gtk2legacy workaroud @@ -586,40 +595,25 @@ return textfield; } -static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - return create_textfield_var(obj, width, frameless, password, var); - } else { - // TODO: error - } - return NULL; +UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) { + return create_textfield(obj, FALSE, FALSE, args); } -static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) { - UiVar *var = NULL; - if(value) { - var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - } - return create_textfield_var(obj, width, frameless, password, var); +UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, TRUE, FALSE, args); } +UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, FALSE, TRUE, args); +} + + void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) { - if(textfield->var) { - UiText *text = textfield->var->value; - if(text->undomgr) { - ui_destroy_undomgr(text->undomgr); - } - ui_destroy_boundvar(textfield->ctx, textfield->var); - } free(textfield); } void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) { + // changed event is only registered, if the textfield->var != NULL UiString *value = textfield->var->value; if(value->observers) { UiEvent e; @@ -632,45 +626,6 @@ } } -UIWIDGET ui_textfield_deprecated(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, FALSE, varname); -} - -UIWIDGET ui_textfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, FALSE, varname); -} - -UIWIDGET ui_frameless_textfield_deprecated(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, TRUE, FALSE, value); -} - -UIWIDGET ui_frameless_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, TRUE, FALSE, varname); -} - -UIWIDGET ui_passwordfield_deprecated(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, TRUE, varname); -} - -UIWIDGET ui_passwordfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, TRUE, varname); -} char* ui_textfield_get(UiString *str) { if(str->value.ptr) { @@ -689,3 +644,283 @@ str->value.free = NULL; } } + +// ----------------------- path textfield ----------------------- + +// TODO: move to common +static UiPathElm* default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) { + cxstring *pathelms; + size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms); + + if (nelm == 0) { + *ret_nelm = 0; + return NULL; + } + + UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm)); + size_t n = nelm; + int j = 0; + for (int i = 0; i < nelm; i++) { + cxstring c = pathelms[i]; + if (c.length == 0) { + if (i == 0) { + c.length = 1; + } + else { + n--; + continue; + } + } + + cxmutstr m = cx_strdup(c); + elms[j].name = m.ptr; + elms[j].name_len = m.length; + + size_t elm_path_len = c.ptr + c.length - full_path; + cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len)); + elms[j].path = elm_path.ptr; + elms[j].path_len = elm_path.length; + + j++; + } + *ret_nelm = n; + + return elms; +} + +static gboolean path_textfield_btn_pressed(GtkWidget *widget, GdkEventButton *event, UiPathTextField *pathtf) { + gtk_box_pack_start(GTK_BOX(pathtf->hbox), pathtf->entry, TRUE, TRUE, 0); + gtk_container_remove(GTK_CONTAINER(pathtf->hbox), pathtf->buttonbox); + + gtk_widget_show(pathtf->entry); + gtk_widget_grab_focus(pathtf->entry); + + return TRUE; +} + +static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) { + for(int i=0;i<nelm;i++) { + free(elms[i].name); + free(elms[i].path); + } + free(elms); +} + +static void ui_path_textfield_destroy(GtkWidget *object, UiPathTextField *pathtf) { + free(pathtf->current_path); + g_object_unref(pathtf->entry); + free(pathtf); +} + +static void ui_path_textfield_activate(GtkWidget *entry, UiPathTextField *pathtf) { + const gchar *text = gtk_entry_get_text(GTK_ENTRY(pathtf->entry)); + if(strlen(text) == 0) { + return; + } + + UiObject *obj = pathtf->obj; + + if(ui_pathtextfield_update(pathtf, text)) { + return; + } + + if(pathtf->onactivate) { + UiEvent evt; + evt.obj = obj; + evt.window = obj->window; + evt.document = obj->ctx->document; + evt.eventdata = (char*)text; + evt.intval = -1; + pathtf->onactivate(&evt, pathtf->onactivatedata); + } +} + +static gboolean ui_path_textfield_key_press(GtkWidget *self, GdkEventKey *event, UiPathTextField *pathtf) { + if (event->keyval == GDK_KEY_Escape) { + // reset GtkEntry value + gtk_entry_set_text(GTK_ENTRY(self), pathtf->current_path); + const gchar *text = gtk_entry_get_text(GTK_ENTRY(self)); + ui_pathtextfield_update(pathtf, text); + return TRUE; + } + return FALSE; +} + +static GtkWidget* create_path_button_box() { + GtkWidget *bb = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_EXPAND); // linked style + gtk_box_set_homogeneous(GTK_BOX(bb), FALSE); + gtk_box_set_spacing(GTK_BOX(bb), 0); + return bb; +} + +UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) { + UiObject* current = uic_current_obj(obj); + + UiPathTextField *pathtf = malloc(sizeof(UiPathTextField)); + memset(pathtf, 0, sizeof(UiPathTextField)); + pathtf->obj = obj; + pathtf->getpathelm = args.getpathelm; + pathtf->getpathelmdata = args.getpathelmdata; + pathtf->onactivate = args.onactivate; + pathtf->onactivatedata = args.onactivatedata; + pathtf->ondragcomplete = args.ondragcomplete; + pathtf->ondragcompletedata = args.ondragcompletedata; + pathtf->ondragstart = args.ondragstart; + pathtf->ondragstartdata = args.ondragstartdata; + pathtf->ondrop = args.ondrop; + pathtf->ondropdata = args.ondropsdata; + + if(!pathtf->getpathelm) { + pathtf->getpathelm = default_pathelm_func; + pathtf->getpathelmdata = NULL; + } + + // top level container for the path textfield is a GtkEventBox + // the event box is needed to handle background button presses + GtkWidget *eventbox = gtk_event_box_new(); + g_signal_connect( + eventbox, + "button-press-event", + G_CALLBACK(path_textfield_btn_pressed), + pathtf); + g_signal_connect( + eventbox, + "destroy", + G_CALLBACK(ui_path_textfield_destroy), + pathtf); + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, eventbox, FALSE); + + // hbox as parent for the GtkEntry and GtkButtonBox + GtkWidget *hbox = ui_gtk_hbox_new(0); + pathtf->hbox = hbox; + gtk_container_add(GTK_CONTAINER(eventbox), hbox); + gtk_widget_set_name(hbox, "path-textfield-box"); + + // create GtkEntry, that is also visible by default (with input yet) + pathtf->entry = gtk_entry_new(); + g_object_ref(G_OBJECT(pathtf->entry)); + gtk_box_pack_start(GTK_BOX(hbox), pathtf->entry, TRUE, TRUE, 0); + + g_signal_connect( + pathtf->entry, + "activate", + G_CALLBACK(ui_path_textfield_activate), + pathtf); + g_signal_connect( + pathtf->entry, + "key-press-event", + G_CALLBACK(ui_path_textfield_key_press), + pathtf); + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING); + if (var) { + UiString* value = (UiString*)var->value; + value->obj = pathtf; + value->get = ui_path_textfield_get; + value->set = ui_path_textfield_set; + + if(value->value.ptr) { + char *str = strdup(value->value.ptr); + ui_string_set(value, str); + free(str); + } + } + + return hbox; +} + +void ui_path_button_clicked(GtkWidget *widget, UiEventData *event) { + UiPathElm *elm = event->customdata; + cxmutstr path = cx_strdup(cx_strn(elm->path, elm->path_len)); + UiEvent evt; + evt.obj = event->obj; + evt.window = evt.obj->window; + evt.document = evt.obj->ctx->document; + evt.eventdata = elm->path; + evt.intval = event->value; + event->callback(&evt, event->userdata); + free(path.ptr); +} + +int ui_pathtextfield_update(UiPathTextField* pathtf, const char *full_path) { + size_t full_path_len = strlen(full_path); + + size_t nelm = 0; + UiPathElm* path_elm = pathtf->getpathelm(full_path, full_path_len, &nelm, pathtf->getpathelmdata); + if (!path_elm) { + return 1; + } + + free(pathtf->current_path); + pathtf->current_path = strdup(full_path); + + ui_pathelm_destroy(pathtf->current_pathelms, pathtf->current_nelm); + pathtf->current_pathelms = path_elm; + pathtf->current_nelm = nelm; + + GtkWidget *buttonbox = create_path_button_box(); + pathtf->buttonbox = buttonbox; + + // switch from entry to buttonbox + gtk_container_remove(GTK_CONTAINER(pathtf->hbox), pathtf->entry); + gtk_box_pack_start(GTK_BOX(pathtf->hbox), buttonbox, FALSE, FALSE, 0); + + for (int i=0;i<nelm;i++) { + UiPathElm *elm = &path_elm[i]; + + cxmutstr name = cx_strdup(cx_strn(elm->name, elm->name_len)); + GtkWidget *button = gtk_button_new_with_label(name.ptr); + free(name.ptr); + + if(pathtf->onactivate) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = pathtf->onactivate; + eventdata->userdata = pathtf->onactivatedata; + eventdata->obj = pathtf->obj; + eventdata->customdata = elm; + eventdata->value = i; + + g_signal_connect( + button, + "clicked", + G_CALLBACK(ui_path_button_clicked), + eventdata); + + g_signal_connect( + button, + "destroy", + G_CALLBACK(ui_destroy_userdata), + eventdata); + } + + gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 0); + } + + gtk_widget_show_all(buttonbox); + + return 0; +} + +char* ui_path_textfield_get(UiString *str) { + if(str->value.ptr) { + str->value.free(str->value.ptr); + } + UiPathTextField *tf = str->obj; + str->value.ptr = g_strdup(gtk_entry_get_text(GTK_ENTRY(tf->entry))); + str->value.free = (ui_freefunc)g_free; + return str->value.ptr; +} + +void ui_path_textfield_set(UiString *str, const char *value) { + UiPathTextField *tf = str->obj; + gtk_entry_set_text(GTK_ENTRY(tf->entry), value); + ui_pathtextfield_update(tf, value); + if(str->value.ptr) { + str->value.free(str->value.ptr); + str->value.ptr = NULL; + str->value.free = NULL; + } +}
--- a/ui/gtk/text.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/text.h Sun Jun 09 15:43:08 2024 +0200 @@ -72,6 +72,31 @@ // TODO: validatefunc } UiTextField; +typedef struct UiPathTextField { + UiObject *obj; + + GtkWidget *hbox; + GtkWidget *entry; + GtkWidget *buttonbox; + + char *current_path; + UiPathElm *current_pathelms; + size_t current_nelm; + + ui_pathelm_func getpathelm; + void* getpathelmdata; + + ui_callback onactivate; + void* onactivatedata; + + ui_callback ondragstart; + void* ondragstartdata; + ui_callback ondragcomplete; + void* ondragcompletedata; + ui_callback ondrop; + void* ondropdata; +} UiPathTextField; + UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var); void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea); @@ -110,6 +135,10 @@ char* ui_textfield_get(UiString *str); void ui_textfield_set(UiString *str, const char *value); +int ui_pathtextfield_update(UiPathTextField* pathtf, const char *full_path); +char* ui_path_textfield_get(UiString *str); +void ui_path_textfield_set(UiString *str, const char *value); + #ifdef __cplusplus } #endif
--- a/ui/gtk/toolbar.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/toolbar.c Sun Jun 09 15:43:08 2024 +0200 @@ -31,6 +31,7 @@ #include <string.h> #include "toolbar.h" +#include "menu.h" #include "button.h" #include "image.h" #include "tree.h" @@ -40,192 +41,8 @@ #include <cx/array_list.h> #include "../common/context.h" -static CxMap *toolbar_items; -static CxList *defaults; - -void ui_toolbar_init() { - toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - defaults = cxLinkedListCreateSimple(CX_STORE_POINTERS); -} - -void ui_toolitem(char *name, char *label, ui_callback f, void *udata) { - ui_toolitem_img(name, label, NULL, f, udata); -} - -void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgr(name, stockid, f, userdata, -1); -} - -void ui_toolitem_sti(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgri(name, stockid, f, userdata, -1); -} - -void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 0, f, userdata, ap); - va_end(ap); -} - -void ui_toolitem_stgri(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 1, f, userdata, ap); - va_end(ap); -} - -void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) { - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->isimportant = 0; - item->groups = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_vstgr( - char *name, - char *stockid, - int isimportant, - ui_callback f, - void *userdata, - va_list ap) -{ - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = isimportant; - - // add groups - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle(const char *name, const char *label, const char *img, UiInteger *i) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->stockid = NULL; - item->groups = NULL; - item->isimportant = 0; - item->value = i; - item->var = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_st(const char *name, const char *stockid, UiInteger *i) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = NULL; - item->image = NULL; - item->stockid = stockid; - item->groups = NULL; - item->isimportant = 0; - item->value = i; - item->var = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_nv(const char *name, const char *label, const char *img, const char *intvar) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->stockid = NULL; - item->groups = NULL; - item->isimportant = 0; - item->value = NULL; - item->var = intvar; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_stnv(const char *name, const char *stockid, const char *intvar) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = NULL; - item->image = NULL; - item->stockid = stockid; - item->groups = NULL; - item->isimportant = 0; - item->value = NULL; - item->var = intvar; - - cxMapPut(toolbar_items, name, item); -} - - -void ui_toolbar_combobox( - char *name, - UiList *list, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox; - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - cb->var = var; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - -void ui_toolbar_combobox_str( - char *name, - UiList *list, - ui_callback f, - void *udata) -{ - ui_toolbar_combobox(name, list, ui_strmodel_getvalue, f, udata); -} - -void ui_toolbar_combobox_nv( - char *name, - char *listname, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBoxNV *cb = malloc(sizeof(UiToolbarComboBoxNV)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox_nv; - cb->listname = listname; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - GtkWidget* ui_create_toolbar(UiObject *obj) { - if(!defaults) { - return NULL; - } - GtkWidget *toolbar = gtk_toolbar_new(); #ifdef UI_GTK3 gtk_style_context_add_class( @@ -233,6 +50,16 @@ GTK_STYLE_CLASS_PRIMARY_TOOLBAR); #endif + CxMap *items = uic_get_toolbar_items(); + CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); + CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); + CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); + + ui_toolbar_add_items(obj, toolbar, items, left_defaults); + ui_toolbar_add_items(obj, toolbar, items, center_defaults); + ui_toolbar_add_items(obj, toolbar, items, right_defaults); + + /* GtkToolbar *tb = GTK_TOOLBAR(toolbar); CxIterator i = cxListIterator(defaults); cx_foreach(char *, def, i) { @@ -245,57 +72,86 @@ fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); } } + */ return toolbar; } -void add_toolitem_widget(GtkToolbar *tb, UiToolItem *item, UiObject *obj) { - GtkToolItem *button = gtk_tool_button_new(NULL, item->label); - gtk_tool_item_set_homogeneous(button, FALSE); - if(item->image) { - GdkPixbuf *pixbuf = ui_get_image(item->image); - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image); +static void create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { + GtkToolbar *tb = GTK_TOOLBAR(toolbar); + switch(i->type) { + case UI_TOOLBAR_ITEM: { + add_toolitem_widget(tb, (UiToolbarItem*)i, obj); + break; + } + case UI_TOOLBAR_TOGGLEITEM: { + add_toolitem_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); + break; + } + case UI_TOOLBAR_MENU: { + add_toolitem_menu_widget(tb, (UiToolbarMenuItem*)i, obj); + break; + } + default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); + } +} + +void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults) { + // add pre-configured items + CxIterator i = cxListIterator(defaults); + cx_foreach(char*, def, i) { + UiToolbarItemI* item = uic_toolbar_get_item(def); + if (!item) { + fprintf(stderr, "unknown toolbar item: %s\n", def); + continue; + } + create_item(obj, toolbar, item); + } +} + +static void set_toolbutton_icon(GtkToolItem *item, const char *icon_name) { +#if GTK_MAJOR_VERSION >= 3 + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), icon_name); +#else + UiIcon *icon = ui_icon(icon_name, 24); + if(icon) { + GdkPixbuf *pixbuf = ui_icon_pixbuf(icon); + if(pixbuf) { + GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); + gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), image); + } + } +#endif +} + +void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) { + GtkToolItem *button; + if(item->args.stockid) { +#ifdef UI_GTK2 + button = gtk_tool_button_new_from_stock(item->args.stockid); +#else + // TODO: gtk3 stock + button = gtk_tool_button_new(NULL, item->args.label); +#endif } else { - gtk_tool_item_set_is_important(button, TRUE); + button = gtk_tool_button_new(NULL, item->args.label); } - if(item->callback) { + gtk_tool_item_set_homogeneous(button, FALSE); + if(item->args.icon) { + set_toolbutton_icon(button, item->args.icon); + } + gtk_tool_item_set_is_important(button, TRUE); + + if(item->args.onclick) { UiEventData *event = cxMalloc( obj->ctx->allocator, sizeof(UiEventData)); event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - - g_signal_connect( - button, - "clicked", - G_CALLBACK(ui_button_clicked), - event); - } - - gtk_toolbar_insert(tb, button, -1); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); - } -} - -void add_toolitem_st_widget(GtkToolbar *tb, UiStToolItem *item, UiObject *obj) { - GtkToolItem *button = gtk_tool_button_new_from_stock(item->stockid); - gtk_tool_item_set_homogeneous(button, FALSE); - if(item->isimportant) { - gtk_tool_item_set_is_important(button, TRUE); - } - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; + event->callback = item->args.onclick; + event->userdata = item->args.onclickdata; + event->customdata = NULL; + event->value = 0; g_signal_connect( button, @@ -306,74 +162,71 @@ gtk_toolbar_insert(tb, button, -1); + /* if(item->groups) { uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); } + */ } -void add_toolitem_toggle_widget(GtkToolbar *tb, UiToggleToolItem *item, UiObject *obj) { +void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj) { GtkToolItem *button; - if(item->stockid) { - button = gtk_toggle_tool_button_new_from_stock(item->stockid); + if(item->args.stockid) { +#ifdef UI_GTK2 + button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); +#else + button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); // TODO: gtk3 stock +#endif } else { button = gtk_toggle_tool_button_new(); gtk_tool_item_set_homogeneous(button, FALSE); - if(item->label) { - gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->label); + if(item->args.label) { + gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label); } - if(item->image) { - GdkPixbuf *pixbuf = ui_get_image(item->image); - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image); + if(item->args.icon) { + set_toolbutton_icon(button, item->args.icon); } } - UiVar *var; - if(item->value) { - var = malloc(sizeof(UiVar)); - var->value = item->value; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - } else { - var = uic_create_var(obj->ctx, item->var, UI_VAR_INTEGER); - } - - if(var->value) { - UiInteger *i = var->value; - i->get = ui_tool_toggle_button_get; - i->set = ui_tool_toggle_button_set; - i->obj = button; - - if(i->value != 0) { - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), TRUE); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER); + if(var) { + UiInteger *i = (UiInteger*)var->value; + if(i) { + i->get = ui_tool_toggle_button_get; + i->set = ui_tool_toggle_button_set; + i->obj = button; + + if(i->value != 0) { + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), TRUE); + } } } - // register event - // the event func will call the UiInteger observer callbacks - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); + UiVarEventData *event = cxMalloc( + obj->ctx->allocator, + sizeof(UiVarEventData)); event->obj = obj; - event->userdata = var; - event->callback = NULL; + event->callback = item->args.onchange; + event->userdata = item->args.onchangedata; + event->var = var; g_signal_connect( - button, - "toggled", - G_CALLBACK(ui_tool_button_toggled), - event); + button, + "toggled", + G_CALLBACK(ui_tool_button_toggled), + event); // add item to toolbar gtk_toolbar_insert(tb, button, -1); + /* if(item->groups) { uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); } + */ } -void ui_tool_button_toggled(GtkToggleToolButton *widget, UiEventData *event) { +void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event) { UiEvent e; e.obj = event->obj; e.window = event->obj->window; @@ -381,10 +234,16 @@ e.eventdata = NULL; e.intval = gtk_toggle_tool_button_get_active(widget); - UiVar *var = event->userdata; - UiInteger *i = var->value; + if(event->callback) { + event->callback(&e, event->userdata); + } - ui_notify_evt(i->observers, &e); + UiVar *var = event->var; + UiInteger *i = var ? var->value : NULL; + + if(i) { + ui_notify_evt(i->observers, &e); + } } int64_t ui_tool_toggle_button_get(UiInteger *integer) { @@ -398,6 +257,70 @@ integer->value = s; } + + +typedef struct UiToolbarMenuWidget { + GtkWidget *button; + GtkMenu *menu; +} UiToolbarMenuWidget; + +static void ui_toolbar_menubutton_clicked(GtkWidget *widget, UiToolbarMenuWidget *menu) { + int x; + gtk_menu_popup_at_widget(menu->menu, menu->button, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL); +} + +static void ui_toolbar_menubutton_destroy(GtkWidget *widget, UiToolbarMenuWidget *menu) { + free(menu); +} + +void add_toolitem_menu_widget(GtkToolbar *tb, UiToolbarMenuItem *item, UiObject *obj) { + GtkToolItem *button; + if(item->args.stockid) { +#ifdef UI_GTK2 + button = gtk_tool_button_new_from_stock(item->args.stockid); +#else + // TODO: gtk3 stock + button = gtk_tool_button_new(NULL, item->args.label); +#endif + } else { + button = gtk_tool_button_new(NULL, item->args.label); + } + + gtk_tool_item_set_homogeneous(button, FALSE); + if(item->args.icon) { + set_toolbutton_icon(button, item->args.icon); + } + gtk_tool_item_set_is_important(button, TRUE); + + gtk_toolbar_insert(tb, button, -1); + + // menu + GtkWidget *menu_widget = gtk_menu_new(); + ui_add_menu_items(menu_widget, 0, &item->menu, obj); + gtk_widget_show_all(menu_widget); + + UiToolbarMenuWidget *tbmenu = malloc(sizeof(UiToolbarMenuWidget)); + tbmenu->button = GTK_WIDGET(button); + tbmenu->menu = GTK_MENU(menu_widget); + + g_signal_connect( + button, + "clicked", + G_CALLBACK(ui_toolbar_menubutton_clicked), + tbmenu); + + g_signal_connect( + button, + "destroy", + G_CALLBACK(ui_toolbar_menubutton_destroy), + tbmenu); +} + + + + +// deprecated / unsupported +/* void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) { UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); modelinfo->getvalue = cb->getvalue; @@ -422,4 +345,76 @@ gtk_toolbar_insert(tb, item, -1); } } +*/ + + +#ifdef UI_GTK3 + +GtkWidget* ui_create_headerbar(UiObject *obj) { + GtkWidget *headerbar = gtk_header_bar_new(); + + CxMap *items = uic_get_toolbar_items(); + CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); + CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); + CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); + + ui_headerbar_add_items(obj, headerbar, items, left_defaults); + ui_headerbar_add_items(obj, headerbar, items, center_defaults); + ui_headerbar_add_items(obj, headerbar, items, right_defaults); + + return headerbar; +} + +static void hb_create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { + GtkHeaderBar *tb = GTK_HEADER_BAR(toolbar); + switch(i->type) { + case UI_TOOLBAR_ITEM: { + add_headerbar_item_widget(tb, (UiToolbarItem*)i, obj); + break; + } + case UI_TOOLBAR_TOGGLEITEM: { + add_headerbar_item_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); + break; + } + case UI_TOOLBAR_MENU: { + add_headerbar_item_menu_widget(tb, (UiToolbarMenuItem*)i, obj); + break; + } + default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); + } +} + + +void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxMap *items, CxList *defaults) { + // add pre-configured items + CxIterator i = cxListIterator(defaults); + cx_foreach(char*, def, i) { + UiToolbarItemI* item = uic_toolbar_get_item(def); + if (!item) { + fprintf(stderr, "unknown toolbar item: %s\n", def); + continue; + } + hb_create_item(obj, headerbar, item); + } +} + +void add_headerbar_item_widget(GtkHeaderBar *hb, UiToolbarItem *item, UiObject *obj) { + GtkWidget *button = gtk_button_new_with_label(item->args.label); + if(item->args.icon) { + ui_button_set_icon_name(button, item->args.icon); + } + + gtk_header_bar_pack_start(hb, button); + +} + +void add_headerbar_item_toggle_widget(GtkHeaderBar *hb, UiToolbarToggleItem *item, UiObject *obj) { + +} + +void add_headerbar_item_menu_widget(GtkHeaderBar *hb, UiToolbarMenuItem *item, UiObject *obj) { + +} + +#endif
--- a/ui/gtk/toolbar.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/toolbar.h Sun Jun 09 15:43:08 2024 +0200 @@ -30,10 +30,10 @@ #define TOOLBAR_H #include "../ui/toolbar.h" +#include "../common/toolbar.h" #include <cx/map.h> #include <cx/list.h> -#include "model.h" #include "tree.h" #ifdef __cplusplus @@ -102,7 +102,6 @@ void *userdata; }; -void ui_toolbar_init(); void ui_toolitem_vstgr( char *name, @@ -114,18 +113,31 @@ GtkWidget* ui_create_toolbar(UiObject *obj); -void add_toolitem_widget(GtkToolbar *tb, UiToolItem *item, UiObject *obj); -void add_toolitem_st_widget(GtkToolbar *tb, UiStToolItem *item, UiObject *obj); -void add_toolitem_toggle_widget(GtkToolbar *tb, UiToggleToolItem *item, UiObject *obj); +void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults); + +void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj); +void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj); +void add_toolitem_menu_widget(GtkToolbar *tb, UiToolbarMenuItem *item, UiObject *obj); + +void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event); +int64_t ui_tool_toggle_button_get(UiInteger *integer); +void ui_tool_toggle_button_set(UiInteger *integer, int64_t value); +GtkWidget* ui_create_headerbar(UiObject *obj); + +void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxMap *items, CxList *defaults); + +void add_headerbar_item_widget(GtkHeaderBar *hb, UiToolbarItem *item, UiObject *obj); +void add_headerbar_item_toggle_widget(GtkHeaderBar *hb, UiToolbarToggleItem *item, UiObject *obj); +void add_headerbar_item_menu_widget(GtkHeaderBar *hb, UiToolbarMenuItem *item, UiObject *obj); + + +/* void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj); void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj); void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e); void ui_combobox_update(UiEvent *event, void *combobox); - -void ui_tool_button_toggled(GtkToggleToolButton *widget, UiEventData *event); -int64_t ui_tool_toggle_button_get(UiInteger *integer); -void ui_tool_toggle_button_set(UiInteger *integer, int64_t value); +*/ #ifdef __cplusplus }
--- a/ui/gtk/toolkit.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/toolkit.c Sun Jun 09 15:43:08 2024 +0200 @@ -33,10 +33,12 @@ #include "toolkit.h" #include "toolbar.h" -#include "model.h" #include "image.h" #include "../common/document.h" #include "../common/properties.h" +#include "../common/menu.h" +#include "../common/toolbar.h" +#include "../common/threadpool.h" #include <cx/utils.h> #include <cx/string.h> @@ -70,14 +72,12 @@ gtk_init(&argc, &argv); application_name = appname; + ui_css_init(); + uic_docmgr_init(); - ui_toolbar_init(); // TODO: remove uic_toolbar_init(); - // init custom types - ui_list_init(); - ui_image_init(); uic_load_app_properties(); @@ -191,6 +191,23 @@ return NULL; } +static gboolean ui_idle_func(void *data) { + UiJob *job = data; + job->job_func(job->job_data); + free(job); + return FALSE; +} + +void ui_call_mainthread(ui_threadfunc tf, void* td) { + UiJob *job = malloc(sizeof(UiJob)); + job->job_func = tf; + job->job_data = td; + job->finish_callback = NULL; + job->finish_data = NULL; + job->obj = NULL; + g_idle_add(ui_idle_func, job); +} + void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { UiJob *job = malloc(sizeof(UiJob)); job->obj = obj; @@ -245,7 +262,9 @@ } void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { - ui_destroy_boundvar(data->obj->ctx, data->var); + if(data->var) { + ui_destroy_boundvar(data->obj->ctx, data->var); + } free(data); } @@ -270,3 +289,28 @@ } +#if GTK_MAJOR_VERSION >= 3 + +static GtkCssProvider* ui_gtk_css_provider; + +static const char *ui_gtk_css = +"#path-textfield-box {" +" background-color: @theme_base_color;" +" border-radius: 5px;" +" padding: 0px;" +"}"; + +void ui_css_init(void) { + ui_gtk_css_provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1, NULL); + + GdkScreen *screen = gdk_screen_get_default(); + gtk_style_context_add_provider_for_screen( + screen, + GTK_STYLE_PROVIDER(ui_gtk_css_provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); +} + + + +#endif \ No newline at end of file
--- a/ui/gtk/toolkit.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/toolkit.h Sun Jun 09 15:43:08 2024 +0200 @@ -44,23 +44,17 @@ ui_callback callback; void *userdata; int value; + void *customdata; } UiEventData; typedef struct UiVarEventData { - UiObject *obj; - UiVar *var; - UiObserver **observers; + UiObject *obj; + UiVar *var; + UiObserver **observers; + ui_callback callback; + void *userdata; } UiVarEventData; - -typedef struct UiJob { - UiObject *obj; - ui_threadfunc job_func; - void *job_data; - ui_callback finish_callback; - void *finish_data; -} UiJob; - struct UiSelection { GtkSelectionData *data; }; @@ -82,6 +76,10 @@ void ui_set_active_window(UiObject *obj); UiObject *ui_get_active_window(); +#if GTK_MAJOR_VERSION >= 3 +void ui_css_init(void); +#endif + #ifdef __cplusplus } #endif
--- a/ui/gtk/tree.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/tree.c Sun Jun 09 15:43:08 2024 +0200 @@ -36,16 +36,117 @@ #include "container.h" #include "tree.h" +#include "image.h" void* ui_strmodel_getvalue(void *elm, int column) { return column == 0 ? elm : NULL; } +static GtkListStore* create_list_store(UiList *list, UiModel *model) { + int columns = model->columns; + GType types[2*columns]; + int c = 0; + for(int i=0;i<columns;i++,c++) { + switch(model->types[i]) { + case UI_STRING: + case UI_STRING_FREE: types[c] = G_TYPE_STRING; break; + case UI_INTEGER: types[c] = G_TYPE_INT; break; + case UI_ICON: types[c] = G_TYPE_OBJECT; break; + case UI_ICON_TEXT: + case UI_ICON_TEXT_FREE: { + types[c] = G_TYPE_OBJECT; + types[++c] = G_TYPE_STRING; + } + } + } + + GtkListStore *store = gtk_list_store_newv(c, types); + + if(list) { + void *elm = list->first(list); + while(elm) { + // insert new row + GtkTreeIter iter; + gtk_list_store_insert (store, &iter, -1); + + // set column values + int c = 0; + for(int i=0;i<columns;i++,c++) { + void *data = model->getvalue(elm, c); + + GValue value = G_VALUE_INIT; + switch(model->types[i]) { + case UI_STRING: + case UI_STRING_FREE: { + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, data); + if(model->types[i] == UI_STRING_FREE) { + free(data); + } + break; + } + case UI_INTEGER: { + g_value_init(&value, G_TYPE_INT); + int *intptr = data; + g_value_set_int(&value, *intptr); + break; + } + case UI_ICON: { + g_value_init(&value, G_TYPE_OBJECT); + UiIcon *icon = data; + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + + if(icon->pixbuf) { + g_value_set_object(&value, icon->pixbuf); + } + + + break; + } + case UI_ICON_TEXT: + case UI_ICON_TEXT_FREE: { + GValue pixbufvalue = G_VALUE_INIT; + UiIcon *icon = data; + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + g_value_init(&pixbufvalue, G_TYPE_OBJECT); + g_value_set_object(&pixbufvalue, icon->pixbuf); + gtk_list_store_set_value(store, &iter, c, &pixbufvalue); + c++; + + char *str = model->getvalue(elm, c); + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, str); + if(model->types[i] == UI_ICON_TEXT_FREE) { + free(str); + } + break; + } + } + + gtk_list_store_set_value(store, &iter, c, &value); + } + + // next row + elm = list->next(list); + } + } + + return store; +} - -UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { +UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) { + UiObject* current = uic_current_obj(obj); + // create treeview GtkWidget *view = gtk_tree_view_new(); GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); @@ -64,9 +165,12 @@ #endif UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); - model->getvalue = getvalue; - UiList *list = var->value; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + model->getvalue = args.getvalue; + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); + + UiList *list = var ? var->value : NULL; + GtkListStore *listmodel = create_list_store(list, model); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); UiListView *listview = malloc(sizeof(UiListView)); @@ -85,11 +189,11 @@ list->obj = listview; // add callback - if(f) { + if(args.onactivate) { UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); event->obj = obj; - event->userdata = udata; - event->activate = f; + event->activatedata = args.onactivatedata; + event->activate = args.onactivate; event->selection = NULL; g_signal_connect( @@ -107,33 +211,16 @@ GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS gtk_container_add(GTK_CONTAINER(scroll_area), view); - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, scroll_area, TRUE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, scroll_area, FALSE); // ct->current should point to view, not scroll_area, to make it possible // to add a context menu - ct->current = view; + current->container->current = view; return scroll_area; } -UIWIDGET ui_listview_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_listview_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - return ui_listview_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) { printf("drag begin\n"); @@ -156,12 +243,17 @@ { "text/uri-list", 0, 2 }, }; -UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { +UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { + UiObject* current = uic_current_obj(obj); + // create treeview GtkWidget *view = gtk_tree_view_new(); + UiModel *model = args.model; + int columns = model ? model->columns : 0; + int addi = 0; - for(int i=0;i<model->columns;i++) { + for(int i=0;i<columns;i++) { GtkTreeViewColumn *column = NULL; if(model->types[i] == UI_ICON_TEXT) { column = gtk_tree_view_column_new(); @@ -178,6 +270,14 @@ gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); addi++; + } else if (model->types[i] == UI_ICON) { + GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes( + model->titles[i], + iconrenderer, + "pixbuf", + i + addi, + NULL); } else { GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( @@ -198,8 +298,10 @@ #endif - UiList *list = var->value; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); + + UiList *list = var ? var->value : NULL; + GtkListStore *listmodel = create_list_store(list, model); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); @@ -225,17 +327,18 @@ // add callback UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); event->obj = obj; - event->activate = cb.activate; - event->selection = cb.selection; - event->userdata = cb.userdata; - if(cb.activate) { + event->activate = args.onactivate; + event->selection = args.onselection; + event->activatedata = args.onactivatedata; + event->selectiondata = args.onselectiondata; + if(args.onactivate) { g_signal_connect( view, "row-activated", G_CALLBACK(ui_listview_activate_event), event); } - if(cb.selection) { + if(args.onselection) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(view)); g_signal_connect( @@ -258,32 +361,16 @@ GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS gtk_container_add(GTK_CONTAINER(scroll_area), view); - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, scroll_area, TRUE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, scroll_area, FALSE); // ct->current should point to view, not scroll_area, to make it possible // to add a context menu - ct->current = view; + current->container->current = view; return scroll_area; } -UIWIDGET ui_table_deprecated(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_table_var(obj, var, model, cb); -} - -UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModel *model, UiListCallbacks cb) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - return ui_table_var(obj, var, model, cb); - } else { - // TODO: error - } - return NULL; -} GtkWidget* ui_get_tree_widget(UIWIDGET widget) { GList *c = gtk_container_get_children(GTK_CONTAINER(widget)); @@ -370,9 +457,9 @@ void ui_listview_update(UiList *list, int i) { UiListView *view = list->obj; - UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); - gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model)); - g_object_unref(G_OBJECT(model)); + GtkListStore *store = create_list_store(list, view->model); + gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); // TODO: free old model } @@ -407,7 +494,7 @@ e.document = event->obj->ctx->document; e.eventdata = selection; e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->activate(&e, event->userdata); + event->activate(&e, event->activatedata); if(selection->count > 0) { free(selection->rows); @@ -427,7 +514,7 @@ e.document = event->obj->ctx->document; e.eventdata = selection; e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->selection(&e, event->userdata); + event->selection(&e, event->selectiondata); if(selection->count > 0) { free(selection->rows); @@ -468,42 +555,37 @@ /* --------------------------- ComboBox --------------------------- */ -UIWIDGET ui_combobox_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_combobox_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - return ui_combobox_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - -UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { +UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) { + UiObject* current = uic_current_obj(obj); + UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); - model->getvalue = getvalue; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + model->getvalue = args.getvalue; + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); - GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata); - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, combobox, FALSE); + GtkWidget *combobox = ui_create_combobox(obj, model, var, args.onactivate, args.onactivatedata); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, combobox, FALSE); + current->container->current = combobox; return combobox; } -GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) { - GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); - +GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata) { + GtkWidget *combobox = gtk_combo_box_new(); + UiListView *uicbox = malloc(sizeof(UiListView)); uicbox->obj = obj; uicbox->widget = combobox; - uicbox->var = model->var; - uicbox->model = model->model; + + UiList *list = var ? var->value : NULL; + GtkListStore *listmodel = create_list_store(list, model); + + if(listmodel) { + gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel)); + } + + uicbox->var = var; + uicbox->model = model; g_signal_connect( combobox, @@ -512,9 +594,10 @@ uicbox); // bind var - UiList *list = model->var->value; - list->update = ui_combobox_modelupdate; - list->obj = uicbox; + if(list) { + list->update = ui_combobox_modelupdate; + list->obj = uicbox; + } GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); @@ -533,6 +616,7 @@ event->userdata = udata; event->callback = f; event->value = 0; + event->customdata = NULL; g_signal_connect( combobox, @@ -556,7 +640,7 @@ void ui_combobox_modelupdate(UiList *list, int i) { UiListView *view = list->obj; - UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); - gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(model)); + GtkListStore *store = create_list_store(view->var->value, view->model); + gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store)); }
--- a/ui/gtk/tree.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/tree.h Sun Jun 09 15:43:08 2024 +0200 @@ -31,7 +31,6 @@ #include "../ui/tree.h" #include "toolkit.h" -#include "model.h" #ifdef __cplusplus extern "C" { @@ -48,7 +47,8 @@ UiObject *obj; ui_callback activate; ui_callback selection; - void *userdata; + void *activatedata; + void *selectiondata; } UiTreeEventData; void* ui_strmodel_getvalue(void *elm, int column); @@ -76,7 +76,7 @@ int ui_tree_path_list_index(GtkTreePath *path); UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata); -GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata); +GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata); void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e); void ui_combobox_modelupdate(UiList *list, int i);
--- a/ui/gtk/window.c Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/gtk/window.c Sun Jun 09 15:43:08 2024 +0200 @@ -126,6 +126,9 @@ gtk_box_pack_start(GTK_BOX(vbox), tb, FALSE, FALSE, 0); } } + + //GtkWidget *hb = ui_create_headerbar(obj); + //gtk_window_set_titlebar(GTK_WINDOW(obj->widget), hb); } // window content @@ -148,41 +151,171 @@ return create_window(title, window_data, FALSE); } -UiObject* ui_simplewindow(const char *title, void *window_data) { +UiObject* ui_simple_window(const char *title, void *window_data) { return create_window(title, window_data, TRUE); } -static char* ui_gtkfilechooser(UiObject *obj, GtkFileChooserAction action) { +void ui_window_size(UiObject *obj, int width, int height) { + gtk_window_set_default_size( + GTK_WINDOW(obj->widget), + width, + height); +} + +static void ui_dialog_response (GtkDialog* self, gint response_id, gpointer user_data) { + UiEventData *data = user_data; + UiEvent evt; + evt.obj = data->obj; + evt.document = evt.obj->ctx->document; + evt.window = evt.obj->window; + evt.eventdata = NULL; + evt.intval = 0; + + if(data->customdata) { + GtkWidget *entry = data->customdata; + evt.eventdata = (void*)gtk_entry_get_text(GTK_ENTRY(entry)); + + } + + if(response_id == 1 || response_id == 2) { + evt.intval = response_id; + } + + + if(data->callback) { + data->callback(&evt, data->userdata); + } + + gtk_widget_destroy(GTK_WIDGET(self)); +} + +void ui_dialog_create(UiObject *parent, UiDialogArgs args) { + GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new()); + GtkWidget *dialog_w = GTK_WIDGET(dialog); + if(args.title) { + gtk_window_set_title(GTK_WINDOW(dialog), args.title); + } + if(args.button1_label) { + gtk_dialog_add_button(dialog, args.button1_label, 1); + } + if(args.button2_label) { + gtk_dialog_add_button(dialog, args.button2_label, 2); + } + if(args.closebutton_label) { + gtk_dialog_add_button(dialog, args.closebutton_label, 0); + } + + GtkWidget *content_area = gtk_dialog_get_content_area(dialog); + if(args.content) { + GtkWidget *label = gtk_label_new(args.content); + gtk_container_add(GTK_CONTAINER(content_area), label); + } + + GtkWidget *textfield = NULL; + if(args.input) { + textfield = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), textfield); + } + + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = parent; + event->callback = args.result; + event->userdata = args.resultdata; + event->value = 0; + event->customdata = textfield; + + g_signal_connect(dialog_w, + "response", + G_CALLBACK(ui_dialog_response), + event); + + gtk_widget_show_all(GTK_WIDGET(dialog_w)); +} + +static void ui_gtkfilechooser(UiObject *obj, GtkFileChooserAction action, unsigned int mode, ui_callback file_selected_callback, void *cbdata) { char *button; char *title; - if(action == GTK_FILE_CHOOSER_ACTION_OPEN) { - button = GTK_STOCK_OPEN; - title = "Datei öffnen..."; + GtkWidget *dialog; + if((mode & UI_FILEDIALOG_SELECT_FOLDER) == UI_FILEDIALOG_SELECT_FOLDER) { + dialog = gtk_file_chooser_dialog_new ( + "Open Folder", + GTK_WINDOW(obj->widget), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "Cancel", + GTK_RESPONSE_CANCEL, + "Select Folder", + GTK_RESPONSE_ACCEPT, + NULL); + } else if(action == GTK_FILE_CHOOSER_ACTION_OPEN) { + dialog = gtk_file_chooser_dialog_new ( + "Select Folder", + GTK_WINDOW(obj->widget), + action, + "Cancel", + GTK_RESPONSE_CANCEL, + "Open File", + GTK_RESPONSE_ACCEPT, + NULL); } else { - button = GTK_STOCK_SAVE; - title = "Datei speichern..."; + dialog = gtk_file_chooser_dialog_new ( + "Save File", + GTK_WINDOW(obj->widget), + action, + "Cancel", + GTK_RESPONSE_CANCEL, + "Save File", + GTK_RESPONSE_ACCEPT, + NULL); } - GtkWidget *dialog = gtk_file_chooser_dialog_new( - title, - GTK_WINDOW(obj->widget), - action, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - button, - GTK_RESPONSE_ACCEPT, - NULL); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - gtk_widget_destroy(dialog); - char *copy = strdup(file); - g_free(file); - return copy; - } else { - gtk_widget_destroy(dialog); - return NULL; + if((mode & UI_FILEDIALOG_SELECT_MULTI) == UI_FILEDIALOG_SELECT_MULTI) { + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); } + + UiEvent evt; + evt.obj = obj; + evt.document = evt.obj->ctx->document; + evt.window = evt.obj->window; + evt.intval = 0; + + UiFileList flist; + flist.files = NULL; + flist.nfiles = 0; + evt.eventdata = &flist; + + int result = gtk_dialog_run(GTK_DIALOG (dialog)); + GSList *selection = NULL; + if(result == GTK_RESPONSE_ACCEPT) { + selection = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + flist.nfiles = g_slist_length(selection); + flist.files = calloc(flist.nfiles, sizeof(char*)); + int i = 0; + while(selection) { + flist.files[i] = selection->data; + selection = selection->next; + i++; + } + } + + if(file_selected_callback) { + file_selected_callback(&evt, cbdata); + } + + for(int i=0;i<flist.nfiles;i++) { + g_free(flist.files[i]); + } + free(flist.files); + g_slist_free(selection); + + gtk_widget_destroy(dialog); } +void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) { + ui_gtkfilechooser(obj, GTK_FILE_CHOOSER_ACTION_OPEN, mode, file_selected_callback, cbdata); +} +void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) { + ui_gtkfilechooser(obj, GTK_FILE_CHOOSER_ACTION_SAVE, 0, file_selected_callback, cbdata); +} +
--- a/ui/ui/display.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/ui/display.h Sun Jun 09 15:43:08 2024 +0200 @@ -97,8 +97,8 @@ UIEXPORT UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args); UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args); -UIWIDGET ui_space(UiObject *obj); -UIWIDGET ui_separator(UiObject *obj); +UIWIDGET ui_space_deprecated(UiObject *obj); +UIWIDGET ui_separator_deprecated(UiObject *obj); /* progress bar/spinner */
--- a/ui/ui/entry.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/ui/entry.h Sun Jun 09 15:43:08 2024 +0200 @@ -35,13 +35,29 @@ extern "C" { #endif -UIWIDGET ui_spinner(UiObject *obj, int step, UiInteger *i); -UIWIDGET ui_spinnerf(UiObject *obj, double step, int digits, UiDouble *d); -UIWIDGET ui_spinnerr(UiObject *obj, UiRange *r); + +typedef struct UiSpinnerArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; -UIWIDGET ui_spinner_nv(UiObject *obj, int step, char *varname); -UIWIDGET ui_spinnerf_nv(UiObject *obj, double step, int digits, char *varname); -UIWIDGET ui_spinnerr_nv(UiObject *obj, char *varname); + double step; + int digits; + UiInteger *intvalue; + UiDouble* doublevalue; + UiRange *rangevalue; + const char* varname; + ui_callback onchange; + void* onchangedata; +} UiSpinnerArgs; + + + +UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args); + +#define ui_spinner(obj, ...) ui_spinner_create(obj, (UiSpinnerArgs){ __VA_ARGS__ } ) void ui_spinner_setrange(UIWIDGET spinner, double min, double max); void ui_spinner_setdigits(UIWIDGET spinner, int digits);
--- a/ui/ui/text.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/ui/text.h Sun Jun 09 15:43:08 2024 +0200 @@ -84,8 +84,8 @@ void* ondropsdata; } UiPathTextFieldArgs; -UIWIDGET ui_textarea(UiObject *obj, UiText *value); -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname); +UIWIDGET ui_textarea_deprecated(UiObject *obj, UiText *value); +UIWIDGET ui_textarea_nv_deprecated(UiObject *obj, char *varname); UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea);
--- a/ui/ui/toolkit.h Mon Feb 12 21:13:23 2024 +0100 +++ b/ui/ui/toolkit.h Sun Jun 09 15:43:08 2024 +0200 @@ -499,6 +499,7 @@ UIEXPORT void ui_listselection_free(UiListSelection selection); UIEXPORT UiIcon* ui_icon(const char* name, size_t size); +UIEXPORT UiIcon* ui_icon_unscaled(const char *name, int size); UIEXPORT UiIcon* ui_imageicon(const char* file); UIEXPORT void ui_icon_free(UiIcon* icon);