]> uap-core.de Git - mizunara.git/commitdiff
adjust UI code to new toolkit version
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 19 Jul 2025 19:20:29 +0000 (21:20 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 19 Jul 2025 19:20:29 +0000 (21:20 +0200)
86 files changed:
configure
make/Makefile.mk
make/cc.mk
make/clang.mk
make/configure.vm
make/gcc.mk
make/project.xml
make/suncc.mk
make/toolchain.sh
make/uwproj.xsd
mizunara/Makefile
mizunara/window.c
mizunara/window.h
ucx/Makefile
ucx/allocator.c
ucx/array_list.c
ucx/buffer.c
ucx/cx/allocator.h
ucx/cx/array_list.h
ucx/cx/buffer.h
ucx/cx/common.h
ucx/cx/hash_map.h
ucx/cx/linked_list.h
ucx/cx/list.h
ucx/cx/mempool.h
ucx/cx/printf.h
ucx/cx/properties.h
ucx/cx/string.h
ucx/cx/tree.h
ucx/json.c
ucx/linked_list.c
ucx/list.c
ucx/mempool.c
ucx/printf.c
ucx/properties.c
ucx/streams.c
ucx/string.c
ucx/tree.c
ui/Makefile
ui/common/args.c [new file with mode: 0644]
ui/common/args.h [new file with mode: 0644]
ui/common/context.c
ui/common/context.h
ui/common/document.c
ui/common/menu.c
ui/common/object.c
ui/common/object.h
ui/common/objs.mk
ui/common/threadpool.c
ui/common/toolbar.c
ui/common/types.c
ui/common/types.h
ui/common/wrapper.c [new file with mode: 0644]
ui/common/wrapper.h [new file with mode: 0644]
ui/gtk/Makefile
ui/gtk/button.c
ui/gtk/container.c
ui/gtk/container.h
ui/gtk/display.c
ui/gtk/entry.c
ui/gtk/graphics.c
ui/gtk/image.c
ui/gtk/list.c
ui/gtk/list.h
ui/gtk/menu.c
ui/gtk/range.c
ui/gtk/text.c
ui/gtk/toolbar.c
ui/gtk/toolkit.c
ui/gtk/toolkit.h
ui/gtk/webview.c
ui/gtk/widget.c
ui/gtk/window.c
ui/ui/button.h
ui/ui/container.h
ui/ui/display.h
ui/ui/entry.h
ui/ui/icons.h
ui/ui/image.h
ui/ui/menu.h
ui/ui/text.h
ui/ui/toolbar.h
ui/ui/toolkit.h
ui/ui/tree.h
ui/ui/webview.h
ui/ui/widget.h

index 3f1227fe6164333f74428c7b737de721c06eef2d..cb585611625a6811f40a96298cede2c3ce5b8288 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,40 +1,47 @@
 #!/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
-
-# features
+# some utility functions
+isplatform()
+{
+    for p in $PLATFORM
+    do
+        if [ "$p" = "$1" ]; then
+            return 0
+        fi
+    done
+    return 1
+}
+notisplatform()
+{
+    for p in $PLATFORM
+    do
+        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
+}
 
 # clean abort
 abort_configure()
@@ -43,6 +50,37 @@ abort_configure()
     exit 1
 }
 
+# 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`
+ARCH=`uname -m`
+printf "detect platform... "
+if [ "$OS" = "SunOS" ]; then
+    PLATFORM="solaris sunos unix svr4"
+elif [ "$OS" = "Linux" ]; then
+    PLATFORM="linux unix"
+elif [ "$OS" = "FreeBSD" ]; then
+    PLATFORM="freebsd bsd unix"
+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"
+elif echo "$OS" | grep -i "MINGW" > /dev/null; then
+    PLATFORM="windows mingw"
+fi
+: ${PLATFORM:="unix"}
+
+PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -`
+echo "$PLATFORM_NAME"
+
+
 # help text
 printhelp()
 {
@@ -50,7 +88,7 @@ printhelp()
     cat << __EOF__
 Installation directories:
   --prefix=PREFIX         path prefix for architecture-independent files
-                          [/usr]
+                          [$prefix]
   --exec-prefix=EPREFIX   path prefix for architecture-dependent files
                           [PREFIX]
 
@@ -69,14 +107,52 @@ Installation directories:
   --mandir=DIR            man documentation [DATAROOTDIR/man]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
 
-Options:
+Build Types:
   --debug                 add extra compile flags for debug builds
   --release               add extra compile flags for release builds
+
+Options:
   --toolkit=(libadwaita|gtk4|gtk3|gtk2|cocoa)
 
 __EOF__
 }
 
+# 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
+
+# features
+
 #
 # parse arguments
 #
@@ -99,10 +175,11 @@ do
         "--infodir="*)        infodir=${ARG#--infodir=} ;;
         "--mandir"*)          mandir=${ARG#--mandir} ;;
         "--localedir"*)       localedir=${ARG#--localedir} ;;
-        "--help"*) printhelp; abort_configure ;;
-        "--debug")           BUILD_TYPE="debug" ;;
-        "--release")         BUILD_TYPE="release" ;;
+        "--help"*)            printhelp; abort_configure ;;
+        "--debug")            BUILD_TYPE="debug" ;;
+        "--release")          BUILD_TYPE="release" ;;
         "--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;;
+        "--toolkit")  echo "option '$ARG' needs a value:"; echo "  $ARG=(libadwaita|gtk4|gtk3|gtk2|cocoa)"; abort_configure ;;
         "-"*) echo "unknown option: $ARG"; abort_configure ;;
     esac
 done
@@ -126,6 +203,22 @@ done
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
+# remember the above values and compare them later
+orig_bindir="$bindir"
+orig_sbindir="$sbindir"
+orig_libdir="$libdir"
+orig_libexecdir="$libexecdir"
+orig_datarootdir="$datarootdir"
+orig_datadir="$datadir"
+orig_sysconfdir="$sysconfdir"
+orig_sharedstatedir="$sharedstatedir"
+orig_localstatedir="$localstatedir"
+orig_runstatedir="$runstatedir"
+orig_includedir="$includedir"
+orig_infodir="$infodir"
+orig_mandir="$mandir"
+orig_localedir="$localedir"
+
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -142,77 +235,29 @@ elif [ -f "$prefix/etc/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/etc/config.site"
     echo ok
-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
-    PLATFORM="solaris sunos unix svr4"
-elif [ "$OS" = "Linux" ]; then
-    PLATFORM="linux unix"
-elif [ "$OS" = "FreeBSD" ]; then
-    PLATFORM="freebsd bsd unix"
-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"
-elif echo "$OS" | grep -i "MINGW" > /dev/null; then
-    PLATFORM="windows mingw"
-fi
-: ${PLATFORM:="unix"}
-
-PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -`
-echo "$PLATFORM_NAME"
-
-isplatform()
-{
-    for p in $PLATFORM
-    do
-        if [ "$p" = "$1" ]; then
-            return 0
-        fi
-    done
-    return 1
-}
-notisplatform()
-{
-    for p in $PLATFORM
-    do
-        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
+else
+    # try to detect the correct libdir on our own, except it was changed by the user
+    if test "$libdir" = '${exec_prefix}/lib'; then
+        if [ "$OS" = "SunOS" ]; then
+            test -d "${exec_prefix}/lib/amd64" && libdir='${exec_prefix}/lib/amd64'
+        else
+            # check if the standard libdir even exists
+            if test -d "${exec_prefix}/lib" ; then
+                :
+            else
+                # if it does not, maybe a lib32 exists
+                test -d "${exec_prefix}/lib32" && libdir='${exec_prefix}/lib32'
+            fi
+            # now check if there is a special 64bit libdir that we should use
+            for i in x86_64 ppc64 s390x aarch64 aarch64_be arm64 ; do
+                if [ $ARCH = $i ]; then
+                    test -d "${exec_prefix}/lib64" && libdir='${exec_prefix}/lib64'
+                    break
+                fi
+            done
         fi
-    done
-    return 0
-}
+    fi
+fi
 
 
 # generate vars.mk
@@ -649,9 +694,9 @@ echo > "$TEMP_DIR/flags.mk"
 DEPENDENCIES_FAILED=
 ERROR=0
 # unnamed dependencies
-TEMP_CFLAGS=
-TEMP_CXXFLAGS=
-TEMP_LDFLAGS=
+TEMP_CFLAGS="$CFLAGS"
+TEMP_CXXFLAGS="$CXXFLAGS"
+TEMP_LDFLAGS="$LDFLAGS"
 while true
 do
     while true
@@ -676,6 +721,7 @@ do
         cat >> "$TEMP_DIR/make.mk" << __EOF__
 OBJ_EXT = .o
 LIB_EXT = .a
+SHLIB_EXT = .dylib
 LIB_PREFIX = lib
 PACKAGE_SCRIPT = package_osx.sh
 __EOF__
@@ -697,6 +743,7 @@ do
         cat >> "$TEMP_DIR/make.mk" << __EOF__
 OBJ_EXT = .o
 LIB_EXT = .a
+SHLIB_EXT = .so
 LIB_PREFIX = lib
 PACKAGE_SCRIPT = package_unix.sh
 __EOF__
@@ -705,6 +752,19 @@ __EOF__
     break
 done
 while true
+do
+    while true
+    do
+
+        cat >> "$TEMP_DIR/make.mk" << __EOF__
+BUILD_BIN_DIR = bin
+BUILD_LIB_DIR = lib
+__EOF__
+        break
+    done
+    break
+done
+while true
 do
     if notisplatform "bsd"; then
         break
@@ -719,6 +779,16 @@ do
     break
 done
 
+# build type
+if [ "$BUILD_TYPE" = "debug" ]; then
+    TEMP_CFLAGS="\${DEBUG_CFLAGS} $TEMP_CFLAGS"
+    TEMP_CXXFLAGS="\${DEBUG_CXXFLAGS} $TEMP_CXXFLAGS"
+fi
+if [ "$BUILD_TYPE" = "release" ]; then
+    TEMP_CFLAGS="\${RELEASE_CFLAGS} $TEMP_CFLAGS"
+    TEMP_CXXFLAGS="\${RELEASE_CXXFLAGS} $TEMP_CXXFLAGS"
+fi
+
 # add general dependency flags to flags.mk
 echo "# general flags" >> "$TEMP_DIR/flags.mk"
 if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then
@@ -842,22 +912,6 @@ 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
@@ -969,6 +1023,11 @@ else
             ERROR=1
             DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
         fi
+    else
+        echo
+        echo "Invalid option value - usage:"
+        echo "  --toolkit=(libadwaita|gtk4|gtk3|gtk2|cocoa)"
+        abort_configure
     fi
 fi
 
@@ -978,22 +1037,6 @@ fi
 if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
     echo "TK_CXXFLAGS  += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
 fi
-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 [ "$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
@@ -1009,20 +1052,81 @@ fi
 
 echo "configure finished"
 echo
+echo "Toolchain"
+echo "  name:           $TOOLCHAIN_NAME"
+if [ -n "$TOOLCHAIN_CC" ]; then
+    echo "  cc:             $TOOLCHAIN_CC"
+fi
+if [ -n "$TOOLCHAIN_CXX" ]; then
+    echo "  cxx:            $TOOLCHAIN_CXX"
+fi
+if [ -n "$TOOLCHAIN_WSIZE" ]; then
+    echo "  word size:      $TOOLCHAIN_WSIZE bit"
+fi
+if [ -n "$TOOLCHAIN_CSTD" ]; then
+    echo "  default C std:  $TOOLCHAIN_CSTD"
+fi
+echo
 echo "Build Config:"
-echo "  PREFIX:      $prefix"
-echo "  TOOLCHAIN:   $TOOLCHAIN_NAME"
+echo "  prefix:         $prefix"
+echo "  exec_prefix:    $exec_prefix"
+if [ "$orig_bindir" != "$bindir" ]; then
+    echo "  bindir:      $bindir"
+fi
+if [ "$orig_sbindir" != "$sbindir" ]; then
+    echo "  sbindir:     $sbindir"
+fi
+if [ "$orig_libdir" != "$libdir" ]; then
+    echo "  libdir:         $libdir"
+fi
+if [ "$orig_libexecdir" != "$libexecdir" ]; then
+    echo "  libexecdir:     $libexecdir"
+fi
+if [ "$orig_datarootdir" != "$datarootdir" ]; then
+    echo "  datarootdir:    $datarootdir"
+fi
+if [ "$orig_datadir" != "$datadir" ]; then
+    echo "  datadir:        $datadir"
+fi
+if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
+    echo "  sysconfdir:     $sysconfdir"
+fi
+if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
+    echo "  sharedstatedir: $sharedstatedir"
+fi
+if [ "$orig_localstatedir" != "$localstatedir" ]; then
+    echo "  localstatedir:  $localstatedir"
+fi
+if [ "$orig_runstatedir" != "$runstatedir" ]; then
+    echo "  runstatedir:    $runstatedir"
+fi
+if [ "$orig_includedir" != "$includedir" ]; then
+    echo "  includedir:     $includedir"
+fi
+if [ "$orig_infodir" != "$infodir" ]; then
+    echo "  infodir:        $infodir"
+fi
+if [ "$orig_mandir" != "$mandir" ]; then
+    echo "  mandir:         $mandir"
+fi
+if [ "$orig_localedir" != "$localedir" ]; then
+    echo "  localedir:      $localedir"
+fi
+echo
 echo "Options:"
 cat "$TEMP_DIR/options"
 echo
 
 # generate the config.mk file
+pwd=`pwd`
 cat > "$TEMP_DIR/config.mk" << __EOF__
 #
-# config.mk generated by configure
+# config.mk generated by:
+# pwd: $pwd
+# $0 $@
 #
 
 __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
+cat "$TEMP_DIR/config.mk" "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
 rm -Rf "$TEMP_DIR"
index 11b8e739fcd843f401ae69ce566212414c142198..d791cbf86808e927d64a50164bbb7b340c140a78 100644 (file)
@@ -32,6 +32,7 @@ BUILD_ROOT = ./
 include config.mk
 
 BUILD_DIRS = build/bin build/lib
+BUILD_DIRS += build/ucx
 BUILD_DIRS += build/libidav
 BUILD_DIRS += build/mizunara
 BUILD_DIRS += build/mizucp
index 149bde6d72caeaecdb85a415d05d9d97779fa8f5..72e31558b1188ac6a5f927493c820ab85f2ecbc5 100644 (file)
@@ -4,11 +4,11 @@
 
 CFLAGS =
 CXXFLAGS =
-DEBUG_CC_FLAGS = -g
-DEBUG_CXX_FLAGS = -g
-RELEASE_CC_FLAGS = -O3 -DNDEBUG
-RELEASE_CXX_FLAGS = -O3 -DNDEBUG
+DEBUG_CFLAGS = -g
+DEBUG_CXXFLAGS = -g
+RELEASE_CFLAGS = -O3 -DNDEBUG
+RELEASE_CXXFLAGS = -O3 -DNDEBUG
 LDFLAGS =
 
 SHLIB_CFLAGS = -fPIC
-SHLIB_LDFLAGS = -shared
\ No newline at end of file
+SHLIB_LDFLAGS = -shared
index 772ebb71b64fc76774ec894e2108354b9c62900e..fb1844307a98e9d5a776130419e69cfde4e67d47 100644 (file)
@@ -4,10 +4,10 @@
 
 CFLAGS =
 CXXFLAGS =
-DEBUG_CC_FLAGS = -g
-DEBUG_CXX_FLAGS = -g
-RELEASE_CC_FLAGS = -O3 -DNDEBUG
-RELEASE_CXX_FLAGS = -O3 -DNDEBUG
+DEBUG_CFLAGS = -g
+DEBUG_CXXFLAGS = -g
+RELEASE_CFLAGS = -O3 -DNDEBUG
+RELEASE_CXXFLAGS = -O3 -DNDEBUG
 LDFLAGS =
 
 SHLIB_CFLAGS = -fPIC
index b8acad321d3f91e4afddfd72ac4d059137bd22b6..7be6ed7e4be8822c8c0999613c6fb32e4a11c82f 100644 (file)
@@ -1,52 +1,48 @@
 #!/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.varName}=`${var.value}`
-#else
-${var.varName}="${var.value}"
-#end
-#end
-
-# features
-#foreach( $feature in $features )
-#if( ${feature.auto} )
-${feature.varName}=auto
-#end
-#end
+#set( $D = '$' )
+#[[
+# some utility functions
+isplatform()
+{
+    for p in $PLATFORM
+    do
+        if [ "$p" = "$1" ]; then
+            return 0
+        fi
+    done
+    return 1
+}
+notisplatform()
+{
+    for p in $PLATFORM
+    do
+        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
+}
 
 # clean abort
 abort_configure()
@@ -55,6 +51,37 @@ abort_configure()
     exit 1
 }
 
+# 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`
+ARCH=`uname -m`
+printf "detect platform... "
+if [ "$OS" = "SunOS" ]; then
+    PLATFORM="solaris sunos unix svr4"
+elif [ "$OS" = "Linux" ]; then
+    PLATFORM="linux unix"
+elif [ "$OS" = "FreeBSD" ]; then
+    PLATFORM="freebsd bsd unix"
+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"
+elif echo "$OS" | grep -i "MINGW" > /dev/null; then
+    PLATFORM="windows mingw"
+fi
+: ${PLATFORM:="unix"}
+
+PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -`
+echo "$PLATFORM_NAME"
+]]#
+
 # help text
 printhelp()
 {
@@ -62,7 +89,7 @@ printhelp()
     cat << __EOF__
 Installation directories:
   --prefix=PREFIX         path prefix for architecture-independent files
-                          [/usr]
+                          [${D}prefix]
   --exec-prefix=EPREFIX   path prefix for architecture-dependent files
                           [PREFIX]
 
@@ -81,30 +108,90 @@ Installation directories:
   --mandir=DIR            man documentation [DATAROOTDIR/man]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
 
-#if( $options.size() > 0 )
-Options:
+Build Types:
   --debug                 add extra compile flags for debug builds
   --release               add extra compile flags for release builds
+#if( $options.size() > 0 )
+
+Options:
 #foreach( $opt in $options )
   --${opt.argument}=${opt.valuesString}
 #end
-
 #end
 #if( $features.size() > 0 )
+
 Optional Features:
 #foreach( $feature in $features )
 ${feature.helpText}
 #end
-
 #end
+
 __EOF__
 }
 
+# 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( $cfg in $config )
+if true \
+#if( $cfg.platform )
+    && isplatform "${cfg.platform}" \
+#end
+#foreach( $np in $cfg.notList )
+      && notisplatform "${np}" \
+#end
+      ; then
+    #foreach( $var in $cfg.vars )
+    #if( $var.exec )
+    ${var.varName}=`${var.value}`
+    #else
+    ${var.varName}="${var.value}"
+    #end
+    #end
+fi
+#end
+
+# features
+#foreach( $feature in $features )
+#if( ${feature.auto} )
+${feature.varName}=auto
+#end
+#end
+
 #
 # parse arguments
 #
 BUILD_TYPE="default"
-#set( $D = '$' )
 for ARG in "$@"
 do
     case "$ARG" in
@@ -123,11 +210,12 @@ do
         "--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" ;;
+        "--help"*)            printhelp; abort_configure ;;
+        "--debug")            BUILD_TYPE="debug" ;;
+        "--release")          BUILD_TYPE="release" ;;
     #foreach( $opt in $options )
         "--${opt.argument}="*) ${opt.varName}=${D}{ARG#--${opt.argument}=} ;;
+        "--${opt.argument}")  echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
     #end
     #foreach( $feature in $features )
         "--enable-${feature.arg}") ${feature.varName}=on ;;
@@ -157,6 +245,22 @@ done
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
+# remember the above values and compare them later
+orig_bindir="$bindir"
+orig_sbindir="$sbindir"
+orig_libdir="$libdir"
+orig_libexecdir="$libexecdir"
+orig_datarootdir="$datarootdir"
+orig_datadir="$datadir"
+orig_sysconfdir="$sysconfdir"
+orig_sharedstatedir="$sharedstatedir"
+orig_localstatedir="$localstatedir"
+orig_runstatedir="$runstatedir"
+orig_includedir="$includedir"
+orig_infodir="$infodir"
+orig_mandir="$mandir"
+orig_localedir="$localedir"
+
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -173,77 +277,29 @@ elif [ -f "$prefix/etc/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/etc/config.site"
     echo ok
-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
-    PLATFORM="solaris sunos unix svr4"
-elif [ "$OS" = "Linux" ]; then
-    PLATFORM="linux unix"
-elif [ "$OS" = "FreeBSD" ]; then
-    PLATFORM="freebsd bsd unix"
-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"
-elif echo "$OS" | grep -i "MINGW" > /dev/null; then
-    PLATFORM="windows mingw"
-fi
-: ${PLATFORM:="unix"}
-
-PLATFORM_NAME=`echo "$PLATFORM" | cut -f1 -d' ' -`
-echo "$PLATFORM_NAME"
-
-isplatform()
-{
-    for p in $PLATFORM
-    do
-        if [ "$p" = "$1" ]; then
-            return 0
-        fi
-    done
-    return 1
-}
-notisplatform()
-{
-    for p in $PLATFORM
-    do
-        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
+else
+    # try to detect the correct libdir on our own, except it was changed by the user
+    if test "$libdir" = '${exec_prefix}/lib'; then
+        if [ "$OS" = "SunOS" ]; then
+            test -d "${exec_prefix}/lib/amd64" && libdir='${exec_prefix}/lib/amd64'
+        else
+            # check if the standard libdir even exists
+            if test -d "${exec_prefix}/lib" ; then
+                :
+            else
+                # if it does not, maybe a lib32 exists
+                test -d "${exec_prefix}/lib32" && libdir='${exec_prefix}/lib32'
+            fi
+            # now check if there is a special 64bit libdir that we should use
+            for i in x86_64 ppc64 s390x aarch64 aarch64_be arm64 ; do
+                if [ $ARCH = $i ]; then
+                    test -d "${exec_prefix}/lib64" && libdir='${exec_prefix}/lib64'
+                    break
+                fi
+            done
         fi
-    done
-    return 0
-}
+    fi
+fi
 ]]#
 ## End of unparsed content **
 
@@ -394,9 +450,9 @@ DEPENDENCIES_FAILED=
 ERROR=0
 #if( $dependencies.size() > 0 )
 # unnamed dependencies
-TEMP_CFLAGS=
-TEMP_CXXFLAGS=
-TEMP_LDFLAGS=
+TEMP_CFLAGS="$CFLAGS"
+TEMP_CXXFLAGS="$CXXFLAGS"
+TEMP_LDFLAGS="$LDFLAGS"
 #foreach( $dependency in $dependencies )
 while true
 do
@@ -468,6 +524,16 @@ __EOF__
 done
 #end
 
+# build type
+if [ "$BUILD_TYPE" = "debug" ]; then
+    TEMP_CFLAGS="\${DEBUG_CFLAGS} $TEMP_CFLAGS"
+    TEMP_CXXFLAGS="\${DEBUG_CXXFLAGS} $TEMP_CXXFLAGS"
+fi
+if [ "$BUILD_TYPE" = "release" ]; then
+    TEMP_CFLAGS="\${RELEASE_CFLAGS} $TEMP_CFLAGS"
+    TEMP_CXXFLAGS="\${RELEASE_CXXFLAGS} $TEMP_CXXFLAGS"
+fi
+
 # add general dependency flags to flags.mk
 echo "# general flags" >> "$TEMP_DIR/flags.mk"
 if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then
@@ -554,6 +620,35 @@ if [ -n "${D}${feature.varName}" ]; then
         unset ${feature.varName}
     fi
 fi
+if [ -n "${D}${feature.varName}" ]; then
+    :
+#foreach( $def in $feature.defines )
+    TEMP_CFLAGS="$TEMP_CFLAGS ${def.toFlags()}"
+    TEMP_CXXFLAGS="$TEMP_CXXFLAGS ${def.toFlags()}"
+#end
+#if( $feature.hasMake() )
+    cat >> "$TEMP_DIR/make.mk" << __EOF__
+$feature.make
+__EOF__
+#end
+else
+    :
+#foreach( $def in $feature.disabled.defines )
+    TEMP_CFLAGS="$TEMP_CFLAGS ${def.toFlags()}"
+    TEMP_CXXFLAGS="$TEMP_CXXFLAGS ${def.toFlags()}"
+#end
+#if( $feature.disabled.hasMake() )
+    cat >> "$TEMP_DIR/make.mk" << __EOF__
+$feature.disabled.make
+__EOF__
+#end
+#foreach( $dependency in $feature.disabled.dependencies )
+    if dependency_error_$dependency ; then
+        DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED ${dependency} "
+        ERROR=1
+    fi
+#end
+fi
 #end
 
 #foreach( $opt in $target.options )
@@ -600,6 +695,11 @@ else
             DEPENDENCIES_FAILED="option '${opt.argument}' $DEPENDENCIES_FAILED"
         fi
     #end
+    else
+        echo
+        echo "Invalid option value - usage:"
+        echo "  --${opt.argument}=${opt.valuesString}"
+        abort_configure
     fi
 fi
 #end
@@ -610,22 +710,6 @@ fi
 if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
     echo "${target.cxxFlags}  += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
 fi
-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 [ "$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
@@ -642,14 +726,73 @@ fi
 
 echo "configure finished"
 echo
+echo "Toolchain"
+echo "  name:           $TOOLCHAIN_NAME"
+if [ -n "$TOOLCHAIN_CC" ]; then
+    echo "  cc:             $TOOLCHAIN_CC"
+fi
+if [ -n "$TOOLCHAIN_CXX" ]; then
+    echo "  cxx:            $TOOLCHAIN_CXX"
+fi
+if [ -n "$TOOLCHAIN_WSIZE" ]; then
+    echo "  word size:      $TOOLCHAIN_WSIZE bit"
+fi
+if [ -n "$TOOLCHAIN_CSTD" ]; then
+    echo "  default C std:  $TOOLCHAIN_CSTD"
+fi
+echo
 echo "Build Config:"
-echo "  PREFIX:      $prefix"
-echo "  TOOLCHAIN:   $TOOLCHAIN_NAME"
+echo "  prefix:         $prefix"
+echo "  exec_prefix:    $exec_prefix"
+if [ "$orig_bindir" != "$bindir" ]; then
+    echo "  bindir:      $bindir"
+fi
+if [ "$orig_sbindir" != "$sbindir" ]; then
+    echo "  sbindir:     $sbindir"
+fi
+if [ "$orig_libdir" != "$libdir" ]; then
+    echo "  libdir:         $libdir"
+fi
+if [ "$orig_libexecdir" != "$libexecdir" ]; then
+    echo "  libexecdir:     $libexecdir"
+fi
+if [ "$orig_datarootdir" != "$datarootdir" ]; then
+    echo "  datarootdir:    $datarootdir"
+fi
+if [ "$orig_datadir" != "$datadir" ]; then
+    echo "  datadir:        $datadir"
+fi
+if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
+    echo "  sysconfdir:     $sysconfdir"
+fi
+if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
+    echo "  sharedstatedir: $sharedstatedir"
+fi
+if [ "$orig_localstatedir" != "$localstatedir" ]; then
+    echo "  localstatedir:  $localstatedir"
+fi
+if [ "$orig_runstatedir" != "$runstatedir" ]; then
+    echo "  runstatedir:    $runstatedir"
+fi
+if [ "$orig_includedir" != "$includedir" ]; then
+    echo "  includedir:     $includedir"
+fi
+if [ "$orig_infodir" != "$infodir" ]; then
+    echo "  infodir:        $infodir"
+fi
+if [ "$orig_mandir" != "$mandir" ]; then
+    echo "  mandir:         $mandir"
+fi
+if [ "$orig_localedir" != "$localedir" ]; then
+    echo "  localedir:      $localedir"
+fi
 #if ( $options.size() > 0 )
+echo
 echo "Options:"
 cat "$TEMP_DIR/options"
 #end
 #if ( $features.size() > 0 )
+echo
 echo "Features:"
 #foreach( $feature in $features )
 if [ -n "${D}${feature.varName}" ]; then
@@ -662,12 +805,15 @@ fi
 echo
 
 # generate the config.mk file
+pwd=`pwd`
 cat > "$TEMP_DIR/config.mk" << __EOF__
 #
-# config.mk generated by configure
+# config.mk generated by:
+# pwd: $pwd
+# $0 $@
 #
 
 __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
+cat "$TEMP_DIR/config.mk" "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
 rm -Rf "$TEMP_DIR"
index 5eea8e162451dfa9123b8fe4ca13bbf313ed672f..e2f294039b5e35c1797de454190fff16df464559 100644 (file)
@@ -4,10 +4,10 @@
 
 CFLAGS =
 CXXFLAGS =
-DEBUG_CC_FLAGS = -g
-DEBUG_CXX_FLAGS = -g
-RELEASE_CC_FLAGS = -O3 -DNDEBUG
-RELEASE_CXX_FLAGS = -O3 -DNDEBUG
+DEBUG_CFLAGS = -g
+DEBUG_CXXFLAGS = -g
+RELEASE_CFLAGS = -O3 -DNDEBUG
+RELEASE_CXXFLAGS = -O3 -DNDEBUG
 LDFLAGS =
 
 SHLIB_CFLAGS = -fPIC
index b2553d3a798c361077da0cd9eb8a1557c02d2381..332310a9ddf898cbf1b8b66b8a74d07c8631fa71 100644 (file)
        <dependency platform="macos">
                <make>OBJ_EXT = .o</make>
                <make>LIB_EXT = .a</make>
+               <make>SHLIB_EXT = .dylib</make>
                <make>LIB_PREFIX = lib</make>
                <make>PACKAGE_SCRIPT = package_osx.sh</make>
        </dependency>
        <dependency platform="unix" not="macos">
                <make>OBJ_EXT = .o</make>
                <make>LIB_EXT = .a</make>
+               <make>SHLIB_EXT = .so</make>
                <make>LIB_PREFIX = lib</make>
                <make>PACKAGE_SCRIPT = package_unix.sh</make>
        </dependency>
+       <dependency>
+               <make>BUILD_BIN_DIR = bin</make>
+               <make>BUILD_LIB_DIR = lib</make>
+       </dependency>
        
        <dependency platform="bsd">
                <cflags>-I/usr/local/include</cflags>
index 38cbb87195a845b1ba90867e69f10ec2443567a6..8b941d2b5e3798939ac70189218e60971a77914c 100644 (file)
@@ -4,10 +4,10 @@
 
 CFLAGS =
 CXXFLAGS =
-DEBUG_CC_FLAGS = -g
-DEBUG_CXX_FLAGS = -g
-RELEASE_CC_FLAGS = -O3 -DNDEBUG
-RELEASE_CXX_FLAGS = -O3 -DNDEBUG
+DEBUG_CFLAGS = -g
+DEBUG_CXXFLAGS = -g
+RELEASE_CFLAGS = -O3 -DNDEBUG
+RELEASE_CXXFLAGS = -O3 -DNDEBUG
 LDFLAGS =
 
 SHLIB_CFLAGS = -Kpic
index ac5fb6808b981a74035cc20686ab2866a559692b..e68fcc76bf8c95b7bc6d538b4efb9d42e18e5b0b 100644 (file)
@@ -17,20 +17,28 @@ unset TOOLCHAIN_CXX
 
 check_c_compiler()
 {
+  command -v $1 2>&1 >/dev/null
+  if [ $? -ne 0 ]; then
+    return 1
+  fi
   cat > "$TEMP_DIR/test.c" << __EOF__
 /* test file */
 #include <stdio.h>
 int main(int argc, char **argv) {
 #if defined(_MSC_VER)
-  printf("msc\n");
+  printf("toolchain:msc\n");
 #elif defined(__clang__)
-  printf("clang gnuc\n");
+  printf("toolchain:clang gnuc\n");
 #elif defined(__GNUC__)
-  printf("gcc gnuc\n");
+  printf("toolchain:gcc gnuc\n");
 #elif defined(__sun)
-  printf("suncc\n");
+  printf("toolchain:suncc\n");
 #else
-  printf("unknown\n");
+  printf("toolchain:unknown\n");
+#endif
+  printf("wsize:%d\n", (int)sizeof(void*)*8);
+#ifdef __STDC_VERSION__
+  printf("stdcversion:%d\n", __STDC_VERSION__);
 #endif
   return 0;
 }
@@ -41,21 +49,26 @@ __EOF__
 
 check_cpp_compiler()
 {
+  command -v $1 2>&1 >/dev/null
+  if [ $? -ne 0 ]; then
+    return 1
+  fi
   cat > "$TEMP_DIR/test.cpp" << __EOF__
 /* test file */
 #include <iostream>
 int main(int argc, char **argv) {
 #if defined(_MSC_VER)
-  std::cout << "msc" << std::endl;
+  std::cout << "toolchain:msc" << std::endl;
 #elif defined(__clang__)
-  std::cout << "clang gnuc" << std::endl;
+  std::cout << "toolchain:clang gnuc" << std::endl;
 #elif defined(__GNUC__)
-  std::cout << "gcc gnuc" << std::endl;
+  std::cout << "toolchain:gcc gnuc" << std::endl;
 #elif defined(__sun)
-  std::cout << "suncc" << std::endl;
+  std::cout << "toolchain:suncc" << std::endl;
 #else
-  std::cout << "cc" << std::endl;
+  std::cout << "toolchain:unknown" << std::endl;
 #endif
+  std::cout << "wsize:" << sizeof(void*)*8 << std::endl;
   return 0;
 }
 __EOF__
@@ -113,6 +126,14 @@ check_lib()
   fi
 }
 
+parse_toolchain_properties()
+{
+  info_file="$1"
+  TOOLCHAIN=`grep '^toolchain:' "$info_file" | tail -c +11`
+  TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+  TOOLCHAIN_WSIZE=`grep '^wsize:' "$info_file" | tail -c +7`
+}
+
 detect_c_compiler()
 {
   if [ -n "$TOOLCHAIN_CC" ]; then
@@ -122,8 +143,9 @@ 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' ' -`
+      "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+      parse_toolchain_properties "$TEMP_DIR/checkcc_out"
+      TOOLCHAIN_CSTD=`grep '^stdcversion:' "$TEMP_DIR/checkcc_out" | tail -c +13`
       echo "$CC"
       return 0
     else
@@ -135,8 +157,9 @@ detect_c_compiler()
     do
       if check_c_compiler "$COMP"; then
         TOOLCHAIN_CC=$COMP
-        TOOLCHAIN=`"$TEMP_DIR/checkcc"`
-        TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+        "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+        parse_toolchain_properties "$TEMP_DIR/checkcc_out"
+        TOOLCHAIN_CSTD=`grep '^stdcversion:' "$TEMP_DIR/checkcc_out" | tail -c +13`
         echo "$COMP"
         return 0
       fi
@@ -156,8 +179,8 @@ detect_cpp_compiler()
   if [ -n "$CXX" ]; then
     if check_cpp_compiler "$CXX"; then
       TOOLCHAIN_CXX=$CXX
-      TOOLCHAIN=`"$TEMP_DIR/checkcc"`
-      TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+      "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+      parse_toolchain_properties "$TEMP_DIR/checkcc_out"
       echo "$CXX"
       return 0
     else
@@ -169,8 +192,8 @@ detect_cpp_compiler()
     do
       if check_cpp_compiler "$COMP"; then
         TOOLCHAIN_CXX=$COMP
-        TOOLCHAIN=`"$TEMP_DIR/checkcc"`
-        TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+        "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+        parse_toolchain_properties "$TEMP_DIR/checkcc_out"
         echo "$COMP"
         return 0
       fi
index f702701ae1b22228a1b986053c5271d51ac0bb1a..a62ddb2bc08139264d936d9bc090f6a82da42430 100644 (file)
@@ -3,7 +3,7 @@
            xmlns="http://unixwork.de/uwproj"
            targetNamespace="http://unixwork.de/uwproj"
            elementFormDefault="qualified"
-           version="0.2"
+           version="0.3"
 >
     <xs:element name="project" type="ProjectType"/>
 
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
-            <xs:element name="config" type="ConfigType" minOccurs="0"/>
+            <xs:element name="config" type="ConfigType" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="dependency" type="DependencyType" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="target" type="TargetType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
+        <xs:attribute name="version" type="xs:string" use="required" />
     </xs:complexType>
 
     <xs:complexType name="ConfigType">
         <xs:annotation>
             <xs:documentation>
-                The configuration section.
-                Consists of an arbitrary number of <code>var</code> elements.
+                <p>
+                    The configuration section.
+                    Consists of an arbitrary number of <code>var</code> elements.
+                </p>
+                <p>
+                    The optional <code>platform</code> attribute may specify a <em>single</em> platform identifier and
+                    the optional <code>not</code> attribute may specify a comma-separated list of platform identifiers.
+                    The configure script shall skip this config declaration if the detected platform is not matching
+                    the filter specification of these attributes.
+                </p>
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
             <xs:element name="var" type="ConfigVarType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
+        <xs:attribute name="platform" type="xs:string"/>
+        <xs:attribute name="not" type="xs:string"/>
     </xs:complexType>
 
     <xs:complexType name="ConfigVarType">
                 <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.
+                If a feature is disabled, an optional <code>disabled</code> element may specify which
+                <code>define</code> and <code>make</code> definitions are supposed to be applied.
+                There might also be <code>dependencies</code> when the feature is disabled (e.g. specifying a fallback).
                 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
         </xs:annotation>
         <xs:choice minOccurs="0" maxOccurs="unbounded">
             <xs:group ref="TargetDataGroup"/>
+            <xs:element name="desc" type="xs:string"/>
+            <xs:element name="disabled">
+                <xs:complexType>
+                    <xs:choice minOccurs="0" maxOccurs="unbounded">
+                        <xs:group ref="TargetDataGroup"/>
+                    </xs:choice>
+                </xs:complexType>
+            </xs:element>
         </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">
index 1445ec887abf0602db872e493879b04b90c8b7e3..4fb25c147d4cbd32472a856dc85b833d9b91795a 100644 (file)
@@ -46,8 +46,8 @@ OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/mizunara/%.$(OBJ_EXT))
 
 all: $(BUILD_ROOT)/build/bin/mizunara
 
-$(BUILD_ROOT)/build/bin/mizunara: $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a
-       $(CC) -o $(BUILD_ROOT)/build/bin/mizunara$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lidav -lucx $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS)
+$(BUILD_ROOT)/build/bin/mizunara: $(OBJ) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
+       $(CC) -o $(BUILD_ROOT)/build/bin/mizunara$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libucx.a $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libuitk.a
 
 $(BUILD_ROOT)/build/mizunara/%.$(OBJ_EXT): %.c
        $(CC) $(CFLAGS) $(TK_CFLAGS) -o $@ -c $<
index 6d996ccb83096314377f8cf58abf8a837c46a725..e0045833abe5cf94329cc3e657b0a356461739ed 100644 (file)
@@ -81,13 +81,18 @@ UiObject* window_create(const char *url) {
                 { .value = wdata->default_dirs, .userdata = window_sidebar_user_dirs_item },
                 { .value = wdata->user_dirs, .userdata = window_sidebar_user_dirs_item, .separator = TRUE }
         };
-        ui_sourcelist(obj, .sublists = sublists, .numsublists = 2, .getvalue = window_sidebar_getvalue, .onactivate = action_sourcelist_activate);
+        ui_sourcelist(obj,
+                .sublists = sublists,
+                .numsublists = 2,
+                .getvalue = window_sidebar_getvalue,
+                .onactivate = action_sourcelist_activate,
+                .fill = TRUE);
     }
     
-    ui_hbox(obj, .spacing = 4, .fill = UI_OFF) {
+    ui_hbox(obj, .spacing = 4) {
         ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_BACK);
         ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_FORWARD);
-        ui_path_textfield(obj, .varname = "path", .fill = UI_ON, .onactivate = action_pathbar_activate);
+        ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
     }
     
     window_create_browser_view(obj, wdata);
@@ -115,7 +120,7 @@ static void open_files(FileInfo **files, size_t numfiles, void *userdata) {
 }
 
 #ifdef GTK_MAJOR_VERSION
-static UIWIDGET create_filesview(UiObject *obj, UiWidgetArgs args, void *userdata) {
+static UIWIDGET create_filesview(UiObject *obj, UiWidgetArgs *args, void *userdata) {
     MainWindow *win = userdata;
     MzFilesView *view = mz_files_view_new();
     view->open = open_files;
@@ -129,9 +134,9 @@ static UIWIDGET create_filesview(UiObject *obj, UiWidgetArgs args, void *userdat
 #endif
 
 void window_create_browser_view(UiObject *obj, MainWindow *win) {
-    ui_tabview(obj, .tabview = UI_TABVIEW_INVISIBLE, .varname = "view") {
+    ui_tabview(obj, .tabview = UI_TABVIEW_INVISIBLE, .varname = "view", .fill = TRUE) {
         ui_tab(obj, "iconview") {
-            ui_customwidget(obj, create_filesview, win, .fill = UI_ON);
+            ui_customwidget(obj, create_filesview, win, .fill = TRUE);
         }
         
         ui_tab(obj, "listview") {
@@ -153,12 +158,12 @@ void windowdata_init(UiContext *ctx, MainWindow *win) {
  * 
  * sublist_userdata: sublist identifier (sidebar_list_default_dirs, sidebar_list_user_dirs)
  */
-void window_sidebar_getvalue(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item) {
+void window_sidebar_getvalue(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata) {
     ui_sublist_getvalue_func getvalue = sublist_userdata;
-    getvalue(NULL, rowdata, index, item);
+    getvalue(list ,NULL, rowdata, index, item, userdata);
 }
 
-void window_sidebar_user_dirs_item(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item) {
+void window_sidebar_user_dirs_item(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata) {
     MZBookmark *bookmark = rowdata;
     item->icon = strdup(bookmark->icon);
     item->label = strdup(bookmark->name);
index 3df92201703d7375fc2e09a27f5e7748f86773a9..e3579c5f5ef3f8f6f012cd0370a1cedc7f78cf3e 100644 (file)
@@ -41,9 +41,9 @@ void window_create_browser_view(UiObject *obj, MainWindow *win);
 
 void windowdata_init(UiContext *ctx, MainWindow *win);
 
-void window_sidebar_getvalue(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item);
+void window_sidebar_getvalue(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
 
-void window_sidebar_user_dirs_item(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item);
+void window_sidebar_user_dirs_item(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
 
 void action_pathbar_activate(UiEvent *event, void *userdata);
 
index e24476e18c22591b3e37144f9527bca85c667c54..1005259ccf35597f830ac529b9091915b48e1c7b 100644 (file)
@@ -49,16 +49,20 @@ SRC += json.c
 
 OBJ   = $(SRC:%.c=../build/ucx/%$(OBJ_EXT))
 
-UCX_LIB = ../build/lib/libucx$(LIB_EXT)
+UCX_LIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(LIB_EXT)
+UCX_SHLIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(SHLIB_EXT)
 
-all: ../build/ucx $(UCX_LIB)
+all: $(UCX_LIB) $(UCX_SHLIB)
 
 $(UCX_LIB): $(OBJ)
-       $(AR) $(ARFLAGS) $(UCX_LIB) $(OBJ)
+       $(AR) $(ARFLAGS) $@ $(OBJ)
+
+$(UCX_SHLIB): $(OBJ)
+       $(CC) -o $@ $(LDFLAGS) $(SHLIB_LDFLAGS) $(OBJ)
 
 ../build/ucx:
        mkdir -p ../build/ucx
 
 ../build/ucx/%$(OBJ_EXT): %.c
-       $(CC) $(CFLAGS) -o $@ -c $<
+       $(CC) $(CFLAGS) $(SHLIB_CFLAGS) -o $@ -c $<
 
index f6f20c85b4887606fd71b8675ba9f110727f80d1..b10096c05efc84b4dc272e2d8e244aee2a7fe6d5 100644 (file)
@@ -29,6 +29,7 @@
 #include "cx/allocator.h"
 
 #include <errno.h>
+#include <string.h>
 
 static void *cx_malloc_stdlib(
         cx_attr_unused void *d,
@@ -60,18 +61,19 @@ static void cx_free_stdlib(
     free(mem);
 }
 
-static cx_allocator_class cx_default_allocator_class = {
+static cx_allocator_class cx_stdlib_allocator_class = {
         cx_malloc_stdlib,
         cx_realloc_stdlib,
         cx_calloc_stdlib,
         cx_free_stdlib
 };
 
-struct cx_allocator_s cx_default_allocator = {
-        &cx_default_allocator_class,
+struct cx_allocator_s cx_stdlib_allocator = {
+        &cx_stdlib_allocator_class,
         NULL
 };
-const CxAllocator * const cxDefaultAllocator = &cx_default_allocator;
+const CxAllocator * const cxStdlibAllocator = &cx_stdlib_allocator;
+const CxAllocator * cxDefaultAllocator = cxStdlibAllocator;
 
 int cx_reallocate_(
         void **mem,
@@ -115,6 +117,17 @@ void *cxMalloc(
     return allocator->cl->malloc(allocator->data, n);
 }
 
+void *cxZalloc(
+        const CxAllocator *allocator,
+        size_t n
+) {
+    void *mem = allocator->cl->malloc(allocator->data, n);
+    if (mem != NULL) {
+        memset(mem, 0, n);
+    }
+    return mem;
+}
+
 void *cxRealloc(
         const CxAllocator *allocator,
         void *mem,
index 5387bfb8f7cd7cc82aedc9a030e7d3a825af1006..a66db5110b3ce421f024f424dc9a886ebcb98355 100644 (file)
 
 static void *cx_array_default_realloc(
         void *array,
-        size_t capacity,
+        cx_attr_unused size_t old_capacity,
+        size_t new_capacity,
         size_t elem_size,
         cx_attr_unused CxArrayReallocator *alloc
 ) {
     size_t n;
-    if (cx_szmul(capacity, elem_size, &n)) {
+    if (cx_szmul(new_capacity, elem_size, &n)) {
         errno = EOVERFLOW;
         return NULL;
     }
-    return realloc(array, n);
+    return cxReallocDefault(array, n);
 }
 
 CxArrayReallocator cx_array_default_reallocator_impl = {
@@ -58,13 +59,14 @@ CxArrayReallocator *cx_array_default_reallocator = &cx_array_default_reallocator
 
 static void *cx_array_advanced_realloc(
         void *array,
-        size_t capacity,
+        size_t old_capacity,
+        size_t new_capacity,
         size_t elem_size,
         cx_attr_unused CxArrayReallocator *alloc
 ) {
     // check for overflow
     size_t n;
-    if (cx_szmul(capacity, elem_size, &n)) {
+    if (cx_szmul(new_capacity, elem_size, &n)) {
         errno = EOVERFLOW;
         return NULL;
     }
@@ -77,7 +79,7 @@ static void *cx_array_advanced_realloc(
     if (array == alloc->ptr2) {
         newmem = cxMalloc(al, n);
         if (newmem != NULL && array != NULL) {
-            memcpy(newmem, array, n);
+            memcpy(newmem, array, old_capacity*elem_size);
         }
     } else {
         newmem = cxRealloc(al, array, n);
@@ -180,7 +182,7 @@ int cx_array_reserve(
 
         // perform reallocation
         void *newmem = reallocator->realloc(
-                *array, newcap, elem_size, reallocator
+                *array, oldcap, newcap, elem_size, reallocator
         );
         if (newmem == NULL) {
             return 1; // LCOV_EXCL_LINE
@@ -286,7 +288,7 @@ int cx_array_copy(
 
         // perform reallocation
         void *newmem = reallocator->realloc(
-                *target, newcap, elem_size, reallocator
+                *target, oldcap, newcap, elem_size, reallocator
         );
         if (newmem == NULL) {
             return 1;
@@ -366,13 +368,14 @@ int cx_array_insert_sorted(
 
     // store some counts
     size_t old_size = *size;
+    size_t old_capacity = *capacity;
     size_t needed_capacity = old_size + elem_count;
 
     // if we need more than we have, try a reallocation
-    if (needed_capacity > *capacity) {
+    if (needed_capacity > old_capacity) {
         size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX);
         void *new_mem = reallocator->realloc(
-                *target, new_capacity, elem_size, reallocator
+                *target, old_capacity, new_capacity, elem_size, reallocator
         );
         if (new_mem == NULL) {
             // give it up right away, there is no contract
@@ -572,7 +575,7 @@ void cx_array_swap(
 
     // decide if we can use the local buffer
     if (elem_size > CX_ARRAY_SWAP_SBO_SIZE) {
-        tmp = malloc(elem_size);
+        tmp = cxMallocDefault(elem_size);
         // we don't want to enforce error handling
         if (tmp == NULL) abort();
     } else {
@@ -591,7 +594,7 @@ void cx_array_swap(
 
     // free dynamic memory, if it was needed
     if (tmp != sbo_mem) {
-        free(tmp);
+        cxFreeDefault(tmp);
     }
 }
 
@@ -638,50 +641,38 @@ static size_t cx_arl_insert_array(
     // get a correctly typed pointer to the list
     cx_array_list *arl = (cx_array_list *) list;
 
-    // do we need to move some elements?
-    if (index < list->collection.size) {
-        const char *first_to_move = (const char *) arl->data;
-        first_to_move += index * list->collection.elem_size;
-        size_t elems_to_move = list->collection.size - index;
-        size_t start_of_moved = index + n;
-
-        if (cx_array_copy(
-                &arl->data,
-                &list->collection.size,
-                &arl->capacity,
-                0,
-                start_of_moved,
-                first_to_move,
-                list->collection.elem_size,
-                elems_to_move,
-                &arl->reallocator
-        )) {
-            // if moving existing elems is unsuccessful, abort
+    // guarantee enough capacity
+    if (arl->capacity < list->collection.size + n) {
+        size_t new_capacity = list->collection.size + n;
+        new_capacity = new_capacity - (new_capacity % 16) + 16;
+        if (cxReallocateArray(
+                list->collection.allocator,
+                &arl->data, new_capacity,
+                list->collection.elem_size)
+        ) {
             return 0;
         }
+        arl->capacity = new_capacity;
     }
 
-    // note that if we had to move the elements, the following operation
-    // is guaranteed to succeed, because we have the memory already allocated
-    // therefore, it is impossible to leave this function with an invalid array
+    // determine insert position
+    char *arl_data = arl->data;
+    char *insert_pos = arl_data + index * list->collection.elem_size;
 
-    // place the new elements
-    if (cx_array_copy(
-            &arl->data,
-            &list->collection.size,
-            &arl->capacity,
-            0,
-            index,
-            array,
-            list->collection.elem_size,
-            n,
-            &arl->reallocator
-    )) {
-        // array list implementation is "all or nothing"
-        return 0;
-    } else {
-        return n;
+    // do we need to move some elements?
+    if (index < list->collection.size) {
+        size_t elems_to_move = list->collection.size - index;
+        char *target = insert_pos + n * list->collection.elem_size;
+        memmove(target, insert_pos, elems_to_move * list->collection.elem_size);
     }
+
+    // place the new elements, if any
+    if (array != NULL) {
+        memcpy(insert_pos, array, n * list->collection.elem_size);
+    }
+    list->collection.size += n;
+
+    return n;
 }
 
 static size_t cx_arl_insert_sorted(
@@ -709,12 +700,16 @@ static size_t cx_arl_insert_sorted(
     }
 }
 
-static int cx_arl_insert_element(
+static void *cx_arl_insert_element(
         struct cx_list_s *list,
         size_t index,
         const void *element
 ) {
-    return 1 != cx_arl_insert_array(list, index, element, 1);
+    if (cx_arl_insert_array(list, index, element, 1) == 1) {
+        return ((char*)((cx_array_list *) list)->data) + index * list->collection.elem_size;
+    } else {
+        return NULL;
+    }
 }
 
 static int cx_arl_insert_iter(
@@ -724,26 +719,23 @@ static int cx_arl_insert_iter(
 ) {
     struct cx_list_s *list = iter->src_handle.m;
     if (iter->index < list->collection.size) {
-        int result = cx_arl_insert_element(
-                list,
-                iter->index + 1 - prepend,
-                elem
-        );
-        if (result == 0) {
-            iter->elem_count++;
-            if (prepend != 0) {
-                iter->index++;
-                iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size;
-            }
+        if (cx_arl_insert_element(list,
+                iter->index + 1 - prepend, elem) == NULL) {
+            return 1;
+        }
+        iter->elem_count++;
+        if (prepend != 0) {
+            iter->index++;
+            iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size;
         }
-        return result;
+        return 0;
     } else {
-        int result = cx_arl_insert_element(list, list->collection.size, elem);
-        if (result == 0) {
-            iter->elem_count++;
-            iter->index = list->collection.size;
+        if (cx_arl_insert_element(list, list->collection.size, elem) == NULL) {
+            return 1;
         }
-        return result;
+        iter->elem_count++;
+        iter->index = list->collection.size;
+        return 0;
     }
 }
 
index 1a7713eec5b298f4bed8ef1ab69c54cf5234720a..658dddf9fd30eef43bc5b23b7ed9d690ebe925c6 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#ifdef _WIN32
+#include <Windows.h>
+#include <sysinfoapi.h>
+static unsigned long system_page_size() {
+    static unsigned long ps = 0;
+    if (ps == 0) {
+        SYSTEM_INFO sysinfo;
+        GetSystemInfo(&sysinfo);
+        ps = sysinfo.dwPageSize;
+    }
+    return ps;
+}
+#define SYSTEM_PAGE_SIZE system_page_size()
+#else
+#include <unistd.h>
+#define SYSTEM_PAGE_SIZE sysconf(_SC_PAGESIZE)
+#endif
+
 static int buffer_copy_on_write(CxBuffer* buffer) {
     if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0;
     void *newspace = cxMalloc(buffer->allocator, buffer->capacity);
@@ -80,7 +98,7 @@ int cxBufferEnableFlushing(
     CxBuffer *buffer,
     CxBufferFlushConfig config
 ) {
-    buffer->flush = malloc(sizeof(CxBufferFlushConfig));
+    buffer->flush = cxMallocDefault(sizeof(CxBufferFlushConfig));
     if (buffer->flush == NULL) return -1; // LCOV_EXCL_LINE
     memcpy(buffer->flush, &config, sizeof(CxBufferFlushConfig));
     return 0;
@@ -90,7 +108,7 @@ void cxBufferDestroy(CxBuffer *buffer) {
     if (buffer->flags & CX_BUFFER_FREE_CONTENTS) {
         cxFree(buffer->allocator, buffer->bytes);
     }
-    free(buffer->flush);
+    cxFreeDefault(buffer->flush);
     memset(buffer, 0, sizeof(CxBuffer));
 }
 
@@ -139,6 +157,7 @@ int cxBufferSeek(
             npos = 0;
             break;
         default:
+            errno = EINVAL;
             return -1;
     }
 
@@ -146,11 +165,16 @@ int cxBufferSeek(
     npos += offset;
 
     if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
-        errno = EOVERFLOW;
+        // to be compliant with fseek() specification
+        // we return EINVAL on underflow
+        errno = EINVAL;
         return -1;
     }
 
     if (npos > buffer->size) {
+        // not compliant with fseek() specification
+        // but this is the better behavior for CxBuffer
+        errno = EINVAL;
         return -1;
     } else {
         buffer->pos = npos;
@@ -184,6 +208,28 @@ int cxBufferMinimumCapacity(
         return 0;
     }
 
+    unsigned long pagesize = SYSTEM_PAGE_SIZE;
+    // if page size is larger than 64 KB - for some reason - truncate to 64 KB
+    if (pagesize > 65536) pagesize = 65536;
+    if (newcap < pagesize) {
+        // when smaller as one page, map to the next power of two
+        newcap--;
+        newcap |= newcap >> 1;
+        newcap |= newcap >> 2;
+        newcap |= newcap >> 4;
+        // last operation only needed for pages larger 4096 bytes
+        // but if/else would be more expensive than just doing this
+        newcap |= newcap >> 8;
+        newcap++;
+    } else {
+        // otherwise, map to a multiple of the page size
+        newcap -= newcap % pagesize;
+        newcap += pagesize;
+        // note: if newcap is already page aligned,
+        // this gives a full additional page (which is good)
+    }
+
+
     const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
     if (buffer->flags & force_copy_flags) {
         void *newspace = cxMalloc(buffer->allocator, newcap);
@@ -203,6 +249,28 @@ int cxBufferMinimumCapacity(
     }
 }
 
+void cxBufferShrink(
+        CxBuffer *buffer,
+        size_t reserve
+) {
+    // Ensure buffer is in a reallocatable state
+    const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
+    if (buffer->flags & force_copy_flags) {
+        // do nothing when we are not allowed to reallocate
+        return;
+    }
+
+    // calculate new capacity
+    size_t newCapacity = buffer->size + reserve;
+
+    // If new capacity is smaller than current capacity, resize the buffer
+    if (newCapacity < buffer->capacity) {
+        if (0 == cxReallocate(buffer->allocator, &buffer->bytes, newCapacity)) {
+            buffer->capacity = newCapacity;
+        }
+    }
+}
+
 static size_t cx_buffer_flush_helper(
         const CxBuffer *buffer,
         const unsigned char *src,
@@ -399,10 +467,8 @@ int cxBufferPut(
 }
 
 int cxBufferTerminate(CxBuffer *buffer) {
-    bool success = 0 == cxBufferPut(buffer, 0);
-    if (success) {
-        buffer->pos--;
-        buffer->size--;
+    if (0 == cxBufferPut(buffer, 0)) {
+        buffer->size = buffer->pos - 1;
         return 0;
     } else {
         return -1;
index 8f16774326df5d0c50483a7fa30cd9eb870d9de6..c169a928d470ae963eadad85df7b27b6c9451080 100644 (file)
@@ -98,10 +98,17 @@ struct cx_allocator_s {
 typedef struct cx_allocator_s CxAllocator;
 
 /**
- * A default allocator using standard library malloc() etc.
+ * A pre-defined allocator using standard library malloc() etc.
  */
 cx_attr_export
-extern const CxAllocator * const cxDefaultAllocator;
+extern const CxAllocator * const cxStdlibAllocator;
+
+/**
+ * The default allocator that is used by UCX.
+ * Initialized with cxStdlibAllocator, but you may change it.
+ */
+cx_attr_export
+extern const CxAllocator * cxDefaultAllocator;
 
 /**
  * Function pointer type for destructor functions.
@@ -135,6 +142,8 @@ typedef void (*cx_destructor_func2)(
  * Reallocate a previously allocated block and changes the pointer in-place,
  * if necessary.
  *
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
  * @par Error handling
  * @c errno will be set by realloc() on failure.
  *
@@ -158,6 +167,8 @@ int cx_reallocate_(
  *
  * The size is calculated by multiplying @p nemb and @p size.
  *
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
  * @par Error handling
  * @c errno will be set by realloc() on failure or when the multiplication of
  * @p nmemb and @p size overflows.
@@ -182,6 +193,8 @@ int cx_reallocatearray_(
  * Reallocate a previously allocated block and changes the pointer in-place,
  * if necessary.
  *
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
  * @par Error handling
  * @c errno will be set by realloc() on failure.
  *
@@ -199,6 +212,8 @@ int cx_reallocatearray_(
  *
  * The size is calculated by multiplying @p nemb and @p size.
  *
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
  * @par Error handling
  * @c errno will be set by realloc() on failure or when the multiplication of
  * @p nmemb and @p size overflows.
@@ -212,6 +227,14 @@ int cx_reallocatearray_(
 #define cx_reallocatearray(mem, nmemb, size) \
     cx_reallocatearray_((void**)(mem), nmemb, size)
 
+/**
+ * Allocates memory and sets every byte to zero.
+ *
+ * @param n (@c size_t) the number of bytes
+ * @return (@c void*) a pointer to the allocated memory
+ */
+#define cx_zalloc(n) calloc(1, n)
+
 /**
  * Free a block allocated by this allocator.
  *
@@ -414,6 +437,57 @@ void *cxCalloc(
         size_t size
 );
 
+/**
+ * Allocate @p n bytes of memory and sets every byte to zero.
+ *
+ * @param allocator the allocator
+ * @param n the number of bytes
+ * @return a pointer to the allocated memory
+ */
+cx_attr_nodiscard
+cx_attr_nonnull
+cx_attr_malloc
+cx_attr_dealloc_ucx
+cx_attr_allocsize(2)
+cx_attr_export
+void *cxZalloc(
+        const CxAllocator *allocator,
+        size_t n
+);
+
+/**
+ * Convenience macro that invokes cxMalloc() with the cxDefaultAllocator.
+ */
+#define cxMallocDefault(...) cxMalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxZalloc() with the cxDefaultAllocator.
+ */
+#define cxZallocDefault(...) cxZalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxCalloc() with the cxDefaultAllocator.
+ */
+#define cxCallocDefault(...) cxCalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxRealloc() with the cxDefaultAllocator.
+ */
+#define cxReallocDefault(...) cxRealloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocate() with the cxDefaultAllocator.
+ */
+#define cxReallocateDefault(...) cxReallocate(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocateArray() with the cxDefaultAllocator.
+ */
+#define cxReallocateArrayDefault(...) cxReallocateArray(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocArray() with the cxDefaultAllocator.
+ */
+#define cxReallocArrayDefault(...) cxReallocArray(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxFree() with the cxDefaultAllocator.
+ */
+#define cxFreeDefault(...) cxFree(cxDefaultAllocator, __VA_ARGS__)
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 198407f85ffe750a3e5d462bcedc9e7941b45902..b38710d778a508844bb03578b0760003fe8a3faa 100644 (file)
@@ -123,7 +123,8 @@ extern const unsigned cx_array_swap_sbo_size;
  * @endcode
  *
  *
- * The memory for the array is allocated with stdlib malloc().
+ * The memory for the array is allocated with the cxDefaultAllocator.
+ *
  * @param array the name of the array
  * @param capacity the initial capacity
  * @see cx_array_initialize_a()
@@ -133,7 +134,7 @@ extern const unsigned cx_array_swap_sbo_size;
 #define cx_array_initialize(array, capacity) \
         array##_capacity = capacity; \
         array##_size = 0; \
-        array = malloc(sizeof(array[0]) * capacity)
+        array = cxMallocDefault(sizeof(array[0]) * capacity)
 
 /**
  * Initializes an array with the given capacity using the specified allocator.
@@ -149,7 +150,6 @@ extern const unsigned cx_array_swap_sbo_size;
  * cxFree(al, myarray); // don't forget to free with same allocator
  * @endcode
  *
- * The memory for the array is allocated with stdlib malloc().
  * @param allocator (@c CxAllocator*) the allocator
  * @param array the name of the array
  * @param capacity the initial capacity
@@ -178,17 +178,19 @@ struct cx_array_reallocator_s {
      * or to transport other additional data.
      *
      * @param array the array to reallocate
-     * @param capacity the new capacity (number of elements)
+     * @param old_capacity the old number of elements
+     * @param new_capacity the new number of elements
      * @param elem_size the size of each element
      * @param alloc a reference to this allocator
      * @return a pointer to the reallocated memory or @c NULL on failure
      */
     cx_attr_nodiscard
-    cx_attr_nonnull_arg(4)
-    cx_attr_allocsize(2, 3)
+    cx_attr_nonnull_arg(5)
+    cx_attr_allocsize(3, 4)
     void *(*realloc)(
             void *array,
-            size_t capacity,
+            size_t old_capacity,
+            size_t new_capacity,
             size_t elem_size,
             struct cx_array_reallocator_s *alloc
     );
@@ -217,7 +219,7 @@ struct cx_array_reallocator_s {
 typedef struct cx_array_reallocator_s CxArrayReallocator;
 
 /**
- * A default stdlib-based array reallocator.
+ * A default array reallocator that is based on the cxDefaultAllocator.
  */
 cx_attr_export
 extern CxArrayReallocator *cx_array_default_reallocator;
@@ -225,7 +227,7 @@ extern CxArrayReallocator *cx_array_default_reallocator;
 /**
  * Creates a new array reallocator.
  *
- * When @p allocator is @c NULL, the stdlib default allocator will be used.
+ * When @p allocator is @c NULL, the cxDefaultAllocator will be used.
  *
  * When @p stackmem is not @c NULL, the reallocator is supposed to be used
  * @em only for the specific array that is initially located at @p stackmem.
@@ -699,7 +701,7 @@ void cx_array_swap(
  * to cx_cmp_ptr(), if none is given.
  *
  * @param allocator the allocator for allocating the list memory
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param comparator the comparator for the elements
  * (if @c NULL, and the list is not storing pointers, sort and find
  * functions will not work)
@@ -727,7 +729,7 @@ CxList *cxArrayListCreate(
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * to cx_cmp_ptr().
  *
  * @param elem_size (@c size_t) the size of each element in bytes
  * @param initial_capacity (@c size_t) the initial number of elements the array can store
index e2868326bbb0cbe4dec92fd824706d92fe10e9f3..867fb3084f207816a62d053700982cd56123b5f5 100644 (file)
@@ -222,7 +222,7 @@ typedef struct cx_buffer_s CxBuffer;
  * @param capacity the capacity of the buffer
  * @param allocator the allocator this buffer shall use for automatic
  * memory management
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param flags buffer features (see cx_buffer_s.flags)
  * @return zero on success, non-zero if a required allocation failed
  */
@@ -305,7 +305,7 @@ void cxBufferFree(CxBuffer *buffer);
  * @param capacity the capacity of the buffer
  * @param allocator the allocator to use for allocating the structure and the automatic
  * memory management within the buffer
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param flags buffer features (see cx_buffer_s.flags)
  * @return a pointer to the buffer on success, @c NULL if a required allocation failed
  */
@@ -474,10 +474,14 @@ bool cxBufferEof(const CxBuffer *buffer);
  *
  * If the current capacity is not sufficient, the buffer will be extended.
  *
+ * The new capacity will be a power of two until the system's page size is reached.
+ * Then, the new capacity will be a multiple of the page size.
+ *
  * @param buffer the buffer
  * @param capacity the minimum required capacity for this buffer
  * @retval zero the capacity was already sufficient or successfully increased
  * @retval non-zero on allocation failure
+ * @see cxBufferShrink()
  */
 cx_attr_nonnull
 cx_attr_export
@@ -486,6 +490,29 @@ int cxBufferMinimumCapacity(
         size_t capacity
 );
 
+/**
+ * Shrinks the capacity of the buffer to fit its current size.
+ *
+ * If @p reserve is larger than zero, the buffer is shrunk to its size plus
+ * the number of reserved bytes.
+ *
+ * If the current capacity is not larger than the size plus the reserved bytes,
+ * nothing happens.
+ *
+ * If the #CX_BUFFER_COPY_ON_WRITE or #CX_BUFFER_COPY_ON_EXTEND flag is set,
+ * this function does nothing.
+ *
+ * @param buffer the buffer
+ * @param reserve the number of bytes that shall remain reserved
+ * @see cxBufferMinimumCapacity()
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxBufferShrink(
+        CxBuffer *buffer,
+        size_t reserve
+);
+
 /**
  * Writes data to a CxBuffer.
  *
@@ -674,11 +701,10 @@ int cxBufferPut(
 /**
  * Writes a terminating zero to a buffer at the current position.
  *
- * On successful write, @em neither the position @em nor the size of the buffer is
- * increased.
+ * If successful, sets the size to the current position and advances the position by one.
  *
  * The purpose of this function is to have the written data ready to be used as
- * a C string.
+ * a C string with the buffer's size being the length of that string.
  *
  * @param buffer the buffer to write to
  * @return zero, if the terminator could be written, non-zero otherwise
index 604ca5f617c1ac68eff676929468986806ce7b16..0fc9e47dec846c76e6cf210972a7f791dfed63d9 100644 (file)
@@ -46,7 +46,7 @@
  * Repositories:<br>
  * <a href="https://sourceforge.net/p/ucx/code">https://sourceforge.net/p/ucx/code</a>
  * -&nbsp;or&nbsp;-
- * <a href="https://develop.uap-core.de/hg/ucx">https://develop.uap-core.de/hg/ucx</a>
+ * <a href="https://uap-core.de/hg/ucx">https://uap-core.de/hg/ucx</a>
  * </p>
  *
  * <h2>LICENCE</h2>
  */
 #define cx_attr_malloc __attribute__((__malloc__))
 
-#ifndef __clang__
+#if !defined(__clang__) && __GNUC__ >= 11
 /**
  * The pointer returned by the attributed function is supposed to be freed
  * by @p freefunc.
  */
 #define cx_attr_access_w(...) cx_attr_access(__write_only__, __VA_ARGS__)
 
-#if __STDC_VERSION__ >= 202300L
-
-/**
- * Do not warn about unused variable.
- */
-#define cx_attr_unused [[maybe_unused]]
-
-/**
- * Warn about discarded return value.
- */
-#define cx_attr_nodiscard [[nodiscard]]
-
-#else // no C23
-
 /**
  * Do not warn about unused variable.
  */
  */
 #define cx_attr_nodiscard __attribute__((__warn_unused_result__))
 
-#endif // __STDC_VERSION__
-
 
 // ---------------------------------------------------------------------------
 //       MSVC specifics
index 07e115564a88c67eb38c52dc988ea97c15dc9e19..6b11e2c1c61cbad1184ff48275ee2287244d9530 100644 (file)
@@ -77,7 +77,7 @@ struct cx_hash_map_s {
  * In other words, when the iterator is finished, @c index==size .
  *
  * @param allocator the allocator to use
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param itemsize the size of one element
  * @param buckets the initial number of buckets in this hash map
  * @return a pointer to the new hash map
index fcdae7490e69860c1b4597b529b9046ed602257b..3da2cae45b759b1b81b62ce3bf91bb2637ff4c50 100644 (file)
@@ -51,7 +51,7 @@ extern "C" {
  * to cx_cmp_ptr(), if none is given.
  *
  * @param allocator the allocator for allocating the list nodes
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param comparator the comparator for the elements
  * (if @c NULL, and the list is not storing pointers, sort and find
  * functions will not work)
@@ -77,7 +77,7 @@ CxList *cxLinkedListCreate(
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * to cx_cmp_ptr().
  *
  * @param elem_size (@c size_t) the size of each element in bytes
  * @return (@c CxList*) the created list
@@ -393,7 +393,7 @@ void cx_linked_list_insert_sorted_chain(
  * @li @p loc_next and @p loc_prev (ancestor node is determined by using the prev pointer, overall O(1) performance)
  * @li @p loc_next and @p begin (ancestor node is determined by list traversal, overall O(n) performance)
  *
- * @remark The @c next and @c prev pointers of the removed node are not cleared by this function and may still be used
+ * @remark The @c next and @c prev pointers of the removed chain are not cleared by this function and may still be used
  * to traverse to a former adjacent node in the list, or within the chain.
  *
  * @param begin a pointer to the beginning node pointer (optional)
index 2df6c506002096f10066de8672c353e93f912a71..14ddc043c2f86a95a8b4b0cb3c8a1e1b09a3c2d2 100644 (file)
@@ -80,8 +80,10 @@ struct cx_list_class_s {
 
     /**
      * Member function for inserting a single element.
+     * The data pointer may be @c NULL in which case the function shall only allocate memory.
+     * Returns a pointer to the data of the inserted element.
      */
-    int (*insert_element)(
+    void *(*insert_element)(
             struct cx_list_s *list,
             size_t index,
             const void *data
@@ -202,6 +204,22 @@ struct cx_list_class_s {
     );
 };
 
+/**
+ * Common type for all list implementations.
+ */
+typedef struct cx_list_s CxList;
+
+/**
+ * A shared instance of an empty list.
+ *
+ * Writing to that list is not allowed.
+ *
+ * You can use this is a placeholder for initializing CxList pointers
+ * for which you do not want to reserve memory right from the beginning.
+ */
+cx_attr_export
+extern CxList *const cxEmptyList;
+
 /**
  * Default implementation of an array insert.
  *
@@ -335,11 +353,6 @@ void cx_list_init(
     size_t elem_size
 );
 
-/**
- * Common type for all list implementations.
- */
-typedef struct cx_list_s CxList;
-
 /**
  * Returns the number of elements currently stored in the list.
  *
@@ -359,6 +372,7 @@ static inline size_t cxListSize(const CxList *list) {
  * @retval zero success
  * @retval non-zero memory allocation failure
  * @see cxListAddArray()
+ * @see cxListEmplace()
  */
 cx_attr_nonnull
 static inline int cxListAdd(
@@ -366,7 +380,7 @@ static inline int cxListAdd(
         const void *elem
 ) {
     list->collection.sorted = false;
-    return list->cl->insert_element(list, list->collection.size, elem);
+    return list->cl->insert_element(list, list->collection.size, elem) == NULL;
 }
 
 /**
@@ -407,6 +421,7 @@ static inline size_t cxListAddArray(
  * @retval non-zero memory allocation failure or the index is out of bounds
  * @see cxListInsertAfter()
  * @see cxListInsertBefore()
+ * @see cxListEmplaceAt()
  */
 cx_attr_nonnull
 static inline int cxListInsert(
@@ -415,7 +430,41 @@ static inline int cxListInsert(
         const void *elem
 ) {
     list->collection.sorted = false;
-    return list->cl->insert_element(list, index, elem);
+    return list->cl->insert_element(list, index, elem) == NULL;
+}
+
+/**
+ * Allocates memory for an element at the specified index and returns a pointer to that memory.
+ *
+ * @remark When the list is storing pointers, this will return a @c void**.
+ *
+ * @param list the list
+ * @param index the index where to emplace the element
+ * @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
+ * @see cxListEmplace()
+ * @see cxListInsert()
+ */
+cx_attr_nonnull
+static inline void *cxListEmplaceAt(CxList *list, size_t index) {
+    list->collection.sorted = false;
+    return list->cl->insert_element(list, index, NULL);
+}
+
+
+/**
+ * Allocates memory for an element at the end of the list and returns a pointer to that memory.
+ *
+ * @remark When the list is storing pointers, this will return a @c void**.
+ *
+ * @param list the list
+ * @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
+ * @see cxListEmplaceAt()
+ * @see cxListAdd()
+ */
+cx_attr_nonnull
+static inline void *cxListEmplace(CxList *list) {
+    list->collection.sorted = false;
+    return list->cl->insert_element(list, list->collection.size, NULL);
 }
 
 /**
@@ -571,8 +620,9 @@ static inline int cxListRemove(
 /**
  * Removes and returns the element at the specified index.
  *
- * No destructor is called and instead the element is copied to the
+ * No destructor is called, and instead the element is copied to the
  * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
  *
  * @param list the list
  * @param index the index of the element
@@ -590,12 +640,94 @@ static inline int cxListRemoveAndGet(
     return list->cl->remove(list, index, 1, targetbuf) == 0;
 }
 
+/**
+ * Removes and returns the first element of the list.
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list the list
+ * @param targetbuf a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListPopFront()
+ * @see cxListRemoveAndGetLast()
+ */
+cx_attr_nonnull
+cx_attr_access_w(2)
+static inline int cxListRemoveAndGetFirst(
+    CxList *list,
+    void *targetbuf
+) {
+    return list->cl->remove(list, 0, 1, targetbuf) == 0;
+}
+
+/**
+ * Removes and returns the first element of the list.
+ *
+ * Alias for cxListRemoveAndGetFirst().
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list (@c CxList*) the list
+ * @param targetbuf (@c void*) a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListRemoveAndGetFirst()
+ * @see cxListPop()
+ */
+#define cxListPopFront(list, targetbuf) cxListRemoveAndGetFirst((list), (targetbuf))
+
+
+/**
+ * Removes and returns the last element of the list.
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list the list
+ * @param targetbuf a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ */
+cx_attr_nonnull
+cx_attr_access_w(2)
+static inline int cxListRemoveAndGetLast(
+    CxList *list,
+    void *targetbuf
+) {
+    // note: index may wrap - member function will catch that
+    return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
+}
+
+/**
+ * Removes and returns the last element of the list.
+ *
+ * Alias for cxListRemoveAndGetLast().
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list (@c CxList*) the list
+ * @param targetbuf (@c void*) a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListRemoveAndGetLast()
+ * @see cxListPopFront()
+ */
+#define cxListPop(list, targetbuf) cxListRemoveAndGetLast((list), (targetbuf))
+
 /**
  * Removes multiple element starting at the specified index.
  *
  * If an element destructor function is specified, it is called for each
  * element. It is guaranteed that the destructor is called before removing
- * the element, however, due to possible optimizations it is neither guaranteed
+ * the element. However, due to possible optimizations, it is neither guaranteed
  * that the destructors are invoked for all elements before starting to remove
  * them, nor that the element is removed immediately after the destructor call
  * before proceeding to the next element.
@@ -615,10 +747,11 @@ static inline size_t cxListRemoveArray(
 }
 
 /**
- * Removes and returns multiple element starting at the specified index.
+ * Removes and returns multiple elements starting at the specified index.
  *
- * No destructor is called and instead the elements are copied to the
+ * No destructor is called, and instead the elements are copied to the
  * @p targetbuf which MUST be large enough to hold all removed elements.
+ * If the list is storing pointers, @p targetbuf is expected to be an array of pointers.
  *
  * @param list the list
  * @param index the index of the element
@@ -654,15 +787,15 @@ static inline void cxListClear(CxList *list) {
 /**
  * Swaps two items in the list.
  *
- * Implementations should only allocate temporary memory for the swap, if
+ * Implementations should only allocate temporary memory for the swap if
  * it is necessary.
  *
  * @param list the list
  * @param i the index of the first element
  * @param j the index of the second element
  * @retval zero success
- * @retval non-zero one of the indices is out of bounds
- * or the swap needed extra memory but allocation failed
+ * @retval non-zero one of the indices is out of bounds,
+ * or the swap needed extra memory, but allocation failed
  */
 cx_attr_nonnull
 static inline int cxListSwap(
@@ -677,6 +810,8 @@ static inline int cxListSwap(
 /**
  * Returns a pointer to the element at the specified index.
  *
+ * If the list is storing pointers, returns the pointer stored at the specified index.
+ *
  * @param list the list
  * @param index the index of the element
  * @return a pointer to the element or @c NULL if the index is out of bounds
@@ -689,6 +824,49 @@ static inline void *cxListAt(
     return list->cl->at(list, index);
 }
 
+/**
+ * Returns a pointer to the first element.
+ *
+ * If the list is storing pointers, returns the first pointer stored in the list.
+ *
+ * @param list the list
+ * @return a pointer to the first element or @c NULL if the list is empty
+ */
+cx_attr_nonnull
+static inline void *cxListFirst(const CxList *list) {
+    return list->cl->at(list, 0);
+}
+
+/**
+ * Returns a pointer to the last element.
+ *
+ * If the list is storing pointers, returns the last pointer stored in the list.
+ *
+ * @param list the list
+ * @return a pointer to the last element or @c NULL if the list is empty
+ */
+cx_attr_nonnull
+static inline void *cxListLast(const CxList *list) {
+    return list->cl->at(list, list->collection.size - 1);
+}
+
+/**
+ * Sets the element at the specified index in the list
+ *
+ * @param list the list to set the element in
+ * @param index the index to set the element at
+ * @param elem element to set
+ * @retval zero on success
+ * @retval non-zero when index is out of bounds
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxListSet(
+        CxList *list,
+        size_t index,
+        const void *elem
+);
+
 /**
  * Returns an iterator pointing to the item at the specified index.
  *
@@ -773,14 +951,14 @@ CxIterator cxListMutBackwardsIteratorAt(
  *
  * The returned iterator is position-aware.
  *
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
  *
  * @param list the list
  * @return a new iterator
  */
-cx_attr_nonnull
 cx_attr_nodiscard
 static inline CxIterator cxListIterator(const CxList *list) {
+    if (list == NULL) list = cxEmptyList;
     return list->cl->iterator(list, 0, false);
 }
 
@@ -789,14 +967,14 @@ static inline CxIterator cxListIterator(const CxList *list) {
  *
  * The returned iterator is position-aware.
  *
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
  *
  * @param list the list
  * @return a new iterator
  */
-cx_attr_nonnull
 cx_attr_nodiscard
 static inline CxIterator cxListMutIterator(CxList *list) {
+    if (list == NULL) list = cxEmptyList;
     return cxListMutIteratorAt(list, 0);
 }
 
@@ -806,14 +984,14 @@ static inline CxIterator cxListMutIterator(CxList *list) {
  *
  * The returned iterator is position-aware.
  *
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
  *
  * @param list the list
  * @return a new iterator
  */
-cx_attr_nonnull
 cx_attr_nodiscard
 static inline CxIterator cxListBackwardsIterator(const CxList *list) {
+    if (list == NULL) list = cxEmptyList;
     return list->cl->iterator(list, list->collection.size - 1, true);
 }
 
@@ -822,14 +1000,14 @@ static inline CxIterator cxListBackwardsIterator(const CxList *list) {
  *
  * The returned iterator is position-aware.
  *
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
  *
  * @param list the list
  * @return a new iterator
  */
-cx_attr_nonnull
 cx_attr_nodiscard
 static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
+    if (list == NULL) list = cxEmptyList;
     return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
 }
 
@@ -842,6 +1020,7 @@ static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
  * @param elem the element to find
  * @return the index of the element or the size of the list when the element is not found
  * @see cxListIndexValid()
+ * @see cxListContains()
  */
 cx_attr_nonnull
 cx_attr_nodiscard
@@ -852,6 +1031,26 @@ static inline size_t cxListFind(
     return list->cl->find_remove((CxList*)list, elem, false);
 }
 
+/**
+ * Checks, if the list contains the specified element.
+ *
+ * The elements are compared with the list's comparator function.
+ *
+ * @param list the list
+ * @param elem the element to find
+ * @retval true if the element is contained
+ * @retval false if the element is not contained
+ * @see cxListFind()
+ */
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline bool cxListContains(
+    const CxList* list,
+    const void* elem
+) {
+    return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
+}
+
 /**
  * Checks if the specified index is within bounds.
  *
@@ -894,6 +1093,7 @@ static inline size_t cxListFindRemove(
  */
 cx_attr_nonnull
 static inline void cxListSort(CxList *list) {
+    if (list->collection.sorted) return;
     list->cl->sort(list);
     list->collection.sorted = true;
 }
@@ -942,17 +1142,6 @@ int cxListCompare(
 cx_attr_export
 void cxListFree(CxList *list);
 
-/**
- * A shared instance of an empty list.
- *
- * Writing to that list is not allowed.
- *
- * You can use this is a placeholder for initializing CxList pointers
- * for which you do not want to reserve memory right from the beginning.
- */
-cx_attr_export
-extern CxList *const cxEmptyList;
-
 
 #ifdef __cplusplus
 } // extern "C"
index 43b3b173a20c24d57e0d0184e811e9b387de94fd..5d8d2849ea7e19af1fe7b6b4144a854e559396dd 100644 (file)
 extern "C" {
 #endif
 
-/** Internal structure for pooled memory. */
-struct cx_mempool_memory_s;
+/** A memory block in a simple memory pool. */
+struct cx_mempool_memory_s {
+    /** The destructor. */
+    cx_destructor_func destructor;
+    /** The actual memory. */
+    char c[];
+};
+
+/** A memory block in an advanced memory pool. */
+struct cx_mempool_memory2_s {
+    /** The destructor. */
+    cx_destructor_func2 destructor;
+    /** Data for the destructor. */
+    void *data;
+    /** The actual memory. */
+    char c[];
+};
+
+/** Represents memory that is not allocated by, but registered with a pool. */
+struct cx_mempool_foreign_memory_s {
+    /** The foreign memory. */
+    void* mem;
+    union {
+        /** Simple destructor. */
+        cx_destructor_func destr;
+        /** Advanced destructor. */
+        cx_destructor_func2 destr2;
+    };
+    /** Data for the advanced destructor. */
+    void *destr2_data;
+};
+
+/** Specifies how individual blocks are allocated. */
+enum cx_mempool_type {
+    /**
+     * Allows registration of cx_destructor_func for each memory block.
+     */
+    CX_MEMPOOL_TYPE_SIMPLE,
+    /**
+     * Allows registration of cx_destructor_func2 for each memory block.
+     */
+    CX_MEMPOOL_TYPE_ADVANCED,
+    /**
+     * No individual destructor registration allowed.
+     *
+     * In this mode, no additional memory per block is allocated.
+     */
+    CX_MEMPOOL_TYPE_PURE,
+};
 
 /**
  * The basic structure of a memory pool.
  * Should be the first member of an actual memory pool implementation.
  */
 struct cx_mempool_s {
+    /** The used allocator, initialized with the cxDefaultAllocator. */
+    const CxAllocator * const base_allocator;
+
     /** The provided allocator. */
     const CxAllocator *allocator;
 
-    /**
-     * A destructor that shall be automatically registered for newly allocated memory.
-     * This destructor MUST NOT free the memory.
-     */
-    cx_destructor_func auto_destr;
-
     /** Array of pooled memory. */
-    struct cx_mempool_memory_s **data;
+    void **data;
 
     /** Number of pooled memory items. */
     size_t size;
 
     /** Memory pool capacity. */
     size_t capacity;
+
+    /** Array of registered memory. */
+    struct cx_mempool_foreign_memory_s *registered;
+
+    /** Number of registered memory items. */
+    size_t registered_size;
+
+    /** Capacity for registered memory. */
+    size_t registered_capacity;
+
+    /**
+     * A destructor that shall be called before deallocating a memory block.
+     * This destructor MUST NOT free the memory itself.
+     *
+     * It is guaranteed that this destructor is called after the individual
+     * destructor of the memory block and before @c destr2.
+     */
+    cx_destructor_func destr;
+
+    /**
+     * A destructor that shall be called before deallocating a memory block.
+     * This destructor MUST NOT free the memory itself.
+     *
+    * It is guaranteed that this destructor is called after the individual
+     * destructor of the memory block and @c destr.
+     */
+    cx_destructor_func2 destr2;
+
+    /**
+     * Additional data for the @c destr2.
+     */
+    void *destr2_data;
 };
 
 /**
@@ -84,31 +160,76 @@ cx_attr_export
 void cxMempoolFree(CxMempool *pool);
 
 /**
- * Creates an array-based memory pool with a shared destructor function.
+ * Creates an array-based memory pool.
  *
- * This destructor MUST NOT free the memory.
+ * The type determines how much additional memory is allocated per block
+ * to register a destructor function.
  *
- * @param capacity the initial capacity of the pool
- * @param destr optional destructor function to use for allocated memory
+ * @param capacity the initial capacity of the pool (an implementation default if zero)
+ * @param type the type of memory pool
  * @return the created memory pool or @c NULL if allocation failed
  */
 cx_attr_nodiscard
 cx_attr_malloc
 cx_attr_dealloc(cxMempoolFree, 1)
 cx_attr_export
-CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func destr);
+CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
 
 /**
  * Creates a basic array-based memory pool.
  *
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_SIMPLE.
+ *
  * @param capacity (@c size_t) the initial capacity of the pool
  * @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
  */
-#define cxMempoolCreateSimple(capacity) cxMempoolCreate(capacity, NULL)
+#define cxMempoolCreateSimple(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_SIMPLE)
+
+/**
+ * Creates a basic array-based memory pool.
+ *
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_ADVANCED.
+ *
+ * @param capacity (@c size_t) the initial capacity of the pool
+ * @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
+ */
+#define cxMempoolCreateAdvanced(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_ADVANCED)
+
+/**
+ * Creates a basic array-based memory pool.
+ *
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_PURE.
+ *
+ * @param capacity (@c size_t) the initial capacity of the pool
+ * @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
+ */
+#define cxMempoolCreatePure(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_PURE)
+
+/**
+ * Sets the global destructor for all memory blocks within the specified pool.
+ *
+ * @param pool the memory pool
+ * @param fnc the destructor that shall be applied to all memory blocks
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
+
+/**
+ * Sets the global destructor for all memory blocks within the specified pool.
+ *
+ * @param pool the memory pool
+ * @param fnc the destructor that shall be applied to all memory blocks
+ * @param data additional data for the destructor function
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
 
 /**
  * Sets the destructor function for a specific allocated memory object.
  *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_SIMPLE, the behavior is undefined.
  * If the memory is not managed by a UCX memory pool, the behavior is undefined.
  * The destructor MUST NOT free the memory.
  *
@@ -123,24 +244,56 @@ void cxMempoolSetDestructor(
 );
 
 /**
- * Removes the destructor function for a specific allocated memory object.
+ * Sets the destructor function for a specific allocated memory object.
  *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_ADVANCED, the behavior is undefined.
  * If the memory is not managed by a UCX memory pool, the behavior is undefined.
  * The destructor MUST NOT free the memory.
  *
  * @param memory the object allocated in the pool
+ * @param fnc the destructor function
+ * @param data additional data for the destructor function
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxMempoolSetDestructor2(
+        void *memory,
+        cx_destructor_func2 fnc,
+        void *data
+);
+
+/**
+ * Removes the destructor function for a specific allocated memory object.
+ *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_SIMPLE, the behavior is undefined.
+ * If the memory is not managed by a UCX memory pool, the behavior is undefined.
+ *
+ * @param memory the object allocated in the pool
  */
 cx_attr_nonnull
 cx_attr_export
 void cxMempoolRemoveDestructor(void *memory);
 
+/**
+ * Removes the destructor function for a specific allocated memory object.
+ *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_ADVANCED, the behavior is undefined.
+ * If the memory is not managed by a UCX memory pool, the behavior is undefined.
+ *
+ * @param memory the object allocated in the pool
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxMempoolRemoveDestructor2(void *memory);
+
 /**
  * Registers foreign memory with this pool.
  *
  * The destructor, in contrast to memory allocated by the pool, MUST free the memory.
+ * This function can be used with any pool of any type, since destructors for registered memory
+ * are entirely independent of the pool's memory management.
  *
- * A small portion of memory will be allocated to register the information in the pool.
- * If that allocation fails, this function will return non-zero.
+ * The destructor for the registered memory will be called after all pooled items have been freed.
  *
  * @param pool the pool
  * @param memory the object to register (MUST NOT be already allocated in the pool)
@@ -156,6 +309,79 @@ int cxMempoolRegister(
         cx_destructor_func destr
 );
 
+
+/**
+ * Registers foreign memory with this pool.
+ *
+ * The destructor, in contrast to memory allocated by the pool, MUST free the memory.
+ * This function can be used with any pool of any type, since destructors for registered memory
+ * are entirely independent of the pool's memory management.
+ *
+ * The destructor for the registered memory will be called after all pooled items have been freed.
+ *
+ * @attention The data pointer MUST NOT be @c NULL.
+ * If you wish to register a destructor without additional data, use cxMempoolRegister().
+ *
+ * @param pool the pool
+ * @param memory the object to register (MUST NOT be already allocated in the pool)
+ * @param destr the destructor function
+ * @param data additional data for the destructor function
+ * @retval zero success
+ * @retval non-zero failure
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolRegister2(
+        CxMempool *pool,
+        void *memory,
+        cx_destructor_func2 destr,
+        void *data
+);
+
+/**
+ * Transfers all the memory managed by one pool to another.
+ *
+ * The allocator of the source pool will also be transferred and registered with the destination pool
+ * and stays valid, as long as the destination pool is not destroyed.
+ *
+ * The source pool will get a completely new allocator and can be reused or destroyed afterward.
+ *
+ * This function fails when the destination pool has a different type than the source pool.
+ *
+ * @param source the pool to move the memory from
+ * @param dest the pool where to transfer the memory to
+ * @retval zero success
+ * @retval non-zero allocation failure or incompatible pools
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolTransfer(
+        CxMempool *source,
+        CxMempool *dest
+);
+
+/**
+ * Transfers an object from one pool to another.
+ *
+ * This function fails when the destination pool has a different type than the source pool.
+ *
+ * @attention If the object maintains a reference to the pool's allocator,
+ * you must make sure to update that reference to the allocator of the destination pool.
+ *
+ * @param source the pool to move the memory from
+ * @param dest the pool where to transfer the memory to
+ * @param obj pointer to the object that shall be transferred
+ * @retval zero success
+ * @retval non-zero failure, or the object was not found in the source pool, or the pools are incompatible
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolTransferObject(
+        CxMempool *source,
+        CxMempool *dest,
+        const void *obj
+);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index f02a80fb9457d12b196c9b9175fe5c3f89c635a7..4ffd05f3381887dadaa76b78aa41e16b5b2b9baa 100644 (file)
@@ -229,7 +229,7 @@ cx_attr_printf(4, 5)
 cx_attr_cstr_arg(4)
 cx_attr_export
 int cx_sprintf_a(
-        CxAllocator *alloc,
+        const CxAllocator *alloc,
         char **str,
         size_t *len,
         const char *fmt,
@@ -274,7 +274,7 @@ cx_attr_access_rw(2)
 cx_attr_access_rw(3)
 cx_attr_export
 int cx_vsprintf_a(
-        CxAllocator *alloc,
+        const CxAllocator *alloc,
         char **str,
         size_t *len,
         const char *fmt,
@@ -333,7 +333,7 @@ cx_attr_access_rw(3)
 cx_attr_access_rw(4)
 cx_attr_export
 int cx_sprintf_sa(
-        CxAllocator *alloc,
+        const CxAllocator *alloc,
         char *buf,
         size_t *len,
         char **str,
@@ -388,7 +388,7 @@ cx_attr_nonnull
 cx_attr_cstr_arg(5)
 cx_attr_export
 int cx_vsprintf_sa(
-        CxAllocator *alloc,
+        const CxAllocator *alloc,
         char *buf,
         size_t *len,
         char **str,
index 619229f906e37df086022dfe47be8f88e3e2d0ff..d6df8f5fb2104cd10da4a14b216f58dfec38e673 100644 (file)
@@ -551,10 +551,12 @@ CxPropertiesStatus cxPropertiesNext(
 /**
  * Creates a properties sink for an UCX map.
  *
- * The values stored in the map will be pointers to strings allocated
- * by #cx_strdup_a().
- * The default stdlib allocator will be used, unless you specify a custom
- * allocator in the optional @c data of the sink.
+ * The values stored in the map will be pointers to freshly allocated,
+ * zero-terminated C strings (@c char*), which means the @p map should have been
+ * created with #CX_STORE_POINTERS.
+ *
+ * The cxDefaultAllocator will be used unless you specify a custom
+ * allocator in the optional @c data field of the returned sink.
  *
  * @param map the map that shall consume the k/v-pairs.
  * @return the sink
index 64c8dbaa0260f6f3f9756a8a079441c6df9a93c2..41bf18a59a8634f62b77daa96acae68462e395bb 100644 (file)
 #include "common.h"
 #include "allocator.h"
 
+/** Expands a UCX string as printf arguments. */
+#define CX_SFMT(s) (int) (s).length, (s).ptr
+
+/** Format specifier for a UCX string */
+#define CX_PRIstr ".*s"
+
 /**
  * The maximum length of the "needle" in cx_strstr() that can use SBO.
  */
@@ -151,7 +157,7 @@ extern "C" {
  *
  * @param literal the string literal
  */
-#define CX_STR(literal) (cxstring){literal, sizeof(literal) - 1}
+#define CX_STR(literal) ((cxstring){literal, sizeof(literal) - 1})
 
 #endif
 
@@ -257,6 +263,10 @@ cx_attr_nodiscard
 static inline cxstring cx_strcast(cxstring str) {
     return str;
 }
+cx_attr_nodiscard
+static inline cxstring cx_strcast(const char *str) {
+    return cx_str(str);
+}
 extern "C" {
 #else
 /**
@@ -280,6 +290,17 @@ static inline cxstring cx_strcast_c(cxstring str) {
     return str;
 }
 
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ * @see cx_strcast()
+ */
+cx_attr_nodiscard
+static inline cxstring cx_strcast_z(const char *str) {
+    return cx_str(str);
+}
+
 /**
 * Casts a mutable string to an immutable string.
 *
@@ -294,12 +315,13 @@ static inline cxstring cx_strcast_c(cxstring str) {
 */
 #define cx_strcast(str) _Generic((str), \
         cxmutstr: cx_strcast_m, \
-        cxstring: cx_strcast_c) \
-        (str)
+        cxstring: cx_strcast_c, \
+        const char*: cx_strcast_z, \
+        char *: cx_strcast_z) (str)
 #endif
 
 /**
- * Passes the pointer in this string to @c free().
+ * Passes the pointer in this string to the cxDefaultAllocator's @c free() function.
  *
  * The pointer in the struct is set to @c NULL and the length is set to zero
  * which means that this function protects you against double-free.
@@ -333,6 +355,46 @@ void cx_strfree_a(
         cxmutstr *str
 );
 
+/**
+ * Copies a string.
+ *
+ * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
+ * source string, including a zero-terminator.
+ *
+ * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
+ *
+ * @param alloc the allocator
+ * @param dest a pointer to the structure where to copy the contents to
+ * @param src the source string
+ *
+ * @retval zero success
+ * @retval non-zero if re-allocation failed
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+int cx_strcpy_a(
+        const CxAllocator *alloc,
+        cxmutstr *dest,
+        cxstring src
+);
+
+
+/**
+ * Copies a string.
+ *
+ * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
+ * source string, including a zero-terminator.
+ *
+ * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
+ *
+ * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to
+ * @param src (@c cxstring) the source string
+ *
+ * @retval zero success
+ * @retval non-zero if re-allocation failed
+ */
+#define cx_strcpy(dest, src) cx_strcpy_a(cxDefaultAllocator, dest, src)
+
 /**
  * Returns the accumulated length of all specified strings.
  * 
@@ -408,7 +470,7 @@ cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
 /**
  * Concatenates strings and returns a new string.
  *
- * The resulting string will be allocated by standard @c malloc().
+ * The resulting string will be allocated by the cxDefaultAllocator.
  * So developers @em must pass the return value to cx_strfree() eventually.
  *
 * If memory allocation fails, the pointer in the returned string will
@@ -428,7 +490,7 @@ cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
 /**
  * Concatenates strings.
  *
- * The resulting string will be allocated by standard @c malloc().
+ * The resulting string will be allocated by the cxDefaultAllocator.
  * So developers @em must pass the return value to cx_strfree() eventually.
  *
  * If @p str already contains a string, the memory will be reallocated and
@@ -879,13 +941,13 @@ cxmutstr cx_strdup_a_(
  * @see cx_strfree_a()
  */
 #define cx_strdup_a(allocator, string) \
-    cx_strdup_a_((allocator), cx_strcast((string)))
+    cx_strdup_a_((allocator), cx_strcast(string))
 
 /**
  * Creates a duplicate of the specified string.
  *
- * The new string will contain a copy allocated by standard
- * @c malloc(). So developers @em must pass the return value to cx_strfree().
+ * The new string will contain a copy allocated by the cxDefaultAllocator.
+ * So developers @em must pass the return value to cx_strfree().
  *
  * @note The returned string is guaranteed to be zero-terminated.
  *
@@ -894,7 +956,7 @@ cxmutstr cx_strdup_a_(
  * @see cx_strdup_a()
  * @see cx_strfree()
  */
-#define cx_strdup(string) cx_strdup_a_(cxDefaultAllocator, string)
+#define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string)
 
 /**
  * Omits leading and trailing spaces.
@@ -1016,7 +1078,7 @@ cxmutstr cx_strreplacen_a(
  *
  * Replaces at most @p replmax occurrences.
  *
- * The returned string will be allocated by @c malloc() and is guaranteed
+ * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
  * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
@@ -1052,7 +1114,7 @@ cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
 /**
  * Replaces a string with another string.
  *
- * The returned string will be allocated by @c malloc() and is guaranteed
+ * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
  * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
@@ -1091,7 +1153,7 @@ CxStrtokCtx cx_strtok_(
  * @return (@c CxStrtokCtx) a new string tokenization context
  */
 #define cx_strtok(str, delim, limit) \
-    cx_strtok_(cx_strcast((str)), cx_strcast((delim)), (limit))
+    cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
 
 /**
  * Returns the next token.
index b7f49b5127ed8d2ad6f337127524dfc4e7634377..14832dbeff20cb06fea7f008b02cc18ec6f6e33e 100644 (file)
@@ -120,6 +120,7 @@ typedef struct cx_tree_iterator_s {
         size_t stack_size;
         /**
          * The current depth in the tree.
+         * The node with which the iteration starts has depth 1.
          */
         size_t depth;
     };
@@ -135,6 +136,7 @@ struct cx_tree_visitor_queue_s {
     void *node;
     /**
      * The depth of the node.
+     * The first visited node has depth 1.
      */
     size_t depth;
     /**
@@ -211,7 +213,7 @@ typedef struct cx_tree_visitor_s {
  */
 cx_attr_nonnull
 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
-    free(iter->stack);
+    cxFreeDefault(iter->stack);
     iter->stack = NULL;
 }
 
@@ -224,7 +226,7 @@ static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
     struct cx_tree_visitor_queue_s *q = visitor->queue_next;
     while (q != NULL) {
         struct cx_tree_visitor_queue_s *next = q->next;
-        free(q);
+        cxFreeDefault(q);
         q = next;
     }
 }
@@ -441,7 +443,7 @@ int cx_tree_search(
  * Creates a depth-first iterator for a tree with the specified root node.
  *
  * @note A tree iterator needs to maintain a stack of visited nodes, which is
- * allocated using stdlib malloc().
+ * allocated using the cxDefaultAllocator.
  * When the iterator becomes invalid, this memory is automatically released.
  * However, if you wish to cancel the iteration before the iterator becomes
  * invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
@@ -469,8 +471,8 @@ CxTreeIterator cx_tree_iterator(
 /**
  * Creates a breadth-first iterator for a tree with the specified root node.
  *
- * @note A tree visitor needs to maintain a queue of to be visited nodes, which
- * is allocated using stdlib malloc().
+ * @note A tree visitor needs to maintain a queue of to-be visited nodes, which
+ * is allocated using the cxDefaultAllocator.
  * When the visitor becomes invalid, this memory is automatically released.
  * However, if you wish to cancel the iteration before the visitor becomes
  * invalid by itself, you MUST call cxTreeVisitorDispose() manually to release
@@ -956,7 +958,7 @@ void cxTreeFree(CxTree *tree);
  * will free the nodes with the allocator's free() method.
  *
  * @param allocator the allocator that shall be used
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
  * @param create_func a function that creates new nodes
  * @param search_func a function that compares two nodes
  * @param search_data_func a function that compares a node with data
@@ -1020,7 +1022,7 @@ cx_tree_node_base_layout)
  * tree, you need to specify those functions afterwards.
  *
  * @param allocator the allocator that was used for nodes of the wrapped tree
- * (if @c NULL, a default stdlib allocator is assumed)
+ * (if @c NULL, the cxDefaultAllocator is assumed)
  * @param root the root node of the tree that shall be wrapped
  * @param loc_parent offset in the node struct for the parent pointer
  * @param loc_children offset in the node struct for the children linked list
@@ -1187,6 +1189,18 @@ cx_attr_nodiscard
 cx_attr_export
 size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
 
+/**
+ * Determines the size of the entire tree.
+ *
+ * @param tree the tree
+ * @return the tree size, counting the root as one
+ */
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline size_t cxTreeSize(CxTree *tree) {
+    return tree->size;
+}
+
 /**
  * Determines the depth of the entire tree.
  *
index 4993d97569a32fbc97a2699da796f826e08efac6..484c7d374c7f21de0893c38b63650de0fb59242a 100644 (file)
@@ -500,7 +500,7 @@ static cxmutstr escape_string(cxmutstr str, bool escape_slash) {
 
         if (all_printable && escape) {
             size_t capa = str.length + 32;
-            char *space = malloc(capa);
+            char *space = cxMallocDefault(capa);
             if (space == NULL) return cx_mutstrn(NULL, 0);
             cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND);
             cxBufferWrite(str.ptr, 1, i, &buf);
@@ -631,10 +631,10 @@ void cxJsonInit(CxJson *json, const CxAllocator *allocator) {
 void cxJsonDestroy(CxJson *json) {
     cxBufferDestroy(&json->buffer);
     if (json->states != json->states_internal) {
-        free(json->states);
+        cxFreeDefault(json->states);
     }
     if (json->vbuf != json->vbuf_internal) {
-        free(json->vbuf);
+        cxFreeDefault(json->vbuf);
     }
     cxJsonValueFree(json->parsed);
     json->parsed = NULL;
@@ -984,67 +984,67 @@ static void json_arr_free_temp(CxJsonValue** values, size_t count) {
         if (values[i] == NULL) break;
         cxJsonValueFree(values[i]);
     }
-    free(values);
+    cxFreeDefault(values);
 }
 // LCOV_EXCL_STOP
 
 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) {
-    CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+    CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
     if (values == NULL) return -1;
     for (size_t i = 0; i < count; i++) {
         values[i] = cxJsonCreateNumber(arr->allocator, num[i]);
         if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
     }
     int ret = cxJsonArrAddValues(arr, values, count);
-    free(values);
+    cxFreeDefault(values);
     return ret;
 }
 
 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) {
-    CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+    CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
     if (values == NULL) return -1;
     for (size_t i = 0; i < count; i++) {
         values[i] = cxJsonCreateInteger(arr->allocator, num[i]);
         if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
     }
     int ret = cxJsonArrAddValues(arr, values, count);
-    free(values);
+    cxFreeDefault(values);
     return ret;
 }
 
 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) {
-    CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+    CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
     if (values == NULL) return -1;
     for (size_t i = 0; i < count; i++) {
         values[i] = cxJsonCreateString(arr->allocator, str[i]);
         if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
     }
     int ret = cxJsonArrAddValues(arr, values, count);
-    free(values);
+    cxFreeDefault(values);
     return ret;
 }
 
 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) {
-    CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+    CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
     if (values == NULL) return -1;
     for (size_t i = 0; i < count; i++) {
         values[i] = cxJsonCreateCxString(arr->allocator, str[i]);
         if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
     }
     int ret = cxJsonArrAddValues(arr, values, count);
-    free(values);
+    cxFreeDefault(values);
     return ret;
 }
 
 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) {
-    CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+    CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
     if (values == NULL) return -1;
     for (size_t i = 0; i < count; i++) {
         values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]);
         if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
     }
     int ret = cxJsonArrAddValues(arr, values, count);
-    free(values);
+    cxFreeDefault(values);
     return ret;
 }
 
index 3833d4426f0cac7393ceeb78e6c2d7b6088ac364..7cd2ff2e49a0608d01a2294425746a294ce08534 100644 (file)
@@ -401,7 +401,7 @@ static void cx_linked_list_sort_merge(
 ) {
     void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE];
     void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ?
-                    malloc(sizeof(void *) * length) : sbo;
+                    cxMallocDefault(sizeof(void *) * length) : sbo;
     if (sorted == NULL) abort();
     void *rc, *lc;
 
@@ -439,7 +439,7 @@ static void cx_linked_list_sort_merge(
     *begin = sorted[0];
     *end = sorted[length - 1];
     if (sorted != sbo) {
-        free(sorted);
+        cxFreeDefault(sorted);
     }
 }
 
@@ -613,7 +613,9 @@ static int cx_ll_insert_at(
 
     // initialize new new_node
     new_node->prev = new_node->next = NULL;
-    memcpy(new_node->payload, elem, list->collection.elem_size);
+    if (elem != NULL) {
+        memcpy(new_node->payload, elem, list->collection.elem_size);
+    }
 
     // insert
     cx_linked_list *ll = (cx_linked_list *) list;
@@ -659,12 +661,26 @@ static size_t cx_ll_insert_array(
     return n;
 }
 
-static int cx_ll_insert_element(
+static void *cx_ll_insert_element(
         struct cx_list_s *list,
         size_t index,
         const void *element
 ) {
-    return 1 != cx_ll_insert_array(list, index, element, 1);
+    // out-of-bounds check
+    if (index > list->collection.size) return NULL;
+
+    // find position efficiently
+    cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
+
+    // perform first insert
+    if (cx_ll_insert_at(list, node, element)) return NULL;
+
+    // return a pointer to the data of the inserted node
+    if (node == NULL) {
+        return ((cx_linked_list *) list)->begin->payload;
+    } else {
+        return node->next->payload;
+    }
 }
 
 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func;
@@ -920,6 +936,8 @@ static size_t cx_ll_find_remove(
         const void *elem,
         bool remove
 ) {
+    if (list->collection.size == 0) return 0;
+
     size_t index;
     cx_linked_list *ll = ((cx_linked_list *) list);
     cx_linked_list_node *node = cx_linked_list_find(
@@ -1054,12 +1072,12 @@ static int cx_ll_insert_iter(
         }
         return result;
     } else {
-        int result = cx_ll_insert_element(list, list->collection.size, elem);
-        if (result == 0) {
-            iter->elem_count++;
-            iter->index = list->collection.size;
+        if (cx_ll_insert_element(list, list->collection.size, elem) == NULL) {
+            return 1;
         }
-        return result;
+        iter->elem_count++;
+        iter->index = list->collection.size;
+        return 0;
     }
 }
 
index daf6b9ecce5a897aec6a16292b419dcc2ab374a2..7fbbb8b76de9a6ac806d81afe2b5ab1ad226ef13 100644 (file)
@@ -62,7 +62,7 @@ static void cx_pl_destructor(struct cx_list_s *list) {
     list->climpl->deallocate(list);
 }
 
-static int cx_pl_insert_element(
+static void *cx_pl_insert_element(
         struct cx_list_s *list,
         size_t index,
         const void *element
@@ -282,7 +282,7 @@ size_t cx_list_default_insert_array(
     const char *src = data;
     size_t i = 0;
     for (; i < n; i++) {
-        if (0 != invoke_list_func(
+        if (NULL == invoke_list_func(
             insert_element, list, index + i,
             src + (i * elem_size))) return i;
     }
@@ -329,7 +329,7 @@ size_t cx_list_default_insert_sorted(
 
         // insert the elements at location si
         if (ins == 1) {
-            if (0 != invoke_list_func(
+            if (NULL == invoke_list_func(
                 insert_element, list, di, src)) return inserted;
         } else {
             size_t r = invoke_list_func(insert_array, list, di, src, ins);
@@ -354,7 +354,7 @@ size_t cx_list_default_insert_sorted(
 void cx_list_default_sort(struct cx_list_s *list) {
     size_t elem_size = list->collection.elem_size;
     size_t list_size = list->collection.size;
-    void *tmp = malloc(elem_size * list_size);
+    void *tmp = cxMallocDefault(elem_size * list_size);
     if (tmp == NULL) abort();
 
     // copy elements from source array
@@ -377,7 +377,7 @@ void cx_list_default_sort(struct cx_list_s *list) {
         loc += elem_size;
     }
 
-    free(tmp);
+    cxFreeDefault(tmp);
 }
 
 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
@@ -387,7 +387,7 @@ int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
 
     size_t elem_size = list->collection.elem_size;
 
-    void *tmp = malloc(elem_size);
+    void *tmp = cxMallocDefault(elem_size);
     if (tmp == NULL) return 1;
 
     void *ip = invoke_list_func(at, list, i);
@@ -397,7 +397,7 @@ int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
     memcpy(ip, jp, elem_size);
     memcpy(jp, tmp, elem_size);
 
-    free(tmp);
+    cxFreeDefault(tmp);
 
     return 0;
 }
@@ -494,3 +494,24 @@ void cxListFree(CxList *list) {
     if (list == NULL) return;
     list->cl->deallocate(list);
 }
+
+int cxListSet(
+        CxList *list,
+        size_t index,
+        const void *elem
+) {
+    if (index >= list->collection.size) {
+        return 1;
+    }
+
+    if (list->collection.store_pointer) {
+        // For pointer collections, always use climpl
+        void **target = list->climpl->at(list, index);
+        *target = (void *)elem;
+    } else {
+        void *target = list->cl->at(list, index);
+        memcpy(target, elem, list->collection.elem_size);
+    }
+
+    return 0;
+}
index fea4d7026dcdd3283c0c2de5935544aefc2f7db7..8711439f50d784defc3c4823f69823ee4e7465ee 100644 (file)
 #include <string.h>
 #include <errno.h>
 
-struct cx_mempool_memory_s {
-    /** The destructor. */
-    cx_destructor_func destructor;
-    /** The actual memory. */
-    char c[];
-};
+static int cx_mempool_ensure_capacity(
+        struct cx_mempool_s *pool,
+        size_t needed_capacity
+) {
+    if (needed_capacity <= pool->capacity) return 0;
+    size_t newcap = pool->capacity >= 1000 ?
+        pool->capacity + 1000 : pool->capacity * 2;
+    size_t newmsize;
+    // LCOV_EXCL_START
+    if (pool->capacity > newcap
+            || cx_szmul(newcap, sizeof(void*), &newmsize)) {
+        errno = EOVERFLOW;
+        return 1;
+    } // LCOV_EXCL_STOP
+    void **newdata = cxRealloc(pool->base_allocator, pool->data, newmsize);
+    if (newdata == NULL) return 1;
+    pool->data = newdata;
+    pool->capacity = newcap;
+    return 0;
+}
 
-static void *cx_mempool_malloc(
+static int cx_mempool_ensure_registered_capacity(
+        struct cx_mempool_s *pool,
+        size_t needed_capacity
+) {
+    if (needed_capacity <= pool->registered_capacity) return 0;
+    // we do not expect so many registrations
+    size_t newcap = pool->registered_capacity + 8;
+    size_t newmsize;
+    // LCOV_EXCL_START
+    if (pool->registered_capacity > newcap || cx_szmul(newcap,
+            sizeof(struct cx_mempool_foreign_memory_s), &newmsize)) {
+        errno = EOVERFLOW;
+        return 1;
+    } // LCOV_EXCL_STOP
+    void *newdata = cxRealloc(pool->base_allocator, pool->registered, newmsize);
+    if (newdata == NULL) return 1;
+    pool->registered = newdata;
+    pool->registered_capacity = newcap;
+    return 0;
+}
+
+static void *cx_mempool_malloc_simple(
         void *p,
         size_t n
 ) {
     struct cx_mempool_s *pool = p;
 
-    if (pool->size >= pool->capacity) {
-        size_t newcap = pool->capacity - (pool->capacity % 16) + 16;
-        size_t newmsize;
-        if (pool->capacity > newcap || cx_szmul(newcap,
-                sizeof(struct cx_mempool_memory_s*), &newmsize)) {
-            errno = EOVERFLOW;
-            return NULL;
-        }
-        struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
-        if (newdata == NULL) return NULL;
-        pool->data = newdata;
-        pool->capacity = newcap;
+    if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+        return NULL; // LCOV_EXCL_LINE
     }
 
-    struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
+    struct cx_mempool_memory_s *mem =
+        cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory_s) + n);
     if (mem == NULL) return NULL;
-
-    mem->destructor = pool->auto_destr;
+    mem->destructor = NULL;
     pool->data[pool->size] = mem;
     pool->size++;
 
     return mem->c;
 }
 
-static void *cx_mempool_calloc(
+static void *cx_mempool_calloc_simple(
         void *p,
         size_t nelem,
         size_t elsize
@@ -78,53 +103,165 @@ static void *cx_mempool_calloc(
         errno = EOVERFLOW;
         return NULL;
     }
-    void *ptr = cx_mempool_malloc(p, msz);
+    void *ptr = cx_mempool_malloc_simple(p, msz);
     if (ptr == NULL) return NULL;
     memset(ptr, 0, nelem * elsize);
     return ptr;
 }
 
-static void *cx_mempool_realloc(
+static void cx_mempool_free_simple(
+        void *p,
+        void *ptr
+) {
+    if (!ptr) return;
+    struct cx_mempool_s *pool = p;
+
+    struct cx_mempool_memory_s *mem =
+        (void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s));
+
+    for (size_t i = 0; i < pool->size; i++) {
+        if (mem == pool->data[i]) {
+            if (mem->destructor) {
+                mem->destructor(mem->c);
+            }
+            if (pool->destr) {
+                pool->destr(mem->c);
+            }
+            if (pool->destr2) {
+                pool->destr2(pool->destr2_data, mem->c);
+            }
+            cxFree(pool->base_allocator, mem);
+            size_t last_index = pool->size - 1;
+            if (i != last_index) {
+                pool->data[i] = pool->data[last_index];
+                pool->data[last_index] = NULL;
+            }
+            pool->size--;
+            return;
+        }
+    }
+    abort(); // LCOV_EXCL_LINE
+}
+
+static void *cx_mempool_realloc_simple(
         void *p,
         void *ptr,
         size_t n
 ) {
+    if (ptr == NULL) {
+        return cx_mempool_malloc_simple(p, n);
+    }
+    if (n == 0) {
+        cx_mempool_free_simple(p, ptr);
+        return NULL;
+    }
     struct cx_mempool_s *pool = p;
 
-    struct cx_mempool_memory_s *mem, *newm;
-    mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func));
-    newm = realloc(mem, n + sizeof(cx_destructor_func));
+    const unsigned overhead = sizeof(struct cx_mempool_memory_s);
+    struct cx_mempool_memory_s *mem =
+        (void *) (((char *) ptr) - overhead);
+    struct cx_mempool_memory_s *newm =
+        cxRealloc(pool->base_allocator, mem, n + overhead);
 
     if (newm == NULL) return NULL;
     if (mem != newm) {
         for (size_t i = 0; i < pool->size; i++) {
             if (pool->data[i] == mem) {
                 pool->data[i] = newm;
-                return ((char*)newm) + sizeof(cx_destructor_func);
+                return ((char*)newm) + overhead;
             }
         }
         abort(); // LCOV_EXCL_LINE
     } else {
-        return ptr;
+        // unfortunately glibc() realloc seems to always move
+        return ptr;  // LCOV_EXCL_LINE
+    }
+}
+
+static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) {
+    const bool has_destr = pool->destr;
+    const bool has_destr2 = pool->destr2;
+    for (size_t i = 0; i < pool->size; i++) {
+        struct cx_mempool_memory_s *mem = pool->data[i];
+        if (mem->destructor) {
+            mem->destructor(mem->c);
+        }
+        if (has_destr) {
+            pool->destr(mem->c);
+        }
+        if (has_destr2) {
+            pool->destr2(pool->destr2_data, mem->c);
+        }
+        cxFree(pool->base_allocator, mem);
+    }
+}
+
+static cx_allocator_class cx_mempool_simple_allocator_class = {
+    cx_mempool_malloc_simple,
+    cx_mempool_realloc_simple,
+    cx_mempool_calloc_simple,
+    cx_mempool_free_simple
+};
+
+static void *cx_mempool_malloc_advanced(
+        void *p,
+        size_t n
+) {
+    struct cx_mempool_s *pool = p;
+
+    if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+        return NULL;  // LCOV_EXCL_LINE
+    }
+
+    struct cx_mempool_memory2_s *mem =
+        cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory2_s) + n);
+    if (mem == NULL) return NULL;
+    mem->destructor = NULL;
+    mem->data = NULL;
+    pool->data[pool->size] = mem;
+    pool->size++;
+
+    return mem->c;
+}
+
+static void *cx_mempool_calloc_advanced(
+        void *p,
+        size_t nelem,
+        size_t elsize
+) {
+    size_t msz;
+    if (cx_szmul(nelem, elsize, &msz)) {
+        errno = EOVERFLOW;
+        return NULL;
     }
+    void *ptr = cx_mempool_malloc_advanced(p, msz);
+    if (ptr == NULL) return NULL;
+    memset(ptr, 0, nelem * elsize);
+    return ptr;
 }
 
-static void cx_mempool_free(
+static void cx_mempool_free_advanced(
         void *p,
         void *ptr
 ) {
     if (!ptr) return;
     struct cx_mempool_s *pool = p;
 
-    struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *)
-            ((char *) ptr - sizeof(cx_destructor_func));
+    struct cx_mempool_memory2_s *mem =
+        (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s));
 
     for (size_t i = 0; i < pool->size; i++) {
         if (mem == pool->data[i]) {
             if (mem->destructor) {
-                mem->destructor(mem->c);
+                mem->destructor(mem->data, mem->c);
+            }
+            if (pool->destr) {
+                pool->destr(mem->c);
             }
-            free(mem);
+            if (pool->destr2) {
+                pool->destr2(pool->destr2_data, mem->c);
+            }
+            cxFree(pool->base_allocator, mem);
             size_t last_index = pool->size - 1;
             if (i != last_index) {
                 pool->data[i] = pool->data[last_index];
@@ -137,19 +274,207 @@ static void cx_mempool_free(
     abort(); // LCOV_EXCL_LINE
 }
 
-void cxMempoolFree(CxMempool *pool) {
-    if (pool == NULL) return;
-    struct cx_mempool_memory_s *mem;
+static void *cx_mempool_realloc_advanced(
+        void *p,
+        void *ptr,
+        size_t n
+) {
+    if (ptr == NULL) {
+        return cx_mempool_malloc_advanced(p, n);
+    }
+    if (n == 0) {
+        cx_mempool_free_advanced(p, ptr);
+        return NULL;
+    }
+    struct cx_mempool_s *pool = p;
+
+    const unsigned overhead = sizeof(struct cx_mempool_memory2_s);
+    struct cx_mempool_memory2_s *mem =
+        (void *) (((char *) ptr) - overhead);
+    struct cx_mempool_memory2_s *newm =
+        cxRealloc(pool->base_allocator, mem, n + overhead);
+
+    if (newm == NULL) return NULL;
+    if (mem != newm) {
+        for (size_t i = 0; i < pool->size; i++) {
+            if (pool->data[i] == mem) {
+                pool->data[i] = newm;
+                return ((char*)newm) + overhead;
+            }
+        }
+        abort(); // LCOV_EXCL_LINE
+    } else {
+        // unfortunately glibc() realloc seems to always move
+        return ptr;  // LCOV_EXCL_LINE
+    }
+}
+
+static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) {
+    const bool has_destr = pool->destr;
+    const bool has_destr2 = pool->destr2;
     for (size_t i = 0; i < pool->size; i++) {
-        mem = pool->data[i];
+        struct cx_mempool_memory2_s *mem = pool->data[i];
         if (mem->destructor) {
-            mem->destructor(mem->c);
+            mem->destructor(mem->data, mem->c);
         }
-        free(mem);
+        if (has_destr) {
+            pool->destr(mem->c);
+        }
+        if (has_destr2) {
+            pool->destr2(pool->destr2_data, mem->c);
+        }
+        cxFree(pool->base_allocator, mem);
+    }
+}
+
+static cx_allocator_class cx_mempool_advanced_allocator_class = {
+    cx_mempool_malloc_advanced,
+    cx_mempool_realloc_advanced,
+    cx_mempool_calloc_advanced,
+    cx_mempool_free_advanced
+};
+
+
+static void *cx_mempool_malloc_pure(
+        void *p,
+        size_t n
+) {
+    struct cx_mempool_s *pool = p;
+
+    if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+        return NULL; // LCOV_EXCL_LINE
     }
-    free(pool->data);
-    free((void*) pool->allocator);
-    free(pool);
+
+    void *mem = cxMalloc(pool->base_allocator, n);
+    if (mem == NULL) return NULL;
+    pool->data[pool->size] = mem;
+    pool->size++;
+
+    return mem;
+}
+
+static void *cx_mempool_calloc_pure(
+        void *p,
+        size_t nelem,
+        size_t elsize
+) {
+    size_t msz;
+    if (cx_szmul(nelem, elsize, &msz)) {
+        errno = EOVERFLOW;
+        return NULL;
+    }
+    void *ptr = cx_mempool_malloc_pure(p, msz);
+    if (ptr == NULL) return NULL;
+    memset(ptr, 0, nelem * elsize);
+    return ptr;
+}
+
+static void cx_mempool_free_pure(
+        void *p,
+        void *ptr
+) {
+    if (!ptr) return;
+    struct cx_mempool_s *pool = p;
+
+    for (size_t i = 0; i < pool->size; i++) {
+        if (ptr == pool->data[i]) {
+            if (pool->destr) {
+                pool->destr(ptr);
+            }
+            if (pool->destr2) {
+                pool->destr2(pool->destr2_data, ptr);
+            }
+            cxFree(pool->base_allocator, ptr);
+            size_t last_index = pool->size - 1;
+            if (i != last_index) {
+                pool->data[i] = pool->data[last_index];
+                pool->data[last_index] = NULL;
+            }
+            pool->size--;
+            return;
+        }
+    }
+    abort(); // LCOV_EXCL_LINE
+}
+
+static void *cx_mempool_realloc_pure(
+        void *p,
+        void *ptr,
+        size_t n
+) {
+    if (ptr == NULL) {
+        return cx_mempool_malloc_pure(p, n);
+    }
+    if (n == 0) {
+        cx_mempool_free_pure(p, ptr);
+        return NULL;
+    }
+    struct cx_mempool_s *pool = p;
+    void *newm = cxRealloc(pool->base_allocator, ptr, n);
+    if (newm == NULL) return NULL;
+    if (ptr != newm) {
+        for (size_t i = 0; i < pool->size; i++) {
+            if (pool->data[i] == ptr) {
+                pool->data[i] = newm;
+                return newm;
+            }
+        }
+        abort(); // LCOV_EXCL_LINE
+    } else {
+        // unfortunately glibc() realloc seems to always move
+        return ptr;  // LCOV_EXCL_LINE
+    }
+}
+
+static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) {
+    const bool has_destr = pool->destr;
+    const bool has_destr2 = pool->destr2;
+    for (size_t i = 0; i < pool->size; i++) {
+        void *mem = pool->data[i];
+        if (has_destr) {
+            pool->destr(mem);
+        }
+        if (has_destr2) {
+            pool->destr2(pool->destr2_data, mem);
+        }
+        cxFree(pool->base_allocator, mem);
+    }
+}
+
+static cx_allocator_class cx_mempool_pure_allocator_class = {
+    cx_mempool_malloc_pure,
+    cx_mempool_realloc_pure,
+    cx_mempool_calloc_pure,
+    cx_mempool_free_pure
+};
+
+static void cx_mempool_free_foreign(const struct cx_mempool_s *pool) {
+    for (size_t i = 0; i < pool->registered_size; i++) {
+        struct cx_mempool_foreign_memory_s info = pool->registered[i];
+        if (info.destr2_data == NULL) {
+            if (info.destr) {
+                info.destr(info.mem);
+            }
+        } else {
+            info.destr2(info.destr2_data, info.mem);
+        }
+    }
+}
+
+void cxMempoolFree(CxMempool *pool) {
+    if (pool == NULL) return;
+    if (pool->allocator->cl == &cx_mempool_simple_allocator_class) {
+        cx_mempool_free_all_simple(pool);
+    } else if (pool->allocator->cl == &cx_mempool_advanced_allocator_class) {
+        cx_mempool_free_all_advanced(pool);
+    } else {
+        cx_mempool_free_all_pure(pool);
+    }
+    cx_mempool_free_foreign(pool);
+    cxFree(pool->base_allocator, pool->data);
+    cxFree(pool->base_allocator, pool->registered);
+    cxFree(pool->base_allocator, (void*) pool->allocator);
+    cxFree(pool->base_allocator, pool);
 }
 
 void cxMempoolSetDestructor(
@@ -159,18 +484,26 @@ void cxMempoolSetDestructor(
     *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
 }
 
+void cxMempoolSetDestructor2(
+        void *ptr,
+        cx_destructor_func2 func,
+        void *data
+) {
+    struct cx_mempool_memory2_s *info =
+        (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
+    info->destructor = func;
+    info->data = data;
+}
+
 void cxMempoolRemoveDestructor(void *ptr) {
     *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = NULL;
 }
 
-struct cx_mempool_foreign_mem_s {
-    cx_destructor_func destr;
-    void* mem;
-};
-
-static void cx_mempool_destr_foreign_mem(void* ptr) {
-    struct cx_mempool_foreign_mem_s *fm = ptr;
-    fm->destr(fm->mem);
+void cxMempoolRemoveDestructor2(void *ptr) {
+    struct cx_mempool_memory2_s *info =
+        (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
+    info->destructor = NULL;
+    info->data = NULL;
 }
 
 int cxMempoolRegister(
@@ -178,60 +511,206 @@ int cxMempoolRegister(
         void *memory,
         cx_destructor_func destr
 ) {
-    struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc(
-            pool,
-            sizeof(struct cx_mempool_foreign_mem_s)
-    );
-    if (fm == NULL) return 1;
+    if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
+        return 1; // LCOV_EXCL_LINE
+    }
 
-    fm->mem = memory;
-    fm->destr = destr;
-    *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem;
+    pool->registered[pool->registered_size++] =
+        (struct cx_mempool_foreign_memory_s) {
+            .mem = memory,
+            .destr = destr,
+            .destr2_data = NULL
+        };
 
     return 0;
 }
 
-static cx_allocator_class cx_mempool_allocator_class = {
-        cx_mempool_malloc,
-        cx_mempool_realloc,
-        cx_mempool_calloc,
-        cx_mempool_free
-};
+int cxMempoolRegister2(
+        CxMempool *pool,
+        void *memory,
+        cx_destructor_func2 destr,
+        void *data
+) {
+    if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
+        return 1; // LCOV_EXCL_LINE
+    }
+
+    pool->registered[pool->registered_size++] =
+        (struct cx_mempool_foreign_memory_s) {
+            .mem = memory,
+            .destr2 = destr,
+            .destr2_data = data
+        };
+
+    return 0;
+}
 
 CxMempool *cxMempoolCreate(
         size_t capacity,
-        cx_destructor_func destr
+        enum cx_mempool_type type
 ) {
+    if (capacity == 0) capacity = 16;
     size_t poolsize;
-    if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) {
+    if (cx_szmul(capacity, sizeof(void*), &poolsize)) {
+        // LCOV_EXCL_START
         errno = EOVERFLOW;
         return NULL;
-    }
-
-    struct cx_mempool_s *pool =
-            malloc(sizeof(struct cx_mempool_s));
-    if (pool == NULL) return NULL;
+    }  // LCOV_EXCL_STOP
 
-    CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
+    CxAllocator *provided_allocator = cxMallocDefault(sizeof(CxAllocator));
     if (provided_allocator == NULL) { // LCOV_EXCL_START
-        free(pool);
         return NULL;
     } // LCOV_EXCL_STOP
-    provided_allocator->cl = &cx_mempool_allocator_class;
-    provided_allocator->data = pool;
 
+    CxMempool *pool = cxCallocDefault(1, sizeof(CxMempool));
+    if (pool == NULL) {  // LCOV_EXCL_START
+        cxFreeDefault(provided_allocator);
+        return NULL;
+    }  // LCOV_EXCL_STOP
+
+    provided_allocator->data = pool;
+    *((const CxAllocator**)&pool->base_allocator) = cxDefaultAllocator;
     pool->allocator = provided_allocator;
+    if (type == CX_MEMPOOL_TYPE_SIMPLE) {
+        provided_allocator->cl = &cx_mempool_simple_allocator_class;
+    } else if (type == CX_MEMPOOL_TYPE_ADVANCED) {
+        provided_allocator->cl = &cx_mempool_advanced_allocator_class;
+    } else {
+        provided_allocator->cl = &cx_mempool_pure_allocator_class;
+    }
 
-    pool->data = malloc(poolsize);
+    pool->data = cxMallocDefault(poolsize);
     if (pool->data == NULL) { // LCOV_EXCL_START
-        free(provided_allocator);
-        free(pool);
+        cxFreeDefault(provided_allocator);
+        cxFreeDefault(pool);
         return NULL;
     } // LCOV_EXCL_STOP
 
     pool->size = 0;
     pool->capacity = capacity;
-    pool->auto_destr = destr;
 
     return pool;
 }
+
+void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc) {
+    pool->destr = fnc;
+}
+
+void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data) {
+    pool->destr2 = fnc;
+    pool->destr2_data = data;
+}
+
+static void cx_mempool_free_transferred_allocator(void *base_al, void *al) {
+    cxFree(base_al, al);
+}
+
+int cxMempoolTransfer(
+        CxMempool *source,
+        CxMempool *dest
+) {
+    // safety checks
+    if (source == dest) return 1;
+    if (source->allocator->cl != dest->allocator->cl) return 1;
+    if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
+
+    // ensure enough capacity in the destination pool
+    if (cx_mempool_ensure_capacity(dest, dest->size + source->size)) {
+        return 1; // LCOV_EXCL_LINE
+    }
+    if (cx_mempool_ensure_registered_capacity(dest,
+            dest->registered_size + source->registered_size)) {
+        return 1; // LCOV_EXCL_LINE
+    }
+
+    // allocate a replacement allocator for the source pool
+    CxAllocator *new_source_allocator =
+        cxMalloc(source->base_allocator, sizeof(CxAllocator));
+    if (new_source_allocator == NULL) { // LCOV_EXCL_START
+        return 1;
+    } // LCOV_EXCL_STOP
+    new_source_allocator->cl = source->allocator->cl;
+    new_source_allocator->data = source;
+
+    // transfer all the data
+    memcpy(&dest->data[dest->size], source->data, sizeof(void*)*source->size);
+    dest->size += source->size;
+
+    // transfer all registered memory
+    memcpy(&dest->registered[dest->registered_size], source->registered,
+           sizeof(struct cx_mempool_foreign_memory_s) * source->size);
+    dest->registered_size += source->registered_size;
+
+    // register the old allocator with the new pool
+    // we have to remove const-ness for this, but that's okay here
+    // also register the base allocator, s.t. the pool knows how to free it
+    CxAllocator *transferred_allocator = (CxAllocator*) source->allocator;
+    transferred_allocator->data = dest;
+    cxMempoolRegister2(dest, transferred_allocator,
+        cx_mempool_free_transferred_allocator, (void*)source->base_allocator);
+
+    // prepare the source pool for re-use
+    source->allocator = new_source_allocator;
+    memset(source->data, 0, source->size * sizeof(void*));
+    memset(source->registered, 0,
+        source->registered_size * sizeof(struct cx_mempool_foreign_memory_s));
+    source->size = 0;
+    source->registered_size = 0;
+
+    return 0;
+}
+
+int cxMempoolTransferObject(
+        CxMempool *source,
+        CxMempool *dest,
+        const void *obj
+) {
+    // safety checks
+    if (source == dest) return 1;
+    if (source->allocator->cl != dest->allocator->cl) return 1;
+    if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
+
+    // search for the object
+    for (size_t i = 0; i < source->size; i++) {
+        struct cx_mempool_memory_s *mem = source->data[i];
+        if (mem->c == obj) {
+            // first, make sure that the dest pool can take the object
+            if (cx_mempool_ensure_capacity(dest, dest->size + 1)) {
+                return 1; // LCOV_EXCL_LINE
+            }
+            // remove from the source pool
+            size_t last_index = source->size - 1;
+            if (i != last_index) {
+                source->data[i] = source->data[last_index];
+                source->data[last_index] = NULL;
+            }
+            source->size--;
+            // add to the target pool
+            dest->data[dest->size++] = mem;
+            return 0;
+        }
+    }
+    // search in the registered objects
+    for (size_t i = 0; i < source->registered_size; i++) {
+        struct cx_mempool_foreign_memory_s *mem = &source->registered[i];
+        if (mem->mem == obj) {
+            // first, make sure that the dest pool can take the object
+            if (cx_mempool_ensure_registered_capacity(dest,
+                    dest->registered_size + 1)) {
+                return 1; // LCOV_EXCL_LINE
+            }
+            dest->registered[dest->registered_size++] = *mem;
+            // remove from the source pool
+            size_t last_index = source->registered_size - 1;
+            if (i != last_index) {
+                source->registered[i] = source->registered[last_index];
+                memset(&source->registered[last_index], 0,
+                    sizeof(struct cx_mempool_foreign_memory_s));
+            }
+            source->registered_size--;
+            return 0;
+        }
+    }
+    // not found
+    return 1;
+}
index bf691cf63008b6d53a57c5c90cb219ee87cc834e..9d18673aa7748f2a9660b31d6a00dfb34aac526e 100644 (file)
@@ -68,7 +68,7 @@ int cx_vfprintf(
         return (int) wfc(buf, 1, ret, stream);
     } else {
         int len = ret + 1;
-        char *newbuf = malloc(len);
+        char *newbuf = cxMallocDefault(len);
         if (!newbuf) { // LCOV_EXCL_START
             va_end(ap2);
             return -1;
@@ -79,7 +79,7 @@ int cx_vfprintf(
         if (ret > 0) {
             ret = (int) wfc(newbuf, 1, ret, stream);
         }
-        free(newbuf);
+        cxFreeDefault(newbuf);
     }
     return ret;
 }
@@ -121,7 +121,7 @@ cxmutstr cx_vasprintf_a(
         if (s.ptr) {
             ret = vsnprintf(s.ptr, len, fmt, ap2);
             if (ret < 0) {
-                free(s.ptr);
+                cxFree(a, s.ptr);
                 s.ptr = NULL;
             } else {
                 s.length = (size_t) ret;
@@ -132,7 +132,13 @@ cxmutstr cx_vasprintf_a(
     return s;
 }
 
-int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) {
+int cx_sprintf_a(
+        const CxAllocator *alloc,
+        char **str,
+        size_t *len,
+        const char *fmt,
+        ...
+) {
     va_list ap;
     va_start(ap, fmt);
     int ret = cx_vsprintf_a(alloc, str, len, fmt, ap);
@@ -140,7 +146,13 @@ int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, .
     return ret;
 }
 
-int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) {
+int cx_vsprintf_a(
+        const CxAllocator *alloc,
+        char **str,
+        size_t *len,
+        const char *fmt,
+        va_list ap
+) {
     va_list ap2;
     va_copy(ap2, ap);
     int ret = vsnprintf(*str, *len, fmt, ap);
@@ -162,7 +174,14 @@ int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt,
     return ret;
 }
 
-int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) {
+int cx_sprintf_sa(
+        const CxAllocator *alloc,
+        char *buf,
+        size_t *len,
+        char **str,
+        const char *fmt,
+        ...
+) {
     va_list ap;
     va_start(ap, fmt);
     int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap);
@@ -170,7 +189,14 @@ int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const
     return ret;
 }
 
-int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) {
+int cx_vsprintf_sa(
+        const CxAllocator *alloc,
+        char *buf,
+        size_t *len,
+        char **str,
+        const char *fmt,
+        va_list ap
+) {
     va_list ap2;
     va_copy(ap2, ap);
     int ret = vsnprintf(buf, *len, fmt, ap);
index 23f79b318a65c92d3ada6caa4edc5854bd9670a0..4593602c84a89162cdfedac781f412636550a192 100644 (file)
@@ -287,7 +287,7 @@ static int cx_properties_read_init_file(
         cx_attr_unused CxProperties *prop,
         CxPropertiesSource *src
 ) {
-    src->data_ptr = malloc(src->data_size);
+    src->data_ptr = cxMallocDefault(src->data_size);
     if (src->data_ptr == NULL) return 1;
     return 0;
 }
@@ -296,7 +296,7 @@ static void cx_properties_read_clean_file(
         cx_attr_unused CxProperties *prop,
         CxPropertiesSource *src
 ) {
-    free(src->data_ptr);
+    cxFreeDefault(src->data_ptr);
 }
 
 CxPropertiesSource cxPropertiesStringSource(cxstring str) {
index 2efc035dd336be4c87d34603afa3daabd1fd6402..bee37da64b61c4c5960fd17a60d55dab67663765 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #include "cx/streams.h"
+#include "cx/allocator.h"
 
 #ifndef CX_STREAM_BCOPY_BUF_SIZE
 #define CX_STREAM_BCOPY_BUF_SIZE 8192
@@ -57,7 +58,7 @@ size_t cx_stream_bncopy(
         lbuf = buf;
     } else {
         if (bufsize == 0) bufsize = CX_STREAM_BCOPY_BUF_SIZE;
-        lbuf = malloc(bufsize);
+        lbuf = cxMallocDefault(bufsize);
         if (lbuf == NULL) return 0;
     }
 
@@ -74,7 +75,7 @@ size_t cx_stream_bncopy(
     }
 
     if (lbuf != buf) {
-        free(lbuf);
+        cxFreeDefault(lbuf);
     }
 
     return ncp;
index 14b732e6d16623dc7798cb65dc9a02e061d7c0a3..61d88f35acd65dd9afe38320a519ca1a63c9ec03 100644 (file)
@@ -65,7 +65,7 @@ cxstring cx_strn(
 
 void cx_strfree(cxmutstr *str) {
     if (str == NULL) return;
-    free(str->ptr);
+    cxFreeDefault(str->ptr);
     str->ptr = NULL;
     str->length = 0;
 }
@@ -80,6 +80,22 @@ void cx_strfree_a(
     str->length = 0;
 }
 
+int cx_strcpy_a(
+        const CxAllocator *alloc,
+        cxmutstr *dest,
+        cxstring src
+) {
+    if (cxReallocate(alloc, &dest->ptr, src.length + 1)) {
+        return 1;
+    }
+
+    memcpy(dest->ptr, src.ptr, src.length);
+    dest->length = src.length;
+    dest->ptr[dest->length] = '\0';
+
+    return 0;
+}
+
 size_t cx_strlen(
         size_t count,
         ...
@@ -106,27 +122,16 @@ cxmutstr cx_strcat_ma(
         ...
 ) {
     if (count == 0) return str;
-
-    cxstring strings_stack[8];
-    cxstring *strings;
-    if (count > 8) {
-        strings = calloc(count, sizeof(cxstring));
-        if (strings == NULL) {
-            return (cxmutstr) {NULL, 0};
-        }
-    } else {
-        strings = strings_stack;
-    }
-
     va_list ap;
     va_start(ap, count);
+    va_list ap2;
+    va_copy(ap2, ap);
 
-    // get all args and overall length
+    // compute overall length
     bool overflow = false;
     size_t slen = str.length;
     for (size_t i = 0; i < count; i++) {
-        cxstring s = va_arg (ap, cxstring);
-        strings[i] = s;
+        cxstring s = va_arg(ap, cxstring);
         if (slen > SIZE_MAX - str.length) overflow = true;
         slen += s.length;
     }
@@ -134,10 +139,8 @@ cxmutstr cx_strcat_ma(
 
     // abort in case of overflow
     if (overflow) {
+        va_end(ap2);
         errno = EOVERFLOW;
-        if (strings != strings_stack) {
-            free(strings);
-        }
         return (cxmutstr) { NULL, 0 };
     }
 
@@ -149,9 +152,7 @@ cxmutstr cx_strcat_ma(
         newstr = cxRealloc(alloc, str.ptr, slen + 1);
     }
     if (newstr == NULL) {
-        if (strings != strings_stack) {
-            free(strings);
-        }
+        va_end(ap2);
         return (cxmutstr) {NULL, 0};
     }
     str.ptr = newstr;
@@ -160,19 +161,15 @@ cxmutstr cx_strcat_ma(
     size_t pos = str.length;
     str.length = slen;
     for (size_t i = 0; i < count; i++) {
-        cxstring s = strings[i];
+        cxstring s = va_arg(ap2, cxstring);
         memcpy(str.ptr + pos, s.ptr, s.length);
         pos += s.length;
     }
+    va_end(ap2);
 
     // terminate string
     str.ptr[str.length] = '\0';
 
-    // free temporary array
-    if (strings != strings_stack) {
-        free(strings);
-    }
-
     return str;
 }
 
@@ -289,8 +286,9 @@ cxstring cx_strstr(
     // check needle length and use appropriate prefix table
     // if the pattern exceeds static prefix table, allocate on the heap
     const bool useheap = needle.length >= CX_STRSTR_SBO_SIZE;
-    register size_t *ptable = useheap ? calloc(needle.length + 1,
-                                               sizeof(size_t)) : s_prefix_table;
+    register size_t *ptable = useheap
+        ? cxCallocDefault(needle.length + 1, sizeof(size_t))
+        : s_prefix_table;
 
     // keep counter in registers
     register size_t i, j;
@@ -328,7 +326,7 @@ cxstring cx_strstr(
 
     // if prefix table was allocated on the heap, free it
     if (useheap) {
-        free(ptable);
+        cxFreeDefault(ptable);
     }
 
     return result;
@@ -588,27 +586,6 @@ bool cx_strcasesuffix(
 #endif
 }
 
-#ifndef CX_STRREPLACE_INDEX_BUFFER_SIZE
-#define CX_STRREPLACE_INDEX_BUFFER_SIZE 64
-#endif
-
-struct cx_strreplace_ibuf {
-    size_t *buf;
-    struct cx_strreplace_ibuf *next;
-    unsigned int len;
-};
-
-static void cx_strrepl_free_ibuf(struct cx_strreplace_ibuf *buf) {
-    // remember, the first data is on the stack!
-    buf = buf->next;
-    while (buf) {
-        struct cx_strreplace_ibuf *next = buf->next;
-        free(buf->buf);
-        free(buf);
-        buf = next;
-    }
-}
-
 cxmutstr cx_strreplacen_a(
         const CxAllocator *allocator,
         cxstring str,
@@ -616,108 +593,60 @@ cxmutstr cx_strreplacen_a(
         cxstring replacement,
         size_t replmax
 ) {
-
-    if (search.length == 0 || search.length > str.length || replmax == 0)
+    // special cases
+    if (search.length == 0 || search.length > str.length || replmax == 0) {
         return cx_strdup_a(allocator, str);
-
-    // Compute expected buffer length
-    size_t ibufmax = str.length / search.length;
-    size_t ibuflen = replmax < ibufmax ? replmax : ibufmax;
-    if (ibuflen > CX_STRREPLACE_INDEX_BUFFER_SIZE) {
-        ibuflen = CX_STRREPLACE_INDEX_BUFFER_SIZE;
     }
 
-    // First index buffer can be on the stack
-    struct cx_strreplace_ibuf ibuf, *curbuf = &ibuf;
-    size_t ibuf_sbo[CX_STRREPLACE_INDEX_BUFFER_SIZE];
-    ibuf.buf = ibuf_sbo;
-    ibuf.next = NULL;
-    ibuf.len = 0;
+    size_t in_len = str.length;
+    size_t search_len = search.length;
+    size_t repl_len = replacement.length;
 
-    // Search occurrences
-    cxstring searchstr = str;
-    size_t found = 0;
-    do {
-        cxstring match = cx_strstr(searchstr, search);
-        if (match.length > 0) {
-            // Allocate next buffer in chain, if required
-            if (curbuf->len == ibuflen) {
-                struct cx_strreplace_ibuf *nextbuf =
-                        calloc(1, sizeof(struct cx_strreplace_ibuf));
-                if (!nextbuf) {
-                    cx_strrepl_free_ibuf(&ibuf);
-                    return cx_mutstrn(NULL, 0);
-                }
-                nextbuf->buf = calloc(ibuflen, sizeof(size_t));
-                if (!nextbuf->buf) {
-                    free(nextbuf);
-                    cx_strrepl_free_ibuf(&ibuf);
-                    return cx_mutstrn(NULL, 0);
-                }
-                curbuf->next = nextbuf;
-                curbuf = nextbuf;
-            }
-
-            // Record match index
-            found++;
-            size_t idx = match.ptr - str.ptr;
-            curbuf->buf[curbuf->len++] = idx;
-            searchstr.ptr = match.ptr + search.length;
-            searchstr.length = str.length - idx - search.length;
-        } else {
-            break;
-        }
-    } while (searchstr.length > 0 && found < replmax);
-
-    // Allocate result string
-    cxmutstr result;
-    {
-        long long adjlen = (long long) replacement.length - (long long) search.length;
-        size_t rcount = 0;
-        curbuf = &ibuf;
-        do {
-            rcount += curbuf->len;
-            curbuf = curbuf->next;
-        } while (curbuf);
-        result.length = str.length + rcount * adjlen;
-        result.ptr = cxMalloc(allocator, result.length + 1);
-        if (!result.ptr) {
-            cx_strrepl_free_ibuf(&ibuf);
-            return cx_mutstrn(NULL, 0);
-        }
+    // first run, count the occurrences
+    // and remember where the first is
+    size_t occurrences = 1;
+    cxstring first = cx_strstr(str, search);
+    if (first.length == 0) {
+        // special case, no replacements
+        return cx_strdup_a(allocator, str);
+    }
+    cxstring tmp = cx_strsubs(first, search_len);
+    while (occurrences < replmax &&
+            (tmp = cx_strstr(tmp, search)).length > 0) {
+        occurrences++;
+        tmp = cx_strsubs(tmp, search_len);
     }
 
-    // Build result string
-    curbuf = &ibuf;
-    size_t srcidx = 0;
-    char *destptr = result.ptr;
-    do {
-        for (size_t i = 0; i < curbuf->len; i++) {
-            // Copy source part up to next match
-            size_t idx = curbuf->buf[i];
-            size_t srclen = idx - srcidx;
-            if (srclen > 0) {
-                memcpy(destptr, str.ptr + srcidx, srclen);
-                destptr += srclen;
-                srcidx += srclen;
-            }
-
-            // Copy the replacement and skip the source pattern
-            srcidx += search.length;
-            memcpy(destptr, replacement.ptr, replacement.length);
-            destptr += replacement.length;
-        }
-        curbuf = curbuf->next;
-    } while (curbuf);
-    memcpy(destptr, str.ptr + srcidx, str.length - srcidx);
-
-    // Result is guaranteed to be zero-terminated
-    result.ptr[result.length] = '\0';
+    // calculate necessary memory
+    signed long long diff_len = (signed long long) repl_len - search_len;
+    size_t out_len = in_len + diff_len * occurrences;
+    cxmutstr out = {
+        cxMalloc(allocator, out_len + 1),
+        out_len
+    };
+    if (out.ptr == NULL) return out;
+
+    // second run: perform the replacements
+    // but start where we found the first occurrence
+    const char *inp = str.ptr;
+    tmp = first;
+    char *outp = out.ptr;
+    while (occurrences-- > 0 && (tmp = cx_strstr(tmp, search)).length > 0) {
+        size_t copylen = tmp.ptr - inp;
+        memcpy(outp, inp, copylen);
+        outp += copylen;
+        memcpy(outp, replacement.ptr, repl_len);
+        outp += repl_len;
+        inp += copylen + search_len;
+        tmp = cx_strsubs(tmp, search_len);
+    }
 
-    // Free index buffer
-    cx_strrepl_free_ibuf(&ibuf);
+    // add the remaining string
+    size_t copylen = in_len - (inp - str.ptr);
+    memcpy(outp, inp, copylen);
+    out.ptr[out_len] = '\0';
 
-    return result;
+    return out;
 }
 
 CxStrtokCtx cx_strtok_(
index 397f9087ad937e87293f0d07f16d065008ff7c82..1b2b38ec0174e02addefb4f3d15ccee36831095c 100644 (file)
@@ -226,14 +226,14 @@ int cx_tree_search(
         int ret_elem = sfunc(elem, node);
         if (ret_elem == 0) {
             // if found, exit the search
-            *result = (void *) elem;
+            *result = elem;
             ret = 0;
             break;
         } else if (ret_elem > 0 && ret_elem < ret) {
             // new distance is better
             *result = elem;
             ret = ret_elem;
-        } else {
+        } else if (ret_elem < 0 || ret_elem > ret) {
             // not contained or distance is worse, skip entire subtree
             cxTreeIteratorContinue(iter);
         }
@@ -305,12 +305,12 @@ static void cx_tree_iter_next(void *it) {
 
     if (children == NULL) {
         // search for the next node
-        void *next;
+        void *next = NULL;
         cx_tree_iter_search_next:
-        // check if there is a sibling
+        // check if there is a sibling, but only if we are not a (subtree-)root
         if (iter->exiting) {
             next = iter->node_next;
-        } else {
+        } else if (iter->depth > 1) {
             next = tree_next(iter->node);
             iter->node_next = next;
         }
@@ -326,7 +326,7 @@ static void cx_tree_iter_next(void *it) {
                     // invalidate the iterator and free the node stack
                     iter->node = iter->node_next = NULL;
                     iter->stack_capacity = iter->depth = 0;
-                    free(iter->stack);
+                    cxFreeDefault(iter->stack);
                     iter->stack = NULL;
                 } else {
                     // the parent node can be obtained from the top of stack
@@ -386,7 +386,7 @@ CxTreeIterator cx_tree_iterator(
     iter.node = root;
     if (root != NULL) {
         iter.stack_capacity = 16;
-        iter.stack = malloc(sizeof(void *) * 16);
+        iter.stack = cxMallocDefault(sizeof(void *) * 16);
         iter.stack[0] = root;
         iter.counter = 1;
         iter.depth = 1;
@@ -416,7 +416,7 @@ static void cx_tree_visitor_enqueue_siblings(
     node = tree_next(node);
     while (node != NULL) {
         struct cx_tree_visitor_queue_s *q;
-        q = malloc(sizeof(struct cx_tree_visitor_queue_s));
+        q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s));
         q->depth = iter->queue_last->depth;
         q->node = node;
         iter->queue_last->next = q;
@@ -445,7 +445,7 @@ static void cx_tree_visitor_next(void *it) {
     }
     if (children != NULL) {
         struct cx_tree_visitor_queue_s *q;
-        q = malloc(sizeof(struct cx_tree_visitor_queue_s));
+        q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s));
         q->depth = iter->depth + 1;
         q->node = children;
         if (iter->queue_last == NULL) {
@@ -474,7 +474,7 @@ static void cx_tree_visitor_next(void *it) {
             assert(iter->queue_last == q);
             iter->queue_last = NULL;
         }
-        free(q);
+        cxFreeDefault(q);
     }
 
     // increment the node counter
index 6905986c4862966add9767c8f85f99b28c33291b..ad5aad0f563cbf93f8b7de3d6e7ed169a9abf4a8 100644 (file)
@@ -33,15 +33,16 @@ OBJ_DIR = ../build/
 
 include common/objs.mk
 
-UI_LIB = ../build/lib/$(LIB_PREFIX)uitk$(LIB_EXT)
+UI_LIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
+UI_SHLIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(SHLIB_EXT)
 
 include $(TOOLKIT)/objs.mk
 OBJ = $(TOOLKITOBJS) $(COMMONOBJS)
 
-all: $(UI_LIB)
+all: $(UI_LIB) $(UI_SHLIB)
 
 include $(TOOLKIT)/Makefile
 
 $(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c
-       $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(TK_CFLAGS) $<
+       $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
 
diff --git a/ui/common/args.c b/ui/common/args.c
new file mode 100644 (file)
index 0000000..e799889
--- /dev/null
@@ -0,0 +1,1586 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "args.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "../ui/container.h"
+
+/* ---------------------------- UiMenuItemArgs ---------------------------- */
+
+UiMenuItemArgs* ui_menuitem_args_new(void) {
+    UiMenuItemArgs *args = malloc(sizeof(UiMenuItemArgs));
+    memset(args, 0, sizeof(UiMenuItemArgs));
+    return args;
+}
+
+void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid) {
+    args->stockid = strdup(stockid);
+}
+
+void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon) {
+    args->icon = strdup(icon);
+}
+
+void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback) {
+    args->onclick = callback;
+}
+
+void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) {
+    args->onclickdata = onclickdata;
+}
+
+void ui_menuitem_args_free(UiMenuItemArgs *args) {
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free(args);
+}
+
+
+/* ---------------------------- UiMenuToggleItemArgs ---------------------------- */
+
+UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void) {
+    UiMenuToggleItemArgs *args = malloc(sizeof(UiMenuToggleItemArgs));
+    memset(args, 0, sizeof(UiMenuToggleItemArgs));
+    return args;
+}
+
+void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid) {
+    args->stockid = strdup(stockid);
+}
+
+void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon) {
+    args->icon = strdup(icon);
+}
+
+void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback) {
+    args->onchange = callback;
+}
+
+void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onclickdata) {
+    args->onchangedata = onclickdata;
+}
+
+void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) {
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free((void*)args->varname);
+    free(args);
+}
+
+/* --------------------------- UiMenuItemListArgs --------------------------- */
+
+UiMenuItemListArgs* ui_menuitemlist_args_new(void) {
+    UiMenuItemListArgs *args = malloc(sizeof(UiMenuItemListArgs));
+    memset(args, 0, sizeof(UiMenuItemListArgs));
+    return args;
+}
+
+void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func) {
+    args->getvalue = func;
+}
+
+void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback) {
+    args->onselect = callback;
+}
+
+void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data){
+    args->onselectdata = data;
+}
+
+void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value) {
+    args->addseparator = value;
+}
+
+void ui_menuitemlist_args_free(UiMenuItemListArgs *args){
+    free((void*)args->varname);
+    free(args);
+}
+
+/* --------------------------- UiToolbarItemArgs --------------------------- */
+
+UiToolbarItemArgs* ui_toolbar_item_args_new(void) {
+    UiToolbarItemArgs *args = malloc(sizeof(UiToolbarItemArgs));
+    memset(args, 0, sizeof(UiToolbarItemArgs));
+    return args;
+}
+
+void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid) {
+    args->stockid = strdup(stockid);
+}
+
+void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon) {
+    args->icon = strdup(icon);
+}
+
+void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback) {
+    args->onclick = callback;
+}
+
+void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata) {
+    args->onclickdata = onclickdata;
+}
+
+void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *groups) {
+    // TODO
+}
+void ui_toolbar_item_args_free(UiToolbarItemArgs *args) {
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free(args);
+}
+
+/* ---------------------------- UiToolbarToggleItemArgs ---------------------------- */
+
+UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void) {
+    UiToolbarToggleItemArgs *args = malloc(sizeof(UiToolbarToggleItemArgs));
+    memset(args, 0, sizeof(UiToolbarToggleItemArgs));
+    return args;
+}
+
+
+void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+
+void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid) {
+    args->stockid = strdup(stockid);
+}
+
+
+void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon) {
+    args->icon = strdup(icon);
+}
+
+
+void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+
+void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback) {
+    args->onchange = callback;
+}
+
+
+void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata) {
+    args->onchangedata = onchangedata;
+}
+
+
+void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *groups) {
+    // TODO
+}
+
+
+void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free((void*)args->varname);
+    free(args);
+}
+
+/* ---------------------------- UiToolbarMenuArgs ---------------------------- */
+
+
+UiToolbarMenuArgs* ui_toolbar_menu_args_new(void) {
+    UiToolbarMenuArgs *args = malloc(sizeof(UiToolbarMenuArgs));
+    memset(args, 0, sizeof(UiToolbarMenuArgs));
+    return args;
+}
+
+
+void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+
+void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid) {
+    args->stockid = strdup(stockid);
+}
+
+
+void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon) {
+    args->icon = strdup(icon);
+}
+
+
+void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args) {
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free(args);
+}
+
+
+/* ---------------------------- UiContainerArgs ---------------------------- */
+
+UiContainerArgs* ui_container_args_new(void) {
+    UiContainerArgs *args = malloc(sizeof(UiContainerArgs));
+    memset(args, 0, sizeof(UiContainerArgs));
+    return args;
+}
+
+void ui_container_args_set_fill(UiContainerArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_container_args_set_hexpand(UiContainerArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_container_args_set_vexpand(UiContainerArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_container_args_set_hfill(UiContainerArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_container_args_set_vfill(UiContainerArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_container_args_set_override_defaults(UiContainerArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_container_args_set_colspan(UiContainerArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value) {
+    args->def_hexpand = value;
+}
+
+
+void ui_container_args_set_def_vexpand(UiContainerArgs *args, UiBool value) {
+    args->def_vexpand = value;
+}
+
+
+void ui_container_args_set_def_hfill(UiContainerArgs *args, UiBool value) {
+    args->def_hfill = value;
+}
+
+
+void ui_container_args_set_def_vfill(UiContainerArgs *args, UiBool value) {
+    args->def_vfill = value;
+}
+
+
+void ui_container_args_set_name(UiContainerArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_container_args_set_style_class(UiContainerArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+
+void ui_container_args_set_margin(UiContainerArgs *args, int value) {
+    args->margin = value;
+}
+
+
+void ui_container_args_set_spacing(UiContainerArgs *args, int value) {
+    args->spacing = value;
+}
+
+
+void ui_container_args_set_columnspacing(UiContainerArgs *args, int value) {
+    args->columnspacing = value;
+}
+
+
+void ui_container_args_set_rowspacing(UiContainerArgs *args, int value) {
+    args->rowspacing = value;
+}
+
+
+void ui_container_args_free(UiContainerArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free(args);
+}
+
+
+/* ------------------------------- UiFrameArgs ------------------------------*/
+
+UiFrameArgs* ui_frame_args_new(void) {
+    UiFrameArgs *args = malloc(sizeof(UiFrameArgs));
+    memset(args, 0, sizeof(UiContainerArgs));
+    return args;
+}
+
+
+void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_frame_args_set_hexpand(UiFrameArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_frame_args_set_vexpand(UiFrameArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_frame_args_set_hfill(UiFrameArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_frame_args_set_vfill(UiFrameArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_frame_args_set_rowspan(UiFrameArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_frame_args_set_name(UiFrameArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+
+void ui_frame_args_set_margin(UiFrameArgs *args, int value) {
+    args->margin = value;
+}
+
+
+void ui_frame_args_set_spacing(UiFrameArgs *args, int value) {
+    args->spacing = value;
+}
+
+
+void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value) {
+    args->columnspacing = value;
+}
+
+
+void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value) {
+    args->rowspacing = value;
+}
+
+
+void ui_frame_args_set_expanded(UiFrameArgs *args, UiBool value) {
+    args->isexpanded = value;
+}
+
+
+void ui_frame_args_set_label(UiFrameArgs *args, const char *label) {
+    args->label = strdup(label);
+}
+
+
+void ui_frame_args_free(UiFrameArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->label);
+    free(args);
+}
+
+
+/* ---------------------------- UiSidebarArgs -------------------------------*/
+
+UiSidebarArgs* ui_sidebar_args_new(void) {
+    UiSidebarArgs *args = malloc(sizeof(UiSidebarArgs));
+    memset(args, 0, sizeof(UiSidebarArgs));
+    return args;
+}
+
+
+void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+
+void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value) {
+    args->margin = value;
+}
+
+
+void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value) {
+    args->spacing = value;
+}
+
+
+void ui_sidebar_args_free(UiSidebarArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free(args);
+}
+
+
+/* --------------------------- UiSplitPaneArgs ------------------------------*/
+
+UiSplitPaneArgs* ui_splitpane_args_new(void) {
+    UiSplitPaneArgs *args = malloc(sizeof(UiSplitPaneArgs));
+    memset(args, 0, sizeof(UiSplitPaneArgs));
+    return args;
+}
+
+
+void ui_splitpane_args_set_fill(UiSplitPaneArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_splitpane_args_set_hexpand(UiSplitPaneArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+
+void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value) {
+    args->margin = value;
+}
+
+
+void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value) {
+    args->spacing = value;
+}
+
+
+void ui_splitpane_args_set_columnspacing(UiSplitPaneArgs *args, int value) {
+    args->columnspacing = value;
+}
+
+
+void ui_splitpane_args_set_rowspacing(UiSplitPaneArgs *args, int value) {
+    args->rowspacing = value;
+}
+
+
+void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos) {
+    args->initial_position = pos;
+}
+
+
+void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+
+void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value) {
+    args->value = value;
+}
+
+void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max) {
+    args->max_panes = max;
+}
+
+
+void ui_splitpane_args_free(UiSplitPaneArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free(args);
+}
+
+
+/* ------------------------- UiLabelArgs ----------------------------*/
+
+
+UiLabelArgs* ui_label_args_new(void) {
+    UiLabelArgs *args = malloc(sizeof(UiLabelArgs));
+    memset(args, 0, sizeof(UiLabelArgs));
+    return args;
+}
+
+
+void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_label_args_set_colspan(UiLabelArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_label_args_set_name(UiLabelArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_label_args_set_style_class(UiLabelArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_label_args_set_label(UiLabelArgs *args, const char *label){
+    args->label = strdup(label);
+}
+
+
+void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align) {
+    args->align = align;
+}
+
+void ui_label_args_set_style(UiLabelArgs *args, UiLabelStyle style) {
+    args->style = style;
+}
+
+void ui_label_args_set_varname(UiLabelArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_label_args_set_value(UiLabelArgs *args, UiString *value) {
+    args->value = value;
+}
+
+void ui_label_args_free(UiLabelArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->label);
+    free((void*)args->varname);
+    free(args);
+}
+
+
+/* ------------------------- UiProgressbarArgs ----------------------------*/
+
+
+UiProgressbarArgs* ui_progressbar_args_new(void) {
+    UiProgressbarArgs *args = malloc(sizeof(UiProgressbarArgs));
+    memset(args, 0, sizeof(UiProgressbarArgs));
+    return args;
+}
+
+
+void ui_progressbar_args_set_fill(UiProgressbarArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_progressbar_args_set_hexpand(UiProgressbarArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_progressbar_args_set_vexpand(UiProgressbarArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_progressbar_args_set_hfill(UiProgressbarArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_progressbar_args_set_vfill(UiProgressbarArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_progressbar_args_set_rowspan(UiProgressbarArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_progressbar_args_set_name(UiProgressbarArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_progressbar_args_set_style_class(UiProgressbarArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_progressbar_args_set_min(UiProgressbarArgs *args, double min) {
+    args->min = min;
+}
+
+void ui_progressbar_args_set_max(UiProgressbarArgs *args, double max) {
+    args->max = max;
+}
+
+void ui_progressbar_args_set_varname(UiProgressbarArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value) {
+    args->value = value;
+}
+
+void ui_progressbar_args_free(UiProgressbarArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free(args);
+}
+
+
+/* ------------------------- UiProgressbarSpinnerArgs ----------------------------*/
+
+UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void) {
+    UiProgressbarSpinnerArgs *args = malloc(sizeof(UiProgressbarSpinnerArgs));
+    memset(args, 0, sizeof(UiProgressbarSpinnerArgs));
+    return args;
+}
+
+void ui_progress_spinner_args_set_fill(UiProgressbarSpinnerArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_progress_spinner_args_set_hexpand(UiProgressbarSpinnerArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+void ui_progress_spinner_args_set_vexpand(UiProgressbarSpinnerArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+void ui_progress_spinner_args_set_hfill(UiProgressbarSpinnerArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+void ui_progress_spinner_args_set_vfill(UiProgressbarSpinnerArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+void ui_progress_spinner_args_set_rowspan(UiProgressbarSpinnerArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+void ui_progress_spinner_args_set_style_class(UiProgressbarSpinnerArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_progress_spinner_args_set_varname(UiProgressbarSpinnerArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiInteger *value) {
+    args->value = value;
+}
+
+void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free(args);
+}
+
+
+/* ---------------------------- UiButtonArgs -------------------------------*/
+
+UiButtonArgs* ui_button_args_new(void) {
+    UiButtonArgs *args = malloc(sizeof(UiButtonArgs));
+    memset(args, 0, sizeof(UiButtonArgs));
+    return args;
+}
+
+
+void ui_button_args_set_fill(UiButtonArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_button_args_set_hexpand(UiButtonArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_button_args_set_colspan(UiButtonArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_button_args_set_name(UiButtonArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_button_args_set_label(UiButtonArgs *args, const char *label){
+    args->label = strdup(label);
+}
+
+
+void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid){
+    args->stockid = strdup(stockid);
+}
+
+
+void ui_button_args_set_icon(UiButtonArgs *args, const char *icon){
+    args->icon = strdup(icon);
+}
+
+
+void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype){
+    args->labeltype = labeltype;
+}
+
+void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback){
+    args->onclick = callback;
+}
+
+
+void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
+    args->onclickdata = onclickdata;
+}
+
+void ui_button_args_set_groups(UiButtonArgs *args, int *groups){
+    // TODO
+}
+
+void ui_button_args_free(UiButtonArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free((void*)args->groups);
+    free(args);
+}
+
+
+/* ------------------------- UiToggleArgs ----------------------------*/
+
+
+UiToggleArgs* ui_toggle_args_new(void) {
+    UiToggleArgs *args = malloc(sizeof(UiToggleArgs));
+    memset(args, 0, sizeof(UiToggleArgs));
+    return args;
+}
+
+
+void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_toggle_args_set_name(UiToggleArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_toggle_args_set_label(UiToggleArgs *args, const char *label){
+    args->label = strdup(label);
+}
+
+
+void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid){
+    args->stockid = strdup(stockid);
+}
+
+
+void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon){
+    args->icon = strdup(icon);
+}
+
+
+void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype){
+    args->labeltype = labeltype;
+}
+
+void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback){
+    args->onchange = callback;
+}
+
+
+void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
+    args->onchangedata = onchangedata;
+}
+
+void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value) {
+    args->value = value;
+}
+
+void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group) {
+    args->enable_group = group;
+}
+
+void ui_toggle_args_set_groups(UiToggleArgs *args, int *groups){
+    // TODO
+}
+
+void ui_toggle_args_free(UiToggleArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->label);
+    free((void*)args->stockid);
+    free((void*)args->icon);
+    free((void*)args->varname);
+    free((void*)args->groups);
+    free(args);
+}
+
+
+/* ------------------------- UiListArgs ----------------------------*/
+
+UiListArgs* ui_list_args_new(void) {
+    UiListArgs *args = malloc(sizeof(UiListArgs));
+    memset(args, 0, sizeof(UiListArgs));
+    return args;
+}
+
+void ui_list_args_set_fill(UiListArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_list_args_set_hexpand(UiListArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+void ui_list_args_set_vexpand(UiListArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+void ui_list_args_set_hfill(UiListArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+void ui_list_args_set_vfill(UiListArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+void ui_list_args_set_colspan(UiListArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+void ui_list_args_set_rowspan(UiListArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+void ui_list_args_set_name(UiListArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+void ui_list_args_set_style_class(UiListArgs *args, const char *classname) {
+    args->style_class = classname;
+}
+
+void ui_list_args_set_varname(UiListArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_list_args_set_value(UiListArgs *args, UiList *value) {
+    args->list = value;
+}
+
+void ui_list_args_set_model(UiListArgs *args, UiModel *model) {
+    args->model = model;
+}
+
+void ui_list_args_set_static_elements(UiListArgs *args, char **strarray, size_t nelm) {
+    char **array = calloc(nelm, sizeof(char*));
+    for(int i=0;i<nelm;i++) {
+        array[i] = strdup(strarray[i]);
+    }
+    args->static_elements = array;
+    args->static_nelm = nelm;
+}
+
+void ui_list_args_set_getvalue_func(UiListArgs *args, ui_getvaluefunc getvalue) {
+    args->getvalue = getvalue;
+}
+
+void ui_list_args_set_getvalue_func2(UiListArgs *args, ui_getvaluefunc2 getvalue) {
+    args->getvalue2 = getvalue;
+}
+
+void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata) {
+    args->getvalue2data = userdata;
+}
+
+void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback) {
+    args->onactivate = callback;
+}
+
+void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata) {
+    args->onactivatedata = userdata;
+}
+
+void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback) {
+    args->onselection = callback;
+}
+
+void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata) {
+    args->onselectiondata = userdata;
+}
+
+void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback) {
+    args->ondragstart = callback;
+}
+
+void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata) {
+    args->ondragstartdata = userdata;
+}
+
+void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback) {
+    args->ondragcomplete = callback;
+}
+
+void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata) {
+    args->ondragcompletedata = userdata;
+}
+
+void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback) {
+    args->ondrop = callback;
+}
+
+void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata) {
+    args->ondropdata = userdata;
+}
+
+void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection) {
+    args->multiselection = multiselection;
+}
+
+void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder) {
+    args->contextmenu = menubuilder;
+}
+
+void ui_list_args_set_groups(UiListArgs *args, int *groups) {
+    // TODO
+}
+
+void ui_list_args_free(UiListArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    if(args->static_elements) {
+        for(int i=0;i<args->static_nelm;i++) {
+            free(args->static_elements[i]);
+        }
+        free(args->static_elements);
+    }
+    free(args);
+}
+
+
+
+/* ---------------------- SurceList ------------------------------------- */
+
+UiSourceListArgs* ui_sourcelist_args_new(void) {
+    UiSourceListArgs *args = malloc(sizeof(UiSourceListArgs));
+    memset(args, 0, sizeof(UiSourceListArgs));
+    return args;
+}
+
+
+void ui_sourcelist_args_set_fill(UiSourceListArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_sourcelist_args_set_hexpand(UiSourceListArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_sourcelist_args_set_vexpand(UiSourceListArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_sourcelist_args_set_hfill(UiSourceListArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_sourcelist_args_set_vfill(UiSourceListArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_sourcelist_args_set_rowspan(UiSourceListArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_sourcelist_args_set_name(UiSourceListArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_sourcelist_args_set_style_class(UiSourceListArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+UIEXPORT void ui_sourcelist_args_set_static_sublists(UiSourceListArgs *args, UiSubList *sublists, size_t numsublists) {
+    args->sublists = calloc(numsublists, sizeof(UiSubList));
+    memcpy(args->sublists, sublists, numsublists * sizeof(UiSubList));
+    args->numsublists = numsublists;
+}
+
+void ui_sourcelist_args_set_varname(UiSourceListArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+
+void ui_sourcelist_args_set_dynamic_sublists(UiSourceListArgs *args, UiList *value) {
+    args->dynamic_sublist = value;
+}
+
+
+void ui_sourcelist_args_set_getvalue_func(UiSourceListArgs *args, ui_sublist_getvalue_func getvalue) {
+    args->getvalue = getvalue;
+}
+
+void ui_sourcelist_args_set_getvalue_userdata(UiSourceListArgs *args, void *userdata) {
+    args->getvaluedata = userdata;
+}
+
+void ui_sourcelist_args_set_onactivate(UiSourceListArgs *args, ui_callback callback) {
+    args->onactivate = callback;
+}
+
+
+void ui_sourcelist_args_set_onactivatedata(UiSourceListArgs *args, void *userdata) {
+    args->onactivatedata = userdata;
+}
+
+
+void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback callback) {
+    args->onbuttonclick = callback;
+    
+}
+
+
+void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata) {
+    args->onbuttonclickdata = userdata;
+}
+
+
+void ui_sourcelist_args_free(UiSourceListArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free((void*)args->sublists);
+    free(args);
+}
+
+
+/* ------------------------- UiTextAreaArgs ----------------------------*/
+
+UiTextAreaArgs* ui_textarea_args_new(void) {
+    UiTextAreaArgs *args = malloc(sizeof(UiTextAreaArgs));
+    memset(args, 0, sizeof(UiTextAreaArgs));
+    return args;
+}
+
+
+void ui_textarea_args_set_fill(UiTextAreaArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_textarea_args_set_hexpand(UiTextAreaArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_textarea_args_set_vexpand(UiTextAreaArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_textarea_args_set_hfill(UiTextAreaArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_textarea_args_set_vfill(UiTextAreaArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_textarea_args_set_rowspan(UiTextAreaArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback){
+    args->onchange = callback;
+}
+
+
+void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata){
+    args->onchangedata = onchangedata;
+}
+
+void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value) {
+    args->value = value;
+}
+
+void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *groups){
+    // TODO
+}
+
+void ui_textarea_args_free(UiTextAreaArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free((void*)args->groups);
+    free(args);
+}
+
+
+
+/* ------------------------- UiTextFieldArgs ----------------------------*/
+
+UiTextFieldArgs* ui_textfield_args_new(void) {
+    UiTextFieldArgs *args = malloc(sizeof(UiTextFieldArgs));
+    memset(args, 0, sizeof(UiTextFieldArgs));
+    return args;
+}
+
+
+void ui_textfield_args_set_fill(UiTextFieldArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_textfield_args_set_hexpand(UiTextFieldArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_textfield_args_set_vexpand(UiTextFieldArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_textfield_args_set_hfill(UiTextFieldArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_textfield_args_set_vfill(UiTextFieldArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_textfield_args_set_rowspan(UiTextFieldArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_textfield_args_set_name(UiTextFieldArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_textfield_args_set_style_class(UiTextFieldArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback callback){
+    args->onchange = callback;
+}
+
+
+void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata){
+    args->onchangedata = onchangedata;
+}
+
+void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback){
+    args->onactivate = callback;
+}
+
+
+void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata){
+    args->onactivatedata = onactivatedata;
+}
+
+void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value) {
+    args->value = value;
+}
+
+void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *groups){
+    // TODO
+}
+
+void ui_textfield_args_free(UiTextFieldArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free((void*)args->groups);
+    free(args);
+}
+
+
+/* ------------------------- UiWebviewArgs ----------------------------*/
+
+UiWebviewArgs* ui_webview_args_new(void) {
+    UiWebviewArgs *args = malloc(sizeof(UiWebviewArgs));
+    memset(args, 0, sizeof(UiWebviewArgs));
+    return args;
+}
+
+
+void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill) {
+    args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_webview_args_set_hexpand(UiWebviewArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+
+void ui_webview_args_set_vexpand(UiWebviewArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+
+void ui_webview_args_set_hfill(UiWebviewArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+
+void ui_webview_args_set_vfill(UiWebviewArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+
+void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+
+void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+
+void ui_webview_args_set_rowspan(UiWebviewArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_webview_args_set_name(UiWebviewArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+
+void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value) {
+    args->value = value;
+}
+
+void ui_webview_args_set_groups(UiWebviewArgs *args, int *groups){
+    // TODO
+}
+
+void ui_webview_args_free(UiWebviewArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->varname);
+    free((void*)args->groups);
+    free(args);
+}
+
diff --git a/ui/common/args.h b/ui/common/args.h
new file mode 100644 (file)
index 0000000..04e7063
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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_ARGS_H
+#define UIC_ARGS_H
+
+#include "../ui/container.h"
+#include "../ui/display.h"
+#include "../ui/button.h"
+#include "../ui/menu.h"
+#include "../ui/toolbar.h"
+#include "../ui/tree.h"
+#include "../ui/text.h"
+#include "../ui/webview.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    
+UIEXPORT UiMenuItemArgs* ui_menuitem_args_new(void);
+UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label);
+UIEXPORT void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid);
+UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon);
+UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback);
+UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata);
+UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args);
+
+UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void);
+UIEXPORT void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *label);
+UIEXPORT void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid);
+UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname);
+UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback);
+UIEXPORT void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args);
+
+UIEXPORT UiMenuItemListArgs* ui_menuitemlist_args_new(void);
+UIEXPORT void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname);
+UIEXPORT void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func);
+UIEXPORT void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback);
+UIEXPORT void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data);
+UIEXPORT void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value);
+UIEXPORT void ui_menuitemlist_args_free(UiMenuItemListArgs *args);
+
+UIEXPORT UiToolbarItemArgs* ui_toolbar_item_args_new(void);
+UIEXPORT void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback);
+UIEXPORT void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata);
+UIEXPORT void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *groups);
+UIEXPORT void ui_toolbar_item_args_free(UiToolbarItemArgs *args);
+
+UIEXPORT UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void);
+UIEXPORT void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname);
+UIEXPORT void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback);
+UIEXPORT void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *groups);
+UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
+
+UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
+UIEXPORT void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label);
+UIEXPORT void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args);
+    
+UIEXPORT UiContainerArgs* ui_container_args_new(void);
+UIEXPORT void ui_container_args_set_fill(UiContainerArgs *args, UiBool fill);
+UIEXPORT void ui_container_args_set_hexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_vexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_hfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_vfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_override_defaults(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_colspan(UiContainerArgs *args, int colspan);
+UIEXPORT void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan);
+UIEXPORT void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_def_vexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_def_hfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_def_vfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_name(UiContainerArgs *args, const char *name);
+UIEXPORT void ui_container_args_set_style_class(UiContainerArgs *args, const char *classname);
+UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_spacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_columnspacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_rowspacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_free(UiContainerArgs *args);
+    
+
+UIEXPORT UiFrameArgs* ui_frame_args_new(void);
+UIEXPORT void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill);
+UIEXPORT void ui_frame_args_set_hexpand(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_vexpand(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_hfill(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_vfill(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan);
+UIEXPORT void ui_frame_args_set_rowspan(UiFrameArgs *args, int rowspan);
+UIEXPORT void ui_frame_args_set_name(UiFrameArgs *args, const char *name);
+UIEXPORT void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname);
+UIEXPORT void ui_frame_args_set_margin(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_spacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_expanded(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_label(UiFrameArgs *args, const char *label);
+UIEXPORT void ui_frame_args_free(UiFrameArgs *args);
+
+UIEXPORT UiSidebarArgs* ui_sidebar_args_new(void);
+UIEXPORT void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name);
+UIEXPORT void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname);
+UIEXPORT void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_free(UiSidebarArgs *args);
+
+UIEXPORT UiSplitPaneArgs* ui_splitpane_args_new(void);
+UIEXPORT void ui_splitpane_args_set_fill(UiSplitPaneArgs *args, UiBool fill);
+UIEXPORT void ui_splitpane_args_set_hexpand(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan);
+UIEXPORT void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan);
+UIEXPORT void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name);
+UIEXPORT void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname);
+UIEXPORT void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_columnspacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_rowspacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos);
+UIEXPORT void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname);
+UIEXPORT void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value);
+UIEXPORT void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max);
+UIEXPORT void ui_splitpane_args_free(UiSplitPaneArgs *args);
+
+UIEXPORT UiLabelArgs* ui_label_args_new(void);
+UIEXPORT void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill);
+UIEXPORT void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_colspan(UiLabelArgs *args, int colspan);
+UIEXPORT void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan);
+UIEXPORT void ui_label_args_set_name(UiLabelArgs *args, const char *name);
+UIEXPORT void ui_label_args_set_style_class(UiLabelArgs *args, const char *classname);
+UIEXPORT void ui_label_args_set_label(UiLabelArgs *args, const char *label);
+UIEXPORT void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align);
+UIEXPORT void ui_label_args_set_style(UiLabelArgs *args, UiLabelStyle style);
+UIEXPORT void ui_label_args_set_value(UiLabelArgs *args, UiString *value);
+UIEXPORT void ui_label_args_set_varname(UiLabelArgs *args, const char *varname);
+UIEXPORT void ui_label_args_free(UiLabelArgs *args);
+
+UIEXPORT UiProgressbarArgs* ui_progressbar_args_new(void);
+UIEXPORT void ui_progressbar_args_set_fill(UiProgressbarArgs *args, UiBool fill);
+UIEXPORT void ui_progressbar_args_set_hexpand(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_vexpand(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_hfill(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_vfill(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan);
+UIEXPORT void ui_progressbar_args_set_rowspan(UiProgressbarArgs *args, int rowspan);
+UIEXPORT void ui_progressbar_args_set_name(UiProgressbarArgs *args, const char *name);
+UIEXPORT void ui_progressbar_args_set_style_class(UiProgressbarArgs *args, const char *classname);
+UIEXPORT void ui_progressbar_args_set_min(UiProgressbarArgs *args, double min);
+UIEXPORT void ui_progressbar_args_set_max(UiProgressbarArgs *args, double max);
+UIEXPORT void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value);
+UIEXPORT void ui_progressbar_args_set_varname(UiProgressbarArgs *args, const char *varname);
+UIEXPORT void ui_progressbar_args_free(UiProgressbarArgs *args);
+
+UIEXPORT UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void);
+UIEXPORT void ui_progress_spinner_args_set_fill(UiProgressbarSpinnerArgs *args, UiBool fill);
+UIEXPORT void ui_progress_spinner_args_set_hexpand(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_vexpand(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_hfill(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_vfill(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan);
+UIEXPORT void ui_progress_spinner_args_set_rowspan(UiProgressbarSpinnerArgs *args, int rowspan);
+UIEXPORT void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, const char *name);
+UIEXPORT void ui_progress_spinner_args_set_style_class(UiProgressbarSpinnerArgs *args, const char *classname);
+UIEXPORT void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiInteger *value);
+UIEXPORT void ui_progress_spinner_args_set_varname(UiProgressbarSpinnerArgs *args, const char *varname);
+UIEXPORT void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args);
+
+UIEXPORT UiButtonArgs* ui_button_args_new(void);
+UIEXPORT void ui_button_args_set_fill(UiButtonArgs *args, UiBool fill);
+UIEXPORT void ui_button_args_set_hexpand(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_colspan(UiButtonArgs *args, int colspan);
+UIEXPORT void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan);
+UIEXPORT void ui_button_args_set_name(UiButtonArgs *args, const char *name);
+UIEXPORT void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname);
+UIEXPORT void ui_button_args_set_label(UiButtonArgs *args, const char *label);
+UIEXPORT void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid);
+UIEXPORT void ui_button_args_set_icon(UiButtonArgs *args, const char *icon);
+UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype);
+UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback);
+UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata);
+UIEXPORT void ui_button_args_set_groups(UiButtonArgs *args, int *groups);
+UIEXPORT void ui_button_args_free(UiButtonArgs *args);
+
+UIEXPORT UiToggleArgs* ui_toggle_args_new(void);
+UIEXPORT void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill);
+UIEXPORT void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan);
+UIEXPORT void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan);
+UIEXPORT void ui_toggle_args_set_name(UiToggleArgs *args, const char *name);
+UIEXPORT void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname);
+UIEXPORT void ui_toggle_args_set_label(UiToggleArgs *args, const char *label);
+UIEXPORT void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid);
+UIEXPORT void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon);
+UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype);
+UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback);
+UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
+UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname);
+UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value);
+UIEXPORT void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group);
+UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *groups);
+UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
+
+UIEXPORT UiListArgs* ui_list_args_new(void);
+UIEXPORT void ui_list_args_set_fill(UiListArgs *args, UiBool fill);
+UIEXPORT void ui_list_args_set_hexpand(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_vexpand(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_hfill(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_vfill(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_colspan(UiListArgs *args, int colspan);
+UIEXPORT void ui_list_args_set_rowspan(UiListArgs *args, int rowspan);
+UIEXPORT void ui_list_args_set_name(UiListArgs *args, const char *name);
+UIEXPORT void ui_list_args_set_style_class(UiListArgs *args, const char *classname);
+UIEXPORT void ui_list_args_set_varname(UiListArgs *args, const char *varname);
+UIEXPORT void ui_list_args_set_value(UiListArgs *args, UiList *value);
+UIEXPORT void ui_list_args_set_model(UiListArgs *args, UiModel *model);
+UIEXPORT void ui_list_args_set_static_elements(UiListArgs *args, char **strarray, size_t nelm);
+UIEXPORT void ui_list_args_set_getvalue_func(UiListArgs *args, ui_getvaluefunc getvalue);
+UIEXPORT void ui_list_args_set_getvalue_func2(UiListArgs *args, ui_getvaluefunc2 getvalue);
+UIEXPORT void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection);
+UIEXPORT void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder);
+UIEXPORT void ui_list_args_set_groups(UiListArgs *args, int *groups);
+UIEXPORT void ui_list_args_free(UiListArgs *args);
+
+UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void);
+UIEXPORT void ui_sourcelist_args_set_fill(UiSourceListArgs *args, UiBool fill);
+UIEXPORT void ui_sourcelist_args_set_hexpand(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_vexpand(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_hfill(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_vfill(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan);
+UIEXPORT void ui_sourcelist_args_set_rowspan(UiSourceListArgs *args, int rowspan);
+UIEXPORT void ui_sourcelist_args_set_name(UiSourceListArgs *args, const char *name);
+UIEXPORT void ui_sourcelist_args_set_style_class(UiSourceListArgs *args, const char *classname);
+UIEXPORT void ui_sourcelist_args_set_static_sublists(UiSourceListArgs *args, UiSubList *sublists, size_t numsublists);
+UIEXPORT void ui_sourcelist_args_set_varname(UiSourceListArgs *args, const char *varname);
+UIEXPORT void ui_sourcelist_args_set_dynamic_sublists(UiSourceListArgs *args, UiList *value);
+UIEXPORT void ui_sourcelist_args_set_getvalue_func(UiSourceListArgs *args, ui_sublist_getvalue_func getvalue);
+UIEXPORT void ui_sourcelist_args_set_getvalue_userdata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_set_onactivate(UiSourceListArgs *args, ui_callback callback);
+UIEXPORT void ui_sourcelist_args_set_onactivatedata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback callback);
+UIEXPORT void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_free(UiSourceListArgs *args);
+
+UIEXPORT UiTextAreaArgs* ui_textarea_args_new(void);
+UIEXPORT void ui_textarea_args_set_fill(UiTextAreaArgs *args, UiBool fill);
+UIEXPORT void ui_textarea_args_set_hexpand(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_vexpand(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_hfill(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_vfill(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan);
+UIEXPORT void ui_textarea_args_set_rowspan(UiTextAreaArgs *args, int rowspan);
+UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name);
+UIEXPORT void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname);
+UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback);
+UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
+UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname);
+UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value);
+UIEXPORT void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *groups);
+UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args);
+
+UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void);
+UIEXPORT void ui_textfield_args_set_fill(UiTextFieldArgs *args, UiBool fill);
+UIEXPORT void ui_textfield_args_set_hexpand(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_vexpand(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_hfill(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_vfill(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan);
+UIEXPORT void ui_textfield_args_set_rowspan(UiTextFieldArgs *args, int rowspan);
+UIEXPORT void ui_textfield_args_set_name(UiTextFieldArgs *args, const char *name);
+UIEXPORT void ui_textfield_args_set_style_class(UiTextFieldArgs *args, const char *classname);
+UIEXPORT void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback callback);
+UIEXPORT void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata);
+UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback);
+UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
+UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname);
+UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value);
+UIEXPORT void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *groups);
+UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args);
+
+UIEXPORT UiWebviewArgs* ui_webview_args_new(void);
+UIEXPORT void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill);
+UIEXPORT void ui_webview_args_set_hexpand(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_vexpand(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_hfill(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_vfill(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan);
+UIEXPORT void ui_webview_args_set_rowspan(UiWebviewArgs *args, int rowspan);
+UIEXPORT void ui_webview_args_set_name(UiWebviewArgs *args, const char *name);
+UIEXPORT void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname);
+UIEXPORT void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname);
+UIEXPORT void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value);
+UIEXPORT void ui_webview_args_set_groups(UiWebviewArgs *args, int *groups);
+UIEXPORT void ui_webview_args_free(UiWebviewArgs *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_ARGS_H */
+
index db9d85038c902dca47d72188717d219269bf86cb..d0cd53d5302c7ac34d53cfd5021c65744b558044 100644 (file)
@@ -67,7 +67,7 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
     
     ctx->attach_document = uic_context_attach_document;
-    ctx->detach_document2 = uic_context_detach_document2;
+    ctx->detach_document2 = uic_context_detach_document;
     
 #if UI_GTK2 || UI_GTK3
     if(toplevel && toplevel->widget) {
@@ -146,7 +146,7 @@ static void uic_context_unbind_vars(UiContext *ctx) {
     }
 }
 
-void uic_context_detach_document2(UiContext *ctx, void *document) {
+void uic_context_detach_document(UiContext *ctx, void *document) {
     // find the document in the documents list
     size_t docIndex = cxListFind(ctx->documents, document);
     if(!cxListIndexValid(ctx->documents, docIndex)) {
@@ -409,7 +409,7 @@ void uic_unbind_var(UiVar *var) {
     }
 }
 
-void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) {
+void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) {
     // TODO: do we need/want this? Why adding vars to a context after
     // widgets reference these? Workarounds:
     // 1. add vars to ctx before creating ui
@@ -467,8 +467,8 @@ void ui_attach_document(UiContext *ctx, void *document) {
     uic_context_attach_document(ctx, document);
 }
 
-void ui_detach_document2(UiContext *ctx, void *document) {
-    uic_context_detach_document2(ctx, document);
+void ui_detach_document(UiContext *ctx, void *document) {
+    uic_context_detach_document(ctx, document);
 }
 
 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
@@ -476,7 +476,7 @@ void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
     ctx->close_data = udata;
 }
 
-UIEXPORT void ui_context_destroy(UiContext *ctx) {
+void ui_context_destroy(UiContext *ctx) {
     CxIterator i = cxListIterator(ctx->destroy_handler);
     cx_foreach(UiDestroyHandler *, h, i) {
         h->destructor(h->data);
@@ -484,6 +484,10 @@ UIEXPORT void ui_context_destroy(UiContext *ctx) {
     cxMempoolFree(ctx->mp);
 }
 
+UiContext* ui_context_parent(UiContext *ctx) {
+    return ctx->parent;
+}
+
 
 void ui_set_group(UiContext *ctx, int group) {
     if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) {
index e0ce3deb9cb2430ddbd012c605bf8f8ce1512b0a..4fdcfe64e4c0a0bb8564648a4a50bde7fd5243e1 100644 (file)
@@ -119,15 +119,13 @@ void uic_init_global_context(void);
 UiContext* uic_context(UiObject *toplevel, CxMempool *mp);
 UiContext* uic_root_context(UiContext *ctx);
 void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
-void uic_context_set_document(UiContext *ctx, void *document); // deprecated
-void uic_context_detach_document(UiContext *ctx); // deprecated
 
 void uic_context_prepare_close(UiContext *ctx);
 
 void uic_context_attach_document(UiContext *ctx, void *document);
-void uic_context_detach_document2(UiContext *ctx, void *document);
-void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx);
-void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx);
+void uic_context_detach_document(UiContext *ctx, void *document);
+void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
+void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
 void uic_context_detach_all(UiContext *ctx);
 
 UiVar* uic_get_var(UiContext *ctx, const char *name);
@@ -141,7 +139,7 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
 void uic_save_var2(UiVar *var);
 void uic_unbind_var(UiVar *var);
 
-void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value);
+void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
 
 void uic_remove_bound_var(UiContext *ctx, UiVar *var);
 
index 07177bdbfc47d63228df23d5426d6dd7a4beee7f..bd69073f5a9c5112cd4495b160c0bd65e5dff72b 100644 (file)
@@ -44,44 +44,6 @@ void uic_docmgr_init() {
     }
 }
 
-void ui_set_document(UiObject *obj, void *document) {
-    uic_context_detach_all(obj->ctx);
-    obj->ctx->attach_document(obj->ctx, document);
-}
-
-void ui_detach_document(UiObject *obj) {
-    uic_context_detach_all(obj->ctx);
-}
-
-void* ui_get_document(UiObject *obj) {
-    return obj->ctx->document;
-}
-
-void ui_set_subdocument(void *document, void *sub) {
-    UiContext *ctx = ui_document_context(document);
-    if(!ctx) {
-        fprintf(stderr, "UI Error: pointer is not a document\n");
-    }
-    // TODO
-}
-
-void ui_detach_subdocument(void *document, void *sub) {
-    UiContext *ctx = ui_document_context(document);
-    if(!ctx) {
-        fprintf(stderr, "UI Error: pointer is not a document\n");
-    }
-    // TODO
-}
-
-void* ui_get_subdocument(void *document) {
-    UiContext *ctx = ui_document_context(document);
-    if(!ctx) {
-        fprintf(stderr, "UI Error: pointer is not a document\n");
-    }
-    // TODO
-    return NULL;
-}
-
 void* ui_document_new(size_t size) {
     CxMempool *mp = cxMempoolCreateSimple(256);
     const CxAllocator *a = mp->allocator;
@@ -100,6 +62,7 @@ void ui_document_destroy(void *doc) {
         ev.document = doc;
         ev.obj = NULL;
         ev.eventdata = NULL;
+        ev.eventdatatype = 0;
         ev.intval = 0;
 
         if(ctx->close_callback) {
index 4b234181a533ebce8d53e504c1abc1371cc26e3b..31f81713e3c6e5a2d2a8afd6244f20ed2dc47f6c 100644 (file)
@@ -125,19 +125,19 @@ UIEXPORT void ui_menu_end(void) {
 
 
 
-void ui_menuitem_create(UiMenuItemArgs args) {
+void ui_menuitem_create(UiMenuItemArgs *args) {
     UiMenuItem* item = malloc(sizeof(UiMenuItem));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_ITEM;
 
-    item->label = nl_strdup(args.label);
-    item->stockid = nl_strdup(args.stockid);
-    item->icon = nl_strdup(args.icon);
-    item->userdata = args.onclickdata;
-    item->callback = args.onclick;
-    item->groups = uic_copy_groups(args.groups, &item->ngroups);
+    item->label = nl_strdup(args->label);
+    item->stockid = nl_strdup(args->stockid);
+    item->icon = nl_strdup(args->icon);
+    item->userdata = args->onclickdata;
+    item->callback = args->onclick;
+    item->groups = uic_copy_groups(args->groups, &item->ngroups);
 
     add_item((UiMenuItemI*)item);
 }
@@ -152,79 +152,79 @@ void ui_menuseparator() {
     add_item((UiMenuItemI*)item);
 }
 
-void ui_menu_toggleitem_create(UiMenuToggleItemArgs args) {
+void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args) {
     UiMenuCheckItem *item = malloc(sizeof(UiMenuCheckItem));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_CHECK_ITEM;
 
-    item->label = nl_strdup(args.label);
-    item->stockid = nl_strdup(args.stockid);
-    item->icon = nl_strdup(args.icon);
-    item->varname = nl_strdup(args.varname);
-    item->userdata = args.onchangedata;
-    item->callback = args.onchange;
-    item->groups = uic_copy_groups(args.groups, &item->ngroups);
+    item->label = nl_strdup(args->label);
+    item->stockid = nl_strdup(args->stockid);
+    item->icon = nl_strdup(args->icon);
+    item->varname = nl_strdup(args->varname);
+    item->userdata = args->onchangedata;
+    item->callback = args->onchange;
+    item->groups = uic_copy_groups(args->groups, &item->ngroups);
     
     add_item((UiMenuItemI*)item);
 }
 
-void ui_menu_radioitem_create(UiMenuToggleItemArgs args) {
+void ui_menu_radioitem_create(UiMenuToggleItemArgs *args) {
     UiMenuCheckItem* item = malloc(sizeof(UiMenuCheckItem));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_RADIO_ITEM;
 
-    item->label = nl_strdup(args.label);
-    item->stockid = nl_strdup(args.stockid);
-    item->icon = nl_strdup(args.icon);
-    item->varname = nl_strdup(args.varname);
-    item->userdata = args.onchangedata;
-    item->callback = args.onchange;
-    item->groups = uic_copy_groups(args.groups, &item->ngroups);
+    item->label = nl_strdup(args->label);
+    item->stockid = nl_strdup(args->stockid);
+    item->icon = nl_strdup(args->icon);
+    item->varname = nl_strdup(args->varname);
+    item->userdata = args->onchangedata;
+    item->callback = args->onchange;
+    item->groups = uic_copy_groups(args->groups, &item->ngroups);
 
     add_item((UiMenuItemI*)item);
 }
 
-void ui_menu_itemlist_create(UiMenuItemListArgs args) {
+void ui_menu_itemlist_create(UiMenuItemListArgs *args) {
     UiMenuItemList*item = malloc(sizeof(UiMenuItemList));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_ITEM_LIST;
-    item->getvalue = args.getvalue;
-    item->callback = args.onselect;
-    item->userdata = args.onselectdata;
-    item->varname = nl_strdup(args.varname);
-    item->addseparator = args.addseparator;
+    item->getvalue = args->getvalue;
+    item->callback = args->onselect;
+    item->userdata = args->onselectdata;
+    item->varname = nl_strdup(args->varname);
+    item->addseparator = args->addseparator;
     
     add_item((UiMenuItemI*)item);
 }
 
-void ui_menu_checkitemlist_create(UiMenuItemListArgs args) {
+void ui_menu_checkitemlist_create(UiMenuItemListArgs *args) {
     UiMenuItemList* item = malloc(sizeof(UiMenuItemList));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_CHECKITEM_LIST;
-    item->callback = args.onselect;
-    item->userdata = args.onselectdata;
-    item->varname = nl_strdup(args.varname);
+    item->callback = args->onselect;
+    item->userdata = args->onselectdata;
+    item->varname = nl_strdup(args->varname);
 
     add_item((UiMenuItemI*)item);
 }
 
-void ui_menu_radioitemlist_create(UiMenuItemListArgs args) {
+void ui_menu_radioitemlist_create(UiMenuItemListArgs *args) {
     UiMenuItemList* item = malloc(sizeof(UiMenuItemList));
     mitem_set_id(&item->item);
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_RADIOITEM_LIST;
-    item->callback = args.onselect;
-    item->userdata = args.onselectdata;
-    item->varname = nl_strdup(args.varname);
+    item->callback = args->onselect;
+    item->userdata = args->onselectdata;
+    item->varname = nl_strdup(args->varname);
 
     add_item((UiMenuItemI*)item);
 }
index 2c10597f7a1f4d45333ee5a23fef5c61b0fa787b..e7981c4687f2c3d82823a2df8701847c4e21309d 100644 (file)
 #include "object.h"
 #include "context.h"
 
+#include <cx/linked_list.h>
+
 #include "../ui/container.h"
 
+static CxList *creation_callbacks;
+static CxList *destruction_callbacks;
+
+typedef struct objcallback {
+    ui_object_callback func;
+    void *userdata;
+} objcallback;
+
+void ui_register_object_creation_callback(ui_object_callback func, void *userdata) {
+    if(!creation_callbacks) {
+        creation_callbacks = cxLinkedListCreateSimple(sizeof(objcallback));
+    }
+    objcallback cb = { func, userdata };
+    cxListAdd(creation_callbacks, &cb);
+}
+
+void ui_register_object_destruction_callback(ui_object_callback func, void *userdata) {
+    if(!destruction_callbacks) {
+        destruction_callbacks = cxLinkedListCreateSimple(sizeof(objcallback));
+    }
+    objcallback cb = { func, userdata };
+    cxListAdd(destruction_callbacks, &cb);
+}
+
+void uic_object_created(UiObject *obj) {
+    CxIterator i = cxListIterator(creation_callbacks);
+    cx_foreach(objcallback *, cb, i) {
+        cb->func(obj, cb->userdata);
+    }
+}
+
+void uic_object_destroyed(UiObject *obj) {
+    CxIterator i = cxListIterator(destruction_callbacks);
+    cx_foreach(objcallback *, cb, i) {
+        cb->func(obj, cb->userdata);
+    }
+}
+
 void ui_end(UiObject *obj) {
     if(!obj->next) {
         return;
@@ -84,12 +124,22 @@ void uic_object_destroy(UiObject *obj) {
         ev.document = obj->ctx->document;
         ev.obj = obj;
         ev.eventdata = NULL;
+        ev.eventdatatype = 0;
         ev.intval = 0;
         obj->ctx->close_callback(&ev, obj->ctx->close_data);
     }
+    uic_object_destroyed(obj);
     cxMempoolFree(obj->ctx->mp);
 }
 
+UiObject* uic_object_new_toplevel(void) {
+    CxMempool *mp = cxMempoolCreateSimple(256);
+    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+    obj->ctx = uic_context(obj, mp);
+    uic_object_created(obj);
+    return obj;
+}
+
 UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget) {
     return uic_ctx_object_new(toplevel->ctx, widget);
 }
@@ -98,7 +148,7 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
     UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
     newobj->ctx = ctx;
     newobj->widget = widget;
-    
+    uic_object_created(newobj);
     return newobj;
 }
 
index a5011a07262fca54a32a011c75f6465e67d4000e..45cf6837043fd8db56f4d44d1daec50f14aadf5e 100644 (file)
 extern "C" {
 #endif
 
+typedef void (*ui_object_callback)(UiObject *obj, void *userdata);
+
+void ui_register_object_creation_callback(ui_object_callback func, void *userdata);
+void ui_register_object_destruction_callback(ui_object_callback func, void *userdata);
+
+void uic_object_created(UiObject *obj);
+void uic_object_destroyed(UiObject *obj);
+    
 void uic_object_destroy(UiObject *obj);
     
+UiObject* uic_object_new_toplevel(void);
 UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget);
 UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
 void uic_obj_add(UiObject *toplevel, UiObject *ctobj);
index bc1b385abe8977a874d0a26749ce68566879aced..a126b56ab8289a46254d4454650b021fc5b4987f 100644 (file)
@@ -33,13 +33,14 @@ COMMON_OBJ = context$(OBJ_EXT)
 COMMON_OBJ += document$(OBJ_EXT)
 COMMON_OBJ += object$(OBJ_EXT)
 COMMON_OBJ += types$(OBJ_EXT)
-COMMON_OBJ += menu$(OBJ_EXT)
 COMMON_OBJ += properties$(OBJ_EXT)
 COMMON_OBJ += menu$(OBJ_EXT)
 COMMON_OBJ += toolbar$(OBJ_EXT)
 COMMON_OBJ += ucx_properties$(OBJ_EXT)
 COMMON_OBJ += threadpool$(OBJ_EXT)
 COMMON_OBJ += condvar$(OBJ_EXT)
+COMMON_OBJ += args$(OBJ_EXT)
+COMMON_OBJ += wrapper$(OBJ_EXT)
 
 TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
 TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
index 7a37407621b98d8556fd53120accb700c1df605d..7988eab577a9daa66999cc6d34e08891a7ab5b7d 100644 (file)
@@ -165,6 +165,7 @@ static int ui_threadpool_job_finish(void *data) {
     event.document = job->obj->ctx->document;
     event.intval = 0;
     event.eventdata = NULL;
+    event.eventdatatype = 0;
     job->finish_callback(&event, job->finish_data);
     free(job);
     return 0;
index 0d86f1729c3f186549afc54687d2c8246d6db9c6..199dc41b254bae6381cc8dce8851f98e61f9f291 100644 (file)
@@ -49,18 +49,18 @@ static char* nl_strdup(const char* str) {
     return str ? strdup(str) : NULL;\r
 }\r
 \r
-static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs args, size_t *ngroups) {\r
+static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups) {\r
     UiToolbarItemArgs newargs;\r
-    newargs.label = nl_strdup(args.label);\r
-    newargs.stockid = nl_strdup(args.stockid);\r
-    newargs.icon = nl_strdup(args.icon);\r
-    newargs.onclick = args.onclick;\r
-    newargs.onclickdata = args.onclickdata;\r
-    newargs.groups = uic_copy_groups(args.groups, ngroups);\r
+    newargs.label = nl_strdup(args->label);\r
+    newargs.stockid = nl_strdup(args->stockid);\r
+    newargs.icon = nl_strdup(args->icon);\r
+    newargs.onclick = args->onclick;\r
+    newargs.onclickdata = args->onclickdata;\r
+    newargs.groups = uic_copy_groups(args->groups, ngroups);\r
     return newargs;\r
 }\r
 \r
-void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args) {\r
+void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args) {\r
     UiToolbarItem* item = malloc(sizeof(UiToolbarItem));\r
     item->item.type = UI_TOOLBAR_ITEM;\r
     item->args = itemargs_copy(args, &item->ngroups);\r
@@ -68,34 +68,34 @@ void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args) {
 }\r
 \r
 \r
-static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs args, size_t *ngroups) {\r
+static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args, size_t *ngroups) {\r
     UiToolbarToggleItemArgs newargs;\r
-    newargs.label = nl_strdup(args.label);\r
-    newargs.stockid = nl_strdup(args.stockid);\r
-    newargs.icon = nl_strdup(args.icon);\r
-    newargs.varname = nl_strdup(args.varname);\r
-    newargs.onchange = args.onchange;\r
-    newargs.onchangedata = args.onchangedata;\r
-    newargs.groups = uic_copy_groups(args.groups, ngroups);\r
+    newargs.label = nl_strdup(args->label);\r
+    newargs.stockid = nl_strdup(args->stockid);\r
+    newargs.icon = nl_strdup(args->icon);\r
+    newargs.varname = nl_strdup(args->varname);\r
+    newargs.onchange = args->onchange;\r
+    newargs.onchangedata = args->onchangedata;\r
+    newargs.groups = uic_copy_groups(args->groups, ngroups);\r
     return newargs;\r
 }\r
 \r
-void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs args) {\r
+void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args) {\r
     UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem));\r
     item->item.type = UI_TOOLBAR_TOGGLEITEM;\r
     item->args = toggleitemargs_copy(args, &item->ngroups);\r
     cxMapPut(toolbar_items, name, item);\r
 }\r
 \r
-static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs args) {\r
+static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args) {\r
     UiToolbarMenuArgs newargs;\r
-    newargs.label = nl_strdup(args.label);\r
-    newargs.stockid = nl_strdup(args.stockid);\r
-    newargs.icon = nl_strdup(args.icon);\r
+    newargs.label = nl_strdup(args->label);\r
+    newargs.stockid = nl_strdup(args->stockid);\r
+    newargs.icon = nl_strdup(args->icon);\r
     return newargs;\r
 }\r
 \r
-UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs args) {\r
+UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args) {\r
     UiToolbarMenuItem* item = malloc(sizeof(UiToolbarMenuItem));\r
     item->item.type = UI_TOOLBAR_MENU;\r
     memset(&item->menu, 0, sizeof(UiMenu));\r
index a704b8593f5e18198499207167e44a9035415c6e..b3f55d19215332f39759f5db34d69081fe26d3d7 100644 (file)
 #include "../ui/tree.h"
 #include "types.h"
 #include "context.h"
+#include "../ui/image.h"
 
-
+static ui_list_init_func default_list_init;
+static void *default_list_init_userdata;
 
 UiObserver* ui_observer_new(ui_callback f, void *data) {
     UiObserver *observer = malloc(sizeof(UiObserver));
@@ -75,6 +77,7 @@ void ui_notify_except(UiObserver *observer, UiObserver *exc, void *data) {
     evt.window = NULL;
     evt.document = NULL;
     evt.eventdata = data;
+    evt.eventdatatype = UI_EVENT_DATA_POINTER;
     evt.intval = 0;
     
     while(observer) {
@@ -94,20 +97,22 @@ void ui_notify_evt(UiObserver *observer, UiEvent *event) {
 
 /* --------------------------- UiList --------------------------- */
 
-UiList* ui_list_new(UiContext *ctx, char *name) {
-    UiList *list = malloc(sizeof(UiList));
+void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
+    list->data = cxArrayListCreate(ctx->mp->allocator, NULL, CX_STORE_POINTERS, 32);
     list->first = ui_list_first;
     list->next = ui_list_next;
     list->get = ui_list_get;
     list->count = ui_list_count;
-    list->observers = NULL;
-    
-    list->data = cxArrayListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS, 32);
-    list->iter = NULL;
-    
-    list->update = NULL;
-    list->getselection = NULL;
-    list->obj = NULL;
+}
+
+UiList* ui_list_new(UiContext *ctx, const char *name) {
+    return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata);
+}
+
+UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) {
+    UiList *list = cxMalloc(ctx->mp->allocator, sizeof(UiList));
+    memset(list, 0, sizeof(UiList));
+    listinit(ctx, list, userdata);
     
     if(name) {
         uic_reg_var(ctx, name, UI_VAR_LIST, list);
@@ -248,7 +253,7 @@ void ui_model_free(UiContext *ctx, UiModel *mi) {
 // types
 
 // public functions
-UiInteger* ui_int_new(UiContext *ctx, char *name) {
+UiInteger* ui_int_new(UiContext *ctx, const char *name) {
     UiInteger *i = ui_malloc(ctx, sizeof(UiInteger));
     memset(i, 0, sizeof(UiInteger));
     if(name) {
@@ -257,7 +262,7 @@ UiInteger* ui_int_new(UiContext *ctx, char *name) {
     return i;
 }
 
-UiDouble* ui_double_new(UiContext *ctx, char *name) {
+UiDouble* ui_double_new(UiContext *ctx, const char *name) {
     UiDouble *d = ui_malloc(ctx, sizeof(UiDouble));
     memset(d, 0, sizeof(UiDouble));
     if(name) {
@@ -266,7 +271,7 @@ UiDouble* ui_double_new(UiContext *ctx, char *name) {
     return d;
 }
 
-UiString* ui_string_new(UiContext *ctx, char *name) {
+UiString* ui_string_new(UiContext *ctx, const char *name) {
     UiString *s = ui_malloc(ctx, sizeof(UiString));
     memset(s, 0, sizeof(UiString));
     if(name) {
@@ -275,7 +280,7 @@ UiString* ui_string_new(UiContext *ctx, char *name) {
     return s;
 }
 
-UiText* ui_text_new(UiContext *ctx, char *name) {
+UiText* ui_text_new(UiContext *ctx, const char *name) {
     UiText *t = ui_malloc(ctx, sizeof(UiText));
     memset(t, 0, sizeof(UiText));
     if(name) {
@@ -284,7 +289,7 @@ UiText* ui_text_new(UiContext *ctx, char *name) {
     return t;
 }
 
-UiRange* ui_range_new(UiContext *ctx, char *name) {
+UiRange* ui_range_new(UiContext *ctx, const char *name) {
     UiRange *r = ui_malloc(ctx, sizeof(UiRange));
     memset(r, 0, sizeof(UiRange));
     if(name) {
@@ -293,7 +298,7 @@ UiRange* ui_range_new(UiContext *ctx, char *name) {
     return r;
 }
 
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name) {
+UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
     UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
     memset(g, 0, sizeof(UiGeneric));
     if(name) {
@@ -404,6 +409,30 @@ char* ui_text_get(UiText* s) {
     }
 }
 
+void ui_generic_set_image(UiGeneric *g, void *img) {
+    if(g->set) {
+        g->set(g, img, UI_IMAGE_OBJECT_TYPE);
+    } else {
+        if(g->value) {
+            ui_image_unref(g->value);
+        }
+        ui_image_ref(img);
+        g->value = img;
+        g->type = UI_IMAGE_OBJECT_TYPE;
+    }
+}
+
+void* ui_generic_get_image(UiGeneric *g) {
+    if(g->type) {
+        if(!strcmp(g->type, UI_IMAGE_OBJECT_TYPE)) {
+            return g->value;
+        } else {
+            return NULL;
+        }
+    }
+    return g->value;
+}
+
 
 // private functions
 void uic_int_copy(UiInteger *from, UiInteger *to) {
@@ -636,3 +665,34 @@ void ui_setop_enable(int set) {
 int ui_get_setop(void) {
     return ui_set_op;
 }
+
+/* ---------------- List initializers and wrapper functions ---------------- */
+
+void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
+    default_list_init = func;
+    default_list_init_userdata = userdata;
+}
+
+void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
+    list->first = first;
+}
+
+void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list)) {
+    list->next = next;
+}
+
+void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i)) {
+    list->get = get;
+}
+
+void ui_list_class_set_count(UiList *list, int(*count)(UiList *list)) {
+    list->count = count;
+}
+
+void ui_list_class_set_data(UiList *list, void *data) {
+    list->data = data;
+}
+
+void ui_list_class_set_iter(UiList *list, void *iter) {
+    list->iter = iter;
+}
index 677199f492728e4656329f59d7bc78f3214e44d6..46d6c2e2f11a35f7890f9ffb13bf8159924758c6 100644 (file)
@@ -34,8 +34,9 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-
-
+    
+void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused);
+    
 void uic_int_copy(UiInteger *from, UiInteger *to);
 void uic_double_copy(UiDouble *from, UiDouble *to);
 void uic_string_copy(UiString *from, UiString *to);
diff --git a/ui/common/wrapper.c b/ui/common/wrapper.c
new file mode 100644 (file)
index 0000000..ea88553
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "wrapper.h"
+#include "types.h"
+#include <cx/list.h>
+#include <string.h>
+
+/* ---------------------------- UiObject ---------------------------- */
+
+UiContext* ui_object_get_context(UiObject *obj) {
+    return obj->ctx;
+}
+
+void* ui_object_get_windowdata(UiObject *obj) {
+    return obj->window;
+}
+
+void ui_object_set_windowdata(UiObject *obj, void *windowdata) {
+    obj->window = windowdata;
+}
+
+
+/* ---------------------------- UiList ---------------------------- */
+
+void* ui_list_get_data(UiList *list) {
+    return list->data;
+}
+
+void ui_list_set_data(UiList *list, void *data) {
+    list->data = data;
+}
+
+void* ui_list_get_iter(UiList *list) {
+    return list->iter;
+}
+
+void ui_list_set_iter(UiList *list, void *iter) {
+    list->iter = iter;
+}
+
+
+/* ------------------------------ UiSublist ------------------------------ */
+
+UiSubList* ui_sublist_new(void) {
+    UiSubList *sublist = malloc(sizeof(UiSubList));
+    memset(sublist, 0, sizeof(UiSubList));
+    return sublist;
+}
+
+void ui_sublist_set_value(UiSubList *sublist, UiList *value) {
+    sublist->value = value;
+}
+
+void ui_sublist_set_varname(UiSubList *sublist, const char *varname) {
+    free((void*)sublist->varname);
+    sublist->varname = strdup(varname);
+}
+
+void ui_sublist_set_header(UiSubList *sublist, const char *header) {
+    free((void*)sublist->header);
+    sublist->header = strdup(header);
+}
+
+void ui_sublist_set_separator(UiSubList *sublist, UiBool separator) {
+    sublist->separator = separator;
+}
+
+void ui_sublist_set_userdata(UiSubList *sublist, void *userdata) {
+    sublist->userdata = userdata;
+}
+
+void ui_sublist_free(UiSubList *sublist) {
+    free((void*)sublist->varname);
+    free((void*)sublist->header);
+    free(sublist);
+}
+
+
+/* -------------------- Source list (UiList<UiSublist>) -------------------- */
+
+UiList* ui_srclist_new(UiContext *ctx, const char *name) {
+    UiList *list = ui_list_new2(ctx, name, uic_ucx_list_init, NULL);
+    CxList *cxlist = list->data;
+    cxlist->collection.simple_destructor = (cx_destructor_func)ui_sublist_free;
+    return list;
+}
+
+void ui_srclist_add(UiList *list, UiSubList *item) {
+    ui_list_append(list, item);
+}
+
+void ui_srclist_insert(UiList *list, int index, UiSubList *item) {
+    CxList *cxlist = list->data;
+    cxListInsert(cxlist, index, item);
+}
+
+void ui_srclist_remove(UiList *list, int index) {
+    CxList *cxlist = list->data;
+    cxListRemove(cxlist, index);
+}
+
+void ui_srclist_clear(UiList *list) {
+    CxList *cxlist = list->data;
+    cxListClear(cxlist);
+}
+
+int ui_srclist_size(UiList *list) {
+    return ui_list_count(list);
+}
+
+
+/* ---------------------------- UiSubListEventData ---------------------------- */
+
+UiList* ui_sublist_event_get_list(UiSubListEventData *event) {
+    return event->list;
+}
+
+int ui_sublist_event_get_sublist_index(UiSubListEventData *event) {
+    return event->sublist_index;
+}
+
+int ui_sublist_event_get_row_index(UiSubListEventData *event) {
+    return event->row_index;
+}
+
+void* ui_sublist_event_get_row_data(UiSubListEventData *event) {
+    return event->row_data;
+}
+
+void* ui_sublist_event_get_sublist_userdata(UiSubListEventData *event) {
+    return event->sublist_userdata;
+}
+
+void* ui_sublist_event_get_event_data(UiSubListEventData *event) {
+    return event->event_data;
+}
+
+
+/* ---------------------------- UiEvent ---------------------------- */
+
+UiObject* ui_event_get_obj(UiEvent *event) {
+    return event->obj;
+}
+
+void* ui_event_get_document(UiEvent *event) {
+    return event->document;
+}
+
+void* ui_event_get_windowdata(UiEvent *event) {
+    return event->window;
+}
+
+void* ui_event_get_eventdata(UiEvent *event) {
+    return event->eventdata;
+}
+
+int ui_event_get_eventdatatype(UiEvent *event) {
+    return event->eventdatatype;
+}
+
+int ui_event_get_int(UiEvent *event) {
+    return event->intval;
+}
+
+int ui_event_get_set(UiEvent *event) {
+    return event->set;
+}
+
+
+/* ------------------------- SubListItem (public) ------------------------- */
+
+void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon) {
+    item->icon = icon ? strdup(icon) : NULL;
+}
+
+void ui_sublist_item_set_label(UiSubListItem *item, const char *label) {
+    item->label = label ? strdup(label) : NULL;
+}
+
+void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon) {
+    item->button_icon = button_icon ? strdup(button_icon) : NULL;
+}
+
+void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label) {
+    item->button_label = button_label ? strdup(button_label) : NULL;
+}
+
+void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge) {
+    item->badge = badge ? strdup(badge) : NULL;
+}
+
+void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) {
+    item->eventdata = NULL;
+}
diff --git a/ui/common/wrapper.h b/ui/common/wrapper.h
new file mode 100644 (file)
index 0000000..d190fc8
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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_WRAPPER_H
+#define UIC_WRAPPER_H
+
+#include "../ui/toolkit.h"
+#include "../ui/tree.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UIEXPORT UiContext* ui_object_get_context(UiObject *obj);
+UIEXPORT void* ui_object_get_windowdata(UiObject *obj);
+UIEXPORT void ui_object_set_windowdata(UiObject *obj, void *windowdata);
+
+UIEXPORT void* ui_list_get_data(UiList *list);
+UIEXPORT void* ui_list_get_iter(UiList *list);
+UIEXPORT void ui_list_set_iter(UiList *list, void *iter);
+
+UIEXPORT UiSubList* ui_sublist_new(void);
+UIEXPORT void ui_sublist_set_value(UiSubList *sublist, UiList *value);
+UIEXPORT void ui_sublist_set_varname(UiSubList *sublist, const char *varname);
+UIEXPORT void ui_sublist_set_header(UiSubList *sublist, const char *header);
+UIEXPORT void ui_sublist_set_separator(UiSubList *sublist, UiBool separator);
+UIEXPORT void ui_sublist_set_userdata(UiSubList *sublist, void *userdata);
+UIEXPORT void ui_sublist_free(UiSubList *sublist);
+
+UIEXPORT UiList* ui_srclist_new(UiContext *ctx, const char *name);
+UIEXPORT void ui_srclist_add(UiList *list, UiSubList *item);
+UIEXPORT void ui_srclist_insert(UiList *list, int index, UiSubList *item);
+UIEXPORT void ui_srclist_remove(UiList *list, int index);
+UIEXPORT void ui_srclist_clear(UiList *list);
+UIEXPORT int ui_srclist_size(UiList *list);
+
+UIEXPORT UiList* ui_sublist_event_get_list(UiSubListEventData *event);
+UIEXPORT int ui_sublist_event_get_sublist_index(UiSubListEventData *event);
+UIEXPORT int ui_sublist_event_get_row_index(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_row_data(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_sublist_userdata(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_event_data(UiSubListEventData *event);
+    
+UIEXPORT UiObject* ui_event_get_obj(UiEvent *event);
+UIEXPORT void* ui_event_get_document(UiEvent *event);
+UIEXPORT void* ui_event_get_windowdata(UiEvent *event);
+UIEXPORT void* ui_event_get_eventdata(UiEvent *event);
+UIEXPORT int ui_event_get_eventdatatype(UiEvent *event);
+UIEXPORT int ui_event_get_int(UiEvent *event);
+UIEXPORT int ui_event_get_set(UiEvent *event);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_WRAPPER_H */
+
index aba263f0e91884213deb445b8674d2a33d4dcd3d..d1979fb679363275ee0324300dc598bc6a5a4c83 100644 (file)
 #
 
 $(GTK_OBJPRE)%.o: gtk/%.c
-       $(CC) -o $@ -c -I../ucx $(CFLAGS) $(TK_CFLAGS) $<
+       $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
        
 $(UI_LIB): $(OBJ)
        $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)       
-       
+
+$(UI_SHLIB): $(OBJ)
+       $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
index b26a13056e951a3e8c88a13f9546ee396b612fa1..6f6ad0ba2daf126cccc937f4a9bb6b9518836df5 100644 (file)
@@ -73,6 +73,7 @@ GtkWidget* ui_create_button(
         event->callback = onclick;
         event->value = event_value;
         event->customdata = NULL;
+        event->customint = 0;
 
         g_signal_connect(
                 button,
@@ -96,13 +97,13 @@ GtkWidget* ui_create_button(
     return button;
 }
 
-UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) {
+UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata, 0, FALSE);
-    ui_set_name_and_style(button, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, button, args.groups);
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, button, FALSE);
+    GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->onclick, args->onclickdata, 0, FALSE);
+    ui_set_name_and_style(button, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, button, args->groups);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, button);
     return button;
 }
 
@@ -113,6 +114,7 @@ void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = event->value;
     e.set = ui_get_setop();
     event->callback(&e, event->userdata);
@@ -137,6 +139,7 @@ void ui_toggled_obs(void *widget, UiVarEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = event->var->value;
+    e.eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
     e.intval = i->get(i);
     e.set = ui_get_setop();
     
@@ -149,6 +152,7 @@ static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = gtk_toggle_button_get_active(widget);
     e.set = ui_get_setop();
     event->callback(&e, event->userdata);    
@@ -240,6 +244,7 @@ void ui_bind_togglebutton(
         event->callback = onchange;
         event->value = 0;
         event->customdata = NULL;
+        event->customint = 0;
         
         g_signal_connect(
                 widget,
@@ -260,6 +265,7 @@ void ui_bind_togglebutton(
         event->callback = NULL;
         event->value = enable_state;
         event->customdata = NULL;
+        event->customint = 0;
         
         g_signal_connect(
                 widget,
@@ -274,29 +280,29 @@ void ui_bind_togglebutton(
     }
 }
 
-static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) {
+static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     ui_setup_togglebutton(
             obj,
             widget,
-            args.label,
-            args.icon,
-            args.varname,
-            args.value,
-            args.onchange,
-            args.onchangedata,
-            args.enable_group);
-    ui_set_name_and_style(widget, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, widget, args.groups);
+            args->label,
+            args->icon,
+            args->varname,
+            args->value,
+            args->onchange,
+            args->onchangedata,
+            args->enable_group);
+    ui_set_name_and_style(widget, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, widget, args->groups);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, widget, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, widget);
     
     return widget;
 }
 
-UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) {
     return togglebutton_create(obj, gtk_toggle_button_new(), args);
 }
 
@@ -320,6 +326,7 @@ static void ui_checkbox_callback(GtkCheckButton *widget, UiEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = gtk_check_button_get_active(widget);
     e.set = ui_get_setop();
     event->callback(&e, event->userdata);    
@@ -333,39 +340,39 @@ static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event)
     }
 }
 
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
-    GtkWidget *widget = gtk_check_button_new_with_label(args.label); 
+    GtkWidget *widget = gtk_check_button_new_with_label(args->label); 
     ui_bind_togglebutton(
             obj,
             widget,
             ui_check_button_get,
             ui_check_button_set,
-            args.varname,
-            args.value,
+            args->varname,
+            args->value,
             (ui_toggled_func)ui_checkbox_callback,
-            args.onchange,
-            args.onchangedata,
+            args->onchange,
+            args->onchangedata,
             (ui_toggled_func)ui_checkbox_enable_state,
-            args.enable_group);
+            args->enable_group);
     
-    ui_set_name_and_style(widget, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, widget, args.groups);
+    ui_set_name_and_style(widget, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, widget, args->groups);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, widget, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, widget);
     
     return widget;
 }
 
 #else
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
     return togglebutton_create(obj, gtk_check_button_new(), args);
 }
 #endif
 
-UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
 #ifdef UI_GTK3
     return NULL; // TODO
 #else
@@ -391,6 +398,7 @@ static void radiobutton_toggled(void *widget, UiEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = RADIOBUTTON_GET_ACTIVE(widget);
     e.set = ui_get_setop();
     event->callback(&e, event->userdata);    
@@ -415,13 +423,13 @@ static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) {
     free(data);
 }
 
-UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
+UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     GSList *rg = NULL;
     UiInteger *rgroup;
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
     
     UiBool first = FALSE;
     if(var) {
@@ -432,9 +440,9 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
         }
     }
     
-    GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args.label); 
-    ui_set_name_and_style(rbutton, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, rbutton, args.groups);
+    GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args->label); 
+    ui_set_name_and_style(rbutton, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, rbutton, args->groups);
     if(rgroup) {
 #if GTK_MAJOR_VERSION >= 4
         if(rg) {
@@ -476,13 +484,14 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
                 rbdata);
     }
     
-    if(args.onchange) {
+    if(args->onchange) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
-        event->userdata = args.onchangedata;
-        event->callback = args.onchange;
+        event->userdata = args->onchangedata;
+        event->callback = args->onchange;
         event->value = 0;
         event->customdata = NULL;
+        event->customint = 0;
         
         g_signal_connect(
                 rbutton,
@@ -496,8 +505,8 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
                 event);
     }
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, rbutton, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, rbutton);
     
     return rbutton;
 }
@@ -510,6 +519,7 @@ void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = i->get(i);
     
     ui_notify_evt(i->observers, &e);
index 41c7924c45fec35c37547057e59aa9b53260e6a0..7a98bf475561f6ac720ac58e38b2b0cb4a6b32d1 100644 (file)
@@ -120,12 +120,9 @@ UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType
     return (UiContainer*)ct;
 }
 
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_box_container_add(UiContainer *ct, GtkWidget *widget) {
     UiBoxContainer *bc = (UiBoxContainer*)ct;
-    if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
-        fill = ui_lb2bool(ct->layout.fill);
-    }
-    
+    UiBool fill = ct->layout.fill;
     if(bc->has_fill && fill) {
         fprintf(stderr, "UiError: container has 2 filled widgets");
         fill = FALSE;
@@ -180,7 +177,7 @@ UiContainer* ui_grid_container(
 }
 
 #if GTK_MAJOR_VERSION >= 3
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
     UiGridContainer *grid = (UiGridContainer*)ct;
     
     if(ct->layout.newline) {
@@ -208,9 +205,7 @@ void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
         }
     }
     
-    if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
-        fill = ui_lb2bool(ct->layout.fill);
-    }
+    UiBool fill = ct->layout.fill;
     if(ct->layout.hexpand) {
         hexpand = TRUE;
         hfill = TRUE;
@@ -249,7 +244,7 @@ void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
 }
 #endif
 #ifdef UI_GTK2
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
     UiGridContainer *grid = (UiGridContainer*)ct;
     
     if(ct->layout.newline) {
@@ -277,9 +272,7 @@ void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
         }
     }
     
-    if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
-        fill = ui_lb2bool(ct->layout.fill);
-    }
+    UiBool fill = ct->layout.fill;
     if(ct->layout.hexpand) {
         hexpand = TRUE;
         hfill = TRUE;
@@ -340,7 +333,7 @@ UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
     return ct;
 }
 
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget) {
     FRAME_SET_CHILD(ct->widget, widget);
 }
 
@@ -354,11 +347,11 @@ UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) {
     return ct;
 }
 
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_expander_container_add(UiContainer *ct, GtkWidget *widget) {
     EXPANDER_SET_CHILD(ct->widget, widget);
 }
 
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget) {
     // TODO: check if the widget implements GtkScrollable
     SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
     ui_reset_layout(ct->layout);
@@ -385,7 +378,7 @@ UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
     return (UiContainer*)ct;
 }
 
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget) {
     UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget);
     if(!data) {
         fprintf(stderr, "UI Error: widget is not a tabview");
@@ -420,15 +413,15 @@ GtkWidget* ui_box_set_margin(GtkWidget *box, int margin) {
     return ret;
 }
 
-UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) {
+UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type) {
     UiObject *current = uic_current_obj(obj);
     UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
-    GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
-    ui_set_name_and_style(box, args.name, args.style_class);
-    GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
-    ct->add(ct, widget, TRUE);
+    GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
+    ui_set_name_and_style(box, args->name, args->style_class);
+    GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
+    ct->add(ct, widget);
     
     UiObject *newobj = uic_object_new(obj, box);
     newobj->container = ui_box_container(obj, box, type);
@@ -437,11 +430,11 @@ UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType t
     return widget;
 }
 
-UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
     return ui_box_create(obj, args, UI_CONTAINER_VBOX);
 }
 
-UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
     return ui_box_create(obj, args, UI_CONTAINER_HBOX);
 }
 
@@ -458,74 +451,74 @@ GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing) {
     return grid;
 }
 
-UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     GtkWidget *widget;
     
-    GtkWidget *grid = ui_create_grid_widget(args.columnspacing, args.rowspacing);
-    ui_set_name_and_style(grid, args.name, args.style_class);
-    widget = ui_box_set_margin(grid, args.margin);
-    current->container->add(current->container, widget, TRUE);
+    GtkWidget *grid = ui_create_grid_widget(args->columnspacing, args->rowspacing);
+    ui_set_name_and_style(grid, args->name, args->style_class);
+    widget = ui_box_set_margin(grid, args->margin);
+    current->container->add(current->container, widget);
     
     UiObject *newobj = uic_object_new(obj, grid);
-    newobj->container = ui_grid_container(obj, grid, args.def_hexpand, args.def_vexpand, args.def_hfill, args.def_vfill);
+    newobj->container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
     uic_obj_add(obj, newobj);
     
     return widget;
 }
 
-UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args) {
+UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
-    GtkWidget *frame = gtk_frame_new(args.label);
+    GtkWidget *frame = gtk_frame_new(args->label);
     UiObject *newobj = uic_object_new(obj, frame);
-    GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
     if(sub) {
         FRAME_SET_CHILD(frame, sub);
     } else {
         newobj->widget = frame;
         newobj->container = ui_frame_container(obj, frame);
     }
-    current->container->add(current->container, frame, FALSE);
+    current->container->add(current->container, frame);
     uic_obj_add(obj, newobj);
     
     return frame;
 }
 
-UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args) {
+UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
-    GtkWidget *expander = gtk_expander_new(args.label);
-    gtk_expander_set_expanded(GTK_EXPANDER(expander), args.isexpanded);
+    GtkWidget *expander = gtk_expander_new(args->label);
+    gtk_expander_set_expanded(GTK_EXPANDER(expander), args->isexpanded);
     UiObject *newobj = uic_object_new(obj, expander);
-    GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
     if(sub) {
         EXPANDER_SET_CHILD(expander, sub);
     } else {
         newobj->widget = expander;
         newobj->container = ui_expander_container(obj, expander);
     }
-    current->container->add(current->container, expander, FALSE);
+    current->container->add(current->container, expander);
     uic_obj_add(obj, newobj);
     
     return expander;
 }
 
 
-UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
     GtkWidget *sw = SCROLLEDWINDOW_NEW();
-    ui_set_name_and_style(sw, args.name, args.style_class);
-    GtkWidget *widget = ui_box_set_margin(sw, args.margin);
-    current->container->add(current->container, widget, TRUE);
+    ui_set_name_and_style(sw, args->name, args->style_class);
+    GtkWidget *widget = ui_box_set_margin(sw, args->margin);
+    current->container->add(current->container, widget);
     
     UiObject *newobj = uic_object_new(obj, sw);
-    GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
     if(sub) {
         SCROLLEDWINDOW_SET_CHILD(sw, sub);
     } else {
@@ -689,22 +682,71 @@ UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview) {
     return g_object_get_data(G_OBJECT(tabview), "ui_tabview");
 }
 
+static void tabview_switch_page(
+        GtkNotebook *self,
+        GtkWidget *page,
+        guint page_num,
+        gpointer userdata)
+{
+    UiGtkTabView *tabview = userdata;
+    if(!tabview->onchange) {
+        return;
+    }
+    
+    UiEvent event;
+    event.obj = tabview->obj;
+    event.window = event.obj->window;
+    event.document = event.obj->ctx->document;
+    event.set = ui_get_setop();
+    event.eventdata = NULL;
+    event.eventdatatype = 0;
+    event.intval = page_num;
+    
+    tabview->onchange(&event, tabview->onchange);
+}
+
+#if GTK_CHECK_VERSION(3, 10, 0)
+
+static void tabview_stack_changed(
+        GObject *object,
+        GParamSpec *pspec,
+        UiGtkTabView *tabview)
+{
+    if(!tabview->onchange) {
+        return;
+    }
+    
+    UiEvent event;
+    event.obj = tabview->obj;
+    event.window = event.obj->window;
+    event.document = event.obj->ctx->document;
+    event.set = ui_get_setop();
+    event.eventdata = NULL;
+    event.eventdatatype = 0;
+    event.intval = 0;
+    
+    tabview->onchange(&event, tabview->onchange);
+}
+
+#endif
+
 typedef int64_t(*ui_tabview_get_func)(UiInteger*);
 typedef void (*ui_tabview_set_func)(UiInteger*, int64_t);
 
-UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
+UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
     UiGtkTabView *data = malloc(sizeof(UiGtkTabView));
-    data->margin = args.margin;
-    data->spacing = args.spacing;
-    data->columnspacing = args.columnspacing;
-    data->rowspacing = args.rowspacing;
+    memset(data, 0, sizeof(UiGtkTabView));
+    data->margin = args->margin;
+    data->spacing = args->spacing;
+    data->columnspacing = args->columnspacing;
+    data->rowspacing = args->rowspacing;
     
     ui_tabview_get_func getfunc = NULL;
     ui_tabview_set_func setfunc = NULL;
     
     GtkWidget *widget = NULL;
     GtkWidget *data_widget = NULL;
-    switch(args.tabview) {
+    switch(args->tabview) {
         case UI_TABVIEW_DOC: {
             // TODO
             break;
@@ -715,6 +757,7 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
             GtkWidget *sidebar = gtk_stack_sidebar_new();
             BOX_ADD(widget, sidebar);
             GtkWidget *stack = gtk_stack_new();
+            g_signal_connect(stack, "notify::visible-child", G_CALLBACK(tabview_stack_changed), data);
             gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN);
             gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack));
             BOX_ADD_EXPAND(widget, stack);
@@ -734,13 +777,18 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
         case UI_TABVIEW_INVISIBLE: /* fall through */
         case UI_TABVIEW_NAVIGATION_TOP2: {
             widget = gtk_notebook_new();
+            g_signal_connect(
+                    widget,
+                    "switch-page",
+                    G_CALLBACK(tabview_switch_page),
+                    data);
             data_widget = widget;
             data->select_tab = ui_notebook_tab_select;
             data->remove_tab = ui_notebook_tab_remove;
             data->add_tab = ui_notebook_tab_add;
             getfunc = ui_notebook_get;
             setfunc = ui_notebook_set;
-            if(args.tabview == UI_TABVIEW_INVISIBLE) {
+            if(args->tabview == UI_TABVIEW_INVISIBLE) {
                 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE);
                 gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE);
             }
@@ -749,8 +797,8 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
     }
     
     UiObject* current = uic_current_obj(obj);
-    if(args.value || args.varname) {
-        UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+    if(args->value || args->varname) {
+        UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
         UiInteger *i = var->value;
         i->get = getfunc;
         i->set = setfunc;
@@ -759,10 +807,10 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
     
     g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
     data->widget = data_widget;
-    data->subcontainer = args.subcontainer;
+    data->subcontainer = args->subcontainer;
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, widget, TRUE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, widget);
     
     UiObject *newobj = uic_object_new(obj, widget);
     newobj->container = ui_tabview_container(obj, widget);
@@ -872,14 +920,14 @@ void ui_headerbar_end_create(UiObject *obj) {
     hb_set_part(obj, 1);
 }
 
-UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) {
     UiObject *current = uic_current_obj(obj);
     UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
-    GtkWidget *box = ui_gtk_hbox_new(args.alt_spacing);
-    ui_set_name_and_style(box, args.name, args.style_class);
-    ct->add(ct, box, FALSE);
+    GtkWidget *box = ui_gtk_hbox_new(args->alt_spacing);
+    ui_set_name_and_style(box, args->name, args->style_class);
+    ct->add(ct, box);
     
     UiObject *newobj = uic_object_new(obj, box);
     newobj->container = ui_headerbar_fallback_container(obj, box);
@@ -910,14 +958,14 @@ UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar
     return (UiContainer*)ct;
 }
 
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget) {
     UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
     BOX_ADD(ct->widget, widget);
 }
 
 #if GTK_CHECK_VERSION(3, 10, 0)
 
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
     GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar");
     if(!headerbar) {
         return ui_headerbar_fallback_create(obj, args);
@@ -940,7 +988,7 @@ UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
     return (UiContainer*)ct;
 }
 
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget) {
     UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
     if(hb->part == 0) {
         UI_HEADERBAR_PACK_START(ct->widget, widget);
@@ -958,7 +1006,7 @@ void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill)
 
 #else
 
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
     return ui_headerbar_fallback_create(obj, args);  
 }
 
@@ -967,15 +1015,15 @@ UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
 /* -------------------- Sidebar -------------------- */
 
 #ifdef UI_LIBADWAITA
-UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
+UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
     GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
     if(!sidebar_toolbar_view) {
         fprintf(stderr, "Error: window is not configured for sidebar\n");
         return NULL;
     }
     
-    GtkWidget *box = ui_gtk_vbox_new(args.spacing);
-    ui_box_set_margin(box, args.margin);
+    GtkWidget *box = ui_gtk_vbox_new(args->spacing);
+    ui_box_set_margin(box, args->margin);
     adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
     
     UiObject *newobj = uic_object_new(obj, box);
@@ -985,11 +1033,11 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
     return box;
 }
 #else
-UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
+UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
     GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
     
-    GtkWidget *box = ui_gtk_vbox_new(args.spacing);
-    ui_box_set_margin(box, args.margin);
+    GtkWidget *box = ui_gtk_vbox_new(args->spacing);
+    ui_box_set_margin(box, args->margin);
     BOX_ADD_EXPAND(sidebar_vbox, box);
     
     UiObject *newobj = uic_object_new(obj, box);
@@ -1019,18 +1067,18 @@ static GtkWidget* create_paned(UiOrientation orientation) {
 
 
 
-static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs args) {
+static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     GtkWidget *pane0 = create_paned(orientation);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, pane0, TRUE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, pane0);
     
-    int max = args.max_panes == 0 ? 2 : args.max_panes;
+    int max = args->max_panes == 0 ? 2 : args->max_panes;
     
     UiObject *newobj = uic_object_new(obj, pane0);
-    newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args.initial_position);
+    newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position);
     uic_obj_add(obj, newobj);
     
     g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container);
@@ -1038,11 +1086,11 @@ static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSpl
     return pane0;
 }
 
-UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args) {
+UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
     return splitpane_create(obj, UI_HORIZONTAL, args);
 }
 
-UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args) {
+UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
     return splitpane_create(obj, UI_VERTICAL, args);
 }
 
@@ -1058,7 +1106,7 @@ UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientatio
     return (UiContainer*)ct;
 }
 
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) {
     UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct;
     
     if(s->nchildren >= s->max) {
@@ -1151,7 +1199,7 @@ static void update_itemlist(UiList *list, int c) {
         UiObject *item_obj = cxMapGet(ct->current_items, key);
         if(item_obj) {
             // re-add previously created widget
-            ui_box_container_add(ct->container, item_obj->widget, FALSE);
+            ui_box_container_add(ct->container, item_obj->widget);
         } else {
             // create new widget and object for this list element
             CxMempool *mp = cxMempoolCreateSimple(256);
@@ -1166,7 +1214,7 @@ static void update_itemlist(UiList *list, int c) {
                     ct->columnspacing,
                     ct->rowspacing,
                     ct->margin);
-            ui_box_container_add(ct->container, obj->widget, FALSE);
+            ui_box_container_add(ct->container, obj->widget);
             if(ct->create_ui) {
                 ct->create_ui(obj, index, elm, ct->userdata);
             }
@@ -1187,33 +1235,33 @@ static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *con
     free(container);
 }
 
-UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) {
+UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
     UiObject *current = uic_current_obj(obj);
     UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     
-    GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
-    ui_set_name_and_style(box, args.name, args.style_class);
-    GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
-    ct->add(ct, widget, TRUE);
+    GtkWidget *box = args->container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
+    ui_set_name_and_style(box, args->name, args->style_class);
+    GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
+    ct->add(ct, widget);
     
     UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
     container->parent = obj;
     container->widget = box;
-    container->container = ui_box_container(current, box, args.container);
-    container->create_ui = args.create_ui;
-    container->userdata = args.userdata;
-    container->subcontainer = args.subcontainer;
+    container->container = ui_box_container(current, box, args->container);
+    container->create_ui = args->create_ui;
+    container->userdata = args->userdata;
+    container->subcontainer = args->subcontainer;
     container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
     container->current_items->collection.advanced_destructor = remove_item;
     container->current_items->collection.destructor_data = container;
-    container->margin = args.sub_margin;
-    container->spacing = args.sub_spacing;
-    container->columnspacing = args.sub_columnspacing;
-    container->rowspacing = args.sub_rowspacing;
+    container->margin = args->sub_margin;
+    container->spacing = args->sub_spacing;
+    container->columnspacing = args->sub_columnspacing;
+    container->rowspacing = args->sub_rowspacing;
     container->remove_items = TRUE;
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_LIST);
     if(var) {
         UiList *list = var->value;
         list->obj = container;
@@ -1240,7 +1288,7 @@ UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) {
 
 void ui_layout_fill(UiObject *obj, UiBool fill) {
     UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.fill = ui_bool2lb(fill);
+    ct->layout.fill = fill;
 }
 
 void ui_layout_hexpand(UiObject *obj, UiBool expand) {
index b39a3e4f4b485cd5368d98ecd0ceedb0e97ee831..5f447662477881ec25a9b4c8ca8bfabd8bd37d9d 100644 (file)
@@ -44,23 +44,15 @@ extern "C" {
 #endif
   
 #define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
-#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE)
-#define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE)
     
-typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*, UiBool);
+typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*);
 
 typedef struct UiDocumentView UiDocumentView;
 
 
-typedef enum UiLayoutBool {
-    UI_LAYOUT_UNDEFINED = 0,
-    UI_LAYOUT_TRUE,
-    UI_LAYOUT_FALSE,
-} UiLayoutBool;
-
 typedef struct UiLayout UiLayout;
 struct UiLayout {
-    UiLayoutBool fill;
+    UiBool       fill;
     UiBool       newline;
     char         *label;
     UiBool       hexpand;
@@ -78,7 +70,7 @@ struct UiContainer {
     UIMENU menu;
     GtkWidget *current;
     
-    void (*add)(UiContainer*, GtkWidget*, UiBool);
+    void (*add)(UiContainer*, GtkWidget*);
     UiLayout layout;
     
     int close;
@@ -122,6 +114,8 @@ typedef struct UiGtkTabView {
     int spacing;
     int columnspacing;
     int rowspacing;
+    ui_callback onchange;
+    void *onchangedata;
 } UiGtkTabView;
 
 
@@ -170,13 +164,13 @@ GtkWidget* ui_subcontainer_create(
         int margin);
 
 UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
 
 GtkWidget* ui_box_set_margin(GtkWidget *box, int margin);
-UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type);
+UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type);
 
 UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_box_container_add(UiContainer *ct, GtkWidget *widget);
 
 GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing);
 UiContainer* ui_grid_container(
@@ -186,22 +180,22 @@ UiContainer* ui_grid_container(
         UiBool def_vexpand,
         UiBool def_hfill,
         UiBool def_vfill);
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget);
 
 UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
 
 UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander);
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_expander_container_add(UiContainer *ct, GtkWidget *widget);
 
 UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget);
 
 UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget);
 
 UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget);
 
 
 UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview);
@@ -210,11 +204,11 @@ void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab);
 
 #if GTK_CHECK_VERSION(3, 10, 0)
 UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget);
 #endif
 
 UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget);
 
 #ifdef __cplusplus
 }
index 78ff754a5b28696443ec994d4cd411c55c5cbd1b..40fcde1e376fcbb2774cc2d79d9d0e990a3c26f6 100644 (file)
@@ -46,19 +46,19 @@ static void set_alignment(GtkWidget *widget, float xalign, float yalign) {
 #endif
 }
 
-UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
+UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     const char *css_class = NULL;
     char *markup = NULL;
-    if(args.label) {
+    if(args->label) {
         #if GTK_MAJOR_VERSION < 3
-            switch(args.style) {
+            switch(args->style) {
                 case UI_LABEL_STYLE_DEFAULT: break;
                 case UI_LABEL_STYLE_TITLE: {
-                    cxmutstr m = cx_asprintf("<b>%s</b>", args.label);
+                    cxmutstr m = cx_asprintf("<b>%s</b>", args->label);
                     markup = m.ptr;
-                    args.label = NULL;
+                    args->label = NULL;
                 }
                 case UI_LABEL_STYLE_SUBTITLE: {
                     break;
@@ -68,7 +68,7 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
                 }
             }
 #       else
-            switch(args.style) {
+            switch(args->style) {
                 case UI_LABEL_STYLE_DEFAULT: break;
                 case UI_LABEL_STYLE_TITLE: {
                     css_class = "ui_label_title";
@@ -87,7 +87,7 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
     }
 
     
-    GtkWidget *widget = gtk_label_new(args.label);
+    GtkWidget *widget = gtk_label_new(args->label);
     if(markup) {
         gtk_label_set_markup(GTK_LABEL(widget), markup);
         free(markup);
@@ -97,7 +97,7 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
         WIDGET_ADD_CSS_CLASS(widget, css_class);
     }
     
-    switch(args.align) {
+    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;
@@ -105,7 +105,7 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
     }
     
 
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+    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;
@@ -113,19 +113,19 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
         value->set = ui_label_set;
     }
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, widget, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, widget);
     
     return widget;
 }
 
-UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) {
-    args.align = UI_ALIGN_LEFT;
+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;
+UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
+    args->align = UI_ALIGN_RIGHT;
     return ui_label_create(obj, args);
 }
 
@@ -150,7 +150,7 @@ void ui_label_set(UiString *s, const char *value) {
 UIWIDGET ui_space_deprecated(UiObject *obj) {
     GtkWidget *widget = gtk_label_new("");
     UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget, TRUE);
+    ct->add(ct, widget);
     
     return widget;
 }
@@ -162,7 +162,7 @@ UIWIDGET ui_separator_deprecated(UiObject *obj) {
     GtkWidget *widget = gtk_hseparator_new();
 #endif
     UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget, FALSE);
+    ct->add(ct, widget);
     
     return widget;
 }
@@ -174,14 +174,14 @@ typedef struct UiProgressBarRange {
     double max;
 } UiProgressBarRange;
 
-UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) {
+UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     GtkWidget *progressbar = gtk_progress_bar_new();
-    if(args.max > args.min) {
+    if(args->max > args->min) {
         UiProgressBarRange *range = malloc(sizeof(UiProgressBarRange));
-        range->min = args.min;
-        range->max = args.max;
+        range->min = args->min;
+        range->max = args->max;
         g_signal_connect(
                 progressbar,
                 "destroy",
@@ -191,7 +191,7 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) {
     }
     
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_DOUBLE);
+    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;
@@ -200,8 +200,8 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) {
         ui_progressbar_set(value, value->value);
     }
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, progressbar, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, progressbar);
     
     return progressbar;
 }
@@ -228,12 +228,12 @@ void ui_progressbar_set(UiDouble *d, double value) {
 
 /* ------------------------- progress spinner ------------------------- */
 
-UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args) {
+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);
+    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;
@@ -242,8 +242,8 @@ UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args)
         ui_spinner_set(value, value->value);
     }
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, spinner, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, spinner);
     
     return spinner;
 }
index 38ebe178406a567c021dce84c48b5e8163ec1ac7..3c83f111d8f944b362bc05f45cb55d347ee1e6ea 100644 (file)
 #include "entry.h"
 
 
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) {
+UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
     double min = 0;
     double max = 1000;
     
     UiObject* current = uic_current_obj(obj);
     
     UiVar *var = NULL;
-    if(args.varname) {
-        var = uic_get_var(obj->ctx, args.varname);
+    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(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);
         }
     }
     
@@ -61,18 +61,18 @@ UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) {
         min = r->min;
         max = r->max;
     }
-    if(args.step == 0) {
-        args.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, args.step);
-    ui_set_name_and_style(spin, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, spin, args.groups);
-    gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args.digits);
+    GtkWidget *spin = gtk_spin_button_new_with_range(min, max, args->step);
+    ui_set_name_and_style(spin, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, spin, args->groups);
+    gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args->digits);
     UiObserver **obs = NULL;
     if(var) {
         double value = 0;
@@ -115,8 +115,8 @@ UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) {
     event->obj = obj;
     event->var = var;
     event->observers = obs;
-    event->callback = args.onchange;
-    event->userdata = args.onchangedata;
+    event->callback = args->onchange;
+    event->userdata = args->onchangedata;
 
     g_signal_connect(
             spin,
@@ -129,8 +129,8 @@ UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) {
             G_CALLBACK(ui_destroy_vardata),
             event);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, spin, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, spin);
     
     return spin;
 }
@@ -150,7 +150,8 @@ void ui_spinner_changed(GtkSpinButton *spinner, UiVarEventData *event) {
     e.obj = event->obj;
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
-    e.eventdata = &value;
+    e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = (int64_t)value;
     
     if(event->callback) {
index dcaff88a05fb3abced071f17a48a590cc85da71c..6883575f3b3b1194633de428adafe4c1f1848baf 100644 (file)
@@ -45,7 +45,7 @@ UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) {
     }
     
     UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget, TRUE);
+    ct->add(ct, widget);
     
     return widget;
 }
index ea2f6bbaa7d988500c45a8d0dd218b31f4c43024..425af82ef311bb96c428b9c51ae1b04cf64899bc 100644 (file)
@@ -63,7 +63,7 @@ static gboolean imageviewer_draw(GtkWidget *widget, cairo_t *cr, gpointer userda
 
 #endif
 
-UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
+UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
     UiObject *current = uic_current_obj(obj);
     
     GtkWidget *drawingarea = gtk_drawing_area_new();
@@ -78,10 +78,10 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
     widget = eventbox;
 #endif
     
-    if(args.scrollarea) {
+    if(args->scrollarea) {
         toplevel = SCROLLEDWINDOW_NEW();
         SCROLLEDWINDOW_SET_CHILD(toplevel, widget);
-        args.adjustwidgetsize = TRUE;
+        args->adjustwidgetsize = TRUE;
     } else {
         toplevel = widget;
     }
@@ -89,29 +89,29 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
     UiImageViewer *imgviewer = malloc(sizeof(UiImageViewer));
     memset(imgviewer, 0, sizeof(UiImageViewer));
     imgviewer->obj = obj;
-    imgviewer->onbuttonpress = args.onbuttonpress;
-    imgviewer->onbuttonpressdata = args.onbuttonpressdata;
-    imgviewer->onbuttonrelease = args.onbuttonrelease;
-    imgviewer->onbuttonreleasedata = args.onbuttonreleasedata;
-    if(args.image_padding > 0) {
-        imgviewer->padding_left = args.image_padding;
-        imgviewer->padding_right = args.image_padding;
-        imgviewer->padding_top = args.image_padding;
-        imgviewer->padding_bottom = args.image_padding;
+    imgviewer->onbuttonpress = args->onbuttonpress;
+    imgviewer->onbuttonpressdata = args->onbuttonpressdata;
+    imgviewer->onbuttonrelease = args->onbuttonrelease;
+    imgviewer->onbuttonreleasedata = args->onbuttonreleasedata;
+    if(args->image_padding > 0) {
+        imgviewer->padding_left = args->image_padding;
+        imgviewer->padding_right = args->image_padding;
+        imgviewer->padding_top = args->image_padding;
+        imgviewer->padding_bottom = args->image_padding;
     } else {
-        imgviewer->padding_left = args.image_padding_left;
-        imgviewer->padding_right = args.image_padding_right;
-        imgviewer->padding_top = args.image_padding_top;
-        imgviewer->padding_bottom = args.image_padding_bottom;
+        imgviewer->padding_left = args->image_padding_left;
+        imgviewer->padding_right = args->image_padding_right;
+        imgviewer->padding_top = args->image_padding_top;
+        imgviewer->padding_bottom = args->image_padding_bottom;
     }
-    imgviewer->adjustwidgetsize = args.adjustwidgetsize;
-    imgviewer->autoscale = args.autoscale;
-    imgviewer->useradjustable = args.useradjustable;
+    imgviewer->adjustwidgetsize = args->adjustwidgetsize;
+    imgviewer->autoscale = args->autoscale;
+    imgviewer->useradjustable = args->useradjustable;
     imgviewer->zoom_scale = 20;
     
     g_object_set_data_full(G_OBJECT(drawingarea), "uiimageviewer", imgviewer, (GDestroyNotify)imageviewer_destroy);
     
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC);
+    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
     imgviewer->var = var;
     imgviewer->widget = drawingarea;
     
@@ -136,7 +136,7 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
             imgviewer,
             NULL);
     
-    if(args.useradjustable) {
+    if(args->useradjustable) {
         gtk_widget_set_focusable(drawingarea, TRUE);
     }
     
@@ -182,13 +182,13 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
 
 #endif
     
-    if(args.contextmenu) {
-        UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, widget);
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, widget);
         ui_widget_set_contextmenu(widget, menu);
     }
        
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, toplevel, TRUE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, toplevel);
     
     return toplevel;
 }
@@ -438,6 +438,7 @@ static void imgviewer_button_event(
     event.window = event.obj->window;
     event.document = event.obj->ctx->document;
     event.eventdata = NULL;
+    event.eventdatatype = 0;
     event.intval = gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(gesture));
     event.set = 0;
     callback(&event, userdata);
index 978ab532780fcf7e823a7b11754a6cabeda3d8f8..be9c00ae911ee2d606c27983fe459f7d0e877955 100644 (file)
@@ -48,6 +48,15 @@ void* ui_strmodel_getvalue(void *elm, int column) {
     return column == 0 ? elm : NULL;
 }
 
+static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
+    if(model->getvalue2) {
+        return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
+    } else if(model->getvalue) {
+        return model->getvalue(elm, col);
+    }
+    return NULL;
+}
+
 /*
 static GtkTargetEntry targetentries[] =
     {
@@ -73,6 +82,7 @@ static void listview_copy_static_elements(UiListView *listview, char **elm, size
 typedef struct _ObjWrapper {
     GObject parent_instance;
     void *data;
+    int i;
 } ObjWrapper;
 
 typedef struct _ObjWrapperClass {
@@ -89,9 +99,10 @@ static void obj_wrapper_init(ObjWrapper *self) {
     self->data = NULL;
 }
 
-ObjWrapper* obj_wrapper_new(void* data) {
+ObjWrapper* obj_wrapper_new(void* data, int i) {
     ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL);
     obj->data = data;
+    obj->i = i;
     return obj;
 }
 
@@ -122,20 +133,21 @@ static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item,
 
 static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
     UiColData *col = userdata;
+    UiList *list = col->listview->var ? col->listview->var->value : NULL;
     
     ObjWrapper *obj = gtk_list_item_get_item(item);
     UiModel *model = col->listview->model;
     UiModelType type = model->types[col->model_column];
     
-    void *data = model->getvalue(obj->data, col->data_column);
+    UiBool freevalue = FALSE;
+    void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
     GtkWidget *child = gtk_list_item_get_child(item);
     
-    bool freevalue = TRUE;
     switch(type) {
-        case UI_STRING: {
-            freevalue = FALSE;
-        }
         case UI_STRING_FREE: {
+            freevalue = TRUE;
+        }
+        case UI_STRING: {
             gtk_label_set_label(GTK_LABEL(child), data);
             if(freevalue) {
                 free(data);
@@ -157,10 +169,13 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
             break;
         }
         case UI_ICON_TEXT: {
-            freevalue = FALSE;
+            
         }
         case UI_ICON_TEXT_FREE: {
-            void *data2 = model->getvalue(obj->data, col->data_column+1);
+            void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
+            if(type == UI_ICON_TEXT_FREE) {
+                freevalue = TRUE;
+            }
             GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
             GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
             if(data && image) {
@@ -189,34 +204,41 @@ static GtkSelectionModel* create_selection_model(UiListView *listview, GListStor
     return selection_model;
 }
 
-static UiListView* create_listview(UiObject *obj, UiListArgs args) {
+static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
     UiListView *tableview = malloc(sizeof(UiListView));
     memset(tableview, 0, sizeof(UiListView));
     tableview->obj = obj;
-    tableview->model = args.model;
-    tableview->onactivate = args.onactivate;
-    tableview->onactivatedata = args.onactivatedata;
-    tableview->onselection = args.onselection;
-    tableview->onselectiondata = args.onselectiondata;
-    tableview->ondragstart = args.ondragstart;
-    tableview->ondragstartdata = args.ondragstartdata;
-    tableview->ondragcomplete = args.ondragcomplete;
-    tableview->ondragcompletedata = args.ondragcompletedata;
-    tableview->ondrop = args.ondrop;
-    tableview->ondropdata = args.ondropsdata;
+    tableview->model = args->model;
+    tableview->onactivate = args->onactivate;
+    tableview->onactivatedata = args->onactivatedata;
+    tableview->onselection = args->onselection;
+    tableview->onselectiondata = args->onselectiondata;
+    tableview->ondragstart = args->ondragstart;
+    tableview->ondragstartdata = args->ondragstartdata;
+    tableview->ondragcomplete = args->ondragcomplete;
+    tableview->ondragcompletedata = args->ondragcompletedata;
+    tableview->ondrop = args->ondrop;
+    tableview->ondropdata = args->ondropdata;
     tableview->selection.count = 0;
     tableview->selection.rows = NULL;
     return tableview;
 }
 
-UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     // to simplify things and share code with ui_table_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
-    args.model = model;
+    if(args->getvalue2) {
+        model->getvalue2 = args->getvalue2;
+        model->getvalue2data = args->getvalue2data;
+    } else if(args->getvalue) {
+        model->getvalue = args->getvalue;
+    } else {
+        model->getvalue = ui_strmodel_getvalue;
+    }
+    args->model = model;
     
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     UiListView *listview = create_listview(obj, args);
@@ -230,10 +252,10 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
     g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
     g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
     
-    GtkSelectionModel *selection_model = create_selection_model(listview, ls, args.multiselection);
+    GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
     GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init listview
     listview->widget = view;
@@ -256,21 +278,21 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
         list->setselection = ui_listview_setselection2;
         
         ui_update_liststore(ls, list);
-    } else if (args.static_elements && args.static_nelm > 0) {
-        listview_copy_static_elements(listview, args.static_elements, args.static_nelm);
+    } else if (args->static_elements && args->static_nelm > 0) {
+        listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
         listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
         ui_update_liststore_static(ls, listview->elements, listview->nelm);
     }
     
     // event handling
-    if(args.onactivate) {
+    if(args->onactivate) {
         // columnview and listview can use the same callback function, because
         // the first parameter (which is technically a different pointer type)
         // is ignored
         g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
     }
-    if(args.contextmenu) {
-        UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
         ui_widget_set_contextmenu(view, menu);
     }
     
@@ -282,8 +304,8 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, scroll_area, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, scroll_area);
     
     // ct->current should point to view, not scroll_area, to make it possible
     // to add a context menu
@@ -292,14 +314,21 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
     return scroll_area;
 }
 
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     // to simplify things and share code with ui_tableview_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
-    args.model = model;
+    if(args->getvalue2) {
+        model->getvalue2 = args->getvalue2;
+        model->getvalue2data = args->getvalue2data;
+    } else if(args->getvalue) {
+        model->getvalue = args->getvalue;
+    } else {
+        model->getvalue = ui_strmodel_getvalue;
+    }
+    args->model = model;
     
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     UiListView *listview = create_listview(obj, args);
@@ -316,7 +345,7 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
     GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
     gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init listview
     listview->widget = view;
@@ -339,20 +368,20 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
         list->setselection = ui_combobox_setselection;
         
         ui_update_liststore(ls, list);
-    } else if (args.static_elements && args.static_nelm > 0) {
-        listview_copy_static_elements(listview, args.static_elements, args.static_nelm);
+    } else if (args->static_elements && args->static_nelm > 0) {
+        listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
         listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
         ui_update_liststore_static(ls, listview->elements, listview->nelm);
     }
     
     // event handling
-    if(args.onactivate) {
+    if(args->onactivate) {
         g_signal_connect(view, "notify::selected", G_CALLBACK(ui_dropdown_notify), listview);
     }
     
     // add widget to parent 
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, view, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, view);
     return view;
 }
 
@@ -365,7 +394,7 @@ void ui_combobox_select(UIWIDGET dropdown, int index) {
     gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
 }
 
-UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
@@ -375,10 +404,10 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     // and list updates
     UiListView *tableview = create_listview(obj, args);
     
-    GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args.multiselection);
+    GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
     GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init tableview
     tableview->widget = view;
@@ -393,7 +422,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     
     
     // create columns from UiModel
-    UiModel *model = args.model;
+    UiModel *model = args->model;
     int columns = model ? model->columns : 0;
     
     tableview->columns = calloc(columns, sizeof(UiColData));
@@ -439,11 +468,11 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     }
     
     // event handling
-    if(args.onactivate) {
+    if(args->onactivate) {
         g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
     }
-    if(args.contextmenu) {
-        UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
         ui_widget_set_contextmenu(view, menu);
     }
     
@@ -455,8 +484,8 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, scroll_area, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, scroll_area);
     
     // ct->current should point to view, not scroll_area, to make it possible
     // to add a context menu
@@ -482,6 +511,7 @@ static void listview_event(ui_callback cb, void *cbdata, UiListView *view) {
     event.window = event.obj->window;
     event.intval = view->selection.count;
     event.eventdata = &view->selection;
+    event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
     event.set = ui_get_setop();
     if(cb) {
         cb(&event, cbdata);
@@ -525,6 +555,7 @@ void ui_dropdown_notify(GtkWidget *dropdown, GObject *pspec, gpointer userdata)
         event.window = event.obj->window;
         event.intval = index;
         event.eventdata = eventdata->data;
+        event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
         event.set = ui_get_setop();
         view->onactivate(&event, view->onactivatedata);
     }
@@ -562,6 +593,7 @@ void ui_dropdown_activate(GtkDropDown* self, gpointer userdata) {
         event.window = event.obj->window;
         event.intval = view->selection.count;
         event.eventdata = &view->selection;
+        event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
         event.set = ui_get_setop();
         view->onactivate(&event, view->onactivatedata);
     }
@@ -569,9 +601,10 @@ void ui_dropdown_activate(GtkDropDown* self, gpointer userdata) {
 
 void ui_update_liststore(GListStore *liststore, UiList *list) {
     g_list_store_remove_all(liststore);
+    int i = 0;
     void *elm = list->first(list);
     while(elm) {
-        ObjWrapper *obj = obj_wrapper_new(elm);
+        ObjWrapper *obj = obj_wrapper_new(elm, i++);
         g_list_store_append(liststore, obj);
         elm = list->next(list);
     }
@@ -580,7 +613,7 @@ void ui_update_liststore(GListStore *liststore, UiList *list) {
 void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) {
     g_list_store_remove_all(liststore);
     for(int i=0;i<nelm;i++) {
-        ObjWrapper *obj = obj_wrapper_new(elm[i]);
+        ObjWrapper *obj = obj_wrapper_new(elm[i], i);
         g_list_store_append(liststore, obj);
     }
 }
@@ -592,7 +625,7 @@ void ui_listview_update2(UiList *list, int i) {
     } else {
         void *value = list->get(list, i);
         if(value) {
-            ObjWrapper *obj = obj_wrapper_new(value);
+            ObjWrapper *obj = obj_wrapper_new(value, i);
             // TODO: if index i is selected, the selection is lost
             // is it possible to update the item without removing it?
             int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
@@ -662,19 +695,22 @@ void ui_combobox_setselection(UiList *list, UiListSelection selection) {
 
 #else
 
-static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) {
+static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
     // set column values
     int c = 0;
     for(int i=0;i<model->columns;i++,c++) {
-        void *data = model->getvalue(elm, c);
+        UiBool freevalue = FALSE;
+        void *data = model_getvalue(model, list, elm, row, c, &freevalue);
 
         GValue value = G_VALUE_INIT;
         switch(model->types[i]) {
-            case UI_STRING: 
             case UI_STRING_FREE: {
+                freevalue = TRUE;
+            } 
+            case UI_STRING: {
                 g_value_init(&value, G_TYPE_STRING);
                 g_value_set_string(&value, data);
-                if(model->types[i] == UI_STRING_FREE) {
+                if(freevalue) {
                     free(data);
                 }
                 break;
@@ -727,11 +763,12 @@ static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *mod
                 }
 #endif
                 c++;
-
-                char *str = model->getvalue(elm, c);
+                
+                freevalue = FALSE;
+                char *str = model_getvalue(model, list, elm, row, c, &freevalue);
                 g_value_init(&value, G_TYPE_STRING);
                 g_value_set_string(&value, str);
-                if(model->types[i] == UI_ICON_TEXT_FREE) {
+                if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
                     free(str);
                 }
                 break;
@@ -764,12 +801,13 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
     
     if(list) {
         void *elm = list->first(list);
+        int i = 0;
        while(elm) {
             // insert new row
             GtkTreeIter iter;
             gtk_list_store_insert (store, &iter, -1);
             
-            update_list_row(store, &iter, model, elm);
+            update_list_row(store, &iter, model, list, elm, i++);
             
             // next row
             elm = list->next(list);
@@ -780,13 +818,13 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
 }
 
 
-UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
-    ui_set_name_and_style(view, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, view, args.groups);
+    ui_set_name_and_style(view, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, view, args->groups);
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
     gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
@@ -803,9 +841,16 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
 #endif
     
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    if(args->getvalue2) {
+        model->getvalue2 = args->getvalue2;
+        model->getvalue2data = args->getvalue2data;
+    } else if(args->getvalue) {
+        model->getvalue = args->getvalue;
+    } else {
+        model->getvalue = ui_strmodel_getvalue;
+    }
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    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);
@@ -835,24 +880,24 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
     // add callback
     UiTreeEventData *event = malloc(sizeof(UiTreeEventData));
     event->obj = obj;
-    event->activate = args.onactivate;
-    event->activatedata = args.onactivatedata;
-    event->selection = args.onselection;
-    event->selectiondata = args.onselectiondata;
+    event->activate = args->onactivate;
+    event->activatedata = args->onactivatedata;
+    event->selection = args->onselection;
+    event->selectiondata = args->onselectiondata;
     g_signal_connect(
             view,
             "destroy",
             G_CALLBACK(ui_destroy_userdata),
             event);
     
-    if(args.onactivate) {
+    if(args->onactivate) {
         g_signal_connect(
                 view,
                 "row-activated",
                 G_CALLBACK(ui_listview_activate_event),
                 event);
     }
-    if(args.onselection) {
+    if(args->onselection) {
         GtkTreeSelection *selection = gtk_tree_view_get_selection(
                 GTK_TREE_VIEW(view));
         g_signal_connect(
@@ -861,8 +906,8 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
                 G_CALLBACK(ui_listview_selection_event),
                 event);
     }
-    if(args.contextmenu) {
-        UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
         ui_widget_set_contextmenu(view, menu);
     }
     
@@ -875,7 +920,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     current->container->add(current->container, scroll_area, FALSE);
     
     // ct->current should point to view, not scroll_area, to make it possible
@@ -896,13 +941,13 @@ void ui_combobox_select(UIWIDGET dropdown, int index) {
     gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
 }
 
-UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+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;
+    UiModel *model = args->model;
     int columns = model ? model->columns : 0;
     
     int addi = 0;
@@ -959,7 +1004,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     
 #endif
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    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);
@@ -977,12 +1022,12 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     tableview->widget = view;
     tableview->var = var;
     tableview->model = model;
-    tableview->ondragstart = args.ondragstart;
-    tableview->ondragstartdata = args.ondragstartdata;
-    tableview->ondragcomplete = args.ondragcomplete;
-    tableview->ondragcompletedata = args.ondragcompletedata;
-    tableview->ondrop = args.ondrop;
-    tableview->ondropdata = args.ondropsdata;
+    tableview->ondragstart = args->ondragstart;
+    tableview->ondragstartdata = args->ondragstartdata;
+    tableview->ondragcomplete = args->ondragcomplete;
+    tableview->ondragcompletedata = args->ondragcompletedata;
+    tableview->ondrop = args->ondrop;
+    tableview->ondropdata = args->ondropdata;
     tableview->selection.count = 0;
     tableview->selection.rows = NULL;
     g_signal_connect(
@@ -1000,18 +1045,18 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     // add callback
     UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
     event->obj = obj;
-    event->activate = args.onactivate;
-    event->selection = args.onselection;
-    event->activatedata = args.onactivatedata;
-    event->selectiondata = args.onselectiondata;
-    if(args.onactivate) {
+    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(args.onselection) {
+    if(args->onselection) {
         GtkTreeSelection *selection = gtk_tree_view_get_selection(
                 GTK_TREE_VIEW(view));
         g_signal_connect(
@@ -1023,15 +1068,15 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     // TODO: destroy callback
     
     
-    if(args.ondragstart) {
-        ui_listview_add_dnd(tableview, &args);
+    if(args->ondragstart) {
+        ui_listview_add_dnd(tableview, args);
     }
-    if(args.ondrop) {
-        ui_listview_enable_drop(tableview, &args);
+    if(args->ondrop) {
+        ui_listview_enable_drop(tableview, args);
     }
       
     GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
-    if(args.multiselection) {
+    if(args->multiselection) {
         gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
     }
     
@@ -1043,8 +1088,8 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    if(args.contextmenu) {
-        UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, scroll_area);
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, scroll_area);
 #if GTK_MAJOR_VERSION >= 4
         ui_widget_set_contextmenu(scroll_area, menu);
 #else
@@ -1052,7 +1097,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
 #endif
     }
     
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     current->container->add(current->container, scroll_area, FALSE);
     
     // ct->current should point to view, not scroll_area, to make it possible
@@ -1075,7 +1120,7 @@ void ui_listview_update(UiList *list, int i) {
         GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
         GtkTreeIter iter;
         if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
-            update_list_row(GTK_LIST_STORE(store), &iter, view->model, elm);
+            update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
         }
     }
 }
@@ -1102,18 +1147,25 @@ void ui_listview_setselection(UiList *list, UiListSelection selection) {
 
 /* --------------------------- ComboBox ---------------------------  */
 
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+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 = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    if(args->getvalue2) {
+        model->getvalue2 = args->getvalue2;
+        model->getvalue2data = args->getvalue2data;
+    } else if(args->getvalue) {
+        model->getvalue = args->getvalue;
+    } else {
+        model->getvalue = ui_strmodel_getvalue;
+    }
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
     
-    GtkWidget *combobox = ui_create_combobox(obj, model, var, args.static_elements, args.static_nelm, args.onactivate, args.onactivatedata);
-    ui_set_name_and_style(combobox, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, combobox, args.groups);
-    UI_APPLY_LAYOUT1(current, args);
+    GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
+    ui_set_name_and_style(combobox, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, combobox, args->groups);
+    UI_APPLY_LAYOUT2(current, args);
     current->container->add(current->container, combobox, FALSE);
     current->container->current = combobox;
     return combobox;
@@ -1336,6 +1388,7 @@ static GdkContentProvider *ui_listview_dnd_prepare(GtkDragSource *source, double
         event.window = event.obj->window;
         event.document = event.obj->ctx->document;
         event.eventdata = dnd;
+        event.eventdatatype = UI_EVENT_DATA_DND;
         event.intval = 0;
         event.set = ui_get_setop();
         listview->ondragstart(&event, listview->ondragstartdata);
@@ -1372,6 +1425,7 @@ static void ui_listview_drag_end(GtkDragSource *self, GdkDrag *drag, gboolean de
         event.window = event.obj->window;
         event.document = event.obj->ctx->document;
         event.eventdata = &dnd;
+        event.eventdatatype = UI_EVENT_DATA_DND;
         event.intval = 0;
         event.set = ui_get_setop();
         listview->ondragcomplete(&event, listview->ondragcompletedata);
@@ -1401,6 +1455,7 @@ static gboolean ui_listview_drop(
         event.window = event.obj->window;
         event.document = event.obj->ctx->document;
         event.eventdata = &dnd;
+        event.eventdatatype = UI_EVENT_DATA_DND;
         event.intval = 0;
         event.set = ui_get_setop();
         listview->ondrop(&event, listview->ondropdata);
@@ -1758,7 +1813,7 @@ static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *subli
     cxListAdd(sublists, &uisublist);
 }
 
-UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
+UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
 #ifdef UI_GTK3
@@ -1766,7 +1821,7 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
 #else
     GtkWidget *listbox = gtk_list_box_new();
 #endif
-    if(!args.style_class) {
+    if(!args->style_class) {
 #if GTK_MAJOR_VERSION >= 4
         WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar");
 #else
@@ -1777,31 +1832,32 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
     GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
     SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
     
-    ui_set_name_and_style(listbox, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, listbox, args.groups);
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, scroll_area, TRUE);
+    ui_set_name_and_style(listbox, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, listbox, args->groups);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, scroll_area);
     
     UiListBox *uilistbox = malloc(sizeof(UiListBox));
     uilistbox->obj = obj;
     uilistbox->listbox = GTK_LIST_BOX(listbox);
-    uilistbox->getvalue = args.getvalue;
-    uilistbox->onactivate = args.onactivate;
-    uilistbox->onactivatedata = args.onactivatedata;
-    uilistbox->onbuttonclick = args.onbuttonclick;
-    uilistbox->onbuttonclickdata = args.onbuttonclickdata;
+    uilistbox->getvalue = args->getvalue;
+    uilistbox->getvaluedata = args->getvaluedata;
+    uilistbox->onactivate = args->onactivate;
+    uilistbox->onactivatedata = args->onactivatedata;
+    uilistbox->onbuttonclick = args->onbuttonclick;
+    uilistbox->onbuttonclickdata = args->onbuttonclickdata;
     uilistbox->sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), 4);
     uilistbox->sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_destroy;
     uilistbox->sublists->collection.destructor_data = obj;
     uilistbox->first_row = NULL;
     
-    if(args.sublists) {
+    if(args->sublists) {
         // static sublist initalization
-        if(args.numsublists == 0 && args.sublists) {
-            args.numsublists = INT_MAX;
+        if(args->numsublists == 0 && args->sublists) {
+            args->numsublists = INT_MAX;
         }
-        for(int i=0;i<args.numsublists;i++) {
-            UiSubList sublist = args.sublists[i];
+        for(int i=0;i<args->numsublists;i++) {
+            UiSubList sublist = args->sublists[i];
             if(!sublist.varname && !sublist.value) {
                 break;
             }
@@ -1812,7 +1868,7 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
         // fill items
         ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
     } else {
-        UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.dynamic_sublist, args.varname, UI_VAR_LIST);
+        UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
         if(var) {
             UiList *list = var->value;
             list->obj = uilistbox;
@@ -1834,7 +1890,7 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
                 G_CALLBACK(ui_destroy_sourcelist),
                 uilistbox);
     
-    if(args.onactivate) {
+    if(args->onactivate) {
         g_signal_connect(
                 listbox,
                 "row-activated",
@@ -1958,7 +2014,11 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
     void *elm = list->first(list);
     while(elm) {
         UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
-        listbox->getvalue(sublist->userdata, elm, index, &item);
+        if(listbox->getvalue) {
+            listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata);
+        } else {
+            item.label = strdup(elm);
+        }
         
         // create listbox item
         GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index);
@@ -2009,7 +2069,7 @@ void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user
     eventdata.sublist_index = sublist->index;
     eventdata.row_index = data->value0;
     eventdata.sublist_userdata = sublist->userdata;
-    eventdata.row_data = ui_list_get(eventdata.list, eventdata.row_index);
+    eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
     eventdata.event_data = data->customdata2;
     
     UiEvent event;
@@ -2017,6 +2077,7 @@ void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user
     event.window = event.obj->window;
     event.document = event.obj->ctx->document;
     event.eventdata = &eventdata;
+    event.eventdatatype = UI_EVENT_DATA_SUBLIST;
     event.intval = data->value0;
     event.set = ui_get_setop();
     
index 784e6447247cc814ecbdf21e625173499bba5aa4..bd490ab3250bcc8dd8f8d1bb2bd70be2cb5eda9e 100644 (file)
@@ -98,6 +98,7 @@ struct UiListBox {
     GtkListBox               *listbox;
     CxList                   *sublists; // contains UiListBoxSubList elements
     ui_sublist_getvalue_func getvalue;
+    void                     *getvaluedata;
     ui_callback              onactivate;
     void                     *onactivatedata;
     ui_callback              onbuttonclick;
index a54a34b86b20b4e74accbe5e724eb0c1acfb4f59..521bf91d9f8f05e24ea77a5407d6133599b409d4 100644 (file)
@@ -514,6 +514,7 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         event->callback = i->callback;
         event->value = 0;
         event->customdata = NULL;
+        event->customint = 0;
 
         g_signal_connect(
                 action,
@@ -613,6 +614,7 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject
     event->userdata = il->userdata;
     event->callback = il->callback;
     event->customdata = var;
+    event->customint = 0;
     event->value = 0;
     
     g_signal_connect(
@@ -638,6 +640,7 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent
     evt.window = event->obj->window;
     evt.document = event->obj->ctx->document;
     evt.eventdata = event->customdata;
+    evt.eventdatatype = event->customint;
     evt.intval = intval;
     event->callback(&evt, event->userdata);    
 }
@@ -652,6 +655,7 @@ void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* par
     evt.window = event->obj->window;
     evt.document = event->obj->ctx->document;
     evt.eventdata = ui_list_get(list, index);
+    evt.eventdatatype = UI_EVENT_DATA_LIST_ELM;
     evt.intval = index;
     event->callback(&evt, event->userdata);    
     
index c9921592cbdf934a4b2d2b87d1b7f3928857b3a0..45c5bfc19e60bafca0cbda4164328b3bdb4c6598 100644 (file)
@@ -62,6 +62,7 @@ static UIWIDGET ui_scrollbar(UiObject *obj, UiOrientation orientation, UiRange *
         event->callback = f;
         event->value = 0;
         event->customdata = NULL;
+        event->customint = 0;
         
         g_signal_connect(
                 G_OBJECT(scrollbar),
@@ -76,7 +77,7 @@ static UIWIDGET ui_scrollbar(UiObject *obj, UiOrientation orientation, UiRange *
     }
     
     UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, scrollbar, FALSE);
+    ct->add(ct, scrollbar);
     
     return scrollbar;
 }
@@ -95,6 +96,7 @@ gboolean ui_scrollbar_value_changed(GtkRange *range, UiEventData *event) {
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = event->value;
     event->callback(&e, event->userdata); 
     return TRUE;
index 475543c765bb96281d903212e22dab81185cc04f..9ea0c4ca2c55bd58b44dc0ff6463b060e379c91b 100644 (file)
@@ -107,13 +107,13 @@ static GtkTextBuffer* create_textbuffer(UiTextArea *textarea) {
     return buf;
 }
 
-UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
+UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
     UiObject* current = uic_current_obj(obj);
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_TEXT);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_TEXT);
     
     GtkWidget *text_area = gtk_text_view_new();
-    ui_set_name_and_style(text_area, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, text_area, args.groups);
+    ui_set_name_and_style(text_area, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, text_area, args->groups);
     
     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR);
     g_signal_connect(
@@ -127,8 +127,8 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
     uitext->ctx = obj->ctx;
     uitext->var = var;
     uitext->last_selection_state = 0;
-    uitext->onchange = args.onchange;
-    uitext->onchangedata = args.onchangedata;
+    uitext->onchange = args->onchange;
+    uitext->onchangedata = args->onchangedata;
     
     g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext);
     
@@ -155,8 +155,8 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
     gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_area), 2);
     
     // add
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, scroll_area, TRUE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, scroll_area);
     
     // bind value
     if(var) {
@@ -330,6 +330,7 @@ void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
     e.window = e.obj->window;
     e.document = textarea->ctx->document;
     e.eventdata = value;
+    e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
     e.intval = 0;
     e.set = ui_get_setop();
     
@@ -592,21 +593,21 @@ void ui_text_redo(UiText *value) {
 
 
 
-static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs args) {
+static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs *args) {
     GtkWidget *textfield = gtk_entry_new();
-    ui_set_name_and_style(textfield, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, textfield, args.groups);
+    ui_set_name_and_style(textfield, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, textfield, args->groups);
     
     UiObject* current = uic_current_obj(obj);
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
     
     UiTextField *uitext = malloc(sizeof(UiTextField));
     uitext->obj = obj;
     uitext->var = var;
-    uitext->onchange = args.onchange;
-    uitext->onchangedata = args.onchangedata;
-    uitext->onactivate = args.onactivate;
-    uitext->onactivatedata = args.onactivatedata;
+    uitext->onchange = args->onchange;
+    uitext->onchangedata = args->onchangedata;
+    uitext->onactivate = args->onactivate;
+    uitext->onactivatedata = args->onactivatedata;
     
     g_signal_connect(
                 textfield,
@@ -614,10 +615,10 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
                 G_CALLBACK(ui_textfield_destroy),
                 uitext);
     
-    if(args.width > 0) {
+    if(args->width > 0) {
         // TODO: gtk4
 #if GTK_MAJOR_VERSION <= 3
-        gtk_entry_set_width_chars(GTK_ENTRY(textfield), args.width);
+        gtk_entry_set_width_chars(GTK_ENTRY(textfield), args->width);
 #endif
     }
     if(frameless) {
@@ -628,8 +629,8 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
         gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
     }
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, textfield, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, textfield);
     
     if(var) {
         UiString *value = var->value;
@@ -647,7 +648,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
         value->obj = GTK_ENTRY(textfield);
     }
     
-    if(args.onchange || var) {
+    if(args->onchange || var) {
         g_signal_connect(
                 textfield,
                 "changed",
@@ -655,7 +656,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
                 uitext);
     }
     
-    if(args.onactivate) {
+    if(args->onactivate) {
         g_signal_connect(
                 textfield,
                 "activate",
@@ -666,15 +667,15 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
     return textfield;
 }
 
-UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) {
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
     return create_textfield(obj, FALSE, FALSE, args);
 }
 
-UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args) {
     return create_textfield(obj, TRUE, FALSE, args);
 }
 
-UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) {
     return create_textfield(obj, FALSE, TRUE, args);
 }
 
@@ -691,6 +692,7 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
     e.window = e.obj->window;
     e.document = textfield->obj->ctx->document;
     e.eventdata = value;
+    e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
     e.intval = 0;
     e.set = ui_get_setop();
     
@@ -710,6 +712,7 @@ void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
         e.window = e.obj->window;
         e.document = textfield->obj->ctx->document;
         e.eventdata = NULL;
+        e.eventdatatype = 0;
         e.intval = 0;
         e.set = ui_get_setop();
         textfield->onactivate(&e, textfield->onactivatedata);
@@ -807,6 +810,7 @@ void ui_path_button_clicked(GtkWidget *widget, UiEventDataExt *event) {
     evt.window = evt.obj->window;
     evt.document = evt.obj->ctx->document;
     evt.eventdata = elm->path;
+    evt.eventdatatype = UI_EVENT_DATA_STRING;
     evt.intval = event->value0;
     evt.set = ui_get_setop();
     event->callback(&evt, event->userdata);
@@ -888,6 +892,7 @@ static void ui_path_textfield_activate(GtkWidget *entry, UiPathTextField *pathtf
         evt.window = obj->window;
         evt.document = obj->ctx->document;
         evt.eventdata = (char*)text;
+        evt.eventdatatype = UI_EVENT_DATA_STRING;
         evt.intval = -1;
         pathtf->onactivate(&evt, pathtf->onactivatedata);
     }
@@ -915,22 +920,22 @@ static gboolean ui_path_textfield_key_controller(
     return FALSE;
 }
 
-UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
+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;
+    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;
@@ -940,8 +945,8 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
     pathtf->stack = gtk_stack_new();
     gtk_widget_set_name(pathtf->stack, "path-textfield-box");
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, pathtf->stack, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, pathtf->stack);
     
     pathtf->entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     pathtf->entry = gtk_entry_new();
@@ -973,7 +978,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
     gtk_stack_set_visible_child(GTK_STACK(pathtf->stack), pathtf->entry_box);
     
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+    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;
@@ -1076,22 +1081,22 @@ static GtkWidget* create_path_button_box() {
     return bb;
 }
 
-UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
+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;
+    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;
@@ -1112,7 +1117,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
             G_CALLBACK(ui_path_textfield_destroy),
             pathtf);
     
-    UI_APPLY_LAYOUT1(current, args);
+    UI_APPLY_LAYOUT2(current, args);
     current->container->add(current->container, eventbox, FALSE);
     
     // hbox as parent for the GtkEntry and GtkButtonBox
@@ -1137,7 +1142,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
             G_CALLBACK(ui_path_textfield_key_press),
             pathtf);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+    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;
index 60c4bac5f23853ac817e3fbd30dd6667b545ef3f..0409be93bf18715a30576aa342902671f3751b3a 100644 (file)
@@ -155,6 +155,7 @@ void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) {
         event->callback = item->args.onclick;
         event->userdata = item->args.onclickdata;
         event->customdata = NULL;
+        event->customint = 0;
         event->value = 0;
         
         g_signal_connect(
@@ -237,6 +238,7 @@ void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event)
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = NULL;
+    e.eventdatatype = 0;
     e.intval = gtk_toggle_tool_button_get_active(widget);
     
     if(event->callback) {
index 7e8e3a5864999417dd8bfa3975fca814be62557d..7a26a708dc98cb6fa1eb20bf83b7d4559b2d6f43 100644 (file)
@@ -191,6 +191,7 @@ static gboolean ui_job_finished(void *data) {
     event.document = job->obj->ctx->document;
     event.intval = 0;
     event.eventdata = NULL;
+    event.eventdatatype = 0;
 
     job->finish_callback(&event, job->finish_data);
     free(job);
index b98bb25fd6b3187b87e55af753e9ed57275290db..b66c695cd4abd84594ba4b4b1f73a4f9a4603943 100644 (file)
@@ -131,6 +131,7 @@ typedef struct UiEventData {
     ui_callback callback;
     void        *userdata;
     int         value;
+    int         customint;
     void        *customdata;
 } UiEventData;
 
index 9f3bebb95b63b7a11ac2694e5d93d04687f4e65e..3b9a94661a2356a1a6e27212fcfb26afea5eb2e5 100644 (file)
 
 #ifdef UI_WEBVIEW
 
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs args) {
+UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     GtkWidget *webview = webkit_web_view_new();
     
-    ui_set_name_and_style(webview, args.name, args.style_class);
+    ui_set_name_and_style(webview, args->name, args->style_class);
     
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC);
+    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
     if(var) {
         WebViewData *data = malloc(sizeof(WebViewData));
         memset(data, 0, sizeof(WebViewData));
@@ -59,9 +59,9 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs args) {
         }
     }
     
-    ui_set_widget_groups(obj->ctx, webview, args.groups);
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, webview, FALSE);
+    ui_set_widget_groups(obj->ctx, webview, args->groups);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, webview);
     
     return webview;
 }
@@ -115,7 +115,14 @@ void ui_webview_load_content(
         const char *mimetype,
         const char *encoding)
 {
+    WebViewData *data0 = g->obj;
+    if(!data0) {
+        return;
+    }
+    
     WebViewData data;
+    memset(&data, 0, sizeof(WebViewData));
+    data.webview = data0->webview;
     data.uri = (char*)uri;
     data.content = (char*)content;
     data.contentlength = contentlength;
index 505bca6499eff47839e533897e5f24edf717a224..36f446505d93daba204ba3f5e14d8932dcdfd4c4 100644 (file)
 
 #include "../common/object.h"
 
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     UIWIDGET widget = create_widget(obj, args, userdata);
     
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, widget, FALSE);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, widget);
     
     return widget;
 }
@@ -47,7 +47,7 @@ UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) {
     GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
     ui_set_name_and_style(widget, args->name, args->style_class);
     UI_APPLY_LAYOUT1(current, (*args));
-    current->container->add(current->container, widget, FALSE);
+    current->container->add(current->container, widget);
     return widget;
 }
 
index ca284c01d48a6a0edc5041c7842c8f66791d29a2..cdafae3d4678470360648ad225bd672240b4ba7b 100644 (file)
@@ -102,9 +102,7 @@ static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) {
 #endif
 
 static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool simple) {
-    CxMempool *mp = cxMempoolCreateSimple(256);
-    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
-    obj->ref = 0;
+    UiObject *obj = uic_object_new_toplevel();
    
 #ifdef UI_LIBADWAITA
     obj->widget = adw_application_window_new(ui_get_application());
@@ -114,8 +112,6 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
     obj->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 #endif
     
-    
-    obj->ctx = uic_context(obj, mp);
     obj->window = window_data;
     
 #if GTK_CHECK_VERSION(4, 0, 0)
@@ -316,6 +312,8 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
     evt.document = evt.obj->ctx->document;
     evt.window = evt.obj->window;
     evt.eventdata = NULL;
+    evt.eventdatatype = 0;
+    evt.eventdatatype = 0;
     evt.intval = 0;
     
     if(!strcmp(response, "btn1")) {
@@ -327,6 +325,7 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
     if(data->customdata) {
         GtkWidget *entry = data->customdata;
         evt.eventdata = (void*)ENTRY_GET_TEXT(GTK_ENTRY(entry));
+        evt.eventdatatype = UI_EVENT_DATA_STRING;
     }
     
     if(data->callback) {
@@ -340,6 +339,7 @@ void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
     event->callback = args.result;
     event->userdata = args.resultdata;
     event->customdata = NULL;
+    event->customint = 0;
     event->value = 0;
     event->obj = parent;
     
@@ -365,6 +365,7 @@ void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
         }
         adw_alert_dialog_set_extra_child(ADW_ALERT_DIALOG(dialog), entry);
         event->customdata = entry;
+        event->customint = 0;
     }
     
     g_signal_connect(
@@ -521,6 +522,7 @@ static void filechooser_opened(GObject *source, GAsyncResult *result, void *data
     flist.files = NULL;
     flist.nfiles = 0;
     evt.eventdata = &flist;
+    evt.eventdatatype = UI_EVENT_DATA_FILE_LIST;
     
     if(selection) {
         flist = listmodel2filelist(selection);
@@ -555,6 +557,7 @@ static void ui_gtkfilechooser(UiObject *obj, GtkFileChooserAction action, unsign
     event->callback = file_selected_callback;
     event->userdata = cbdata;
     event->customdata = NULL;
+    event->customint = 0;
     event->value = mode;
     event->obj = obj;
     
@@ -761,9 +764,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
         gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
     }
     
-    CxMempool *mp = cxMempoolCreateSimple(256);
-    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); 
-    obj->ctx = uic_context(obj, mp);
+    UiObject *obj = uic_object_new_toplevel(); 
     obj->widget = dialog;
     obj->ref = 0;
     obj->destroy = ui_window_widget_destroy;
index 7123858199c8248a3ce0ff0d7a5b5d391611fdec..fb578f787621d2482f3e20ae1086332943270c53 100644 (file)
@@ -36,7 +36,7 @@ extern "C" {
 #endif
 
 typedef struct UiButtonArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -58,7 +58,7 @@ typedef struct UiButtonArgs {
 } UiButtonArgs;
 
 typedef struct UiToggleArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -82,17 +82,17 @@ typedef struct UiToggleArgs {
     const int* groups;
 } UiToggleArgs;
  
-#define ui_button(obj, ...) ui_button_create(obj, (UiButtonArgs){ __VA_ARGS__ } )
-#define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_checkbox(obj, ...) ui_checkbox_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_switch(obj, ...) ui_switch_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
+#define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } )
+#define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_checkbox(obj, ...) ui_checkbox_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_switch(obj, ...) ui_switch_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
 
-UIEXPORT UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args);
-UIEXPORT UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args);
+UIEXPORT UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args);
+UIEXPORT UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args);
 
 
 
index 3f828ea6b219c9b598917fda72da67254a5b6198..75c78b002d14411795982e963ee221e8b9c56593 100644 (file)
@@ -59,7 +59,7 @@ typedef enum UiHeaderbarAlternative {
 
 
 typedef struct UiContainerArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -81,7 +81,7 @@ typedef struct UiContainerArgs {
 } UiContainerArgs;
 
 typedef struct UiFrameArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -104,7 +104,7 @@ typedef struct UiFrameArgs {
 } UiFrameArgs;
 
 typedef struct UiTabViewArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -116,6 +116,8 @@ typedef struct UiTabViewArgs {
     const char *style_class;
 
     UiTabViewType tabview;
+    ui_callback onchange;
+    void *onchangedata;
 
     UiSubContainerType subcontainer;
     
@@ -132,7 +134,7 @@ typedef struct UiTabViewArgs {
 } UiTabViewArgs;
 
 typedef struct UiHeaderbarArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -158,7 +160,7 @@ typedef struct UiSidebarArgs {
 } UiSidebarArgs;
 
 typedef struct UiSplitPaneArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -181,7 +183,7 @@ typedef struct UiSplitPaneArgs {
 } UiSplitPaneArgs;
 
 typedef struct UiItemListContainerArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -235,39 +237,39 @@ struct UiContainerX {
 
 #define UI_CTN(obj, ctn) for(ctn;ui_container_finish(obj);ui_container_begin_close(obj))
 
-#define ui_vbox(obj, ...) for(ui_vbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hbox(obj, ...) for(ui_hbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_grid(obj, ...) for(ui_grid_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_frame(obj, ...) for(ui_frame_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_expander(obj, ...) for(ui_expander_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_tabview(obj, ...) for(ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, (UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-
-#define ui_vbox0(obj) for(ui_vbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hbox0(obj) for(ui_hbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_grid0(obj) for(ui_grid_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_frame0(obj) for(ui_frame_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_expander0(obj) for(ui_expande_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_tabview0(obj) for(ui_tabview_create(obj, (UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_headerbar0(obj) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_sidebar0(obj) for(ui_sidebar_create(obj, (UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-
-#define ui_vbox_w(obj, w, ...) for(w = ui_vbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-
-#define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hsplitpane0(obj) for(ui_hsplitpane_create(obj, (UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vsplitpane0(obj) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-
-#define ui_hsplitpane_w(obj, w, ...) for(w = ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vsplitpane_w(obj, w, ...) for(w = ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vbox(obj, ...) for(ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hbox(obj, ...) for(ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_grid(obj, ...) for(ui_grid_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_frame(obj, ...) for(ui_frame_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_expander(obj, ...) for(ui_expander_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_tabview(obj, ...) for(ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, &(UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+
+#define ui_vbox0(obj) for(ui_vbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hbox0(obj) for(ui_hbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_grid0(obj) for(ui_grid_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_frame0(obj) for(ui_frame_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_expander0(obj) for(ui_expande_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_tabview0(obj) for(ui_tabview_create(obj, &(UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_headerbar0(obj) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_sidebar0(obj) for(ui_sidebar_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+
+#define ui_vbox_w(obj, w, ...) for(w = ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+
+#define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hsplitpane0(obj) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vsplitpane0(obj) for(ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+
+#define ui_hsplitpane_w(obj, w, ...) for(w = ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vsplitpane_w(obj, w, ...) for(w = ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 
 #define ui_tab(obj, label) for(ui_tab_create(obj, label);ui_container_finish(obj);ui_container_begin_close(obj))
 
@@ -275,35 +277,35 @@ struct UiContainerX {
 #define ui_headerbar_center(obj) for(ui_headerbar_center_create(obj);ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_headerbar_end(obj) for(ui_headerbar_end_create(obj);ui_container_finish(obj);ui_container_begin_close(obj))
 
-#define ui_itemlist(obj, ...) ui_itemlist_create(obj, (UiItemListContainerArgs) { __VA_ARGS__} )
+#define ui_itemlist(obj, ...) ui_itemlist_create(obj, &(UiItemListContainerArgs) { __VA_ARGS__} )
 
 UIEXPORT void ui_end(UiObject *obj); // deprecated
 UIEXPORT void ui_end_new(UiObject *obj); // TODO: rename to ui_end
     
-UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args);
-UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args);
-UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs args);
-
-UIEXPORT UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs args);
+UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args);
+UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args);
+UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs *args);
+
+UIEXPORT UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args);
 UIEXPORT void ui_tab_create(UiObject *obj, const char* title);
 UIEXPORT void ui_tabview_select(UIWIDGET tabview, int tab);
 UIEXPORT void ui_tabview_remove(UIWIDGET tabview, int tab);
 UIEXPORT UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index);
 
-UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args);
+UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args);
 UIEXPORT void ui_headerbar_start_create(UiObject *obj);
 UIEXPORT void ui_headerbar_center_create(UiObject *obj);
 UIEXPORT void ui_headerbar_end_create(UiObject *obj);
 
-UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args);
+UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args);
 
-UIEXPORT UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args);
+UIEXPORT UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args);
 
-UIEXPORT UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args);
-UIEXPORT UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args);
+UIEXPORT UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args);
+UIEXPORT UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args);
 
 UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBool visible);
 
@@ -342,6 +344,17 @@ UIEXPORT int ui_container_finish(UiObject *obj);
     if(args.rowspan > 0) ui_layout_rowspan(obj, args.rowspan); \
     /*force caller to add ';'*/(void)0
 
+#define UI_APPLY_LAYOUT2(obj, args) \
+    if(args->fill != UI_DEFAULT) ui_layout_fill(obj, args->fill == UI_ON ? 1 : 0 ); \
+    if(args->hexpand) ui_layout_hexpand(obj, 1); \
+    if(args->vexpand) ui_layout_vexpand(obj, 1); \
+    if(args->hfill) ui_layout_hfill(obj, 1); \
+    if(args->vfill) ui_layout_vfill(obj, 1); \
+    if(args->override_defaults) ui_layout_override_defaults(obj, 1); \
+    if(args->colspan > 0) ui_layout_colspan(obj, args->colspan); \
+    if(args->rowspan > 0) ui_layout_rowspan(obj, args->rowspan); \
+    /*force caller to add ';'*/(void)0
+
 
 #ifdef __cplusplus
 }
index 8ed861b6e9030e836ed9e61bd3ee6dc4dc65ab81..3cb3d6597f50a62e631f367915cc3766210a9117 100644 (file)
@@ -58,7 +58,7 @@ enum UiLabelStyle {
 typedef enum UiLabelStyle UiLabelStyle;
 
 typedef struct UiLabelArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -77,7 +77,7 @@ typedef struct UiLabelArgs {
 } UiLabelArgs;
 
 typedef struct UiProgressbarArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -96,7 +96,7 @@ typedef struct UiProgressbarArgs {
 } UiProgressbarArgs;
 
 typedef struct UiProgressbarSpinnerArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -113,24 +113,24 @@ typedef struct UiProgressbarSpinnerArgs {
 
 /* label widgets */
 
-#define ui_label(obj, ...) ui_label_create(obj, (UiLabelArgs) { __VA_ARGS__ })
-#define ui_llabel(obj, ...) ui_llabel_create(obj, (UiLabelArgs) { __VA_ARGS__ })
-#define ui_rlabel(obj, ...) ui_rlabel_create(obj, (UiLabelArgs) { __VA_ARGS__ })
+#define ui_label(obj, ...) ui_label_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
+#define ui_llabel(obj, ...) ui_llabel_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
+#define ui_rlabel(obj, ...) ui_rlabel_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
 
 
-UIEXPORT UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs args);
-UIEXPORT UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args);
-UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args);
+UIEXPORT UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs *args);
+UIEXPORT UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args);
+UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args);
 
 UIWIDGET ui_space_deprecated(UiObject *obj);
 
 /* progress bar/spinner */
 
-#define ui_progressbar(obj, ...) ui_progressbar_create(obj, (UiProgressbarArgs) { __VA_ARGS__ } )
-#define ui_progressspinner(obj, ...) ui_progressspinner_create(obj, (UiProgressbarSpinnerArgs) { __VA_ARGS__ } )
+#define ui_progressbar(obj, ...) ui_progressbar_create(obj, &(UiProgressbarArgs) { __VA_ARGS__ } )
+#define ui_progressspinner(obj, ...) ui_progressspinner_create(obj, &(UiProgressbarSpinnerArgs) { __VA_ARGS__ } )
 
-UIEXPORT UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args);
-UIEXPORT UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args);
+UIEXPORT UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args);
+UIEXPORT UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args);
 
 
 #ifdef __cplusplus
index 5c8990a98f59d0d3b44ec50bea733e28e8d30ab2..cb1b7f70633f0e67eb0df4c56d9073b897472afb 100644 (file)
@@ -37,7 +37,7 @@ extern "C" {
 
 
 typedef struct UiSpinnerArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -62,9 +62,9 @@ typedef struct UiSpinnerArgs {
 
 
     
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args);
+UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args);
 
-#define ui_spinner(obj, ...) ui_spinner_create(obj, (UiSpinnerArgs){ __VA_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);
index cd4ef6c9922767363dd0ff1c9fc1b0fce95cce7e..9bc86a44927ced04df40d59a9cfd3c62ab5ed490 100644 (file)
@@ -49,6 +49,8 @@ extern "C" {
 #define UI_ICON_DOCK_RIGHT ""
 #define UI_ICON_GO_BACK "go-previous"
 #define UI_ICON_GO_FORWARD "go-next"
+#define UI_ICON_GO_UP "go-up"
+#define UI_ICON_GO_DOWN "go-down"
     
 #endif /* UI_GTK */
     
@@ -68,6 +70,8 @@ extern "C" {
 #define UI_ICON_DOCK_RIGHT "DockRight"
 #define UI_ICON_GO_BACK "Back"
 #define UI_ICON_GO_FORWARD "Forward"
+#define UI_ICON_GO_UP "Up"
+#define UI_ICON_GO_DOWN "" // TODO: implement workaround for missing down symbol
     
 #endif /* UI_WINUI */
     
index 7217caa5185e995c5375d4e4dd057d285dba3ed4..405b50946cdc4ddf77261375d410f80a82798fab 100644 (file)
@@ -45,7 +45,7 @@ extern "C" {
     
     
 typedef struct UiImageViewerArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -75,9 +75,9 @@ typedef struct UiImageViewerArgs {
     void *onbuttonreleasedata;
 } UiImageViewerArgs;
     
-#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } )
+#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, &(UiImageViewerArgs){ __VA_ARGS__ } )
     
-UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args);
+UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args);
 
 UIEXPORT UIWIDGET ui_imageviewer_reset(UIWIDGET w);
 UIEXPORT UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set);
index 2e7b6b1cacee2ffe5c3f715047c2e0df91d8e4b2..3f805b886e78278683a87c048d1d32d83d760d93 100644 (file)
@@ -69,23 +69,23 @@ typedef struct UiMenuItemListArgs {
 
 #define ui_menu(label) for(ui_menu_create(label);ui_menu_is_open();ui_menu_close())
 
-#define ui_menuitem(...) ui_menuitem_create((UiMenuItemArgs){ __VA_ARGS__ })
-#define ui_menu_toggleitem(...) ui_menu_toggleitem_create((UiMenuToggleItemArgs){ __VA_ARGS__ })
-#define ui_menu_radioitem(...) ui_menu_radioitem_create((UiMenuToggleItemArgs){ __VA_ARGS__ })
-#define ui_menu_itemlist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS__ } )
-#define ui_menu_togglelist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS} )
-#define ui_menu_radiolist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS} )
+#define ui_menuitem(...) ui_menuitem_create(&(UiMenuItemArgs){ __VA_ARGS__ })
+#define ui_menu_toggleitem(...) ui_menu_toggleitem_create(&(UiMenuToggleItemArgs){ __VA_ARGS__ })
+#define ui_menu_radioitem(...) ui_menu_radioitem_create(&(UiMenuToggleItemArgs){ __VA_ARGS__ })
+#define ui_menu_itemlist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS__ } )
+#define ui_menu_togglelist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS} )
+#define ui_menu_radiolist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS} )
 
 UIEXPORT void ui_menu_create(const char* label);
-UIEXPORT void ui_menuitem_create(UiMenuItemArgs args);
-UIEXPORT void ui_menu_toggleitem_create(UiMenuToggleItemArgs args);
-UIEXPORT void ui_menu_radioitem_create(UiMenuToggleItemArgs args);
+UIEXPORT void ui_menuitem_create(UiMenuItemArgs *args);
+UIEXPORT void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args);
+UIEXPORT void ui_menu_radioitem_create(UiMenuToggleItemArgs *args);
 
 UIEXPORT void ui_menuseparator();
 
-UIEXPORT void ui_menu_itemlist_create(UiMenuItemListArgs args);
-UIEXPORT void ui_menu_toggleitemlist_create(UiMenuItemListArgs args);
-UIEXPORT void ui_menu_radioitemlist_create(UiMenuItemListArgs args);
+UIEXPORT void ui_menu_itemlist_create(UiMenuItemListArgs *args);
+UIEXPORT void ui_menu_toggleitemlist_create(UiMenuItemListArgs *args);
+UIEXPORT void ui_menu_radioitemlist_create(UiMenuItemListArgs *args);
 
 UIEXPORT void ui_menu_end(void); // TODO: private
 
index 5c40df5ba1f35e05f72ddafdf32f08bf2fddbf74..0daf925a8504fb768a2d75f567754052a83f01cb 100644 (file)
@@ -36,7 +36,7 @@ extern "C" {
 #endif
 
 typedef struct UiTextAreaArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -57,7 +57,7 @@ typedef struct UiTextAreaArgs {
 } UiTextAreaArgs;
     
 typedef struct UiTextFieldArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -91,7 +91,7 @@ typedef UiPathElm*(*ui_pathelm_func)(const char *full_path, size_t len, size_t *
 
 
 typedef struct UiPathTextFieldArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -119,25 +119,25 @@ typedef struct UiPathTextFieldArgs {
     void *ondropsdata;
 } UiPathTextFieldArgs;
 
-#define ui_textarea(obj, ...) ui_textarea_create(obj, (UiTextAreaArgs) { __VA_ARGS__ })
+#define ui_textarea(obj, ...) ui_textarea_create(obj, &(UiTextAreaArgs) { __VA_ARGS__ })
 
-UIEXPORT UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args);
+UIEXPORT UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args);
 
 UIEXPORT UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea);
 
 UIEXPORT void ui_text_undo(UiText *value);
 UIEXPORT void ui_text_redo(UiText *value);
 
-#define ui_textfield(obj, ...) ui_textfield_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_path_textfield(obj, ...) ui_path_textfield_create(obj, (UiPathTextFieldArgs) { __VA_ARGS__ } )
+#define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_path_textfield(obj, ...) ui_path_textfield_create(obj, &(UiPathTextFieldArgs) { __VA_ARGS__ } )
 
-UIEXPORT UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args);
-UIEXPORT UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args);
-UIEXPORT UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args);
+UIEXPORT UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args);
+UIEXPORT UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args);
+UIEXPORT UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args);
 
-UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args);
+UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args);
         
 #ifdef __cplusplus
 }
index 05093219cefb2975cba4d3325e6323a534bdfcbb..4b42af2a2e92c5d1c4fb309f9332c3aef1521f98 100644 (file)
@@ -71,16 +71,16 @@ enum UiToolbarPos {
        UI_TOOLBAR_RIGHT
 };
 
-#define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, (UiToolbarItemArgs){ __VA_ARGS__ } )
-#define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, (UiToolbarToggleItemArgs){ __VA_ARGS__ } )
+#define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, &(UiToolbarItemArgs){ __VA_ARGS__ } )
+#define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } )
 
-#define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, (UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close())
-#define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, (UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close())
+#define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, &(UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close())
+#define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, &(UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close())
 
 
-UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args);
-UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs args);
-UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs args);
+UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args);
+UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args);
+UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args);
 
 UIEXPORT void ui_toolbar_add_default(const char *name, enum UiToolbarPos pos);
 
index 2af07c5406e381b78976b793aae3dea8ece61a8c..7b5474272f293da0f7ea5567b894f57afd542294 100644 (file)
@@ -92,7 +92,11 @@ typedef void* UIMENU;   // NSMenu*
 
 #define UIEXPORT __declspec(dllexport)
 
-#define UIWIDGET void*
+typedef struct W32Widget {
+    HWND hwnd;
+} W32Widget;
+
+#define UIWIDGET W32Widget*
 #define UIWINDOW void*
 #define UIMENU   void*
 
@@ -217,7 +221,6 @@ typedef enum UiTri {
     UI_OFF
 } UiTri;
 
-
 enum UiMouseEventType { UI_PRESS = 0, UI_PRESS2 };
 
 typedef enum UiLabelType {
@@ -237,7 +240,8 @@ typedef enum UiDnDAction {
   
 typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
 
-typedef void*(*ui_getvaluefunc)(void*, int);
+typedef void*(*ui_getvaluefunc)(void *elm, int col);
+typedef void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult);
 
 typedef int(*ui_threadfunc)(void*);
 
@@ -318,6 +322,7 @@ struct UiEvent {
     void     *document;
     void     *window;
     void     *eventdata;
+    int      eventdatatype;
     int      intval;
     int      set;
 };
@@ -405,6 +410,8 @@ struct UiGeneric {
     UiObserver *observers;
 };
     
+typedef void (*ui_list_init_func)(UiContext *ctx, UiList *list, void *userdata);
+
 /*
  * abstract list
  */
@@ -470,6 +477,22 @@ typedef struct UiCondVar {
     int intdata;
 } UiCondVar;
 
+enum UiEventType {
+    UI_EVENT_DATA_NULL = 0,
+    UI_EVENT_DATA_POINTER,
+    UI_EVENT_DATA_STRING,
+    UI_EVENT_DATA_INTEGER_VALUE,
+    UI_EVENT_DATA_STRING_VALUE,
+    UI_EVENT_DATA_TEXT_VALUE,
+    UI_EVENT_DATA_DOUBLE_VALUE,
+    UI_EVENT_DATA_RANGE_VALUE,
+    UI_EVENT_DATA_LIST_SELECTION,
+    UI_EVENT_DATA_LIST_ELM,
+    UI_EVENT_DATA_DND,
+    UI_EVENT_DATA_SUBLIST,
+    UI_EVENT_DATA_FILE_LIST
+};
+
 
 UIEXPORT void ui_init(const char *appname, int argc, char **argv);
 UIEXPORT const char* ui_appname();
@@ -482,6 +505,8 @@ UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata)
 
 UIEXPORT void ui_context_destroy(UiContext *ctx);
 
+UIEXPORT UiContext* ui_context_parent(UiContext *ctx);
+
 UIEXPORT void ui_object_ref(UiObject *obj);
 UIEXPORT int ui_object_unref(UiObject *obj);
 
@@ -502,17 +527,12 @@ UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc
 UIEXPORT void* ui_document_new(size_t size);
 UIEXPORT void  ui_document_destroy(void *doc);
 
-UIEXPORT void ui_set_document(UiObject *obj, void *document);    // deprecated
-UIEXPORT void ui_detach_document(UiObject *obj);                 // deprecated
-UIEXPORT void* ui_get_document(UiObject *obj);                   // deprecated
-UIEXPORT void ui_set_subdocument(void *document, void *sub);     // deprecated
-UIEXPORT void ui_detach_subdocument(void *document, void *sub);  // deprecated
 UIEXPORT void* ui_get_subdocument(void *document);               // deprecated
 
 UIEXPORT UiContext* ui_document_context(void *doc);
 
 UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
-UIEXPORT void ui_detach_document2(UiContext *ctx, void *document);
+UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
 
 UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
 
@@ -531,12 +551,12 @@ UIEXPORT char* ui_strdup(UiContext *ctx, const char *str);
 
 // types
 
-UIEXPORT UiInteger* ui_int_new(UiContext *ctx, char *name);
-UIEXPORT UiDouble* ui_double_new(UiContext *ctx, char *name);
-UIEXPORT UiString* ui_string_new(UiContext *ctx, char *name);
-UIEXPORT UiText* ui_text_new(UiContext *ctx, char *name);
-UIEXPORT UiRange* ui_range_new(UiContext *ctx, char *name);
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name);
+UIEXPORT UiInteger* ui_int_new(UiContext *ctx, const char *name);
+UIEXPORT UiDouble* ui_double_new(UiContext *ctx, const char *name);
+UIEXPORT UiString* ui_string_new(UiContext *ctx, const char *name);
+UIEXPORT UiText* ui_text_new(UiContext *ctx, const char *name);
+UIEXPORT UiRange* ui_range_new(UiContext *ctx, const char *name);
+UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name);
 
 #define ui_get(v) _Generic(v, \
     UiInteger*: ui_int_get, \
@@ -558,6 +578,8 @@ UIEXPORT void ui_string_set(UiString *s, const char *value);
 UIEXPORT char* ui_string_get(UiString *s);
 UIEXPORT void ui_text_set(UiText *s, const char* value);
 UIEXPORT char* ui_text_get(UiText *s);
+UIEXPORT void ui_generic_set_image(UiGeneric *g, void *img);
+UIEXPORT void* ui_generic_get_image(UiGeneric *g);
 
 UIEXPORT void ui_var_set_int(UiContext *ctx, const char *name, int64_t value);
 UIEXPORT int64_t ui_var_get_int(UiContext *ctx, const char *name);
@@ -574,7 +596,8 @@ UIEXPORT void ui_notify_except(UiObserver *observer, UiObserver *exc, void *data
 UIEXPORT void ui_notify_evt(UiObserver *observer, UiEvent *event);
 
 
-UIEXPORT UiList* ui_list_new(UiContext *ctx, char *name);
+UIEXPORT UiList* ui_list_new(UiContext *ctx, const char *name);
+UIEXPORT UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func init, void *userdata);
 UIEXPORT void ui_list_free(UiList *list);
 UIEXPORT void* ui_list_first(UiList *list);
 UIEXPORT void* ui_list_next(UiList *list);
@@ -624,6 +647,15 @@ UIEXPORT void ui_condvar_destroy(UiCondVar *var);
 UIEXPORT void ui_setop_enable(int set);
 UIEXPORT int ui_get_setop(void);
 
+    
+UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata);
+UIEXPORT void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list));
+UIEXPORT void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list));
+UIEXPORT void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i));
+UIEXPORT void ui_list_class_set_count(UiList *list, int(*count)(UiList *list));
+UIEXPORT void ui_list_class_set_data(UiList *list, void *data);
+UIEXPORT void ui_list_class_set_iter(UiList *list, void *iter);
+
 #ifdef __cplusplus
 }
 #endif
index 8217cf601512b023957c91817430d0cbfbc483d1..af51d086ae5ab5f11926e2b58858a07110ede641 100644 (file)
@@ -78,12 +78,23 @@ struct UiModel {
     int *columnsize;
     
     /*
+     * void*(*ui_getvaluefunc)(void *elm, int col);
+     * 
      * function for translating model data to view data
-     * first argument is the pointer returned by UiList->get or UiTree->get
+     * first argument is the pointer returned by UiList first|next|get
      * second argument is the column index
      * TODO: return
      */
-    void*(*getvalue)(void*, int);
+    ui_getvaluefunc getvalue;
+    
+    /*
+     * void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata)
+     * 
+     * alternative for getvalue
+     */
+    ui_getvaluefunc2 getvalue2;
+    
+    void *getvalue2data;
 };
 
 struct UiListCallbacks {
@@ -104,7 +115,7 @@ struct UiListCallbacks {
 };
 
 struct UiListArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -121,6 +132,8 @@ struct UiListArgs {
     char **static_elements;
     size_t static_nelm;
     ui_getvaluefunc getvalue;
+    ui_getvaluefunc2 getvalue2;
+    void *getvalue2data;
     ui_callback onactivate;
     void* onactivatedata;
     ui_callback onselection;
@@ -130,14 +143,14 @@ struct UiListArgs {
     ui_callback ondragcomplete;
     void* ondragcompletedata;
     ui_callback ondrop;
-    void* ondropsdata;
+    void* ondropdata;
     UiBool multiselection;
     UiMenuBuilder *contextmenu;
     
     const int *groups;
 };
 
-typedef void (*ui_sublist_getvalue_func)(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item);
+typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
 
 struct UiSubList {
     UiList *value;
@@ -171,7 +184,7 @@ struct UiSubListItem {
 };
 
 struct UiSourceListArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -219,6 +232,11 @@ struct UiSourceListArgs {
      */
     ui_sublist_getvalue_func getvalue;
     
+    /*
+     * getvalue_func userdata
+     */
+    void *getvaluedata;
+    
     /*
      * activated when a list item is selected
      */
@@ -240,21 +258,28 @@ UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
 UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
 UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
 
-#define ui_listview(obj, ...) ui_listview_create(obj, (UiListArgs) { __VA_ARGS__ } )
-#define ui_table(obj, ...) ui_table_create(obj, (UiListArgs) { __VA_ARGS__ } )
-#define ui_combobox(obj, ...) ui_combobox_create(obj, (UiListArgs) { __VA_ARGS__ } )
-#define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, (UiListArgs) { __VA_ARGS__ } )
-#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, (UiSourceListArgs) { __VA_ARGS__ } )
+#define ui_listview(obj, ...) ui_listview_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_table(obj, ...) ui_table_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_combobox(obj, ...) ui_combobox_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, &(UiSourceListArgs) { __VA_ARGS__ } )
 
-UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args);
+UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs *args);
 
 UIEXPORT void ui_listview_select(UIWIDGET listview, int index);
 UIEXPORT void ui_combobox_select(UIWIDGET dropdown, int index);
 
-UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args);
+UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args);
+
+UIEXPORT void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon);
+UIEXPORT void ui_sublist_item_set_label(UiSubListItem *item, const char *label);
+UIEXPORT void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon);
+UIEXPORT void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label);
+UIEXPORT void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge);
+UIEXPORT void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata);
 
 
 #ifdef __cplusplus
index 98be28c01d19f276987cd9b77bd53da97bb1b621..36f77f97a7d0a67491e4bd39c0bbe446f4668960 100644 (file)
@@ -56,9 +56,9 @@ typedef struct UiWebviewArgs {
     const int* groups;
 } UiWebviewArgs;
 
-#define ui_webview(obj, ...) ui_webview_create(obj, (UiWebviewArgs){ __VA_ARGS__ } )
+#define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
 
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs args);
+UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
 
 void ui_webview_load_url(UiGeneric *g, const char *url);
 
index e08233dfef0c289c56e2a7598f0a05df5ac9a0f1..fee08d90e27aa50e99b1d07e0694b8d2b2ff1b17 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
 #endif
 
 typedef struct UiWidgetArgs {
-    UiTri fill;
+    UiBool fill;
     UiBool hexpand;
     UiBool vexpand;
     UiBool hfill;
@@ -48,21 +48,21 @@ typedef struct UiWidgetArgs {
 } UiWidgetArgs;
 
 #ifdef UI_GTK
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_QT)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_MOTIF)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata, Widget parent, Arg *a, int n);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata, Widget parent, Arg *a, int n);
 #elif defined(UI_COCOA)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_WINUI)
-typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_WIN32)
-typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #endif
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args);
+UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args);
 
-#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, (UiWidgetArgs) { __VA_ARGS__ })
+#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, &(UiWidgetArgs) { __VA_ARGS__ })
 
 
 UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);