diff --git a/.clang-format b/.clang-format index 376186b3..eb9d30cc 100644 --- a/.clang-format +++ b/.clang-format @@ -5,6 +5,8 @@ AlignConsecutiveAssignments: Enabled: true AlignConsecutiveDeclarations: Enabled: true +AccessModifierOffset: -4 +NamespaceIndentation: All IndentWidth: 8 PointerAlignment: Left ColumnLimit: 0 @@ -12,6 +14,9 @@ AllowShortIfStatementsOnASingleLine: Always AllowShortBlocksOnASingleLine: Never AllowShortFunctionsOnASingleLine: Empty AllowShortLoopsOnASingleLine: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: true SpaceBeforeParens: Never AlignEscapedNewlines: DontAlign SortIncludes: false diff --git a/.gitignore b/.gitignore index 8535b651..58b172ad 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,10 @@ examples/*/*.exe compile_flags.txt .cache .DS_Store +/vms +/BorMakefile +*.err +*.zip *.pef *.dsk @@ -26,3 +30,4 @@ compile_flags.txt *.rsrc *.finf *.gdb + diff --git a/BorMakefile b/BorMakefile deleted file mode 100644 index 0f61bac9..00000000 --- a/BorMakefile +++ /dev/null @@ -1,100 +0,0 @@ -CC = bcc32 -c -LD = bcc32 - -CFLAGS = -Iinclude -Iexternal\libz\include -D_MILSKO -DUSE_GDI -DUSE_STB_TRUETYPE -DUSE_STB_IMAGE -DSTBI_NO_SIMD -LDFLAGS = -tWD -.SUFFIXES: .obj .c -all: src\Mw.dll -clean: - del /f /q external\libz\src\adler32.obj - del /f /q external\libz\src\compress.obj - del /f /q external\libz\src\crc32.obj - del /f /q external\libz\src\deflate.obj - del /f /q external\libz\src\gzclose.obj - del /f /q external\libz\src\gzlib.obj - del /f /q external\libz\src\gzread.obj - del /f /q external\libz\src\gzwrite.obj - del /f /q external\libz\src\infback.obj - del /f /q external\libz\src\inffast.obj - del /f /q external\libz\src\inflate.obj - del /f /q external\libz\src\inftrees.obj - del /f /q external\libz\src\trees.obj - del /f /q external\libz\src\uncompr.obj - del /f /q external\libz\src\zutil.obj - del /f /q external\stb_ds.obj - del /f /q external\stb_image.obj - del /f /q external\stb_truetype.obj - del /f /q src\abstract\directory.obj - del /f /q src\abstract\dynamic.obj - del /f /q src\abstract\time.obj - del /f /q src\backend\gdi.obj - del /f /q src\color.obj - del /f /q src\core.obj - del /f /q src\cursor\arrow.obj - del /f /q src\cursor\cross.obj - del /f /q src\cursor\default.obj - del /f /q src\cursor\hidden.obj - del /f /q src\cursor\text.obj - del /f /q src\default.obj - del /f /q src\dialog\colorpicker.obj - del /f /q src\dialog\directorychooser.obj - del /f /q src\dialog\filechooser.obj - del /f /q src\dialog\messagebox.obj - del /f /q src\draw.obj - del /f /q src\icon\back.obj - del /f /q src\icon\clock.obj - del /f /q src\icon\computer.obj - del /f /q src\icon\directory.obj - del /f /q src\icon\down.obj - del /f /q src\icon\error.obj - del /f /q src\icon\file.obj - del /f /q src\icon\forward.obj - del /f /q src\icon\info.obj - del /f /q src\icon\left.obj - del /f /q src\icon\news.obj - del /f /q src\icon\note.obj - del /f /q src\icon\right.obj - del /f /q src\icon\search.obj - del /f /q src\icon\up.obj - del /f /q src\icon\warning.obj - del /f /q src\lowlevel.obj - del /f /q src\string.obj - del /f /q src\text\font\boldfont.obj - del /f /q src\text\font\boldmonottf.obj - del /f /q src\text\font\boldttf.obj - del /f /q src\text\font\font.obj - del /f /q src\text\font\monottf.obj - del /f /q src\text\font\ttf.obj - del /f /q src\text\ft2.obj - del /f /q src\text\stbtt.obj - del /f /q src\text\text.obj - del /f /q src\unicode.obj - del /f /q src\widget\box.obj - del /f /q src\widget\button.obj - del /f /q src\widget\checkbox.obj - del /f /q src\widget\combobox.obj - del /f /q src\widget\entry.obj - del /f /q src\widget\frame.obj - del /f /q src\widget\image.obj - del /f /q src\widget\label.obj - del /f /q src\widget\listbox.obj - del /f /q src\widget\menu.obj - del /f /q src\widget\numberentry.obj - del /f /q src\widget\opengl.obj - del /f /q src\widget\progressbar.obj - del /f /q src\widget\radiobox.obj - del /f /q src\widget\scrollbar.obj - del /f /q src\widget\separator.obj - del /f /q src\widget\submenu.obj - del /f /q src\widget\treeview.obj - del /f /q src\widget\viewport.obj - del /f /q src\widget\window.obj - del /f /q src\Mw.dll - del /f /q src\Mw.lib - -src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) -e$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj -lopengl32.lib -lgdi32.lib -luser32.lib -ladvapi32.lib - implib src\Mw.lib src\Mw.dll - -.c.obj: - $(CC) $(CFLAGS) -o$@ $< diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 00000000..83daed86 --- /dev/null +++ b/CHANGELOG.txt @@ -0,0 +1,17 @@ +========================= 1.4 ========================= +- CMakeLists.txt downgraded to version 3.13 to allow compiling on Windows XP +- CMake build now generates a pkgconfig file. +- GDI backend now natively uses GDI for text rendering +- Widgets can now be disabled with MwNdisabled +- Added `MwTabFocus` for letting a tab widget steal focus. +- New table widget (`MwTableClass`). +- Added `MwWindowShouldClose` for letting custom loops know when a window should close. +- Remove VMS build files +- Entry widgets now have blinking cursor that appears only when you hover over the widget. +- Wayland backend: + - Can now create layer surfaces (Use `MwLLMakeToolWindow` on a parentless window) + - Now properly handles keys being held down + - has drastically improved CSD (functionality wise) + - Uses KMSDRM directly for the OpenGL widget instead of wl_egl for a smoother experience + - Various overall performance improvements putting it on the same level as the X11 backend finally + - Menu widget works better under compositors that use CSD. diff --git a/CMakeLists.txt b/CMakeLists.txt index a6f823d3..5441692f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.13) project( milsko ) @@ -9,6 +9,12 @@ include(GNUInstallDirs) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if(WIN32) + set(CMAKE_STATIC_LIBRARY_PREFIX "") + set(CMAKE_SHARED_LIBRARY_PREFIX "") +endif() option(MW_CLASSIC_THEME "Use classic theme" OFF) option(MW_BUILD_EXAMPLES "Build examples" OFF) @@ -29,13 +35,19 @@ endif() option(MW_INSTALL_HEADERS "Install headers" ON) -if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin OR ${CMAKE_SYSTEM_NAME} MATCHES Retro) +if( ${CMAKE_SYSTEM_NAME} STREQUAL Darwin + OR ${CMAKE_SYSTEM_NAME} MATCHES Retro + OR ${CMAKE_SYSTEM_NAME} MATCHES Windows) option(MW_USE_FREETYPE2 "Use FreeType 2" OFF) else() option(MW_USE_FREETYPE2 "Use FreeType 2" ON) endif() -if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) +if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + option(MW_USE_GDI_TEXT "Use GDI for text rendering" ON) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux OR ${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) option(MW_USE_WAYLAND "Enable Wayland backend" ON) endif() @@ -60,11 +72,8 @@ endif() if(MW_TRY_OPENGL) find_package(OpenGL) - if(OpenGL_FOUND) + if(OpenGL_FOUND AND NOT APPLE) set(MW_BUILD_OPENGL ON) - if(APPLE) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") - endif() message(STATUS "OpenGL widget has been enabled") else() message(WARNING "OpenGL widget has been disabled") @@ -72,8 +81,8 @@ if(MW_TRY_OPENGL) endif() if(MW_TRY_VULKAN) - check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) - if(HAVE_VULKAN_VULKAN_H) + find_package(Vulkan) + if(${Vulkan_FOUND}) set(MW_BUILD_VULKAN ON) message(STATUS "Vulkan widget has been enabled") else() @@ -131,23 +140,35 @@ if(MW_USE_STB_TRUETYPE) endif() if(MW_USE_FREETYPE2) - target_compile_definitions( - Mw - PRIVATE - USE_FREETYPE2 - ) + find_package(Freetype) + if(Freetype_FOUND) + message(STATUS "FreeType2 found") + target_compile_definitions( + Mw + PRIVATE + USE_FREETYPE2 + ) - find_package(PkgConfig) - pkg_check_modules(FT2 REQUIRED freetype2) - list(APPEND INCLUDE_DIRS ${FT2_INCLUDE_DIRS}) - list(APPEND LIBRARY_DIRS ${FT2_LIBRARY_DIRS}) - list(APPEND LIBRARIES ${FT2_LIBRARIES}) + list(APPEND INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${FREETYPE_LIBRARY_DIRS}) + else() + message(WARNING "FreeType2 not found") + endif() +endif() + + +if(MW_USE_GDI_TEXT) + target_compile_definitions( + Mw + PRIVATE + USE_GDI_TEXT + ) endif() if(MW_USE_WAYLAND) function(scan_wayland_protocol_core) execute_process( - COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c + COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT ERROR_VARIABLE WAYLAND_SCANNER_ERROR ECHO_OUTPUT_VARIABLE @@ -157,7 +178,7 @@ if(MW_USE_WAYLAND) target_sources( Mw PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c ) execute_process( COMMAND wayland-scanner client-header /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/wayland-core-protocol.h @@ -171,7 +192,7 @@ if(MW_USE_WAYLAND) endfunction() function(scan_wayland_protocol tier proto ver) - SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-${proto}-protocol.c) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c) execute_process( COMMAND wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -197,6 +218,33 @@ if(MW_USE_WAYLAND) ) endfunction() + function(scan_wayland_protocol_from_file proto file) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c) + execute_process( + COMMAND wayland-scanner private-code ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${proto_c} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${proto_c} + ) + execute_process( + COMMAND wayland-scanner client-header ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + check_include_files(wayland-client.h HAVE_WL_H) check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H) check_include_files(cairo/cairo.h HAVE_CAIRO_H) @@ -213,11 +261,16 @@ if(MW_USE_WAYLAND) scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") + scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") target_sources( Mw PRIVATE - src/backend/wayland.c + src/backend/cairo.c + src/backend/wayland/wayland.c + src/backend/wayland/buffer.c + src/backend/wayland/interfaces.c + src/backend/wayland/region.c ) target_compile_definitions( Mw @@ -264,7 +317,8 @@ if(MW_CLASSIC_THEME) ) endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Windows") +message("Building Milsko for ${CMAKE_SYSTEM_NAME}") +if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") target_sources( Mw PRIVATE @@ -275,23 +329,30 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") PRIVATE USE_GDI ) - list(APPEND LIBRARIES gdi32) + list(APPEND LIBRARIES gdi32 ole32 uuid) + if(NOT MSVC) target_link_options( Mw PRIVATE -static-libgcc ) + endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # target_sources( + # Mw + # PRIVATE + # src/backend/cocoa.m + # ) target_sources( - Mw - PRIVATE - src/backend/cocoa.m - ) - target_compile_definitions( - Mw - PRIVATE - USE_COCOA - ) + Mw + PRIVATE + src/backend/nococoa.m +) + # target_compile_definitions( + # Mw + # PRIVATE + # USE_COCOA + # ) list(APPEND LIBRARIES objc) target_link_options( Mw @@ -299,6 +360,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") -framework Cocoa ) elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") + target_sources( Mw PRIVATE @@ -317,26 +379,57 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") CLASSIC_MAC_OS ) else() + find_package(PkgConfig) - pkg_check_modules(X11 REQUIRED x11) - pkg_check_modules(XRENDER REQUIRED xrender) + find_package(X11) + pkg_check_modules(DBUS dbus-1) target_sources( Mw PRIVATE src/backend/x11.c ) - target_compile_definitions( - Mw - PRIVATE - USE_X11 - ) - list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS} ${XRENDER_INCLUDE_DIRS}) - list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS} ${XRENDER_LIBRARY_DIRS}) - list(APPEND LIBRARIES ${X11_LIBRARIES} ${XRENDER_LIBRARIES} m) + + if(${X11_FOUND}) + list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_X11 + ) + endif() + if(${X11_Xrender_FOUND}) + list(APPEND INCLUDE_DIRS ${XRENDER_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${XRENDER_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_XRENDER + ) + endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND LIBRARIES dl) endif() + + find_package(DBus1) + + if(${DBus1_FOUND}) + list(APPEND INCLUDE_DIRS ${DBUS_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${DBUS_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_DBUS + ) + endif() +endif() + + + +if(UNIX) + list(APPEND LIBRARIES m) endif() target_include_directories( @@ -373,17 +466,20 @@ if(MW_BUILD_VULKAN) ) endif() + check_include_files(vulkan/VULKAN.h HAS_VK_HEADER) + if(HAS_VK_HEADER) target_compile_definitions( Mw PRIVATE MW_VULKAN ) + endif() endif() target_compile_definitions( Mw PRIVATE - _MILSKO + _MILSKO _MILSKO_BUILD ) install( @@ -393,6 +489,17 @@ install( ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/resource/${PROJECT_NAME}.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + @ONLY + ) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION $ENV{MINGW_PREFIX}/${CMAKE_INSTALL_DATADIR}/pkgconfig + ) + if(MW_INSTALL_HEADERS) install( DIRECTORY include/ diff --git a/Jenkinsfile b/Jenkinsfile index 8c1d0050..6c1637e8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,9 +29,11 @@ pipeline { label "built-in" } steps { + sh("git clean -dfx") sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") - sh("make clean") sh("make -j4") + sh("mv src/libMw.so libMw64.so") + archiveArtifacts("libMw64.so") } } stage("Build for Windows 32-bit") { @@ -39,9 +41,12 @@ pipeline { label "built-in" } steps { + sh("git clean -dfx") sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") - sh("make clean") sh("make -j4") + sh("mv src/Mw.dll Mw32.dll") + sh("mv src/libMw.dll.a libMw32.dll.a") + archiveArtifacts("Mw32.dll,libMw32.dll.a") } } stage("Build for Windows 64-bit") { @@ -49,9 +54,12 @@ pipeline { label "built-in" } steps { + sh("git clean -dfx") sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") - sh("make clean") sh("make -j4") + sh("mv src/Mw.dll Mw64.dll") + sh("mv src/libMw.dll.a libMw64.dll.a") + archiveArtifacts("Mw64.dll,libMw64.dll.a") } } stage("Build for Windows 32-bit (MSVC)") { @@ -59,8 +67,31 @@ pipeline { label "2012r2" } steps { - bat("nmake -f NTMakefile clean") + bat("git clean -dfx") bat("nmake -f NTMakefile") + bat("move /y src\\Mw.dll MwMSVC32.dll") + bat("move /y src\\Mw.lib MwMSVC32.lib") + archiveArtifacts("MwMSVC32.dll,MwMSVC32.lib") + } + } + stage("Build for Windows 32-bit (Watcom)") { + agent { + label "built-in" + } + environment { + WATCOM = "/usr/watcom" + INCLUDE = "/usr/watcom/h:/usr/watcom/h/nt" + PATH = "/usr/watcom/binl64:${env.PATH}" + } + steps { + sh("git clean -dfx") + sh("wmake -f WatMakefile") + sh("mv src/Mw.dll MwWat32.dll") + sh("mv src/Mw.lib MwWat32.lib") + archiveArtifacts("MwWat32.dll,MwWat32.lib") + sh("./tools/watcom-pack.sh") + sh("mv milsko-examples.zip milsko-examples-win32.zip") + archiveArtifacts("milsko-examples-win32.zip") } } } diff --git a/NTMakefile b/NTMakefile index de518684..63a4a2c9 100644 --- a/NTMakefile +++ b/NTMakefile @@ -1,10 +1,14 @@ CC = cl /TC /c /nologo LD = link /nologo -CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /DUSE_GDI /DUSE_STB_TRUETYPE /DUSE_STB_IMAGE /DSTBI_NO_SIMD -LDFLAGS = /DLL +MW_CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /D_MILSKO_BUILD /DUSE_GDI /DUSE_STB_IMAGE /DSTBI_NO_SIMD /DUSE_GDI_TEXT /DMW_OPENGL +MW_LDFLAGS = /DLL +EXE_CFLAGS = /Iinclude +EXE_LDFLAGS = .SUFFIXES: .obj .c -all: src\Mw.dll +all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +lib: src\Mw.dll +examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe clean: del /f /q external\libz\src\adler32.obj del /f /q external\libz\src\compress.obj @@ -24,6 +28,7 @@ clean: del /f /q external\stb_ds.obj del /f /q external\stb_image.obj del /f /q external\stb_truetype.obj + del /f /q src\abstract\charset.obj del /f /q src\abstract\directory.obj del /f /q src\abstract\dynamic.obj del /f /q src\abstract\time.obj @@ -66,11 +71,14 @@ clean: del /f /q src\text\font\monottf.obj del /f /q src\text\font\ttf.obj del /f /q src\text\ft2.obj + del /f /q src\text\gdi.obj del /f /q src\text\stbtt.obj del /f /q src\text\text.obj + del /f /q src\truetype.obj del /f /q src\unicode.obj del /f /q src\widget\box.obj del /f /q src\widget\button.obj + del /f /q src\widget\calendar.obj del /f /q src\widget\checkbox.obj del /f /q src\widget\combobox.obj del /f /q src\widget\entry.obj @@ -86,15 +94,235 @@ clean: del /f /q src\widget\scrollbar.obj del /f /q src\widget\separator.obj del /f /q src\widget\submenu.obj + del /f /q src\widget\subwindow.obj + del /f /q src\widget\tab.obj + del /f /q src\widget\table.obj del /f /q src\widget\treeview.obj del /f /q src\widget\viewport.obj del /f /q src\widget\window.obj del /f /q src\Mw.dll del /f /q src\Mw.lib + del /f /q examples\basic\box.obj + del /f /q examples\basic\calculator.obj + del /f /q examples\basic\checkbox.obj + del /f /q examples\basic\clipboard.obj + del /f /q examples\basic\colorpicker.obj + del /f /q examples\basic\combobox.obj + del /f /q examples\basic\example.obj + del /f /q examples\basic\filechooser.obj + del /f /q examples\basic\image.obj + del /f /q examples\basic\listbox.obj + del /f /q examples\basic\messagebox.obj + del /f /q examples\basic\periodic.obj + del /f /q examples\basic\progressbar.obj + del /f /q examples\basic\radiobox.obj + del /f /q examples\basic\rotate.obj + del /f /q examples\basic\scrollbar.obj + del /f /q examples\basic\sevensegment.obj + del /f /q examples\basic\subwindow.obj + del /f /q examples\basic\tab.obj + del /f /q examples\basic\treeview.obj + del /f /q examples\basic\viewport.obj + del /f /q examples\gldemos\boing.obj + del /f /q examples\gldemos\clock.obj + del /f /q examples\gldemos\cube.obj + del /f /q examples\gldemos\gears.obj + del /f /q examples\gldemos\triangle.obj + del /f /q examples\gldemos\tripaint.obj + del /f /q examples\basic\box.exe + del /f /q examples\basic\calculator.exe + del /f /q examples\basic\checkbox.exe + del /f /q examples\basic\clipboard.exe + del /f /q examples\basic\colorpicker.exe + del /f /q examples\basic\combobox.exe + del /f /q examples\basic\example.exe + del /f /q examples\basic\filechooser.exe + del /f /q examples\basic\image.exe + del /f /q examples\basic\listbox.exe + del /f /q examples\basic\messagebox.exe + del /f /q examples\basic\periodic.exe + del /f /q examples\basic\progressbar.exe + del /f /q examples\basic\radiobox.exe + del /f /q examples\basic\rotate.exe + del /f /q examples\basic\scrollbar.exe + del /f /q examples\basic\sevensegment.exe + del /f /q examples\basic\subwindow.exe + del /f /q examples\basic\tab.exe + del /f /q examples\basic\treeview.exe + del /f /q examples\basic\viewport.exe + del /f /q examples\gldemos\boing.exe + del /f /q examples\gldemos\clock.exe + del /f /q examples\gldemos\cube.exe + del /f /q examples\gldemos\gears.exe + del /f /q examples\gldemos\triangle.exe + del /f /q examples\gldemos\tripaint.exe -src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib user32.lib advapi32.lib +examples\basic\box.exe: examples\basic\box.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\box.obj src\Mw.lib + +examples\basic\box.obj: examples/basic/box.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/box.c + +examples\basic\calculator.exe: examples\basic\calculator.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\calculator.obj src\Mw.lib + +examples\basic\calculator.obj: examples/basic/calculator.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/calculator.c + +examples\basic\checkbox.exe: examples\basic\checkbox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\checkbox.obj src\Mw.lib + +examples\basic\checkbox.obj: examples/basic/checkbox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/checkbox.c + +examples\basic\clipboard.exe: examples\basic\clipboard.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\clipboard.obj src\Mw.lib + +examples\basic\clipboard.obj: examples/basic/clipboard.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/clipboard.c + +examples\basic\colorpicker.exe: examples\basic\colorpicker.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\colorpicker.obj src\Mw.lib + +examples\basic\colorpicker.obj: examples/basic/colorpicker.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/colorpicker.c + +examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\combobox.obj src\Mw.lib + +examples\basic\combobox.obj: examples/basic/combobox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c + +examples\basic\example.exe: examples\basic\example.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\example.obj src\Mw.lib + +examples\basic\example.obj: examples/basic/example.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/example.c + +examples\basic\filechooser.exe: examples\basic\filechooser.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\filechooser.obj src\Mw.lib + +examples\basic\filechooser.obj: examples/basic/filechooser.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/filechooser.c + +examples\basic\image.exe: examples\basic\image.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\image.obj src\Mw.lib + +examples\basic\image.obj: examples/basic/image.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/image.c + +examples\basic\listbox.exe: examples\basic\listbox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\listbox.obj src\Mw.lib + +examples\basic\listbox.obj: examples/basic/listbox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/listbox.c + +examples\basic\messagebox.exe: examples\basic\messagebox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\messagebox.obj src\Mw.lib + +examples\basic\messagebox.obj: examples/basic/messagebox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/messagebox.c + +examples\basic\periodic.exe: examples\basic\periodic.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\periodic.obj src\Mw.lib + +examples\basic\periodic.obj: examples/basic/periodic.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/periodic.c + +examples\basic\progressbar.exe: examples\basic\progressbar.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\progressbar.obj src\Mw.lib + +examples\basic\progressbar.obj: examples/basic/progressbar.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/progressbar.c + +examples\basic\radiobox.exe: examples\basic\radiobox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\radiobox.obj src\Mw.lib + +examples\basic\radiobox.obj: examples/basic/radiobox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/radiobox.c + +examples\basic\rotate.exe: examples\basic\rotate.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\rotate.obj src\Mw.lib + +examples\basic\rotate.obj: examples/basic/rotate.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/rotate.c + +examples\basic\scrollbar.exe: examples\basic\scrollbar.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\scrollbar.obj src\Mw.lib + +examples\basic\scrollbar.obj: examples/basic/scrollbar.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/scrollbar.c + +examples\basic\sevensegment.exe: examples\basic\sevensegment.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\sevensegment.obj src\Mw.lib + +examples\basic\sevensegment.obj: examples/basic/sevensegment.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/sevensegment.c + +examples\basic\subwindow.exe: examples\basic\subwindow.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\subwindow.obj src\Mw.lib + +examples\basic\subwindow.obj: examples/basic/subwindow.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/subwindow.c + +examples\basic\tab.exe: examples\basic\tab.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\tab.obj src\Mw.lib + +examples\basic\tab.obj: examples/basic/tab.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/tab.c + +examples\basic\treeview.exe: examples\basic\treeview.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\treeview.obj src\Mw.lib + +examples\basic\treeview.obj: examples/basic/treeview.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/treeview.c + +examples\basic\viewport.exe: examples\basic\viewport.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\viewport.obj src\Mw.lib + +examples\basic\viewport.obj: examples/basic/viewport.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/viewport.c + +examples\gldemos\boing.exe: examples\gldemos\boing.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\boing.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\boing.obj: examples/gldemos/boing.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/boing.c + +examples\gldemos\clock.exe: examples\gldemos\clock.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\clock.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\clock.obj: examples/gldemos/clock.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/clock.c + +examples\gldemos\cube.exe: examples\gldemos\cube.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\cube.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\cube.obj: examples/gldemos/cube.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/cube.c + +examples\gldemos\gears.exe: examples\gldemos\gears.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\gears.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\gears.obj: examples/gldemos/gears.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/gears.c + +examples\gldemos\triangle.exe: examples\gldemos\triangle.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\triangle.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\triangle.obj: examples/gldemos/triangle.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/triangle.c + +examples\gldemos\tripaint.exe: examples\gldemos\tripaint.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\tripaint.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c + + +src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib .c.obj: - $(CC) $(CFLAGS) /Fo$@ $< + $(CC) $(MW_CFLAGS) /Fo$@ $< diff --git a/README.txt b/README.txt index dc9d6bf2..0f57f905 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) +Greetings - Welcome to the Milsko GUI Toolkit (Version 1.4) This document contains a brief summary of the contents of this source distributions and building instructions for Milsko GUI Toolkit. @@ -8,8 +8,7 @@ distributions and building instructions for Milsko GUI Toolkit. Milsko requires either * A Windows environment with GDI (so anything NT or 9x) - * A MacOS environment with Cocoa (10.4 or above supported) - * A Unix-like environment with X11 for runtime. + * A Unix-like environment with Wayland and/or X11 for runtime. To build Milsko for Windows, you must have one of following compilers: * Visual C++ 6.0 or newer @@ -63,8 +62,10 @@ D. MinGW-w64/GCC/Clang 1) Determine if you need Vulkan and/or OpenGL. -2) Run `./configure'. - For help, run `./configure --help'. +2) Either: + a.) Run `./configure'. For help, run `./configure --help'. + b.) Use CMake; i.e. `cmake -B build`. (if contributing, name the build +folder build as that's what's included in the .gitignore) 3) Run `make'. diff --git a/WatMakefile b/WatMakefile index 633a259a..4533f3c2 100644 --- a/WatMakefile +++ b/WatMakefile @@ -1,9 +1,13 @@ -CC = wcc386 -bt=nt -q -bd -d3 +CC = wcc386 -bt=nt -q LD = wlink option quiet -CFLAGS = -i=include -i=external/libz/include -d_MILSKO -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD -LDFLAGS = system nt_dll -all: src/Mw.dll +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dUSE_GDI_TEXT -dMW_OPENGL +MW_LDFLAGS = system nt_dll +EXE_CFLAGS = -i=include +EXE_LDFLAGS = system nt +all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +lib: src/Mw.dll +examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe clean: .SYMBOLIC %erase external/libz/src/adler32.obj %erase external/libz/src/compress.obj @@ -23,6 +27,7 @@ clean: .SYMBOLIC %erase external/stb_ds.obj %erase external/stb_image.obj %erase external/stb_truetype.obj + %erase src/abstract/charset.obj %erase src/abstract/directory.obj %erase src/abstract/dynamic.obj %erase src/abstract/time.obj @@ -65,11 +70,14 @@ clean: .SYMBOLIC %erase src/text/font/monottf.obj %erase src/text/font/ttf.obj %erase src/text/ft2.obj + %erase src/text/gdi.obj %erase src/text/stbtt.obj %erase src/text/text.obj + %erase src/truetype.obj %erase src/unicode.obj %erase src/widget/box.obj %erase src/widget/button.obj + %erase src/widget/calendar.obj %erase src/widget/checkbox.obj %erase src/widget/combobox.obj %erase src/widget/entry.obj @@ -85,180 +93,414 @@ clean: .SYMBOLIC %erase src/widget/scrollbar.obj %erase src/widget/separator.obj %erase src/widget/submenu.obj + %erase src/widget/subwindow.obj + %erase src/widget/tab.obj + %erase src/widget/table.obj %erase src/widget/treeview.obj %erase src/widget/viewport.obj %erase src/widget/window.obj %erase src/Mw.dll %erase src/Mw.lib + %erase examples/basic/box.obj + %erase examples/basic/calculator.obj + %erase examples/basic/checkbox.obj + %erase examples/basic/clipboard.obj + %erase examples/basic/colorpicker.obj + %erase examples/basic/combobox.obj + %erase examples/basic/example.obj + %erase examples/basic/filechooser.obj + %erase examples/basic/image.obj + %erase examples/basic/listbox.obj + %erase examples/basic/messagebox.obj + %erase examples/basic/periodic.obj + %erase examples/basic/progressbar.obj + %erase examples/basic/radiobox.obj + %erase examples/basic/rotate.obj + %erase examples/basic/scrollbar.obj + %erase examples/basic/sevensegment.obj + %erase examples/basic/subwindow.obj + %erase examples/basic/tab.obj + %erase examples/basic/treeview.obj + %erase examples/basic/viewport.obj + %erase examples/gldemos/boing.obj + %erase examples/gldemos/clock.obj + %erase examples/gldemos/cube.obj + %erase examples/gldemos/gears.obj + %erase examples/gldemos/triangle.obj + %erase examples/gldemos/tripaint.obj + %erase examples/basic/box.exe + %erase examples/basic/calculator.exe + %erase examples/basic/checkbox.exe + %erase examples/basic/clipboard.exe + %erase examples/basic/colorpicker.exe + %erase examples/basic/combobox.exe + %erase examples/basic/example.exe + %erase examples/basic/filechooser.exe + %erase examples/basic/image.exe + %erase examples/basic/listbox.exe + %erase examples/basic/messagebox.exe + %erase examples/basic/periodic.exe + %erase examples/basic/progressbar.exe + %erase examples/basic/radiobox.exe + %erase examples/basic/rotate.exe + %erase examples/basic/scrollbar.exe + %erase examples/basic/sevensegment.exe + %erase examples/basic/subwindow.exe + %erase examples/basic/tab.exe + %erase examples/basic/treeview.exe + %erase examples/basic/viewport.exe + %erase examples/gldemos/boing.exe + %erase examples/gldemos/clock.exe + %erase examples/gldemos/cube.exe + %erase examples/gldemos/gears.exe + %erase examples/gldemos/triangle.exe + %erase examples/gldemos/tripaint.exe -src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/stbtt.obj src/text/text.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/stbtt.obj file src/text/text.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library user32.lib library advapi32.lib +examples/basic/box.exe: examples/basic/box.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/box.obj library clib3r.lib library src/Mw.lib + +examples/basic/box.obj: examples/basic/box.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/box.c + +examples/basic/calculator.exe: examples/basic/calculator.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/calculator.obj library clib3r.lib library src/Mw.lib + +examples/basic/calculator.obj: examples/basic/calculator.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/calculator.c + +examples/basic/checkbox.exe: examples/basic/checkbox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/checkbox.obj library clib3r.lib library src/Mw.lib + +examples/basic/checkbox.obj: examples/basic/checkbox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/checkbox.c + +examples/basic/clipboard.exe: examples/basic/clipboard.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/clipboard.obj library clib3r.lib library src/Mw.lib + +examples/basic/clipboard.obj: examples/basic/clipboard.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/clipboard.c + +examples/basic/colorpicker.exe: examples/basic/colorpicker.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/colorpicker.obj library clib3r.lib library src/Mw.lib + +examples/basic/colorpicker.obj: examples/basic/colorpicker.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/colorpicker.c + +examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/combobox.obj library clib3r.lib library src/Mw.lib + +examples/basic/combobox.obj: examples/basic/combobox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c + +examples/basic/example.exe: examples/basic/example.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/example.obj library clib3r.lib library src/Mw.lib + +examples/basic/example.obj: examples/basic/example.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/example.c + +examples/basic/filechooser.exe: examples/basic/filechooser.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/filechooser.obj library clib3r.lib library src/Mw.lib + +examples/basic/filechooser.obj: examples/basic/filechooser.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/filechooser.c + +examples/basic/image.exe: examples/basic/image.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/image.obj library clib3r.lib library src/Mw.lib + +examples/basic/image.obj: examples/basic/image.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/image.c + +examples/basic/listbox.exe: examples/basic/listbox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/listbox.obj library clib3r.lib library src/Mw.lib + +examples/basic/listbox.obj: examples/basic/listbox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/listbox.c + +examples/basic/messagebox.exe: examples/basic/messagebox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/messagebox.obj library clib3r.lib library src/Mw.lib + +examples/basic/messagebox.obj: examples/basic/messagebox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/messagebox.c + +examples/basic/periodic.exe: examples/basic/periodic.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/periodic.obj library clib3r.lib library src/Mw.lib + +examples/basic/periodic.obj: examples/basic/periodic.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/periodic.c + +examples/basic/progressbar.exe: examples/basic/progressbar.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/progressbar.obj library clib3r.lib library src/Mw.lib + +examples/basic/progressbar.obj: examples/basic/progressbar.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/progressbar.c + +examples/basic/radiobox.exe: examples/basic/radiobox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/radiobox.obj library clib3r.lib library src/Mw.lib + +examples/basic/radiobox.obj: examples/basic/radiobox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/radiobox.c + +examples/basic/rotate.exe: examples/basic/rotate.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/rotate.obj library clib3r.lib library src/Mw.lib + +examples/basic/rotate.obj: examples/basic/rotate.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/rotate.c + +examples/basic/scrollbar.exe: examples/basic/scrollbar.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/scrollbar.obj library clib3r.lib library src/Mw.lib + +examples/basic/scrollbar.obj: examples/basic/scrollbar.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/scrollbar.c + +examples/basic/sevensegment.exe: examples/basic/sevensegment.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/sevensegment.obj library clib3r.lib library src/Mw.lib + +examples/basic/sevensegment.obj: examples/basic/sevensegment.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/sevensegment.c + +examples/basic/subwindow.exe: examples/basic/subwindow.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/subwindow.obj library clib3r.lib library src/Mw.lib + +examples/basic/subwindow.obj: examples/basic/subwindow.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/subwindow.c + +examples/basic/tab.exe: examples/basic/tab.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/tab.obj library clib3r.lib library src/Mw.lib + +examples/basic/tab.obj: examples/basic/tab.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/tab.c + +examples/basic/treeview.exe: examples/basic/treeview.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/treeview.obj library clib3r.lib library src/Mw.lib + +examples/basic/treeview.obj: examples/basic/treeview.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/treeview.c + +examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/viewport.obj library clib3r.lib library src/Mw.lib + +examples/basic/viewport.obj: examples/basic/viewport.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c + +examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/boing.obj: examples/gldemos/boing.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/boing.c + +examples/gldemos/clock.exe: examples/gldemos/clock.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/clock.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/clock.obj: examples/gldemos/clock.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/clock.c + +examples/gldemos/cube.exe: examples/gldemos/cube.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/cube.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/cube.obj: examples/gldemos/cube.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/cube.c + +examples/gldemos/gears.exe: examples/gldemos/gears.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/gears.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/gears.obj: examples/gldemos/gears.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/gears.c + +examples/gldemos/triangle.exe: examples/gldemos/triangle.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/triangle.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/triangle.obj: examples/gldemos/triangle.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/triangle.c + +examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/tripaint.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c + + +src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib external/libz/src/adler32.obj: external/libz/src/adler32.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/adler32.c external/libz/src/compress.obj: external/libz/src/compress.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/compress.c external/libz/src/crc32.obj: external/libz/src/crc32.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/crc32.c external/libz/src/deflate.obj: external/libz/src/deflate.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/deflate.c external/libz/src/gzclose.obj: external/libz/src/gzclose.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzclose.c external/libz/src/gzlib.obj: external/libz/src/gzlib.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzlib.c external/libz/src/gzread.obj: external/libz/src/gzread.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzread.c external/libz/src/gzwrite.obj: external/libz/src/gzwrite.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzwrite.c external/libz/src/infback.obj: external/libz/src/infback.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/infback.c external/libz/src/inffast.obj: external/libz/src/inffast.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inffast.c external/libz/src/inflate.obj: external/libz/src/inflate.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inflate.c external/libz/src/inftrees.obj: external/libz/src/inftrees.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inftrees.c external/libz/src/trees.obj: external/libz/src/trees.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/trees.c external/libz/src/uncompr.obj: external/libz/src/uncompr.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/uncompr.c external/libz/src/zutil.obj: external/libz/src/zutil.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/zutil.c external/stb_ds.obj: external/stb_ds.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_ds.c external/stb_image.obj: external/stb_image.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_image.c external/stb_truetype.obj: external/stb_truetype.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_truetype.c +src/abstract/charset.obj: src/abstract/charset.c + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/charset.c src/abstract/directory.obj: src/abstract/directory.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/directory.c src/abstract/dynamic.obj: src/abstract/dynamic.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/dynamic.c src/abstract/time.obj: src/abstract/time.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/time.c src/backend/gdi.obj: src/backend/gdi.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/backend/gdi.c src/color.obj: src/color.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/color.c src/core.obj: src/core.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/core.c src/cursor/arrow.obj: src/cursor/arrow.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/arrow.c src/cursor/cross.obj: src/cursor/cross.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/cross.c src/cursor/default.obj: src/cursor/default.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/default.c src/cursor/hidden.obj: src/cursor/hidden.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/hidden.c src/cursor/text.obj: src/cursor/text.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/text.c src/default.obj: src/default.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/default.c src/dialog/colorpicker.obj: src/dialog/colorpicker.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/colorpicker.c src/dialog/directorychooser.obj: src/dialog/directorychooser.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/directorychooser.c src/dialog/filechooser.obj: src/dialog/filechooser.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/filechooser.c src/dialog/messagebox.obj: src/dialog/messagebox.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/messagebox.c src/draw.obj: src/draw.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/draw.c src/icon/back.obj: src/icon/back.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/back.c src/icon/clock.obj: src/icon/clock.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/clock.c src/icon/computer.obj: src/icon/computer.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/computer.c src/icon/directory.obj: src/icon/directory.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/directory.c src/icon/down.obj: src/icon/down.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/down.c src/icon/error.obj: src/icon/error.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/error.c src/icon/file.obj: src/icon/file.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/file.c src/icon/forward.obj: src/icon/forward.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/forward.c src/icon/info.obj: src/icon/info.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/info.c src/icon/left.obj: src/icon/left.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/left.c src/icon/news.obj: src/icon/news.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/news.c src/icon/note.obj: src/icon/note.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/note.c src/icon/right.obj: src/icon/right.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/right.c src/icon/search.obj: src/icon/search.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/search.c src/icon/up.obj: src/icon/up.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/up.c src/icon/warning.obj: src/icon/warning.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/warning.c src/lowlevel.obj: src/lowlevel.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/lowlevel.c src/string.obj: src/string.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/string.c src/text/font/boldfont.obj: src/text/font/boldfont.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldfont.c src/text/font/boldmonottf.obj: src/text/font/boldmonottf.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldmonottf.c src/text/font/boldttf.obj: src/text/font/boldttf.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldttf.c src/text/font/font.obj: src/text/font/font.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/font.c src/text/font/monottf.obj: src/text/font/monottf.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/monottf.c src/text/font/ttf.obj: src/text/font/ttf.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c src/text/ft2.obj: src/text/ft2.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/ft2.c +src/text/gdi.obj: src/text/gdi.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/gdi.c src/text/stbtt.obj: src/text/stbtt.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c src/text/text.obj: src/text/text.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/text/text.c +src/truetype.obj: src/truetype.c + $(CC) $(MW_CFLAGS) -fo=$@ src/truetype.c src/unicode.obj: src/unicode.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/unicode.c src/widget/box.obj: src/widget/box.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/box.c src/widget/button.obj: src/widget/button.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/button.c +src/widget/calendar.obj: src/widget/calendar.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/calendar.c src/widget/checkbox.obj: src/widget/checkbox.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/checkbox.c src/widget/combobox.obj: src/widget/combobox.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/combobox.c src/widget/entry.obj: src/widget/entry.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/entry.c src/widget/frame.obj: src/widget/frame.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/frame.c src/widget/image.obj: src/widget/image.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/image.c src/widget/label.obj: src/widget/label.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/label.c src/widget/listbox.obj: src/widget/listbox.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/listbox.c src/widget/menu.obj: src/widget/menu.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c src/widget/numberentry.obj: src/widget/numberentry.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c src/widget/opengl.obj: src/widget/opengl.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c src/widget/progressbar.obj: src/widget/progressbar.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c src/widget/radiobox.obj: src/widget/radiobox.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/radiobox.c src/widget/scrollbar.obj: src/widget/scrollbar.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/scrollbar.c src/widget/separator.obj: src/widget/separator.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/separator.c src/widget/submenu.obj: src/widget/submenu.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/submenu.c +src/widget/subwindow.obj: src/widget/subwindow.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/subwindow.c +src/widget/tab.obj: src/widget/tab.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/tab.c +src/widget/table.obj: src/widget/table.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/table.c src/widget/treeview.obj: src/widget/treeview.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/treeview.c src/widget/viewport.obj: src/widget/viewport.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/viewport.c src/widget/window.obj: src/widget/window.c - $(CC) $(CFLAGS) -fo=$@ $< + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/window.c diff --git a/configure b/configure index 98a6b3a6..44db66d8 100755 --- a/configure +++ b/configure @@ -2,6 +2,11 @@ our $target = `uname -s`; $target =~ s/\r?\n$//; +# MSYS with MinGW gives us some other shit idk +if (index($target, "MINGW") != -1) { + $target = "Windows"; +} + foreach my $l (@ARGV) { if ($l =~ /^--.+$/) { } @@ -12,10 +17,11 @@ foreach my $l (@ARGV) { our $prefix = "/usr/local"; our $cc = defined($ENV{CC}) ? $ENV{CC} : "*host*gcc"; +our $cxx = defined($ENV{CXX}) ? $ENV{CXX} : "*host*g++"; our $ar = defined($ENV{AR}) ? $ENV{AR} : "*host*ar"; our $incdir = "-I include"; our $incdir2 = ""; -our $cflags = "-fPIC -D_MILSKO -fvisibility=hidden"; +our $cflags = "-fPIC -D_MILSKO -D_MILSKO_BUILD -fvisibility=hidden"; our $libdir = ""; our $ldflags = ""; our $math = "-lm"; @@ -38,7 +44,6 @@ require("./pl/utils.pl"); param_set("classic-theme", 0); param_set("stb-image", 1); -param_set("xrender", 1); param_set("opengl", 0); param_set("vulkan", 0); param_set("vulkan-string-helper", 1); @@ -46,13 +51,16 @@ param_set("shared", 1); param_set("static", 1); param_set("examples", 1); +# (option that only makes sense on x11) +param_set("allow-sloppy-focus", 0); my %features = ( "classic-theme" => "use classic theme", "stb-image" => "use stb_image, instead use libjpeg/libpng", "stb-truetype" => "use stb_truetype", "freetype2" => "use FreeType2", - "xrender" => "use XRender", + "gdi-text" => "(Windows only) use GDI Text", + "xrender" => "(X11 only) use XRender", "opengl" => "build OpenGL widget", "vulkan" => "build Vulkan widget", "vulkan-string-helper" => "use Vulkan string helper", @@ -60,16 +68,57 @@ my %features = ( "static" => "build static library", "wayland" => "enable wayland backend", "gnustep" => "use gnustep", + "dbus" => "use DBus on supported platform", + "allow-sloppy-focus" => "prevent the x11 backend from using XSetInputFocus to enforce click-to-focus" ); my @features_keys = ( "1classic-theme", "1stb-image", - "1stb-truetype", "1freetype2", + "1stb-truetype", "1freetype2", "1gdi-text", "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", "1shared", "1static", "1wayland", "1gnustep", + "1dbus" ); +sub def_platform { + if($target eq "Windows") { + param_set("freetype2", 0); + param_set("stb-truetype", 0); + } elsif($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Haiku") { + param_set("freetype2", 1); + param_set("stb-truetype", 0); + } else { + param_set("freetype2", 0); + param_set("stb-truetype", 1); + } + if($target eq "Linux" || $target eq "FreeBSD") { + param_set("x11", 1); + param_set("xrender", 1); + if(!param_get("tiny")){ + param_set("wayland", 1); + } + param_set("dbus", 1); + } + if($target eq "NetBSD" || $target eq "OpenBSD") { + param_set("x11", 1); + } + if($target eq "Windows") { + param_set("gdi-text", 1); + } else { + param_set("gdi-text", 0); + } +} + +foreach my $l (@ARGV) { + if ($l =~ /^--target=(.+)$/) { + $target = $1; + } +} + +def_platform(); + + foreach my $l (@ARGV) { if ($l =~ /^--with-([^=]+)=(.+)$/) { param_set($1, $2); @@ -80,9 +129,6 @@ foreach my $l (@ARGV) { elsif ($l =~ /^--(?:without|disable)-(.+)$/) { param_set($1, 0); } - elsif ($l =~ /^--target=(.+)$/) { - $target = $1; - } elsif ($l =~ /^--host=(.+)$/) { $host = $1 . "-"; } @@ -132,21 +178,6 @@ foreach my $l (@ARGV) { } } -if($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Windows") { - param_set("freetype2", 1); - param_set("stb-truetype", 0); -} else { - param_set("freetype2", 0); - param_set("stb-truetype", 0); -} - -if($target eq "Linux") { - param_set("x11", 1); - if(!param_get("tiny")){ - param_set("wayland", 1); - } -} - if (-f "./pl/ostype/${target}.pl") { require("./pl/ostype/${target}.pl"); } @@ -179,12 +210,14 @@ foreach my $e (param_list()) { print("Enabled: " . join(" ", @l) . "\n"); $cc =~ s/\*host\*/$host/; +$cxx =~ s/\*host\*/$host/; $ar =~ s/\*host\*/$host/; open(OUT, ">", "Makefile"); print(OUT "PREFIX = ${prefix}\n"); print(OUT "AR = ${ar}\n"); print(OUT "CC = ${cc}\n"); +print(OUT "CXX = ${cxx}\n"); print(OUT "INCDIR = ${incdir} ${incdir2}\n"); print(OUT "CFLAGS = ${cflags}\n"); print(OUT "LIBDIR = ${libdir}\n"); @@ -208,7 +241,7 @@ print(OUT " cp -rf include \$(DESTDIR)\$(PREFIX)/\n"); print(OUT "\n"); print(OUT "format:\n"); print(OUT -" clang-format --verbose -i `find src include examples \"(\" -name \"*.c\" -or -name \"*.h\" -or -name \"*.m\" \")\" -and -not -name \"*ttf.c\"`\n" +" clang-format --verbose -i `find tools src include examples \"(\" -name \"*.c\" -or -name \"*.cc\" -or -name \"*.h\" -or -name \"*.m\" \")\" -and -not -name \"*ttf.c\"`\n" ); print(OUT " perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl configure -name \"*.pl\"`\n" @@ -225,11 +258,15 @@ if (param_get("static")) { print(OUT "\n"); print(OUT "\n"); if (param_get("shared")) { + my $linker = "CC"; +if (grep(/^haiku$/, @backends)) { + $linker = "CXX"; +} print( OUT "src/${library_prefix}Mw${library_suffix}: " . join(" ", @library_targets) . "\n"); print(OUT -" \$(CC) \$(SHARED) \$(LDFLAGS\) \$(LIBDIR) -o src/${library_prefix}Mw${library_suffix} " +" \$($linker) \$(SHARED) \$(LDFLAGS\) \$(LIBDIR) -o src/${library_prefix}Mw${library_suffix} " . join(" ", @library_targets) . " \$(LIBS)\n"); print(OUT "\n"); @@ -242,12 +279,17 @@ if (param_get("static")) { foreach my $l (@library_targets) { my $warn = "-Wall -Wextra -Wno-sign-compare -Wno-unused-value"; my $s = $l; + my $compiler = "CC"; my $o = $object_suffix; $o =~ s/\./\\\./g; if ($l =~ /cocoa/) { $s =~ s/$o$/.m/; } + elsif ($l =~ /haiku/) { + $s =~ s/$o$/.cc/; + $compiler = "CXX"; + } else { $s =~ s/$o$/.c/; } @@ -257,7 +299,7 @@ foreach my $l (@library_targets) { } print(OUT "${l}: ${s}\n"); - print(OUT " \$(CC) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); + print(OUT " \$($compiler) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); } print(OUT "\n"); print(OUT "\n"); diff --git a/doc/BACKENDDEV.md b/doc/BACKENDDEV.md new file mode 100644 index 00000000..85f61f4f --- /dev/null +++ b/doc/BACKENDDEV.md @@ -0,0 +1,25 @@ +# Backend dev + +The basic process of creating a new Milsko backend is + +- Adding a new include header into `include/Mw/LowLevel`. It must include; + - `struct _MwLLBackendName`: Any details about a window or a subwidget + - `struct _MwLLBackendNameColor`: An 8-bit RGB Color. You'll probably never impl this, this is for platforms like X11/GDI where they have a secondary color representation that can be stored. + - `struct _MwLLBackendNamePixmap`: Self-explanatory. This is also used for the soft gradients in the modern theme. + - `MwLLBackendNameCallInitImpl(void)` called by `MwLibraryInit` to address and platform globals. + - Note that all of those structs are actually unions. They should all start with their `MwLLCommon...` equivalants. +- Fill out `Mw/LowLevel.h` appopriately, adding an include to your new file and the structs in the appropriate unions. These need to be guarded by a `USE_BACKENDNAME` macro which you'll define later when you modify the build system. +- Creating a new impl file in `src/backend` + - Backends actually return a table of function pointers that you have to implement with static functions. Your file should end with `#include "call.c"` and then `CALL(BackendName);`, and somewhere you should have the impl for `MwLLBackendNameCallInitImpl(void)`. + - Prefer to keep the backend file to one file if you can, though obviously exceptions like the Wayland backend exist because it's simply too complex to sanely stuff into one file. +- Add `MwLLBackendNameCallInitImpl` to the `MwLibraryInit` impl in `src/core.c`. +- Add a new enum variation to `MwLLBackends` in `Mw/Include/LowLevel.h`; your impl of `MwLLCreateImpl` will set `common.type` to this so the user can check which backend they're on (important for platforms with multiple supported backends). +- Either + - a.) Modify `CMakeLists.txt` for your platform. + - b.) Add a new perl file in `pl/ostype` that `./configure` can reference, and modify `pl/rules.pl`; If you don't know how to use perl it's fine, just copy a file like the `Linux.pl` or `Windows.pl`, the functions you'll have to change for your platform are self explanatory. Ensure it ends with `1;`. + - c.) Both. + - Both are recommended, but some platforms like Classic Mac OS can't be used with the `./configure` script, and that's fine. + +The functions you'll have to impl are too many to list here so you should start by just copying `x11.c` and then replacing all the function impls with your own. + +\*\*Pay attention to some of these functions' comments in LowLevel.h as they might not be as you expect; for example, `MwLLSetDarkThemeImpl` is for setting the accent color to dark theme on platforms like modern Windows (dark theme itself is set with `MwSetInteger(handle, MwNdarktheme, 1)`). diff --git a/doc/LOWLEVEL.md b/doc/LOWLEVEL.md deleted file mode 100644 index 9593e8d0..00000000 --- a/doc/LOWLEVEL.md +++ /dev/null @@ -1,5 +0,0 @@ -# LowLevel.h function tips -@warning This is mainly for developers - -1. `MwLLSetSizeHints`, `MwLLMakeBorderless`, `MwLLMakeToolWindow`, `MwLLMakePopup` have to be called between `MwLLBeginStateChange` and `MwLLEndStateChange` - diff --git a/doc/TIERS.md b/doc/TIERS.md new file mode 100644 index 00000000..c94cd6a6 --- /dev/null +++ b/doc/TIERS.md @@ -0,0 +1,20 @@ +# Tiers + +Ports of Milsko are grouped into three "tiers" in terms of their support. + +- **Tier 1**: Before every new release of Milsko, these platforms will be tested to make sure they have full support, and the CI will test them. +- **Tier 2**: These might be outdated or not updated in awhile, they might only compile under a specific version/commit of Milsko. Authors of these backends will be made aware of these updates. +- **Tier 3**: These are outright unfinished. Only use these if you're a developer. + +Currently, the Tier 1 backends are: + +- Windows 9x+/NT 4.0+ +- Any Unix/Linux system that supports X11 or Wayland. + +There are currently no Tier 2 backends. + +Tier 3 backends are: + +- Mac OS X 10.4+ with Cocoa +- Mac OS 7-9, PowerPC (68k support not planned). +- Haiku diff --git a/doc/TINYCONFIG.md b/doc/TINYCONFIG.md index 7ab60b52..024edf60 100644 --- a/doc/TINYCONFIG.md +++ b/doc/TINYCONFIG.md @@ -5,4 +5,5 @@ Milsko's configure script supports the `--tiny` option for building the tiniest - Add `-Oz` to the cflags - (clang only) add `-flto=thin` to the cflags and linker flags - Build stb-image with `STB_IMAGE_STATIC` (this is why you get warnings with stb_image when you use it) -- Disable the Wayland backend +- (Linux) Disable the Wayland backend +- (Linux) Disable dbus integration diff --git a/examples/basic/box.c b/examples/basic/box.c index 1b37168e..e14b9f57 100644 --- a/examples/basic/box.c +++ b/examples/basic/box.c @@ -2,7 +2,7 @@ MwWidget window, box; -void resize(MwWidget handle, void* user, void* client) { +void MWAPI resize(MwWidget handle, void* user, void* client) { int ww = MwGetInteger(handle, MwNwidth); int wh = MwGetInteger(handle, MwNheight); diff --git a/examples/basic/calculator.c b/examples/basic/calculator.c index 998c3e35..8889e97d 100644 --- a/examples/basic/calculator.c +++ b/examples/basic/calculator.c @@ -7,7 +7,7 @@ MwWidget inp; double stack[512]; int sp = 0; -static void resize(MwWidget handle, void* client, void* user) { +static void MWAPI resize(MwWidget handle, void* client, void* user) { int ww = MwGetInteger(handle, MwNwidth); int wh = MwGetInteger(handle, MwNheight) - MwGetInteger(inp, MwNheight); int i; @@ -30,7 +30,7 @@ static void resize(MwWidget handle, void* client, void* user) { } } -static void activate(MwWidget handle, void* client, void* user) { +static void MWAPI activate(MwWidget handle, void* client, void* user) { const char* n = MwGetText(handle, MwNtext); if(('0' <= n[0] && n[0] <= '9') || n[0] == '.') { diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 94a192f2..9d060c31 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -2,7 +2,7 @@ MwWidget window, instructions, text1, text2, cur_text; -static void resize(MwWidget handle, void* user_data, void* call_data) { +static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h; (void)user_data; @@ -28,7 +28,7 @@ static void resize(MwWidget handle, void* user_data, void* call_data) { MwNheight, h - 125 - 50 * 3, NULL); } -static void clipboard(MwWidget handle, void* user_data, void* call_data) { +static void MWAPI clipboard(MwWidget handle, void* user_data, void* call_data) { char* clipboard = call_data; (void)handle; @@ -40,7 +40,7 @@ static void clipboard(MwWidget handle, void* user_data, void* call_data) { } } -static void tick(MwWidget handle, void* user_data, void* call_data) { +static void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { cur_text = text1; MwGetClipboard(handle, MwCLIPBOARD_MAIN); cur_text = text2; diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 6471b782..dbce7fe2 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -1,10 +1,10 @@ #include -MwWidget cpicker; +MwWidget fpicker; MwWidget window; MwWidget button; -void color_callback(MwWidget handle, void* user_data, void* call_data) { +void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { char hexColor[8]; MwRGB* rgb = call_data; @@ -18,14 +18,14 @@ void color_callback(MwWidget handle, void* user_data, void* call_data) { MwSetText(window, MwNbackground, hexColor); } -void color_picker(MwWidget handle, void* user_data, void* call_data) { +void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwWidget cpicker = MwColorPicker(window, "cpicker"); (void)handle; (void)user_data; (void)call_data; - MwAddUserHandler(cpicker, MwNcolorChosenHandler, color_callback, NULL); + MwAddUserHandler(cpicker, MwNcolorChosenHandler, file_callback, NULL); MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); } @@ -42,7 +42,7 @@ int main() { NULL); MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); - MwAddUserHandler(button, MwNactivateHandler, color_picker, NULL); + MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); MwLoop(window); } diff --git a/examples/basic/example.c b/examples/basic/example.c index 7e13acd1..8fe38da7 100644 --- a/examples/basic/example.c +++ b/examples/basic/example.c @@ -1,8 +1,8 @@ #include -MwWidget window, menu, button, button2, button3, button4, button5, button6; +MwWidget window, menu, button, button2, button3, button4, button5, button6, button7; -void handler(MwWidget handle, void* user_data, void* call_data) { +void MWAPI handler(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -10,7 +10,7 @@ void handler(MwWidget handle, void* user_data, void* call_data) { printf("hello world!\n"); } -void handler_theme(MwWidget handle, void* user_data, void* call_data) { +void MWAPI handler_theme(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -20,7 +20,7 @@ void handler_theme(MwWidget handle, void* user_data, void* call_data) { NULL); } -void handler_look(MwWidget handle, void* user_data, void* call_data) { +void MWAPI handler_look(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -30,7 +30,7 @@ void handler_look(MwWidget handle, void* user_data, void* call_data) { NULL); } -void handler_font(MwWidget handle, void* user_data, void* call_data) { +void MWAPI handler_font(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -40,7 +40,7 @@ void handler_font(MwWidget handle, void* user_data, void* call_data) { NULL); } -void resize(MwWidget handle, void* user_data, void* call_data) { +void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h, mh; (void)user_data; @@ -51,24 +51,29 @@ void resize(MwWidget handle, void* user_data, void* call_data) { MwVaApply(button, MwNy, 50 + mh, - MwNwidth, (w - 50 * 2) / 3, + MwNwidth, (w - 50 * 2) / 4, MwNheight, h - 125 - 50 * 3, NULL); MwVaApply(button2, - MwNx, 50 + (w - 50 * 2) / 3, + MwNx, 50 + (w - 50 * 2) / 4, MwNy, 50 + mh, - MwNwidth, (w - 50 * 2) / 3, + MwNwidth, (w - 50 * 2) / 4, MwNheight, h - 125 - 50 * 3, NULL); MwVaApply(button3, - MwNx, 50 + (w - 50 * 2) / 3 * 2, + MwNx, 50 + (w - 50 * 2) / 4 * 2, MwNy, 50 + mh, - MwNwidth, (w - 50 * 2) / 3, + MwNwidth, (w - 50 * 2) / 4, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(button7, + MwNx, 50 + (w - 50 * 2) / 4 * 3, + MwNy, 50 + mh, + MwNwidth, (w - 50 * 2) / 4, MwNheight, h - 125 - 50 * 3, NULL); - MwVaApply(button4, MwNx, 50 + (w - 50 * 2) / 3 * 0, MwNy, h - 50 - 125 + mh, @@ -121,6 +126,10 @@ int main() { MwNbackground, "#66f", MwNforeground, "#000", NULL); + button7 = MwVaCreateWidget(MwButtonClass, "button", window, 250, 50, 100, 125, + MwNtext, "disabled", + MwNdisabled, 1, + NULL); MwAddUserHandler(window, MwNresizeHandler, resize, NULL); MwAddUserHandler(button, MwNactivateHandler, handler_theme, NULL); diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c new file mode 100644 index 00000000..2637f86f --- /dev/null +++ b/examples/basic/filechooser.c @@ -0,0 +1,70 @@ +#include + +MwWidget fpicker; +MwWidget window; +MwWidget button; +MwWidget mb; + +MwBool fpicker_wait = MwFALSE; +MwBool msgbox_wait = MwFALSE; + +void MWAPI ok(MwWidget handle, void* user, void* call) { + (void)handle; + (void)call; + msgbox_wait = MwFALSE; +} + +void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { + mb = MwMessageBox(handle, call_data, "File chosen", MwMB_ICONERROR | MwMB_BUTTONOK); + + (void)user_data; + + MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); + + msgbox_wait = MwTRUE; + + while(msgbox_wait) { + MwStep(mb); + } + + fpicker_wait = MwFALSE; +} + +void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { + fpicker = MwFileChooserEx(handle, "file chooser", 0); + + (void)handle; + (void)user_data; + (void)call_data; + + MwAddUserHandler(fpicker, MwNfileChosenHandler, file_callback, NULL); + + MwSetText(fpicker, MwNbackground, MwGetInteger(fpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + + fpicker_wait = MwTRUE; + + while(fpicker_wait) { + MwStep(fpicker); + } + + MwDestroyWidget(fpicker); + MwDestroyWidget(mb); +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, + MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, + MwNtext, "select file", + NULL); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); + + MwLoop(window); +} diff --git a/examples/basic/listbox.c b/examples/basic/listbox.c index 3f63ad14..0ec9fe7c 100644 --- a/examples/basic/listbox.c +++ b/examples/basic/listbox.c @@ -2,15 +2,15 @@ #include "../harvard.c" -MwWidget wmain; +MwWidget w_main; -void destroy(MwWidget handle, void* user, void* call) { +void MWAPI destroy(MwWidget handle, void* user, void* call) { (void)handle; (void)call; - MwMessageBoxDestroy(user); + MwDestroyWidget(user); } -void activate(MwWidget handle, void* user, void* call) { +void MWAPI activate(MwWidget handle, void* user, void* call) { char msg[256]; MwWidget msgbox; @@ -18,51 +18,44 @@ void activate(MwWidget handle, void* user, void* call) { MwStringPrintIntoBuffer(msg, 256, "You pressed: %s", MwListBoxGet(handle, *(int*)call)); - msgbox = MwMessageBox(wmain, msg, "wow", MwMB_ICONINFO | MwMB_BUTTONOK); + msgbox = MwMessageBox(w_main, msg, "wow", MwMB_ICONINFO | MwMB_BUTTONOK); MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, destroy, msgbox); } int main() { - MwWidget lb; - int len = sizeof(harvard) / sizeof(harvard[0]) - 1; - int i; - MwListBoxPacket* packet; - int index; - MwLLPixmap px; + MwWidget lb; + int len = sizeof(harvard) / sizeof(harvard[0]) - 1; + int i; + int index; + MwLLPixmap px; MwLibraryInit(); - wmain = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, - MwNtitle, "listbox", - NULL); - lb = MwCreateWidget(MwListBoxClass, "listbox", wmain, 5, 5, 630, 470); + w_main = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, + MwNtitle, "listbox", + NULL); + lb = MwCreateWidget(MwListBoxClass, "listbox", w_main, 5, 5, 630, 470); px = MwLoadIcon(lb, MwIconInfo); MwSetInteger(lb, MwNleftPadding, 20); - packet = MwListBoxCreatePacket(); - index = MwListBoxPacketInsert(packet, -1); - MwListBoxPacketSet(packet, index, 0, "Harvard sentence"); - MwListBoxPacketSet(packet, index, 1, "Length"); + index = MwListBoxSet(lb, -1, 0, "Harvard sentence"); + MwListBoxSet(lb, index, -1, "Length"); for(i = 0; i < len; i++) { char sz[16]; MwStringPrintIntoBuffer(sz, 16, "%d", (int)strlen(harvard[i])); - index = MwListBoxPacketInsert(packet, -1); - MwListBoxPacketSetIcon(packet, index, px); - MwListBoxPacketSet(packet, index, 0, harvard[i]); - MwListBoxPacketSet(packet, index, 1, sz); + index = MwListBoxSet(lb, -1, 0, harvard[i]); + MwListBoxSet(lb, index, -1, sz); + MwListBoxSetIcon(lb, index, px); } - MwAddUserHandler(lb, MwNactivateHandler, activate, NULL); + MwAddUserHandler(lb, MwNlistBoxActivateHandler, activate, NULL); MwVaApply(lb, MwNhasHeading, 1, NULL); MwListBoxSetWidth(lb, 0, -128); - MwListBoxInsert(lb, -1, packet); - MwListBoxDestroyPacket(packet); - - MwLoop(wmain); + MwLoop(w_main); } diff --git a/examples/basic/messagebox.c b/examples/basic/messagebox.c index bb1c30dd..8c617d7b 100644 --- a/examples/basic/messagebox.c +++ b/examples/basic/messagebox.c @@ -1,30 +1,32 @@ #include -void ok(MwWidget handle, void* user, void* call) { +void MWAPI ok(MwWidget handle, void* user, void* call) { (void)handle; (void)call; - MwMessageBoxDestroy(user); + MwDestroyWidget(user); } -void spawn(MwWidget handle, void* user, void* call) { +void MWAPI spawn(MwWidget handle, void* user, void* call) { MwWidget mb = MwMessageBox(user, "news has arrived!", "title", MwMB_ICONNEWS | MwMB_BUTTONOK); (void)handle; (void)call; MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); } -void spawn2(MwWidget handle, void* user, void* call) { +void MWAPI spawn2(MwWidget handle, void* user, void* call) { MwWidget mb = MwMessageBox(user, "something went wrong!", "title", MwMB_ICONERROR | MwMB_BUTTONOK); (void)handle; (void)call; MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); } -void spawn3(MwWidget handle, void* user, void* call) { +void MWAPI spawn3(MwWidget handle, void* user, void* call) { int i; (void)handle; @@ -33,6 +35,7 @@ void spawn3(MwWidget handle, void* user, void* call) { for(i = 0; i <= MwMB_ICONCLOCK; i++) { MwWidget mb = MwMessageBox(user, "messagebox test", "title", i | MwMB_BUTTONOK); MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); } } diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index 593e7669..92dab70a 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -6,16 +6,14 @@ #define Padding 20 #define PaddingContent 2 -MwWidget window, menu, box; -MwWidget boxes[32]; -int n = 0, row = -1; +MwWidget window, menu, table; MwMenu e; -static void resize(MwWidget handle, void* user, void* call) { +static void MWAPI resize(MwWidget handle, void* user, void* call) { int w = MwGetInteger(window, MwNwidth); int h = MwGetInteger(window, MwNheight); - MwVaApply(box, + MwVaApply(table, MwNx, Padding, MwNy, MwGetInteger(menu, MwNheight) + Padding, MwNwidth, w - Padding * 2, @@ -23,31 +21,7 @@ static void resize(MwWidget handle, void* user, void* call) { NULL); } -static void newrow(void) { - if(row >= 0) { - int i; - - for(i = n; i < Columns; i++) MwCreateWidget(MwFrameClass, "frame", boxes[row], 0, 0, 0, 0); - } - - boxes[++row] = MwCreateWidget(MwBoxClass, "box", box, 0, 0, 0, 0); - - n = 0; -} - -static void add(MwWidget w) { - int r = MwGetInteger(w, MwNratio); - - if(r == MwDEFAULT) r = 1; - - n += r; - - if(n == Columns) { - newrow(); - } -} - -static void resize_content(MwWidget handle, void* user, void* call) { +static void MWAPI resize_content(MwWidget handle, void* user, void* call) { MwWidget* ws = MwGetChildren(handle); if(ws != NULL) { int pw = MwGetInteger(ws[0], "IpWidth"); @@ -76,7 +50,7 @@ static void resize_content(MwWidget handle, void* user, void* call) { } } -static void resize_frame(MwWidget handle, void* user, void* call) { +static void MWAPI resize_frame(MwWidget handle, void* user, void* call) { MwWidget* ws = MwGetChildren(handle); if(ws != NULL) { int w = MwGetInteger(handle, MwNwidth); @@ -95,14 +69,14 @@ static void resize_frame(MwWidget handle, void* user, void* call) { } static MwWidget frame(const char* name, int width, int height, MwClass cl, ...) { - MwWidget f = MwVaCreateWidget(MwFrameClass, "frame", boxes[row], 0, 0, 0, 0, + MwWidget f = MwVaCreateWidget(MwFrameClass, "frame", table, 0, 0, 0, 0, MwNhasBorder, 1, MwNinverted, 1, NULL); - MwWidget box = MwVaCreateWidget(MwBoxClass, "box", f, 0, 0, 0, 0, + MwWidget table = MwVaCreateWidget(MwBoxClass, "table", f, 0, 0, 0, 0, MwNorientation, MwVERTICAL, NULL); - MwWidget label = MwVaCreateWidget(MwLabelClass, "label", box, 0, 0, 0, 0, + MwWidget label = MwVaCreateWidget(MwLabelClass, "label", table, 0, 0, 0, 0, MwNtext, name, MwNalignment, MwALIGNMENT_BEGINNING, MwNfixedSize, 20, @@ -110,7 +84,7 @@ static MwWidget frame(const char* name, int width, int height, MwClass cl, ...) va_list va; if(cl != NULL) { - MwWidget frame = MwCreateWidget(MwFrameClass, "frame", box, 0, 0, 0, 0); + MwWidget frame = MwCreateWidget(MwFrameClass, "frame", table, 0, 0, 0, 0); MwWidget w; va_start(va, cl); @@ -126,6 +100,8 @@ static MwWidget frame(const char* name, int width, int height, MwClass cl, ...) MwVaApply(f, "VhandledWidget", w, + MwNcolumnSpan, MwGetInteger(w, MwNcolumnSpan), + MwNrowSpan, MwGetInteger(w, MwNrowSpan), NULL); } @@ -140,17 +116,18 @@ static MwWidget child(MwWidget w) { return MwGetVoid(w, "VhandledWidget"); } -static void menu_handler(MwWidget handle, void* user, void* call) { +static void MWAPI menu_handler(MwWidget handle, void* user, void* call) { if(call == e) MwDestroyWidget(window); } int main() { - int i; - MwWidget f, w; - MwListBoxPacket* pkt; - int index; - MwMenu m, m2; - void* v; + int i, j; + MwWidget f, w, b; + MwLLPixmap px; + int index; + MwMenu m, m2; + void* v; + MwRect rc; MwLibraryInit(); @@ -158,6 +135,18 @@ int main() { MwNtitle, "Milsko Periodic Table", NULL); + MwGetScreenSize(window, &rc); + if(rc.height < 800) { + MwVaApply(window, + MwNx, (rc.width - (rc.height - 64)) / 2, + MwNy, (rc.height - (rc.height - 64)) / 2, + MwNwidth, rc.height - 64, + MwNheight, rc.height - 64, + NULL); + } + + px = MwLoadIcon(window, MwIconError); + menu = MwCreateWidget(MwMenuClass, "menu", window, 0, 0, 0, 0); m = MwMenuAdd(menu, NULL, "File"); @@ -208,78 +197,130 @@ int main() { MwAddUserHandler(menu, MwNmenuHandler, menu_handler, NULL); - box = MwVaCreateWidget(MwBoxClass, "box", window, 0, 0, 0, 0, - MwNorientation, MwVERTICAL, - NULL); + table = MwVaCreateWidget(MwTableClass, "table", window, 0, 0, 0, 0, + MwNwaitLayout, 1, + MwNcolumns, 5, + NULL); - newrow(); - - f = frame("Button", -PaddingContent, -PaddingContent, MwButtonClass, - MwNtext, "Press me", + f = frame("Button", -PaddingContent, -PaddingContent, MwBoxClass, + MwNorientation, MwVERTICAL, NULL); - add(f); + b = MwVaCreateWidget(MwButtonClass, "btn", child(f), 0, 0, 0, 0, + MwNtext, "Press me", + NULL); + b = MwVaCreateWidget(MwButtonClass, "btn_disabled", child(f), 0, 0, 0, 0, + MwNtext, "Cannot press me", + MwNdisabled, 1, + NULL); - add(MwVaCreateWidget(MwLabelClass, "label", boxes[row], 0, 0, 0, 0, - MwNbold, 1, - MwNtext, "The Periodic Table of Milsko Widgets", - MwNratio, Columns - 2, - NULL)); + MwVaCreateWidget(MwLabelClass, "label", table, 0, 0, 0, 0, + MwNbold, 1, + MwNtext, "The Periodic Table of Milsko Widgets", + MwNcolumnSpan, Columns - 2, + NULL); + + for(i = 0; i < 2; i++) { + f = frame(i == 0 ? "CheckBox" : "RadioBox", -PaddingContent, -PaddingContent, MwBoxClass, + MwNmargin, PaddingContent, + NULL); + w = child(f); + b = MwVaCreateWidget(MwBoxClass, "table1", w, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + MwNfixedSize, 16, + NULL); + for(j = 0; j < 6; j++) MwVaCreateWidget(i == 0 ? MwCheckBoxClass : MwRadioBoxClass, i == 0 ? "cb" : "rb", b, 0, 0, 0, 0, MwNdisabled, (j == 5) ? 1 : 0, NULL); + b = MwVaCreateWidget(MwBoxClass, "table1", w, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + NULL); + for(j = 0; j < 6; j++) { + char buf[32]; + sprintf(buf, "%sBox %d", i == 0 ? "Check" : "Radio", j + 1); + MwVaCreateWidget(MwLabelClass, "label", b, 0, 0, 0, 0, + MwNtext, buf, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + } + } + + f = frame("Calendar", -PaddingContent, -PaddingContent, MwCalendarClass, + MwNscale, 1, + NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); MwComboBoxAdd(w, -1, "Hello!"); - add(f); f = frame("Entry", -PaddingContent, 24, MwEntryClass, NULL); - add(f); + + f = frame("Image", -PaddingContent, -PaddingContent, MwImageClass, + MwNpixmap, px, + NULL); f = frame("Label", -PaddingContent, -PaddingContent, MwLabelClass, - MwNtext, "Epic text", + MwNtext, "Epic text\nNewline can be used too!", NULL); - add(f); f = frame("ListBox", -PaddingContent, -PaddingContent, MwListBoxClass, MwNhasHeading, 1, NULL); w = child(f); - pkt = MwListBoxCreatePacket(); - index = MwListBoxPacketInsert(pkt, -1); - MwListBoxPacketSet(pkt, index, 0, "Epic title..."); - index = MwListBoxPacketInsert(pkt, -1); - MwListBoxPacketSet(pkt, index, 0, "Hello"); - MwListBoxInsert(w, -1, pkt); - MwListBoxDestroyPacket(pkt); - add(f); + index = MwListBoxSet(w, -1, 0, "Epic title..."); + index = MwListBoxSet(w, -1, 0, "Hello"); f = frame("NumberEntry", -PaddingContent, 24, MwNumberEntryClass, NULL); - add(f); f = frame("ProgressBar", -PaddingContent, 24, MwProgressBarClass, MwNvalue, 25, NULL); - add(f); f = frame("ScrollBar", -PaddingContent, 16, MwScrollBarClass, MwNorientation, MwHORIZONTAL, NULL); - add(f); f = frame("Separator", -PaddingContent, -PaddingContent, MwSeparatorClass, NULL); - add(f); + + f = frame("SubWindow", -PaddingContent, -PaddingContent, MwViewportClass, + MwNcolumnSpan, 2, + NULL); + w = child(f); + MwViewportSetSize(w, 512, 512); + MwVaCreateWidget(MwSubWindowClass, "swnd", MwViewportGetViewport(w), 32, 32, 256, 128, + MwNtitle, "Sub window", + NULL); + MwVaCreateWidget(MwSubWindowClass, "swnd", MwViewportGetViewport(w), 64, 64, 256, 128, + MwNtitle, "Sub window 2", + NULL); + + f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, + MwNcolumnSpan, 2, + NULL); + w = child(f); + MwSetText(MwTabAdd(w, "ABC"), MwNbackground, "#f00"); + MwSetText(MwTabAdd(w, "DEF"), MwNbackground, "#0f0"); + MwSetText(MwTabAdd(w, "GHI"), MwNbackground, "#00f"); f = frame("TreeView", -PaddingContent, -PaddingContent, MwTreeViewClass, NULL); w = child(f); v = MwTreeViewAdd(w, NULL, NULL, "abc"); v = MwTreeViewAdd(w, v, NULL, "def"); v = MwTreeViewAdd(w, v, NULL, "ghi"); - add(f); - if(n != 0) newrow(); - if(n == 0) MwDestroyWidget(boxes[row]); + f = frame("Viewport", -PaddingContent, -PaddingContent, MwViewportClass, NULL); + w = child(f); + MwViewportSetSize(w, 256, 256); + MwVaCreateWidget(MwButtonClass, "btn", MwViewportGetViewport(w), 64, 64, 128, 128, + MwNtext, "Thing", + NULL); MwAddUserHandler(window, MwNresizeHandler, resize, NULL); resize(window, NULL, NULL); + MwVaApply(table, + MwNwaitLayout, 0, + NULL); + MwLoop(window); + + MwLLDestroyPixmap(px); } diff --git a/examples/basic/rotate.c b/examples/basic/rotate.c index 574eb2d6..dbf9c5e1 100644 --- a/examples/basic/rotate.c +++ b/examples/basic/rotate.c @@ -14,7 +14,7 @@ double deg = 0; int ww, wh; -void handler(MwWidget w, void* user, void* client) { +void MWAPI handler(MwWidget w, void* user, void* client) { int i; double cdeg = deg; @@ -44,7 +44,7 @@ void handler(MwWidget w, void* user, void* client) { deg += 120.0 / (1000.0 / MwWaitMS); } -void resize(MwWidget w, void* user, void* client) { +void MWAPI resize(MwWidget w, void* user, void* client) { (void)w; (void)user; (void)client; diff --git a/examples/basic/scrollbar.c b/examples/basic/scrollbar.c index 594cd981..dbaae9a0 100644 --- a/examples/basic/scrollbar.c +++ b/examples/basic/scrollbar.c @@ -1,4 +1,3 @@ - #include int main() { diff --git a/examples/basic/subwindow.c b/examples/basic/subwindow.c new file mode 100644 index 00000000..93145923 --- /dev/null +++ b/examples/basic/subwindow.c @@ -0,0 +1,52 @@ +#include + +#define Shift 16 + +static void MWAPI resize(MwWidget handle, void* user, void* client) { + MwWidget f = MwSubWindowGetFrame(handle); + MwVaApply(user, + MwNwidth, MwGetInteger(f, MwNwidth), + MwNheight, MwGetInteger(f, MwNheight), + NULL); +} + +int main() { + MwWidget w; + int i; + MwLLPixmap px[6]; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 800, 600, + MwNtitle, "subwindow", + NULL); + + px[0] = MwLoadIcon(w, MwIconClock); + px[1] = MwLoadIcon(w, MwIconError); + px[2] = MwLoadIcon(w, MwIconInfo); + px[3] = MwLoadIcon(w, MwIconNews); + px[4] = MwLoadIcon(w, MwIconNote); + px[5] = MwLoadIcon(w, MwIconWarning); + + for(i = 0; i < 16; i++) { + char buf[32]; + MwWidget sw, f, img; + + sprintf(buf, "Sub window %d", i); + + sw = MwVaCreateWidget(MwSubWindowClass, "swnd", w, i * Shift, i * Shift, 128, 128, + MwNtitle, buf, + MwNiconPixmap, px[rand() % 6], + NULL); + + f = MwSubWindowGetFrame(sw); + + img = MwVaCreateWidget(MwImageClass, "img", f, 0, 0, MwGetInteger(f, MwNwidth), MwGetInteger(f, MwNheight), + MwNpixmap, px[rand() % 6], + NULL); + + MwAddUserHandler(sw, MwNresizeHandler, resize, img); + } + + MwLoop(w); +} diff --git a/examples/basic/tab.c b/examples/basic/tab.c new file mode 100644 index 00000000..8ae16c04 --- /dev/null +++ b/examples/basic/tab.c @@ -0,0 +1,43 @@ +#include + +MwWidget tab; + +static void MWAPI resize(MwWidget handle, void* user, void* client) { + MwVaApply(tab, + MwNwidth, MwGetInteger(handle, MwNwidth), + MwNheight, MwGetInteger(handle, MwNheight), + NULL); +} + +int main() { + MwWidget w; + int i; + MwLLPixmap px[6]; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 800, 600, + MwNtitle, "subwindow", + NULL); + + tab = MwCreateWidget(MwTabClass, "tab", w, 0, 0, 800, 600); + + for(i = 0; i < 16; i++) { + char buf[32]; + MwWidget sw, f, img; + + sprintf(buf, "Tab %d", i); + + MwTabAdd(tab, buf); + } + + MwVaApply(MwTabGetFrame(tab, "Tab 1"), + MwNiconPixmap, MwLoadIcon(tab, MwIconWarning), + NULL); + + MwAddUserHandler(w, MwNresizeHandler, resize, NULL); + + resize(w, NULL, NULL); + + MwLoop(w); +} diff --git a/examples/basic/treeview.c b/examples/basic/treeview.c index e08db39c..273dd3e2 100644 --- a/examples/basic/treeview.c +++ b/examples/basic/treeview.c @@ -2,13 +2,13 @@ MwWidget wmain; -void destroy(MwWidget handle, void* user, void* call) { +void MWAPI destroy(MwWidget handle, void* user, void* call) { (void)handle; (void)call; - MwMessageBoxDestroy(user); + MwDestroyWidget(user); } -void activate(MwWidget handle, void* user, void* call) { +void MWAPI activate(MwWidget handle, void* user, void* call) { char msg[256]; MwWidget msgbox; diff --git a/examples/basic/viewport.c b/examples/basic/viewport.c index a9b8961e..930488d9 100644 --- a/examples/basic/viewport.c +++ b/examples/basic/viewport.c @@ -2,7 +2,7 @@ MwWidget vp; -static void resize(MwWidget handle, void* user, void* call) { +static void MWAPI resize(MwWidget handle, void* user, void* call) { int w = MwGetInteger(handle, MwNwidth); int h = MwGetInteger(handle, MwNheight); @@ -10,8 +10,8 @@ static void resize(MwWidget handle, void* user, void* call) { (void)call; MwVaApply(vp, - MwNwidth, w - 10, - MwNheight, h - 10, + MwNwidth, w - 10 - 100, + MwNheight, h - 10 - 100, NULL); } @@ -23,7 +23,7 @@ int main() { w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, MwNtitle, "test", NULL); - vp = MwCreateWidget(MwViewportClass, "vp", w, 5, 5, 630, 470); + vp = MwCreateWidget(MwViewportClass, "vp", w, 5 + 50, 5 + 50, 640 - 10 - 100, 480 - 10 - 100); px = MwLoadImage(vp, "examples/picture.png"); diff --git a/examples/gldemos/clock.c b/examples/gldemos/clock.c index 271b0881..9f683b50 100644 --- a/examples/gldemos/clock.c +++ b/examples/gldemos/clock.c @@ -13,7 +13,7 @@ double deg2rad(double deg) { return (360.0 - deg) / 180.0 * M_PI; } -void tick(MwWidget handle, void* user, void* call) { +void MWAPI tick(MwWidget handle, void* user, void* call) { time_t t = time(NULL); int i; double rad; @@ -104,7 +104,7 @@ void tick(MwWidget handle, void* user, void* call) { MwOpenGLSwapBuffer(opengl); } -void resize(MwWidget handle, void* user, void* call) { +void MWAPI resize(MwWidget handle, void* user, void* call) { int w = MwGetInteger(handle, MwNwidth); int h = MwGetInteger(handle, MwNheight); diff --git a/examples/gldemos/gears.c b/examples/gldemos/gears.c index 04962c8c..5d06b067 100644 --- a/examples/gldemos/gears.c +++ b/examples/gldemos/gears.c @@ -231,13 +231,13 @@ static void init(void) { static void key(int k) { (void)k; - if(k == MwLLKeyLeft) { + if(k == MwKEY_LEFT) { view_roty += 5.0; - } else if(k == MwLLKeyRight) { + } else if(k == MwKEY_RIGHT) { view_roty -= 5.0; - } else if(k == MwLLKeyUp) { + } else if(k == MwKEY_UP) { view_rotx += 5.0; - } else if(k == MwLLKeyDown) { + } else if(k == MwKEY_DOWN) { view_rotx -= 5.0; } } diff --git a/examples/gldemos/glutlayer.c b/examples/gldemos/glutlayer.c index dd24ef5a..8746b940 100644 --- a/examples/gldemos/glutlayer.c +++ b/examples/gldemos/glutlayer.c @@ -9,7 +9,7 @@ static void reshape(int width, int height); static void init(void); static void key(int k); -static void tick(MwWidget handle, void* user, void* client) { +static void MWAPI tick(MwWidget handle, void* user, void* client) { (void)handle; (void)user; (void)client; @@ -20,7 +20,7 @@ static void tick(MwWidget handle, void* user, void* client) { MwOpenGLSwapBuffer(opengl); } -static void resize(MwWidget handle, void* user, void* client) { +static void MWAPI resize(MwWidget handle, void* user, void* client) { int ww, wh; (void)user; @@ -37,7 +37,7 @@ static void resize(MwWidget handle, void* user, void* client) { reshape(ww, wh); } -static void key_pressed(MwWidget handle, void* user, void* client) { +static void MWAPI key_pressed(MwWidget handle, void* user, void* client) { (void)handle; (void)user; @@ -53,18 +53,21 @@ int main() { MwNtitle, TITLE, NULL); opengl = MwCreateWidget(MwOpenGLClass, "opengl", window, 50, 50, 400, 400); + if(!opengl) { + MwMessageBox(NULL, "Unable to create OpenGL window.", "Error", MwMB_ICONERROR); + } else { + MwOpenGLMakeCurrent(opengl); - MwOpenGLMakeCurrent(opengl); + init(); + reshape(400, 400); - init(); - reshape(400, 400); + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(opengl, MwNtickHandler, tick, NULL); - MwAddUserHandler(window, MwNresizeHandler, resize, NULL); - MwAddUserHandler(opengl, MwNtickHandler, tick, NULL); + MwAddTickList(opengl); - MwAddTickList(opengl); - - MwAddUserHandler(opengl, MwNkeyHandler, key_pressed, NULL); + MwAddUserHandler(opengl, MwNkeyHandler, key_pressed, NULL); + } MwLoop(window); } diff --git a/examples/gldemos/triangle.c b/examples/gldemos/triangle.c index ceb70e37..702fca05 100644 --- a/examples/gldemos/triangle.c +++ b/examples/gldemos/triangle.c @@ -6,7 +6,7 @@ int ow, oh; double deg = 0; double dir = 1; -void resize(MwWidget handle, void* user_data, void* call_data) { +void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h; (void)user_data; @@ -27,7 +27,7 @@ void resize(MwWidget handle, void* user_data, void* call_data) { NULL); } -void tick(MwWidget handle, void* user_data, void* call_data) { +void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -61,7 +61,7 @@ void tick(MwWidget handle, void* user_data, void* call_data) { deg += 120.0 / (1000.0 / MwWaitMS) * dir; } -void activate(MwWidget handle, void* user_data, void* call_data) { +void MWAPI activate(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; diff --git a/examples/gldemos/tripaint.c b/examples/gldemos/tripaint.c index 1208b26a..11eaffd5 100644 --- a/examples/gldemos/tripaint.c +++ b/examples/gldemos/tripaint.c @@ -17,7 +17,7 @@ int ct = 0; int click = 0; int mx, my; -static void tick(MwWidget handle, void* user, void* call) { +static void MWAPI tick(MwWidget handle, void* user, void* call) { int i; int w = MwGetInteger(opengl, MwNwidth); int h = MwGetInteger(opengl, MwNheight); @@ -50,7 +50,7 @@ static void tick(MwWidget handle, void* user, void* call) { MwOpenGLSwapBuffer(opengl); } -static void mouse(MwWidget handle, void* user, void* call) { +static void MWAPI mouse(MwWidget handle, void* user, void* call) { MwMouse* mouse = call; (void)handle; @@ -91,7 +91,7 @@ static void mouse(MwWidget handle, void* user, void* call) { } } -static void mouse_move(MwWidget handle, void* user, void* call) { +static void MWAPI mouse_move(MwWidget handle, void* user, void* call) { MwPoint* point = call; (void)handle; @@ -125,13 +125,12 @@ int main() { MwNtext, "Press left click to draw triangle, right click to undo", NULL); - MwViewportSetSize(viewport, 1024, 768); - t = malloc(sizeof(*t)); - opengl = MwCreateWidget(MwOpenGLClass, "opengl", MwViewportGetViewport(viewport), 0, 0, 1024, 768); + opengl = MwCreateWidget(MwOpenGLClass, "opengl", viewport, 0, 0, 1024, 768); MwAddUserHandler(window, MwNtickHandler, tick, NULL); + MwAddUserHandler(opengl, MwNtickHandler, tick, NULL); MwAddUserHandler(opengl, MwNmouseDownHandler, mouse, NULL); MwAddUserHandler(opengl, MwNmouseMoveHandler, mouse_move, NULL); diff --git a/examples/vkdemos/CMakeLists.txt b/examples/vkdemos/CMakeLists.txt index 41f832c2..9f37e0f7 100644 --- a/examples/vkdemos/CMakeLists.txt +++ b/examples/vkdemos/CMakeLists.txt @@ -1,28 +1,30 @@ file( - GLOB - EXAMPLES_VULKAN_SOURCES - *.c + GLOB + EXAMPLES_VULKAN_SOURCES + *.c ) find_package(Vulkan) -foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) - get_filename_component(TARGET ${PATH} NAME_WE) - add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) - target_include_directories( - ${TARGET} - PRIVATE - ${Vulkan_INCLUDE_DIR} - ) - target_link_libraries( - ${TARGET} - PRIVATE - Mw - ) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries( - ${TARGET} - PRIVATE - m - ) - endif() -endforeach() +if(${Vulkan_FOUND}) + foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) + target_include_directories( + ${TARGET} + PRIVATE + ${Vulkan_INCLUDE_DIR} + ) + target_link_libraries( + ${TARGET} + PRIVATE + Mw + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() + endforeach() +endif() diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 7e20a5be..9060a970 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -1,10 +1,3 @@ - -/** - * this example is quite minimal, you may need to modify it if your graphics card is more esoteric - * - * ioixd maintains this file. nishi doesn't know vulkan at all - */ - #include #include @@ -66,7 +59,7 @@ VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; PFN_##name _##name = (PFN_##name)_vkGetInstanceProcAddr(instance, #name); \ assert(_##name); -void tick(MwWidget handle, void* user_data, void* call_data) { +void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; @@ -624,9 +617,9 @@ int main() { MwNtitle, "hello world", NULL); - MwVulkanEnableExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - - vulkan = MwCreateWidget(MwVulkanClass, "vulkan", window, 50, 50, ow, oh); + vulkan = MwVaCreateWidget(MwVulkanClass, "vulkan", window, 50, 50, ow, oh, + MwNvulkanExtension, VK_KHR_SWAPCHAIN_EXTENSION_NAME, + NULL); MwAddUserHandler(window, MwNtickHandler, tick, NULL); diff --git a/include/Mw/Abstract/CharSet.h b/include/Mw/Abstract/CharSet.h new file mode 100644 index 00000000..f0a42f7d --- /dev/null +++ b/include/Mw/Abstract/CharSet.h @@ -0,0 +1,22 @@ +/*! + * @file Mw/Abstract/CharSet.h + * @brief CharSet + */ +#ifndef __MW_ABSTRACT_CHARSET_H__ +#define __MW_ABSTRACT_CHARSET_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MWDECL char* MWAPI MwACPToUTF8(const char* input); + +MWDECL char* MWAPI MwUTF8ToACP(const char* input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/Abstract/Directory.h b/include/Mw/Abstract/Directory.h index 7f6629bd..1e1db49c 100644 --- a/include/Mw/Abstract/Directory.h +++ b/include/Mw/Abstract/Directory.h @@ -17,32 +17,32 @@ extern "C" { * @param path Path * @return Handle */ -MWDECL void* MwDirectoryOpen(const char* path); +MWDECL void* MWAPI MwDirectoryOpen(const char* path); /*! * @brief Closes a directory * @param handle Handle */ -MWDECL void MwDirectoryClose(void* handle); +MWDECL void MWAPI MwDirectoryClose(void* handle); /*! * @brief Reads a directory * @param handle Handle * @return Directory entry */ -MWDECL MwDirectoryEntry* MwDirectoryRead(void* handle); +MWDECL MwDirectoryEntry* MWAPI MwDirectoryRead(void* handle); /*! * @brief Frees a directory entry * @param entry Entry */ -MWDECL void MwDirectoryFreeEntry(MwDirectoryEntry* entry); +MWDECL void MWAPI MwDirectoryFreeEntry(MwDirectoryEntry* entry); /*! * @brief Gets a current directory * @param Directory */ -MWDECL char* MwDirectoryCurrent(void); +MWDECL char* MWAPI MwDirectoryCurrent(void); /*! * @brief Joins 2 paths @@ -50,7 +50,7 @@ MWDECL char* MwDirectoryCurrent(void); * @param b Path * @return Path */ -MWDECL char* MwDirectoryJoin(char* a, char* b); +MWDECL char* MWAPI MwDirectoryJoin(char* a, char* b); #ifdef __cplusplus } diff --git a/include/Mw/Abstract/Dynamic.h b/include/Mw/Abstract/Dynamic.h index d649d4d5..ead50706 100644 --- a/include/Mw/Abstract/Dynamic.h +++ b/include/Mw/Abstract/Dynamic.h @@ -16,20 +16,20 @@ extern "C" { * @param path Path * @return Handle */ -MWDECL void* MwDynamicOpen(const char* path); +MWDECL void* MWAPI MwDynamicOpen(const char* path); /*! * @brief Gets a symbol from the dynamic library * @param handle Handle * @param symbol Symbol */ -MWDECL void* MwDynamicSymbol(void* handle, const char* symbol); +MWDECL void* MWAPI MwDynamicSymbol(void* handle, const char* symbol); /*! * @brief Closes a dynamic library * @param handle Handle */ -MWDECL void MwDynamicClose(void* handle); +MWDECL void MWAPI MwDynamicClose(void* handle); #ifdef __cplusplus } diff --git a/include/Mw/Abstract/Time.h b/include/Mw/Abstract/Time.h index 58f246ec..c8ffbf6b 100644 --- a/include/Mw/Abstract/Time.h +++ b/include/Mw/Abstract/Time.h @@ -15,13 +15,13 @@ extern "C" { * @brief Sleeps for milliseconds * @param ms Milliseconds */ -MWDECL void MwTimeSleep(int ms); +MWDECL void MWAPI MwTimeSleep(int ms); /*! * @brief Gets a monotonic time * @return Monotonic time */ -MWDECL long MwTimeGetTick(void); +MWDECL long MWAPI MwTimeGetTick(void); #ifdef __cplusplus } diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index d710ca00..15853ff7 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -121,4 +121,22 @@ enum MwMOUSE { MwMOUSE_WHEELDOWN }; +#define MwKEY_FLAG 0x80000000 +#define MwKEY_CONTROL_FLAG MwKEY_FLAG | 0x40000000 +#define MwKEY_ALT_FLAG MwKEY_FLAG | 0x20000000 + +enum MwKEY { + MwKEY_BACKSPACE = MwKEY_FLAG | 1, + MwKEY_LEFT, + MwKEY_RIGHT, + MwKEY_UP, + MwKEY_DOWN, + MwKEY_ENTER, + MwKEY_ESCAPE, + MwKEY_LEFTSHIFT, + MwKEY_RIGHTSHIFT, + MwKEY_ALT, + MwKEY_CONTROL +}; + #endif diff --git a/include/Mw/Core.h b/include/Mw/Core.h index ad4cd19d..61cb0855 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -60,7 +60,7 @@ extern "C" { * @brief Initializes the Milsko Toolkit * @return `0` if successful */ -MWDECL int MwLibraryInit(void); +MWDECL int MWAPI MwLibraryInit(void); /*! * @brief Creates a widget @@ -73,7 +73,7 @@ MWDECL int MwLibraryInit(void); * @param height Height * @return Widget */ -MWDECL MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height); +MWDECL MwWidget MWAPI MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height); /*! * @brief Creates a widget @@ -87,7 +87,7 @@ MWDECL MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget * @param ... Same with MwVaApply * @return Widget */ -MWDECL MwWidget MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, ...); +MWDECL MwWidget MWAPI MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, ...); /*! * @brief Creates a widget @@ -101,13 +101,13 @@ MWDECL MwWidget MwVaCreateWidget(MwClass widget_class, const char* name, MwWidge * @param va Same with MwVaListApply * @return Widget */ -MWDECL MwWidget MwVaListCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, va_list va); +MWDECL MwWidget MWAPI MwVaListCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, va_list va); /*! * @brief Destroys the widget and its child widgets * @param handle Widget */ -MWDECL void MwDestroyWidget(MwWidget handle); +MWDECL void MWAPI MwDestroyWidget(MwWidget handle); /*! * @brief Executes a method specific to the widget (varadic version). @@ -115,7 +115,7 @@ MWDECL void MwDestroyWidget(MwWidget handle); * @param handle Widget * @param ... Widget function arguments. */ -MWDECL void MwVaWidgetExecute(MwWidget handle, const char* func_name, void* out, ...); +MWDECL void MWAPI MwVaWidgetExecute(MwWidget handle, const char* func_name, void* out, ...); /*! * @brief Executes a method specific to the widget (va_list version). @@ -123,27 +123,27 @@ MWDECL void MwVaWidgetExecute(MwWidget handle, const char* func_name, void* out, * @param handle Widget * @param va Widget function arguments. */ -MWDECL void MwVaListWidgetExecute(MwWidget handle, const char* func_name, void* out, va_list va); +MWDECL void MWAPI MwVaListWidgetExecute(MwWidget handle, const char* func_name, void* out, va_list va); /*! * @brief Runs the main loop * @param handle Widget */ -MWDECL void MwLoop(MwWidget handle); +MWDECL void MWAPI MwLoop(MwWidget handle); /*! * @brief Runs the single step * @param handle Widget * @return `0` if successful */ -MWDECL int MwStep(MwWidget handle); +MWDECL int MWAPI MwStep(MwWidget handle); /*! * @brief Check if any event is pending * @param handle Widget * @return `1` if any event is pending */ -MWDECL int MwPending(MwWidget handle); +MWDECL int MWAPI MwPending(MwWidget handle); /*! * @brief Sets an integer property @@ -151,7 +151,7 @@ MWDECL int MwPending(MwWidget handle); * @param key Key * @param n Value */ -MWDECL void MwSetInteger(MwWidget handle, const char* key, int n); +MWDECL void MWAPI MwSetInteger(MwWidget handle, const char* key, int n); /*! * @brief Sets a text property @@ -159,7 +159,7 @@ MWDECL void MwSetInteger(MwWidget handle, const char* key, int n); * @param key Key * @param value Value */ -MWDECL void MwSetText(MwWidget handle, const char* key, const char* value); +MWDECL void MWAPI MwSetText(MwWidget handle, const char* key, const char* value); /*! * @brief Sets a void pointer property @@ -167,7 +167,7 @@ MWDECL void MwSetText(MwWidget handle, const char* key, const char* value); * @param key Key * @param value Value */ -MWDECL void MwSetVoid(MwWidget handle, const char* key, void* value); +MWDECL void MWAPI MwSetVoid(MwWidget handle, const char* key, void* value); /*! * @brief Gets the integer property @@ -175,7 +175,7 @@ MWDECL void MwSetVoid(MwWidget handle, const char* key, void* value); * @param key Key * @return Value */ -MWDECL int MwGetInteger(MwWidget handle, const char* key); +MWDECL int MWAPI MwGetInteger(MwWidget handle, const char* key); /*! * @brief Gets the text property @@ -183,7 +183,7 @@ MWDECL int MwGetInteger(MwWidget handle, const char* key); * @param key Key * @return Value */ -MWDECL const char* MwGetText(MwWidget handle, const char* key); +MWDECL const char* MWAPI MwGetText(MwWidget handle, const char* key); /*! * @brief Gets the void pointer property @@ -191,28 +191,28 @@ MWDECL const char* MwGetText(MwWidget handle, const char* key); * @param key Key * @return Value */ -MWDECL void* MwGetVoid(MwWidget handle, const char* key); +MWDECL void* MWAPI MwGetVoid(MwWidget handle, const char* key); /*! * @brief Sets the default property * @param handle Widget * @warning This is called when widget is created */ -MWDECL void MwSetDefault(MwWidget handle); +MWDECL void MWAPI MwSetDefault(MwWidget handle); /*! * @brief Sets the properties * @param handle Widget * @param ... Properties */ -MWDECL void MwVaApply(MwWidget handle, ...); +MWDECL void MWAPI MwVaApply(MwWidget handle, ...); /*! * @brief Sets properties * @param handle Widget * @param va Properties */ -MWDECL void MwVaListApply(MwWidget handle, va_list va); +MWDECL void MWAPI MwVaListApply(MwWidget handle, va_list va); /*! * @brief Sets a user handler @@ -221,7 +221,7 @@ MWDECL void MwVaListApply(MwWidget handle, va_list va); * @param handler Handler * @param user_data User data passed to handler */ -MWDECL void MwAddUserHandler(MwWidget handle, const char* key, MwUserHandler handler, void* user_data); +MWDECL void MWAPI MwAddUserHandler(MwWidget handle, const char* key, MwUserHandler handler, void* user_data); /*! * @brief Dispatches the user handler @@ -229,7 +229,7 @@ MWDECL void MwAddUserHandler(MwWidget handle, const char* key, MwUserHandler han * @param key Key * @param handler_data Handler data passed to handler */ -MWDECL void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data); +MWDECL void MWAPI MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data); /*! * @brief Sets an error handler @@ -237,59 +237,52 @@ MWDECL void MwDispatchUserHandler(MwWidget handle, const char* key, void* handle * @param handler Handler * @param user_data User data passed to handler */ -MWDECL void MwSetErrorHandler(MwErrorHandler handler, void* user_data); +MWDECL void MWAPI MwSetErrorHandler(MwErrorHandler handler, void* user_data); /*! * @brief Dispatches the error handler * @param code Error code * @param message Error message */ -MWDECL void MwDispatchError(int code, const char* message); - -/*! - * @brief Gets the before_step of widget - * @param handle Widget - * @param jmpbuf jmp_buf - */ -MWDECL void MwGetBeforeStep(MwWidget handle, jmp_buf* jmpbuf); +MWDECL void MWAPI MwDispatchError(int code, const char* message); /*! * @brief Forcefully makes widget render * @param handle Widget */ -MWDECL void MwForceRender(MwWidget handle); +MWDECL void MWAPI MwForceRender(MwWidget handle); /*! * @brief Forcefully makes widget render * @param handle Widget * @param ptr Ignored */ -MWDECL void MwForceRender2(MwWidget handle, void* ptr); +MWDECL void MWAPI MwForceRender2(MwWidget handle, void* ptr); /*! * @brief Adds an widget to tick handler list * @param handle Widget */ -MWDECL void MwAddTickList(MwWidget handle); +MWDECL void MWAPI MwAddTickList(MwWidget handle); /*! * @brief Focus the widget * @param handle Widget */ -MWDECL void MwFocus(MwWidget handle); +MWDECL void MWAPI MwFocus(MwWidget handle); /*! * @brief Grabs the pointer * @param handle Widget * @param toggle Toggle */ -MWDECL void MwGrabPointer(MwWidget handle, int toggle); +MWDECL void MWAPI MwGrabPointer(MwWidget handle, int toggle); /*! * @brief Hides the cursor * @param handle Widget */ -MWDECL void MwHideCursor(MwWidget handle); +MWDECL void MWAPI MwHideCursor(MwWidget handle); /*! * @brief Toggles the dark theme @@ -297,76 +290,113 @@ MWDECL void MwHideCursor(MwWidget handle); * @param toggle Toggle * @deprecated Use MwNdarkTheme instead */ -MWDECL void MwSetDarkTheme(MwWidget handle, int toggle); +MWDECL void MWAPI MwSetDarkTheme(MwWidget handle, int toggle); /*! * @brief Gets the parent widget * @param handle Widget * @return Parent widget */ -MWDECL MwWidget MwGetParent(MwWidget handle); +MWDECL MwWidget MWAPI MwGetParent(MwWidget handle); /*! * @brief Show widget * @param handle Widget * @param toggle Toggle */ -MWDECL void MwShow(MwWidget handle, int toggle); +MWDECL void MWAPI MwShow(MwWidget handle, int toggle); /*! * @brief Reparents widget * @param handle Widget * @param new_parent New parent */ -MWDECL void MwReparent(MwWidget handle, MwWidget new_parent); +MWDECL void MWAPI MwReparent(MwWidget handle, MwWidget new_parent); /*! * @brief Gets class of widget * @param handle Widget * @return Class */ -MWDECL MwClass MwGetClass(MwWidget handle); +MWDECL MwClass MWAPI MwGetClass(MwWidget handle); /*! * @brief Gets name of widget * @param handle Widget * @return Name */ -MWDECL const char* MwGetName(MwWidget handle); +MWDECL const char* MWAPI MwGetName(MwWidget handle); /*! * @brief Gets children of widget * @param handle Widget * @return Children (NULL-terminated array) */ -MWDECL MwWidget* MwGetChildren(MwWidget handle); +MWDECL MwWidget* MWAPI MwGetChildren(MwWidget handle); /*! * @brief Gets the cursor coordinate * @param handle Widget * @param point Point */ -MWDECL void MwGetCursorCoord(MwWidget handle, MwPoint* point); +MWDECL void MWAPI MwGetCursorCoord(MwWidget handle, MwPoint* point); /*! * @brief Gets the screen size * @param handle Widget * @param rect Rectangle */ -MWDECL void MwGetScreenSize(MwWidget handle, MwRect* rect); +MWDECL void MWAPI MwGetScreenSize(MwWidget handle, MwRect* rect); /*! * @brief Reports whether a widget reports global or local coordinates upon GetXY/SetXY. Anything with a parent reports local, and most backends report global coordinates being supported for top level windows, but some (Wayland) do not. * @param handle Widget */ -MWDECL int MwGetCoordinateType(MwWidget handle); +MWDECL int MWAPI MwGetCoordinateType(MwWidget handle); /*! - * @brief Queue to get clipboard content. + * @brief Queue to get clipboard content * @param handle Widget * @param clipboard_type The Clipboard Type to get. See MwClipboardType. This is ignored on backends that aren't X11/Wayland, so if you're unsure, just use MwClipboardMain */ -MWDECL void MwGetClipboard(MwWidget handle, int clipboard_type); +MWDECL void MWAPI MwGetClipboard(MwWidget handle, int clipboard_type); + +/*! + * @brief Set user pointer + * @param handle Widget + * @param user User pointer + */ +MWDECL void MWAPI MwSetUser(MwWidget handle, void* user); + +/*! + * @brief Get user pointer + * @param handle Widget + * @return User pointer + */ +MWDECL void* MWAPI MwGetUser(MwWidget handle); + +/*! + * @brief Free the widget + * @param handle Widget + * @warning This is used internally! + * @note You can call this on toplevel widget safely if you're sure no event loops will be ran, e.g. after `MwLoop`. + */ +MWDECL void MWAPI MwFreeWidget(MwWidget handle); + +/*! + * @brief Gets the frame of the widget + * @param handle Widget + * @param rect Frame + */ +MWDECL void MWAPI MwGetFrame(MwWidget handle, MwRect* rect); + +#ifdef _MILSKO +MWDECL void MwForceRender_Internal(MwWidget handle); +MWDECL void MwForceRender2_Internal(MwWidget handle, void* ptr); + +#define MwForceRender MwForceRender_Internal +#define MwForceRender2 MwForceRender2_Internal +#endif #ifdef __cplusplus } diff --git a/include/Mw/Default.h b/include/Mw/Default.h index 3d197d01..322082b2 100644 --- a/include/Mw/Default.h +++ b/include/Mw/Default.h @@ -32,6 +32,16 @@ MWDECL const char* MwDefaultSubBackground; */ MWDECL const char* MwDefaultSubForeground; +/*! + * @brief Default title background color + */ +MWDECL const char* MwDefaultTitleBackground; + +/*! + * @brief Default title foreground color + */ +MWDECL const char* MwDefaultTitleForeground; + /*! * @brief Default dark theme background color */ @@ -52,6 +62,16 @@ MWDECL const char* MwDefaultDarkSubBackground; */ MWDECL const char* MwDefaultDarkSubForeground; +/*! + * @brief Default dark theme title background color + */ +MWDECL const char* MwDefaultDarkTitleBackground; + +/*! + * @brief Default dark theme title foreground color + */ +MWDECL const char* MwDefaultDarkTitleForeground; + /*! * @brief Default shadow difference */ @@ -61,7 +81,13 @@ MWDECL const int MwDefaultShadow; * @brief Gets default border width * @param handle Widget */ -MWDECL int MwDefaultBorderWidth(MwWidget handle); +MWDECL int MWAPI MwDefaultBorderWidth(MwWidget handle); + +/*! + * @brief Gets default thin border width + * @param handle Widget + */ +MWDECL int MwDefaultThinBorderWidth(MwWidget handle); #ifdef __cplusplus } diff --git a/include/Mw/Dialog/ColorPicker.h b/include/Mw/Dialog/ColorPicker.h index a4d77a17..b143fdf5 100644 --- a/include/Mw/Dialog/ColorPicker.h +++ b/include/Mw/Dialog/ColorPicker.h @@ -18,7 +18,7 @@ extern "C" { * @param title Title text * @return Widget */ -MWDECL MwWidget MwColorPicker(MwWidget handle, const char* title); +MWDECL MwWidget MWAPI MwColorPicker(MwWidget handle, const char* title); #ifdef __cplusplus } diff --git a/include/Mw/Dialog/DirectoryChooser.h b/include/Mw/Dialog/DirectoryChooser.h index dceaaa66..cc6853c3 100644 --- a/include/Mw/Dialog/DirectoryChooser.h +++ b/include/Mw/Dialog/DirectoryChooser.h @@ -18,7 +18,7 @@ extern "C" { * @param title Title text * @return Widget */ -MWDECL MwWidget MwDirectoryChooser(MwWidget handle, const char* title); +MWDECL MwWidget MWAPI MwDirectoryChooser(MwWidget handle, const char* title); #ifdef __cplusplus } diff --git a/include/Mw/Dialog/FileChooser.h b/include/Mw/Dialog/FileChooser.h index d086a74e..f6aa094e 100644 --- a/include/Mw/Dialog/FileChooser.h +++ b/include/Mw/Dialog/FileChooser.h @@ -18,7 +18,7 @@ extern "C" { * @param title Title text * @return Widget */ -MWDECL MwWidget MwFileChooser(MwWidget handle, const char* title); +MWDECL MwWidget MWAPI MwFileChooser(MwWidget handle, const char* title); /*! * @brief Creates a file chooser @@ -27,7 +27,7 @@ MWDECL MwWidget MwFileChooser(MwWidget handle, const char* title); * @param dir Show directory only or not * @return Widget */ -MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir); +MWDECL MwWidget MWAPI MwFileChooserEx(MwWidget handle, const char* title, int dir); #ifdef __cplusplus } diff --git a/include/Mw/Dialog/MessageBox.h b/include/Mw/Dialog/MessageBox.h index 8a5e9cba..a8a5a462 100644 --- a/include/Mw/Dialog/MessageBox.h +++ b/include/Mw/Dialog/MessageBox.h @@ -20,20 +20,14 @@ extern "C" { * @param flag Flag * @return Widget */ -MWDECL MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsigned int flag); +MWDECL MwWidget MWAPI MwMessageBox(MwWidget handle, const char* text, const char* title, unsigned int flag); /*! * @brief Gets a child of the message box * @param handle Widget * @param child Child */ -MWDECL MwWidget MwMessageBoxGetChild(MwWidget handle, int child); - -/*! - * @brief Destroys the message box - * @param handle Widget - */ -MWDECL void MwMessageBoxDestroy(MwWidget handle); +MWDECL MwWidget MWAPI MwMessageBoxGetChild(MwWidget handle, int child); #ifdef __cplusplus } diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index 9208d725..deefe0fc 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -19,14 +19,20 @@ extern "C" { * @param text Color text * @return Color */ -MWDECL MwLLColor MwParseColor(MwWidget handle, const char* text); +MWDECL MwLLColor MWAPI MwParseColor(MwWidget handle, const char* text); /*! * @brief Parses a color text * @param text Color text * @param rgb RGB */ -MWDECL void MwParseColorNoAllocate(const char* text, MwRGB* rgb); +MWDECL void MWAPI MwParseColorNoAllocate(const char* text, MwRGB* rgb); + +/*! + * @brief Initialize color table + * @warning This is called in MwLibraryInit - you do not have to call this + */ +MWDECL void MWAPI MwColorTableInit(void); /*! * @brief Lighten a color @@ -37,7 +43,7 @@ MWDECL void MwParseColorNoAllocate(const char* text, MwRGB* rgb); * @param b Blue * @return Color */ -MWDECL MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b); +MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b); /*! * @brief Draws a filled rectangle @@ -45,7 +51,7 @@ MWDECL MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, * @param rect Rectangle area * @param color Color */ -MWDECL void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); +MWDECL void MWAPI MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); /*! * @brief Draws a filled rectangle that fades to a darker color @@ -53,7 +59,7 @@ MWDECL void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); * @param rect Rectangle area * @param color Color */ -MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); +MWDECL void MWAPI MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); /*! * @brief Draws a frame @@ -63,7 +69,18 @@ MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); * @param invert Invert the 3D border color or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert); +MWDECL void MWAPI MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert); + +/*! + * @brief Draws a frame + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + * @param border Border + * @warning `rect` gets changed to the area of rectangle inside + */ +MWDECL void MWAPI MwDrawFrameWithBorder(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border); /*! * @brief Does the DrawFrame/DrawRect combo used for drawing widget. @@ -73,7 +90,7 @@ MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int inve * @param invert Invert the 3D border color or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border); +MWDECL void MWAPI MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border); /*! * @brief Draws a triangle @@ -82,7 +99,7 @@ MWDECL void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int * @param color Color * @param invert Invert the 3D border color or not */ -MWDECL void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction); +MWDECL void MWAPI MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction); /*! * @brief Draws a frame with specified border width @@ -93,10 +110,9 @@ MWDECL void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int i * @param border Border width * @param diff Difference (set this to 0 if you don't know what this does) * @param same Same as dark color - * @param rounded Rounded or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); +MWDECL void MWAPI MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); /*! * @brief Creates a pixmap from image @@ -104,7 +120,7 @@ MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int in * @param path Path * @return Pixmap */ -MWDECL MwLLPixmap MwLoadImage(MwWidget handle, const char* path); +MWDECL MwLLPixmap MWAPI MwLoadImage(MwWidget handle, const char* path); /*! * @brief Get color components @@ -113,7 +129,7 @@ MWDECL MwLLPixmap MwLoadImage(MwWidget handle, const char* path); * @param green Pointer to green color * @param blue Pointer to blue color */ -MWDECL void MwColorGet(MwLLColor color, int* red, int* green, int* blue); +MWDECL void MWAPI MwColorGet(MwLLColor color, int* red, int* green, int* blue); /*! * @brief Creates a pixmap from raw data @@ -123,28 +139,28 @@ MWDECL void MwColorGet(MwLLColor color, int* red, int* green, int* blue); * @param height Height * @return Pixmap */ -MWDECL MwLLPixmap MwLoadRaw(MwWidget handle, unsigned char* rgb, int width, int height); +MWDECL MwLLPixmap MWAPI MwLoadRaw(MwWidget handle, unsigned char* rgb, int width, int height); /*! * @brief Updates a pixmap using raw data * @param pixmap Pixmap to update * @param rgb RGBA data */ -MWDECL void MwPixmapReloadRaw(MwLLPixmap pixmap, unsigned char* rgb); +MWDECL void MWAPI MwPixmapReloadRaw(MwLLPixmap pixmap, unsigned char* rgb); /*! * @brief Gets the raw data of pixmap * @param pixmap Pixmap - * @return RFBA data + * @return RGBA data */ -MWDECL unsigned char* MwPixmapGetRaw(MwLLPixmap pixmap); +MWDECL unsigned char* MWAPI MwPixmapGetRaw(MwLLPixmap pixmap); /*! * @brief Gets the size of pixmap * @param pixmap Pixmap * @param rect Size */ -MWDECL void MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); +MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); /*! * @brief Creates a pixmap from XPM data @@ -152,7 +168,7 @@ MWDECL void MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); * @param data Data * @return Pixmap */ -MWDECL MwLLPixmap MwLoadXPM(MwWidget handle, char** data); +MWDECL MwLLPixmap MWAPI MwLoadXPM(MwWidget handle, char** data); /*! * @brief Creates a pixmap from icon data @@ -160,7 +176,7 @@ MWDECL MwLLPixmap MwLoadXPM(MwWidget handle, char** data); * @param data Data * @return Pixmap */ -MWDECL MwLLPixmap MwLoadIcon(MwWidget handle, MwU32* data); +MWDECL MwLLPixmap MWAPI MwLoadIcon(MwWidget handle, MwU32* data); /*! * @brief Draws a diamond @@ -169,7 +185,7 @@ MWDECL MwLLPixmap MwLoadIcon(MwWidget handle, MwU32* data); * @param color Color * @param invert Invert the 3D border color or not */ -MWDECL void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert); +MWDECL void MWAPI MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert); /* text.c */ @@ -182,7 +198,7 @@ MWDECL void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int in * @param align Align * @param color Color */ -MWDECL void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, int align, MwLLColor color); +MWDECL void MWAPI MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, int align, MwLLColor color); /*! * @brief Calculates a text width @@ -191,7 +207,7 @@ MWDECL void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char * @param font Font, NULLable * @return Text width */ -MWDECL int MwTextWidth(MwWidget handle, MwFLFont font, const char* text); +MWDECL int MWAPI MwTextWidth(MwWidget handle, MwFLFont font, const char* text); /*! * @brief Calculates a text height @@ -200,7 +216,7 @@ MWDECL int MwTextWidth(MwWidget handle, MwFLFont font, const char* text); * @param font Font, NULLable * @return Text height */ -MWDECL int MwTextHeight(MwWidget handle, MwFLFont font, const char* text); +MWDECL int MWAPI MwTextHeight(MwWidget handle, MwFLFont font, const char* text); /* color.c */ @@ -210,14 +226,14 @@ MWDECL int MwTextHeight(MwWidget handle, MwFLFont font, const char* text); * @param color Color name * @return Color */ -MWDECL MwLLColor MwParseColorName(MwWidget handle, const char* color); +MWDECL MwLLColor MWAPI MwParseColorName(MwWidget handle, const char* color); /*! * @brief Parses a color name * @param color Color name * @param rgb RGB */ -MWDECL void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb); +MWDECL void MWAPI MwParseColorNameNoAllocate(const char* color, MwRGB* rgb); #ifdef __cplusplus } diff --git a/include/Mw/Font.h b/include/Mw/Font.h index 6f22b89f..9902af69 100644 --- a/include/Mw/Font.h +++ b/include/Mw/Font.h @@ -18,13 +18,13 @@ extern "C" { * @param size Data size * @return Font handle */ -MWDECL void* MwFontLoad(unsigned char* data, unsigned int size); +MWDECL void* MWAPI MwFontLoad(unsigned char* data, unsigned int size); /*! * @brief Frees a font handle * @param handle Handle */ -MWDECL void MwFontFree(void* handle); +MWDECL void MWAPI MwFontFree(void* handle); #ifdef __cplusplus } diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 2ba3ff0b..6647672d 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -30,6 +30,7 @@ enum MwLLBackends { MwLLBackendGDI, MwLLBackendWayland, MwLLBackendCocoa, + MwLLBackendHaiku }; struct _MwLLCommon { @@ -66,11 +67,17 @@ typedef struct _MwLLDBusFuncTable { DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + void (*dbus_connection_flush)(DBusConnection* connection); + dbus_bool_t (*dbus_connection_read_write)(DBusConnection* connection, int timeout_milliseconds); DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + DBusMessage* (*dbus_connection_pop_message)(DBusConnection* connection); + void (*dbus_bus_add_match)(DBusConnection* connection, const char* rule, DBusError* error); void (*dbus_message_unref)(DBusMessage* message); dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_is_signal)(DBusMessage* message, const char* iface, const char* signal_name); int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_message_iter_next)(DBusMessageIter* iter); void (*dbus_connection_unref)(DBusConnection* connection); void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); } MwLLDBusFuncTable; @@ -80,7 +87,6 @@ typedef struct _MwLLDBusContext { DBusError dbus_err; DBusMessage* dbus_msg; DBusMessage* dbus_reply; - DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); @@ -112,6 +118,9 @@ MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); #ifdef CLASSIC_MAC_OS #include #endif +#ifdef USE_HAIKU +#include +#endif union _MwLL { struct _MwLLCommon common; @@ -123,6 +132,7 @@ union _MwLL { #endif #ifdef USE_WAYLAND struct _MwLLWayland wayland; + struct _MwLLCairo cairo; #endif #ifdef USE_COCOA struct _MwLLCocoa cocoa; @@ -130,6 +140,9 @@ union _MwLL { #ifdef CLASSIC_MAC_OS struct _MwLLClassicMacOS cmacos; #endif +#ifdef USE_HAIKU + struct _MwLLHaiku haiku; +#endif }; union _MwLLColor { @@ -141,11 +154,14 @@ union _MwLLColor { struct _MwLLGDIColor gdi; #endif #ifdef USE_WAYLAND - struct _MwLLWaylandColor wayland; + struct _MwLLCairoColor wayland; #endif #ifdef USE_COCOA struct _MwLLCocoaColor cocoa; #endif +#ifdef USE_HAIKU + struct _MwLLHaikuColor haiku; +#endif }; union _MwLLPixmap { @@ -158,6 +174,7 @@ union _MwLLPixmap { #endif #ifdef USE_WAYLAND struct _MwLLWaylandPixmap wayland; + struct _MwLLCairoPixmap cairo; /* same structure but we do this for code clarity */ #endif #ifdef USE_COCOA struct _MwLLCocoaPixmap cocoa; @@ -165,6 +182,9 @@ union _MwLLPixmap { #ifdef CLASSIC_MAC_OS struct _MwLLClassicMacOSPixmap cmacos; #endif +#ifdef USE_HAIKU + struct _MwLLHaikuPixmap haiku; +#endif }; #endif #include @@ -172,24 +192,6 @@ union _MwLLPixmap { #define MwLLDispatch(x, y, z) \ if(x->common.handler != NULL && x->common.handler->y != NULL) x->common.handler->y(x, z) -#define MwLLKeyMask (1 << 31) -enum MwLLKeyEnum { - MwLLKeyBackSpace = MwLLKeyMask | 1, - MwLLKeyLeft, - MwLLKeyRight, - MwLLKeyUp, - MwLLKeyDown, - MwLLKeyEnter, - MwLLKeyEscape, - MwLLKeyLeftShift, - MwLLKeyRightShift, - MwLLKeyAlt, - MwLLKeyControl -}; - -#define MwLLControlMask MwLLKeyMask | (1 << 30) -#define MwLLAltMask MwLLKeyMask | (1 << 29) - struct _MwLLHandler { void (*draw)(MwLL handle, void* data); void (*up)(MwLL handle, void* data); @@ -203,6 +205,7 @@ struct _MwLLHandler { void (*focus_out)(MwLL handle, void* data); void (*clipboard)(MwLL handle, void* data); void (*dark_theme)(MwLL handle, void* data); + void (*drag_and_drop)(MwLL handle, void* data); }; struct _MwLLTextDispatchTable { @@ -215,6 +218,7 @@ struct _MwLLTextDispatchTable { #define MwFLFlagMonospace (1 << 0) #define MwFLFlagBold (1 << 1) +#define MwFLFlagBitmap (1 << 2) #define MwFLBuildFont(x) ((MwFLFont)(void*)(size_t)(x)) #ifdef __cplusplus @@ -231,7 +235,17 @@ MWDECL void (*MwLLDestroy)(MwLL handle); MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); + +/*! + * @brief Begin drawing sequence + * @param handle Handle + */ MWDECL void (*MwLLBeginDraw)(MwLL handle); + +/*! + * @brief End drawing sequence + * @param handle Handle + */ MWDECL void (*MwLLEndDraw)(MwLL handle); MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); @@ -256,18 +270,44 @@ MWDECL void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap); MWDECL void (*MwLLForceRender)(MwLL handle); MWDECL void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask); + +/*! + * @brief Detach handle and make it toplevel window + * @param handle Handle + * @param point Point to be detached at, relative from the parent handle + */ MWDECL void (*MwLLDetach)(MwLL handle, MwPoint* point); MWDECL void (*MwLLShow)(MwLL handle, int show); MWDECL void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy); MWDECL void (*MwLLMakeBorderless)(MwLL handle, int toggle); + +/*! + * @brief Make handle "tool" window, e.g. Submenu, combobox menu, and etc. + * @param handle Handle + */ MWDECL void (*MwLLMakeToolWindow)(MwLL handle); MWDECL void (*MwLLMakePopup)(MwLL handle, MwLL parent); +/*! + * @brief Begin changing state (has to be called before `MwLLSetSizeHints`, `MwLLMakeBorderless`, `MwLLMakeToolWindow`, and `MwLLMakePopup`) + * @param handle Handle + */ MWDECL void (*MwLLBeginStateChange)(MwLL handle); + +/*! + * @brief End changing state + * @param handle Handle + */ MWDECL void (*MwLLEndStateChange)(MwLL handle); MWDECL void (*MwLLFocus)(MwLL handle); + +/*! + * @brief Grab pointer, and keep moving pointer to center of handle + * @param handle Handle + * @param toggle Toggle + */ MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type); @@ -276,24 +316,59 @@ MWDECL void (*MwLLGetClipboard)(MwLL handle, int clipboard_type); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +/*! + * @brief Setup drag and drop capabilities, should the user request it with MwNacceptsDnD + * @param handle Handle + */ +MWDECL void (*MwLLSetupDragAndDrop)(MwLL handle); + +/*! + * @brief Set any extra parameters for dark theme + * @param handle Handle + * @param toggle Toggle + * @warning Do not run `handle->common.handler->dark_theme` when this function gets called + * @warning This is for stuff like, i.e. setting the accent color on modern Windows. The user themselves sets dark theme with MwNdarkTheme. + */ MWDECL void (*MwLLSetDarkTheme)(MwLL handle, int toggle); +/*! + * @brief Whether or not the platform should default to modern theme. + * @param handle Handle + * @return whether to default. + */ +MWDECL MwBool (*MwLLDoModern)(MwLL handle); + +MWDECL void (*MwLLRaise)(MwLL handle); + +MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); + /* font renderer */ MWDECL void MwFLSetup(void); #ifdef USE_FREETYPE2 -MWDECL int MWFL_FT2Setup(void); +MWDECL int MwFL_FT2Setup(void); #endif #ifdef USE_STB_TRUETYPE MWDECL int MwFL_STBTTSetup(void); #endif +#ifdef USE_GDI_TEXT +MWDECL int MwFL_GDISetup(void); +#endif + MWDECL int (*MwFLDrawText)(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color); MWDECL int (*MwFLTextWidth)(MwFLFont ttf, const char* text); MWDECL int (*MwFLTextHeight)(MwFLFont ttf, int count); +MWDECL int (*MwFLTextHeightWithText)(MwFLFont ttf, const char* text); MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px); MWDECL void (*MwFLFontFree)(void* handle); +#ifdef _WIN32 +MWDECL void *MwLL_winmmLib; +MWDECL long (__stdcall* MwLL_PFN_timeGetTime)(void); +MWDECL unsigned int (__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); +#endif + #ifdef __cplusplus } #endif diff --git a/include/Mw/LowLevel/Cairo.h b/include/Mw/LowLevel/Cairo.h new file mode 100644 index 00000000..dd2cfa32 --- /dev/null +++ b/include/Mw/LowLevel/Cairo.h @@ -0,0 +1,229 @@ +/*! + * @file Mw/LowLevel/Cairo.h + * @brief Cairo Backend + * @warning This is used MEGA internally. + */ +#ifndef __MW_LOWLEVEL_CAIRO_H__ +#define __MW_LOWLEVEL_CAIRO_H__ + +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MWDECL int MwLLCairoCallInit(void); + +#ifdef __cplusplus +} +#endif + +#define CSD_BORDER_FRAME_LEFT 5 +#define CSD_BORDER_FRAME_RIGHT 5 +#define CSD_BORDER_FRAME_TOP 23 +#define CSD_BORDER_FRAME_BOTTOM 4 + +typedef struct cairo_call_table { + void* cairo_lib; + + void (*cairo_set_line_width)(cairo_t* cr, + double width); + void (*cairo_scale)(cairo_t* cr, + double sx, + double sy); + cairo_t* (*cairo_create)(cairo_surface_t* target); + void (*cairo_move_to)(cairo_t* cr, + double x, + double y); + + void (*cairo_rectangle)(cairo_t* cr, + double x, + double y, + double width, + double height); + void (*cairo_new_path)(cairo_t* cr); + void (*cairo_set_line_cap)(cairo_t* cr, + cairo_line_cap_t line_cap); + void (*cairo_set_source_rgba)(cairo_t* cr, + double red, + double green, + double blue, + double alpha); + void (*cairo_set_source_rgb)(cairo_t* cr, + double red, + double green, + double blue); + void (*cairo_reset_clip)(cairo_t* cr); + unsigned char* (*cairo_image_surface_get_data)(cairo_surface_t* surface); + void (*cairo_line_to)(cairo_t* cr, + double x, + double y); + cairo_status_t (*cairo_surface_write_to_png)(cairo_surface_t* surface, const char* filename); + void (*cairo_surface_destroy)(cairo_surface_t* surface); + cairo_surface_t* (*cairo_image_surface_create_for_data)(unsigned char* data, + cairo_format_t format, + int width, + int height, + int stride); + cairo_surface_t* (*cairo_image_surface_create)(cairo_format_t format, + int width, + int height); + void (*cairo_destroy)(cairo_t* cr); + cairo_pattern_t* (*cairo_get_source)(cairo_t* cr); + void (*cairo_close_path)(cairo_t* cr); + void (*cairo_paint)(cairo_t* cr); + void (*cairo_surface_flush)(cairo_surface_t* surface); + void (*cairo_clip)(cairo_t* cr); + void (*cairo_save)(cairo_t* cr); + void (*cairo_restore)(cairo_t* cr); + void (*cairo_surface_mark_dirty)(cairo_surface_t* surface); + void (*cairo_stroke)(cairo_t* cr); + void (*cairo_set_source_surface)(cairo_t* cr, + cairo_surface_t* surface, + double x, + double y); + void (*cairo_fill)(cairo_t* cr); + void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, + cairo_filter_t filter); + void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); + void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); + +} cairo_call_table_t; + +extern cairo_call_table_t cairo_call_tbl; + +/* defined inline right here so that it doesn't conflict with the other macros */ +MwInline int cairo_load_funcs() { +#ifdef __APPLE__ + cairo_call_tbl.cairo_lib = MwDynamicOpen("libcairo.dylib"); +#else + cairo_call_tbl.cairo_lib = MwDynamicOpen("libcairo.so"); +#endif + if(!cairo_call_tbl.cairo_lib) { + printf("(libcairo not found, cannot use Wayland or Cairo backend.)\n"); + return 1; + } + +#define CAIRO_FUNC(x) \ + cairo_call_tbl.x = MwDynamicSymbol(cairo_call_tbl.cairo_lib, #x); \ + if(!cairo_call_tbl.x) { \ + printf("WARNING: Could use Wayland/Cairo backend if " #x " was not found. Do you have libcairo?\n"); \ + return 1; \ + }; + + CAIRO_FUNC(cairo_set_line_width); + CAIRO_FUNC(cairo_scale); + CAIRO_FUNC(cairo_create); + CAIRO_FUNC(cairo_move_to); + CAIRO_FUNC(cairo_rectangle); + CAIRO_FUNC(cairo_new_path); + CAIRO_FUNC(cairo_set_line_cap); + CAIRO_FUNC(cairo_set_antialias); + CAIRO_FUNC(cairo_set_source_rgba); + CAIRO_FUNC(cairo_set_source_rgb); + CAIRO_FUNC(cairo_reset_clip); + CAIRO_FUNC(cairo_image_surface_get_data); + CAIRO_FUNC(cairo_line_to); + CAIRO_FUNC(cairo_surface_write_to_png); + CAIRO_FUNC(cairo_surface_destroy); + CAIRO_FUNC(cairo_image_surface_create_for_data); + CAIRO_FUNC(cairo_image_surface_create); + CAIRO_FUNC(cairo_destroy); + CAIRO_FUNC(cairo_get_source); + CAIRO_FUNC(cairo_close_path); + CAIRO_FUNC(cairo_paint); + CAIRO_FUNC(cairo_surface_flush); + CAIRO_FUNC(cairo_clip); + CAIRO_FUNC(cairo_save); + CAIRO_FUNC(cairo_restore); + CAIRO_FUNC(cairo_surface_mark_dirty); + CAIRO_FUNC(cairo_stroke); + CAIRO_FUNC(cairo_set_source_surface); + CAIRO_FUNC(cairo_fill); + CAIRO_FUNC(cairo_set_operator); + CAIRO_FUNC(cairo_pattern_set_filter); +#undef CAIRO_FUNC + + return 0; +} + +#define cairo_set_line_width cairo_call_tbl.cairo_set_line_width +#define cairo_scale cairo_call_tbl.cairo_scale +#define cairo_create cairo_call_tbl.cairo_create +#define cairo_move_to cairo_call_tbl.cairo_move_to +#define cairo_rectangle cairo_call_tbl.cairo_rectangle +#define cairo_new_path cairo_call_tbl.cairo_new_path +#define cairo_set_line_cap cairo_call_tbl.cairo_set_line_cap +#define cairo_set_antialias cairo_call_tbl.cairo_set_antialias +#define cairo_set_source_rgba cairo_call_tbl.cairo_set_source_rgba +#define cairo_set_source_rgb cairo_call_tbl.cairo_set_source_rgb +#define cairo_reset_clip cairo_call_tbl.cairo_reset_clip +#define cairo_image_surface_get_data cairo_call_tbl.cairo_image_surface_get_data +#define cairo_line_to cairo_call_tbl.cairo_line_to +#define cairo_surface_write_to_png cairo_call_tbl.cairo_surface_write_to_png +#define cairo_surface_destroy cairo_call_tbl.cairo_surface_destroy +#define cairo_image_surface_create_for_data cairo_call_tbl.cairo_image_surface_create_for_data +#define cairo_image_surface_create cairo_call_tbl.cairo_image_surface_create +#define cairo_destroy cairo_call_tbl.cairo_destroy +#define cairo_get_source cairo_call_tbl.cairo_get_source +#define cairo_close_path cairo_call_tbl.cairo_close_path +#define cairo_paint cairo_call_tbl.cairo_paint +#define cairo_surface_flush cairo_call_tbl.cairo_surface_flush +#define cairo_clip cairo_call_tbl.cairo_clip +#define cairo_save cairo_call_tbl.cairo_save +#define cairo_restore cairo_call_tbl.cairo_restore +#define cairo_surface_mark_dirty cairo_call_tbl.cairo_surface_mark_dirty +#define cairo_stroke cairo_call_tbl.cairo_stroke +#define cairo_set_source_surface cairo_call_tbl.cairo_set_source_surface +#define cairo_fill cairo_call_tbl.cairo_fill +#define cairo_set_operator cairo_call_tbl.cairo_set_operator +#define cairo_pattern_set_filter cairo_call_tbl.cairo_pattern_set_filter + +struct _MwLLCairo { + struct _MwLLCommon common; + + cairo_surface_t* front_cs; + cairo_surface_t* back_cs; + cairo_t* front_cairo; + cairo_t* back_cairo; + /* The cairo to actually use for draw operations. Typically is front_cairo, but wayland's MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ + cairo_t* selected_cairo; + + int x; + int y; + int width; + int height; + + MwBool toplevel; + MwLL parent; +}; + +struct _MwLLCairoColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLCairoPixmap { + struct _MwLLCommonPixmap common; + + cairo_surface_t* cs; +}; + +void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height); +void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height); +void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo); +void MwLLCairoBackDestroy(struct _MwLLCairo* cairo); +void MwLLCairoPolygon(struct _MwLLCairo handle, MwPoint* points, int points_count, MwLLColor color); +void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color); +MwLLPixmap MwLLCairoCreatePixmap(struct _MwLLCairo handle, unsigned char* data, int width, int height); +void MwLLCairoPixmapUpdate(MwLLPixmap handle); +void MwLLCairoDestroyPixmap(MwLLPixmap pixmap); +void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixmap); + +void MwLLCairoDestroy(struct _MwLLCairo handle); + +#endif diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h index 958b5e8b..9d76e202 100644 --- a/include/Mw/LowLevel/ClassicMacOS.h +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -10,6 +10,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct _MwLLClassicMacOS { struct _MwLLCommon common; @@ -32,4 +36,8 @@ struct _MwLLClassicMacOSPixmap { MWDECL int MwLLClassicMacOSCallInit(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 6c5f12b4..1f18006f 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -84,7 +84,7 @@ typedef struct { @end @interface MilskoCocoaPixmap : NSObject { - @public + @public MwBool valid; int width; int height; @@ -106,7 +106,7 @@ typedef struct { @interface MilskoCocoaView : NSView { MwBool _child; - @public + @public draw_command* commands; } @@ -119,10 +119,11 @@ typedef struct { @end @interface MilskoCocoa : NSObject { - @public + @public MilskoCocoaApplication* application; MwBool _forceRender; MwBool _eventsPending; + MwBool isClosing; NSWindow* window; NSRect rect; MilskoCocoaView* view; @@ -159,7 +160,9 @@ typedef struct { #define OBJC(x) void* #endif -MWDECL int MwLLCocoaCallInit(void); +#ifdef __cplusplus +extern "C" { +#endif struct _MwLLCocoa { struct _MwLLCommon common; @@ -177,4 +180,10 @@ struct _MwLLCocoaPixmap { real; }; +MWDECL int MwLLCocoaCallInit(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/Mw/LowLevel/GDI.h b/include/Mw/LowLevel/GDI.h index c695cbd1..d2e24735 100644 --- a/include/Mw/LowLevel/GDI.h +++ b/include/Mw/LowLevel/GDI.h @@ -10,6 +10,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct _MwLLGDI { struct _MwLLCommon common; @@ -19,6 +23,8 @@ struct _MwLLGDI { HCURSOR cursor; HICON icon; + HRGN clip; + int grabbed; int force_render; int get_clipboard; @@ -43,4 +49,8 @@ struct _MwLLGDIPixmap { MWDECL int MwLLGDICallInit(void); MWDECL HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/Mw/LowLevel/Haiku.h b/include/Mw/LowLevel/Haiku.h new file mode 100644 index 00000000..32c1c027 --- /dev/null +++ b/include/Mw/LowLevel/Haiku.h @@ -0,0 +1,173 @@ +/*! + * @file Mw/LowLevel/Haiku.h + * @brief Haiku Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_HAIKU_H__ +#define __MW_LOWLEVEL_HAIKU_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +class MwApplication; +class MwView; +class MwWindow; + +class MwApplication : public BApplication { + public: + MwApplication(MwRect rc, MwLL handle); + ~MwApplication(); + + void MessageReceived(BMessage* message); +}; + +class MwView : public BView { + public: + MwLL handle; + BLocker* locker; + uint32 buttons; + BBitmap* bitmap; + + MwView(MwLL handle, BRect rc, uint32 resizingMode, uint32 flags); + ~MwView(); + + void MessageReceived(BMessage* message); + void PostMessage(BMessage* message); + void PostMessage(uint32 command); + status_t SendMessage(BMessage* message); + status_t SendMessage(uint32 command); + void Invalidate(); + + void AttachedToWindow(); + void Draw(BRect updateRect); + void FrameResized(float width, float height); + void MouseDown(BPoint point); + void MouseUp(BPoint point); + void MouseMoved(BPoint point, uint32 transit, const BMessage* message); + + void SetColor(MwLLColor color); +}; + +class MwWindow : public BWindow { + public: + MwWindow(BRect rc, window_type type, uint32 flags); + + void MessageReceived(BMessage* message); + + void FrameMoved(BPoint newLocation); + bool QuitRequested(); +}; + +typedef BBitmap MwBBitmap; +#else +typedef void MwApplication; +typedef void MwView; +typedef void MwWindow; +typedef void MwBBitmap; +#endif + +typedef union _MwLLHaikuEvent MwLLHaikuEvent; + +enum BAPP_MW_WHAT { + BAPP_MW_DESTROY = 0 +}; + +enum BVIEW_MW_WHAT { + BVIEW_MW_DESTROY = 0, + BVIEW_MW_DETACH, + BVIEW_MW_RESIZE, + BVIEW_MW_MOVE, + BVIEW_MW_SHOW, + BVIEW_MW_HIDE, + BVIEW_MW_SET_COLOR, + BVIEW_MW_POLYGON, + BVIEW_MW_LINE, + BVIEW_MW_BITMAP, + BVIEW_MW_RENDER, + BVIEW_MW_RAISE, + BVIEW_MW_GET_MOUSE +}; + +enum BWIN_MW_WHAT { + BWIN_MW_DESTROY = 0, + BWIN_MW_SET_TITLE, + BWIN_MW_SET_TYPE +}; + +enum MwLLHAIKU_EVENT { + MwLLHAIKU_EVENT_DRAW = 0, + MwLLHAIKU_EVENT_CLOSE, + MwLLHAIKU_EVENT_FRAMERESIZED, + MwLLHAIKU_EVENT_FRAMEMOVED, + MwLLHAIKU_EVENT_MOUSEDOWN, + MwLLHAIKU_EVENT_MOUSEUP, + MwLLHAIKU_EVENT_MOUSEMOVED +}; + +struct _MwLLHaikuEventMouse { + int type; + MwPoint point; + int button; +}; + +struct _MwLLHaikuEventFrameResized { + int type; + float width; + float height; +}; + +struct _MwLLHaikuEventFrameMoved { + int type; + MwPoint point; +}; + +union _MwLLHaikuEvent { + int type; + struct _MwLLHaikuEventMouse mouse; + struct _MwLLHaikuEventFrameResized frame_resized; + struct _MwLLHaikuEventFrameMoved frame_moved; +}; + +struct _MwLLHaiku { + struct _MwLLCommon common; + + int type; + + int x; + int y; + int width; + int height; + + MwLL parent; + MwApplication* app; + MwWindow* window; + MwView* view; + thread_id app_thread; + int force_render; + + MwLLHaikuEvent* events; +}; + +struct _MwLLHaikuColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLHaikuPixmap { + struct _MwLLCommonPixmap common; + + MwBBitmap* bitmap; +}; + +MWDECL int MwLLHaikuCallInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7f9e7625..ccd1f2f0 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -11,17 +11,25 @@ #include #include +#include + #include -#include #include -#include + +#ifdef __cplusplus +extern "C" { +#endif MWDECL int MwLLWaylandCallInit(void); +#ifdef __cplusplus +} +#endif + #define CSD_BORDER_FRAME_LEFT 5 #define CSD_BORDER_FRAME_RIGHT 5 -#define CSD_BORDER_FRAME_TOP 24 -#define CSD_BORDER_FRAME_BOTTOM 5 +#define CSD_BORDER_FRAME_TOP 23 +#define CSD_BORDER_FRAME_BOTTOM 4 struct _MwLLWayland; @@ -35,7 +43,6 @@ struct _MwLLWayland; typedef struct wayland_call_table { void* lib; void* xkb_lib; - void* cairo_lib; #ifdef USE_DBUS MwLLDBusFuncTable dbus; MwBool has_dbus; @@ -60,6 +67,7 @@ typedef struct wayland_call_table { struct wl_display* (*wl_display_connect)(const char* name); uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); struct wl_display* (*wl_display_connect_to_fd)(int fd); + int (*wl_display_get_error)(struct wl_display* display); struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); void (*xkb_context_unref)(struct xkb_context* context); @@ -71,86 +79,38 @@ typedef struct wayland_call_table { xkb_layout_index_t (*xkb_state_key_get_layout)(struct xkb_state* state, xkb_keycode_t key); void (*xkb_keymap_unref)(struct xkb_keymap* keymap); - void (*cairo_set_line_width)(cairo_t* cr, - double width); - void (*cairo_scale)(cairo_t* cr, - double sx, - double sy); - cairo_t* (*cairo_create)(cairo_surface_t* target); - void (*cairo_move_to)(cairo_t* cr, - double x, - double y); - - void (*cairo_rectangle)(cairo_t* cr, - double x, - double y, - double width, - double height); - void (*cairo_new_path)(cairo_t* cr); - void (*cairo_set_line_cap)(cairo_t* cr, - cairo_line_cap_t line_cap); - void (*cairo_set_source_rgba)(cairo_t* cr, - double red, - double green, - double blue, - double alpha); - void (*cairo_set_source_rgb)(cairo_t* cr, - double red, - double green, - double blue); - void (*cairo_reset_clip)(cairo_t* cr); - unsigned char* (*cairo_image_surface_get_data)(cairo_surface_t* surface); - void (*cairo_line_to)(cairo_t* cr, - double x, - double y); - void (*cairo_surface_destroy)(cairo_surface_t* surface); - cairo_surface_t* (*cairo_image_surface_create_for_data)(unsigned char* data, - cairo_format_t format, - int width, - int height, - int stride); - cairo_surface_t* (*cairo_image_surface_create)(cairo_format_t format, - int width, - int height); - void (*cairo_destroy)(cairo_t* cr); - cairo_pattern_t* (*cairo_get_source)(cairo_t* cr); - void (*cairo_close_path)(cairo_t* cr); - void (*cairo_paint)(cairo_t* cr); - void (*cairo_surface_flush)(cairo_surface_t* surface); - void (*cairo_clip)(cairo_t* cr); - void (*cairo_surface_mark_dirty)(cairo_surface_t* surface); - void (*cairo_stroke)(cairo_t* cr); - void (*cairo_set_source_surface)(cairo_t* cr, - cairo_surface_t* surface, - double x, - double y); - void (*cairo_fill)(cairo_t* cr); - void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, - cairo_filter_t filter); - void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); - void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); - } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; -extern MwBool MwWaylandAlwaysRender; +#ifdef MW_VULKAN +extern MwBool MwWaylandVulkan; +#else +#define MwWaylandVulkan 0 +#endif + +MWDECL MwBool MwWaylandCairoOnly; + /* defined inline right here so that it doesn't conflict with the other macros */ MwInline int wayland_load_funcs() { +#ifdef __APPLE__ + wl_call_tbl.lib = MwDynamicOpen("libwayland-client.dylib"); +#else wl_call_tbl.lib = MwDynamicOpen("libwayland-client.so"); +#endif if(!wl_call_tbl.lib) { - printf("(libwayland-client.so not found, falling back to X11)\n"); + printf("(libwayland-client not found, falling back to X11)\n"); return 1; } +#ifdef __APPLE__ + wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.dylib"); +#else wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.so"); +#endif if(!wl_call_tbl.xkb_lib) { - printf("(libxkbcommon.so not found, cannot use Wayland backend.)\n"); - return 1; - } - wl_call_tbl.cairo_lib = MwDynamicOpen("libcairo.so"); - if(!wl_call_tbl.cairo_lib) { - printf("(libcairo.so not found, cannot use Wayland backend.)\n"); + printf("(libxkbcommon not found, cannot use Wayland backend.)\n"); return 1; } + #define WAYLAND_FUNC(x) \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \ if(!wl_call_tbl.x) { \ @@ -174,6 +134,7 @@ MwInline int wayland_load_funcs() { WAYLAND_FUNC(wl_display_connect) WAYLAND_FUNC(wl_proxy_get_version) WAYLAND_FUNC(wl_display_connect_to_fd) + WAYLAND_FUNC(wl_display_get_error) #undef WAYLAND_FUNC @@ -195,42 +156,9 @@ MwInline int wayland_load_funcs() { XKB_FUNC(xkb_state_key_get_layout) #undef XKB_FUNC -#define CAIRO_FUNC(x) \ - wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.cairo_lib, #x); \ - if(!wl_call_tbl.x) { \ - printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libcairo?\n"); \ - return 1; \ - }; - - CAIRO_FUNC(cairo_set_line_width); - CAIRO_FUNC(cairo_scale); - CAIRO_FUNC(cairo_create); - CAIRO_FUNC(cairo_move_to); - CAIRO_FUNC(cairo_rectangle); - CAIRO_FUNC(cairo_new_path); - CAIRO_FUNC(cairo_set_line_cap); - CAIRO_FUNC(cairo_set_antialias); - CAIRO_FUNC(cairo_set_source_rgba); - CAIRO_FUNC(cairo_set_source_rgb); - CAIRO_FUNC(cairo_reset_clip); - CAIRO_FUNC(cairo_image_surface_get_data); - CAIRO_FUNC(cairo_line_to); - CAIRO_FUNC(cairo_surface_destroy); - CAIRO_FUNC(cairo_image_surface_create_for_data); - CAIRO_FUNC(cairo_image_surface_create); - CAIRO_FUNC(cairo_destroy); - CAIRO_FUNC(cairo_get_source); - CAIRO_FUNC(cairo_close_path); - CAIRO_FUNC(cairo_paint); - CAIRO_FUNC(cairo_surface_flush); - CAIRO_FUNC(cairo_clip); - CAIRO_FUNC(cairo_surface_mark_dirty); - CAIRO_FUNC(cairo_stroke); - CAIRO_FUNC(cairo_set_source_surface); - CAIRO_FUNC(cairo_fill); - CAIRO_FUNC(cairo_set_operator); - CAIRO_FUNC(cairo_pattern_set_filter); -#undef CAIRO_FUNC + if(cairo_load_funcs() != 0) { + return 1; + } #ifdef USE_DBUS wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); @@ -255,6 +183,7 @@ MwInline int wayland_load_funcs() { #define wl_display_connect wl_call_tbl.wl_display_connect #define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version #define wl_display_connect_to_fd wl_call_tbl.wl_display_connect_to_fd +#define wl_display_get_error wl_call_tbl.wl_display_get_error #define xkb_state_unref wl_call_tbl.xkb_state_unref #define xkb_context_new wl_call_tbl.xkb_context_new @@ -266,35 +195,6 @@ MwInline int wayland_load_funcs() { #define xkb_keymap_key_get_syms_by_level wl_call_tbl.xkb_keymap_key_get_syms_by_level #define xkb_state_key_get_layout wl_call_tbl.xkb_state_key_get_layout -#define cairo_set_line_width wl_call_tbl.cairo_set_line_width -#define cairo_scale wl_call_tbl.cairo_scale -#define cairo_create wl_call_tbl.cairo_create -#define cairo_move_to wl_call_tbl.cairo_move_to -#define cairo_rectangle wl_call_tbl.cairo_rectangle -#define cairo_new_path wl_call_tbl.cairo_new_path -#define cairo_set_line_cap wl_call_tbl.cairo_set_line_cap -#define cairo_set_antialias wl_call_tbl.cairo_set_antialias -#define cairo_set_source_rgba wl_call_tbl.cairo_set_source_rgba -#define cairo_set_source_rgb wl_call_tbl.cairo_set_source_rgb -#define cairo_reset_clip wl_call_tbl.cairo_reset_clip -#define cairo_image_surface_get_data wl_call_tbl.cairo_image_surface_get_data -#define cairo_line_to wl_call_tbl.cairo_line_to -#define cairo_surface_destroy wl_call_tbl.cairo_surface_destroy -#define cairo_image_surface_create_for_data wl_call_tbl.cairo_image_surface_create_for_data -#define cairo_image_surface_create wl_call_tbl.cairo_image_surface_create -#define cairo_destroy wl_call_tbl.cairo_destroy -#define cairo_get_source wl_call_tbl.cairo_get_source -#define cairo_close_path wl_call_tbl.cairo_close_path -#define cairo_paint wl_call_tbl.cairo_paint -#define cairo_surface_flush wl_call_tbl.cairo_surface_flush -#define cairo_clip wl_call_tbl.cairo_clip -#define cairo_surface_mark_dirty wl_call_tbl.cairo_surface_mark_dirty -#define cairo_stroke wl_call_tbl.cairo_stroke -#define cairo_set_source_surface wl_call_tbl.cairo_set_source_surface -#define cairo_fill wl_call_tbl.cairo_fill -#define cairo_set_operator wl_call_tbl.cairo_set_operator -#define cairo_pattern_set_filter wl_call_tbl.cairo_pattern_set_filter - #ifndef WL_PROTOCOLS_DEFINED #define WL_PROTOCOLS_DEFINED #include "Wayland/wayland-core-protocol.h" @@ -306,6 +206,7 @@ MwInline int wayland_load_funcs() { #include "Wayland/pointer-constraints-client-protocol.h" #include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" +#include "Wayland/wlr-layer-shell-client-protocol.h" #endif typedef struct wayland_protocol { @@ -313,7 +214,7 @@ typedef struct wayland_protocol { void* context; } wayland_protocol_t; -typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*); +typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*, MwU32 version); typedef void(wl_destroy_func)(struct _MwLLWayland* wayland, wayland_protocol_t* data); typedef struct wayland_protocol_callback_table { @@ -326,6 +227,7 @@ struct _MwLLWaylandTopLevel { struct xdg_toplevel* xdg_top_level; struct xdg_toplevel_listener xdg_toplevel_listener; struct xdg_surface_listener xdg_surface_listener; + MwBool maxim_state; MwBool compositor_created; MwBool xdg_wm_base_created; @@ -353,6 +255,10 @@ struct _MwLLWaylandPopup { MwLL topmost_parent; }; +struct _MwLLWaylandLayerSurface { + struct zwlr_layer_surface_v1* surface; +}; + /* Shared set of anything needed for a shm buffer. */ struct _MwLLWaylandShmBuffer { struct wl_shm* shm; @@ -372,10 +278,11 @@ struct _MwLLWaylandShmBuffer { }; enum _MwLLWaylandType { - MWLL_WAYLAND_UNKNOWN = 0, - MWLL_WAYLAND_TOPLEVEL, - MWLL_WAYLAND_SUBLEVEL, - MWLL_WAYLAND_POPUP, + MwLL_WAYLAND_UNKNOWN = 0, + MwLL_WAYLAND_TOPLEVEL, + MwLL_WAYLAND_SUBLEVEL, + MwLL_WAYLAND_POPUP, + MwLL_WAYLAND_LAYER_SURFACE, }; typedef struct wl_clipboard_device_context { @@ -388,13 +295,13 @@ typedef struct wl_clipboard_device_context { struct zwp_primary_selection_offer_v1* zwp; } offer; - MwLL ll; - struct wl_seat* seat; - MwU32 capabilities; + MwLL ll; + // struct wl_seat* seat; } wl_clipboard_device_context_t; struct _MwLLWayland { struct _MwLLCommon common; + struct _MwLLCairo cairo; union { /* Pointer for data that's only loaded if the widget is a toplevel */ @@ -403,30 +310,42 @@ struct _MwLLWayland { struct _MwLLWaylandSublevel* sublevel; /* Pointer for data that's only loaded if the widget is a popup */ struct _MwLLWaylandPopup* popup; + /* Pointer for data that's only loaded if the widget is a layer surface */ + struct _MwLLWaylandLayerSurface* layer_surface; }; enum _MwLLWaylandType type; enum _MwLLWaylandType type_to_be; + MwRect clipping_rect; + MwBool no; + + MwBool changing; MwBool detatching; MwPoint detach_point; MwBool did_initial_resize; + MwBool is_toplevel; + + MwBool is_clipping; + MwRect clip; + /* Map of Wayland interfaces to their relevant setup functions. */ struct { - char key[255]; + char* key; wayland_protocol_callback_table_t* value; }* wl_protocol_setup_map; /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ struct { - char key[255]; + char* key; wayland_protocol_t* value; }* wl_protocol_map; + MwBool do_csd; MwBool has_decorations; - char title[255]; + char title[256]; struct xkb_context* xkb_context; struct xkb_keymap* xkb_keymap; @@ -448,12 +367,14 @@ struct _MwLLWayland { struct zwp_relative_pointer_v1* relative_pointer; struct zwp_locked_pointer_v1* locked_pointer; MwBool pointer_constrained; + MwBool valid; #ifdef USE_DBUS MwLLDBusContext dbus; #endif MwBool dark_theme_detection; + MwU32 dark_theme; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ @@ -468,6 +389,7 @@ struct _MwLLWayland { } clipboard_source; char* clipboard_buffer; MwBool supports_zwp; + MwBool zwp_setup; uint32_t clipboard_serial; wl_clipboard_device_context_t** clipboard_devices_wl; @@ -492,6 +414,11 @@ struct _MwLLWayland { MwI32 ox, oy; MwU32 ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ + MwLL currentlyHeldWidget; + MwLL focusedWidget; + + int resizing; + int setting_wh; MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ @@ -502,37 +429,89 @@ struct _MwLLWayland { MwBool dispatching_resize; + MwBool is_toplevel_menu; + struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; - /* - Events mutex. Any time a keyboard/mouse event happens, we try to lock this for 100 milliseconds, then give up if we can't do it. This is used in conjunction with some code in the MwLLDestroyImpl to make sure that destroy is NEVER interferes with an ongoing event. + MwLLPixmap icon_pixmap; - IOI_XD: This sounds like a hilariously rare edge case, so it's almost funnier that this happened with 100% certainty for me and I spent day(s) trying to figure out what was happening. */ pthread_mutex_t eventsMutex; + int cancelEvent; + int numCallbacksRunning; + uint32_t last_time; MwBool moving; - cairo_surface_t* front_cs; - cairo_surface_t* back_cs; - cairo_t* front_cairo; - cairo_t* back_cairo; - /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ - cairo_t* selected_cairo; + MwI64 keyboard_rate; + MwI32 keyboard_delay; + int last_pressed_key; + MwBool holding_key; + MwU64 next_elapsed; + long start_time; + long end_time; }; struct _MwLLWaylandColor { struct _MwLLCommonColor common; }; -struct _MwLLWaylandPixmap { - struct _MwLLCommonPixmap common; +#define _MwLLWaylandPixmap _MwLLCairoPixmap - cairo_surface_t* cs; -}; +/* Setup the framebuffer with the saved width/height */ +void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland); +/* Destroy the framebuffer */ +void MwLLWaylandFramebufferDestroy(struct _MwLLWayland* handle); + +/* Setup the framebuffer with the saved width/height */ +void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland); +/* Destroy the backbuffer */ +void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* handle); + +void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height); +void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer); +void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); + +void MwLLWaylandRegionSetup(MwLL handle); +void MwLLWaylandRegionInvalidate(MwLL handle); + +void MwLLWaylandHangUntilConfigured(MwLL handle); + +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); +void MwLLWaylandWidgetUndestroy(MwLL self); + +/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ +void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); + +void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_type); + +/* Flush Wayland events */ +void MwLLWaylandFlush(MwLL handle); + +/* Standard procedure before event callbacks in Wayland */ +#define WAYLAND_EVENT_OP_START(self) \ + if(MwLLWaylandWidgetIsDestroyed(self)) { \ + return; \ + } + +/* Footer for WAYLAND_EVENT_OP_START */ +#define WAYLAND_EVENT_OP_END(self) + +#define WIDGET_CHECK(handle) \ + if(!handle->wayland.valid) { \ + return; \ + } + +/* the two decoration manager constructs */ +typedef struct zxdg_decoration_manager_v1_context { + struct zxdg_decoration_manager_v1* manager; + struct zxdg_toplevel_decoration_v1* decoration; +} zxdg_decoration_manager_v1_context_t; + +extern struct zwp_relative_pointer_v1_listener MwLLWaylandRelativePointerListener; #endif diff --git a/include/Mw/LowLevel/X11.h b/include/Mw/LowLevel/X11.h index 3d0e1252..e1b74169 100644 --- a/include/Mw/LowLevel/X11.h +++ b/include/Mw/LowLevel/X11.h @@ -17,6 +17,10 @@ #include #endif +#ifdef __cplusplus +extern "C" { +#endif + struct _MwLLX11 { struct _MwLLCommon common; @@ -39,7 +43,7 @@ struct _MwLLX11 { XIC xic; long clipboard_time; - int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUNd_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ + int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUND_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ int top; int toplevel; @@ -86,4 +90,8 @@ struct _MwLLX11Pixmap { MWDECL int MwLLX11CallInit(void); MWDECL Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 10a1a04b..4c98b24d 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -17,11 +16,16 @@ #include #include #include +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199409L +#include +#define MW_HAS_WCHAR +#endif #ifdef _WIN32 #include #ifdef _MILSKO #include +#include #ifndef GWLP_USERDATA #define GWLP_USERDATA GWL_USERDATA #define GWLP_WNDPROC GWL_WNDPROC @@ -54,11 +58,24 @@ #include #endif -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) #include #include #endif +#ifdef __HAIKU__ +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#endif + #ifdef __APPLE__ #include #include @@ -73,7 +90,7 @@ #endif /* Windows */ -#if defined(_MILSKO) && defined(_WIN32) +#if defined(_MILSKO) && defined(_MILSKO_BUILD) && defined(_WIN32) #define MWDECL extern __declspec(dllexport) #elif defined(_WIN32) #define MWDECL extern __declspec(dllimport) @@ -95,6 +112,12 @@ #define MWDECL extern #endif +#if defined(_WIN32) +#define MWAPI __cdecl +#else +#define MWAPI +#endif + #define MwInline static __inline #endif diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index 07a560b0..9860990c 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -17,10 +17,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -31,24 +33,28 @@ #include #include -#include -#include -#include +#include #include -#include +#include #include +#include +#include #include #include -#include -#include -#include -#include +#include #include +#include +#include #include #include +#include #include -#include +#include +#include +#include +#include #include -#include +#include +#include #endif diff --git a/include/Mw/String.h b/include/Mw/String.h index 2a744d9e..5333d019 100644 --- a/include/Mw/String.h +++ b/include/Mw/String.h @@ -17,7 +17,7 @@ extern "C" { * @param str String * @return String */ -MWDECL char* MwStringDuplicate(const char* str); +MWDECL char* MWAPI MwStringDuplicate(const char* str); /*! * @brief Concatenates 2 strings @@ -25,21 +25,21 @@ MWDECL char* MwStringDuplicate(const char* str); * @param str2 String * @return String */ -MWDECL char* MwStringConcat(const char* str1, const char* str2); +MWDECL char* MWAPI MwStringConcat(const char* str1, const char* str2); /*! * @brief Converts size to string * @param out Output * @param size Size */ -MWDECL void MwStringSize(char* out, MwOffset size); +MWDECL void MWAPI MwStringSize(char* out, MwOffset size); /*! * @brief Converts time to string * @param out Output * @param t Time */ -MWDECL void MwStringTime(char* out, time_t t); +MWDECL void MWAPI MwStringTime(char* out, time_t t); /*! * @brief Prints up to n characters into a bufferMwStringPrintIntoBuffer. @@ -47,14 +47,14 @@ MWDECL void MwStringTime(char* out, time_t t); * @param out Buffer * @param size Max size */ -MWDECL void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...); +MWDECL void MWAPI MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...); /*! * @brief Check if the given key is UTF8 * @param key Input * @return whether its utf8 */ -MWDECL MwBool MwStringIsKeyUTF8(MwU32 key); +MWDECL MwBool MWAPI MwStringIsKeyUTF8(MwU32 key); #ifdef __cplusplus } diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index c657a637..6ad4e464 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -39,17 +39,34 @@ #define MwNsevenSegment "IsevenSegment" #define MwNlength "Ilength" #define MwNforceInverted "IforceInverted" -#define MwNroundness "Iroundness" #define MwNisRounded "IisRounded" #define MwNdarkTheme "IdarkTheme" #define MwNuseMonospace "IuseMonospace" +#define MwNdarkThemeAutomatic "IdarkThemeAutomatic" +#define MwNyear "Iyear" +#define MwNmonth "Imonth" +#define MwNdate "Idate" +#define MwNday "Iday" +#define MwNwaitLayout "IwaitLayout" +#define MwNscale "Iscale" +#define MwNcolumns "Icolumns" +#define MwNcolumnSpan "IcolumnSpan" +#define MwNrowSpan "IrowSpan" +#define MwNdisabled "Idisabled" +#define MwNacceptsDnD "IacceptsDnD" #define MwNtitle "Stitle" #define MwNtext "Stext" #define MwNbackground "Sbackground" #define MwNsubBackground "SsubBackground" +#define MwNtitleBackground "StitleBackground" #define MwNforeground "Sforeground" #define MwNsubForeground "SsubForeground" +#define MwNtitleForeground "StitleForeground" + +#define MwNvulkanExtension "SEvulkanExtension" +#define MwNvulkanLayer "SEvulkanLayer" +#define MwNvulkanConfig "VEvulkanConfig" #define MwNpixmap "Vpixmap" #define MwNiconPixmap "ViconPixmap" @@ -60,27 +77,28 @@ #define MwNmonospaceFont "VmonospaceFont" #define MwNboldMonospaceFont "VboldMonospaceFont" -#define MwNactivateHandler "Cactivate" /* NULL */ -#define MwNlistBoxActivateHandler "ClistBoxActivate" /* int* */ -#define MwNtreeViewActivateHandler "CtreeViewActivate" /* void* */ -#define MwNresizeHandler "Cresize" /* NULL */ -#define MwNtickHandler "Ctick" /* NULL */ -#define MwNmenuHandler "Cmenu" /* MwMenu */ -#define MwNmouseDownHandler "CmouseDown" /* MwMouse* */ -#define MwNmouseUpHandler "CmouseUp" /* same as MwNmouseDownHandler */ -#define MwNmouseMoveHandler "CmouseMove" /* MwPoint* */ -#define MwNchangedHandler "Cchanged" /* NULL */ -#define MwNcomboBoxChangedHandler "CcomboBoxChanged" /* int* */ -#define MwNkeyHandler "Ckey" /* int* (MwLLKeyEnum or character code) */ -#define MwNkeyReleaseHandler "CkeyRelease" /* same as MwNkeyHandler */ -#define MwNcloseHandler "Cclose" /* NULL */ -#define MwNfocusInHandler "CfocusIn" /* NULL */ -#define MwNfocusOutHandler "CfocusOut" /* NULL */ -#define MwNfileChosenHandler "CfileChosen" /* char* */ -#define MwNdirectoryChosenHandler "CdirectoryChosen" /* char* */ -#define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */ -#define MwNdrawHandler "Cdraw" /* NULL */ -#define MwNclipboardHandler "Cclipboard" /* char* */ -#define MwNdarkThemeHandler "CdarkTheme" /* int* */ +#define MwNactivateHandler "Cactivate" +#define MwNlistBoxActivateHandler "ClistBoxActivate" +#define MwNtreeViewActivateHandler "CtreeViewActivate" +#define MwNresizeHandler "Cresize" +#define MwNtickHandler "Ctick" +#define MwNmenuHandler "Cmenu" +#define MwNmouseDownHandler "CmouseDown" +#define MwNmouseUpHandler "CmouseUp" +#define MwNmouseMoveHandler "CmouseMove" +#define MwNchangedHandler "Cchanged" +#define MwNcomboBoxChangedHandler "CcomboBoxChanged" +#define MwNkeyHandler "Ckey" +#define MwNkeyReleaseHandler "CkeyRelease" +#define MwNcloseHandler "Cclose" +#define MwNfocusInHandler "CfocusIn" +#define MwNfocusOutHandler "CfocusOut" +#define MwNfileChosenHandler "CfileChosen" +#define MwNdirectoryChosenHandler "CdirectoryChosen" +#define MwNcolorChosenHandler "CcolorChosen" +#define MwNdrawHandler "Cdraw" +#define MwNclipboardHandler "Cclipboard" +#define MwNdarkThemeHandler "CdarkTheme" +#define MwNdragAndDropHandler "CdragAndDrop" #endif diff --git a/include/Mw/TrueType.h b/include/Mw/TrueType.h new file mode 100644 index 00000000..eea90c95 --- /dev/null +++ b/include/Mw/TrueType.h @@ -0,0 +1,33 @@ +/*! + * @file Mw/TrueType.h + * @brief TrueType utilities + */ +#ifndef __MW_TRUETYPE_H__ +#define __MW_TRUETYPE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Get the TrueType font information + * @param data Font data + * @param size Font size + * @return Information + */ +MWDECL MwTTFInfo MwTTFGetInfo(unsigned char* data, int size); + +/*! + * @brief Free the TrueType font information + * @param info Information + */ +MWDECL void MwTTFFreeInfo(MwTTFInfo info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index ca8e32b0..ad072a34 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -26,9 +26,12 @@ typedef struct _MwLabelSegment MwLabelSegment; typedef struct _MwListBoxEntry MwListBoxEntry; typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; -typedef struct _MwListBoxPacket MwListBoxPacket; typedef struct _MwBox* MwBox; +typedef struct _MwSubWindow* MwSubWindow; +typedef struct _MwTab* MwTab; +typedef struct _MwTable* MwTable; typedef struct _MwMouse MwMouse; +typedef struct _MwTTFInfo* MwTTFInfo; #ifdef _MILSKO typedef struct _MwWidget* MwWidget; #else @@ -36,15 +39,17 @@ typedef void* MwWidget; #endif typedef void (*MwHandler)(MwWidget handle); typedef int (*MwHandlerWithStatus)(MwWidget handle); +typedef void (*MwHandlerProps)(MwWidget handle, char** key); typedef void (*MwHandlerProp)(MwWidget handle, const char* key); +typedef void (*MwHandlerChildrenUpdate)(MwWidget handle, MwWidget child, int new_child); typedef void (*MwHandlerChildrenProp)(MwWidget handle, MwWidget child, const char* key); typedef void (*MwHandlerKey)(MwWidget handle, int key); typedef void (*MwHandlerMouse)(MwWidget handle, void* ptr); typedef void (*MwHandlerExecute)(MwWidget handle, const char* name, void* out, va_list args); typedef void (*MwHandlerClipboardReceived)(MwWidget handle, const char* data); -typedef void (*MwUserHandler)(MwWidget handle, void* user_data, void* call_data); -typedef void (*MwErrorHandler)(int code, const char* message, void* user_data); +typedef void(MWAPI* MwUserHandler)(MwWidget handle, void* user_data, void* call_data); +typedef void(MWAPI* MwErrorHandler)(int code, const char* message, void* user_data); struct _MwTextKeyValue { char* key; @@ -86,12 +91,13 @@ struct _MwWidget { int pressed; MwPoint mouse_point; int close; - jmp_buf before_step; int prop_event; void* internal; void* opaque; + void* user; void (*draw_inject)(MwWidget handle); + void (*destroy_inject)(MwWidget handle); MwIntegerKeyValue* integer; MwTextKeyValue* text; @@ -110,8 +116,13 @@ struct _MwWidget { int top_step; MwWidget* draw_queue; + MwWidget* resize_queue; + MwWidget* monitored_entries; - int berserk; + int berserk; + long last_tick; + + MwBool is_menu; }; #endif @@ -121,12 +132,15 @@ struct _MwMenu { MwWidget wsub; MwMenu* sub; void* opaque; + int cleaned; }; struct _MwEntry { int cursor; int right; int length; + int active; + int cursor_blink_timer; MwPoint mouse; }; @@ -188,6 +202,7 @@ struct _MwScrollBar { struct _MwLabel { MwLabelSegment* segment; + MwHandler draw; }; struct _MwLabelSegment { @@ -202,20 +217,45 @@ struct _MwDirectoryEntry { time_t mtime; }; -struct _MwListBoxPacket { - MwLLPixmap* pixmaps; - char*** names; -}; - struct _MwBox { int layout; }; +struct _MwTable { + int layout; + MwWidget* widgets; +}; + +struct _MwSubWindow { + MwWidget frame; + MwWidget minimize; + MwWidget maximize; + MwWidget close; + int maximized; + int minimized; + int x; + int y; + int width; + int height; + MwPoint cursor_start; + MwPoint base; +}; + +struct _MwTab { + MwWidget* frames; + char** names; +}; + struct _MwMouse { MwPoint point; int button; }; +struct _MwTTFInfo { + char* family; + int weight; +}; + struct _MwClass { MwHandlerWithStatus create; MwHandler destroy; @@ -230,13 +270,13 @@ struct _MwClass { MwHandlerExecute execute; MwHandler tick; MwHandler resize; - MwHandler children_update; + MwHandlerChildrenUpdate children_update; MwHandlerChildrenProp children_prop_change; MwHandlerClipboardReceived clipboard; - void* reserved1; + MwHandlerProps props_change; + MwHandler drag_and_drop; void* reserved2; void* reserved3; - void* reserved4; }; #endif diff --git a/include/Mw/Unicode.h b/include/Mw/Unicode.h index 2aa6d19e..32edeaab 100644 --- a/include/Mw/Unicode.h +++ b/include/Mw/Unicode.h @@ -18,14 +18,14 @@ extern "C" { * @brief output Output * @return Bytes this multibyte takes */ -MWDECL int MwUTF8ToUTF32(const char* input, int* output); +MWDECL int MWAPI MwUTF8ToUTF32(const char* input, int* output); /*! * @brief Calculates UTF-8 string length * @brief input Input * @return Length */ -MWDECL int MwUTF8Length(const char* input); +MWDECL int MWAPI MwUTF8Length(const char* input); /*! * @brief Copies UTF-8 string to other string @@ -36,7 +36,7 @@ MWDECL int MwUTF8Length(const char* input); * @brief len Length * @return Copied length in bytes */ -MWDECL int MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len); +MWDECL int MWAPI MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len); /*! * @brief Converts UTF-32 to UTF-8 @@ -44,7 +44,7 @@ MWDECL int MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int * @brief output Output * @return Bytes this wide byte takes */ -MWDECL int MwUTF32ToUTF8(int input, char* output); +MWDECL int MWAPI MwUTF32ToUTF8(int input, char* output); #ifdef __cplusplus } diff --git a/include/Mw/Version.h b/include/Mw/Version.h index e83fe71e..9821dc6a 100644 --- a/include/Mw/Version.h +++ b/include/Mw/Version.h @@ -8,16 +8,26 @@ /*! * @brief Major version */ -#define MwMAJOR 0 +#define MwMAJOR 1 /*! * @brief Minor version */ -#define MwMINOR 0 +#define MwMINOR 3 + +/*! + * @brief Patchlevel of version, if patchlevel_alphabet is a or bigger, this value is calculated by `patchlevel_alphabet - 'a' + 1`. Otherwise 0 + */ +#define MwPATCH 0 /*! * @brief Version in string */ -#define MwVERSION "pre-1.0" +#define MwVERSION "1.4" + +/*! + * @brief Version in string + */ +MWDECL const char* MwVersionString; #endif diff --git a/include/Mw/Widget/Calendar.h b/include/Mw/Widget/Calendar.h new file mode 100644 index 00000000..a01968fc --- /dev/null +++ b/include/Mw/Widget/Calendar.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Calendar.h + * @brief Calendar widget + */ +#ifndef __MW_WIDGET_CALENDAR_H__ +#define __MW_WIDGET_CALENDAR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Calendar widget class + */ +MWDECL MwClass MwCalendarClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/Widget/ComboBox.h b/include/Mw/Widget/ComboBox.h index f6170ccd..7b2dc2fc 100644 --- a/include/Mw/Widget/ComboBox.h +++ b/include/Mw/Widget/ComboBox.h @@ -7,6 +7,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/Mw/Widget/Label.h b/include/Mw/Widget/Label.h index 4c751331..f9338e33 100644 --- a/include/Mw/Widget/Label.h +++ b/include/Mw/Widget/Label.h @@ -7,6 +7,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/Mw/Widget/ListBox.h b/include/Mw/Widget/ListBox.h index 1c5c609f..f4fe48f4 100644 --- a/include/Mw/Widget/ListBox.h +++ b/include/Mw/Widget/ListBox.h @@ -19,50 +19,29 @@ extern "C" { MWDECL MwClass MwListBoxClass; /*! - * @brief Creates a listbox packet - * @return Packet - */ -MWDECL MwListBoxPacket* MwListBoxCreatePacket(void); - -/*! - * @brief Destroys a listbox packet - * @param packet Packet - */ -MWDECL void MwListBoxDestroyPacket(MwListBoxPacket* packet); - -/*! - * @brief Inserts a new item to a packet - * @param packet Packet - * @param index Index - * @return Index - */ -MWDECL int MwListBoxPacketInsert(MwListBoxPacket* packet, int index); - -/*! - * @brief Sets a column of item in a packet - * @param packet Packet - * @param index Index + * @brief Sets item on the listbox + * @param handle Widget + * @param row Row * @param col Column * @param text Text + * @return Index */ -MWDECL void MwListBoxPacketSet(MwListBoxPacket* packet, int index, int col, const char* text); +MwInline int MwListBoxSet(MwWidget handle, int row, int col, const char* text) { + int out; + + MwVaWidgetExecute(handle, "mwListBoxSet", (void*)&out, row, col, text); + + return out; +} /*! - * @brief Sets an icon of item in a packet - * @param packet Packet + * @brief Sets the icon of the row + * @param handle Widget * @param index Index * @param icon Icon */ -MWDECL void MwListBoxPacketSetIcon(MwListBoxPacket* packet, int index, MwLLPixmap icon); - -/*! - * @brief Inserts item on the listbox - * @param handle Widget - * @param index Index - * @param packet Packet - */ -MwInline void MwListBoxInsert(MwWidget handle, int index, void* packet) { - MwVaWidgetExecute(handle, "mwListBoxInsert", NULL, index, packet); +MwInline void MwListBoxSetIcon(MwWidget handle, int index, MwLLPixmap icon) { + MwVaWidgetExecute(handle, "mwListBoxSetIcon", NULL, index, icon); } /*! diff --git a/include/Mw/Widget/SubWindow.h b/include/Mw/Widget/SubWindow.h new file mode 100644 index 00000000..c7ce2e1f --- /dev/null +++ b/include/Mw/Widget/SubWindow.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Widget/SubWindow.h + * @brief SubWindow widget + */ +#ifndef __MW_WIDGET_SUBWINDOW_H__ +#define __MW_WIDGET_SUBWINDOW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief SubWindow widget class + */ +MWDECL MwClass MwSubWindowClass; + +/*! + * @brief Get parent widget where widgets should be placed + * @param handle Widget + * @return Widget + */ +MwInline MwWidget MwSubWindowGetFrame(MwWidget handle) { + MwWidget out; + MwVaWidgetExecute(handle, "mwSubWindowGetFrame", &out); + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/Widget/Tab.h b/include/Mw/Widget/Tab.h new file mode 100644 index 00000000..9f80a0df --- /dev/null +++ b/include/Mw/Widget/Tab.h @@ -0,0 +1,59 @@ +/*! + * @file Mw/Widget/Tab.h + * @brief Tab widget + */ +#ifndef __MW_WIDGET_TAB_H__ +#define __MW_WIDGET_TAB_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Tab widget class + */ +MWDECL MwClass MwTabClass; + +/*! + * @brief Adds a tab + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabAdd(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabAdd", &out, name); + return out; +} + +/*! + * @brief Gets a tab frame + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabGetFrame(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabGetFrame", &out, name); + return out; +} + +/*! + * @brief Focus on a tab frame + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline void MwTabFocus(MwWidget handle, const char* name) { + MwVaWidgetExecute(handle, "mwTabFocus", NULL, name); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/Widget/Table.h b/include/Mw/Widget/Table.h new file mode 100644 index 00000000..1d39ec30 --- /dev/null +++ b/include/Mw/Widget/Table.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Table.h + * @brief Table widget + */ +#ifndef __MW_WIDGET_TABLE_H__ +#define __MW_WIDGET_TABLE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Table widget class + */ +MWDECL MwClass MwTableClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/Mw/Widget/TreeView.h b/include/Mw/Widget/TreeView.h index b722e140..f76f6af0 100644 --- a/include/Mw/Widget/TreeView.h +++ b/include/Mw/Widget/TreeView.h @@ -90,6 +90,19 @@ MwInline void MwTreeViewSetOpened(MwWidget handle, void* item, int opened) { MwVaWidgetExecute(handle, "mwTreeViewSetOpened", NULL, item, opened); } +/*! + * @brief Gets the opened state of ithe item + * @param handle Widget + * @param item Item + * @return Opened or not + */ +MwInline int MwTreeViewGetOpened(MwWidget handle, void* item) { + int out; + MwVaWidgetExecute(handle, "mwTreeViewGetOpened", (void*)&out, item); + + return out; +} + #ifdef __cplusplus } #endif diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 0b7db3ac..4c7e0bb1 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -34,19 +34,7 @@ extern "C" { MWDECL MwClass MwVulkanClass; /*! - * @brief Add an extension to the list of extensions to enable prior to initialization. - * @warning This must be called before MwCreateWidget. - */ -MWDECL void MwVulkanEnableExtension(const char* ext_name); - -/*! - * @brief Add an layer to the list of layers to enable prior to initialization. - * @warning This must be called before MwCreateWidget. - */ -MWDECL void MwVulkanEnableLayer(const char* ext_name); - -/*! - * @brief Configuration options that can be passed to setup Vulkan before a widget is created. + * @brief Configuration options that can be passed to setup parts of the Vulkan widget. */ typedef struct _MwVulkanConfig { /*! @@ -63,13 +51,6 @@ typedef struct _MwVulkanConfig { int validation_layers; } MwVulkanConfig; -/*! - * @brief Configure Vulkan prior to initializing the widget. - * @warning This must be called before MwCreateWidget. - * @warning The configuration provided will be used for future initializations of the Vulkan widget (unless it's changed) - */ -MWDECL void MwVulkanConfigure(MwVulkanConfig* cfg); - /*! * @brief Field that can be gotten from Vulkan. */ @@ -122,7 +103,7 @@ MwInline void* MwVulkanGetField(MwWidget handle, int field, int* err) { /*! * @brief Return whether Vulkan is installed on the target platform. */ -MWDECL int MwVulkanSupported(void); +MWDECL int MWAPI MwVulkanSupported(void); #ifdef __cplusplus } diff --git a/include/Mw/Widget/Window.h b/include/Mw/Widget/Window.h index 24b7153f..6a98b68a 100644 --- a/include/Mw/Widget/Window.h +++ b/include/Mw/Widget/Window.h @@ -27,6 +27,17 @@ MwInline void MwWindowMakeBorderless(MwWidget handle, int toggle) { MwVaWidgetExecute(handle, "mwWindowMakeBorderless", NULL, toggle); } +/*! + * @brief Whether the window should close + * @param handle Widget + * @return bool + */ +MwInline MwBool MwWindowShouldClose(MwWidget handle) { + MwBool res = MwFALSE; + MwVaWidgetExecute(handle, "mwWindowShouldClose", NULL, &res); + return res; +} + #ifdef __cplusplus } #endif diff --git a/milsko.xml b/milsko.xml index 5c837043..a94c847c 100644 --- a/milsko.xml +++ b/milsko.xml @@ -55,6 +55,9 @@ String properties must be prefixed with S. Handler properties must be prefixed with C. Other properties must be prefixed with V. + + "Early" properties must have letter "E" as 2nd letter. + e.g. vulkanExtension would be SEvulkanExtension --> @@ -67,31 +70,42 @@ - + - - + + - - - - - - - - + + + + + + + + - - + + - - - - + + + + + + + + + + + + + + + @@ -100,8 +114,14 @@ + + + + + + @@ -112,6 +132,15 @@ + + + + @@ -119,33 +148,33 @@ - - + + - + - + - + - + - + - - + + @@ -156,13 +185,13 @@ - + - + - + 0 @@ -203,6 +232,19 @@ + + 0x80000001 + + + + + + + + + + + 0 @@ -215,21 +257,27 @@ + 0x0fffffff + 0xf 0xf0 0x10 0x20 0x40 0x80 + + 0x80000000 + 0xc0000000 + 0xa0000000 -
+
- + - + @@ -473,20 +521,63 @@ - + + + + + + + + + + + + + + + + + + + + + + + - -
-
+
- + + + + + + + + + + + + + + + + + + +
+
+ + + + @@ -495,11 +586,11 @@
-
+
- + @@ -510,70 +601,13 @@ - + - + - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - - - - - - - -
@@ -587,6 +621,7 @@ + @@ -597,22 +632,43 @@ + + + + + + + + + + + + + + + + + + + + + @@ -647,11 +703,24 @@ + + + - + + + + + + + + + + + - + @@ -677,6 +746,9 @@ + + + @@ -693,6 +765,10 @@ + + + + @@ -702,8 +778,10 @@ - + + + @@ -721,6 +799,13 @@ + + + + + + + @@ -749,6 +834,12 @@ + + + + + + @@ -764,12 +855,18 @@ + + + + + + @@ -782,6 +879,9 @@ + + + @@ -795,9 +895,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pl/ostype/Darwin.pl b/pl/ostype/Darwin.pl index c786eb87..5d5baabd 100644 --- a/pl/ostype/Darwin.pl +++ b/pl/ostype/Darwin.pl @@ -1,7 +1,8 @@ $library_suffix = ".dylib"; set_shared_flag("-dynamiclib"); -use_backend("cocoa"); +#use_backend("cocoa"); +new_object("src/backend/nococoa.m"); add_cflags("-DSTBI_NO_THREAD_LOCALS"); add_ldflags("-framework Cocoa -lobjc"); diff --git a/pl/ostype/FreeBSD.pl b/pl/ostype/FreeBSD.pl new file mode 100644 index 00000000..4d4b17a8 --- /dev/null +++ b/pl/ostype/FreeBSD.pl @@ -0,0 +1,19 @@ +my @enabled_backends = (); + +add_incdir2("-I/usr/local/include"); +add_libdir("-L/usr/local/lib -Wl,-R/usr/local/lib"); + +if (param_get("wayland") && not(param_get("tiny"))) { + push(@enabled_backends, "wayland"); +} +if (param_get("x11")) { + push(@enabled_backends, "x11"); +} + +use_backend(@enabled_backends); + +add_libs("-lpthread"); + +add_cflags("-DUSE_DBUS"); + +1; diff --git a/pl/ostype/Haiku.pl b/pl/ostype/Haiku.pl new file mode 100644 index 00000000..68322b91 --- /dev/null +++ b/pl/ostype/Haiku.pl @@ -0,0 +1,3 @@ +use_backend("haiku"); + +1; diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 278cbfe0..75159d56 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,6 +1,6 @@ my @enabled_backends = (); -if (param_get("wayland")) { +if (param_get("wayland") && not(param_get("tiny"))) { push(@enabled_backends, "wayland"); } if (param_get("x11")) { diff --git a/pl/ostype/OpenBSD.pl b/pl/ostype/OpenBSD.pl new file mode 100644 index 00000000..dbbc3be2 --- /dev/null +++ b/pl/ostype/OpenBSD.pl @@ -0,0 +1,8 @@ +add_incdir2("-I/usr/local/include"); +add_libdir("-L/usr/local/lib -Wl,-R/usr/local/lib"); +use_backend("x11"); +add_libs("-lpthread"); + +add_cflags("-DUSE_DBUS"); + +1; diff --git a/pl/ostype/Windows.pl b/pl/ostype/Windows.pl index 29bdc98f..e2ed1ab8 100644 --- a/pl/ostype/Windows.pl +++ b/pl/ostype/Windows.pl @@ -4,5 +4,7 @@ $executable_suffix = ".exe"; $math = ""; add_ldflags("-Wl,--out-implib,src/libMw.dll.a -static-libgcc"); use_backend("gdi"); +add_libs("-lole32"); +add_libs("-luuid"); 1; diff --git a/pl/rules.pl b/pl/rules.pl index 7ad414db..89f13e93 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -4,9 +4,15 @@ my $gl_libs = ""; if (param_get("tiny")) { add_cflags("-Oz"); if (defined($ENV{CC}) && grep(/^clang$/, $ENV{CC})) { - add_libs("-flto=thin"); - add_cflags("-flto=thin"); + add_libs("-flto=full"); + add_cflags("-flto=full"); } + add_cflags("-fdata-sections -ffunction-sections"); + add_libs("-Wl,--gc-sections"); + + # these don't actually disable either, they're here for the final output. + param_set("wayland", 0); + param_set("dbus", 0); } if (param_get("classic-theme")) { add_cflags("-DUSE_CLASSIC_THEME"); @@ -40,7 +46,11 @@ if (grep(/^classicmacos$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); - new_object("src/backend/wayland.c"); + new_object("src/backend/cairo.c"); + new_object("src/backend/wayland/wayland.c"); + new_object("src/backend/wayland/buffer.c"); + new_object("src/backend/wayland/interfaces.c"); + new_object("src/backend/wayland/region.c"); if (param_get("opengl")) { add_cflags("-DWAYLAND_LOAD_OPENGL"); @@ -56,10 +66,16 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); + scan_wayland_protocol_from_file("wlr-layer-shell", + "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; } +if (not(param_get("dbus")) && not(param_get("tiny"))) { + $cflags =~ s/( |^)-DUSE_DBUS( |$)/ /; +} + if (grep(/( |^)-DUSE_DBUS( |$)/, $cflags)) { add_cflags(`pkg-config --cflags dbus-1`); } @@ -79,12 +95,18 @@ if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { new_object("src/widget/opengl_cocoa.m"); } -# tim cook my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this +# John Apple my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this add_cflags("-DGL_SILENCE_DEPRECATION"); $gl_libs = "-framework OpenGL"; } +if (grep(/^haiku$/, @backends)) { + add_cflags("-DUSE_HAIKU"); + new_object("src/backend/haiku.cc"); + add_libs("-lbe"); +} + if (param_get("stb-image")) { add_cflags("-DUSE_STB_IMAGE"); if (param_get("tiny")) { @@ -100,6 +122,9 @@ else { if (param_get("stb-truetype")) { add_cflags("-DUSE_STB_TRUETYPE"); } +if (param_get("allow-sloppy-focus")) { + add_cflags("-DALLOW_SLOPPY_FOCUS"); +} add_incdir("-Iexternal/libz/include"); @@ -110,6 +135,10 @@ if (param_get("freetype2")) { } } +if (param_get("gdi-text")) { + add_cflags("-DUSE_GDI_TEXT"); +} + if (param_get("vulkan") && param_get("vulkan-string-helper")) { add_cflags("-DHAS_VK_ENUM_STRING_HELPER"); } @@ -121,6 +150,7 @@ new_object("src/text/font/*.c"); new_object("src/widget/box.c"); new_object("src/widget/button.c"); +new_object("src/widget/calendar.c"); new_object("src/widget/checkbox.c"); new_object("src/widget/combobox.c"); new_object("src/widget/entry.c"); @@ -135,6 +165,9 @@ new_object("src/widget/radiobox.c"); new_object("src/widget/scrollbar.c"); new_object("src/widget/separator.c"); new_object("src/widget/submenu.c"); +new_object("src/widget/subwindow.c"); +new_object("src/widget/tab.c"); +new_object("src/widget/table.c"); new_object("src/widget/treeview.c"); new_object("src/widget/viewport.c"); new_object("src/widget/window.c"); @@ -173,7 +206,10 @@ new_example("examples/basic/box"); new_example("examples/basic/clipboard"); new_example("examples/basic/sevensegment"); new_example("examples/basic/calculator"); +new_example("examples/basic/filechooser"); new_example("examples/basic/periodic"); +new_example("examples/basic/subwindow"); +new_example("examples/basic/tab"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); diff --git a/pl/utils.pl b/pl/utils.pl index 70c0b517..504e8dcb 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -54,7 +54,7 @@ sub set_shared_flag { sub new_object { my @l = glob($_[0]); foreach my $e (@l) { - $e =~ s/\.(c|m)$/$object_suffix/; + $e =~ s/\.(cc|c|m)$/$object_suffix/; push(@library_targets, $e); } } @@ -66,7 +66,7 @@ sub use_backend { } sub scan_wayland_protocol_core { - my $proto_c = "src/backend/wayland-core-protocol.c"; + my $proto_c = "src/backend/wayland/wayland-core-protocol.c"; if ( system( @@ -98,7 +98,7 @@ sub scan_wayland_protocol { my $proto = $_[1]; my $ver = $_[2]; - my $proto_c = "src/backend/wayland-${proto}-protocol.c"; + my $proto_c = "src/backend/wayland/wayland-${proto}-protocol.c"; if ( system( @@ -125,6 +125,35 @@ sub scan_wayland_protocol { } } +sub scan_wayland_protocol_from_file { + my $proto = $_[0]; + my $file = $_[1]; + my $proto_c = "src/backend/wayland/wayland-${proto}-protocol.c"; + + if ( + system( + "wayland-scanner private-code ./resource/wayland/${file} ${proto_c}" + ) != 0 + ) + { + print( + "^ Error on getting private code for ./resource/wayland/${file}\n"); + } + else { + new_object($proto_c); + } + if ( + system( +"wayland-scanner client-header ./resource/wayland/${file} include/Mw/LowLevel/Wayland/${proto}-client-protocol.h" + ) + ) + { + print( + "^ Error on getting client header for ./resource/wayland/${file}\n" + ); + } +} + our %params = (); sub param_set { diff --git a/resource/font/cursor.bdf b/resource/font/cursor.bdf new file mode 100644 index 00000000..d78af3f8 --- /dev/null +++ b/resource/font/cursor.bdf @@ -0,0 +1,3289 @@ +STARTFONT 2.1 +COMMENT Created by bitmaptobdf +FONT cursor +SIZE 31 78 78 +FONTBOUNDINGBOX 31 31 -15 -16 +STARTPROPERTIES 3 +COPYRIGHT "These ""glyphs"" are unencumbered" +FONT_ASCENT 16 +FONT_DESCENT 17 +ENDPROPERTIES +CHARS 154 +STARTCHAR X_cursor +ENCODING -1 0 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +e01d +f03c +f87c +7cf8 +3ff0 +1fe0 +0fc0 +0fc0 +1fe0 +3ff0 +7cf8 +f87c +f03c +e01c +ENDCHAR +STARTCHAR X_cursor_mask +ENCODING -1 1 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +f00f +f81f +fc3f +fe7f +7ffe +3ffc +1ff8 +0ff0 +0ff0 +1ff8 +3ffc +7ffe +fe7f +fc3f +f81f +f00f +ENDCHAR +STARTCHAR arrow +ENCODING -1 2 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -14 +BITMAP +000d +003c +00f8 +03f8 +0ff0 +3ff0 +03e0 +07e0 +0ec0 +1cc0 +3880 +7080 +e000 +4000 +ENDCHAR +STARTCHAR arrow_mask +ENCODING -1 3 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -15 +BITMAP +0007 +001f +007f +01fe +07fe +1ffc +3ffc +3ff8 +07f8 +0ff0 +1ff0 +3ee0 +7ce0 +f840 +7000 +2000 +ENDCHAR +STARTCHAR based_arrow_down +ENCODING -1 4 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 10 -3 -1 +BITMAP +ff +00 +ff +18 +18 +18 +18 +5a +3c +18 +ENDCHAR +STARTCHAR based_arrow_down_mask +ENCODING -1 5 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 12 -4 -2 +BITMAP +ffc4 +ffc0 +ffc0 +ffc0 +ffc0 +1e00 +1e00 +7f80 +7f80 +7f80 +3f00 +1e00 +ENDCHAR +STARTCHAR based_arrow_up +ENCODING -1 6 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 10 -3 -1 +BITMAP +18 +3c +5a +18 +18 +18 +18 +ff +00 +ff +ENDCHAR +STARTCHAR based_arrow_up_mask +ENCODING -1 7 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 12 -4 -2 +BITMAP +0c04 +1e00 +7f80 +7f80 +7f80 +1e00 +1e00 +ffc0 +ffc0 +ffc0 +ffc0 +ffc0 +ENDCHAR +STARTCHAR boat +ENCODING -1 8 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 8 -14 -5 +BITMAP +0100 +07c0 +8860 +ffff +0018 +0020 +0040 +ffc0 +ENDCHAR +STARTCHAR boat_mask +ENCODING -1 9 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 -14 -5 +BITMAP +0700 +0fc0 +9fe0 +ffff +ffff +ffff +fff8 +ffe0 +ffc0 +ENDCHAR +STARTCHAR bogosity +ENCODING -1 10 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -8 +BITMAP +e239 +2220 +2220 +2220 +fff8 +a228 +a228 +a228 +a228 +fff8 +2220 +2220 +2220 +e238 +ENDCHAR +STARTCHAR bogosity_mask +ENCODING -1 11 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -9 +BITMAP +fbbe +fbbe +fbbe +3bb8 +fffe +fffe +fffe +fbbe +fbbe +fffe +fffe +fffe +3bb8 +fbbe +fbbe +fbbe +ENDCHAR +STARTCHAR bottom_left_corner +ENCODING -1 12 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -1 +BITMAP +c001 +c000 +c410 +c420 +c440 +c480 +c500 +c600 +c7f0 +c000 +c000 +c000 +fffc +fffc +ENDCHAR +STARTCHAR bottom_left_corner_mask +ENCODING -1 13 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -2 +BITMAP +f000 +f000 +f70c +f71c +f738 +f770 +f7e0 +f7c0 +f7fc +f7fc +f7fc +f000 +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR bottom_right_corner +ENCODING -1 14 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -1 +BITMAP +000d +000c +208c +108c +088c +048c +028c +018c +3f8c +000c +000c +000c +fffc +fffc +ENDCHAR +STARTCHAR bottom_right_corner_mask +ENCODING -1 15 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -2 +BITMAP +000f +000f +30ef +38ef +1cef +0eef +07ef +03ef +3fef +3fef +3fef +000f +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR bottom_side +ENCODING -1 16 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -1 +BITMAP +0201 +0200 +0200 +0200 +0200 +0200 +2220 +1240 +0a80 +0700 +0200 +0000 +fff8 +fff8 +ENDCHAR +STARTCHAR bottom_side_mask +ENCODING -1 17 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -2 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +3398 +3bb8 +1ff0 +0fe0 +07c0 +0380 +fffe +fffe +fffe +fffe +ENDCHAR +STARTCHAR bottom_tee +ENCODING -1 18 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 10 -7 -1 +BITMAP +0301 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +fffc +fffc +ENDCHAR +STARTCHAR bottom_tee_mask +ENCODING -1 19 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 12 -8 -2 +BITMAP +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR box_spiral +ENCODING -1 20 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +ffff +8000 +bffe +a002 +affa +a80a +abea +aa2a +aaaa +abaa +a82a +afea +a00a +bffa +8002 +fffe +ENDCHAR +STARTCHAR box_spiral_mask +ENCODING -1 21 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR center_ptr +ENCODING -1 22 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -4 -14 +BITMAP +0c09 +0c00 +1e00 +1e00 +3f00 +3f00 +7f80 +7f80 +ccc0 +8c40 +0c00 +0c00 +0c00 +0c00 +ENDCHAR +STARTCHAR center_ptr_mask +ENCODING -1 23 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -5 -15 +BITMAP +0f04 +0f00 +1f80 +1f80 +3fc0 +3fc0 +7fe0 +7fe0 +fff0 +fff0 +fff0 +ef70 +0f00 +0f00 +0f00 +0f00 +ENDCHAR +STARTCHAR circle +ENCODING -1 24 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +0781 +1fe0 +3ff0 +7878 +7038 +e01c +e01c +e01c +e01c +7038 +7878 +3ff0 +1fe0 +0780 +ENDCHAR +STARTCHAR circle_mask +ENCODING -1 25 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +07e0 +1ff8 +3ffc +7ffe +7ffe +fc3f +f81f +f81f +f81f +f81f +fc3f +7ffe +7ffe +3ffc +1ff8 +07e0 +ENDCHAR +STARTCHAR clock +ENCODING -1 26 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 16 -6 -13 +BITMAP +3ff1 +6798 +c8cc +9324 +9e24 +8844 +c78c +7ff8 +5328 +5328 +5328 +57a8 +d32c +f03c +fffc +fffc +ENDCHAR +STARTCHAR clock_mask +ENCODING -1 27 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -6 -13 +BITMAP +7ff8 +ef9c +dbee +b7b6 +bff6 +9f66 +cfce +fffc +d7ac +d7ac +d7ac +dfec +d7ae +f33e +fffe +fffe +ENDCHAR +STARTCHAR coffee_mug +ENCODING -1 28 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -7 +BITMAP +1ff1 +2008 +6006 +501a +4fe2 +c002 +c002 +4002 +4002 +591a +6aaa +ebaa +da9a +4002 +4002 +3ffc +ENDCHAR +STARTCHAR coffee_mug_mask +ENCODING -1 29 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -7 +BITMAP +1ff0 +3ff8 +7fff +7fff +ffff +ffff +ffff +ffff +7fff +7fff +ffff +ffff +ffff +ffff +7fff +3ffc +ENDCHAR +STARTCHAR cross +ENCODING -1 30 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +0280 +0280 +0280 +0280 +0280 +0280 +feff +0000 +feff +0280 +0280 +0280 +0280 +0280 +0280 +ENDCHAR +STARTCHAR cross_mask +ENCODING -1 31 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +07c0 +07c0 +07c0 +07c0 +07c0 +ffff +ffff +ffff +ffff +ffff +07c0 +07c0 +07c0 +07c0 +07c0 +07c0 +ENDCHAR +STARTCHAR cross_reverse +ENCODING -1 32 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +4284 +a28a +5294 +2aa8 +16d0 +0aa0 +fd7f +0280 +fd7f +0aa0 +16d0 +2aa8 +5294 +a28a +4284 +ENDCHAR +STARTCHAR cross_reverse_mask +ENCODING -1 33 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +66cc +b6db +def6 +6eec +36d8 +fabf +fc7f +0100 +fc7f +fabf +36d8 +6eec +def6 +b6db +66cc +ENDCHAR +STARTCHAR crosshair +ENCODING -1 34 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +0100 +0100 +0100 +0100 +0100 +0100 +0100 +feff +0100 +0100 +0100 +0100 +0100 +0100 +0100 +ENDCHAR +STARTCHAR crosshair_mask +ENCODING -1 35 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +ffff +ffff +ffff +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR diamond_cross +ENCODING -1 36 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -7 -8 +BITMAP +0281 +06c0 +0aa0 +1290 +2288 +4284 +fefe +0000 +fefe +4284 +2288 +1290 +0aa0 +06c0 +0280 +ENDCHAR +STARTCHAR diamond_cross_mask +ENCODING -1 37 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +07c0 +0fe0 +1ff0 +3bb8 +739c +e38e +ffff +feff +ffff +e38e +739c +3bb8 +1ff0 +0fe0 +07c0 +0380 +ENDCHAR +STARTCHAR dot +ENCODING -1 38 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -5 -5 +BITMAP +1e09 +7f80 +7f80 +ffc0 +ffc0 +ffc0 +ffc0 +7f80 +7f80 +1e00 +ENDCHAR +STARTCHAR dot_mask +ENCODING -1 39 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -6 +BITMAP +1f84 +7fe0 +7fe0 +fff0 +fff0 +fff0 +fff0 +fff0 +fff0 +7fe0 +7fe0 +1f80 +ENDCHAR +STARTCHAR dotbox +ENCODING -1 40 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -7 +BITMAP +fff9 +8010 +8010 +8010 +8010 +8610 +8610 +8010 +8010 +8010 +8010 +fff0 +ENDCHAR +STARTCHAR dotbox_mask +ENCODING -1 41 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +fffc +fffc +fffc +e01c +e01c +e79c +e79c +e79c +e79c +e01c +e01c +fffc +fffc +fffc +ENDCHAR +STARTCHAR double_arrow +ENCODING -1 42 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -5 -7 +BITMAP +0c09 +1e00 +3f00 +6d80 +ccc0 +0c00 +0c00 +0c00 +0c00 +ccc0 +6d80 +3f00 +1e00 +0c00 +ENDCHAR +STARTCHAR double_arrow_mask +ENCODING -1 43 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -6 -8 +BITMAP +0f04 +1f80 +3fc0 +7fe0 +fff0 +fff0 +fff0 +0f00 +0f00 +fff0 +fff0 +fff0 +7fe0 +3fc0 +1f80 +0f00 +ENDCHAR +STARTCHAR draft_large +ENCODING -1 44 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0003 +000c +003c +00f8 +03f8 +0ff0 +3ff0 +01e0 +02e0 +04c0 +08c0 +1080 +2080 +4000 +8000 +ENDCHAR +STARTCHAR draft_large_mask +ENCODING -1 45 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -14 -16 +BITMAP +0006 +001e +007e +01fc +07f8 +1ff8 +7ff0 +7ff0 +07e0 +0fe0 +1dc0 +39c0 +7180 +e180 +c000 +8000 +ENDCHAR +STARTCHAR draft_small +ENCODING -1 46 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0002 +000c +003c +00f8 +03f8 +0070 +00b0 +0120 +0220 +0400 +0800 +1000 +2000 +4000 +8000 +ENDCHAR +STARTCHAR draft_small_mask +ENCODING -1 47 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0006 +001e +007c +01fc +07f8 +07f8 +01f0 +03f0 +0760 +0e40 +1c00 +3800 +7000 +e000 +c000 +ENDCHAR +STARTCHAR draped_box +ENCODING -1 48 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -7 +BITMAP +fff8 +8910 +9990 +b0d0 +e070 +8610 +8610 +e070 +b0d0 +9990 +8910 +fff0 +ENDCHAR +STARTCHAR draped_box_mask +ENCODING -1 49 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +fffc +fffc +cfcc +dfec +fcfc +fb7c +f7bc +f7bc +fb7c +fcfc +dfec +cfcc +fffc +fffc +ENDCHAR +STARTCHAR exchange +ENCODING -1 50 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +8fc0 +dfe0 +f830 +9010 +9800 +fc00 +0000 +0000 +00fc +0064 +2024 +307c +1fec +0fc4 +ENDCHAR +STARTCHAR exchange_mask +ENCODING -1 51 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +c7e0 +eff0 +fff8 +fffc +fc1c +ff0c +ff00 +ff00 +00ff +00ff +307f +383f +3fff +1fff +0ff7 +07e3 +ENDCHAR +STARTCHAR fleur +ENCODING -1 52 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +0300 +0780 +0fc0 +0300 +2310 +6318 +fffc +fffc +6318 +2310 +0300 +0fc0 +0780 +0300 +ENDCHAR +STARTCHAR fleur_mask +ENCODING -1 53 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +03c0 +03e0 +07e0 +0ff0 +17e8 +3bdc +ffff +ffff +ffff +ffff +3bdc +17e8 +0ff0 +07e0 +03c0 +03c0 +ENDCHAR +STARTCHAR gobbler +ENCODING -1 54 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -14 -13 +BITMAP +0078 +0070 +8033 +9fb0 +fff0 +fe30 +fc30 +6038 +00f0 +1fe0 +0800 +0800 +0800 +0800 +1e00 +ENDCHAR +STARTCHAR gobbler_mask +ENCODING -1 55 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -13 +BITMAP +00fc +00fc +c0ff +ffff +ffff +fffc +fffc +fffc +fffc +fffc +7ff8 +1ff0 +1c00 +1c00 +3f00 +3f00 +ENDCHAR +STARTCHAR gumby +ENCODING -1 56 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -2 -16 +BITMAP +3f00 +1080 +c840 +eaa0 +c820 +cba0 +f83c +383f +0827 +0827 +092f +0927 +0920 +1110 +2108 +3ef8 +ENDCHAR +STARTCHAR gumby_mask +ENCODING -1 57 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -2 -16 +BITMAP +3f00 +df80 +efc0 +ffe0 +efe0 +effc +fffe +ffff +3fef +0fef +0fff +0fef +0fe7 +1ff0 +3ff8 +3ef8 +ENDCHAR +STARTCHAR hand1 +ENCODING -1 58 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -12 -16 +BITMAP +0018 +0078 +01e0 +03c0 +0780 +0fc0 +1fe0 +5fc0 +ffe0 +bfe0 +0fc0 +0f80 +9400 +c400 +6800 +3000 +ENDCHAR +STARTCHAR hand1_mask +ENCODING -1 59 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -12 -16 +BITMAP +003b +00f8 +03f0 +07e0 +0fc0 +1fe0 +7ff0 +fff0 +fff0 +fff0 +ffe0 +ffc0 +ff80 +fe00 +fc00 +7800 +ENDCHAR +STARTCHAR hand2 +ENCODING -1 60 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 0 -14 +BITMAP +7f80 +8040 +7e20 +1010 +0e10 +1010 +0e28 +1044 +0c82 +0304 +0248 +0110 +00a0 +0040 +ENDCHAR +STARTCHAR hand2_mask +ENCODING -1 61 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 0 -15 +BITMAP +7f80 +ffc0 +ffe0 +fff0 +7ff8 +1ff8 +3ff8 +1ffc +3ffe +1fff +0ffe +07fc +03f8 +01f0 +00e0 +0040 +ENDCHAR +STARTCHAR heart +ENCODING -1 62 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -6 -6 +BITMAP +3ef8 +638c +c106 +8002 +8002 +8002 +8002 +c006 +600c +3018 +1830 +0c60 +06c0 +0380 +ENDCHAR +STARTCHAR heart_mask +ENCODING -1 63 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -6 -6 +BITMAP +3ef9 +7ffc +e38e +c106 +c006 +c006 +c286 +e10e +701c +3838 +1c70 +0fe0 +07c0 +0380 +ENDCHAR +STARTCHAR icon +ENCODING -1 64 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +d555 +aaab +d555 +a00b +d005 +a00b +d005 +a00b +d005 +a00b +d005 +aaab +d555 +aaab +ffff +ENDCHAR +STARTCHAR icon_mask +ENCODING -1 65 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR iron_cross +ENCODING -1 66 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +7ff8 +3ff0 +9fe4 +cfcc +e79c +f33c +fffc +fffc +f33c +e79c +cfcc +9fe4 +3ff0 +7ff8 +ENDCHAR +STARTCHAR iron_cross_mask +ENCODING -1 67 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -9 +BITMAP +3ffc +7ffe +7ffe +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +7ffe +7ffe +3ffc +ENDCHAR +STARTCHAR left_ptr +ENCODING -1 68 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 14 0 -14 +BITMAP +80 +c0 +e0 +f0 +f8 +fc +fe +ff +f8 +d8 +8c +0c +06 +06 +ENDCHAR +STARTCHAR left_ptr_mask +ENCODING -1 69 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 16 -1 -15 +BITMAP +c003 +e000 +f000 +f800 +fc00 +fe00 +ff00 +ff80 +ffc0 +ffc0 +fe00 +ef00 +cf00 +0780 +0780 +0300 +ENDCHAR +STARTCHAR left_side +ENCODING -1 70 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 13 0 -7 +BITMAP +c000 +c000 +c100 +c200 +c400 +c800 +dffc +c800 +c400 +c200 +c100 +c000 +c000 +ENDCHAR +STARTCHAR left_side_mask +ENCODING -1 71 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -1 -8 +BITMAP +f000 +f000 +f0c0 +f1c0 +f380 +f700 +ffff +ffff +ffff +f700 +f380 +f1c0 +f0c0 +f000 +f000 +ENDCHAR +STARTCHAR left_tee +ENCODING -1 72 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 0 -7 +BITMAP +c008 +c000 +c000 +c000 +c000 +c000 +ffc0 +ffc0 +c000 +c000 +c000 +c000 +c000 +c000 +ENDCHAR +STARTCHAR left_tee_mask +ENCODING -1 73 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -1 -8 +BITMAP +f003 +f000 +f000 +f000 +f000 +f000 +fff0 +fff0 +fff0 +fff0 +f000 +f000 +f000 +f000 +f000 +f000 +ENDCHAR +STARTCHAR leftbutton +ENCODING -1 74 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +4555 +4555 +4555 +4555 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR leftbutton_mask +ENCODING -1 75 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR ll_angle +ENCODING -1 76 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 0 -1 +BITMAP +c008 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +ffc0 +ffc0 +ENDCHAR +STARTCHAR ll_angle_mask +ENCODING -1 77 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -1 -2 +BITMAP +f003 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +fff0 +fff0 +fff0 +fff0 +ENDCHAR +STARTCHAR lr_angle +ENCODING -1 78 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -9 -1 +BITMAP +00c8 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ffc0 +ffc0 +ENDCHAR +STARTCHAR lr_angle_mask +ENCODING -1 79 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -10 -2 +BITMAP +00f3 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +fff0 +fff0 +fff0 +fff0 +ENDCHAR +STARTCHAR man +ENCODING -1 80 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -11 +BITMAP +0380 +1ef0 +0280 +8100 +4387 +244b +1d70 +0540 +0440 +0280 +0440 +0920 +1290 +1450 +783c +f83f +ENDCHAR +STARTCHAR man_mask +ENCODING -1 81 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -11 +BITMAP +1fe0 +3ff0 +3ff8 +c382 +e7c7 +7fff +3ffb +1ff0 +07e0 +07c0 +0fe0 +1ff0 +3ff8 +7efc +fc7f +fc7f +ENDCHAR +STARTCHAR middlebutton +ENCODING -1 82 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +5455 +5455 +5455 +5455 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR middlebutton_mask +ENCODING -1 83 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR mouse +ENCODING -1 84 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -4 -13 +BITMAP +0700 +0c00 +0600 +0300 +7ff8 +8004 +b336 +b336 +b336 +8006 +8006 +601c +1860 +0780 +ENDCHAR +STARTCHAR mouse_mask +ENCODING -1 85 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -4 -15 +BITMAP +0f80 +1e00 +0f00 +0700 +7ff8 +fffc +ffff +ffff +ffff +ffff +ffff +ffff +3ff7 +1fe0 +0fc0 +0780 +ENDCHAR +STARTCHAR pencil +ENCODING -1 86 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -10 -1 +BITMAP +7008 +8800 +8c00 +4a00 +7a00 +2100 +1100 +1080 +0880 +0c40 +0440 +0220 +01e0 +00e0 +0060 +0020 +ENDCHAR +STARTCHAR pencil_mask +ENCODING -1 87 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -11 -1 +BITMAP +fc03 +fe00 +ff00 +7f00 +3f80 +3f80 +1fc0 +0fc0 +0fe0 +07e0 +07f0 +03f8 +01f8 +00f8 +0078 +0038 +ENDCHAR +STARTCHAR pirate +ENCODING -1 88 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -4 +BITMAP +0780 +0fc0 +1fe0 +3330 +3330 +1fe0 +0fc0 +0780 +8784 +8786 +4308 +3870 +0780 +1fe2 +f03e +8004 +ENDCHAR +STARTCHAR pirate_mask +ENCODING -1 89 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -4 +BITMAP +0fc0 +1fe0 +3ff0 +7ff8 +7ff8 +3ff0 +1fe0 +8fc1 +8fc7 +cfcf +f79c +7878 +0780 +7fe3 +ffff +f03e +ENDCHAR +STARTCHAR plus +ENCODING -1 90 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -4 -5 +BITMAP +0c08 +0c00 +0c00 +0c00 +ffc0 +ffc0 +0c00 +0c00 +0c00 +0c00 +ENDCHAR +STARTCHAR plus_mask +ENCODING -1 91 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -5 -6 +BITMAP +0f03 +0f00 +0f00 +0f00 +fff0 +fff0 +fff0 +fff0 +0f00 +0f00 +0f00 +0f00 +ENDCHAR +STARTCHAR question_arrow +ENCODING -1 92 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 15 -4 -8 +BITMAP +3e08 +7f00 +e380 +c180 +e180 +6380 +0700 +1e00 +1c00 +1400 +1400 +7700 +3600 +1c00 +0800 +ENDCHAR +STARTCHAR question_arrow_mask +ENCODING -1 93 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -5 -8 +BITMAP +1f03 +3f80 +7fc0 +ffe0 +f1e0 +f9e0 +7be0 +3fc0 +1f80 +1f00 +1f00 +3f80 +7fc0 +3f80 +1f00 +0e00 +ENDCHAR +STARTCHAR right_ptr +ENCODING -1 94 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 14 -7 -14 +BITMAP +01 +03 +07 +0f +1f +3f +7f +ff +1f +1b +31 +30 +60 +60 +ENDCHAR +STARTCHAR right_ptr_mask +ENCODING -1 95 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 16 -8 -15 +BITMAP +00c3 +01c0 +03c0 +07c0 +0fc0 +1fc0 +3fc0 +7fc0 +ffc0 +ffc0 +1fc0 +3dc0 +3cc0 +7800 +7800 +3000 +ENDCHAR +STARTCHAR right_side +ENCODING -1 96 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 13 -13 -7 +BITMAP +000c +000c +020c +010c +008c +004c +ffec +004c +008c +010c +020c +000c +000c +ENDCHAR +STARTCHAR right_side_mask +ENCODING -1 97 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -14 -8 +BITMAP +000f +000f +030f +038f +01cf +00ef +ffff +ffff +ffff +00ef +01cf +038f +030f +000f +000f +ENDCHAR +STARTCHAR right_tee +ENCODING -1 98 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -9 -7 +BITMAP +00c8 +00c0 +00c0 +00c0 +00c0 +00c0 +ffc0 +ffc0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ENDCHAR +STARTCHAR right_tee_mask +ENCODING -1 99 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -10 -8 +BITMAP +00f3 +00f0 +00f0 +00f0 +00f0 +00f0 +fff0 +fff0 +fff0 +fff0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +ENDCHAR +STARTCHAR rightbutton +ENCODING -1 100 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +5545 +5545 +5545 +5545 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR rightbutton_mask +ENCODING -1 101 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR rtl_logo +ENCODING -1 102 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +fffc +8044 +8044 +8044 +ffc4 +8844 +8844 +8844 +8844 +8ffc +8804 +8804 +8804 +fffc +ENDCHAR +STARTCHAR rtl_logo_mask +ENCODING -1 103 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +ffff +ffff +ffff +e077 +fff7 +fff7 +fff7 +ee77 +ee77 +efff +efff +efff +ee07 +ffff +ffff +ffff +ENDCHAR +STARTCHAR sailboat +ENCODING -1 104 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 13 -6 -14 +BITMAP +0108 +0100 +0580 +0580 +0d80 +0dc0 +1dc0 +1dc0 +3de0 +3de0 +7de0 +7df0 +f8e0 +ENDCHAR +STARTCHAR sailboat_mask +ENCODING -1 105 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -16 +BITMAP +00c0 +00e0 +01e0 +03f0 +03f0 +07f0 +07f8 +0ff8 +0ff8 +1ffc +1ffc +3ffc +3fff +7fff +fff8 +7fe0 +ENDCHAR +STARTCHAR sb_down_arrow +ENCODING -1 106 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 0 +BITMAP +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +fe +7c +38 +10 +ENDCHAR +STARTCHAR sb_down_arrow_mask +ENCODING -1 107 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -1 +BITMAP +3e03 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +ff80 +ff80 +7f00 +3e00 +1c00 +0800 +ENDCHAR +STARTCHAR sb_h_double_arrow +ENCODING -1 108 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 -7 -4 +BITMAP +1010 +3018 +7ffc +f01e +7ffc +3018 +1010 +ENDCHAR +STARTCHAR sb_h_double_arrow_mask +ENCODING -1 109 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 9 -7 -5 +BITMAP +1831 +3838 +7ffc +fffe +fffe +fffe +7ffc +3838 +1830 +ENDCHAR +STARTCHAR sb_left_arrow +ENCODING -1 110 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 1 -4 +BITMAP +1000 +3000 +7ffe +f000 +7ffe +3000 +1000 +ENDCHAR +STARTCHAR sb_left_arrow_mask +ENCODING -1 111 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 0 -5 +BITMAP +0c00 +1c00 +3fff +7fff +ffff +7fff +3fff +1c00 +0c00 +ENDCHAR +STARTCHAR sb_right_arrow +ENCODING -1 112 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 -15 -4 +BITMAP +0010 +0018 +fffc +001e +fffc +0018 +0010 +ENDCHAR +STARTCHAR sb_right_arrow_mask +ENCODING -1 113 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 -15 -5 +BITMAP +0030 +0038 +fffc +fffe +ffff +fffe +fffc +0038 +0030 +ENDCHAR +STARTCHAR sb_up_arrow +ENCODING -1 114 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 -16 +BITMAP +10 +39 +7c +fe +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +ENDCHAR +STARTCHAR sb_up_arrow_mask +ENCODING -1 115 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -16 +BITMAP +0803 +1c00 +3e00 +7f00 +ff80 +ff80 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +ENDCHAR +STARTCHAR sb_v_double_arrow +ENCODING -1 116 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 -8 +BITMAP +10 +39 +7c +fe +28 +28 +28 +28 +28 +28 +28 +fe +7c +38 +10 +ENDCHAR +STARTCHAR sb_v_double_arrow_mask +ENCODING -1 117 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 15 -4 -8 +BITMAP +1c03 +3e00 +7f00 +ff80 +ff80 +3e00 +3e00 +3e00 +3e00 +3e00 +ff80 +ff80 +7f00 +3e00 +1c00 +ENDCHAR +STARTCHAR shuttle +ENCODING -1 118 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -10 -16 +BITMAP +0021 +0070 +00f8 +01de +05de +09de +11de +11de +11de +11de +31de +71de +fdde +1888 +0078 +0030 +ENDCHAR +STARTCHAR shuttle_mask +ENCODING -1 119 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -11 -16 +BITMAP +0038 +007c +00fe +00ff +06ff +0eff +1eff +1eff +1eff +1eff +3eff +7eff +feff +7efe +0c7e +003c +ENDCHAR +STARTCHAR sizing +ENCODING -1 120 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +ff03 +8000 +8000 +8000 +8fc0 +8840 +8844 +8844 +0844 +0fc4 +0024 +0014 +000c +03fc +ENDCHAR +STARTCHAR sizing_mask +ENCODING -1 121 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffc0 +ffc0 +ffc0 +e000 +eff0 +eff0 +eff7 +ee77 +ee77 +eff7 +0ff7 +0fff +001f +03ff +03ff +03ff +ENDCHAR +STARTCHAR spider +ENCODING -1 122 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -6 -9 +BITMAP +2010 +1020 +1020 +0840 +0840 +8787 +6798 +1fe0 +1fe0 +6798 +8787 +0840 +0840 +1020 +1020 +2010 +ENDCHAR +STARTCHAR spider_mask +ENCODING -1 123 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -6 -9 +BITMAP +6018 +3030 +1020 +1860 +8fc1 +cfcf +6fdc +3ff0 +3fe0 +6ff8 +cfcf +8fc1 +1840 +1860 +3030 +6018 +ENDCHAR +STARTCHAR spraycan +ENCODING -1 124 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -9 -14 +BITMAP +0067 +0100 +3460 +7900 +6860 +fc00 +8400 +e400 +a400 +e400 +a400 +e400 +e400 +8400 +8400 +fc00 +ENDCHAR +STARTCHAR spraycan_mask +ENCODING -1 125 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -10 -14 +BITMAP +0032 +18b0 +3eb0 +3eb0 +7eb0 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ENDCHAR +STARTCHAR star +ENCODING -1 126 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -9 +BITMAP +0101 +0280 +0280 +0280 +0440 +0440 +0440 +3938 +c006 +3838 +0920 +1290 +2448 +2828 +3018 +2008 +ENDCHAR +STARTCHAR star_mask +ENCODING -1 127 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +0100 +0380 +0380 +06c0 +06c0 +0c60 +1c78 +f93e +c007 +f83e +3938 +3398 +66cc +6c6c +783c +701c +ENDCHAR +STARTCHAR target +ENCODING -1 128 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 13 -7 -7 +BITMAP +0381 +0fe0 +1c70 +3018 +600c +c106 +c286 +c106 +600c +3018 +1c70 +0fe0 +0380 +ENDCHAR +STARTCHAR target_mask +ENCODING -1 129 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 14 -7 -7 +BITMAP +07c0 +0fe0 +1ff0 +3c78 +701c +e10e +c387 +c6c7 +c387 +e10e +701c +3c78 +1ff0 +07c0 +ENDCHAR +STARTCHAR tcross +ENCODING -1 130 +SWIDTH 516 0 +DWIDTH 16 0 +BBX 13 13 -6 -7 +BITMAP +0207 +0200 +0200 +0200 +0200 +0200 +fff8 +0200 +0200 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR tcross_mask +ENCODING -1 131 +SWIDTH 516 0 +DWIDTH 16 0 +BBX 15 15 -7 -8 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +fffe +fffe +fffe +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR top_left_arrow +ENCODING -1 132 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -14 +BITMAP +c003 +f000 +7c00 +7f00 +3fc0 +3ff0 +1f00 +1f00 +0c80 +0c40 +0420 +0410 +0008 +0004 +ENDCHAR +STARTCHAR top_left_arrow_mask +ENCODING -1 133 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -15 +BITMAP +e000 +f800 +fe00 +7f80 +7fe0 +3ffc +3ffc +1ffc +1fc0 +0fe0 +0f70 +0738 +071c +070e +0007 +0003 +ENDCHAR +STARTCHAR top_left_corner +ENCODING -1 134 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -14 +BITMAP +ffff +fffc +c000 +c000 +c000 +c7f0 +c600 +c500 +c480 +c440 +c420 +c410 +c000 +c000 +ENDCHAR +STARTCHAR top_left_corner_mask +ENCODING -1 135 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -15 +BITMAP +ffff +ffff +ffff +ffff +f000 +f7fc +f7fc +f7fc +f7c0 +f7e0 +f770 +f738 +f71c +f70c +f000 +f000 +ENDCHAR +STARTCHAR top_right_corner +ENCODING -1 136 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -14 +BITMAP +ffff +fffc +000c +000c +000c +3f8c +018c +028c +048c +088c +108c +208c +000c +000c +ENDCHAR +STARTCHAR top_right_corner_mask +ENCODING -1 137 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -15 +BITMAP +ffff +ffff +ffff +ffff +000f +3fef +3fef +3fef +03ef +07ef +0eef +1cef +38ef +30ef +000f +000f +ENDCHAR +STARTCHAR top_side +ENCODING -1 138 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -14 +BITMAP +ffff +fff8 +0000 +0200 +0700 +0a80 +1240 +2220 +0200 +0200 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR top_side_mask +ENCODING -1 139 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -15 +BITMAP +fffe +fffe +fffe +fffe +0380 +07c0 +0fe0 +1ff0 +3bb8 +3398 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR top_tee +ENCODING -1 140 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 10 -7 -10 +BITMAP +ffff +fffc +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR top_tee_mask +ENCODING -1 141 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 12 -8 -11 +BITMAP +ffff +ffff +ffff +ffff +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +ENDCHAR +STARTCHAR trek +ENCODING -1 142 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 16 -3 -16 +BITMAP +11 +01 +38 +7c +fe +ee +fe +7c +38 +10 +ba +d6 +92 +82 +82 +82 +ENDCHAR +STARTCHAR trek_mask +ENCODING -1 143 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -16 +BITMAP +1c02 +1c00 +3e00 +7f00 +ff80 +ff80 +ff80 +7f00 +3e00 +5d00 +ff80 +ff80 +ff80 +eb80 +eb80 +e380 +ENDCHAR +STARTCHAR ul_angle +ENCODING -1 144 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 0 -10 +BITMAP +ffc7 +ffc0 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +ENDCHAR +STARTCHAR ul_angle_mask +ENCODING -1 145 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -1 -11 +BITMAP +fff2 +fff0 +fff0 +fff0 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +ENDCHAR +STARTCHAR umbrella +ENCODING -1 146 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -12 +BITMAP +1123 +0450 +934c +4f90 +3260 +c218 +0200 +0200 +0200 +0200 +0200 +0280 +0280 +0100 +ENDCHAR +STARTCHAR umbrella_mask +ENCODING -1 147 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -14 +BITMAP +176e +dffb +bffc +7fff +fffc +ffff +f39e +0380 +0380 +0380 +0380 +03e0 +03e0 +03e0 +03e0 +01c0 +ENDCHAR +STARTCHAR ur_angle +ENCODING -1 148 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -9 -10 +BITMAP +ffc7 +ffc0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ENDCHAR +STARTCHAR ur_angle_mask +ENCODING -1 149 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -10 -11 +BITMAP +fff2 +fff0 +fff0 +fff0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +ENDCHAR +STARTCHAR watch +ENCODING -1 150 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -15 -7 +BITMAP +1fe0 +1fe0 +1fe0 +3ff0 +6118 +c10c +8107 +8387 +8387 +8407 +c80c +6018 +3ff0 +1fe0 +1fe0 +1fe0 +ENDCHAR +STARTCHAR watch_mask +ENCODING -1 151 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -15 -7 +BITMAP +3ff0 +3ff0 +3ff0 +7ff8 +fffc +ffff +ffff +ffff +ffff +ffff +ffff +fffc +7ff8 +3ff0 +3ff0 +3ff0 +ENDCHAR +STARTCHAR xterm +ENCODING -1 152 +SWIDTH 322 0 +DWIDTH 10 0 +BBX 7 14 -3 -7 +BITMAP +ef +39 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +38 +ee +ENDCHAR +STARTCHAR xterm_mask +ENCODING -1 153 +SWIDTH 322 0 +DWIDTH 10 0 +BBX 9 16 -4 -8 +BITMAP +f782 +ff80 +ff80 +3e00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +3e00 +ff80 +ff80 +f780 +ENDCHAR +ENDFONT diff --git a/resource/font/deccurs.bdf b/resource/font/deccurs.bdf deleted file mode 100644 index c3502d4e..00000000 --- a/resource/font/deccurs.bdf +++ /dev/null @@ -1,1256 +0,0 @@ -STARTFONT 2.1 -FONT DECW$CURSOR -SIZE 31 78 78 -FONTBOUNDINGBOX 31 31 -15 -16 -STARTPROPERTIES 5 -FOUNDRY "Digital Equipment Corporation" -NOTICE "These images are owned by Digital Equipment Corporation" -FONT_ASCENT 16 -FONT_DESCENT 16 -COPYRIGHT "Copyright (c) Digital Equipment Corporation,1988. All Rights Reserved." -COMMENT -COMMENT Permission to use, copy, modify, and distribute this software and -COMMENT its documentation for any purpose and without fee is hereby granted, -COMMENT provided that the above copyright notices appear in all copies and -COMMENT that both those copyright notices and this permission notice appear -COMMENT in supporting documentation, and that the name -COMMENT Digital Equipment Corporation not be used in advertising or -COMMENT publicity pertaining to distribution of the software without -COMMENT specific, written prior permission. Digital -COMMENT Equipment Corporation makes no representations about the suitability -COMMENT of this software for any purpose. It is provided "as is" without -COMMENT express or implied warranty. -COMMENT -COMMENT DIGITAL EQUIPMENT CORPORATION DISCLAIMS ALL -COMMENT WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED -COMMENT WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -COMMENT DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, -COMMENT INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -COMMENT RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF -COMMENT CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -COMMENT CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -COMMENT -ENDPROPERTIES -CHARS 54 -COMMENT XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -STARTCHAR decw$c_select_cursor -ENCODING -1 0 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -15 -BITMAP -0000 -6000 -7800 -3E00 -3F80 -1FE0 -1FF8 -0F80 -0FC0 -06E0 -0670 -0238 -021c -000e -0004 -0000 -ENDCHAR -STARTCHAR decw$c_select_cursor_mask -ENCODING -1 1 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -15 -BITMAP -E000 -f800 -fe00 -7f80 -7fe0 -3ff8 -3ffc -1ff8 -1fe0 -0ff0 -0ff8 -077c -073e -021f -000e -0004 -ENDCHAR -STARTCHAR decw$c_help_cursor -ENCODING -1 2 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -14 -BITMAP -0000 -6000 -70e0 -3bf0 -1ff8 -0ff8 -07fc -0bfc -07fc -03fb -00f6 -002f -001e -000c -0000 -0000 -ENDCHAR -STARTCHAR decw$c_help_cursor_mask -ENCODING -1 3 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -14 -BITMAP -e000 -f0e0 -fbf0 -7ff8 -3ffc -1ffc -1ffe -1ffe -0fff -07ff -03ff -00ff -003e -001c -0000 -0000 -ENDCHAR -STARTCHAR decw$c_wait_cursor -ENCODING -1 4 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -14 -BITMAP -2000 -5548 -a814 -500a -23c4 -4760 -0f72 -4f70 -0c72 -4ff0 -07e2 -23c4 -100a -0815 -02aa -0004 -ENDCHAR -STARTCHAR decw$c_wait_cursor_mask -ENCODING -1 5 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -14 -BITMAP -3000 -7d48 -fffc -fffe -7ffc -7ffc -3ffe -7ffc -3ffe -7ffc -3ffe -3ffe -1fff -0fff -02be -000c -ENDCHAR -STARTCHAR decw$c_inactive_cursor -ENCODING -1 6 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -8 -BITMAP -07c0 -1830 -2008 -4004 -4004 -8002 -9ff2 -9ff2 -9ff2 -8002 -4004 -4004 -2008 -1830 -07c0 -0000 -ENDCHAR -STARTCHAR decw$c_inactive_cursor_mask -ENCODING -1 7 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -8 -BITMAP -07c0 -1ff0 -3ff8 -7ffc -7ffc -fffe -fffe -fffe -fffe -fffe -7ffc -7ffc -3ff8 -1ff0 -07c0 -0000 -ENDCHAR -STARTCHAR decw$c_resize_cursor -ENCODING -1 8 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -6 -9 -BITMAP -0000 -78f0 -4010 -5dd0 -5050 -1040 -0000 -1040 -5050 -5dd0 -4010 -78f0 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_resize_cursor_mask -ENCODING -1 9 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -6 -9 -BITMAP -f078 -f8f8 -f8f8 -fdf8 -7ff0 -18c0 -0880 -18c0 -7ff0 -fdf8 -f8f8 -f8f8 -f078 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_vpane_cursor -ENCODING -1 10 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -6 -8 -BITMAP -0200 -0500 -0880 -1240 -2720 -4f90 -8008 -7ff0 -8008 -4f90 -2720 -1240 -0880 -0500 -0200 -0000 -ENDCHAR -STARTCHAR decw$c_vpane_cursor_mask -ENCODING -1 11 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -6 -8 -BITMAP -0200 -0700 -0f80 -1fc0 -3fe0 -7ff0 -fff8 -7ff0 -fff8 -7ff0 -3fe0 -1fc0 -0f80 -0700 -0200 -0000 -ENDCHAR -STARTCHAR decw$c_hpane_cursor -ENCODING -1 12 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -7 -9 -BITMAP -0280 -0540 -0920 -1110 -2548 -4d64 -9d72 -4d64 -2548 -1110 -0920 -0540 -0280 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_hpane_cursor_mask -ENCODING -1 13 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -7 -9 -BITMAP -0280 -07c0 -0fe0 -1ff0 -3ff8 -7ffc -fffe -7ffc -3ff8 -1ff0 -0fe0 -07c0 -0280 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_text_insertion_cursor -ENCODING -1 14 -SWIDTH 0 0 -DWIDTH 7 0 -BBX 7 16 -3 -7 -BITMAP -0000 -8800 -5000 -2000 -2000 -2000 -2000 -2000 -2000 -2000 -2000 -2000 -2000 -5000 -8800 -0000 -ENDCHAR -STARTCHAR decw$c_text_insertion_cursor_mask -ENCODING -1 15 -SWIDTH 0 0 -DWIDTH 7 0 -BBX 7 16 -3 -7 -BITMAP -0000 -cc00 -7800 -3000 -3000 -3000 -3000 -3000 -3000 -3000 -3000 -3000 -3000 -7800 -cc00 -0000 -ENDCHAR -STARTCHAR decw$c_bitmap_text_insertion_cursor -ENCODING -1 16 -SWIDTH 0 0 -DWIDTH 8 0 -BBX 8 16 -3 -5 -BITMAP -0000 -4400 -2800 -1000 -1000 -1000 -1000 -1000 -1000 -1000 -aa00 -1000 -1000 -2800 -4400 -0000 -ENDCHAR -STARTCHAR decw$c_bitmap_text_insertion_cursor_mask -ENCODING -1 17 -SWIDTH 0 0 -DWIDTH 8 0 -BBX 8 16 -3 -5 -BITMAP -0000 -6600 -3c00 -1800 -1800 -1800 -1800 -1800 -1800 -1800 -ff00 -1800 -1800 -3c00 -6600 -0000 -ENDCHAR -STARTCHAR decw$c_crosshair_cursor -ENCODING -1 18 -SWIDTH 0 0 -DWIDTH 13 0 -BBX 13 13 -6 -6 -BITMAP -0700 -0500 -0500 -0500 -0500 -fdf8 -8008 -fdf8 -0500 -0500 -0500 -0500 -0700 -ENDCHAR -STARTCHAR decw$c_crosshair_cursor_mask -ENCODING -1 19 -SWIDTH 0 0 -DWIDTH 13 0 -BBX 13 13 -6 -6 -BITMAP -0700 -0700 -0700 -0700 -0700 -fff8 -fff8 -fff8 -0700 -0700 -0700 -0700 -0700 -ENDCHAR -STARTCHAR decw$c_draw_cursor -ENCODING -1 20 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 15 -8 -7 -BITMAP -0380 -0280 -06c0 -0820 -16d0 -2ee8 -ec6e -8002 -ec6e -2ee8 -16d0 -0820 -06c0 -0280 -0380 -ENDCHAR -STARTCHAR decw$c_draw_cursor_mask -ENCODING -1 21 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 15 -8 -7 -BITMAP -0380 -0380 -07c0 -0fe0 -1ff0 -3ff8 -fc7e -fc7e -fc7e -3ff8 -1ff0 -0fe0 -07c0 -0380 -0380 -ENDCHAR -STARTCHAR decw$c_rpencil_cursor -ENCODING -1 22 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -1 -2 -BITMAP -0000 -001C -001C -002C -00D0 -01E0 -03e0 -07c0 -0f80 -1f00 -1e00 -2c00 -3000 -4000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_rpencil_cursor_mask -ENCODING -1 23 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -1 -2 -BITMAP -001c -003e -007e -00fe -01fc -03f8 -07f0 -0fe0 -1fc0 -3f80 -3f00 -7e00 -7c00 -f000 -c000 -0000 -ENDCHAR -STARTCHAR decw$c_centercursor -ENCODING -1 24 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -5 -15 -BITMAP -0000 -0400 -0400 -0e00 -0e00 -1f00 -1f00 -3f80 -3f80 -64c0 -4440 -0400 -0400 -0400 -0400 -0000 -ENDCHAR -STARTCHAR decw$c_centercursor_mask -ENCODING -1 25 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -5 -15 -BITMAP -0400 -0e00 -0e00 -1f00 -1f00 -3f80 -3f80 -7fc0 -7fc0 -ffe0 -eee0 -ce60 -0e00 -0e00 -0e00 -0e00 -ENDCHAR -STARTCHAR decw$c_rightselect_cursor -ENCODING -1 26 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -15 -BITMAP -0000 -0006 -001e -007c -01fc -07f8 -1ff8 -01f0 -03f0 -0760 -0e60 -1c40 -3840 -7000 -2000 -0000 -ENDCHAR -STARTCHAR decw$c_rightselect_cursor_mask -ENCODING -1 27 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -15 -BITMAP -0007 -001f -007f -01fe -07fe -1ffc -3ffc -1ff8 -07f8 -0ff0 -1ff0 -3ee0 -7ce0 -f840 -7000 -2000 -ENDCHAR -STARTCHAR decw$c_wselect_cursor -ENCODING -1 28 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -10 -BITMAP -0000 -0060 -01c0 -0780 -1f80 -7ffe -1f80 -0780 -01c0 -0060 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_wselect_cursor_mask -ENCODING -1 29 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -10 -BITMAP -0070 -01f0 -07e0 -1fc0 -7fff -ffff -7fff -1fc0 -07e0 -01f0 -0070 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_eselect_cursor -ENCODING -1 30 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -10 -BITMAP -0000 -0600 -0380 -01e0 -01f8 -7ffe -01f8 -01e0 -0380 -0600 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_eselect_cursor_mask -ENCODING -1 31 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -10 -BITMAP -0e00 -0f80 -07e0 -03f8 -fffe -ffff -fffe -03f8 -07e0 -0f80 -0e00 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_x_cursor -ENCODING -1 32 -SWIDTH 0 0 -DWIDTH 13 0 -BBX 13 12 -6 -6 -BITMAP -e038 -9048 -4890 -2520 -1240 -0880 -0880 -1240 -2520 -4890 -9048 -e038 -ENDCHAR -STARTCHAR decw$c_x_cursor_mask -ENCODING -1 33 -SWIDTH 0 0 -DWIDTH 13 0 -BBX 13 12 -6 -6 -BITMAP -e038 -f078 -78f0 -3de0 -1fc0 -0f80 -0f80 -1fc0 -3de0 -78f0 -f078 -e038 -ENDCHAR -STARTCHAR decw$c_circle_cursor -ENCODING -1 34 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 13 -7 -7 -BITMAP -0700 -18c0 -2020 -4010 -4010 -8008 -8008 -8008 -4010 -4010 -2020 -18c0 -0700 -ENDCHAR -STARTCHAR decw$c_circle_cursor_mask -ENCODING -1 35 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 13 -7 -7 -BITMAP -0700 -1fc0 -38e0 -6030 -6030 -c018 -c018 -c018 -6030 -6030 -38e0 -1fc0 -0700 -ENDCHAR -STARTCHAR decw$c_mouse_cursor -ENCODING -1 36 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -7 -BITMAP -0000 -0000 -07c0 -1450 -2448 -2448 -4444 -7ffc -7ffc -7ffc -7ffc -3ff8 -3ff8 -1ff0 -07c0 -0000 -ENDCHAR -STARTCHAR decw$c_mouse_cursor_mask -ENCODING -1 37 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -7 -BITMAP -0100 -07c0 -1ff0 -3ff8 -7ffc -7ffc -fffe -fffe -fffe -fffe -fffe -7ffc -7ffc -3ff8 -1ff0 -07c0 -ENDCHAR -STARTCHAR decw$c_lpencil_cursor -ENCODING -1 38 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -1 -2 -BITMAP -0000 -3800 -3800 -3400 -0b00 -0780 -07c0 -03e0 -01f0 -00f8 -0078 -0034 -000c -0002 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_lpencil_cursor_mask -ENCODING -1 39 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -1 -2 -BITMAP -3800 -7c00 -7e00 -7f00 -3f80 -1fc0 -0fe0 -07f0 -03f8 -01fc -00fc -007e -003e -000f -0003 -0000 -ENDCHAR -STARTCHAR decw$c_leftgrab_cursor -ENCODING -1 40 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -15 -BITMAP -0000 -6c00 -3680 -5b40 -6da0 -36f0 -1bf8 -0ff8 -07f8 -3bf8 -0ff6 -07ee -005c -003c -0018 -0000 -ENDCHAR -STARTCHAR decw$c_leftgrab_cursor_mask -ENCODING -1 41 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -15 -BITMAP -6c00 -ff80 -7fc0 -ffe0 -fff0 -7ff8 -3ffc -1ffc -3ffc -7ffe -7fff -0ffe -07fe -007c -0038 -0010 -ENDCHAR -STARTCHAR decw$c_grabhand_cursor -ENCODING -1 42 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -15 -BITMAP -0000 -0100 -0540 -0540 -0540 -0550 -6550 -37d0 -17f0 -1ff0 -1ff0 -0ff0 -07e0 -07e0 -0000 -07e0 -ENDCHAR -STARTCHAR decw$c_grabhand_cursor_mask -ENCODING -1 43 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -8 -15 -BITMAP -0100 -07c0 -0fe0 -0fe0 -0ff0 -6ff8 -fff8 -7ff8 -3ff8 -3ff8 -3ff8 -1ff8 -0ff0 -0ff0 -0ff0 -0ff0 -ENDCHAR -STARTCHAR decw$c_rightgrab_cursor -ENCODING -1 44 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -15 -BITMAP -0000 -0036 -016c -02da -05b6 -0f6c -1fd8 -1ff0 -1fe0 -1fdc -6ff0 -77e0 -3a00 -3c00 -1800 -0000 -ENDCHAR -STARTCHAR decw$c_rightgrab_cursor_mask -ENCODING -1 45 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -15 -BITMAP -0036 -01ff -03fe -07ff -0fff -1ffe -3ffc -3ff8 -3ffc -7ffe -fffe -7ff0 -7fe0 -3e00 -1c00 -0800 -ENDCHAR -STARTCHAR decw$c_leftpointing_cursor -ENCODING -1 46 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -13 -BITMAP -0000 -00e0 -7ff0 -01fb -07fb -03fb -03fa -01f3 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_leftpointing_cursor_mask -ENCODING -1 47 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 0 -13 -BITMAP -03e0 -7ff0 -ffff -7fff -0fff -0fff -07ff -07ff -03f7 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_uppointing_cursor -ENCODING -1 48 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -15 -BITMAP -0000 -2000 -2000 -2000 -2000 -2800 -3e00 -3f00 -7f00 -7f00 -7f00 -3f00 -1e00 -0000 -1f00 -1d00 -ENDCHAR -STARTCHAR decw$c_uppointing_cursor_mask -ENCODING -1 49 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -2 -15 -BITMAP -2000 -7000 -7000 -7000 -7c00 -7f00 -ff80 -ff80 -ff80 -ff80 -ff80 -7f80 -3f00 -3f80 -3f80 -3f80 -ENDCHAR -STARTCHAR decw$c_rightpointing_cursor -ENCODING -1 50 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -13 -BITMAP -0000 -0700 -0ffe -df80 -dfe0 -dfc0 -5fc0 -cf80 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_rightpointing_cursor_mask -ENCODING -1 51 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -15 -13 -BITMAP -07c0 -0ffe -ffff -fffe -fff0 -fff0 -ffe0 -ffe0 -efc0 -0000 -0000 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_check_cursor -ENCODING -1 52 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -5 -6 -BITMAP -000e -0012 -0024 -0048 -e090 -9120 -4a40 -2480 -1100 -0a00 -0400 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -STARTCHAR decw$c_check_cursor_mask -ENCODING -1 53 -SWIDTH 0 0 -DWIDTH 16 0 -BBX 16 16 -5 -6 -BITMAP -000e -001e -003c -0078 -e0f0 -f1e0 -7bc0 -3f80 -1f00 -0e00 -0400 -0000 -0000 -0000 -0000 -0000 -ENDCHAR -ENDFONT diff --git a/resource/logo/102x47.png b/resource/logo/102x47.png index 54dade6d..b00815fd 100644 Binary files a/resource/logo/102x47.png and b/resource/logo/102x47.png differ diff --git a/resource/logo/banner-nodejs.png b/resource/logo/banner-nodejs.png new file mode 100644 index 00000000..5d347575 Binary files /dev/null and b/resource/logo/banner-nodejs.png differ diff --git a/resource/logo/banner.pov b/resource/logo/banner.pov index 2b6f33d3..0f4e3ec7 100644 --- a/resource/logo/banner.pov +++ b/resource/logo/banner.pov @@ -1,14 +1,41 @@ #declare BASE = 1; #include "resource/logo/logo.pov" +#ifdef(VERSION) +object { + text { + ttf "resource/font/IBMPlexSerif.ttf", + VERSION, + 1, 0 + } + scale 5 + translate <7.5, 0, 1> + pigment { + color Red + } + finish { + phong 1 + reflection 0.3 + } +} +#end + object { text { ttf "resource/font/IBMPlexSerif.ttf", +#ifdef(NODEJS) + "for Node.JS", +#else "Milsko Toolkit", +#end 1, 0 } scale 2 +#ifdef(NODEJS) + translate <5, -1, -1> +#else translate <2.5, -1, -1> +#end pigment { color White } diff --git a/resource/logo/banner_10.pov b/resource/logo/banner_10.pov new file mode 100644 index 00000000..a306e982 --- /dev/null +++ b/resource/logo/banner_10.pov @@ -0,0 +1,2 @@ +#declare VERSION="1.0"; +#include "resource/logo/banner.pov" diff --git a/resource/logo/logo.pov b/resource/logo/logo.pov index b86f23ec..5348056e 100644 --- a/resource/logo/logo.pov +++ b/resource/logo/logo.pov @@ -17,6 +17,7 @@ sky_sphere { } } +union { object { Cube translate <-1, 0, 1> @@ -57,6 +58,9 @@ object { } } +rotate <0, clock * 360, 0> +} + plane { y, -1 pigment { diff --git a/resource/logo/logo64.png b/resource/logo/logo64.png deleted file mode 100644 index 56678711..00000000 Binary files a/resource/logo/logo64.png and /dev/null differ diff --git a/resource/milsko.pc.in b/resource/milsko.pc.in new file mode 100644 index 00000000..9cdc61e9 --- /dev/null +++ b/resource/milsko.pc.in @@ -0,0 +1,10 @@ +prefix="@CMAKE_INSTALL_PREFIX@" +includedir="@CMAKE_INSTALL_PREFIX@/include" +libdir="@CMAKE_INSTALL_PREFIX@/bin" + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +URL: @PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ +Cflags: -I"${includedir}"/ +Libs: -L"${libdir}" -lMw diff --git a/resource/wayland/wlr-layer-shell-unstable-v1.xml b/resource/wayland/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 00000000..f9ee0ff7 --- /dev/null +++ b/resource/wayland/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,451 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + After creating a layer_surface object and setting it up, the client + must perform an initial commit without any buffer attached. + The compositor will reply with a layer_surface.configure event. + The client must acknowledge it and is then allowed to attach a buffer + to map the surface. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + + This request indicates that the client will not use the layer_shell + object any more. Objects that have been created through this instance + are not affected. + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + Attaching a null buffer to a layer surface unmaps it. + + Unmapping a layer_surface means that the surface cannot be shown by the + compositor until it is explicitly mapped again. The layer_surface + returns to the state it had right after layer_shell.get_layer_surface. + The client can re-map the surface by performing a commit without any + buffer attached, waiting for a configure event and handling it as usual. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Types of keyboard interaction possible for layer shell surfaces. The + rationale for this is twofold: (1) some applications are not interested + in keyboard events and not allowing them to be focused can improve the + desktop experience; (2) some applications will want to take exclusive + keyboard focus. + + + + + This value indicates that this surface is not interested in keyboard + events and the compositor should never assign it the keyboard focus. + + This is the default value, set for newly created layer shell surfaces. + + This is useful for e.g. desktop widgets that display information or + only have interaction with non-keyboard input devices. + + + + + Request exclusive keyboard focus if this surface is above the shell surface layer. + + For the top and overlay layers, the seat will always give + exclusive keyboard focus to the top-most layer which has keyboard + interactivity set to exclusive. If this layer contains multiple + surfaces with keyboard interactivity set to exclusive, the compositor + determines the one receiving keyboard events in an implementation- + defined manner. In this case, no guarantee is made when this surface + will receive keyboard focus (if ever). + + For the bottom and background layers, the compositor is allowed to use + normal focus semantics. + + This setting is mainly intended for applications that need to ensure + they receive all keyboard events, such as a lock screen or a password + prompt. + + + + + This requests the compositor to allow this surface to be focused and + unfocused by the user in an implementation-defined manner. The user + should be able to unfocus this surface even regardless of the layer + it is on. + + Typically, the compositor will want to use its normal mechanism to + manage keyboard focus between layer shell surfaces with this setting + and regular toplevels on the desktop layer (e.g. click to focus). + Nevertheless, it is possible for a compositor to require a special + interaction to focus or unfocus layer shell surfaces (e.g. requiring + a click even if focus follows the mouse normally, or providing a + keybinding to switch focus between layers). + + This setting is mainly intended for desktop shell components (e.g. + panels) that allow keyboard interaction. Using this option can allow + implementing a desktop shell that can be fully usable without the + mouse. + + + + + + + Set how keyboard events are delivered to this surface. By default, + layer shell surfaces do not receive keyboard events; this request can + be used to change this. + + This setting is inherited by child surfaces set by the get_popup + request. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Keyboard interactivity is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/src/abstract/charset.c b/src/abstract/charset.c new file mode 100644 index 00000000..3bd76252 --- /dev/null +++ b/src/abstract/charset.c @@ -0,0 +1,95 @@ +#include + +#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif + +char* MwACPToUTF8(const char* input) { +#if defined(_WIN32) && defined(MW_HAS_WCHAR) + int mbbytes = (strlen(input) + 1) * 4; + int wbytes = 0; + int len; + + wchar_t* wout; + char* mbout = malloc(mbbytes); + + wbytes = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); + if(wbytes == 0) { + free(mbout); + return MwStringDuplicate(input); + } + + wout = malloc(wbytes + sizeof(wchar_t)); + len = wbytes / sizeof(wchar_t); + + memset(wout, 0, wbytes); + memset(mbout, 0, mbbytes); + + len = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), wout, len); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + wout[len] = 0; + + len = WideCharToMultiByte(CP_UTF8, 0, wout, len, mbout, mbbytes, 0, 0); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + mbout[len] = 0; + + free(wout); + + return mbout; +#else + return MwStringDuplicate(input); +#endif +} + +char* MwUTF8ToACP(const char* input) { +#if defined(_WIN32) && defined(MW_HAS_WCHAR) + int mbbytes = (strlen(input) + 1) * 4; + int wbytes = 0; + int len; + + wchar_t* wout; + char* mbout = malloc(mbbytes); + + wbytes = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); + if(wbytes == 0) { + free(mbout); + return MwStringDuplicate(input); + } + + wout = malloc(wbytes + sizeof(wchar_t)); + len = wbytes / sizeof(wchar_t); + + memset(wout, 0, wbytes); + memset(mbout, 0, mbbytes); + + len = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), wout, len); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + wout[len] = 0; + + len = WideCharToMultiByte(CP_ACP, 0, wout, len, mbout, mbbytes, 0, 0); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + mbout[len] = 0; + + free(wout); + + return mbout; +#else + return MwStringDuplicate(input); +#endif +} diff --git a/src/abstract/directory.c b/src/abstract/directory.c index ac5a382d..ddf10e15 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -19,15 +19,19 @@ typedef struct dir { void* MwDirectoryOpen(const char* path) { dir_t* dir = malloc(sizeof(*dir)); -#ifdef _WIN32 - char* p = malloc(strlen(path) + 2 + 1); - strcpy(p, path); - if(strchr(path, '/') != NULL) { - strcat(p, "/"); - } else { - strcat(p, "\\"); + char * p; + if(!dir) { + printf("Out Of Memory\n"); + return NULL; } - strcat(p, "*"); +#ifdef _WIN32 + p = MwStringDuplicate(path); + if(strchr(path, '/') != NULL) { + MwStringConcat(p, "/"); + } else { + MwStringConcat(p, "\\"); + } + MwStringConcat(p, "*"); if((dir->hFind = FindFirstFile(p, &dir->ffd)) == INVALID_HANDLE_VALUE) { free(p); free(dir); @@ -66,8 +70,19 @@ MwDirectoryEntry* MwDirectoryRead(void* handle) { dir_t* dir = handle; MwDirectoryEntry* entry = malloc(sizeof(*entry)); #ifdef _WIN32 - ULARGE_INTEGER* l; - + ULARGE_INTEGER* l; +#elif defined(CLASSIC_MAC_OS) +#else + struct dirent* d; + struct stat s; + char* p; +#endif + + if(!entry) { + printf("Out Of Memory\n"); + return NULL; + } +#ifdef _WIN32 if(!dir->next) return NULL; entry->name = MwStringDuplicate(dir->ffd.cFileName); @@ -91,9 +106,6 @@ MwDirectoryEntry* MwDirectoryRead(void* handle) { #elif defined(CLASSIC_MAC_OS) /* todo */ #else - struct dirent* d; - struct stat s; - char* p; if((d = readdir(dir->dir)) == NULL) { free(entry); return NULL; @@ -170,8 +182,8 @@ static void MwDirectoryJoinSingle(char* target, char* p) { b[0] = DIRSEP; b[1] = 0; - strcat(target, b); - strcat(target, p); + MwStringConcat(target, b); + MwStringConcat(target, p); } for(i = strlen(target) - 1; i >= 0; i--) { @@ -187,17 +199,16 @@ static void MwDirectoryJoinSingle(char* target, char* p) { b[0] = DIRSEP; b[1] = 0; - strcat(target, b); + MwStringConcat(target, b); } } char* MwDirectoryJoin(char* a, char* b) { - char* p = malloc(strlen(a) + 1 + strlen(b) + 1); + char* p = MwStringDuplicate(a); char* bdup = MwStringDuplicate(b); char* b2 = bdup; int i; - strcpy(p, a); for(i = strlen(p) - 1; i >= 0; i--) { if(p[i] == DIRSEP) { p[i] = 0; diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index ae31e82b..58bc8312 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -48,7 +48,7 @@ void MwDynamicClose(void* handle) { // CFragConnectionID connID = (CFragConnectionID)handle; // CloseConnection(&connID); } -#elif defined(__unix__) || defined(__APPLE__) +#elif defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) void* MwDynamicOpen(const char* path) { return dlopen(path, RTLD_LOCAL | RTLD_LAZY); } diff --git a/src/abstract/time.c b/src/abstract/time.c index cd09b94d..892cd322 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -2,7 +2,7 @@ #if defined(_WIN32) long MwTimeGetTick(void) { - return GetTickCount(); + return MwLL_PFN_timeGetTime(); } void MwTimeSleep(int ms) { @@ -55,7 +55,7 @@ void MwTimeSleep(int ms) { // DisposeTimerUPP(tm.tmAddr); } -#elif defined(__unix__) +#elif defined(__unix__) || defined(__HAIKU__) long MwTimeGetTick(void) { struct timespec ts; long n = 0; diff --git a/src/backend/cairo.c b/src/backend/cairo.c new file mode 100644 index 00000000..65380fba --- /dev/null +++ b/src/backend/cairo.c @@ -0,0 +1,266 @@ +#include + +#include "../../external/stb_ds.h" + +cairo_call_table_t cairo_call_tbl; + +void MwLLCairoPolygon(struct _MwLLCairo handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo); + for(i = 0; i < points_count; i++) { + if(i == 0) { + cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle.front_cairo); + + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_SOURCE); + cairo_fill(handle.front_cairo); + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); +}; + +void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { + int i; + + cairo_set_antialias(handle.front_cairo, CAIRO_ANTIALIAS_NONE); + cairo_set_line_cap(handle.front_cairo, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo); + for(i = 0; i < 2; i++) { + if(i == 0) { + cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle.front_cairo); + cairo_stroke(handle.front_cairo); +}; + +MwLLPixmap MwLLCairoCreatePixmap(struct _MwLLCairo handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + (void)handle; + + if(width >= INT16_MAX) width = INT16_MAX; + if(height >= INT16_MAX) height = INT16_MAX; + + r->common.width = width; + r->common.height = height; + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->wayland.cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + + MwLLPixmapUpdate(r); + + return r; +} + +void MwLLCairoPixmapUpdate(MwLLPixmap r) { + int i; + unsigned char* d; + + cairo_surface_flush(r->wayland.cs); + d = cairo_image_surface_get_data(r->wayland.cs); + for(i = 0; i < r->common.width * r->common.height * 4; i += 4) { + MwU32* p = (MwU32*)&d[i]; + *p <<= 8; + *p |= r->common.raw[i + 3]; + *p <<= 8; + *p |= r->common.raw[i + 0]; + *p <<= 8; + *p |= r->common.raw[i + 1]; + *p <<= 8; + *p |= r->common.raw[i + 2]; + } + cairo_surface_mark_dirty(r->wayland.cs); +} + +void MwLLCairoDestroyPixmap(MwLLPixmap pixmap) { + cairo_surface_destroy(pixmap->wayland.cs); + free(pixmap->common.raw); + free(pixmap); +} + +void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixmap) { + cairo_t* c; + cairo_surface_t* cs; + cairo_t* selected_cairo = handle.selected_cairo ? handle.selected_cairo : handle.front_cairo; + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); + c = cairo_create(cs); + + if(rect->width <= 0 || rect->height <= 0 || pixmap->common.width <= 0 || pixmap->common.height <= 0) return; + if(rect->width >= INT16_MAX) rect->width = INT16_MAX; + if(rect->height >= INT16_MAX) rect->height = INT16_MAX; + + cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); + + cairo_set_source_surface(c, pixmap->cairo.cs, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); + + cairo_paint(c); + + cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); + cairo_paint(selected_cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); +}; + +void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { + if(data) { + cairo->front_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4); + } else { + cairo->front_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + } + cairo->front_cairo = cairo_create(cairo->front_cs); +} + +void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { + if(data) { + cairo->back_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4); + } else { + cairo->back_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + } + cairo->back_cairo = cairo_create(cairo->back_cs); +} + +void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo) { + cairo_destroy(cairo->front_cairo); + cairo_surface_destroy(cairo->front_cs); +}; +void MwLLCairoBackDestroy(struct _MwLLCairo* cairo) { + cairo_destroy(cairo->back_cairo); + cairo_surface_destroy(cairo->back_cs); +}; + +void MwLLCairoDestroy(struct _MwLLCairo handle) { + // MwLLCairoFrontDestroy(&handle); + // MwLLCairoBackDestroy(&handle); +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + r->cairo.width = width; + r->cairo.height = height; + r->cairo.x = x; + r->cairo.y = x; + + r->cairo.toplevel = !parent; + r->cairo.parent = parent; + + MwLLCairoFrontSetup(&r->cairo, NULL, r->cairo.width, r->cairo.height); + MwLLCairoBackSetup(&r->cairo, NULL, r->cairo.width, r->cairo.height); + + return r; +} +static void MwLLDestroyImpl(MwLL handle) { + MwLLCairoDestroy(handle->cairo); + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + handle->cairo.selected_cairo = handle->cairo.front_cairo; +} +static void MwLLEndDrawImpl(MwLL handle) { +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + MwLLCairoPolygon(handle->cairo, points, points_count, color); +} +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MwLLCairoLine(handle->cairo, points, color); +} +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + (void)handle; + *x = handle->cairo.x; + *y = handle->cairo.y; + *w = handle->cairo.width; + *h = handle->cairo.height; +} +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + handle->cairo.x = x; + handle->cairo.y = y; +} +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + handle->cairo.width = w; + handle->cairo.height = h; +} +static void MwLLFreeColorImpl(MwLLColor color) {} + +static MwBool lmao = MwFALSE; +static int MwLLPendingImpl(MwLL handle) { + lmao = !lmao; + return lmao; +} +static void MwLLNextEventImpl(MwLL handle) { + MwLLDispatch(handle, draw, NULL); +} +static void MwLLSetTitleImpl(MwLL handle, const char* title) {} +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + return MwLLCairoCreatePixmap(handle->cairo, data, width, height); +} +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + MwLLCairoPixmapUpdate(r); +} +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + MwLLCairoPixmapUpdate(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + MwLLCairoDrawPixmap(handle->cairo, rect, pixmap); +} +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {} +static void MwLLForceRenderImpl(MwLL handle) {} +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) {} +static void MwLLDetachImpl(MwLL handle, MwPoint* point) {} +static void MwLLShowImpl(MwLL handle, int show) {} +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {} +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) {} +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) {} +static void MwLLFocusImpl(MwLL handle) {} +static void MwLLGrabPointerImpl(MwLL handle, int toggle) {} +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) {} +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) {} +static void MwLLMakeToolWindowImpl(MwLL handle) {} +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) {} +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) {} +static void MwLLBeginStateChangeImpl(MwLL handle) {} +static void MwLLEndStateChangeImpl(MwLL handle) {} +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) {} +static MwBool MwLLDoModernImpl(MwLL handle) { + return MwFALSE; +} +static void MwLLRaiseImpl(MwLL handle) {} +static void MwLLClipImpl(MwLL handle, MwRect* rect) {} +static void MwLLSetupDragAndDropImpl(MwLL handle) {} +static int MwLLCairoCallInitImpl(void) { + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; +} +#include "call.c" +CALL(Cairo); diff --git a/src/backend/call.c b/src/backend/call.c index 14338ecc..0deffb49 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -52,10 +52,15 @@ MwLLSetClipboard = MwLLSetClipboardImpl; \ MwLLGetClipboard = MwLLGetClipboardImpl; \ \ - MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ - MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ + MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ + MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ + MwLLSetupDragAndDrop = MwLLSetupDragAndDropImpl; \ \ MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ + MwLLDoModern = MwLLDoModernImpl; \ \ + MwLLRaise = MwLLRaiseImpl; \ +\ + MwLLClip = MwLLClipImpl; \ return 0; \ } diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index d7db4331..f0635510 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -1,6 +1,5 @@ #include #include -#include #include "../../external/stb_ds.h" @@ -53,9 +52,6 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL col.green = color->common.green * 0x101; col.blue = color->common.blue * 0x101; - RGBForeColor(&col); - PenMode(patCopy); - for(i = 0; i < points_count; i++) { if(i == 0) { MoveTo(points[i].x, points[i].y); @@ -65,7 +61,11 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } ClosePoly(); - FillCPoly(p, &qd.ltGray); + + PenMode(patCopy); + RGBForeColor(&col); + PaintPoly(p); + KillPoly(p); EndUpdate(handle->cmacos.window); @@ -130,13 +130,29 @@ static void MwLLNextEventImpl(MwLL handle) { GetNextEvent(everyEvent, &event); switch(event.what) { - case updateEvt: { - } - // MwLLDispatch(handle, draw, NULL); - break; + case updateEvt: + { + /* + This is our blocker for getting anything running. + This needs to be called at this point to start drawing anything. + ...It locks up and/or crashes the entire system. At least on SheepShaver. + It's not a stack overflow, it's not anything in the drawing functions. + It's *something* else. But because Classic Mac OS development is like + digging up forbidden tombs while stabbing yourself in the eye several times, + I don't know what. + + Fun fact: for as much as everyone loves to glaze about AI being the future + of programming, even Claude got confused when I gave up and tried to ask it + for help. Information about Classic Mac OS probably takes up 0.0001% of its + knowledge base; god knows it's hard enough finding information online about + this! + */ + MwLLDispatch(handle, draw, NULL); + } break; case osEvt: break; - case mouseUp: { + case mouseUp: + { // MwLLMouse m; // m.button = MwLLMouseLeft; // if(___curWindow->mouseButtonCallback != NULL) { @@ -151,7 +167,8 @@ static void MwLLNextEventImpl(MwLL handle) { // } // } } - case mouseDown: { + case mouseDown: + { // // start with callback stuff // if(___curWindow->mouseButtonCallback != NULL) { // int mods = MacModifiersToGLFWModifiers(event.modifiers); @@ -174,7 +191,8 @@ static void MwLLNextEventImpl(MwLL handle) { // event.where.v); // } break; - case inGrow: { + case inGrow: + { long growResult = GrowWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); @@ -201,7 +219,8 @@ static void MwLLNextEventImpl(MwLL handle) { // } } break; - case inGoAway: { + case inGoAway: + { if(TrackGoAway(handle->cmacos.window, event.where)) { MwLLDispatch(handle, close, NULL); // if(___curWindow->windowCloseCallback != NULL) { @@ -214,7 +233,8 @@ static void MwLLNextEventImpl(MwLL handle) { } case autoKey: case keyDown: - case keyUp: { + case keyUp: + { // // key char stuff // unsigned char ch = (event.message & charCodeMask); // if(*___curWindow->charCallback != NULL) { @@ -327,6 +347,10 @@ static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } @@ -340,6 +364,20 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; } +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwFALSE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLClassicMacOSCallInitImpl(void) { InitGraf(&qd.thePort); InitFonts(); diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index d9c6382e..85b8b5bd 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,10 @@ +/* + * some implementation notes to know: + * - Mac really does not like immediate mode drawing, there was some trick I tried where I rendered to a bitmap context but it was very slow. So instead we just convert it to a commands system which gets cleared out whenever MacOS Actually draws the window. + * - We override NSApplication to intercept sendEvent and know when an event has been sent. When it is, doPending is sent. The appropriate "pending" function then returns whether that's set (before resetting it). + * - We want the application to be *functional* on old MacOS, at a minimum of 10.4. There's obviously points where newer functions will have to be used, and in that case we use ObjC's "respondsToSelector" function to know if we can call the newer function. + */ + #include #include "../../external/stb_ds.h" #include "Mw/LowLevel/Cocoa.h" @@ -12,6 +19,17 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif +/* + * GNUStep has the modal session be a global singleton and once we assign it we can't do any more. This breaks several widgets. + * I barely care about supporting this so we'll just not support that, sorry. + */ +#ifndef __APPLE__ +static bool canAssignModalSession = MwTRUE; +#else +#define canAssignModalSession 1 +#endif + +/* Coordinate flipping function (global, rect) */ static NSRect rectFlip(NSRect originFrame) { NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; double screenHeight = [zeroScreen frame].size.height; @@ -23,10 +41,12 @@ static NSRect rectFlip(NSRect originFrame) { return destinationFrame; } -static NSPoint pointFlip(NSPoint point) { +/* Coordinate flipping function (global, point) */ +static inline NSPoint pointFlip(NSPoint point) { return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; } +/* Coordinate flipping function (local to view; rect) */ static NSRect localRectFlip(NSRect originFrame, NSView* view) { float viewHeight = [view bounds].size.height; NSRect destinationFrame = @@ -36,7 +56,9 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { originFrame.size.width, originFrame.size.height); return destinationFrame; } -static NSPoint localPointFlip(NSPoint point, NSView* view) { + +/* Coordinate flipping function (local to view; point) */ +static inline NSPoint localPointFlip(NSPoint point, NSView* view) { return localRectFlip(NSMakeRect(point.x, point.y, 0, 0), view).origin; } @@ -106,7 +128,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { for(i = 0; i < arrlen(self->commands); i++) { draw_command cmd = self->commands[i]; switch(cmd.type) { - case COCOA_DRAW_COMMAND_POLY: { + case COCOA_DRAW_COMMAND_POLY: + { int n; NSBezierPath* path = [NSBezierPath bezierPath]; @@ -119,6 +142,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [nscolor setFill]; for(n = 0; n < cmd.poly.points_count; n++) { NSPoint p = localPointFlip(NSMakePoint(cmd.poly.points[n].x, cmd.poly.points[n].y), self); + p.x += [self bounds].origin.x; + p.y += [self bounds].origin.y; if(n == 0) { [path moveToPoint:p]; } else { @@ -132,7 +157,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { free(cmd.poly.points); } break; - case COCOA_DRAW_COMMAND_LINES: { + case COCOA_DRAW_COMMAND_LINES: + { int n; NSBezierPath* path = [NSBezierPath bezierPath]; @@ -145,6 +171,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [nscolor setFill]; for(n = 0; n < 2; n++) { NSPoint p = localPointFlip(NSMakePoint(cmd.lines.points[n].x, cmd.lines.points[n].y), self); + p.x += [self bounds].origin.x; + p.y += [self bounds].origin.y; if(n == 0) { [path moveToPoint:p]; } else { @@ -158,9 +186,13 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { free(cmd.lines.points); } break; - case COCOA_DRAW_COMMAND_PIXMAP: { + case COCOA_DRAW_COMMAND_PIXMAP: + { + NSRect rect = localRectFlip(NSMakeRect(cmd.pixmap.rect.x, cmd.pixmap.rect.y, cmd.pixmap.rect.width, cmd.pixmap.rect.height), self); + rect.origin.x += [self bounds].origin.x; + rect.origin.y += [self bounds].origin.y; [cmd.pixmap.pixmap->cocoa.real->image - drawInRect:localRectFlip(NSMakeRect(cmd.pixmap.rect.x, cmd.pixmap.rect.y, cmd.pixmap.rect.width, cmd.pixmap.rect.height), self) + drawInRect:rect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; @@ -174,6 +206,10 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [pool release]; } +- (BOOL)isFlipped { + return NO; +} + - (BOOL)canBecomeKeyView { return YES; } @@ -181,14 +217,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { return YES; } -- (NSView*)hitTest:(NSPoint)aPoint { - if(self->_child) { - return NSPointInRect(aPoint, [self bounds]) ? self : nil; - } else { - return [super hitTest:aPoint]; - } -} - - (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll down:(MwBool)isDown { int ch; /* todo: consolidate these values into the below switch case. */ @@ -298,23 +326,23 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { KEY_CASE(kVK_ANSI_Backslash, '/') KEY_CASE(kVK_ANSI_Comma, ',') KEY_CASE(kVK_ANSI_Equal, '=') - KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_Escape, MwKEY_ESCAPE) KEY_CASE(kVK_ANSI_LeftBracket, '[') KEY_CASE(kVK_ANSI_Minus, '-') KEY_CASE(kVK_ANSI_Period, '.') - KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_Return, MwKEY_ENTER) KEY_CASE(kVK_ANSI_RightBracket, ']') KEY_CASE(kVK_ANSI_Semicolon, ';') KEY_CASE(kVK_ANSI_Slash, '\\') KEY_CASE(kVK_Space, ' ') - KEY_CASE(kVK_Control, MwLLKeyControl) - KEY_CASE(kVK_RightControl, MwLLKeyControl) - KEY_CASE(kVK_Shift, MwLLKeyLeftShift) - KEY_CASE(kVK_RightShift, MwLLKeyRightShift) - KEY_CASE(kVK_DownArrow, MwLLKeyDown) - KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) - KEY_CASE(kVK_RightArrow, MwLLKeyRight) - KEY_CASE(kVK_UpArrow, MwLLKeyUp) + KEY_CASE(kVK_Control, MwKEY_CONTROL) + KEY_CASE(kVK_RightControl, MwKEY_CONTROL) + KEY_CASE(kVK_Shift, MwKEY_LEFTSHIFT) + KEY_CASE(kVK_RightShift, MwKEY_RIGHTSHIFT) + KEY_CASE(kVK_DownArrow, MwKEY_DOWN) + KEY_CASE(kVK_LeftArrow, MwKEY_LEFT) + KEY_CASE(kVK_RightArrow, MwKEY_RIGHT) + KEY_CASE(kVK_UpArrow, MwKEY_UP) } if(isDown) { recursive_dispatch_key(ll, &ch); @@ -348,13 +376,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (void)mouseMoved:(NSEvent*)ev { MwMouse mouse; - NSPoint mousePoint = pointFlip([ev locationInWindow]); + NSPoint mousePoint = [ev locationInWindow]; MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mouse.button = MwMOUSE_LEFT; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, move, &mouse); - [this->cocoa.real nudge]; [super mouseMoved:ev]; } - (BOOL)mouseDownCanMoveWindow { @@ -370,7 +397,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); - [this->cocoa.real nudge]; [super mouseDown:ev]; } @@ -383,7 +409,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); - [this->cocoa.real nudge]; [super mouseUp:ev]; } - (void)rightMouseDown:(NSEvent*)ev { @@ -395,7 +420,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); - [this->cocoa.real nudge]; [super rightMouseDown:ev]; } @@ -408,7 +432,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); - [this->cocoa.real nudge]; [super rightMouseUp:ev]; } @@ -425,11 +448,14 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; { - if([[[win contentView] subviews] count] >= 1) { - NSView* ptr = [[[win contentView] subviews] objectAtIndex:0]; + int i; + NSUInteger placeholder = [[[win contentView] subviews] count]; + for(i = 0; i < placeholder; i++) { + NSView* ptr = [[[win contentView] subviews] objectAtIndex:i]; if([ptr isKindOfClass:[MilskoFakePointer class]]) { MwLL h = [(MilskoFakePointer*)ptr pointer]; MwLLDispatch(h, resize, NULL); + break; } } return frameSize; @@ -454,6 +480,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] objectAtIndex:0]) pointer]; MwLLDispatch(h, close, NULL); + h->cocoa.real->isClosing = MwTRUE; } } @@ -551,6 +578,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @implementation MilskoCocoa - (void)sendClipboardEvent { + /* Either uncomment this and make it use respondsToSelector and/or find out what the api proceeding NSPasteboard is. */ /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSArray* items = @[ @@ -598,14 +626,33 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)nudge { - MwLL p = self->parent; - self->_eventsPending = MwTRUE; + MwLL topmost_parent = [self->handle pointer]; + MwWidget h; - while(p) { - MwLLDispatch(p, draw, NULL); - [p->cocoa.real->view setNeedsDisplay:true]; - p = p->cocoa.real->parent; + while(topmost_parent->cocoa.real->parent) topmost_parent = topmost_parent->cocoa.real->parent; + + if(!topmost_parent->cocoa.real->isClosing) + self->_eventsPending = MwTRUE; + + [topmost_parent->cocoa.real->view setNeedsDisplay:true]; + MwLLDispatch(topmost_parent, draw, NULL); + + h = (MwWidget)topmost_parent->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + [h->children[i]->lowlevel->cocoa.real->view setNeedsDisplay:true]; + MwLLDispatch(h->children[i]->lowlevel, draw, NULL); + } } + + // MwLL p = self->parent; + // self->_eventsPending = MwTRUE; + + // while(p) { + // MwLLDispatch(p, draw, NULL); + // p = p->cocoa.real->parent; + // } } - (void)pushCursor { @@ -639,11 +686,10 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { * respond appropriately. Also for child windows just have it be 0. */ if(x == MwDEFAULT) { - x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; + x = parent ? 0 : ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); } if(y == MwDEFAULT) { - y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) - : 0; + y = parent ? 0 : ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); } c->rect = NSMakeRect(x, y, width, height); @@ -678,14 +724,20 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { [c->application retain]; [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; - c->modalSession = [c->application beginModalSessionForWindow:c->window]; + if(canAssignModalSession) + c->modalSession = [c->application beginModalSessionForWindow:c->window]; + +#ifndef __APPLE__ + canAssignModalSession = MwFALSE; +#endif + } else { MilskoCocoa* p = parent->cocoa.real; NSRect rect = localRectFlip(c->rect, p->view); c->window = p->window; c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; - [c->view setBounds:c->rect]; + [c->view setBounds:rect]; [c->view retain]; [c->view setChild]; @@ -715,6 +767,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { [pool release]; + c->isClosing = MwFALSE; + r->cocoa.real = c; return r; @@ -736,7 +790,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { (void)handle; - [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; + // [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, @@ -751,6 +805,8 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, memcpy(poly.poly.points, points, sizeof(MwPoint) * points_count); arrpush(handle->cocoa.real->view->commands, poly); + + [handle->cocoa.real nudge]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -763,6 +819,8 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { memcpy(lines.lines.points, points, sizeof(MwPoint) * 2); arrpush(handle->cocoa.real->view->commands, lines); + + [handle->cocoa.real nudge]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -816,29 +874,37 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(!self->parent) { frame = rectFlip(frame); - [self->window setFrame:frame display:MwTRUE animate:MwTRUE]; + [self->window setFrame:frame display:MwTRUE animate:false]; } else { frame = localRectFlip(frame, self->parent->cocoa.real->view); [self->view setFrame:frame]; + [self->view setBounds:frame]; } - [self nudge]; + MwLLForceRender(handle); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - MilskoCocoa* self = handle->cocoa.real; - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + + frame.size.width = w; + frame.size.height = h; self->rect = frame; [self->view setFrameSize:frame.size]; if(self->parent) { [self->view setFrame:frame]; + [self->view setBounds:frame]; } else { [self->window setFrame:frame display:YES animate:false]; } - [self nudge]; + MwLLForceRender(handle); } static void MwLLFreeColorImpl(MwLLColor color) { @@ -849,9 +915,12 @@ static int MwLLPendingImpl(MwLL handle) { MilskoCocoa* self = handle->cocoa.real; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; MwBool isPending = [self->application pending]; - [self->application runModalSession:self->modalSession]; + + if(self->modalSession) { + [self->application runModalSession:self->modalSession]; + } [pool release]; - return self->_forceRender || self->_eventsPending || isPending; + return !self->isClosing && (self->_forceRender || self->_eventsPending || isPending); } static void MwLLNextEventImpl(MwLL handle) { @@ -862,7 +931,6 @@ static void MwLLNextEventImpl(MwLL handle) { self->_forceRender = MwFALSE; } if(self->_eventsPending) { - MwLLDispatch(h, draw, NULL); self->_eventsPending = MwFALSE; } [self sendClipboardEvent]; @@ -929,7 +997,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { pix.pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); arrpush(handle->cocoa.real->view->commands, pix); - // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; + + [handle->cocoa.real nudge]; } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { @@ -1000,7 +1069,8 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - [handle->cocoa.real->window setParentWindow:NULL]; + (void)handle; + (void)point; } static void MwLLShowImpl(MwLL handle, int show) { @@ -1076,6 +1146,10 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { rect->height = [screen frame].size.height; } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } @@ -1089,6 +1163,20 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; } +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLCocoaCallInitImpl(void) { #ifndef __APPLE__ printf("Using GNUStep Backend\n"); diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 024959e9..eace1d38 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -1,5 +1,7 @@ #include +#include "../../external/stb_ds.h" + typedef struct userdata { MwLL ll; POINT min; @@ -10,12 +12,31 @@ typedef struct userdata { static struct symtbl { void* lib_dwmapi; + void* shell32lib; + MwBool has_drag_and_drop; HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + + UINT(WINAPI* DragQueryFileW)(HDROP hDrop, UINT iFile, LPWSTR lpszFile, UINT cch); + void (*DragAcceptFiles)(HWND hWnd, BOOL fAccept); + void (*DragFinish)(HDROP hDrop); } wsymtbl; +static int is_plgblt_reliable = 0; + #define DwmSetWindowAttribute wsymtbl.DwmSetWindowAttribute +/* Dark theme detection for classic Windows: check if the user has set their theme to be dark. */ +static void detect_darktheme_classictheme(MwLL handle) { + /* Returns NULL on Windows 10+, use this to our advantage to check if the value is supported. */ + if(GetSysColorBrush(COLOR_MENU)) { + DWORD col = GetSysColor(COLOR_MENU); + int t = (GetRValue(col) <= 75 && GetGValue(col) <= 75 && GetBValue(col) <= 75); + MwLLDispatch(handle, dark_theme, &t); + } +} + +/* Dark theme detection for modern Windows: use the registry to check if dark mode is enabled. */ static void detect_darktheme(MwLL handle) { DWORD dw; DWORD sz = sizeof(dw); @@ -24,20 +45,27 @@ static void detect_darktheme(MwLL handle) { DWORD type; err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_QUERY_VALUE, &hkey); - if(err != ERROR_SUCCESS) return; + if(err != ERROR_SUCCESS) { + detect_darktheme_classictheme(handle); + return; + } err = RegQueryValueEx(hkey, "AppsUseLightTheme", NULL, &type, (PBYTE)&dw, &sz); RegCloseKey(hkey); if(err != ERROR_SUCCESS || type != REG_DWORD) { + detect_darktheme_classictheme(handle); return; } t = dw ? 0 : 1; + /* no don't do this here (nishi) */ +#if 0 if(t && DwmSetWindowAttribute != NULL) { LPARAM style = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); if(!(style & WS_CHILD)) MwLLSetDarkTheme(handle, 1); } +#endif MwLLDispatch(handle, dark_theme, &t); } @@ -47,7 +75,11 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { if(u == NULL) return DefWindowProc(hWnd, msg, wp, lp); - if(msg == WM_PAINT) { + switch(msg) { + case WM_INITDIALOG: + return TRUE; + case WM_PAINT: + { PAINTSTRUCT ps; RECT rc; HBITMAP hbmp; @@ -78,7 +110,12 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { MwLLDispatch(u->ll, draw, NULL); EndPaint(hWnd, &ps); } - } else if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { + break; + } + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { MwMouse p; p.point.x = LOWORD(lp); p.point.y = HIWORD(lp); @@ -93,7 +130,12 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { SetCapture(hWnd); SetFocus(hWnd); MwLLDispatch(u->ll, down, &p); - } else if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { + break; + } + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { MwMouse p; p.point.x = LOWORD(lp); p.point.y = HIWORD(lp); @@ -107,7 +149,10 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { SetCapture(NULL); MwLLDispatch(u->ll, up, &p); - } else if(msg == WM_MOUSEWHEEL) { + break; + } + case WM_MOUSEWHEEL: + { int d = GET_WHEEL_DELTA_WPARAM(wp); MwMouse p; p.point.x = LOWORD(lp); @@ -121,7 +166,31 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { MwLLDispatch(u->ll, down, &p); MwLLDispatch(u->ll, up, &p); - } else if(msg == WM_MOUSEMOVE) { + break; + } + case WM_DROPFILES: + { + HDROP hDrop = (HDROP)wp; + UINT count; + UINT i; + + count = wsymtbl.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); + + for(i = 0; i < count; i++) { + wchar_t wpath[MAX_PATH]; + char path[MAX_PATH]; + wsymtbl.DragQueryFileW(hDrop, i, wpath, MAX_PATH); + + memset(path, 0, sizeof(path)); + WideCharToMultiByte(CP_UTF8, 0, wpath, -1, path, sizeof(path) - 1, NULL, NULL); + + MwLLDispatch(u->ll, drag_and_drop, path); + } + wsymtbl.DragFinish(hDrop); + break; + } + case WM_MOUSEMOVE: + { MwPoint p; p.x = LOWORD(lp); p.y = HIWORD(lp); @@ -149,51 +218,106 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { SetCursorPos(p.x, p.y); } - } else if(msg == WM_SIZE) { + + break; + } + case WM_SIZE: + { MwLLDispatch(u->ll, resize, NULL); - } else if(msg == WM_ERASEBKGND) { + break; + } + case WM_ERASEBKGND: + { return 1; - } else if(msg == WM_NCHITTEST) { + } + case WM_NCHITTEST: + { LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); if(style & WS_CHILD) return HTCLIENT; return DefWindowProc(hWnd, msg, wp, lp); - } else if(msg == WM_DESTROY) { + } + case WM_DESTROY: + { PostQuitMessage(0); - } else if(msg == WM_CLOSE) { + break; + } + case WM_CLOSE: + { MwLLDispatch(u->ll, close, NULL); - } else if(msg == WM_CHAR || msg == WM_SYSCHAR) { + break; + } + case WM_CHAR: + case WM_SYSCHAR: + { int n = wp; const int base = 'A' - 1; if(n != 0x1b && n <= 0x1f) { - n = (n + base) | MwLLControlMask; + n = (n + base) | MwKEY_CONTROL_FLAG; if(!(GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT))) n += 0x20; } - if(HIBYTE(VkKeyScan(wp)) & 2) n |= MwLLControlMask; - if(msg == WM_SYSCHAR) n |= MwLLAltMask; + if(HIBYTE(VkKeyScan(wp)) & 2) n |= MwKEY_CONTROL_FLAG; + if(msg == WM_SYSCHAR) n |= MwKEY_ALT_FLAG; - if((0x20 <= n && n <= 0x7f) || (n & MwLLKeyMask)) MwLLDispatch(u->ll, key, &n); - } else if(msg == WM_SETFOCUS) { + if((0x20 <= n && n <= 0x7f) || (n & MwKEY_FLAG)) MwLLDispatch(u->ll, key, &n); + break; + } + case WM_SETFOCUS: + { MwLLDispatch(u->ll, focus_in, NULL); - } else if(msg == WM_KILLFOCUS) { + break; + } + case WM_KILLFOCUS: + { MwLLDispatch(u->ll, focus_out, NULL); - } else if(msg == WM_KEYDOWN || msg == WM_KEYUP || msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) { + break; + } + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + { int n = -1; + if(wp == VK_MENU && msg == WM_KEYUP) return 0; - if(wp == VK_LEFT) n = MwLLKeyLeft; - if(wp == VK_RIGHT) n = MwLLKeyRight; - if(wp == VK_UP) n = MwLLKeyUp; - if(wp == VK_DOWN) n = MwLLKeyDown; - if(wp == VK_RETURN) n = MwLLKeyEnter; - if(wp == VK_BACK) n = MwLLKeyBackSpace; - if(wp == VK_ESCAPE) n = MwLLKeyEscape; - if(wp == VK_LSHIFT) n = MwLLKeyLeftShift; - if(wp == VK_RSHIFT) n = MwLLKeyRightShift; - if(wp == VK_MENU) n = MwLLKeyAlt; - if(wp == VK_CONTROL) n = MwLLKeyControl; + switch(wp) { + case VK_LEFT: + n = MwKEY_LEFT; + break; + case VK_RIGHT: + n = MwKEY_RIGHT; + break; + case VK_UP: + n = MwKEY_UP; + break; + case VK_DOWN: + n = MwKEY_DOWN; + break; + case VK_RETURN: + n = MwKEY_ENTER; + break; + case VK_BACK: + n = MwKEY_BACKSPACE; + break; + case VK_ESCAPE: + n = MwKEY_ESCAPE; + break; + case VK_LSHIFT: + n = MwKEY_LEFTSHIFT; + break; + case VK_RSHIFT: + n = MwKEY_RIGHTSHIFT; + break; + case VK_MENU: + n = MwKEY_ALT; + break; + case VK_CONTROL: + n = MwKEY_CONTROL; + break; + } if((msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) && n != -1 && wp != VK_MENU) { - n |= MwLLAltMask; + n |= MwKEY_ALT_FLAG; } if(n != -1) { if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) { @@ -202,7 +326,10 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { MwLLDispatch(u->ll, key_released, &n); } } - } else if(msg == WM_GETMINMAXINFO) { + break; + } + case WM_GETMINMAXINFO: + { if(u->min_set || u->max_set) { LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); MINMAXINFO* mmi = (MINMAXINFO*)lp; @@ -233,22 +360,35 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } else { return DefWindowProc(hWnd, msg, wp, lp); } - } else if(msg == WM_SETCURSOR) { + break; + } + case WM_SETCURSOR: + { if(LOWORD(lp) != HTCLIENT) return DefWindowProc(hWnd, msg, wp, lp); if(u->ll->gdi.cursor != NULL) SetCursor(u->ll->gdi.cursor); - } else if(msg == WM_USER) { + break; + } + case WM_USER: + { InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); - } else if(msg == WM_WININICHANGE) { + break; + } + case WM_WININICHANGE: + { char* s = (char*)lp; LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); if(!(style & WS_CHILD)) { if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); } - } else { + break; + } + default: + { return DefWindowProc(hWnd, msg, wp, lp); } + } return 0; } @@ -257,6 +397,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { userdata_t* u = malloc(sizeof(*u)); WNDCLASSEX wc; + if(!r || !u) { + printf("Out Of Memory\n"); + return NULL; + } + memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; @@ -282,11 +427,13 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(parent == NULL) r->gdi.get_darktheme = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; - r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); + r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); r->gdi.hInstance = wc.hInstance; r->gdi.cursor = NULL; r->gdi.icon = NULL; + r->gdi.clip = NULL; + u->ll = r; u->min_set = 0; u->max_set = 0; @@ -308,6 +455,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { InvalidateRect(r->gdi.hWnd, NULL, FALSE); } + SetWindowPos(r->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + return r; } @@ -318,6 +467,8 @@ static void MwLLDestroyImpl(MwLL handle) { SetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA, (LPARAM)NULL); DestroyWindow(handle->gdi.hWnd); + if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); free(handle); @@ -336,6 +487,11 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); int i; + if(!p) { + printf("Out Of Memory\n"); + return; + } + for(i = 0; i < points_count; i++) { p[i].x = points[i].x; p[i].y = points[i].y; @@ -352,10 +508,17 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { HPEN pen = CreatePen(PS_SOLID, 1, RGB(color->common.red, color->common.green, color->common.blue)); + RECT rc; + + rc.left = points[1].x; + rc.top = points[1].y; + rc.right = rc.left + 1; + rc.bottom = rc.top + 1; SelectObject(handle->gdi.hDC, pen); MoveToEx(handle->gdi.hDC, points[0].x, points[0].y, NULL); LineTo(handle->gdi.hDC, points[1].x, points[1].y); + FillRect(handle->gdi.hDC, &rc, color->gdi.brush); DeleteObject(pen); } @@ -363,6 +526,11 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { MwLLColor c = malloc(sizeof(*c)); + if(!c) { + printf("Out Of Memory\n"); + return NULL; + } + c->gdi.brush = NULL; MwLLColorUpdate(handle, c, r, g, b); @@ -371,7 +539,8 @@ static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - HDC dc = GetDC(handle->gdi.hWnd); + HDC dc = GetDC(handle->gdi.hWnd); + COLORREF color; if(r > 255) r = 255; if(g > 255) g = 255; @@ -380,8 +549,10 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { if(g < 0) g = 0; if(b < 0) b = 0; + color = GetNearestColor(dc, RGB(r, g, b)); + if(c->gdi.brush != NULL) DeleteObject(c->gdi.brush); - c->gdi.brush = CreateSolidBrush(GetNearestColor(dc, RGB(r, g, b))); + c->gdi.brush = CreateSolidBrush(color); c->common.red = r; c->common.green = g; c->common.blue = b; @@ -408,12 +579,11 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - SetWindowPos(handle->gdi.hWnd, NULL, x, y, 0, 0, SWP_NOSIZE); - InvalidateRect(handle->gdi.hWnd, NULL, FALSE); + SetWindowPos(handle->gdi.hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_NOMOVE); + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER); InvalidateRect(handle->gdi.hWnd, NULL, FALSE); } @@ -438,10 +608,20 @@ static void MwLLNextEventImpl(MwLL handle) { if(handle->gdi.get_clipboard) { HGLOBAL hg; if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) { - char* txt = malloc(GlobalSize(hg)); + int sz = GlobalSize(hg); + char* txt = malloc(sz); char* clp = GlobalLock(hg); + if(!txt || !clp) { + printf("Out of Memory\n"); + return; + } + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + strcpy_s(txt, sz, clp); +#else strcpy(txt, clp); +#endif GlobalUnlock(hg); CloseClipboard(); @@ -458,10 +638,11 @@ static void MwLLNextEventImpl(MwLL handle) { handle->gdi.get_darktheme = 0; } - while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { - GetMessage(&msg, handle->gdi.hWnd, 0, 0); - TranslateMessage(&msg); - DispatchMessage(&msg); + while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + if(GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } } @@ -470,7 +651,17 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid HDC dc = GetDC(handle->gdi.hWnd); BITMAPINFOHEADER bmih; + if(!r) { + printf("Out Of Memory\n"); + return NULL; + } + r->common.raw = malloc(width * height * 4); + if(!r->common.raw) { + printf("Out Of Memory\n"); + return NULL; + } + memcpy(r->common.raw, data, 4 * width * height); r->common.width = width; @@ -510,6 +701,12 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap r) { words = malloc(w * r->common.height); words2 = malloc(w * r->common.height); + + if(!words || !words2) { + printf("Out Of Memory\n"); + return; + } + memset(words, 0, w * r->common.height); memset(words2, 0, w * r->common.height); for(y = 0; y < r->common.height; y++) { @@ -553,6 +750,7 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { HDC hmdc = CreateCompatibleDC(handle->gdi.hDC); POINT p[3]; + SetStretchBltMode(handle->gdi.hDC, HALFTONE); p[0].x = rect->x; p[0].y = rect->y; @@ -565,8 +763,13 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { SelectObject(hmdc, pixmap->gdi.hBitmap); - SetStretchBltMode(handle->gdi.hDC, HALFTONE); - PlgBlt(handle->gdi.hDC, p, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, pixmap->gdi.hMask, 0, 0); + if(!is_plgblt_reliable || PlgBlt(handle->gdi.hDC, p, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, pixmap->gdi.hMask, 0, 0) == 0) { + SelectObject(hmdc, pixmap->gdi.hMask2); + StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCAND); + + SelectObject(hmdc, pixmap->gdi.hBitmap); + StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCPAINT); + } DeleteDC(hmdc); } @@ -605,6 +808,8 @@ HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) { ys = mask->height + mask->y; ys = image->height + image->y - ys; + if(ys < 0) ys = -ys; + memset(dmask, 0xff, (MwCursorDataHeight / 8) * MwCursorDataHeight); memset(dimage, 0, (MwCursorDataHeight / 8) * MwCursorDataHeight); @@ -753,12 +958,30 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty (void)clipboard_type; if(OpenClipboard(handle->gdi.hWnd) != 0) { char* lock; + int sz = strlen(text) + 1; EmptyClipboard(); - hg = GlobalAlloc(GHND | GMEM_SHARE, strlen(text) + 1); + hg = GlobalAlloc(GHND | GMEM_SHARE, sz); + + if(!hg) { + printf("Out of Memory\n"); + return; + } lock = GlobalLock(hg); + + if(!lock) { + printf("Out Of Memory\n"); + GlobalUnlock(hg); + CloseClipboard(); + return; + } + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + strcpy_s(lock, sz, text); +#else strcpy(lock, text); +#endif GlobalUnlock(hg); SetClipboardData(CF_TEXT, hg); @@ -822,16 +1045,90 @@ static void MwLLEndStateChangeImpl(MwLL handle) { static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { BOOL v = toggle ? TRUE : FALSE; - DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); + if(DwmSetWindowAttribute) + DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + OSVERSIONINFO osvi; + + (void)handle; + + osvi.dwOSVersionInfoSize = sizeof(osvi); + + GetVersionEx(&osvi); + + if(osvi.dwMajorVersion < 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion < 1)) { + return MwFALSE; + } + + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + SelectClipRgn(handle->gdi.hDC, NULL); + + if(handle->gdi.clip != NULL) { + DeleteObject(handle->gdi.clip); + handle->gdi.clip = NULL; + } + } else { + HRGN clip = CreateRectRgn(rect->x, rect->y, rect->x + rect->width, rect->y + rect->height); + + SelectClipRgn(handle->gdi.hDC, clip); + + if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + + handle->gdi.clip = clip; + } +} + +static void MwLLSetupDragAndDropImpl(MwLL handle) { + wsymtbl.DragAcceptFiles(handle->gdi.hWnd, TRUE); } static int MwLLGDICallInitImpl(void) { + void* ntdll; + memset(&wsymtbl, 0, sizeof(wsymtbl)); wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); if(wsymtbl.lib_dwmapi != NULL) DwmSetWindowAttribute = MwDynamicSymbol(wsymtbl.lib_dwmapi, "DwmSetWindowAttribute"); + if((ntdll = GetModuleHandle("ntdll.dll")) != NULL && GetProcAddress(ntdll, "wine_get_version") != NULL) { + is_plgblt_reliable = 0; + } else { + is_plgblt_reliable = 1; + } + + wsymtbl.has_drag_and_drop = MwFALSE; + + /* Drag and Drop initialization */ + { + if(!(wsymtbl.shell32lib = LoadLibrary("shell32.dll"))) { + goto dnd_error; + }; + +#define SHELL32_FUNC(x) \ + if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.shell32lib, #x))) { \ + printf(#x "not found, drag and drop will not be supported"); \ + goto dnd_error; \ + } + + SHELL32_FUNC(DragQueryFileW); + SHELL32_FUNC(DragAcceptFiles); + SHELL32_FUNC(DragFinish); + + wsymtbl.has_drag_and_drop = MwTRUE; + } +dnd_error: + /* TODO: check properly */ return 0; } diff --git a/src/backend/haiku.cc b/src/backend/haiku.cc new file mode 100644 index 00000000..2c796d60 --- /dev/null +++ b/src/backend/haiku.cc @@ -0,0 +1,910 @@ +#include + +#include "../../external/stb_ds.h" + +MwApplication::MwApplication(MwRect rc, MwLL handle) + : BApplication("application/milsko-generic") { + BScreen* scr = new BScreen(); + float x = (scr->Frame().Width() - rc.width) / 2; + float y = (scr->Frame().Height() - rc.height) / 2; + BRect rc2; + int dx = rc.x == MwDEFAULT; + int dy = rc.y == MwDEFAULT; + + rc.x += dx ? -rc.x : 0; + rc.y += dy ? -rc.y : 0; + + if(dx) rc.x += x; + if(dy) rc.y += y; + + rc2 = BRect(rc.x, rc.y, rc.x + rc.width - 1, rc.y + rc.height - 1); + + handle->haiku.window = new MwWindow(rc2, B_TITLED_WINDOW, 0); + handle->haiku.window->Show(); + + handle->haiku.view = new MwView(handle, handle->haiku.window->Bounds(), B_FOLLOW_ALL_SIDES, B_WILL_DRAW); + + handle->haiku.window->AddChild(handle->haiku.view); + + delete scr; +} + +MwApplication::~MwApplication() { +} + +void MwApplication::MessageReceived(BMessage* message) { + switch(message->what) { + case BAPP_MW_DESTROY: + { + this->Quit(); + break; + } + default: + { + BLooper::MessageReceived(message); + break; + } + } +} + +MwView::MwView(MwLL handle, BRect frame, uint32 resizingMode, uint32 flags) + : BView(frame, NULL, resizingMode, flags | B_FRAME_EVENTS) { + this->handle = handle; + + this->locker = new BLocker(); + + this->SetDrawingMode(B_OP_OVER); + this->SetLineMode(B_BUTT_CAP, B_BUTT_JOIN); + + this->SetViewColor(B_TRANSPARENT_COLOR); + + this->buttons = 0; +} + +MwView::~MwView() { + delete this->locker; +} + +void MwView::MessageReceived(BMessage* message) { + switch(message->what) { + case BVIEW_MW_DESTROY: + { + this->RemoveSelf(); + delete this; + break; + } + case BVIEW_MW_DETACH: + { + BRect rc; + BPoint point; + + if(message->FindPoint("view-point", &point) != B_OK) break; + + point = this->ConvertToScreen(this->ConvertFromParent(point)); + + rc.left = point.x; + rc.top = point.y; + rc.right = rc.left + this->handle->haiku.width - 1; + rc.bottom = rc.top + this->handle->haiku.height - 1; + + if(this->Parent() != NULL) { + this->RemoveSelf(); + } + + this->handle->haiku.parent = NULL; + + this->handle->haiku.window = new MwWindow(rc, B_TITLED_WINDOW, 0); + this->handle->haiku.window->Show(); + + this->MoveTo(0, 0); + this->ResizeTo(this->handle->haiku.width, this->handle->haiku.height); + this->SetResizingMode(B_FOLLOW_ALL_SIDES); + this->handle->haiku.window->AddChild(this); + + while(this->Window() != this->handle->haiku.window); + + MwLLForceRender(this->handle); + break; + } + case BVIEW_MW_RESIZE: + { + int width, height; + + if(message->FindInt32("view-width", &width) != B_OK) break; + if(message->FindInt32("view-height", &height) != B_OK) break; + + if(this->handle->haiku.window == NULL) { + this->ResizeTo(width - 1, height - 1); + } else { + this->handle->haiku.window->ResizeTo(width - 1, height - 1); + this->ResizeTo(width - 1, height - 1); + } + this->Draw(BRect(0, 0, 0, 0)); + break; + } + case BVIEW_MW_MOVE: + { + int x, y; + + if(message->FindInt32("view-x", &x) != B_OK) break; + if(message->FindInt32("view-y", &y) != B_OK) break; + + if(this->handle->haiku.app == NULL) { + this->MoveTo(x, y); + } else { + this->Window()->MoveTo(x, y); + } + break; + } + case BVIEW_MW_SHOW: + { + if(this->Parent() == NULL) { + this->handle->haiku.parent->haiku.view->AddChild(this); + } + break; + } + case BVIEW_MW_HIDE: + { + if(this->Parent() != NULL) { + this->RemoveSelf(); + } + break; + } + case BVIEW_MW_SET_COLOR: + { + int32 rgb[3]; + int i; + + rgb[0] = rgb[1] = rgb[2] = 0; + + for(i = 0; i < 3 && message->FindInt32("view-color", i, &rgb[i]) == B_OK; i++); + + this->SetHighColor(rgb[0], rgb[1], rgb[2]); + + break; + } + case BVIEW_MW_POLYGON: + { + int i; + BPoint p; + BPoint points[32]; + + for(i = 0; i < 32 && message->FindPoint("view-point", i, &p) == B_OK; i++) { + points[i] = p; + } + + this->FillPolygon(points, i); + break; + } + case BVIEW_MW_LINE: + { + int i; + BPoint p; + BPoint points[2]; + + for(i = 0; i < 2 && message->FindPoint("view-point", i, &p) == B_OK; i++) { + points[i] = p; + } + + this->StrokeLine(points[0], points[1]); + break; + } + case BVIEW_MW_BITMAP: + { + BRect rc; + BBitmap* bitmap; + + if(message->FindRect("view-rect", &rc) != B_OK) break; + if(message->FindPointer("view-bitmap", (void**)&bitmap) != B_OK) break; + + this->DrawBitmap(bitmap, rc); + break; + } + case BVIEW_MW_RENDER: + { + this->Invalidate(); + break; + } + case BVIEW_MW_RAISE: + { + BView* v = this->Parent(); + + this->RemoveSelf(); + v->AddChild(this); + break; + } + case BVIEW_MW_GET_MOUSE: + { + BPoint* p; + uint32 btn; + + if(message->FindPointer("view-ppoint", (void**)&p) != B_OK) break; + + this->GetMouse(p, &btn); + + break; + } + default: + { + BView::MessageReceived(message); + break; + } + } +} + +void MwView::PostMessage(BMessage* message) { + BMessage copy = *message; + MwLL top = this->handle; + + while(top->haiku.parent != NULL) top = top->haiku.parent; + + copy.AddPointer("window-view", this); + + top->haiku.window->PostMessage(©); +} + +void MwView::PostMessage(uint32 command) { + BMessage msg(command); + + this->PostMessage(&msg); +} + +status_t MwView::SendMessage(BMessage* message) { + BMessage copy = *message; + BMessage reply; + MwLL top = this->handle; + + while(top->haiku.parent != NULL) top = top->haiku.parent; + + copy.AddPointer("window-view", this); + + return BMessenger(top->haiku.window).SendMessage(©, &reply); +} + +status_t MwView::SendMessage(uint32 command) { + BMessage msg(command); + + return this->SendMessage(&msg); +} + +void MwView::Invalidate() { + this->Draw(BRect(0, 0, 0, 0)); +} + +void MwView::AttachedToWindow() { + this->SetOrigin(0, 0); +} + +void MwView::Draw(BRect updateRect) { + MwLLHaikuEvent ev; + + (void)updateRect; + + ev.type = MwLLHAIKU_EVENT_DRAW; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::FrameResized(float width, float height) { + MwLLHaikuEvent ev; + + ev.type = MwLLHAIKU_EVENT_FRAMERESIZED; + ev.frame_resized.width = width; + ev.frame_resized.height = height; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseDown(BPoint point) { + MwLLHaikuEvent ev; + uint32 btn; + BPoint p; + + this->GetMouse(&p, &btn, false); + + this->SetMouseEventMask(B_LOCK_WINDOW_FOCUS); + + ev.type = MwLLHAIKU_EVENT_MOUSEDOWN; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + + if((btn & B_PRIMARY_MOUSE_BUTTON) && !(this->buttons & B_PRIMARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_LEFT; + } else if((btn & B_SECONDARY_MOUSE_BUTTON) && !(this->buttons & B_SECONDARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_RIGHT; + } else if((btn & B_TERTIARY_MOUSE_BUTTON) && !(this->buttons & B_TERTIARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_MIDDLE; + } + this->buttons = btn; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseUp(BPoint point) { + MwLLHaikuEvent ev; + uint32 btn; + BPoint p; + + this->GetMouse(&p, &btn, false); + + ev.type = MwLLHAIKU_EVENT_MOUSEUP; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + + if(!(btn & B_PRIMARY_MOUSE_BUTTON) && (this->buttons & B_PRIMARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_LEFT; + } else if(!(btn & B_SECONDARY_MOUSE_BUTTON) && (this->buttons & B_SECONDARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_RIGHT; + } else if(!(btn & B_TERTIARY_MOUSE_BUTTON) && (this->buttons & B_TERTIARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_MIDDLE; + } + this->buttons = btn; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseMoved(BPoint point, uint32 transit, const BMessage* message) { + MwLLHaikuEvent ev; + + (void)transit; + (void)message; + + ev.type = MwLLHAIKU_EVENT_MOUSEMOVED; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + ev.mouse.button = 0; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::SetColor(MwLLColor color) { + BMessage msg(BVIEW_MW_SET_COLOR); + + msg.AddInt32("view-color", color->common.red); + msg.AddInt32("view-color", color->common.green); + msg.AddInt32("view-color", color->common.blue); + + this->PostMessage(&msg); +} + +MwWindow::MwWindow(BRect frame, window_type type, uint32 flags) + : BWindow(frame, "Milsko", type, flags) { +} + +void MwWindow::MessageReceived(BMessage* message) { + void* ptr; + + if(message->FindPointer("window-view", &ptr) == B_OK) { + MwView* v = (MwView*)ptr; + + v->MessageReceived(message); + + return; + } + + switch(message->what) { + case BVIEW_MW_DESTROY: + { + this->Quit(); + delete this; + break; + } + case BWIN_MW_SET_TITLE: + { + const char* title; + + if(message->FindString("window-title", &title) != B_OK) break; + + this->SetTitle(title); + break; + } + case BWIN_MW_SET_TYPE: + { + int type; + + if(message->FindInt32("window-type", &type) != B_OK) break; + + this->SetType((window_type)type); + + if(type == B_UNTYPED_WINDOW) { + this->SetLook(B_NO_BORDER_WINDOW_LOOK); + } + break; + } + default: + { + BWindow::MessageReceived(message); + break; + } + } +} + +void MwWindow::FrameMoved(BPoint newLocation) { + MwLLHaikuEvent ev; + MwView* v = (MwView*)this->ChildAt(0); + + ev.type = MwLLHAIKU_EVENT_FRAMEMOVED; + ev.frame_moved.point.x = newLocation.x; + ev.frame_moved.point.y = newLocation.y; + + v->locker->Lock(); + arrput(v->handle->haiku.events, ev); + v->locker->Unlock(); +} + +bool MwWindow::QuitRequested() { + MwLLHaikuEvent ev; + MwView* v = (MwView*)this->ChildAt(0); + + ev.type = MwLLHAIKU_EVENT_CLOSE; + + v->locker->Lock(); + arrput(v->handle->haiku.events, ev); + v->locker->Unlock(); + + return false; +} + +struct app_param { + MwRect rc; + MwLL handle; +}; + +static int32 app_thread(void* data) { + struct app_param* r = (struct app_param*)data; + + r->handle->haiku.app = new MwApplication(r->rc, r->handle); + r->handle->haiku.app->Run(); + + free(r); + + return 0; +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r = (MwLL)malloc(sizeof(*r)); + MwRect mrc; + BRect rc = BRect(x, y, x + width - 1, y + height - 1); + + mrc.x = x; + mrc.y = y; + mrc.width = width; + mrc.height = height; + + MwLLCreateCommon(r); + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendHaiku; + + r->haiku.force_render = 0; + + r->haiku.parent = parent; + + r->haiku.events = NULL; + + if(parent == NULL) { + struct app_param* p = (struct app_param*)malloc(sizeof(*p)); + + r->haiku.app = NULL; + + p->rc = mrc; + p->handle = r; + + r->haiku.app = NULL; + r->haiku.window = NULL; + r->haiku.view = NULL; + + r->haiku.app_thread = spawn_thread(app_thread, NULL, B_NORMAL_PRIORITY, p); + resume_thread(r->haiku.app_thread); + + while(r->haiku.app == NULL || r->haiku.window == NULL || r->haiku.view == NULL) MwTimeSleep(10); + } else { + MwLL top = r; + while(top->haiku.parent != NULL) { + top = top->haiku.parent; + } + + r->haiku.app = NULL; + r->haiku.window = NULL; + r->haiku.view = new MwView(r, rc, B_FOLLOW_NONE, B_WILL_DRAW); + + parent->haiku.view->AddChild(r->haiku.view); + + r->haiku.view->SendMessage(BVIEW_MW_RAISE); + } + + r->haiku.x = x; + r->haiku.y = y; + r->haiku.width = width; + r->haiku.height = height; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + handle->haiku.view->PostMessage(BVIEW_MW_DESTROY); + + if(handle->haiku.app != NULL) { + status_t exit_value; + + handle->haiku.app->PostMessage(BAPP_MW_DESTROY); + wait_for_thread(handle->haiku.app_thread, &exit_value); + + delete handle->haiku.app; + } else if(handle->haiku.window != NULL) { + handle->haiku.window->PostMessage(BWIN_MW_DESTROY); + } + + free(handle); +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + BMessage msg(BVIEW_MW_POLYGON); + + for(i = 0; i < points_count; i++) { + BPoint p(points[i].x, points[i].y); + + msg.AddPoint("view-point", p); + } + + handle->haiku.view->SetColor(color); + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + int i; + BMessage msg(BVIEW_MW_LINE); + + for(i = 0; i < 2; i++) { + BPoint p(points[i].x, points[i].y); + + msg.AddPoint("view-point", p); + } + + handle->haiku.view->SetColor(color); + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = (MwLLColor)malloc(sizeof(*c)); + + MwLLColorUpdate(handle, c, r, g, b); + + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + *x = handle->haiku.x; + *y = handle->haiku.y; + *w = handle->haiku.width; + *h = handle->haiku.height; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + BMessage msg(BVIEW_MW_MOVE); + + handle->haiku.x = x; + handle->haiku.y = y; + + msg.AddInt32("view-x", x); + msg.AddInt32("view-y", y); + + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + BMessage msg(BVIEW_MW_RESIZE); + + handle->haiku.width = w; + handle->haiku.height = h; + + msg.AddInt32("view-width", w); + msg.AddInt32("view-height", h); + + handle->haiku.view->PostMessage(&msg); + + MwLLDispatch(handle, resize, NULL); +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + BMessage msg(BWIN_MW_SET_TITLE); + + if(handle->haiku.app == NULL) return; + + msg.AddString("window-title", title); + + handle->haiku.window->PostMessage(&msg); +} + +static int MwLLPendingImpl(MwLL handle) { + handle->haiku.view->locker->Lock(); + if(arrlen(handle->haiku.events) > 0) { + handle->haiku.view->locker->Unlock(); + return 1; + } + handle->haiku.view->locker->Unlock(); + + return 0; +} + +static void MwLLNextEventImpl(MwLL handle) { + int rendered = 0; + + handle->haiku.view->locker->Lock(); + while(arrlen(handle->haiku.events) > 0) { + MwLLHaikuEvent* ev = &handle->haiku.events[0]; + MwMouse m; + + if(ev->type == MwLLHAIKU_EVENT_MOUSEDOWN || ev->type == MwLLHAIKU_EVENT_MOUSEUP) { + m.point = ev->mouse.point; + m.button = ev->mouse.button; + } + + if(ev->type == MwLLHAIKU_EVENT_DRAW) { + MwLLDispatch(handle, draw, NULL); + + rendered = 1; + } else if(ev->type == MwLLHAIKU_EVENT_CLOSE) { + MwLLDispatch(handle, close, NULL); + } else if(ev->type == MwLLHAIKU_EVENT_FRAMERESIZED) { + handle->haiku.width = ev->frame_resized.width + 1; + handle->haiku.height = ev->frame_resized.height + 1; + + MwLLDispatch(handle, resize, NULL); + } else if(ev->type == MwLLHAIKU_EVENT_FRAMEMOVED) { + handle->haiku.x = ev->frame_moved.point.x + 1; + handle->haiku.y = ev->frame_moved.point.y + 1; + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEDOWN) { + MwLLDispatch(handle, down, &m); + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEUP) { + MwLLDispatch(handle, up, &m); + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEMOVED) { + MwLLDispatch(handle, move, &ev->mouse.point); + } + + arrdel(handle->haiku.events, 0); + } + handle->haiku.view->locker->Unlock(); + + if(rendered) handle->haiku.force_render = 0; +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = (MwLLPixmap)malloc(sizeof(*r)); + + (void)handle; + + r->common.raw = (unsigned char*)malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + r->haiku.bitmap = NULL; + + MwLLPixmapUpdate(r); + return r; + + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { + uint32* px = (uint32*)malloc(4 * pixmap->common.width * pixmap->common.height); + int i; + + for(i = 0; i < pixmap->common.width * pixmap->common.height; i++) { + unsigned char* ipx = &pixmap->common.raw[4 * i]; + + px[i] = (ipx[3] << 24) | (ipx[0] << 16) | (ipx[1] << 8) | (ipx[2] << 0); + } + + if(pixmap->haiku.bitmap != NULL) delete pixmap->haiku.bitmap; + + pixmap->haiku.bitmap = new BBitmap(BRect(0, 0, pixmap->common.width - 1, pixmap->common.height - 1), B_RGBA32); + + pixmap->haiku.bitmap->SetBits(px, pixmap->common.width * pixmap->common.height * 4, 0, B_RGBA32); + + free(px); +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); + + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + BRect rc; + BMessage msg(BVIEW_MW_BITMAP); + + rc = BRect(rect->x, rect->y, rect->x + rect->width - 1, rect->y + rect->height - 1); + + msg.AddRect("view-rect", rc); + msg.AddPointer("view-bitmap", pixmap->haiku.bitmap); + + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + (void)handle; + (void)pixmap; +} + +static void MwLLForceRenderImpl(MwLL handle) { + if(handle->haiku.force_render) return; + + handle->haiku.force_render = 1; + handle->haiku.view->PostMessage(BVIEW_MW_RENDER); +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + (void)handle; + (void)image; + (void)mask; +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + BMessage msg(BVIEW_MW_DETACH); + + msg.AddPoint("view-point", BPoint(point->x, point->y)); + + handle->haiku.view->PostMessage(&msg); + + while(handle->haiku.window == NULL); +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(show) { + handle->haiku.view->PostMessage(BVIEW_MW_SHOW); + } else { + handle->haiku.view->PostMessage(BVIEW_MW_HIDE); + } +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + (void)handle; + (void)minx; + (void)miny; + (void)maxx; + (void)maxy; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + if(toggle) { + handle->haiku.type = B_TITLED_WINDOW; + } else { + handle->haiku.type = B_UNTYPED_WINDOW; + } +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + handle->haiku.type = B_UNTYPED_WINDOW; +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + handle->haiku.type = handle->haiku.window == NULL ? B_TITLED_WINDOW : handle->haiku.window->Type(); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + BMessage msg(BWIN_MW_SET_TYPE); + + msg.AddInt32("window-type", handle->haiku.type); + + BMessenger(handle->haiku.window).SendMessage(&msg); +} + +static void MwLLFocusImpl(MwLL handle) { + (void)handle; +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + (void)handle; + (void)text; + (void)clipboard_type; +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)handle; + (void)clipboard_type; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MwLL top = handle; + BMessage msg(BVIEW_MW_GET_MOUSE); + BPoint p; + while(top->haiku.parent != NULL) { + top = top->haiku.parent; + } + + msg.AddPointer("view-ppoint", &p); + top->haiku.view->SendMessage(&msg); + + point->x = p.x; + point->y = p.y; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + BScreen* screen = new BScreen(); + + (void)handle; + + if(screen->IsValid()) { + rect->width = screen->Frame().Width(); + rect->height = screen->Frame().Height(); + } + + delete screen; +} + +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + handle->haiku.view->SendMessage(BVIEW_MW_RAISE); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + +int MwLLHaikuCallInitImpl() { + return 0; +} + +#include "call.c" +CALL(Haiku); diff --git a/src/backend/nococoa.m b/src/backend/nococoa.m new file mode 100644 index 00000000..c009b38d --- /dev/null +++ b/src/backend/nococoa.m @@ -0,0 +1,9 @@ +#include +#import + +void MwLLNoCocoaErrorMessage(void) { + NSAlert* alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Milsko applications currently requires XQuartz or cocoa-way. PRs are welcome for anyone who wants to finish the Cocoa backend (prefarably in Objective-C)"]; + [alert addButtonWithTitle:@"Ok"]; + [alert runModal]; +} diff --git a/src/backend/wayland.c b/src/backend/wayland.c deleted file mode 100644 index 56601258..00000000 --- a/src/backend/wayland.c +++ /dev/null @@ -1,2653 +0,0 @@ -#include - -#include -#include - -#include "../../external/stb_ds.h" - -/* TODO: find out what FreeBSD and such wants us to include */ -#ifdef __FreeBSD__ -/* XXX: Untested (nishi) */ -#include -#else -#include -#include -#endif - -wayland_call_table_t wl_call_tbl; -MwBool MwWaylandAlwaysRender = MwFALSE; - -MwU32 wl_dark_theme = -1; - -/* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ -#define WAYLAND_EVENT_OP_START(self) \ - do { \ - struct timespec t; \ - t.tv_sec = 0; \ - t.tv_nsec = 250; \ - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { \ - /*printf("deadlock at line %d\n", __LINE__);*/ \ - return; \ - }; \ - } while(0); - -/* Footer for WAYLAND_EVENT_OP_START */ -#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); - -/* Setup the framebuffer with the saved width/height */ -static void framebuffer_setup(struct _MwLLWayland* wayland); -/* Destroy the framebuffer */ -static void framebuffer_destroy(struct _MwLLWayland* handle); - -/* Setup the framebuffer with the saved width/height */ -static void backbuffer_setup(struct _MwLLWayland* wayland); -/* Destroy the backbuffer */ -static void backbuffer_destroy(struct _MwLLWayland* handle); - -static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer); - -static void region_setup(MwLL handle); -static void region_invalidate(MwLL handle); -static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer); -/* Get the registered interface from r, or NULL if it doesn't currently have it. */ -#define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) - -/* `wl_registry.global` callback */ -static void new_protocol(void* data, struct wl_registry* registry, - MwU32 name, const char* interface, - MwU32 version) { - MwLL self = data; - (void)version; - (void)registry; - - WAYLAND_EVENT_OP_START(self); - - wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); - if(cb != NULL) { - shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data)); - /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ - } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { - self->common.supports_transparency = MwTRUE; - } else { - // printf("unknown interface %s\n", interface); - } - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_registry.global_remove` callback */ -static void protocol_removed(void* data, - struct wl_registry* registry, - MwU32 name) { - (void)data; - (void)registry; - (void)name; - printf("%d destroyed\n", name); -}; - -/* Flush Wayland events */ -static void wl_flush(MwLL handle) { - struct pollfd pfd; - int rc; - - pfd.fd = wl_display_get_fd(handle->wayland.display); - pfd.events = POLLIN; - while(MwTRUE) { - rc = wl_display_flush(handle->wayland.display); - if(errno != EAGAIN || rc != -1) { - break; - } - - if(poll(&pfd, 1, -1) == -1) { - break; - } - } -} - -/* Recursively dispatch a resize event to a widget and its children */ -static void recursive_dispatch_resize(MwLL handle) { - MwWidget h = (MwWidget)handle->common.user; - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwDispatch(h->children[i], resize); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_resize(h->children[i]->lowlevel); - } - } - } -}; - -/* Recursively dispatch a move event to a widget and its children */ -static void recursive_dispatch_move(MwLL handle, MwMouse* p) { - MwWidget h = (MwWidget)handle->common.user; - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, move, p); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_move(h->children[i]->lowlevel, p); - } - } - } -}; - -static void wl_offer(void* data, - struct wl_data_offer* wl_data_offer, - const char* mime_type) { - wl_clipboard_device_context_t* self = data; - wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); -}; - -struct wl_data_offer_listener offer_listener = { - .offer = wl_offer, -}; - -static void wl_data_device_data_offer(void* data, - struct wl_data_device* wl_data_device, - struct wl_data_offer* offer) { - wl_clipboard_device_context_t* self = data; - (void)wl_data_device; - - wl_data_offer_add_listener(offer, &offer_listener, data); - - self->offer.wl = offer; -}; - -static void wl_data_device_enter(void* data, - struct wl_data_device* wl_data_device, - uint32_t serial, - struct wl_surface* surface, - wl_fixed_t x, - wl_fixed_t y, - struct wl_data_offer* id) { - MwLL self = data; - (void)wl_data_device; - (void)surface; - (void)x; - (void)y; - (void)id; - - WAYLAND_EVENT_OP_START(self); - - self->wayland.clipboard_serial = serial; - - WAYLAND_EVENT_OP_END(self); -}; -static void wl_data_device_leave(void* data, - struct wl_data_device* wl_data_device) { - MwLL self = data; - - WAYLAND_EVENT_OP_START(self); - wl_data_device_destroy(wl_data_device); - WAYLAND_EVENT_OP_END(self); -}; -static void wl_data_device_motion(void* data, - struct wl_data_device* wl_data_device, - uint32_t time, - wl_fixed_t x, - wl_fixed_t y) { - (void)data; - (void)wl_data_device; - (void)time; - (void)x; - (void)y; -}; -static void wl_data_device_drop(void* data, - struct wl_data_device* wl_data_device) { - (void)data; - (void)wl_data_device; -}; - -static void wl_data_device_selection(void* data, - struct wl_data_device* wl_data_device, - struct wl_data_offer* id) { - (void)data; - (void)wl_data_device; - (void)id; -}; - -struct wl_data_device_listener wl_data_device_listener = { - .data_offer = wl_data_device_data_offer, - .enter = wl_data_device_enter, - .leave = wl_data_device_leave, - .motion = wl_data_device_motion, - .drop = wl_data_device_drop, - .selection = wl_data_device_selection, -}; - -static void zwp_primary_selection_device_v1_data_offer(void* data, - struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, - struct zwp_primary_selection_offer_v1* offer) { - wl_clipboard_device_context_t* self = data; - (void)zwp_primary_selection_device_v1; - - self->offer.zwp = offer; -}; - -static void zwp_primary_selection_device_v1_selection(void* data, - struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, - struct zwp_primary_selection_offer_v1* id) { - (void)data; - (void)zwp_primary_selection_device_v1; - (void)id; -}; - -struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = { - .data_offer = zwp_primary_selection_device_v1_data_offer, - .selection = zwp_primary_selection_device_v1_selection, -}; - -static void wl_clipboard_read(wl_clipboard_device_context_t* ctx, int clipboard_type) { - int fds[2]; - fd_set set; - char* buf = NULL; - struct timeval timeout; - int rc = 0; - - if(pipe(fds) != 0) { - return; - } - - FD_ZERO(&set); - FD_SET(fds[0], &set); - timeout.tv_sec = 0; - timeout.tv_usec = 100; - - if(clipboard_type == MwCLIPBOARD_PRIMARY) { - zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); - } else if(ctx->offer.wl) { - wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); - } - close(fds[1]); - - wl_flush(ctx->ll); - wl_display_roundtrip(ctx->ll->wayland.display); - - while(MwTRUE) { - rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); - if(rc <= 0) { - break; - } else { - char b; - ssize_t n = read(fds[0], &b, sizeof(b)); - if(n <= 0) { - break; - } - arrpush(buf, b); - } - } - arrpush(buf, 0); - close(fds[0]); - - MwLLDispatch(ctx->ll, clipboard, buf); - arrfree(buf); - - ctx->ll->wayland.events_pending = 1; -} - -static void wl_data_source_listener_target(void* data, - struct wl_data_source* wl_data_source, - const char* mime_type) { - (void)data; - (void)wl_data_source; - (void)mime_type; -}; -static void wl_data_source_listener_send(void* data, - struct wl_data_source* wl_data_source, - const char* mime_type, - int32_t fd) { - MwLL self = data; - (void)wl_data_source; - (void)mime_type; - - WAYLAND_EVENT_OP_START(self); - if(self->wayland.clipboard_buffer != NULL) { - write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); - close(fd); - } - WAYLAND_EVENT_OP_END(self); -}; -static void wl_data_source_listener_cancelled(void* data, - struct wl_data_source* wl_data_source); - -struct wl_data_source_listener wl_data_source_listener = { - .target = wl_data_source_listener_target, - .send = wl_data_source_listener_send, - .cancelled = wl_data_source_listener_cancelled, -}; - -static void wl_data_source_listener_cancelled(void* data, - struct wl_data_source* wl_data_source) { - MwLL self = data; - - WAYLAND_EVENT_OP_START(self); - - wl_data_source_destroy(wl_data_source); - - self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl); - - wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain"); - wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain;charset=utf-8"); - wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); - wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); - wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); - - wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); - - WAYLAND_EVENT_OP_END(self); -}; - -static void zwp_primary_selection_source_v1_send(void* data, - struct zwp_primary_selection_source_v1* wl_data_source, - const char* mime_type, - int32_t fd) { - MwLL self = data; - (void)wl_data_source; - (void)mime_type; - - WAYLAND_EVENT_OP_START(self); - - if(self->wayland.clipboard_buffer != NULL) { - write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); - close(fd); - } - - WAYLAND_EVENT_OP_END(self); -}; -static void zwp_primary_selection_source_v1_cancelled(void* data, - struct zwp_primary_selection_source_v1* wl_data_source) { - MwLL self = data; - (void)wl_data_source; - - WAYLAND_EVENT_OP_START(self); - - zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp); - - self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp); - - zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain"); - zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain;charset=utf-8"); - zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT"); - zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING"); - zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING"); - - WAYLAND_EVENT_OP_END(self); -}; - -struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = { - .send = zwp_primary_selection_source_v1_send, - .cancelled = zwp_primary_selection_source_v1_cancelled, -}; - -/* wl_data_device_manager setup function */ -static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); - - wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); - - wl_data_source_offer(wayland->clipboard_source.wl, "text/plain"); - wl_data_source_offer(wayland->clipboard_source.wl, "text/plain;charset=utf-8"); - wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); - wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); - wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); - - wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); - - return NULL; -} - -static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)data; - if(wayland->clipboard_manager.wl != NULL) { - wl_data_device_manager_destroy(wayland->clipboard_manager.wl); - wl_data_source_destroy(wayland->clipboard_source.wl); - wayland->clipboard_manager.wl = NULL; - } -} - -/* zwp_primary_selection_device_manager_v1 setup function */ -static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); - - wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); - - zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain"); - zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain;charset=utf-8"); - zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "TEXT"); - zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "STRING"); - zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "UTF8_STRING"); - - zwp_primary_selection_source_v1_add_listener(wayland->clipboard_source.zwp, &zwp_primary_selection_source_v1_listener, wayland); - - wayland->supports_zwp = MwTRUE; - - return NULL; -} - -static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* zwp_primary_selection_device_manager_v1 setup function */ -static wayland_protocol_t* zwp_pointer_constraints_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->pointer_constraints = wl_registry_bind(wayland->registry, name, &zwp_pointer_constraints_v1_interface, 1); - return NULL; -} - -static void zwp_pointer_constraints_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -static struct wl_surface* curSurface; - -/* `wl_pointer.enter` callback */ -static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y) { - MwLL self = data; - (void)surface_x; - (void)surface_y; - - WAYLAND_EVENT_OP_START(self); - curSurface = surface; - - self->wayland.pointer_serial = serial; - - wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_pointer.leave` callback */ -static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface) { - MwLL self = data; - (void)wl_pointer; - (void)serial; - (void)surface; - WAYLAND_EVENT_OP_START(self); - curSurface = NULL; - WAYLAND_EVENT_OP_END(self); -}; - -static void xdg_borderless_step(MwLL self, MwMouse p, MwU32 serial) { - if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { - if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { - if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); - } else { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM); - } - } else if(p.point.y <= 5) { - if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT); - } else { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP); - } - } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT); - } else if(p.point.x <= 5) { - xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT); - } else if(p.point.y <= CSD_BORDER_FRAME_TOP) { - xdg_toplevel_move(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial); - } - }; -} - -static MwLL currentlyHeldWidget = NULL; - -static void relative_pointer_motion(void* data, - struct zwp_relative_pointer_v1* pointer, - uint32_t timeHi, - uint32_t timeLo, - wl_fixed_t dx, - wl_fixed_t dy, - wl_fixed_t dxUnaccel, - wl_fixed_t dyUnaccel) { - MwLL self = data; - MwMouse p; - - (void)pointer; - (void)timeHi; - (void)timeLo; - (void)dx; - (void)dy; - - WAYLAND_EVENT_OP_START(self); - - p.point.x = wl_fixed_to_int(dxUnaccel); - p.point.y = wl_fixed_to_int(dyUnaccel); - - recursive_dispatch_move(self, &p); - if(self->wayland.locked_pointer) zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); - - WAYLAND_EVENT_OP_END(self); -} - -struct zwp_relative_pointer_v1_listener relative_pointer_listener = - { - relative_pointer_motion}; - -/* zwp_primary_selection_device_manager_v1 setup function */ -static wayland_protocol_t* zwp_relative_pointer_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->relative_pointer_manager = wl_registry_bind(wayland->registry, name, &zwp_relative_pointer_manager_v1_interface, 1); - return NULL; -} - -static void zwp_relative_pointer_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* `wl_pointer.motion` callback */ -static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, - wl_fixed_t surface_x, wl_fixed_t surface_y) { - MwLL self = data; - MwLL topmost_parent = self; - MwMouse p; - (void)time; - (void)wl_pointer; - - WAYLAND_EVENT_OP_START(self); - while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - - self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); - self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); - p.point = self->wayland.cur_mouse_pos; - MwLLDispatch(self, move, &p); - - if(currentlyHeldWidget) { - MwLLDispatch(currentlyHeldWidget, down, &p); - } - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_pointer.button` callback */ -static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { - MwLL self = data; - MwMouse p; - MwBool inArea = MwFALSE; - - (void)wl_pointer; - (void)serial; - (void)time; - - WAYLAND_EVENT_OP_START(self); - - p.point = self->wayland.cur_mouse_pos; - - if(self->wayland.framebuffer.surface) { - inArea |= self->wayland.framebuffer.surface == curSurface; - } - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } - if(inArea) { - switch(button) { - case BTN_LEFT: - p.button = MwMOUSE_LEFT; - break; - case BTN_MIDDLE: - p.button = MwMOUSE_MIDDLE; - break; - case BTN_RIGHT: - p.button = MwMOUSE_RIGHT; - break; - } - self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - MwLLDispatch(self, down, &p); - currentlyHeldWidget = self; - - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - if(currentlyHeldWidget != NULL) { - MwLLDispatch(currentlyHeldWidget, up, &p); - currentlyHeldWidget = NULL; - } else { - MwLLDispatch(self, up, &p); - } - break; - } - } - - if(!self->wayland.has_decorations) { - xdg_borderless_step(self, p, serial); - } - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_pointer.axis` callback */ -static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, - MwU32 axis, wl_fixed_t value) { - (void)data; - (void)wl_pointer; - (void)time; - (void)axis; - (void)value; -}; - -struct wl_pointer_listener pointer_listener = { - .enter = pointer_enter, - .leave = pointer_leave, - .motion = pointer_motion, - .button = pointer_button, - .axis = pointer_axis, -}; - -/* `wl_keyboard.keymap` callback */ -static void keyboard_keymap(void* data, - struct wl_keyboard* wl_keyboard, - MwU32 format, - int32_t fd, - MwU32 size) { - MwLL self = data; - (void)wl_keyboard; - - if(!self->wayland.parent) { - char* map_shm; - struct xkb_keymap* xkb_keymap; - struct xkb_state* xkb_state; - xkb_state = NULL; - - assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - - map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - assert(map_shm != MAP_FAILED); - - xkb_keymap = xkb_keymap_new_from_string( - self->wayland.xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); - munmap(map_shm, size); - close(fd); - - xkb_state = xkb_state_new(xkb_keymap); - - self->wayland.xkb_keymap = xkb_keymap; - self->wayland.xkb_state = xkb_state; - } else { - self->wayland.xkb_keymap = self->wayland.parent->wayland.xkb_keymap; - self->wayland.xkb_state = self->wayland.parent->wayland.xkb_state; - } -}; - -/* `wl_keyboard.enter` callback */ -static void keyboard_enter(void* data, - struct wl_keyboard* wl_keyboard, - MwU32 serial, - struct wl_surface* surface, - struct wl_array* keys) { - MwLL self = data; - (void)wl_keyboard; - (void)surface; - (void)keys; - - WAYLAND_EVENT_OP_START(self); - - self->wayland.keyboard_serial = serial; - - MwLLDispatch(self, focus_in, NULL); - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_keyboard.leave` callback */ -static void keyboard_leave(void* data, - struct wl_keyboard* wl_keyboard, - MwU32 serial, - struct wl_surface* surface) { - MwLL self = data; - (void)wl_keyboard; - (void)serial; - (void)surface; - - WAYLAND_EVENT_OP_START(self); - - MwLLDispatch(self, focus_out, NULL); - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_keyboard.key` callback */ -static void keyboard_key(void* data, - struct wl_keyboard* wl_keyboard, - MwU32 serial, - MwU32 time, - MwU32 key, - MwU32 state) { - MwLL self = data; - MwBool inArea = 0; - - (void)wl_keyboard; - (void)serial; - (void)time; - - WAYLAND_EVENT_OP_START(self); - - if(self->wayland.framebuffer.surface) { - inArea |= self->wayland.framebuffer.surface == curSurface; - } - - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } - if(inArea) { - xkb_layout_index_t layout; - MwU32 levels; - xkb_level_index_t level = 0; - const xkb_keysym_t* syms_out; - MwU32 keycode = key + 8; - MwU64 syms_num; - int i; - - if(!self->wayland.xkb_keymap) { - return; - } - - layout = xkb_state_key_get_layout(self->wayland.xkb_state, keycode); - levels = - xkb_keymap_num_levels_for_key(self->wayland.xkb_keymap, keycode, layout); - - if((((self->wayland.mod_state & 1) == 1) || ((self->wayland.mod_state & 2) == 2)) && levels >= 2) { - level = 1; - } else if(levels >= 1) { - level = 0; - } - syms_num = xkb_keymap_key_get_syms_by_level(self->wayland.xkb_keymap, keycode, layout, level, &syms_out); - if(syms_out == NULL) { - return; - } - - for(i = 0; i < syms_num; i++) { - int sym = syms_out[i]; - int key = -1; - - switch(sym) { - case XKB_KEY_BackSpace: - key = MwLLKeyBackSpace; - break; - case XKB_KEY_Left: - key = MwLLKeyLeft; - break; - case XKB_KEY_Right: - key = MwLLKeyRight; - break; - case XKB_KEY_Up: - key = MwLLKeyUp; - break; - case XKB_KEY_Down: - key = MwLLKeyDown; - break; - case XKB_KEY_Return: - key = MwLLKeyEnter; - break; - case XKB_KEY_Escape: - key = MwLLKeyEscape; - break; - case XKB_KEY_Shift_L: - key = MwLLKeyLeftShift; - break; - case XKB_KEY_Shift_R: - key = MwLLKeyRightShift; - break; - case XKB_KEY_Alt_L: - case XKB_KEY_Alt_R: - key = MwLLKeyAlt; - break; - case XKB_KEY_Control_L: - case XKB_KEY_Control_R: - key = MwLLKeyControl; - break; - default: - if(MwStringIsKeyUTF8(sym)) { - key = sym; - } - } - - if((self->wayland.mod_state & 4) == 4) { - key |= MwLLControlMask; - } - if((self->wayland.mod_state & 8) == 8) { - key |= MwLLAltMask; - } - - if(key != -1) { - if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { - MwLLDispatch(self, key, &key); - } else { - MwLLDispatch(self, key_released, &key); - } - } - } - } - - if(!MwWaylandAlwaysRender) { - MwLLDispatch(self, draw, NULL); - } - - WAYLAND_EVENT_OP_END(self); -}; - -/* `wl_keyboard.modifiers` callback */ -static void keyboard_modifiers(void* data, - struct wl_keyboard* wl_keyboard, - MwU32 serial, - MwU32 mods_depressed, - MwU32 mods_latched, - MwU32 mods_locked, - MwU32 group) { - MwLL self = data; - (void)wl_keyboard; - (void)serial; - (void)group; - (void)mods_latched; - - WAYLAND_EVENT_OP_START(self); - - self->wayland.mod_state = 0; - self->wayland.mod_state |= mods_depressed; - self->wayland.mod_state |= mods_locked; - - WAYLAND_EVENT_OP_END(self); -}; - -struct wl_keyboard_listener keyboard_listener = { - .keymap = keyboard_keymap, - .enter = keyboard_enter, - .leave = keyboard_leave, - .key = keyboard_key, - .modifiers = keyboard_modifiers, -}; - -/* `wl_seat.name` callback */ -static void -wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { - (void)data; - (void)wl_seat; - (void)name; -}; - -/* `wl_seat.capabilities` callback */ -static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, - MwU32 capabilities) { - MwLL self = data; - wl_clipboard_device_context_t* device_ctx_zwp = NULL; - wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); - - WAYLAND_EVENT_OP_START(self); - - if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); - } - if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - self->wayland.pointer_seat = wl_seat; - self->wayland.pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); - } - - if(self->wayland.clipboard_manager.wl != NULL) { - if(self->wayland.supports_zwp) { - device_ctx_zwp = malloc(sizeof(wl_clipboard_device_context_t)); - device_ctx_zwp->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); - device_ctx_zwp->ll = self; - device_ctx_zwp->seat = wl_seat; - device_ctx_zwp->capabilities = capabilities; - } - device_ctx_wl->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); - device_ctx_wl->ll = self; - device_ctx_wl->seat = wl_seat; - device_ctx_wl->capabilities = capabilities; - - if(self->wayland.supports_zwp) { - zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); - arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); - } - wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); - arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); - } - - WAYLAND_EVENT_OP_END(self); -}; - -static void output_geometry(void* data, - struct wl_output* wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char* make, - const char* model, - int32_t transform) { - (void)data; - (void)wl_output; - (void)x; - (void)y; - (void)physical_width; - (void)physical_height; - (void)subpixel; - (void)make; - (void)model; - (void)transform; -}; -static void output_mode(void* data, - struct wl_output* wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) { - MwLL self = data; - (void)wl_output; - (void)flags; - (void)refresh; - self->wayland.mw = width; - self->wayland.mh = height; -}; - -struct wl_output_listener output_listener = { - .geometry = output_geometry, - .mode = output_mode, -}; - -/* `xdg_wm_base.ping` callback */ -void xdg_wm_base_ping(void* data, - struct xdg_wm_base* xdg_wm_base, - MwU32 serial) { - (void)data; - xdg_wm_base_pong(xdg_wm_base, serial); -}; - -/* wl_seat setup function */ -static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - proto->listener = malloc(sizeof(struct wl_seat_listener)); - - ((struct wl_seat_listener*)proto->listener)->name = wl_seat_name; - ((struct wl_seat_listener*)proto->listener)->capabilities = wl_seat_capabilities; - - wl_seat_add_listener(wl_registry_bind(ll->wayland.registry, name, &wl_seat_interface, 1), proto->listener, ll); - - return proto; -} - -static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - free(data->listener); - free(data); -} - -/* wl_output setup function */ -static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { - ll->wayland.output = wl_registry_bind(ll->wayland.registry, name, &wl_output_interface, 1); - wl_output_add_listener(ll->wayland.output, &output_listener, ll); - - return NULL; -} - -static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* wl_compositor setup function */ -static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); - - return NULL; -} - -static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* wl_subcompositor setup function */ -static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) { - if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { - wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); - } else { - wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); - } - - return NULL; -} - -static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)data; - wl_subcompositor_destroy(wayland->sublevel->subcompositor); -} - -/* xdg_wm_base setup function */ -static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - proto->listener = malloc(sizeof(struct xdg_wm_base_listener)); - - ((struct xdg_wm_base_listener*)proto->listener)->ping = xdg_wm_base_ping; - - proto->context = wl_registry_bind(wayland->registry, name, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(proto->context, proto->listener, wayland); - - return proto; -} - -static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - free(data->listener); -} - -/* xdg_wm_base setup function */ -static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - proto->context = wl_registry_bind(wayland->registry, name, &wp_viewporter_interface, 1); - - return proto; -} - -static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* the two decoration manager constructs */ -typedef struct zxdg_decoration_manager_v1_context { - struct zxdg_decoration_manager_v1* manager; - struct zxdg_toplevel_decoration_v1* decoration; -} zxdg_decoration_manager_v1_context_t; - -/* zxdg_decoration_manager_v1 setup function */ -static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - zxdg_decoration_manager_v1_context_t* ctx = malloc(sizeof(zxdg_decoration_manager_v1_context_t)); - proto->listener = NULL; - - ctx->manager = wl_registry_bind(wayland->registry, name, &zxdg_decoration_manager_v1_interface, 1); - ; - - proto->context = ctx; - - return proto; -} - -static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -/* Standard Wayland event loop. */ -static int event_loop(MwLL handle) { - struct pollfd fd; - struct timespec timeout; - struct _MwLLWayland* wayland = &handle->wayland; - - timeout.tv_nsec = 1; - timeout.tv_sec = 0; - - if(wayland->display == NULL) { - return 0; - } - fd.fd = wl_display_get_fd(wayland->display); - fd.events = POLLIN; - - /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ - while(wl_display_flush(wayland->display) == -1) { - if(errno != EAGAIN) { - return MwFALSE; - } - - while(poll(&fd, 1, -1) == -1) { - if(errno != EINTR && errno != EAGAIN) { - wl_display_cancel_read(wayland->display); - - MwLLDispatch(handle, close, NULL); - return 0; - } - } - } - - wl_display_prepare_read(handle->wayland.display); - /* Condition where no events are being sent. */ - if(!poll(&fd, 1, timeout.tv_nsec)) { - wl_display_cancel_read(wayland->display); - - update_buffer(handle, &wayland->framebuffer); - if(wayland->type == MWLL_WAYLAND_TOPLEVEL) - update_buffer(handle, &wayland->backbuffer); - return 0; - } - wl_display_read_events(wayland->display); - if(wl_display_dispatch_pending(wayland->display) < 0) { - wl_display_cancel_read(wayland->display); - } - wl_display_flush(handle->wayland.display); - - return 1; -} - -/* make the fuck sure that we're configurd */ -static void hang_until_configured(MwLL handle) { - while(!handle->wayland.configured) { - if(wl_display_roundtrip(handle->wayland.display) == -1) { - printf("roundtrip failed\n"); - raise(SIGTRAP); - return; - } - event_loop(handle); - } -} - -/* `xdg_toplevel.configure` callback */ -static void xdg_toplevel_configure(void* data, - struct xdg_toplevel* xdg_toplevel, - MwI32 width, MwI32 height, - struct wl_array* states) { - MwLL self = data; - (void)states; - (void)xdg_toplevel; - - /* Yes, somehow this can get called before */ - if(!self->wayland.configured) { - return; - } - - if(width == 0 || height == 0) { - width = self->wayland.ww; - height = self->wayland.wh; - /* if it's still 0 then bail */ - if(width == 0 || height == 0) { - return; - } - } - - region_invalidate(self); - self->wayland.ww = width; - self->wayland.wh = height; - - xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); - - backbuffer_destroy(&self->wayland); - backbuffer_setup(&self->wayland); - framebuffer_destroy(&self->wayland); - framebuffer_setup(&self->wayland); - - region_setup(self); - MwLLDispatch(self, resize, NULL); - - recursive_dispatch_resize(self); - - if(self->wayland.pointer_constrained) { - zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); - wl_surface_commit(self->wayland.framebuffer.surface); - } -}; - -/* `xdg_surface.close` callback */ -static void xdg_toplevel_close( - void* data, struct xdg_toplevel* xdg_toplevel) { - MwLL self = data; - (void)xdg_toplevel; - WAYLAND_EVENT_OP_START(self); - MwLLDispatch(self, close, NULL); - WAYLAND_EVENT_OP_END(self); -}; - -/* `xdg_surface.configure` callback */ -static void xdg_surface_configure( - void* data, struct xdg_surface* xdg_surface, MwU32 serial) { - MwLL self = data; - - xdg_surface_ack_configure(xdg_surface, serial); - - MwLLDispatch(self, draw, NULL); - - if(self->wayland.configured) { - update_buffer(self, &self->wayland.framebuffer); - update_buffer(self, &self->wayland.backbuffer); - } - - self->wayland.configured = MwTRUE; -} - -/* wl_shm setup function */ -static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - - return NULL; -} - -static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - (void)data; -} - -static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { - memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); - // Yes this is needed every time, it's how we fix weston. - if(self->wayland.configured) - wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - wl_surface_commit(buffer->surface); -} - -static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { - int stride = width * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - - buffer->buf_size = width * height * 4; - - buffer->fd = mkstemp(temp_name); - unlink(temp_name); - - if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(buffer->fd); - return; - } - if(ftruncate(buffer->fd, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(buffer->fd); - return; - } - - buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); - buffer->buf_back = malloc(buffer->buf_size); - - fsync(buffer->fd); - - if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { - close(buffer->fd); - printf("failure setting up wl_shm: could not create pool.\n"); - return; - } - buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->setup = MwTRUE; -} - -static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { - close(buffer->fd); - if(buffer->buf) munmap(buffer->buf, buffer->buf_size); - if(buffer->buf_back) free(buffer->buf_back); - if(buffer->shm_buffer) wl_buffer_destroy(buffer->shm_buffer); - if(buffer->shm_pool) wl_shm_pool_destroy(buffer->shm_pool); - if(buffer->shm_pool_back) wl_shm_pool_destroy(buffer->shm_pool_back); - buffer->setup = MwFALSE; -} - -static void framebuffer_setup(struct _MwLLWayland* wayland) { - buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh); - - wayland->front_cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf_back, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); - wayland->front_cairo = cairo_create(wayland->front_cs); - - memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); - if(wayland->configured) - wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); - wl_surface_commit(wayland->framebuffer.surface); - - hang_until_configured((MwLL)wayland); - update_buffer((MwLL)wayland, &wayland->framebuffer); -}; -static void framebuffer_destroy(struct _MwLLWayland* wayland) { - buffer_destroy(&wayland->framebuffer); - cairo_destroy(wayland->front_cairo); - cairo_surface_destroy(wayland->front_cs); -}; - -static void backbuffer_setup(struct _MwLLWayland* wayland) { - if(wayland->type != MWLL_WAYLAND_TOPLEVEL) { - return; - } - MwU32 w = wayland->ww; - MwU32 h = wayland->wh; - if(!wayland->has_decorations) { - w += (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - h += (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); - } - buffer_setup(&wayland->backbuffer, w, h); - - wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf_back, CAIRO_FORMAT_ARGB32, w, h, 4 * w); - wayland->back_cairo = cairo_create(wayland->back_cs); - - memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); - if(wayland->configured) - wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); - wl_surface_commit(wayland->backbuffer.surface); - hang_until_configured((MwLL)wayland); - update_buffer((MwLL)wayland, &wayland->backbuffer); -}; -static void backbuffer_destroy(struct _MwLLWayland* wayland) { - buffer_destroy(&wayland->backbuffer); - cairo_destroy(wayland->back_cairo); - cairo_surface_destroy(wayland->back_cs); -}; - -static void region_invalidate(MwLL handle) { - if(!handle->wayland.configured) { - return; - } - wl_region_subtract(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); -} -static void region_setup(MwLL handle) { - MwLL parent = handle->wayland.parent; - int width = handle->wayland.ww; - int height = handle->wayland.wh; - - if(!handle->wayland.configured) { - return; - } - - wl_region_add(handle->wayland.o_region, 0, 0, width, height); - - if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); - } else { - if(parent) { - if(width - handle->wayland.x > parent->wayland.ww) { - width = parent->wayland.ww - handle->wayland.x; - } - if(height - handle->wayland.y > parent->wayland.wh) { - height = parent->wayland.wh - handle->wayland.y; - } - } else { - if(!handle->wayland.has_decorations) { - width += CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; - height += CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; - } - } - wl_region_add(handle->wayland.region, 0, 0, width, height); - } - - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region); - wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); - } - wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); - wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); -} - -static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - - proto->context = wl_registry_bind(wayland->registry, name, &xdg_toplevel_icon_manager_v1_interface, 1); - proto->listener = NULL; - - return proto; -} - -static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - free(data->listener); -} - -/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ -static void setup_callbacks(struct _MwLLWayland* wayland) { -/* Convience macro for adding the interface functions to the setup map */ -#define WL_INTERFACE(interface) \ - do { \ - wayland_protocol_callback_table_t* cb = malloc(sizeof(wayland_protocol_callback_table_t)); \ - cb->setup = (wl_setup_func*)interface##_setup; \ - cb->destroy = (wl_destroy_func*)interface##_interface_destroy; \ - shput(wayland->wl_protocol_setup_map, interface##_interface.name, cb); \ - } while(0); - - wayland->registry_listener.global = new_protocol; - wayland->registry_listener.global_remove = protocol_removed; - wayland->wl_protocol_setup_map = NULL; - wayland->wl_protocol_map = NULL; - - WL_INTERFACE(wl_shm); - WL_INTERFACE(wl_compositor); - WL_INTERFACE(wl_seat); - WL_INTERFACE(wl_output); - WL_INTERFACE(wl_data_device_manager); - WL_INTERFACE(zwp_primary_selection_device_manager_v1); - WL_INTERFACE(zwp_pointer_constraints_v1); - WL_INTERFACE(zwp_relative_pointer_manager_v1); - WL_INTERFACE(xdg_wm_base); - if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { - WL_INTERFACE(wp_viewporter); - WL_INTERFACE(zxdg_decoration_manager_v1); - WL_INTERFACE(xdg_toplevel_icon_manager_v1); - WL_INTERFACE(wl_subcompositor); - } else if(wayland->type == MWLL_WAYLAND_POPUP) { - } else { - WL_INTERFACE(wl_subcompositor); - } -#undef WL_INTERFACE -} - -/* Toplevel setup function */ -static void setup_toplevel(MwLL r, int x, int y) { - r->wayland.type = MWLL_WAYLAND_TOPLEVEL; - r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); - r->wayland.x = x; - r->wayland.y = y; - - setup_callbacks(&r->wayland); - - /* Connect to the Wayland compositor */ - r->wayland.display = wl_display_connect(NULL); - if(r->wayland.display == NULL) { - printf("wayland: failed to create display\n"); - raise(SIGTRAP); - return; - } - - /* Do a roundtrip to ensure all interfaces are setup. */ - r->wayland.registry = wl_display_get_registry(r->wayland.display); - wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); - if(wl_display_roundtrip(r->wayland.display) == -1) { - printf("roundtrip failed\n"); - raise(SIGTRAP); - return; - } - - /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { - r->wayland.has_decorations = MwTRUE; - } - - r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ - r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); - wl_subsurface_set_desync(r->wayland.toplevel->ssurface); - - r->wayland.toplevel->xdg_surface = - xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); - r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); - - /* setup mandatory listeners */ - r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; - - r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; - r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; - - xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); - xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, - r); - - xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App"); - xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); - - /* Perform the initial commit and wait for the first configure event */ - wl_surface_commit(r->wayland.backbuffer.surface); - wl_surface_commit(r->wayland.framebuffer.surface); - while(!r->wayland.configured) { - event_loop(r); - } - - /* setup decorations if we can */ - if(r->wayland.has_decorations) { - zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; - - dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - dec->manager, r->wayland.toplevel->xdg_top_level); - - zxdg_toplevel_decoration_v1_set_mode( - dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - } else { - wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); - } -} - -/* Toplevel destroy function */ -static void destroy_toplevel(MwLL r) { - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { - zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; - zxdg_decoration_manager_v1_destroy(dec->manager); - } - - wl_surface_destroy(r->wayland.framebuffer.surface); - - wl_compositor_destroy(r->wayland.compositor); - - xdg_surface_destroy(r->wayland.toplevel->xdg_surface); - - xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); - - xkb_state_unref(r->wayland.xkb_state); - - xkb_context_unref(r->wayland.xkb_context); - - xkb_keymap_unref(r->wayland.xkb_keymap); - - free(r->wayland.toplevel); - - wl_registry_destroy(r->wayland.registry); - - wl_display_disconnect(r->wayland.display); - - r->wayland.configured = MwFALSE; -} - -/* Sublevel setup function */ -static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { - struct wl_compositor* compositor = parent->wayland.compositor; - struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; - - r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); - r->wayland.sublevel->parent = parent; - - r->wayland.type = MWLL_WAYLAND_SUBLEVEL; - - setup_callbacks(&r->wayland); - - r->wayland.registry = wl_display_get_registry(parent->wayland.display); - r->wayland.display = parent->wayland.display; - - if(parent->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - r->wayland.sublevel->xdg_surface = parent->wayland.toplevel->xdg_surface; - } else { - r->wayland.sublevel->xdg_surface = parent->wayland.sublevel->xdg_surface; - } - - wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); - if(wl_display_roundtrip(r->wayland.display) == -1) { - printf("roundtrip failed\n"); - raise(SIGTRAP); - return; - } - - r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); - - r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); - - wl_subsurface_set_desync(r->wayland.sublevel->subsurface); - wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); - - if(parent) { - wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); - } - - r->wayland.xkb_keymap = parent->wayland.xkb_keymap; - r->wayland.xkb_state = parent->wayland.xkb_state; - - r->wayland.configured = MwTRUE; -} - -/* Sublevel setup function */ -static void destroy_sublevel(MwLL r) { - wl_subsurface_destroy(r->wayland.sublevel->subsurface); - - wl_registry_destroy(r->wayland.registry); - - free(r->wayland.sublevel); - - r->wayland.configured = MwFALSE; -} - -static void popup_configure(void* data, - struct xdg_popup* xdg_popup, - int32_t x, - int32_t y, - int32_t width, - int32_t height) { - MwLL self = data; - (void)xdg_popup; - - self->wayland.x = x; - self->wayland.y = y; - self->wayland.ww = width; - self->wayland.wh = height; -}; - -static void popup_done(void* data, - struct xdg_popup* xdg_popup) { - (void)data; - (void)xdg_popup; -}; - -struct xdg_popup_listener popup_listener = { - .configure = popup_configure, - .popup_done = popup_done, -}; - -/* Popup setup function */ -static void setup_popup(MwLL r, int x, int y, MwLL parent) { - struct xdg_surface* xdg_surface; - MwLL topmost_parent = r->wayland.parent; - - r->wayland.type = MWLL_WAYLAND_POPUP; - r->wayland.x = x; - r->wayland.y = y; - r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); - - while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - topmost_parent = topmost_parent->wayland.parent; - } - if(!topmost_parent->wayland.has_decorations) { - r->wayland.x += ceil((float)CSD_BORDER_FRAME_LEFT / 2.); - r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.); - } - - setup_callbacks(&r->wayland); - - /* Connect to the Wayland compositor */ - r->wayland.display = parent->wayland.display; - - /* Do a roundtrip to ensure all interfaces are setup. */ - r->wayland.registry = wl_display_get_registry(r->wayland.display); - wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); - if(wl_display_roundtrip(r->wayland.display) == -1) { - printf("roundtrip failed\n"); - raise(SIGTRAP); - return; - } - - /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { - r->wayland.has_decorations = MwTRUE; - } - - r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; - - r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); - - xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); - xdg_positioner_set_anchor_rect( - r->wayland.popup->xdg_positioner, - r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); - - xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; - r->wayland.xkb_keymap = topmost_parent->wayland.xkb_keymap; - r->wayland.xkb_state = topmost_parent->wayland.xkb_state; - - r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - - r->wayland.popup->xdg_surface = - xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); - - r->wayland.popup->xdg_popup = xdg_surface_get_popup( - r->wayland.popup->xdg_surface, - xdg_surface, - r->wayland.popup->xdg_positioner); - - xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); - - r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; - xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r); - - /* Perform the initial commit and wait for the first configure event */ - wl_surface_commit(r->wayland.framebuffer.surface); - while(!r->wayland.configured) { - event_loop(r); - } -} - -/* Popup destroy function */ -static void destroy_popup(MwLL r) { - xdg_popup_destroy(r->wayland.popup->xdg_popup); - - xdg_surface_destroy(r->wayland.popup->xdg_surface); - - xdg_positioner_destroy(r->wayland.popup->xdg_positioner); - - wl_surface_destroy(r->wayland.framebuffer.surface); - - wl_registry_destroy(r->wayland.registry); - - r->wayland.configured = MwFALSE; -} - -static void clip(MwLL handle) { - MwLL parent = handle->wayland.parent; - if(parent && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - cairo_reset_clip(handle->wayland.front_cairo); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, (parent->wayland.ww + handle->wayland.x), (parent->wayland.wh + handle->wayland.y)); - cairo_clip(handle->wayland.front_cairo); - } -} - -static void wl_logger(const char* fmt, va_list args) { - vprintf(fmt, args); - raise(SIGTRAP); -} - -static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int height, enum _MwLLWaylandType ty) { - /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. - */ - r->common.coordinate_type = MwCOORDINATE_LOCAL; - - r->common.type = MwLLBackendWayland; - - if(width < 2) width = 2; - if(height < 2) height = 2; - - if(x == MwDEFAULT) { - x = 0; - } - if(y == MwDEFAULT) { - y = 0; - } - - r->wayland.ww = width; - r->wayland.wh = height; - r->wayland.x = x; - r->wayland.y = y; - r->wayland.parent = parent; - - if(ty == MWLL_WAYLAND_UNKNOWN) { - if(parent == NULL) { - setup_toplevel(r, x, y); - } else { - setup_sublevel(parent, r, x, y); - } - } else { - switch(ty) { - case MWLL_WAYLAND_UNKNOWN: - break; - case MWLL_WAYLAND_TOPLEVEL: - setup_toplevel(r, x, y); - break; - case MWLL_WAYLAND_SUBLEVEL: - setup_sublevel(parent, r, x, y); - break; - case MWLL_WAYLAND_POPUP: - setup_popup(r, x, y, parent); - break; - } - } - - framebuffer_destroy(&r->wayland); - backbuffer_destroy(&r->wayland); - - framebuffer_setup(&r->wayland); - backbuffer_setup(&r->wayland); - - r->wayland.region = wl_compositor_create_region(r->wayland.compositor); - r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); - region_setup(r); - - MwLLForceRender(r); - if(parent != NULL) { - MwLLForceRender(parent); - } - - if(!r->wayland.has_decorations) { - MwLLBeginDraw(r); - MwLLEndDraw(r); - } -} - -#ifdef USE_DBUS -static void dark_theme_listener(MwLL handle, MwU32 new_value) { - wl_dark_theme = (new_value == 1) ? 1 : 0; - - MwLLDispatch(handle, dark_theme, &wl_dark_theme); -} - -static void detect_dark_theme(MwLL handle) { - MwU32 value = 0; - - MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - wl_dark_theme = (value == 1) ? 1 : 0; - - MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - - MwLLDispatch(handle, dark_theme, &wl_dark_theme); -} -#endif - -static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - r = malloc(sizeof(*r)); - memset(r, 0, sizeof(*r)); - MwLLCreateCommon(r); - - widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); - -#ifdef USE_DBUS - if(!parent && wl_call_tbl.has_dbus) { - wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); - r->wayland.dark_theme_detection = MwTRUE; - } -#endif - - return r; -} - -static void MwLLDestroyImpl(MwLL handle) { - int i; - struct timeval tv; - struct timespec t = { - .tv_sec = 0, - .tv_nsec = 0, - }; - int select_ret; - - event_loop(handle); - wl_flush(handle); - - if(pthread_mutex_timedlock(&handle->wayland.eventsMutex, &t) != 0) { - printf("WARNING: Couldn't call MwLLDestroyImpl due to deadlock.\n"); - return; - }; - - MwLLDestroyCommon(handle); - - /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ - tv.tv_sec = 0; - tv.tv_usec = 1000; - do { - select_ret = select(1, NULL, NULL, NULL, &tv); - } while((select_ret == -1) && (errno == EINTR)); - - pthread_mutex_unlock(&handle->wayland.eventsMutex); - pthread_mutex_destroy(&handle->wayland.eventsMutex); - -#ifdef USE_DBUS - if(!wl_call_tbl.has_dbus) { - MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); - } -#endif - - wl_region_destroy(handle->wayland.region); - - if(handle->wayland.supports_zwp) { - zwp_primary_selection_source_v1_destroy(handle->wayland.clipboard_source.zwp); - } else { - wl_data_source_destroy(handle->wayland.clipboard_source.wl); - } - - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - destroy_toplevel(handle); - } else if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - destroy_sublevel(handle); - } else if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - destroy_popup(handle); - } - - if(handle->wayland.framebuffer.setup) { - framebuffer_destroy(&handle->wayland); - wl_surface_destroy(handle->wayland.framebuffer.surface); - } - if(handle->wayland.backbuffer.setup) { - backbuffer_destroy(&handle->wayland); - wl_surface_destroy(handle->wayland.backbuffer.surface); - } - buffer_destroy(&handle->wayland.cursor); - if(handle->wayland.icon != NULL) { - buffer_destroy(handle->wayland.icon); - wl_surface_destroy(handle->wayland.icon->surface); - } - - for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { - void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); - - if(ctx != NULL) { - handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); - } - shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); - free(handle->wayland.wl_protocol_setup_map[i].value); - free(ctx); - } - shfree(handle->wayland.wl_protocol_map); - shfree(handle->wayland.wl_protocol_setup_map); - - // wl_keyboard_destroy(handle->wayland.keyboard); - // wl_pointer_destroy(handle->wayland.pointer); - - if(handle->wayland.supports_zwp) { - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { - if(handle->wayland.clipboard_devices_zwp[i]->device.zwp) zwp_primary_selection_device_v1_destroy(handle->wayland.clipboard_devices_zwp[i]->device.zwp); - free(handle->wayland.clipboard_devices_zwp[i]); - } - } else { - printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); - } - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { - wl_data_device_destroy(handle->wayland.clipboard_devices_wl[i]->device.wl); - free(handle->wayland.clipboard_devices_wl[i]); - } - - wl_flush(handle); - - if(currentlyHeldWidget == handle) { - currentlyHeldWidget = NULL; - } -} - -static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { - *x = handle->wayland.x; - *y = handle->wayland.y; - *w = handle->wayland.ww; - *h = handle->wayland.wh; -} - -static void MwLLSetXYImpl(MwLL handle, int x, int y) { - region_invalidate(handle); - handle->wayland.x = x; - handle->wayland.y = y; - if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); - } - region_setup(handle); - - MwLLDispatch(handle, draw, NULL); -} - -static void MwLLSetWHImpl(MwLL handle, int w, int h) { - region_invalidate(handle); - - /* Prevent an integer underflow when the w/h is too low */ - if((w < 2 || h < 2)) { - handle->wayland.ww = 2; - handle->wayland.wh = 2; - } else { - handle->wayland.ww = w; - handle->wayland.wh = h; - } - - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { - xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); - } - - if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) { - handle->wayland.dispatching_resize = MwTRUE; - MwLLDispatch(handle, resize, NULL); - handle->wayland.dispatching_resize = MwFALSE; - } - - if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - destroy_popup(handle); - wl_flush(handle); - setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); - } - - region_setup(handle); - - framebuffer_destroy(&handle->wayland); - framebuffer_setup(&handle->wayland); - backbuffer_destroy(&handle->wayland); - backbuffer_setup(&handle->wayland); - MwLLDispatch(handle, draw, NULL); - handle->wayland.events_pending = 1; -} - -static void MwLLBeginDrawImpl(MwLL handle) { - if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - handle->wayland.selected_cairo = handle->wayland.front_cairo; - return; - } - - if(!handle->wayland.has_decorations) { - int x; - MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; - MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; - cairo_set_line_width(handle->wayland.back_cairo, 4.0); - for(x = 0; x < w; x++) { - float placeholder = (float)x / (float)w; - cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25); - - cairo_move_to(handle->wayland.back_cairo, w - x, 0); - cairo_line_to(handle->wayland.back_cairo, w - x, CSD_BORDER_FRAME_TOP); - cairo_stroke(handle->wayland.back_cairo); - - cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP); - cairo_line_to(handle->wayland.back_cairo, x, h); - cairo_stroke(handle->wayland.back_cairo); - } - cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5); - cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, 0, h); - cairo_stroke(handle->wayland.back_cairo); - cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, w, 0); - cairo_stroke(handle->wayland.back_cairo); - - cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5); - cairo_move_to(handle->wayland.back_cairo, 0, h); - cairo_line_to(handle->wayland.back_cairo, w, h); - cairo_stroke(handle->wayland.back_cairo); - cairo_move_to(handle->wayland.back_cairo, w, 0); - cairo_line_to(handle->wayland.back_cairo, w, h); - cairo_stroke(handle->wayland.back_cairo); - - if(strlen(handle->wayland.title) != 0) { - int y, x; - int i = 0, sx = 0, sy = 0; - int tw, th; - unsigned char* px; - MwRect r; - MwLLPixmap p; - tw = strlen(handle->wayland.title) * 7; - th = 14; - px = malloc(tw * th * 4); - assert(px); - - memset(px, 0, tw * th * 4); - - handle->wayland.selected_cairo = handle->wayland.back_cairo; - - while(handle->wayland.title[i]) { - int out; - i += MwUTF8ToUTF32(handle->wayland.title + i, &out); - - if(out > 0xff) { - out = 0; - } - - for(y = 0; y < 14; y++) { - for(x = 0; x < 7; x++) { - unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; - int col = MwFontData[out].data[y] & (1 << ((7 - 1) - x)) ? 255 : 0; - ppx[0] = col; - ppx[1] = col; - ppx[2] = col; - ppx[3] = col; - } - } - sx += 7; - } - - p = MwLLCreatePixmap(handle, px, tw, th); - r.x = 5; - r.y = 5; - r.width = tw; - r.height = th; - - MwLLDrawPixmap(handle, &r, p); - MwLLDestroyPixmap(p); - free(px); - } - update_buffer(handle, &handle->wayland.backbuffer); - } - handle->wayland.selected_cairo = handle->wayland.front_cairo; -} - -static void MwLLEndDrawImpl(MwLL handle) { - if(handle->wayland.configured) { - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - update_buffer(handle, &handle->wayland.backbuffer); - } - update_buffer(handle, &handle->wayland.framebuffer); - } -} - -static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i; - - clip(handle); - - cairo_set_source_rgba(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); - cairo_new_path(handle->wayland.front_cairo); - for(i = 0; i < points_count; i++) { - if(i == 0) { - cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y); - } else { - cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y); - } - } - cairo_close_path(handle->wayland.front_cairo); - - cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE); - cairo_fill(handle->wayland.front_cairo); - cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_OVER); - - handle->wayland.events_pending = 1; -} - -static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - int i; - - clip(handle); - - cairo_set_antialias(handle->wayland.front_cairo, CAIRO_ANTIALIAS_NONE); - cairo_set_line_cap(handle->wayland.front_cairo, CAIRO_LINE_CAP_SQUARE); - cairo_set_source_rgba(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); - cairo_new_path(handle->wayland.front_cairo); - for(i = 0; i < 2; i++) { - if(i == 0) { - cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y); - } else { - cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y); - } - } - cairo_close_path(handle->wayland.front_cairo); - cairo_stroke(handle->wayland.front_cairo); - - handle->wayland.events_pending = 1; -} - -static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - (void)handle; - - c->common.red = r; - c->common.blue = b; - c->common.green = g; - - return c; -} - -static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; - c->common.red = r; - c->common.blue = b; - c->common.green = g; -} - -static void MwLLFreeColorImpl(MwLLColor color) { - free(color); -} - -static int MwLLPendingImpl(MwLL handle) { - struct timespec timeout = { - .tv_nsec = 1, - .tv_sec = 0, - }; - struct pollfd fd = { - .fd = wl_display_get_fd(handle->wayland.display), - .events = POLLOUT, - }; - int pending = 0; - -#ifdef USE_DBUS - if(wl_call_tbl.has_dbus) { - if(handle->wayland.dark_theme_detection) { - - handle->wayland.dark_theme_detection = MwFALSE; - detect_dark_theme(handle); - MwLLDispatch(handle, draw, NULL); - } else { - MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); - } - } -#endif - - if(!handle->wayland.did_initial_resize) { - recursive_dispatch_resize(handle); - handle->wayland.did_initial_resize = 1; - } - - if(!MwWaylandAlwaysRender) { - wl_display_prepare_read(handle->wayland.display); - if(!poll(&fd, 1, timeout.tv_nsec)) { - wl_display_cancel_read(handle->wayland.display); - } else { - wl_display_read_events(handle->wayland.display); - wl_display_flush(handle->wayland.display); - if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { - wl_display_cancel_read(handle->wayland.display); - } - } - } else { - if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { - wl_display_cancel_read(handle->wayland.display); - } - wl_display_flush(handle->wayland.display); - } - - if(MwWaylandAlwaysRender) { - handle->wayland.did_event_loop_early = MwTRUE; - event_loop(handle); - return pending; - } - - update_buffer(handle, &handle->wayland.framebuffer); - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - update_buffer(handle, &handle->wayland.backbuffer); - } - - return handle->wayland.force_render || handle->wayland.events_pending || pending; -} - -static void MwLLNextEventImpl(MwLL handle) { - if(!MwWaylandAlwaysRender) { - if(handle->wayland.did_event_loop_early) { - handle->wayland.did_event_loop_early = MwFALSE; - } else { - event_loop(handle); - } - } - - if(handle->wayland.force_render) { - MwLLDispatch(handle, draw, NULL); - if(handle->wayland.configured) update_buffer(handle, &handle->wayland.framebuffer); - handle->wayland.force_render = 0; - } - if(handle->wayland.events_pending) { - handle->wayland.events_pending = 0; - } -} - -static void MwLLSetTitleImpl(MwLL handle, const char* title) { - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); - } - if(!handle->wayland.has_decorations) { - strncpy(handle->wayland.title, title, 255); - MwLLBeginDraw(handle); - MwLLEndDraw(handle); - } -} - -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { - MwLLPixmap r = malloc(sizeof(*r)); - (void)handle; - - r->common.width = width; - r->common.height = height; - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); - - r->wayland.cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - - MwLLPixmapUpdate(r); - - return r; -} - -static void MwLLPixmapUpdateImpl(MwLLPixmap r) { - int i; - unsigned char* d; - - cairo_surface_flush(r->wayland.cs); - d = cairo_image_surface_get_data(r->wayland.cs); - for(i = 0; i < r->common.width * r->common.height * 4; i += 4) { - MwU32* p = (MwU32*)&d[i]; - *p <<= 8; - *p |= r->common.raw[i + 3]; - *p <<= 8; - *p |= r->common.raw[i + 0]; - *p <<= 8; - *p |= r->common.raw[i + 1]; - *p <<= 8; - *p |= r->common.raw[i + 2]; - } - cairo_surface_mark_dirty(r->wayland.cs); -} - -static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - cairo_surface_destroy(pixmap->wayland.cs); - free(pixmap->common.raw); - free(pixmap); -} - -static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - cairo_t* c; - cairo_surface_t* cs; - cairo_t* selected_cairo = handle->wayland.selected_cairo ? handle->wayland.selected_cairo : handle->wayland.front_cairo; - - cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); - c = cairo_create(cs); - - clip(handle); - - cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); - - cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); - cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - - cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_OVER); - - cairo_paint(c); - - cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); - cairo_paint(selected_cairo); - - cairo_destroy(c); - cairo_surface_destroy(cs); - - MwLLForceRender(handle); - wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); -} -static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { - struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; - struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(icon_manager); - MwU64 size = pixmap->common.width * pixmap->common.height * 4; - int i = 0; - - if(handle->wayland.icon == NULL) { - handle->wayland.icon = malloc(sizeof(struct _MwLLWaylandShmBuffer)); - memset(handle->wayland.icon, 0, sizeof(struct _MwLLWaylandShmBuffer)); - handle->wayland.icon->shm = handle->wayland.framebuffer.shm; - } - - if(handle->wayland.icon->setup) { - buffer_destroy(handle->wayland.icon); - wl_surface_destroy(handle->wayland.icon->surface); - } - handle->wayland.icon->surface = wl_compositor_create_surface(handle->wayland.compositor); - - buffer_setup(handle->wayland.icon, pixmap->common.width, pixmap->common.height); - - wl_surface_attach(handle->wayland.icon->surface, handle->wayland.icon->shm_buffer, 0, 0); - wl_surface_commit(handle->wayland.icon->surface); - - for(; i < size; i += 2) { - handle->wayland.icon->buf_back[i] = pixmap->common.raw[i + 2]; - handle->wayland.icon->buf_back[i + 1] = pixmap->common.raw[i + 1]; - handle->wayland.icon->buf_back[i + 2] = pixmap->common.raw[i + 0]; - handle->wayland.icon->buf_back[i + 3] = 255; - } - - if(handle->wayland.configured) update_buffer(handle, handle->wayland.icon); - - xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); - - xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); - } - } -} - -static void MwLLForceRenderImpl(MwLL handle) { - wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); - - handle->wayland.force_render = MwTRUE; - if(handle->wayland.parent) { - handle->wayland.parent->wayland.force_render = MwTRUE; - } -} - -static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - int x, y, xs, ys; - - if(handle->wayland.cursor.setup) { - buffer_destroy(&handle->wayland.cursor); - wl_surface_destroy(handle->wayland.cursor.surface); - } - buffer_setup(&handle->wayland.cursor, image->width, image->height); - memset(handle->wayland.cursor.buf_back, 0, handle->wayland.cursor.buf_size); - - xs = -mask->x + image->x; - ys = mask->height + mask->y; - ys = image->height + image->y - ys; - - for(y = 0; y < mask->height; y++) { - unsigned int d = mask->data[y]; - for(x = mask->width - 1; x >= 0; x--) { - int idx = ((y * image->width) + x) * 4; - - if(d & 1) { - handle->wayland.cursor.buf_back[idx + 3] = 255; - }; - d = d >> 1; - } - } - for(y = 0; y < image->height; y++) { - unsigned int d = image->data[y]; - for(x = image->width - 1; x >= 0; x--) { - int px = 0; - int idx = (((y + ys) * image->width) + (x + xs)) * 4; - - if(d & 1) { - px = 255; - }; - - handle->wayland.cursor.buf_back[idx] = px; - handle->wayland.cursor.buf_back[idx + 1] = px; - handle->wayland.cursor.buf_back[idx + 2] = px; - d = d >> 1; - } - } - - handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); - wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); - wl_surface_commit(handle->wayland.cursor.surface); - update_buffer(handle, &handle->wayland.cursor); - - /* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */ - if(handle->wayland.pointer != NULL) { - // wl_pointer_set_cursor(handle->wayland.pointer, handle->wayland.pointer_serial, handle->wayland.cursor.surface, 0, 0); - } -} - -static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - MwLL p = handle->wayland.parent; - int x = 0, y = 0; - while(p != NULL) { - x += p->wayland.x; - y += p->wayland.y; - p = p->wayland.parent; - } - - handle->wayland.detatching = MwTRUE; - handle->wayland.detach_point = *point; - handle->wayland.detach_point.x += x; - handle->wayland.detach_point.y += y; -} - -static void MwLLShowImpl(MwLL handle, int show) { - if(!handle->wayland.configured) { - return; - } - /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ - if(handle->wayland.framebuffer.surface) { - wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); - wl_surface_commit(handle->wayland.framebuffer.surface); - } - if(handle->wayland.backbuffer.surface) { - wl_surface_attach(handle->wayland.backbuffer.surface, show ? handle->wayland.backbuffer.shm_buffer : NULL, 0, 0); - wl_surface_commit(handle->wayland.backbuffer.surface); - } -} - -static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - (void)handle; - (void)parent; - /* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ -} - -static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); - xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); - } -} - -static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - (void)toggle; - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { - zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; - - dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - dec->manager, handle->wayland.toplevel->xdg_top_level); - - zxdg_toplevel_decoration_v1_set_mode( - dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); - } - } -} - -static void MwLLFocusImpl(MwLL handle) { - (void)handle; - printf("[WARNING] MwLLFocus not supported on Wayland\n"); -} - -static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MwLL topmost_parent = handle; - while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { - if(toggle) { - topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.backbuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - wl_surface_commit(topmost_parent->wayland.backbuffer.surface); - zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); - handle->wayland.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(handle->wayland.relative_pointer_manager, handle->wayland.pointer); - zwp_relative_pointer_v1_add_listener(handle->wayland.relative_pointer, &relative_pointer_listener, topmost_parent); - } else { - if(topmost_parent->wayland.locked_pointer) { - zwp_locked_pointer_v1_destroy(topmost_parent->wayland.locked_pointer); - topmost_parent->wayland.locked_pointer = NULL; - } - if(topmost_parent->wayland.relative_pointer) { - zwp_relative_pointer_v1_destroy(topmost_parent->wayland.relative_pointer); - topmost_parent->wayland.relative_pointer = NULL; - } - } - handle->wayland.do_lock_pointer = toggle; - } else { - printf("[WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 and relative_pointer_manager_v1 are required.\n"); - } -} - -static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { - int i; - - if(handle->wayland.clipboard_buffer != NULL) { - free(handle->wayland.clipboard_buffer); - } - handle->wayland.clipboard_buffer = malloc(strlen(text)); - strcpy(handle->wayland.clipboard_buffer, text); - - if(clipboard_type == MwCLIPBOARD_PRIMARY) { - if(handle->wayland.supports_zwp) { - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; - zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); - } - } else { - printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); - } - } else { - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_wl[i]; - wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); - } - } -} - -static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { - int i; - if(clipboard_type == MwCLIPBOARD_PRIMARY) { - if(handle->wayland.supports_zwp) { - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { - wl_clipboard_read( - handle->wayland.clipboard_devices_zwp[i], clipboard_type); - } - } else { - printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); - } - } else { - for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { - wl_clipboard_read( - handle->wayland.clipboard_devices_wl[i], clipboard_type); - } - } - return; -} - -static void MwLLMakeToolWindowImpl(MwLL handle) { - handle->wayland.type_to_be = MWLL_WAYLAND_POPUP; -} - -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - *point = handle->wayland.cur_mouse_pos; -} - -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - rect->x = 0; - rect->y = 0; - rect->width = handle->wayland.mw; - rect->height = handle->wayland.mh; -} - -static void MwLLBeginStateChangeImpl(MwLL handle) { - (void)handle; - /* no-op */ -} - -static void MwLLEndStateChangeImpl(MwLL handle) { - if(handle->wayland.detatching) { - MwLL topmost_parent = handle->wayland.parent; - - while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - topmost_parent = topmost_parent->wayland.parent; - } - switch(handle->wayland.type) { - case MWLL_WAYLAND_UNKNOWN: - break; - case MWLL_WAYLAND_TOPLEVEL: - destroy_toplevel(handle); - break; - case MWLL_WAYLAND_SUBLEVEL: - destroy_sublevel(handle); - break; - case MWLL_WAYLAND_POPUP: - destroy_popup(handle); - break; - } - - wl_flush(handle); - - widget_setup(handle, handle->wayland.parent, handle->wayland.detach_point.x, handle->wayland.detach_point.y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); - - if(!handle->wayland.parent) - handle->wayland.dark_theme_detection = MwTRUE; - - if(handle->common.user) { - MwWidget w = handle->common.user; - int i; - for(i = 0; i < arrlen(w->children); i++) { - if(w->children[i]->lowlevel->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - MwLL child = w->children[i]->lowlevel; - child->wayland.sublevel->xdg_surface = handle->wayland.popup->xdg_surface; - wl_subsurface_destroy(child->wayland.sublevel->subsurface); - wl_flush(handle); - - child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); - wl_subsurface_set_desync(child->wayland.sublevel->subsurface); - wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); - - wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); - MwLLEndStateChangeImpl(w->children[i]->lowlevel); - - currentlyHeldWidget = NULL; - } - } - } - - MwLLForceRender(handle); - if(handle->wayland.parent != NULL) { - MwLLForceRender(handle->wayland.parent); - } - - handle->wayland.events_pending = 1; - - handle->wayland.detatching = MwFALSE; - } -} - -static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { - (void)handle; - (void)toggle; -} - -static int MwLLWaylandCallInitImpl(void) { -#ifdef __linux__ - MwBool loadWayland = MwFALSE; - if(getenv("MILSKO_BACKEND")) { - loadWayland |= - (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); - } else if(getenv("WAYLAND_DISPLAY")) { - loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); - } - - if(loadWayland) { - if(wayland_load_funcs()) { - return 1; - } - wl_log_set_handler_client(wl_logger); - - return 0; - } -#endif - return 1; -} - -#include "call.c" -CALL(Wayland); diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c new file mode 100644 index 00000000..df1de797 --- /dev/null +++ b/src/backend/wayland/buffer.c @@ -0,0 +1,114 @@ +#include +#include + +void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { + MwLLWaylandBufferSetup(&wayland->framebuffer, wayland->ww, wayland->wh); + + MwLLCairoFrontSetup(&wayland->cairo, wayland->framebuffer.buf_back, wayland->ww, wayland->wh); + + memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); + if(wayland->configured) + wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); + wl_surface_commit(wayland->framebuffer.surface); + + MwLLWaylandHangUntilConfigured((MwLL)wayland); + MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->framebuffer); +}; +void MwLLWaylandFramebufferDestroy(struct _MwLLWayland* wayland) { + wl_surface_attach(wayland->framebuffer.surface, NULL, 0, 0); + MwLLWaylandBufferDestroy(&wayland->framebuffer); + MwLLCairoFrontDestroy(&wayland->cairo); +}; + +void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland) { + if(wayland->type != MwLL_WAYLAND_TOPLEVEL) { + return; + } + MwU32 w = wayland->ww; + MwU32 h = wayland->wh; + if(!wayland->has_decorations && wayland->do_csd) { + w += (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + h += (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + } + MwLLWaylandBufferSetup(&wayland->backbuffer, w, h); + + MwLLCairoBackSetup(&wayland->cairo, wayland->backbuffer.buf_back, w, h); + + memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); + if(wayland->configured) + wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); + wl_surface_commit(wayland->backbuffer.surface); + MwLLWaylandHangUntilConfigured((MwLL)wayland); + MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->backbuffer); +}; +void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* wayland) { + // wl_surface_attach(wayland->backbuffer.surface, NULL, 0, 0); + MwLLWaylandBufferDestroy(&wayland->backbuffer); + MwLLCairoBackDestroy(&wayland->cairo); +}; + +void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { + int stride = width * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + char temp_name_back[] = "/tmp/milsko-wl-shm-back-XXXXXX"; + + buffer->buf_size = width * height * 4; + + buffer->fd = mkstemp(temp_name); + buffer->fd_back = mkstemp(temp_name_back); + + unlink(temp_name); + unlink(temp_name_back); + + if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(buffer->fd); + return; + } + if(posix_fallocate(buffer->fd_back, 0, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } + if(ftruncate(buffer->fd, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(buffer->fd); + return; + } + if(ftruncate(buffer->fd_back, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } + + buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); + buffer->buf_back = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd_back, 0); + + fsync(buffer->fd); + fsync(buffer->fd_back); + + if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + if(!(buffer->shm_pool_back = wl_shm_create_pool(buffer->shm, buffer->fd_back, buffer->buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->shm_buffer_back = wl_shm_pool_create_buffer(buffer->shm_pool_back, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; +} + +void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer) { + if(!buffer->setup) { + return; + } + if(buffer->buf) munmap(buffer->buf, buffer->buf_size); + if(buffer->buf_back) munmap(buffer->buf_back, buffer->buf_size); + if(buffer->shm_buffer) wl_buffer_destroy(buffer->shm_buffer); + if(buffer->shm_buffer_back) wl_buffer_destroy(buffer->shm_buffer_back); + if(buffer->shm_pool) wl_shm_pool_destroy(buffer->shm_pool); + if(buffer->shm_pool_back) wl_shm_pool_destroy(buffer->shm_pool_back); + close(buffer->fd); + close(buffer->fd_back); + buffer->setup = MwFALSE; +} diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c new file mode 100644 index 00000000..84ed4923 --- /dev/null +++ b/src/backend/wayland/interfaces.c @@ -0,0 +1,1225 @@ +#include +#include +#include "../../../external/stb_ds.h" + +/* TODO: find out what FreeBSD and such wants us to include */ +#ifdef __FreeBSD__ +/* XXX: Untested (nishi) */ +#include +#else +#include +#include +#endif + +#include + +static void setup_clipboard(MwLL self, struct wl_seat* wl_seat); +static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); + +static void destroy_clipboard(MwLL self, struct wl_seat* wl_seat); +static void destroy_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); + +/* Recursively dispatch a move event to a widget and its children */ +static void recursive_dispatch_move(MwLL handle, MwMouse* p) { + MwWidget h = (MwWidget)handle->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, move, p); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_move(h->children[i]->lowlevel, p); + } + } + } +}; + +/* `wl_registry.global` callback */ +static void new_protocol(void* data, struct wl_registry* registry, + MwU32 name, const char* interface, + MwU32 version) { + MwLL self = data; + (void)version; + (void)registry; + + WAYLAND_EVENT_OP_START(self); + + wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); + if(cb != NULL) { + shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data, version)); + /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ + } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { + self->common.supports_transparency = MwTRUE; + } else { + // printf("unknown interface %s\n", interface); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_registry.global_remove` callback */ +static void protocol_removed(void* data, + struct wl_registry* registry, + MwU32 name) { + (void)data; + (void)registry; + (void)name; + printf("%d destroyed\n", name); +}; + +static void wl_offer(void* data, + struct wl_data_offer* wl_data_offer, + const char* mime_type) { + wl_clipboard_device_context_t* self = data; + wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); +}; + +struct wl_data_offer_listener offer_listener = { + .offer = wl_offer, +}; + +static void wl_data_device_data_offer(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* offer) { + wl_clipboard_device_context_t* self = data; + (void)wl_data_device; + + wl_data_offer_add_listener(offer, &offer_listener, data); + + self->offer.wl = offer; +}; + +static void wl_data_device_enter(void* data, + struct wl_data_device* wl_data_device, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer* id) { + MwLL self = data; + (void)wl_data_device; + (void)surface; + (void)x; + (void)y; + (void)id; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.clipboard_serial = serial; + + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_device_leave(void* data, + struct wl_data_device* wl_data_device) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + wl_data_device_destroy(wl_data_device); + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_device_motion(void* data, + struct wl_data_device* wl_data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) { + (void)data; + (void)wl_data_device; + (void)time; + (void)x; + (void)y; +}; +static void wl_data_device_drop(void* data, + struct wl_data_device* wl_data_device) { + (void)data; + (void)wl_data_device; +}; + +static void wl_data_device_selection(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* id) { + (void)data; + (void)wl_data_device; + (void)id; +}; + +struct wl_data_device_listener wl_data_device_listener = { + .data_offer = wl_data_device_data_offer, + .enter = wl_data_device_enter, + .leave = wl_data_device_leave, + .motion = wl_data_device_motion, + .drop = wl_data_device_drop, + .selection = wl_data_device_selection, +}; + +static void zwp_primary_selection_device_v1_data_offer(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* offer) { + wl_clipboard_device_context_t* self = data; + (void)zwp_primary_selection_device_v1; + + self->offer.zwp = offer; +}; + +static void zwp_primary_selection_device_v1_selection(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* id) { + (void)data; + (void)zwp_primary_selection_device_v1; + (void)id; +}; + +struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = { + .data_offer = zwp_primary_selection_device_v1_data_offer, + .selection = zwp_primary_selection_device_v1_selection, +}; + +void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_type) { + int fds[2]; + fd_set set; + char* buf = NULL; + struct timeval timeout; + int rc = 0; + + if(pipe(fds) != 0) { + return; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + timeout.tv_sec = 0; + timeout.tv_usec = 100; + + if(clipboard_type == MwCLIPBOARD_PRIMARY && ctx->offer.zwp) { + zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); + } else if(ctx->offer.wl) { + wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); + } + close(fds[1]); + + MwLLWaylandFlush(ctx->ll); + wl_display_roundtrip(ctx->ll->wayland.display); + + while(MwTRUE) { + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + char b; + ssize_t n = read(fds[0], &b, sizeof(b)); + if(n <= 0) { + break; + } + arrpush(buf, b); + } + } + arrpush(buf, 0); + close(fds[0]); + + MwLLDispatch(ctx->ll, clipboard, buf); + arrfree(buf); + + ctx->ll->wayland.events_pending = 1; +} + +static void wl_data_source_listener_target(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type) { + (void)data; + (void)wl_data_source; + (void)mime_type; +}; +static void wl_data_source_listener_send(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + (void)wl_data_source; + (void)mime_type; + + WAYLAND_EVENT_OP_START(self); + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + } + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source); + +struct wl_data_source_listener wl_data_source_listener = { + .target = wl_data_source_listener_target, + .send = wl_data_source_listener_send, + .cancelled = wl_data_source_listener_cancelled, +}; + +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + + if(wl_data_source) + wl_data_source_destroy(wl_data_source); + + self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl); + + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); + + WAYLAND_EVENT_OP_END(self); +}; + +static void zwp_primary_selection_source_v1_send(void* data, + struct zwp_primary_selection_source_v1* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + (void)wl_data_source; + (void)mime_type; + + WAYLAND_EVENT_OP_START(self); + + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + } + + WAYLAND_EVENT_OP_END(self); +}; +static void zwp_primary_selection_source_v1_cancelled(void* data, + struct zwp_primary_selection_source_v1* wl_data_source) { + MwLL self = data; + (void)wl_data_source; + + WAYLAND_EVENT_OP_START(self); + + zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp); + + self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp); + + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING"); + + WAYLAND_EVENT_OP_END(self); +}; + +struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = { + .send = zwp_primary_selection_source_v1_send, + .cancelled = zwp_primary_selection_source_v1_cancelled, +}; + +/* wl_data_device_manager setup function */ +static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); + + wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); + + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain"); + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); + wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); + wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); + + if(wayland->pointer_seat) { + setup_clipboard((MwLL)wayland, wayland->pointer_seat); + } + + return NULL; +} + +static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; + if(wayland->clipboard_manager.wl != NULL) { + wl_data_device_manager_destroy(wayland->clipboard_manager.wl); + wayland->clipboard_manager.wl = NULL; + } + if(wayland->clipboard_source.wl) { + // wl_data_source_destroy(wayland->clipboard_source.wl); + wayland->clipboard_source.wl = NULL; + } +} + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); + + wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); + + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "UTF8_STRING"); + + zwp_primary_selection_source_v1_add_listener(wayland->clipboard_source.zwp, &zwp_primary_selection_source_v1_listener, wayland); + + wayland->supports_zwp = MwTRUE; + + if(wayland->pointer_seat) { + setup_zwp_clipboard((MwLL)wayland, wayland->pointer_seat); + } + + return NULL; +} + +static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_pointer_constraints_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->pointer_constraints = wl_registry_bind(wayland->registry, name, &zwp_pointer_constraints_v1_interface, 1); + return NULL; +} + +static void zwp_pointer_constraints_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +static struct wl_surface* curSurface = NULL; + +/* `wl_pointer.enter` callback */ +static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, + struct wl_surface* surface, wl_fixed_t surface_x, + wl_fixed_t surface_y) { + MwLL self = data; + MwLL topmost_parent = self; + + (void)surface_x; + (void)surface_y; + (void)wl_pointer; + + WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + if(self->wayland.framebuffer.surface == surface) { + curSurface = surface; + self->wayland.pointer_serial = serial; + + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, topmost_parent->wayland.cursor.surface, 0, 0); + } + + if(self->wayland.backbuffer.surface == surface) { + curSurface = surface; + } + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.leave` callback */ +static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, + struct wl_surface* surface) { + MwLL self = data; + (void)wl_pointer; + (void)serial; + (void)surface; + WAYLAND_EVENT_OP_START(self); + curSurface = NULL; + WAYLAND_EVENT_OP_END(self); +}; + +static void xdg_borderless_step_mdown(MwLL self, MwMouse p, MwU32 serial) { + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { + if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM); + } + } else if(p.point.y <= 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP); + } + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT); + } else if(p.point.x <= 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT); + } else if(p.point.y <= CSD_BORDER_FRAME_TOP) { + if(p.point.x >= CSD_BORDER_FRAME_LEFT && p.point.x <= CSD_BORDER_FRAME_LEFT + 18) { + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 21) { + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 38) { + } else { + xdg_toplevel_move(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial); + } + } + }; +} +static void xdg_borderless_step_mup(MwLL self, MwMouse p, MwU32 serial) { + (void)serial; + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { + if(p.point.y <= CSD_BORDER_FRAME_TOP) { + if(p.point.x >= CSD_BORDER_FRAME_LEFT && p.point.x <= CSD_BORDER_FRAME_LEFT + 18) { + MwLLDispatch(self, close, NULL); + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 21) { + self->wayland.toplevel->maxim_state = !self->wayland.toplevel->maxim_state; + if(self->wayland.toplevel->maxim_state == 0) { + xdg_toplevel_unset_maximized(self->wayland.toplevel->xdg_top_level); + } else { + xdg_toplevel_set_maximized(self->wayland.toplevel->xdg_top_level); + } + self->wayland.setting_wh = 1; + MwLLWaylandRegionSetup(self); + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 38) { + xdg_toplevel_set_minimized(self->wayland.toplevel->xdg_top_level); + } + } + }; +} + +static void relative_pointer_motion(void* data, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) { + MwLL self = data; + MwMouse p; + + (void)pointer; + (void)timeHi; + (void)timeLo; + (void)dx; + (void)dy; + + WAYLAND_EVENT_OP_START(self); + + p.point.x = wl_fixed_to_int(dxUnaccel); + p.point.y = wl_fixed_to_int(dyUnaccel); + + recursive_dispatch_move(self, &p); + if(self->wayland.locked_pointer) zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + + WAYLAND_EVENT_OP_END(self); +} + +struct zwp_relative_pointer_v1_listener MwLLWaylandRelativePointerListener = + { + relative_pointer_motion}; + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_relative_pointer_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->relative_pointer_manager = wl_registry_bind(wayland->registry, name, &zwp_relative_pointer_manager_v1_interface, 1); + return NULL; +} + +static void zwp_relative_pointer_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* `wl_pointer.motion` callback */ +static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, + wl_fixed_t surface_x, wl_fixed_t surface_y) { + MwLL self = data; + MwLL topmost_parent = self; + MwMouse p; + MwBool inArea = MwFALSE; + MwLL currentlyHeldWidget = NULL; + + (void)time; + (void)wl_pointer; + + WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + currentlyHeldWidget = topmost_parent->wayland.currentlyHeldWidget; + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + + self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + if(currentlyHeldWidget != NULL) { + currentlyHeldWidget->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + currentlyHeldWidget->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + } + + if(inArea) { + p.point = self->wayland.cur_mouse_pos; + MwLLDispatch(self, move, &p); + + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); + } else if(currentlyHeldWidget == self) { + p.point = currentlyHeldWidget->wayland.cur_mouse_pos; + MwLLDispatch(currentlyHeldWidget, move, &p); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.button` callback */ +static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { + MwLL self = data; + MwMouse p; + MwBool inArea = MwFALSE; + MwLL topmost_parent = self; + + (void)wl_pointer; + (void)serial; + (void)time; + + WAYLAND_EVENT_OP_START(self); + + p.point = self->wayland.cur_mouse_pos; + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + if(inArea) { + switch(button) { + case BTN_LEFT: + p.button = MwMOUSE_LEFT; + break; + case BTN_MIDDLE: + p.button = MwMOUSE_MIDDLE; + break; + case BTN_RIGHT: + p.button = MwMOUSE_RIGHT; + break; + } + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; + + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + if(button == BTN_LEFT) { + topmost_parent->wayland.focusedWidget = self; + } + MwLLDispatch(self, down, &p); + topmost_parent->wayland.currentlyHeldWidget = self; + + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + if(topmost_parent->wayland.currentlyHeldWidget != NULL) { + MwLLDispatch(topmost_parent->wayland.currentlyHeldWidget, up, &p); + topmost_parent->wayland.currentlyHeldWidget = NULL; + } else { + MwLLDispatch(self, up, &p); + } + break; + } + } + + if(!self->wayland.has_decorations && self->wayland.do_csd) { + if(state != WL_POINTER_BUTTON_STATE_RELEASED) + xdg_borderless_step_mdown(self, p, serial); + else + xdg_borderless_step_mup(self, p, serial); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.axis` callback */ +static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, + MwU32 axis, wl_fixed_t value) { + (void)data; + (void)wl_pointer; + (void)time; + (void)axis; + (void)value; +}; + +struct wl_pointer_listener pointer_listener = { + .enter = pointer_enter, + .leave = pointer_leave, + .motion = pointer_motion, + .button = pointer_button, + .axis = pointer_axis, +}; + +/* `wl_keyboard.keymap` callback */ +static void keyboard_keymap(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 format, + int32_t fd, + MwU32 size) { + MwLL self = data; + (void)wl_keyboard; + + if(!self->wayland.parent) { + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + + char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + assert(map_shm != MAP_FAILED); + + struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string( + self->wayland.xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm, size); + close(fd); + + struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); + + self->wayland.xkb_keymap = xkb_keymap; + self->wayland.xkb_state = xkb_state; + } else { + self->wayland.xkb_keymap = self->wayland.parent->wayland.xkb_keymap; + self->wayland.xkb_state = self->wayland.parent->wayland.xkb_state; + } +}; + +/* `wl_keyboard.enter` callback */ +static void keyboard_enter(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + struct wl_surface* surface, + struct wl_array* keys) { + MwLL self = data; + (void)wl_keyboard; + (void)surface; + (void)keys; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.keyboard_serial = serial; + + MwLLDispatch(self, focus_in, NULL); + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.leave` callback */ +static void keyboard_leave(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + struct wl_surface* surface) { + MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)surface; + + WAYLAND_EVENT_OP_START(self); + + MwLLDispatch(self, focus_out, NULL); + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.key` callback */ +static void keyboard_key(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + MwU32 _time, + MwU32 key, + MwU32 state) { + MwLL self = data; + MwBool inArea = 0; + MwLL topmost_parent = self; + + (void)wl_keyboard; + (void)serial; + (void)_time; + + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + WAYLAND_EVENT_OP_START(self); + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + + inArea |= (self == topmost_parent->wayland.focusedWidget); + + if(inArea) { + xkb_layout_index_t layout; + MwU32 levels; + xkb_level_index_t level = 0; + const xkb_keysym_t* syms_out; + MwU32 keycode = key + 8; + MwU64 syms_num; + int i; + + if(!self->wayland.xkb_keymap) { + WAYLAND_EVENT_OP_END(self); + return; + } + + layout = xkb_state_key_get_layout(self->wayland.xkb_state, keycode); + levels = + xkb_keymap_num_levels_for_key(self->wayland.xkb_keymap, keycode, layout); + + if((((self->wayland.mod_state & 1) == 1) || ((self->wayland.mod_state & 2) == 2)) && levels >= 2) { + level = 1; + } else if(levels >= 1) { + level = 0; + } + syms_num = xkb_keymap_key_get_syms_by_level(self->wayland.xkb_keymap, keycode, layout, level, &syms_out); + if(syms_out == NULL) { + WAYLAND_EVENT_OP_END(self); + return; + } + + for(i = 0; i < syms_num; i++) { + int sym = syms_out[i]; + int key = -1; + + switch(sym) { + case XKB_KEY_BackSpace: + key = MwKEY_BACKSPACE; + break; + case XKB_KEY_Left: + key = MwKEY_LEFT; + break; + case XKB_KEY_Right: + key = MwKEY_RIGHT; + break; + case XKB_KEY_Up: + key = MwKEY_UP; + break; + case XKB_KEY_Down: + key = MwKEY_DOWN; + break; + case XKB_KEY_Return: + key = MwKEY_ENTER; + break; + case XKB_KEY_Escape: + key = MwKEY_ESCAPE; + break; + case XKB_KEY_Shift_L: + key = MwKEY_LEFTSHIFT; + break; + case XKB_KEY_Shift_R: + key = MwKEY_RIGHTSHIFT; + break; + case XKB_KEY_Alt_L: + case XKB_KEY_Alt_R: + key = MwKEY_ALT; + break; + case XKB_KEY_Control_L: + case XKB_KEY_Control_R: + key = MwKEY_CONTROL; + break; + default: + if(MwStringIsKeyUTF8(sym)) { + key = sym; + } + } + + if((self->wayland.mod_state & 4) == 4) { + key |= MwKEY_CONTROL_FLAG; + } + if((self->wayland.mod_state & 8) == 8) { + key |= MwKEY_ALT_FLAG; + } + + if(key != -1) { + if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { + MwLL topmost_parent = self; + while(topmost_parent->wayland.parent) { + MwLLDispatch(topmost_parent, key, &key); + topmost_parent = topmost_parent->wayland.parent; + } + self->wayland.holding_key = MwTRUE; + self->wayland.last_pressed_key = key; + } else { + MwLLDispatch(self, key_released, &key); + self->wayland.holding_key = MwFALSE; + } + self->wayland.start_time = MwTimeGetTick(); + self->wayland.next_elapsed = self->wayland.keyboard_delay; + } + } + } + + if(!MwWaylandVulkan) { + MwLLDispatch(self, draw, NULL); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.modifiers` callback */ +static void keyboard_modifiers(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + MwU32 mods_depressed, + MwU32 mods_latched, + MwU32 mods_locked, + MwU32 group) { + MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)group; + (void)mods_latched; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.mod_state = 0; + self->wayland.mod_state |= mods_depressed; + self->wayland.mod_state |= mods_locked; + + WAYLAND_EVENT_OP_END(self); +}; + +static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat) { + wl_clipboard_device_context_t* device_ctx_zwp = NULL; + device_ctx_zwp = malloc(sizeof(wl_clipboard_device_context_t)); + memset(device_ctx_zwp, 0, sizeof(wl_clipboard_device_context_t)); + device_ctx_zwp->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + device_ctx_zwp->ll = self; + zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); + arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); +} +static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { + wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); + memset(device_ctx_wl, 0, sizeof(wl_clipboard_device_context_t)); + + device_ctx_wl->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_wl->ll = self; + + wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); + arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); +}; + +static void keyboard_repeat_info(void* data, + struct wl_keyboard* wl_keyboard, + int32_t rate, + int32_t delay) { + MwLL self = data; + + (void)wl_keyboard; + + self->wayland.keyboard_rate = rate; + self->wayland.keyboard_delay = delay; +}; + +struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info, +}; + +/* `wl_seat.name` callback */ +static void +wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { + (void)data; + (void)wl_seat; + (void)name; +}; + +/* `wl_seat.capabilities` callback */ +static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, + MwU32 capabilities) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + + if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); + } + if(capabilities & WL_SEAT_CAPABILITY_POINTER) { + self->wayland.pointer_seat = wl_seat; + self->wayland.pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); + } + WAYLAND_EVENT_OP_END(self); + + if(self->wayland.clipboard_manager.wl) + setup_clipboard(self, self->wayland.pointer_seat); + if(self->wayland.clipboard_manager.zwp) + setup_zwp_clipboard(self, self->wayland.pointer_seat); +}; + +static void output_geometry(void* data, + struct wl_output* wl_output, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) { + (void)data; + (void)wl_output; + (void)x; + (void)y; + (void)physical_width; + (void)physical_height; + (void)subpixel; + (void)make; + (void)model; + (void)transform; +}; +static void output_mode(void* data, + struct wl_output* wl_output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) { + MwLL self = data; + (void)wl_output; + (void)flags; + (void)refresh; + self->wayland.mw = width; + self->wayland.mh = height; +}; + +struct wl_output_listener output_listener = { + .geometry = output_geometry, + .mode = output_mode, +}; + +/* `xdg_wm_base.ping` callback */ +void xdg_wm_base_ping(void* data, + struct xdg_wm_base* xdg_wm_base, + MwU32 serial) { + (void)data; + xdg_wm_base_pong(xdg_wm_base, serial); +}; + +/* wl_seat setup function */ +static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + MwU32 ver = (version >= 4) ? 4 : 1; + proto->listener = malloc(sizeof(struct wl_seat_listener)); + + ((struct wl_seat_listener*)proto->listener)->name = wl_seat_name; + ((struct wl_seat_listener*)proto->listener)->capabilities = wl_seat_capabilities; + + wl_seat_add_listener(wl_registry_bind(ll->wayland.registry, name, &wl_seat_interface, ver), proto->listener, ll); + + return proto; +} + +static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +/* wl_output setup function */ +static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll, MwU32 version) { + (void)version; + ll->wayland.output = wl_registry_bind(ll->wayland.registry, name, &wl_output_interface, 1); + wl_output_add_listener(ll->wayland.output, &output_listener, ll); + + return NULL; +} + +static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_compositor setup function */ +static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); + + return NULL; +} + +static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_subcompositor setup function */ +static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } else { + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } + + return NULL; +} + +static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + wl_subcompositor_destroy(wayland->toplevel->scompositor); + } else { + wl_subcompositor_destroy(wayland->sublevel->subcompositor); + } +} + +/* xdg_wm_base setup function */ +static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + (void)version; + proto->listener = malloc(sizeof(struct xdg_wm_base_listener)); + + ((struct xdg_wm_base_listener*)proto->listener)->ping = xdg_wm_base_ping; + + proto->context = wl_registry_bind(wayland->registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(proto->context, proto->listener, wayland); + + return proto; +} + +static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +/* xdg_wm_base setup function */ +static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + (void)version; + proto->context = wl_registry_bind(wayland->registry, name, &wp_viewporter_interface, 1); + + return proto; +} + +static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* zxdg_decoration_manager_v1 setup function */ +static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + zxdg_decoration_manager_v1_context_t* ctx = malloc(sizeof(zxdg_decoration_manager_v1_context_t)); + (void)version; + proto->listener = NULL; + + ctx->manager = wl_registry_bind(wayland->registry, name, &zxdg_decoration_manager_v1_interface, 1); + ; + + proto->context = ctx; + + return proto; +} + +static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_shm setup function */ +static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + + return NULL; +} + +static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + + (void)version; + + proto->context = wl_registry_bind(wayland->registry, name, &xdg_toplevel_icon_manager_v1_interface, 1); + proto->listener = NULL; + + return proto; +} + +static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +static wayland_protocol_t* zwlr_layer_shell_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + + proto->context = wl_registry_bind(wayland->registry, name, &zwlr_layer_shell_v1_interface, version); + proto->listener = NULL; + + return proto; +} + +static void zwlr_layer_shell_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + + free(data); +} + +/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ +void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { +/* Convience macro for adding the interface functions to the setup map */ +#define WL_INTERFACE(interface) \ + do { \ + wayland_protocol_callback_table_t* cb = malloc(sizeof(wayland_protocol_callback_table_t)); \ + cb->setup = (wl_setup_func*)interface##_setup; \ + cb->destroy = (wl_destroy_func*)interface##_interface_destroy; \ + shput(wayland->wl_protocol_setup_map, interface##_interface.name, cb); \ + } while(0); + + wayland->registry_listener.global = new_protocol; + wayland->registry_listener.global_remove = protocol_removed; + + if(wayland->wl_protocol_map) { + shfree(wayland->wl_protocol_map); + } + if(wayland->wl_protocol_setup_map) { + shfree(wayland->wl_protocol_setup_map); + } + + wayland->wl_protocol_setup_map = NULL; + wayland->wl_protocol_map = NULL; + + sh_new_arena(wayland->wl_protocol_map); + sh_new_arena(wayland->wl_protocol_setup_map); + + WL_INTERFACE(wl_shm); + WL_INTERFACE(wl_compositor); + WL_INTERFACE(wl_seat); + WL_INTERFACE(wl_output); + WL_INTERFACE(wl_data_device_manager); + WL_INTERFACE(zwp_primary_selection_device_manager_v1); + WL_INTERFACE(zwp_pointer_constraints_v1); + WL_INTERFACE(zwp_relative_pointer_manager_v1); + WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(zwlr_layer_shell_v1); /* Only used for layer surface, but we use it always if it's turned into a tool window */ + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + WL_INTERFACE(wp_viewporter); + WL_INTERFACE(zxdg_decoration_manager_v1); + WL_INTERFACE(xdg_toplevel_icon_manager_v1); + WL_INTERFACE(wl_subcompositor); + } else if(wayland->type == MwLL_WAYLAND_POPUP) { + } else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) { + WL_INTERFACE(wp_viewporter); + WL_INTERFACE(wl_subcompositor); + } else { + WL_INTERFACE(wl_subcompositor); + } +#undef WL_INTERFACE +} diff --git a/src/backend/wayland/region.c b/src/backend/wayland/region.c new file mode 100644 index 00000000..4b6a5ae2 --- /dev/null +++ b/src/backend/wayland/region.c @@ -0,0 +1,45 @@ +#include + +void MwLLWaylandRegionInvalidate(MwLL handle) { + if(!handle->wayland.configured) { + return; + } + wl_region_subtract(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); +} +void MwLLWaylandRegionSetup(MwLL handle) { + int width = (handle->wayland.clipping_rect.width == 0) ? handle->wayland.ww : handle->wayland.clipping_rect.width; + int height = (handle->wayland.clipping_rect.height == 0) ? handle->wayland.wh : handle->wayland.clipping_rect.height; + + if(!handle->wayland.has_decorations && handle->wayland.do_csd && handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + width += CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + height += CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + } + if(!handle->wayland.configured) { + return; + } + + if(!handle->wayland.parent) + wl_region_add(handle->wayland.o_region, 0, 0, width, height); + + if(handle->wayland.type == MwLL_WAYLAND_POPUP) { + wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); + } else { + wl_region_subtract(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); + wl_region_add(handle->wayland.region, handle->wayland.clipping_rect.x, handle->wayland.clipping_rect.y, handle->wayland.clipping_rect.width, handle->wayland.clipping_rect.height); + + if(!handle->wayland.parent) + wl_region_add(handle->wayland.region, 0, 0, width, height); + else { + if(!handle->wayland.parent->wayland.parent) { + wl_region_add(handle->wayland.region, 0, 0, width, height); + } + } + } + + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region); + wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); + } + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); + wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); +} diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c new file mode 100644 index 00000000..839e9ac6 --- /dev/null +++ b/src/backend/wayland/wayland.c @@ -0,0 +1,1932 @@ +#include + +#include +#include + +#include "../../../external/stb_ds.h" + +wayland_call_table_t wl_call_tbl; +#ifdef MW_VULKAN +MwBool MwWaylandVulkan = MwFALSE; +#endif + +MwBool MwWaylandCairoOnly = MwFALSE; + +static pthread_mutex_t destroyedWidgetsTableMutex; +/* + * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. + * + * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. + */ +static MwLL* destroyedWidgetsTable; + +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwTRUE; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwFALSE; +} +void MwLLWaylandWidgetUndestroy(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + arrdel(destroyedWidgetsTable, i); + break; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return; +} + +static int event_loop(MwLL handle); + +/* Recursively dispatch a resize event to a widget and its children */ +static void recursive_dispatch_resize(MwLL handle) { + MwWidget h = (MwWidget)handle->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwDispatch(h->children[i], resize); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_resize(h->children[i]->lowlevel); + } + } + } +}; + +static void recursive_render(MwLL handle) { + int i; + WIDGET_CHECK(handle); + + for(i = 0; i < arrlen(((MwWidget)handle->common.user)->children); i++) recursive_render(((MwWidget)handle->common.user)->children[i]->lowlevel); + + MwLLForceRender(handle); +} + +/* Flush Wayland events */ +void MwLLWaylandFlush(MwLL handle) { + struct pollfd pfd; + int rc; + + pfd.fd = wl_display_get_fd(handle->wayland.display); + pfd.events = POLLIN; + while(MwTRUE) { + rc = wl_display_flush(handle->wayland.display); + if(errno != EAGAIN || rc != -1) { + break; + } + + if(poll(&pfd, 1, -1) == -1) { + break; + } + } +} + +/* Get the registered interface from r, or NULL if it doesn't currently have it. */ +#define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) + +/* Standard Wayland event loop. */ +static int event_loop(MwLL handle) { + struct pollfd fd; + struct timespec timeout; + struct _MwLLWayland* wayland = &handle->wayland; + + timeout.tv_nsec = 1; + timeout.tv_sec = 0; + + if(wayland->display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(wayland->display); + fd.events = POLLIN; + + /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ + while(wl_display_flush(wayland->display) == -1) { + if(errno != EAGAIN) { + return MwFALSE; + } + + while(poll(&fd, 1, -1) == -1) { + if(errno != EINTR && errno != EAGAIN) { + wl_display_cancel_read(wayland->display); + + MwLLDispatch(handle, close, NULL); + return 0; + } + } + } + + wl_display_prepare_read(handle->wayland.display); + /* Condition where no events are being sent. */ + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(wayland->display); + + if(wayland->configured) { + MwLLWaylandBufferUpdate(handle, &wayland->framebuffer); + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) + MwLLWaylandBufferUpdate(handle, &wayland->backbuffer); + } + return 0; + } + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) < 0) { + wl_display_cancel_read(wayland->display); + } + return 1; +} + +/* make the fuck sure that we're configurd */ +void MwLLWaylandHangUntilConfigured(MwLL handle) { + while(!handle->wayland.configured) { + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(handle->wayland.display)); + raise(SIGTRAP); + return; + } + event_loop(handle); + } +} + +/* `xdg_toplevel.configure` callback */ +static void xdg_toplevel_configure(void* data, + struct xdg_toplevel* xdg_toplevel, + MwI32 width, MwI32 height, + struct wl_array* states) { + MwLL self = data; + (void)states; + (void)xdg_toplevel; + + /* Yes, somehow this can get called before */ + if(!self->wayland.configured) { + return; + } + + if(width == 0 || height == 0) { + width = self->wayland.ww; + height = self->wayland.wh; + /* if it's still 0 then bail */ + if(width == 0 || height == 0) { + return; + } + } + + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(width < 50) width = 50; + if(height < 50) height = 50; + } + + MwLLWaylandRegionInvalidate(self); + self->wayland.ww = width; + self->wayland.wh = height; + // if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + // if(!self->wayland.has_decorations && self->wayland.toplevel->maxim_state) { + // self->wayland.ww -= CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + // self->wayland.wh -= CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + // } + // } + + if(self->wayland.resizing == 0) { + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); + + MwLLWaylandBackbufferDestroy(&self->wayland); + MwLLWaylandBackbufferSetup(&self->wayland); + MwLLWaylandFramebufferDestroy(&self->wayland); + MwLLWaylandFramebufferSetup(&self->wayland); + + MwLLWaylandRegionSetup(self); + MwLLDispatch(self, resize, NULL); + + recursive_dispatch_resize(self); + + if(self->wayland.pointer_constrained) { + zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + wl_surface_commit(self->wayland.framebuffer.surface); + } + self->wayland.resizing = 1; + } +}; + +/* `xdg_surface.close` callback */ +static void xdg_toplevel_close( + void* data, struct xdg_toplevel* xdg_toplevel) { + MwLL self = data; + (void)xdg_toplevel; + WAYLAND_EVENT_OP_START(self); + MwLLDispatch(self, close, NULL); + WAYLAND_EVENT_OP_END(self); +}; + +/* `xdg_surface.configure` callback */ +static void xdg_surface_configure( + void* data, struct xdg_surface* xdg_surface, MwU32 serial) { + MwLL self = data; + + xdg_surface_ack_configure(xdg_surface, serial); + + MwLLDispatch(self, draw, NULL); + + if(self->wayland.configured) { + MwLLWaylandBufferUpdate(self, &self->wayland.framebuffer); + MwLLWaylandBufferUpdate(self, &self->wayland.backbuffer); + } + + self->wayland.configured = MwTRUE; +} + +void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { + if(self->wayland.configured) { + memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); + if(buffer->surface) { + // Yes this is needed every time, it's how we fix weston. + if(self->wayland.configured) + wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); + wl_surface_commit(buffer->surface); + } + } +} + +/* Toplevel setup function */ +static void setup_toplevel(MwLL r, int x, int y) { + r->wayland.type = MwLL_WAYLAND_TOPLEVEL; + r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); + r->wayland.x = x; + r->wayland.y = y; + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + if(!r->wayland.display) { + r->wayland.display = wl_display_connect(NULL); + if(r->wayland.display == NULL) { + printf("wayland: failed to create display\n"); + raise(SIGTRAP); + return; + } + } + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } else { + r->wayland.do_csd = MwTRUE; + } + + r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + wl_subsurface_set_desync(r->wayland.toplevel->ssurface); + + r->wayland.toplevel->xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); + r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); + + /* setup mandatory listeners */ + r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + + r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; + r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; + + xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); + xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, + r); + + xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App"); + xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); + + /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.backbuffer.surface); + wl_surface_commit(r->wayland.framebuffer.surface); + + while(!r->wayland.configured) { + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + } + + /* setup decorations if we can */ + if(r->wayland.has_decorations) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + + dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + dec->manager, r->wayland.toplevel->xdg_top_level); + + zxdg_toplevel_decoration_v1_set_mode( + dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + wl_subsurface_set_position(r->wayland.toplevel->ssurface, r->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, r->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + } + + MwLLWaylandFramebufferSetup(&r->wayland); + MwLLWaylandBackbufferSetup(&r->wayland); +} + +/* Toplevel destroy function */ +static void destroy_toplevel(MwLL r) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + zxdg_toplevel_decoration_v1_destroy(dec->decoration); + zxdg_decoration_manager_v1_destroy(dec->manager); + } + + MwLLWaylandFramebufferDestroy(&r->wayland); + MwLLWaylandBackbufferDestroy(&r->wayland); + + xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + + xdg_surface_destroy(r->wayland.toplevel->xdg_surface); + + wl_compositor_destroy(r->wayland.compositor); + + xkb_keymap_unref(r->wayland.xkb_keymap); + + xkb_state_unref(r->wayland.xkb_state); + + xkb_context_unref(r->wayland.xkb_context); + + wl_pointer_destroy(r->wayland.pointer); + wl_keyboard_destroy(r->wayland.keyboard); + + if(r->common.user) { + MwWidget w = r->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + child->wayland.sublevel->subsurface = NULL; + } + } + } + + wl_surface_destroy(r->wayland.framebuffer.surface); + + free(r->wayland.toplevel); + + r->wayland.configured = MwFALSE; +} + +/* Sublevel setup function */ +static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { + struct wl_compositor* compositor = parent->wayland.compositor; + struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; + + r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); + r->wayland.sublevel->parent = parent; + + r->wayland.type = MwLL_WAYLAND_SUBLEVEL; + + r->wayland.display = parent->wayland.display; + + MwLLWaylandSetupCallbacks(&r->wayland); + + r->wayland.registry = wl_display_get_registry(parent->wayland.display); + r->wayland.display = parent->wayland.display; + + if(parent->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + r->wayland.sublevel->xdg_surface = parent->wayland.toplevel->xdg_surface; + } else { + r->wayland.sublevel->xdg_surface = parent->wayland.sublevel->xdg_surface; + } + + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(r->wayland.display)); + raise(SIGTRAP); + return; + } + + r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); + + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); + + wl_subsurface_set_desync(r->wayland.sublevel->subsurface); + wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); + + if(parent) { + wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); + } + + r->wayland.xkb_keymap = parent->wayland.xkb_keymap; + r->wayland.xkb_state = parent->wayland.xkb_state; + + r->wayland.configured = MwTRUE; + + MwLLWaylandFramebufferSetup(&r->wayland); + MwLLWaylandBackbufferSetup(&r->wayland); +} + +/* Sublevel setup function */ +static void destroy_sublevel(MwLL r) { + MwLLWaylandBackbufferDestroy(&r->wayland); + MwLLWaylandFramebufferDestroy(&r->wayland); + + wl_subsurface_destroy(r->wayland.sublevel->subsurface); + + free(r->wayland.sublevel); + + r->wayland.configured = MwFALSE; +} + +static void popup_configure(void* data, + struct xdg_popup* xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + MwLL self = data; + (void)xdg_popup; + + if(width < 50) width = 50; + if(height < 50) height = 50; + self->wayland.x = x; + self->wayland.y = y; + self->wayland.ww = width; + self->wayland.wh = height; +}; + +static void popup_done(void* data, + struct xdg_popup* xdg_popup) { + (void)data; + (void)xdg_popup; +}; + +static void popup_repositioned(void* data, + struct xdg_popup* xdg_popup, + uint32_t token) { + MwLL self = data; + (void)xdg_popup; + + xdg_surface_ack_configure(self->wayland.popup->xdg_surface, token); +}; + +struct xdg_popup_listener popup_listener = { + .configure = popup_configure, + .popup_done = popup_done, + .repositioned = popup_repositioned, + +}; + +/* Popup setup function */ +static void setup_popup(MwLL r, int x, int y, MwLL parent) { + MwLL topmost_parent = r->wayland.parent; + r->wayland.type = MwLL_WAYLAND_POPUP; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); + + if(parent) { + MwWidget p = parent->common.user; + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + } + + if(!topmost_parent->wayland.has_decorations && topmost_parent->wayland.do_csd) { + if(p->is_menu) { + r->wayland.x += round((float)CSD_BORDER_FRAME_LEFT / 2.); + r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.); + } + } + } + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + r->wayland.display = parent->wayland.display; + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(r->wayland.display)); + raise(SIGTRAP); + return; + } + + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } else { + r->wayland.do_csd = MwTRUE; + } + + r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; + + r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); + + xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_anchor_rect( + r->wayland.popup->xdg_positioner, + topmost_parent->wayland.x, topmost_parent->wayland.y, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_offset( + r->wayland.popup->xdg_positioner, + r->wayland.x, r->wayland.y); + + xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); + xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_GRAVITY_NONE); + + r->wayland.xkb_keymap = topmost_parent->wayland.xkb_keymap; + r->wayland.xkb_state = topmost_parent->wayland.xkb_state; + + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + + r->wayland.popup->xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); + + if(topmost_parent->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + r->wayland.popup->xdg_popup = xdg_surface_get_popup( + r->wayland.popup->xdg_surface, + topmost_parent->wayland.toplevel->xdg_surface, + r->wayland.popup->xdg_positioner); + } else if(topmost_parent->wayland.type == MwLL_WAYLAND_LAYER_SURFACE) { + r->wayland.popup->xdg_popup = xdg_surface_get_popup( + r->wayland.popup->xdg_surface, NULL, + r->wayland.popup->xdg_positioner); + zwlr_layer_surface_v1_get_popup(topmost_parent->wayland.layer_surface->surface, r->wayland.popup->xdg_popup); + } + + xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); + + r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; + xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r); + + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + MwLLWaylandFramebufferSetup(&r->wayland); +} + +/* Popup destroy function */ +static void destroy_popup(MwLL r) { + + MwLLWaylandBackbufferDestroy(&r->wayland); + MwLLWaylandFramebufferDestroy(&r->wayland); + + xdg_surface_destroy(r->wayland.popup->xdg_surface); + + xdg_popup_destroy(r->wayland.popup->xdg_popup); + + xdg_positioner_destroy(r->wayland.popup->xdg_positioner); + + wl_surface_destroy(r->wayland.framebuffer.surface); + + wl_registry_destroy(r->wayland.registry); + + free(r->wayland.popup); + + r->wayland.configured = MwFALSE; +} + +static void layer_shell_configure(void* data, + struct zwlr_layer_surface_v1* surface, + uint32_t serial, + uint32_t width, + uint32_t height) { + MwLL self = data; + zwlr_layer_surface_v1_ack_configure(surface, serial); + + if(width < 50) width = 50; + if(height < 50) height = 50; + + self->wayland.ww = width; + self->wayland.wh = height; + + self->wayland.configured = MwTRUE; + + MwLLWaylandFramebufferSetup(&self->wayland); + MwLLWaylandRegionSetup(self); + MwLLDispatch(self, resize, NULL); + + wl_surface_commit(self->wayland.framebuffer.surface); +}; + +static void layer_shell_done(void* data, + struct zwlr_layer_surface_v1* zwlr_layer_surface_v1) { + (void)data; + (void)zwlr_layer_surface_v1; + + printf("closed\n"); +}; + +static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { + .configure = layer_shell_configure, + .closed = layer_shell_done, +}; + +/* Layer surface setup function */ +static void setup_layer_surface(MwLL r, int x, int y, int width, int height) { + wayland_protocol_t* layer_shell_protocol; + struct zwlr_layer_shell_v1* layer_shell; + r->wayland.type = MwLL_WAYLAND_LAYER_SURFACE; + r->wayland.layer_surface = malloc(sizeof(struct _MwLLWaylandLayerSurface)); + r->wayland.x = x; + r->wayland.y = y; + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + if(!r->wayland.display) { + r->wayland.display = wl_display_connect(NULL); + if(r->wayland.display == NULL) { + printf("wayland: failed to create display\n"); + raise(SIGTRAP); + return; + } + } + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + layer_shell_protocol = WAYLAND_GET_INTERFACE(r->wayland, zwlr_layer_shell_v1); + assert(layer_shell_protocol); + + layer_shell = layer_shell_protocol->context; + + r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + + r->wayland.layer_surface->surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, r->wayland.framebuffer.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "milsko-surfaces"); + + zwlr_layer_surface_v1_set_size(r->wayland.layer_surface->surface, width, height); + zwlr_layer_surface_v1_set_margin(r->wayland.layer_surface->surface, + y, 0, 0, x); + zwlr_layer_surface_v1_set_anchor(r->wayland.layer_surface->surface, ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); + zwlr_layer_surface_v1_set_exclusive_zone(r->wayland.layer_surface->surface, 1); + zwlr_layer_surface_v1_set_keyboard_interactivity( + r->wayland.layer_surface->surface, ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND); + + zwlr_layer_surface_v1_add_listener(r->wayland.layer_surface->surface, &layer_surface_listener, r); + + /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.framebuffer.surface); + + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } +} + +/* Toplevel destroy function */ +static void destroy_layer_surface(MwLL r) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + zxdg_decoration_manager_v1_destroy(dec->manager); + } + + wl_surface_destroy(r->wayland.framebuffer.surface); + + wl_compositor_destroy(r->wayland.compositor); + + xkb_keymap_unref(r->wayland.xkb_keymap); + + xkb_state_unref(r->wayland.xkb_state); + + xkb_context_unref(r->wayland.xkb_context); + + wl_registry_destroy(r->wayland.registry); + + r->wayland.configured = MwFALSE; +} + +static void destroy_widget(MwLL handle) { + int i; + + MwLLShow(handle, MwFALSE); + + switch(handle->wayland.type) { + case MwLL_WAYLAND_TOPLEVEL: + destroy_toplevel(handle); + break; + case MwLL_WAYLAND_SUBLEVEL: + destroy_sublevel(handle); + break; + case MwLL_WAYLAND_POPUP: + destroy_popup(handle); + break; + case MwLL_WAYLAND_LAYER_SURFACE: + destroy_layer_surface(handle); + break; + default: + printf("Handle with unknown type(%d) tried to be destroyed (%p)\n", handle->wayland.type, handle); + break; + } + + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { + void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); + + if(ctx != NULL) { + handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + } + shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); + free(handle->wayland.wl_protocol_setup_map[i].value); + } + + shfree(handle->wayland.wl_protocol_map); + shfree(handle->wayland.wl_protocol_setup_map); + + MwLLWaylandFlush(handle); +} + +static void clip(MwLL handle) { + int i; + int x, y, cx, cy, mx, my; + MwLL toplevel = handle->wayland.parent; + MwLL* ws = NULL; + + arrput(ws, handle); + while(toplevel) { + arrput(ws, toplevel); + if(!toplevel->wayland.parent || toplevel->wayland.is_toplevel) { + break; + } + toplevel = toplevel->wayland.parent; + } + if(toplevel) { + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + /* i seriously have no fucking idea how this works, do not ask me how this really works (nishi) */ + x = 0; + y = 0; + cx = 0; + cy = 0; + mx = toplevel->wayland.ww; + my = toplevel->wayland.wh; + // ws is traversed result + // ws[ws.length - 1] is ignored bc it's toplevel + for(i = arrlen(ws) - 2; i >= 0; i--) { + int j; + int l = 0; + + x += ws[i]->wayland.x; + y += ws[i]->wayland.y; + + for(j = i - 1; j >= 0; j--) { + if(ws[j]->wayland.x > cx) l = 1; + if(ws[j]->wayland.y > cy) l = 1; + if(l) break; + } + + if(!l) { + cx = MAX(cx, ws[i]->wayland.x); + cy = MAX(cy, ws[i]->wayland.y); + } + + mx = MIN(mx, x + ws[i]->wayland.ww); + my = MIN(my, y + ws[i]->wayland.wh); + } + + if(mx < cx) mx = cx; + if(my < cy) my = cy; + + arrfree(ws); + + if(mx < cx) mx = cx; + if(my < cy) my = cy; + + handle->wayland.clipping_rect.x = cx - x; + handle->wayland.clipping_rect.y = cy - y; + handle->wayland.clipping_rect.width = mx - cx; + handle->wayland.clipping_rect.height = my - cy; + MwLLWaylandRegionSetup(handle); + + cairo_reset_clip(handle->wayland.cairo.front_cairo); + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && !handle->wayland.is_toplevel) { + cairo_rectangle(handle->wayland.cairo.front_cairo, cx - x, cy - y, mx - cx, my - cy); + cairo_clip(handle->wayland.cairo.front_cairo); + } + + if(handle->wayland.is_clipping) { + cairo_rectangle(handle->wayland.cairo.front_cairo, handle->wayland.clip.x, handle->wayland.clip.y, handle->wayland.clip.width, handle->wayland.clip.height); + cairo_clip(handle->wayland.cairo.front_cairo); + } + } +} + +static void wl_logger(const char* fmt, va_list args) { + vprintf(fmt, args); + raise(SIGTRAP); +} + +static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int height, enum _MwLLWaylandType ty) { + /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. + */ + r->common.coordinate_type = MwCOORDINATE_LOCAL; + + r->common.type = MwLLBackendWayland; + + if(width < 2) width = 2; + if(height < 2) height = 2; + + if(x == MwDEFAULT) { + x = 0; + } + if(y == MwDEFAULT) { + y = 0; + } + + r->wayland.ww = width; + r->wayland.wh = height; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.parent = parent; + if(MwLLWaylandWidgetIsDestroyed(parent)) { + r->wayland.valid = MwFALSE; + return; + } else { + r->wayland.valid = MwTRUE; + } + + if(ty == MwLL_WAYLAND_UNKNOWN) { + if(parent == NULL) { + setup_toplevel(r, x, y); + } else { + setup_sublevel(parent, r, x, y); + } + } else { + switch(ty) { + case MwLL_WAYLAND_UNKNOWN: + break; + case MwLL_WAYLAND_TOPLEVEL: + setup_toplevel(r, x, y); + break; + case MwLL_WAYLAND_SUBLEVEL: + setup_sublevel(parent, r, x, y); + break; + case MwLL_WAYLAND_POPUP: + if(parent) { + setup_popup(r, x, y, parent); + } else { + /* + * We can't actually have a popup without a parent but this needs to be valid behavior. + * If we're down this code path, though, it means we can't create a layer surface. + * So we just fake it with a borderless window. + */ + setup_toplevel(r, x, y); + MwLLMakeBorderless(r, MwTRUE); + } + break; + case MwLL_WAYLAND_LAYER_SURFACE: + setup_layer_surface(r, x, y, width, height); + break; + } + } + + WIDGET_CHECK(r); + + r->wayland.region = wl_compositor_create_region(r->wayland.compositor); + r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); + MwLLWaylandRegionSetup(r); + + MwLLForceRender(r); + if(parent != NULL) { + MwLLForceRender(parent); + } + + /* If the compositor never sets the keyboard repeat info, we'll copy KDE's default of... */ + r->wayland.keyboard_delay = 600; /* starting at 600ms... */ + r->wayland.keyboard_rate = 25; /* and going every 25ms... */ + + if(!r->wayland.has_decorations && r->wayland.do_csd) { + MwLLBeginDraw(r); + MwLLEndDraw(r); + } +} + +#ifdef USE_DBUS +static void dark_theme_listener(MwLL handle, MwU32 new_value) { + handle->wayland.dark_theme = (new_value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); +} + +static void detect_dark_theme(MwLL handle) { + MwU32 value = 0; + + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + handle->wayland.dark_theme = (value == 1) ? 1 : 0; + + MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); + + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); +} +#endif + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + if(MwLLWaylandWidgetIsDestroyed(r)) { + MwLLWaylandWidgetUndestroy(r); + } + + r->wayland.is_toplevel = parent == NULL; + r->wayland.is_clipping = 0; + + widget_setup(r, parent, x, y, width, height, MwLL_WAYLAND_UNKNOWN); + +#ifdef USE_DBUS + if(!parent && wl_call_tbl.has_dbus) { + wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); + r->wayland.dark_theme_detection = MwTRUE; + r->wayland.dark_theme = -1; + } +#endif + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + int i; + struct timeval tv; + int select_ret; + + event_loop(handle); + // wl_display_cancel_read(handle->wayland.display); + + MwLLWaylandFlush(handle); + + handle->wayland.cancelEvent = MwTRUE; + + MwLLDestroyCommon(handle); + + tv.tv_sec = 0; + tv.tv_usec = 1000; + do { + select_ret = select(1, NULL, NULL, NULL, &tv); + } while((select_ret == -1) && (errno == EINTR)); + + pthread_mutex_destroy(&handle->wayland.eventsMutex); + +#ifdef USE_DBUS + if(!wl_call_tbl.has_dbus) { + MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); + } +#endif + + if(handle->wayland.valid) { + MwLLWaylandBufferDestroy(&handle->wayland.cursor); + wl_region_destroy(handle->wayland.region); + + if(handle->wayland.supports_zwp) { + zwp_primary_selection_source_v1_destroy(handle->wayland.clipboard_source.zwp); + } else { + wl_data_source_destroy(handle->wayland.clipboard_source.wl); + } + if(handle->wayland.icon != NULL) { + MwLLWaylandBufferDestroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + + destroy_widget(handle); + } else { + printf("widget invalid\n"); + } + + pthread_mutex_lock(&destroyedWidgetsTableMutex); + arrput(destroyedWidgetsTable, handle); + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + + free(handle); + + // if(topmost_parent->wayland.currentlyHeldWidget == handle) { + // topmost_parent->wayland.currentlyHeldWidget = NULL; + // } +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + if(!handle->wayland.valid) { + *x = 0; + *y = 0; + *w = 1; + *h = 1; + return; + } + *x = handle->wayland.x; + *y = handle->wayland.y; + *w = handle->wayland.ww; + *h = handle->wayland.wh; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + WIDGET_CHECK(handle); + MwLLWaylandRegionInvalidate(handle); + handle->wayland.x = x; + handle->wayland.y = y; + + switch(handle->wayland.type) { + case MwLL_WAYLAND_TOPLEVEL: + /* toplevels cannot be moved */ + break; + case MwLL_WAYLAND_SUBLEVEL: + wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); + break; + case MwLL_WAYLAND_POPUP: + xdg_positioner_set_anchor_rect(handle->wayland.popup->xdg_positioner, handle->wayland.parent->wayland.x, handle->wayland.parent->wayland.y, handle->wayland.ww, handle->wayland.wh); + xdg_positioner_set_offset(handle->wayland.popup->xdg_positioner, x, y); + xdg_popup_reposition(handle->wayland.popup->xdg_popup, handle->wayland.popup->xdg_positioner, 0); + xdg_surface_set_window_geometry(handle->wayland.popup->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + break; + case MwLL_WAYLAND_LAYER_SURFACE: + zwlr_layer_surface_v1_set_margin(handle->wayland.layer_surface->surface, + y, 0, 0, x); + break; + case MwLL_WAYLAND_UNKNOWN: + break; + } + MwLLWaylandRegionSetup(handle); + + if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) recursive_render(handle); + + MwLLDispatch(handle, draw, NULL); +} + +static void actually_set_wh(MwLL handle) { + MwLLWaylandRegionInvalidate(handle); + + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + } + + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) { + handle->wayland.dispatching_resize = MwTRUE; + MwLLDispatch(handle, resize, NULL); + handle->wayland.dispatching_resize = MwFALSE; + } + + if(handle->wayland.type == MwLL_WAYLAND_POPUP) { + destroy_widget(handle); + MwLLWaylandFlush(handle); + setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); + } + + MwLLWaylandRegionSetup(handle); + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) recursive_render(handle); + + MwLLWaylandFramebufferDestroy(&handle->wayland); + MwLLWaylandFramebufferSetup(&handle->wayland); + MwLLWaylandBackbufferDestroy(&handle->wayland); + MwLLWaylandBackbufferSetup(&handle->wayland); + MwLLDispatch(handle, draw, NULL); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + WIDGET_CHECK(handle); + + if(handle->wayland.ww == w && handle->wayland.wh == h) { + return; + } + + /* Prevent an integer underflow when the w/h is too low */ + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(w < 50) w = 50; + if(h < 50) h = 50; + } + + handle->wayland.ww = w; + handle->wayland.wh = h; + + if(!handle->wayland.setting_wh) { + handle->wayland.setting_wh = 1; + } + + handle->wayland.events_pending = 1; +} + +typedef struct { + double r, g, b; +} float_color; +static float_color lerp_color(float_color a, float_color b, float t) { + return (float_color){ + a.r + (b.r - a.r) * t, + a.g + (b.g - a.g) * t, + a.b + (b.b - a.b) * t}; +} +const float_color one = {.2627451, .37254902, .49411765}; +const float_color two = {.05490196, .17254902, .30588235}; + +static void MwLLBeginDrawImpl(MwLL handle) { + WIDGET_CHECK(handle); + cairo_save(handle->wayland.cairo.front_cairo); + cairo_set_source_rgba(handle->wayland.cairo.front_cairo, 0, 0, 0, 0); + cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(handle->wayland.cairo.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); + cairo_fill(handle->wayland.cairo.front_cairo); + cairo_restore(handle->wayland.cairo.front_cairo); + + if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; + return; + } + + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + int y; + MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + MwRect r; + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.back_cairo; + +#define DO_BOX(x, y, col, w, h) \ + cairo_rectangle(handle->wayland.cairo.back_cairo, x, y, w, h); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_fill(handle->wayland.cairo.back_cairo); + +#define DO_LINE(off, col) \ + cairo_move_to(handle->wayland.cairo.back_cairo, off, off); \ + cairo_line_to(handle->wayland.cairo.back_cairo, off, h - (off)); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_stroke(handle->wayland.cairo.back_cairo); \ + cairo_move_to(handle->wayland.cairo.back_cairo, off, off); \ + cairo_line_to(handle->wayland.cairo.back_cairo, w - (off), off); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_stroke(handle->wayland.cairo.back_cairo); + + /* border */ + cairo_set_antialias(handle->wayland.cairo.back_cairo, CAIRO_ANTIALIAS_NONE); + + DO_BOX(0, 0, 0.14901961, w, h); + DO_BOX(1, 1, 0.55686275, w - 2, h - 2); + DO_BOX(2, 2, 0.82352941, w - 4, h - 4); + DO_BOX(3, 3, 0.93333333, w - 6, h - 6); + DO_BOX(4, 4, 1, w - 8, h - 8); + DO_BOX(4, 4, 0.14901961, w - CSD_BORDER_FRAME_LEFT - 4, h - CSD_BORDER_FRAME_BOTTOM - 4); + cairo_set_line_width(handle->wayland.cairo.back_cairo, 1.0); + + DO_LINE(1, 1) + DO_LINE(2, 0.93333333) + DO_LINE(3, 0.82352941) + DO_LINE(4, 0.55686275) + DO_LINE(5, 0.14901961) + + cairo_set_line_width(handle->wayland.cairo.back_cairo, 2.0); + for(y = 1; y < CSD_BORDER_FRAME_TOP - CSD_BORDER_FRAME_LEFT; y++) { + float_color c = lerp_color(one, two, (double)y / (double)(CSD_BORDER_FRAME_TOP - CSD_BORDER_FRAME_LEFT)); + + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, c.r, c.g, c.b); + + cairo_move_to(handle->wayland.cairo.back_cairo, CSD_BORDER_FRAME_LEFT, y + CSD_BORDER_FRAME_LEFT); + cairo_line_to(handle->wayland.cairo.back_cairo, w - CSD_BORDER_FRAME_RIGHT, y + CSD_BORDER_FRAME_LEFT); + cairo_stroke(handle->wayland.cairo.back_cairo); + } + + /* icon */ + r.x = CSD_BORDER_FRAME_LEFT + 1; + r.y = CSD_BORDER_FRAME_RIGHT + 1; + r.width = 15; + r.height = 15; + DO_BOX(5, 5, 1, 18, 18); + DO_BOX(6, 6, 0.35294118, 17, 17); + DO_BOX(6, 6, 0.82352941, 16, 16); + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.back_cairo; + if(handle->wayland.icon_pixmap) { + MwLLDrawPixmap(handle, &r, handle->wayland.icon_pixmap); + } + + /* close */ + DO_BOX(w - 19 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 1, 1, 18, 18); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.35294118, 17, 17); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.82352941, 16, 16); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT + 5, CSD_BORDER_FRAME_BOTTOM + 7, 0, 6, 6); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT + 6, CSD_BORDER_FRAME_BOTTOM + 8, 0.82352941, 4, 4); + + /* maxim */ + DO_BOX(w - 37 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 1, 1, 18, 18); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.35294118, 17, 17); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.82352941, 16, 16); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 5, CSD_BORDER_FRAME_BOTTOM + 7, 0, 6, 6); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 9, 0.82352941, 16, 2); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 7, CSD_BORDER_FRAME_BOTTOM + 4, 0.82352941, 2, 14); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 6, CSD_BORDER_FRAME_BOTTOM + 8, 0.82352941, 4, 4); + + /* title */ + if(strlen(handle->wayland.title) != 0) { + int y, x; + int i = 0, sx = 0, sy = 0; + int tw, th; + unsigned char* px; + MwLLPixmap p; + tw = strlen(handle->wayland.title) * 7; + th = 14; + px = malloc(tw * th * 4); + assert(px); + + memset(px, 0, tw * th * 4); + + while(handle->wayland.title[i]) { + int out; + i += MwUTF8ToUTF32(handle->wayland.title + i, &out); + + if(out > 0xff) { + out = 0; + } + + for(y = 0; y < 14; y++) { + for(x = 0; x < 7; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + int col = MwFontData[out].data[y] & (1 << ((7 - 1) - x)) ? 255 : 0; + ppx[0] = col; + ppx[1] = col; + ppx[2] = col; + ppx[3] = col; + } + } + sx += 7; + } + + p = MwLLCreatePixmap(handle, px, tw, th); + r.x = 24; + r.y = 5 + 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle, &r, p); + MwLLDestroyPixmap(p); + free(px); + } + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; +} + +static void MwLLEndDrawImpl(MwLL handle) { + if(handle->wayland.configured) { + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + } +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoPolygon(handle->wayland.cairo, points, points_count, color); + + handle->wayland.events_pending = 1; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + int i; + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoLine(handle->wayland.cairo, points, color); + + handle->wayland.events_pending = 1; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + (void)handle; + + c->common.red = r; + c->common.blue = b; + c->common.green = g; + + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + c->common.red = r; + c->common.blue = b; + c->common.green = g; +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + struct timespec timeout = { + .tv_nsec = 1, + .tv_sec = 0, + }; + struct pollfd fd = { + .fd = wl_display_get_fd(handle->wayland.display), + .events = POLLOUT, + }; + int pending = 0; + + if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { + return 0; + } + + handle->wayland.resizing = 0; + + if(handle->wayland.setting_wh) { + actually_set_wh(handle); + handle->wayland.setting_wh = 0; + } + + handle->wayland.end_time = MwTimeGetTick(); + + if(handle->wayland.holding_key) { + float elapsed = ((float)(handle->wayland.end_time - (float)handle->wayland.start_time)); + if(elapsed >= handle->wayland.next_elapsed) { + MwLL topmost_parent = handle; + while(topmost_parent->wayland.parent) { + MwLLDispatch(topmost_parent, key, &handle->wayland.last_pressed_key); + topmost_parent = topmost_parent->wayland.parent; + } + handle->wayland.next_elapsed = elapsed + handle->wayland.keyboard_rate; + } + } + +#ifdef USE_DBUS + if(wl_call_tbl.has_dbus) { + if(handle->wayland.dark_theme_detection) { + + handle->wayland.dark_theme_detection = MwFALSE; + detect_dark_theme(handle); + MwLLDispatch(handle, draw, NULL); + } else { + MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); + } + } +#endif + + if(!handle->wayland.did_initial_resize) { + recursive_dispatch_resize(handle); + handle->wayland.did_initial_resize = 1; + } + + if(!MwWaylandVulkan) { + wl_display_prepare_read(handle->wayland.display); + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(handle->wayland.display); + } else { + wl_display_read_events(handle->wayland.display); + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + } + } else { + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + return pending; + } + + MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + + return handle->wayland.force_render || handle->wayland.events_pending || pending; +} + +static void MwLLNextEventImpl(MwLL handle) { + WIDGET_CHECK(handle); + if(!MwWaylandVulkan) { + if(handle->wayland.did_event_loop_early) { + handle->wayland.did_event_loop_early = MwFALSE; + } else { + event_loop(handle); + } + } + + if(handle->wayland.force_render) { + MwLLDispatch(handle, draw, NULL); + if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + handle->wayland.force_render = 0; + } + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); + } + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + strncpy(handle->wayland.title, title, 255); + MwLLBeginDraw(handle); + MwLLEndDraw(handle); + + xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, (strlen(handle->wayland.title) * 8) + 64, 64); + } +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + return MwLLCairoCreatePixmap(handle->wayland.cairo, data, width, height); +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + MwLLCairoPixmapUpdate(r); +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + MwLLCairoDestroyPixmap(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoDrawPixmap(handle->wayland.cairo, rect, pixmap); + + MwLLForceRender(handle); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); +} +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { + struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; + struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(icon_manager); + MwU64 size = pixmap->common.width * pixmap->common.height * 4; + int i = 0; + int line = (pixmap->common.width < pixmap->common.height) ? pixmap->common.height : pixmap->common.width; + + if(handle->wayland.icon == NULL) { + handle->wayland.icon = malloc(sizeof(struct _MwLLWaylandShmBuffer)); + memset(handle->wayland.icon, 0, sizeof(struct _MwLLWaylandShmBuffer)); + handle->wayland.icon->shm = handle->wayland.framebuffer.shm; + } + + if(handle->wayland.icon->setup) { + MwLLWaylandBufferDestroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + handle->wayland.icon->surface = wl_compositor_create_surface(handle->wayland.compositor); + + MwLLWaylandBufferSetup(handle->wayland.icon, line, line); + + wl_surface_attach(handle->wayland.icon->surface, handle->wayland.icon->shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.icon->surface); + + for(; i < size; i += 2) { + handle->wayland.icon->buf_back[i] = pixmap->common.raw[i + 2]; + handle->wayland.icon->buf_back[i + 1] = pixmap->common.raw[i + 1]; + handle->wayland.icon->buf_back[i + 2] = pixmap->common.raw[i + 0]; + handle->wayland.icon->buf_back[i + 3] = 255; + } + + if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, handle->wayland.icon); + + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer_back, 1); + + xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); + } + } + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + if(handle->wayland.icon_pixmap) { + MwLLDestroyPixmap(handle->wayland.icon_pixmap); + } + handle->wayland.icon_pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); + + actually_set_wh(handle); + actually_set_wh(handle); + MwLLBeginDraw(handle); + MwLLEndDraw(handle); + } +} + +static void MwLLForceRenderImpl(MwLL handle) { + WIDGET_CHECK(handle); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + + handle->wayland.force_render = MwTRUE; + if(handle->wayland.parent) { + handle->wayland.parent->wayland.force_render = MwTRUE; + } +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + int x, y, xs, ys; + + WIDGET_CHECK(handle); + + if(handle->wayland.cursor.setup) { + MwLLWaylandBufferDestroy(&handle->wayland.cursor); + wl_surface_destroy(handle->wayland.cursor.surface); + } + MwLLWaylandBufferSetup(&handle->wayland.cursor, mask->width, mask->height); + memset(handle->wayland.cursor.buf_back, 0, handle->wayland.cursor.buf_size); + + xs = -mask->x + image->x; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; + + if(ys < 0) ys = -ys; + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + handle->wayland.cursor.buf_back[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = (((y + ys) * mask->width) + (x + xs)) * 4; + + if(d & 1) { + px = 255; + }; + + handle->wayland.cursor.buf_back[idx] = px; + handle->wayland.cursor.buf_back[idx + 1] = px; + handle->wayland.cursor.buf_back[idx + 2] = px; + d = d >> 1; + } + } + + handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.cursor.surface); + MwLLWaylandBufferUpdate(handle, &handle->wayland.cursor); +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + MwLL p = handle->wayland.parent; + int x = 0, y = 0; + WIDGET_CHECK(handle); + while(p != NULL) { + if(p->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + x += p->wayland.x; + y += p->wayland.y; + } else { + break; + } + p = p->wayland.parent; + } + + handle->wayland.changing = MwTRUE; + handle->wayland.detatching = MwTRUE; + handle->wayland.detach_point = *point; + handle->wayland.detach_point.x += x; + handle->wayland.detach_point.y += y; +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(!handle->wayland.configured) { + return; + } + WIDGET_CHECK(handle); + /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ + if(handle->wayland.framebuffer.surface) { + wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); + wl_surface_commit(handle->wayland.framebuffer.surface); + } + if(handle->wayland.backbuffer.surface) { + wl_surface_attach(handle->wayland.backbuffer.surface, show ? handle->wayland.backbuffer.shm_buffer : NULL, 0, 0); + wl_surface_commit(handle->wayland.backbuffer.surface); + } +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; + /* Wayland doesn't have "popups" in the Milsko sense per se. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); + xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); + + wl_surface_commit(handle->wayland.framebuffer.surface); + wl_surface_commit(handle->wayland.backbuffer.surface); + } +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; + + if(!dec->decoration) { + dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + dec->manager, handle->wayland.toplevel->xdg_top_level); + } + + zxdg_toplevel_decoration_v1_unset_mode(dec->decoration); + zxdg_toplevel_decoration_v1_set_mode( + dec->decoration, toggle ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + handle->wayland.do_csd = !toggle; + wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + } + } +} + +static void MwLLFocusImpl(MwLL handle) { + (void)handle; + printf("[WARNING] MwLLFocus not supported on Wayland\n"); +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + MwLL topmost_parent = handle; + WIDGET_CHECK(handle); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { + if(toggle) { + topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.backbuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + wl_surface_commit(topmost_parent->wayland.backbuffer.surface); + zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + handle->wayland.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(handle->wayland.relative_pointer_manager, handle->wayland.pointer); + zwp_relative_pointer_v1_add_listener(handle->wayland.relative_pointer, &MwLLWaylandRelativePointerListener, topmost_parent); + } else { + if(topmost_parent->wayland.locked_pointer) { + zwp_locked_pointer_v1_destroy(topmost_parent->wayland.locked_pointer); + topmost_parent->wayland.locked_pointer = NULL; + } + if(topmost_parent->wayland.relative_pointer) { + zwp_relative_pointer_v1_destroy(topmost_parent->wayland.relative_pointer); + topmost_parent->wayland.relative_pointer = NULL; + } + } + handle->wayland.do_lock_pointer = toggle; + } else { + printf("[WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 and relative_pointer_manager_v1 are required.\n"); + } +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + int i; + WIDGET_CHECK(handle); + + if(handle->wayland.clipboard_buffer != NULL) { + free(handle->wayland.clipboard_buffer); + } + handle->wayland.clipboard_buffer = malloc(strlen(text)); + strcpy(handle->wayland.clipboard_buffer, text); + + if(clipboard_type == MwCLIPBOARD_PRIMARY) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; + zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_wl[i]; + wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); + } + } +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + int i; + WIDGET_CHECK(handle); + if(clipboard_type == MwCLIPBOARD_PRIMARY) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + MwLLWaylandClipboardRead( + handle->wayland.clipboard_devices_zwp[i], clipboard_type); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + MwLLWaylandClipboardRead( + handle->wayland.clipboard_devices_wl[i], clipboard_type); + } + } + return; +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + MwBool can_do_layer_surface = MwFALSE; + + WIDGET_CHECK(handle); + + can_do_layer_surface = (WAYLAND_GET_INTERFACE(handle->wayland, zwlr_layer_shell_v1) != NULL); + + if(!handle->wayland.parent && can_do_layer_surface) { + handle->wayland.type_to_be = MwLL_WAYLAND_LAYER_SURFACE; + } else { + handle->wayland.type_to_be = MwLL_WAYLAND_POPUP; + } + + handle->wayland.changing = MwTRUE; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MwLL topmost_parent = handle; + + WIDGET_CHECK(handle); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + *point = topmost_parent->wayland.cur_mouse_pos; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + WIDGET_CHECK(handle); + + rect->x = 0; + rect->y = 0; + rect->width = handle->wayland.mw; + rect->height = handle->wayland.mh; +} + +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + (void)handle; + /* no-op */ +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLL topmost_parent; + int x, y; + WIDGET_CHECK(handle); + + if(!handle->wayland.changing) { + return; + } + handle->wayland.changing = MwFALSE; + + x = handle->wayland.detatching ? handle->wayland.detach_point.x : handle->wayland.x; + y = handle->wayland.detatching ? handle->wayland.detach_point.y : handle->wayland.y; + + topmost_parent = handle->wayland.parent; + + while(topmost_parent) { + if(topmost_parent->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } else { + break; + } + } + + destroy_widget(handle); + + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + MwLLWaylandFlush(handle); + + widget_setup(handle, handle->wayland.parent, x, y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); + + handle->wayland.is_toplevel = MwTRUE; + + if(!handle->wayland.parent) + handle->wayland.dark_theme_detection = MwTRUE; + + if(handle->common.user) { + MwWidget w = handle->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + child->wayland.sublevel->xdg_surface = handle->wayland.popup->xdg_surface; + if(child->wayland.sublevel->subsurface) + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + MwLLWaylandFlush(handle); + + child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); + wl_subsurface_set_desync(child->wayland.sublevel->subsurface); + wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); + + wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); + MwLLEndStateChangeImpl(w->children[i]->lowlevel); + + if(topmost_parent) { + topmost_parent->wayland.currentlyHeldWidget = NULL; + } + } + } + } + + recursive_render(handle); + + handle->wayland.events_pending = 1; + + handle->wayland.detatching = MwFALSE; +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)toggle; + + /* Not Really what's supposed to happen with this function, but take this opprutunity to do the handlers that will force everything to redraw. */ + MwLLDispatch(handle, resize, NULL); + MwLLDispatch(handle, draw, NULL); +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; + /* WIDGET_CHECK(handle); + + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL topmost_parent = handle; + int children_num; + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + children_num = arrlen(((MwWidget)topmost_parent->common.user)->children); + + if(children_num > 1) { + printf("%d\n", children_num); + MwWidget last_child = ((MwWidget)topmost_parent->common.user)->children[children_num - 1]; + wl_subsurface_place_above(handle->wayland.sublevel->subsurface, last_child->lowlevel->wayland.framebuffer.surface); + } + }*/ +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + handle->wayland.is_clipping = MwFALSE; + } else { + handle->wayland.clip = *rect; + handle->wayland.is_clipping = MwTRUE; + } +} + +static int MwLLWaylandCallInitImpl(void) { +#ifdef __linux__ + MwBool loadWayland = MwFALSE; + if(getenv("MILSKO_BACKEND")) { + loadWayland |= + (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); + } else if(getenv("WAYLAND_DISPLAY")) { + loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); + } + +#ifdef MW_OPENGL + if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { + loadWayland = 0; + } +#endif + + if(loadWayland) { + if(wayland_load_funcs()) { + return 1; + } + wl_log_set_handler_client(wl_logger); + + return 0; + } +#endif + return 1; +} + +#include "../call.c" +CALL(Wayland); diff --git a/src/backend/x11.c b/src/backend/x11.c index 704bd7bd..cc4d22bc 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -4,6 +4,10 @@ #define ClipboardTimeout 100 +#ifdef USE_XRENDER +// #undef USE_XRENDER +#endif + static struct symtbl { void* lib_xlib; void* lib_xrender; @@ -61,6 +65,7 @@ static struct symtbl { Status (*XSendEvent)(Display*, Window, Bool, long, XEvent*); int (*XSetClipMask)(Display*, GC, Pixmap); int (*XSetClipOrigin)(Display*, GC, int, int); + int (*XSetClipRectangles)(Display*, GC, int, int, XRectangle[], int, int); int (*XSetForeground)(Display*, GC, unsigned long); int (*XSetGraphicsExposures)(Display*, GC, Bool); int (*XSetInputFocus)(Display*, Window, int, Time); @@ -75,6 +80,8 @@ static struct symtbl { XIC (*XCreateIC)(XIM, ...); void (*XDestroyIC)(XIC); void (*XSetICFocus)(XIC); + XImage* (*XGetImage)(Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int); + int (*XRaiseWindow)(Display*, Window); XSizeHints* (*XAllocSizeHints)(void); XVisualInfo* (*XGetVisualInfo)(Display*, long, XVisualInfo*, int*); @@ -172,10 +179,13 @@ static struct symtbl { #define XReparentWindow xsymtbl.XReparentWindow #define XCreatePixmap xsymtbl.XCreatePixmap #define XSetClipOrigin xsymtbl.XSetClipOrigin +#define XSetClipRectangles xsymtbl.XSetClipRectangles #define XCloseIM xsymtbl.XCloseIM #define XQueryTree xsymtbl.XQueryTree #define XPending xsymtbl.XPending #define XChangeWindowAttributes xsymtbl.XChangeWindowAttributes +#define XGetImage xsymtbl.XGetImage +#define XRaiseWindow xsymtbl.XRaiseWindow #if USE_XRENDER #define XRenderFindStandardFormat xsymtbl.XRenderFindStandardFormat @@ -405,8 +415,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.width = width; r->x11.height = height; - r->x11.grabbed = 0; - r->x11.force_render = 0; + r->x11.grabbed = 0; + r->x11.force_render = 0; + r->x11.dark_theme_detection = 0; r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); @@ -490,7 +501,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { (void)handle; - XClearWindow(handle->x11.display, handle->x11.window); + if(handle->common.copy_buffer) XClearWindow(handle->x11.display, handle->x11.window); } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { @@ -709,7 +720,9 @@ static void MwLLNextEventImpl(MwLL handle) { p.button = MwMOUSE_WHEELDOWN; } +#ifndef ALLOW_SLOPPY_FOCUS XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); +#endif MwLLDispatch(handle, down, &p); } else if(ev.type == ButtonRelease) { @@ -788,35 +801,37 @@ static void MwLLNextEventImpl(MwLL handle) { } else { n = s; } - } else if(strcmp(str, "BackSpace") == 0) { - n = MwLLKeyBackSpace; - } else if(strcmp(str, "Left") == 0) { - n = MwLLKeyLeft; - } else if(strcmp(str, "Right") == 0) { - n = MwLLKeyRight; - } else if(strcmp(str, "Up") == 0) { - n = MwLLKeyUp; - } else if(strcmp(str, "Down") == 0) { - n = MwLLKeyDown; - } else if(strcmp(str, "Return") == 0) { - n = MwLLKeyEnter; - } else if(strcmp(str, "Escape") == 0) { - n = MwLLKeyEscape; - } else if(strcmp(str, "Shift_L") == 0) { - n = MwLLKeyLeftShift; - } else if(strcmp(str, "Shift_R") == 0) { - n = MwLLKeyRightShift; - } else if(strcmp(str, "Alt_L") == 0 || strcmp(str, "Alt_R") == 0) { - n = MwLLKeyAlt; - } else if(strcmp(str, "Control_R") == 0 || strcmp(str, "Control_R") == 0) { - n = MwLLKeyControl; } - if(n != MwLLKeyControl && ev.xkey.state & ControlMask) { - n |= MwLLControlMask; + if(strcmp(str, "BackSpace") == 0) { + n = MwKEY_BACKSPACE; + } else if(strcmp(str, "Left") == 0) { + n = MwKEY_LEFT; + } else if(strcmp(str, "Right") == 0) { + n = MwKEY_RIGHT; + } else if(strcmp(str, "Up") == 0) { + n = MwKEY_UP; + } else if(strcmp(str, "Down") == 0) { + n = MwKEY_DOWN; + } else if(strcmp(str, "Return") == 0) { + n = MwKEY_ENTER; + } else if(strcmp(str, "Escape") == 0) { + n = MwKEY_ESCAPE; + } else if(strcmp(str, "Shift_L") == 0) { + n = MwKEY_LEFTSHIFT; + } else if(strcmp(str, "Shift_R") == 0) { + n = MwKEY_RIGHTSHIFT; + } else if(strcmp(str, "Alt_L") == 0 || strcmp(str, "Alt_R") == 0) { + n = MwKEY_ALT; + } else if(strcmp(str, "Control_R") == 0 || strcmp(str, "Control_R") == 0) { + n = MwKEY_CONTROL; } - if(n != MwLLKeyAlt && ev.xkey.state & Mod1Mask) { - n |= MwLLAltMask; + + if(n != MwKEY_CONTROL && ev.xkey.state & ControlMask) { + n |= MwKEY_CONTROL_FLAG; + } + if(n != MwKEY_ALT && ev.xkey.state & Mod1Mask) { + n |= MwKEY_ALT_FLAG; } if(n != -1) { @@ -914,7 +929,7 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid #endif r->x11.image = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), r->x11.depth, ZPixmap, 0, NULL, width, height, 32, 0); - r->x11.mask = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 1, ZPixmap, 0, NULL, width, height, 32, 0); + r->x11.mask = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 8, ZPixmap, 0, NULL, width, height, 32, 0); r->x11.image->data = malloc(r->x11.image->bytes_per_line * height); r->x11.mask->data = malloc(r->x11.mask->bytes_per_line * height); @@ -943,7 +958,7 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap r) { for(y = 0; y < r->common.height; y++) { for(x = 0; x < r->common.width; x++) { if(r->common.raw[(y * r->common.width + x) * 4 + 3]) { - XPutPixel(r->x11.mask, x, y, 1); + XPutPixel(r->x11.mask, x, y, 255); } else { XPutPixel(r->x11.mask, x, y, 0); } @@ -960,38 +975,52 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { free(pixmap); } +#define DO_XRENDER(dest_px, src, format, bpp) \ + { \ + Picture src_pic, dest_pic; \ + XRenderPictFormat* fmt = XRenderFindStandardFormat(handle->x11.display, format); \ + Pixmap src_px = XCreatePixmap(handle->x11.display, handle->x11.window, pixmap->common.width, pixmap->common.height, bpp); \ + GC gc = XCreateGC(handle->x11.display, src_px, 0, NULL); \ +\ + dest_px = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, bpp); \ +\ + XPutImage(handle->x11.display, src_px, gc, src, 0, 0, 0, 0, pixmap->common.width, pixmap->common.height); \ +\ + src_pic = XRenderCreatePicture(handle->x11.display, src_px, fmt, render_mask, &attr); \ + dest_pic = XRenderCreatePicture(handle->x11.display, dest_px, fmt, render_mask, &attr); \ +\ + XRenderSetPictureTransform(handle->x11.display, src_pic, &m); \ + XRenderComposite(handle->x11.display, PictOpSrc, src_pic, 0, dest_pic, 0, 0, 0, 0, 0, 0, rect->width, rect->height); \ +\ + XRenderFreePicture(handle->x11.display, src_pic); \ + XRenderFreePicture(handle->x11.display, dest_pic); \ + XFreePixmap(handle->x11.display, src_px); \ + XFreeGC(handle->x11.display, gc); \ + } + static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { if(rect->width <= 0 || rect->height <= 0 || pixmap->common.width <= 0 || pixmap->common.height <= 0) return; + if(rect->width >= INT16_MAX) rect->width = INT16_MAX; + if(rect->height >= INT16_MAX) rect->height = INT16_MAX; + #ifdef USE_XRENDER if(pixmap->x11.image != NULL && pixmap->x11.use_xrender) { - Pixmap px = XCreatePixmap(handle->x11.display, handle->x11.window, pixmap->common.width, pixmap->common.height, pixmap->x11.depth); - Pixmap mask = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, 1); - Pixmap pxsrc = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, pixmap->x11.depth); - GC maskgc = XCreateGC(handle->x11.display, mask, 0, NULL); - XRenderPictFormat* format = XRenderFindStandardFormat(handle->x11.display, PictStandardRGB24); + Pixmap px; + Pixmap mask, mask_tmp; XRenderPictureAttributes attr; - Picture src, dest; XTransform m; - double xsc = (double)pixmap->common.width / rect->width; - double ysc = (double)pixmap->common.height / rect->height; - char* dm = malloc(rect->width * rect->height * 4); - XImage* destmask; + double xsc; + double ysc; + unsigned long render_mask = 0; + XImage* mask_tmp_img; + XImage* mask_img; int y, x; + GC mask_gc; - destmask = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 1, ZPixmap, 0, dm, rect->width, rect->height, 32, rect->width * 4); + memset(&attr, 0, sizeof(attr)); - for(y = 0; y < (int)rect->height; y++) { - for(x = 0; x < (int)rect->width; x++) { - int sy = y * pixmap->common.height / rect->height; - int sx = x * pixmap->common.width / rect->width; - sy = (int)sy; - sx = (int)sx; - - XPutPixel(destmask, x, y, XGetPixel(pixmap->x11.mask, sx, sy)); - } - } - - XPutImage(handle->x11.display, mask, maskgc, destmask, 0, 0, 0, 0, rect->width, rect->height); + xsc = (double)pixmap->common.width / rect->width; + ysc = (double)pixmap->common.height / rect->height; m.matrix[0][0] = XDoubleToFixed(xsc); m.matrix[0][1] = XDoubleToFixed(0); @@ -1005,30 +1034,44 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { m.matrix[2][1] = XDoubleToFixed(0); m.matrix[2][2] = XDoubleToFixed(1.0); - memset(&attr, 0, sizeof(attr)); + DO_XRENDER(px, pixmap->x11.image, PictStandardRGB24, pixmap->x11.depth); + DO_XRENDER(mask_tmp, pixmap->x11.mask, PictStandardA8, 8); - XPutImage(handle->x11.display, px, handle->x11.gc, pixmap->x11.image, 0, 0, 0, 0, pixmap->common.width, pixmap->common.height); + /* FIXME: this is terrible way to do this... i hope someone who knows xrender better than me + * gives me better solution + */ + mask_tmp_img = XGetImage(handle->x11.display, mask_tmp, 0, 0, rect->width, rect->height, 0xff, ZPixmap); + mask_img = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 1, ZPixmap, 0, NULL, rect->width, rect->height, 32, 0); + mask = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, 1); + mask_gc = XCreateGC(handle->x11.display, mask, 0, NULL); - src = XRenderCreatePicture(handle->x11.display, px, format, 0, &attr); - dest = XRenderCreatePicture(handle->x11.display, pxsrc, format, 0, &attr); + mask_img->data = malloc(mask_img->bytes_per_line * rect->height); - XRenderSetPictureTransform(handle->x11.display, src, &m); - XRenderComposite(handle->x11.display, PictOpSrc, src, 0, dest, 0, 0, 0, 0, 0, 0, rect->width, rect->height); - - XRenderFreePicture(handle->x11.display, src); - XRenderFreePicture(handle->x11.display, dest); + for(y = 0; y < rect->height; y++) { + for(x = 0; x < rect->width; x++) { + unsigned long p = XGetPixel(mask_tmp_img, x, y); + if(p == 255) { + p = 1; + } else { + p = 0; + } + XPutPixel(mask_img, x, y, p); + } + } + XPutImage(handle->x11.display, mask, mask_gc, mask_img, 0, 0, 0, 0, rect->width, rect->height); + XFreeGC(handle->x11.display, mask_gc); + XDestroyImage(mask_img); + XDestroyImage(mask_tmp_img); + /* end terrible hack */ XSetClipMask(handle->x11.display, handle->x11.gc, mask); XSetClipOrigin(handle->x11.display, handle->x11.gc, rect->x, rect->y); - XCopyArea(handle->x11.display, pxsrc, handle->x11.pixmap, handle->x11.gc, 0, 0, rect->width, rect->height, rect->x, rect->y); + XCopyArea(handle->x11.display, px, handle->x11.pixmap, handle->x11.gc, 0, 0, rect->width, rect->height, rect->x, rect->y); XSetClipMask(handle->x11.display, handle->x11.gc, None); - XDestroyImage(destmask); - - XFreeGC(handle->x11.display, maskgc); + XFreePixmap(handle->x11.display, mask_tmp); XFreePixmap(handle->x11.display, mask); XFreePixmap(handle->x11.display, px); - XFreePixmap(handle->x11.display, pxsrc); } else #endif if(pixmap->x11.image != NULL) { @@ -1122,6 +1165,8 @@ Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask) { ys = mask->height + mask->y; ys = image->height + image->y - ys; + if(ys < 0) ys = -ys; + memset(cimage->data, 0, cimage->bytes_per_line * cimage->height); memset(cmask->data, 0, cmask->bytes_per_line * cmask->height); for(y = 0; y < mask->height; y++) { @@ -1165,6 +1210,9 @@ Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask) { XDestroyImage(cimage); XDestroyImage(cmask); + XFreeGC(display, imagegc); + XFreeGC(display, maskgc); + return cur; } @@ -1202,7 +1250,9 @@ static void MwLLShowImpl(MwLL handle, int show) { if(show) { wait_map(handle, 1); +#ifndef ALLOW_SLOPPY_FOCUS XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); +#endif } else { wait_unmap(handle, 1); } @@ -1311,6 +1361,10 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { rect->height = xwa.height; } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } @@ -1324,6 +1378,30 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; } +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + XRaiseWindow(handle->x11.display, handle->x11.window); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + XSetClipMask(handle->x11.display, handle->x11.gc, None); + } else { + XRectangle rc; + + rc.x = 0; + rc.y = 0; + rc.width = rect->width; + rc.height = rect->height; + + XSetClipRectangles(handle->x11.display, handle->x11.gc, rect->x, rect->y, &rc, 1, Unsorted); + } +} + static int MwLLX11CallInitImpl(void) { MwBool loadX11 = MwFALSE; if(getenv("MILSKO_BACKEND")) { @@ -1403,6 +1481,7 @@ static int MwLLX11CallInitImpl(void) { X11_FUNC_LOAD(XSendEvent); X11_FUNC_LOAD(XSetClipMask); X11_FUNC_LOAD(XSetClipOrigin); + X11_FUNC_LOAD(XSetClipRectangles); X11_FUNC_LOAD(XSetForeground); X11_FUNC_LOAD(XSetGraphicsExposures); X11_FUNC_LOAD(XSetInputFocus); @@ -1417,6 +1496,8 @@ static int MwLLX11CallInitImpl(void) { X11_FUNC_LOAD(XCreateIC); X11_FUNC_LOAD(XDestroyIC); X11_FUNC_LOAD(XSetICFocus); + X11_FUNC_LOAD(XGetImage); + X11_FUNC_LOAD(XRaiseWindow); X11_FUNC_LOAD(XAllocSizeHints); X11_FUNC_LOAD(XGetVisualInfo); diff --git a/src/color.c b/src/color.c index 49c06d69..ae3667ed 100644 --- a/src/color.c +++ b/src/color.c @@ -1,5 +1,14 @@ #include +#include "../external/stb_ds.h" + +struct color { + char* key; + MwU32 value; +}; + +static struct color* colors = NULL; + MwLLColor MwParseColorName(MwWidget handle, const char* color) { MwRGB rgb; MwParseColorNameNoAllocate(color, &rgb); @@ -7,4699 +16,800 @@ MwLLColor MwParseColorName(MwWidget handle, const char* color) { } void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb) { - if(strcmp(color, "snow") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 250; - return; - } - if(strcmp(color, "ghost white") == 0) { - rgb->red = 248; - rgb->green = 248; - rgb->blue = 255; - return; - } - if(strcmp(color, "GhostWhite") == 0) { - rgb->red = 248; - rgb->green = 248; - rgb->blue = 255; - return; - } - if(strcmp(color, "white smoke") == 0) { - rgb->red = 245; - rgb->green = 245; - rgb->blue = 245; - return; - } - if(strcmp(color, "WhiteSmoke") == 0) { - rgb->red = 245; - rgb->green = 245; - rgb->blue = 245; - return; - } - if(strcmp(color, "gainsboro") == 0) { - rgb->red = 220; - rgb->green = 220; - rgb->blue = 220; - return; - } - if(strcmp(color, "floral white") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 240; - return; - } - if(strcmp(color, "FloralWhite") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 240; - return; - } - if(strcmp(color, "old lace") == 0) { - rgb->red = 253; - rgb->green = 245; - rgb->blue = 230; - return; - } - if(strcmp(color, "OldLace") == 0) { - rgb->red = 253; - rgb->green = 245; - rgb->blue = 230; - return; - } - if(strcmp(color, "linen") == 0) { - rgb->red = 250; - rgb->green = 240; - rgb->blue = 230; - return; - } - if(strcmp(color, "antique white") == 0) { - rgb->red = 250; - rgb->green = 235; - rgb->blue = 215; - return; - } - if(strcmp(color, "AntiqueWhite") == 0) { - rgb->red = 250; - rgb->green = 235; - rgb->blue = 215; - return; - } - if(strcmp(color, "papaya whip") == 0) { - rgb->red = 255; - rgb->green = 239; - rgb->blue = 213; - return; - } - if(strcmp(color, "PapayaWhip") == 0) { - rgb->red = 255; - rgb->green = 239; - rgb->blue = 213; - return; - } - if(strcmp(color, "blanched almond") == 0) { - rgb->red = 255; - rgb->green = 235; - rgb->blue = 205; - return; - } - if(strcmp(color, "BlanchedAlmond") == 0) { - rgb->red = 255; - rgb->green = 235; - rgb->blue = 205; - return; - } - if(strcmp(color, "bisque") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 196; - return; - } - if(strcmp(color, "peach puff") == 0) { - rgb->red = 255; - rgb->green = 218; - rgb->blue = 185; - return; - } - if(strcmp(color, "PeachPuff") == 0) { - rgb->red = 255; - rgb->green = 218; - rgb->blue = 185; - return; - } - if(strcmp(color, "navajo white") == 0) { - rgb->red = 255; - rgb->green = 222; - rgb->blue = 173; - return; - } - if(strcmp(color, "NavajoWhite") == 0) { - rgb->red = 255; - rgb->green = 222; - rgb->blue = 173; - return; - } - if(strcmp(color, "moccasin") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 181; - return; - } - if(strcmp(color, "cornsilk") == 0) { - rgb->red = 255; - rgb->green = 248; - rgb->blue = 220; - return; - } - if(strcmp(color, "ivory") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 240; - return; - } - if(strcmp(color, "lemon chiffon") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 205; - return; - } - if(strcmp(color, "LemonChiffon") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 205; - return; - } - if(strcmp(color, "seashell") == 0) { - rgb->red = 255; - rgb->green = 245; - rgb->blue = 238; - return; - } - if(strcmp(color, "honeydew") == 0) { - rgb->red = 240; - rgb->green = 255; - rgb->blue = 240; - return; - } - if(strcmp(color, "mint cream") == 0) { - rgb->red = 245; - rgb->green = 255; - rgb->blue = 250; - return; - } - if(strcmp(color, "MintCream") == 0) { - rgb->red = 245; - rgb->green = 255; - rgb->blue = 250; - return; - } - if(strcmp(color, "azure") == 0) { - rgb->red = 240; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "alice blue") == 0) { - rgb->red = 240; - rgb->green = 248; - rgb->blue = 255; - return; - } - if(strcmp(color, "AliceBlue") == 0) { - rgb->red = 240; - rgb->green = 248; - rgb->blue = 255; - return; - } - if(strcmp(color, "lavender") == 0) { - rgb->red = 230; - rgb->green = 230; - rgb->blue = 250; - return; - } - if(strcmp(color, "lavender blush") == 0) { - rgb->red = 255; - rgb->green = 240; - rgb->blue = 245; - return; - } - if(strcmp(color, "LavenderBlush") == 0) { - rgb->red = 255; - rgb->green = 240; - rgb->blue = 245; - return; - } - if(strcmp(color, "misty rose") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 225; - return; - } - if(strcmp(color, "MistyRose") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 225; - return; - } - if(strcmp(color, "white") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "black") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "dark slate gray") == 0) { - rgb->red = 47; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "DarkSlateGray") == 0) { - rgb->red = 47; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "dark slate grey") == 0) { - rgb->red = 47; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "DarkSlateGrey") == 0) { - rgb->red = 47; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "dim gray") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "DimGray") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "dim grey") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "DimGrey") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "slate gray") == 0) { - rgb->red = 112; - rgb->green = 128; - rgb->blue = 144; - return; - } - if(strcmp(color, "SlateGray") == 0) { - rgb->red = 112; - rgb->green = 128; - rgb->blue = 144; - return; - } - if(strcmp(color, "slate grey") == 0) { - rgb->red = 112; - rgb->green = 128; - rgb->blue = 144; - return; - } - if(strcmp(color, "SlateGrey") == 0) { - rgb->red = 112; - rgb->green = 128; - rgb->blue = 144; - return; - } - if(strcmp(color, "light slate gray") == 0) { - rgb->red = 119; - rgb->green = 136; - rgb->blue = 153; - return; - } - if(strcmp(color, "LightSlateGray") == 0) { - rgb->red = 119; - rgb->green = 136; - rgb->blue = 153; - return; - } - if(strcmp(color, "light slate grey") == 0) { - rgb->red = 119; - rgb->green = 136; - rgb->blue = 153; - return; - } - if(strcmp(color, "LightSlateGrey") == 0) { - rgb->red = 119; - rgb->green = 136; - rgb->blue = 153; - return; - } - if(strcmp(color, "gray") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "grey") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "x11 gray") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "X11Gray") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "x11 grey") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "X11Grey") == 0) { - rgb->red = 190; - rgb->green = 190; - rgb->blue = 190; - return; - } - if(strcmp(color, "web gray") == 0) { - rgb->red = 128; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "WebGray") == 0) { - rgb->red = 128; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "web grey") == 0) { - rgb->red = 128; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "WebGrey") == 0) { - rgb->red = 128; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "light grey") == 0) { - rgb->red = 211; - rgb->green = 211; - rgb->blue = 211; - return; - } - if(strcmp(color, "LightGrey") == 0) { - rgb->red = 211; - rgb->green = 211; - rgb->blue = 211; - return; - } - if(strcmp(color, "light gray") == 0) { - rgb->red = 211; - rgb->green = 211; - rgb->blue = 211; - return; - } - if(strcmp(color, "LightGray") == 0) { - rgb->red = 211; - rgb->green = 211; - rgb->blue = 211; - return; - } - if(strcmp(color, "midnight blue") == 0) { - rgb->red = 25; - rgb->green = 25; - rgb->blue = 112; - return; - } - if(strcmp(color, "MidnightBlue") == 0) { - rgb->red = 25; - rgb->green = 25; - rgb->blue = 112; - return; - } - if(strcmp(color, "navy") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 128; - return; - } - if(strcmp(color, "navy blue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 128; - return; - } - if(strcmp(color, "NavyBlue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 128; - return; - } - if(strcmp(color, "cornflower blue") == 0) { - rgb->red = 100; - rgb->green = 149; - rgb->blue = 237; - return; - } - if(strcmp(color, "CornflowerBlue") == 0) { - rgb->red = 100; - rgb->green = 149; - rgb->blue = 237; - return; - } - if(strcmp(color, "dark slate blue") == 0) { - rgb->red = 72; - rgb->green = 61; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkSlateBlue") == 0) { - rgb->red = 72; - rgb->green = 61; - rgb->blue = 139; - return; - } - if(strcmp(color, "slate blue") == 0) { - rgb->red = 106; - rgb->green = 90; - rgb->blue = 205; - return; - } - if(strcmp(color, "SlateBlue") == 0) { - rgb->red = 106; - rgb->green = 90; - rgb->blue = 205; - return; - } - if(strcmp(color, "medium slate blue") == 0) { - rgb->red = 123; - rgb->green = 104; - rgb->blue = 238; - return; - } - if(strcmp(color, "MediumSlateBlue") == 0) { - rgb->red = 123; - rgb->green = 104; - rgb->blue = 238; - return; - } - if(strcmp(color, "light slate blue") == 0) { - rgb->red = 132; - rgb->green = 112; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightSlateBlue") == 0) { - rgb->red = 132; - rgb->green = 112; - rgb->blue = 255; - return; - } - if(strcmp(color, "medium blue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 205; - return; - } - if(strcmp(color, "MediumBlue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 205; - return; - } - if(strcmp(color, "royal blue") == 0) { - rgb->red = 65; - rgb->green = 105; - rgb->blue = 225; - return; - } - if(strcmp(color, "RoyalBlue") == 0) { - rgb->red = 65; - rgb->green = 105; - rgb->blue = 225; - return; - } - if(strcmp(color, "blue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 255; - return; - } - if(strcmp(color, "dodger blue") == 0) { - rgb->red = 30; - rgb->green = 144; - rgb->blue = 255; - return; - } - if(strcmp(color, "DodgerBlue") == 0) { - rgb->red = 30; - rgb->green = 144; - rgb->blue = 255; - return; - } - if(strcmp(color, "deep sky blue") == 0) { - rgb->red = 0; - rgb->green = 191; - rgb->blue = 255; - return; - } - if(strcmp(color, "DeepSkyBlue") == 0) { - rgb->red = 0; - rgb->green = 191; - rgb->blue = 255; - return; - } - if(strcmp(color, "sky blue") == 0) { - rgb->red = 135; - rgb->green = 206; - rgb->blue = 235; - return; - } - if(strcmp(color, "SkyBlue") == 0) { - rgb->red = 135; - rgb->green = 206; - rgb->blue = 235; - return; - } - if(strcmp(color, "light sky blue") == 0) { - rgb->red = 135; - rgb->green = 206; - rgb->blue = 250; - return; - } - if(strcmp(color, "LightSkyBlue") == 0) { - rgb->red = 135; - rgb->green = 206; - rgb->blue = 250; - return; - } - if(strcmp(color, "steel blue") == 0) { - rgb->red = 70; - rgb->green = 130; - rgb->blue = 180; - return; - } - if(strcmp(color, "SteelBlue") == 0) { - rgb->red = 70; - rgb->green = 130; - rgb->blue = 180; - return; - } - if(strcmp(color, "light steel blue") == 0) { - rgb->red = 176; - rgb->green = 196; - rgb->blue = 222; - return; - } - if(strcmp(color, "LightSteelBlue") == 0) { - rgb->red = 176; - rgb->green = 196; - rgb->blue = 222; - return; - } - if(strcmp(color, "light blue") == 0) { - rgb->red = 173; - rgb->green = 216; - rgb->blue = 230; - return; - } - if(strcmp(color, "LightBlue") == 0) { - rgb->red = 173; - rgb->green = 216; - rgb->blue = 230; - return; - } - if(strcmp(color, "powder blue") == 0) { - rgb->red = 176; - rgb->green = 224; - rgb->blue = 230; - return; - } - if(strcmp(color, "PowderBlue") == 0) { - rgb->red = 176; - rgb->green = 224; - rgb->blue = 230; - return; - } - if(strcmp(color, "pale turquoise") == 0) { - rgb->red = 175; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "PaleTurquoise") == 0) { - rgb->red = 175; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "dark turquoise") == 0) { - rgb->red = 0; - rgb->green = 206; - rgb->blue = 209; - return; - } - if(strcmp(color, "DarkTurquoise") == 0) { - rgb->red = 0; - rgb->green = 206; - rgb->blue = 209; - return; - } - if(strcmp(color, "medium turquoise") == 0) { - rgb->red = 72; - rgb->green = 209; - rgb->blue = 204; - return; - } - if(strcmp(color, "MediumTurquoise") == 0) { - rgb->red = 72; - rgb->green = 209; - rgb->blue = 204; - return; - } - if(strcmp(color, "turquoise") == 0) { - rgb->red = 64; - rgb->green = 224; - rgb->blue = 208; - return; - } - if(strcmp(color, "cyan") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "aqua") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "light cyan") == 0) { - rgb->red = 224; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightCyan") == 0) { - rgb->red = 224; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "cadet blue") == 0) { - rgb->red = 95; - rgb->green = 158; - rgb->blue = 160; - return; - } - if(strcmp(color, "CadetBlue") == 0) { - rgb->red = 95; - rgb->green = 158; - rgb->blue = 160; - return; - } - if(strcmp(color, "medium aquamarine") == 0) { - rgb->red = 102; - rgb->green = 205; - rgb->blue = 170; - return; - } - if(strcmp(color, "MediumAquamarine") == 0) { - rgb->red = 102; - rgb->green = 205; - rgb->blue = 170; - return; - } - if(strcmp(color, "aquamarine") == 0) { - rgb->red = 127; - rgb->green = 255; - rgb->blue = 212; - return; - } - if(strcmp(color, "dark green") == 0) { - rgb->red = 0; - rgb->green = 100; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkGreen") == 0) { - rgb->red = 0; - rgb->green = 100; - rgb->blue = 0; - return; - } - if(strcmp(color, "dark olive green") == 0) { - rgb->red = 85; - rgb->green = 107; - rgb->blue = 47; - return; - } - if(strcmp(color, "DarkOliveGreen") == 0) { - rgb->red = 85; - rgb->green = 107; - rgb->blue = 47; - return; - } - if(strcmp(color, "dark sea green") == 0) { - rgb->red = 143; - rgb->green = 188; - rgb->blue = 143; - return; - } - if(strcmp(color, "DarkSeaGreen") == 0) { - rgb->red = 143; - rgb->green = 188; - rgb->blue = 143; - return; - } - if(strcmp(color, "sea green") == 0) { - rgb->red = 46; - rgb->green = 139; - rgb->blue = 87; - return; - } - if(strcmp(color, "SeaGreen") == 0) { - rgb->red = 46; - rgb->green = 139; - rgb->blue = 87; - return; - } - if(strcmp(color, "medium sea green") == 0) { - rgb->red = 60; - rgb->green = 179; - rgb->blue = 113; - return; - } - if(strcmp(color, "MediumSeaGreen") == 0) { - rgb->red = 60; - rgb->green = 179; - rgb->blue = 113; - return; - } - if(strcmp(color, "light sea green") == 0) { - rgb->red = 32; - rgb->green = 178; - rgb->blue = 170; - return; - } - if(strcmp(color, "LightSeaGreen") == 0) { - rgb->red = 32; - rgb->green = 178; - rgb->blue = 170; - return; - } - if(strcmp(color, "pale green") == 0) { - rgb->red = 152; - rgb->green = 251; - rgb->blue = 152; - return; - } - if(strcmp(color, "PaleGreen") == 0) { - rgb->red = 152; - rgb->green = 251; - rgb->blue = 152; - return; - } - if(strcmp(color, "spring green") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 127; - return; - } - if(strcmp(color, "SpringGreen") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 127; - return; - } - if(strcmp(color, "lawn green") == 0) { - rgb->red = 124; - rgb->green = 252; - rgb->blue = 0; - return; - } - if(strcmp(color, "LawnGreen") == 0) { - rgb->red = 124; - rgb->green = 252; - rgb->blue = 0; - return; - } - if(strcmp(color, "green") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "lime") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "x11 green") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "X11Green") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "web green") == 0) { - rgb->red = 0; - rgb->green = 128; - rgb->blue = 0; - return; - } - if(strcmp(color, "WebGreen") == 0) { - rgb->red = 0; - rgb->green = 128; - rgb->blue = 0; - return; - } - if(strcmp(color, "chartreuse") == 0) { - rgb->red = 127; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "medium spring green") == 0) { - rgb->red = 0; - rgb->green = 250; - rgb->blue = 154; - return; - } - if(strcmp(color, "MediumSpringGreen") == 0) { - rgb->red = 0; - rgb->green = 250; - rgb->blue = 154; - return; - } - if(strcmp(color, "green yellow") == 0) { - rgb->red = 173; - rgb->green = 255; - rgb->blue = 47; - return; - } - if(strcmp(color, "GreenYellow") == 0) { - rgb->red = 173; - rgb->green = 255; - rgb->blue = 47; - return; - } - if(strcmp(color, "lime green") == 0) { - rgb->red = 50; - rgb->green = 205; - rgb->blue = 50; - return; - } - if(strcmp(color, "LimeGreen") == 0) { - rgb->red = 50; - rgb->green = 205; - rgb->blue = 50; - return; - } - if(strcmp(color, "yellow green") == 0) { - rgb->red = 154; - rgb->green = 205; - rgb->blue = 50; - return; - } - if(strcmp(color, "YellowGreen") == 0) { - rgb->red = 154; - rgb->green = 205; - rgb->blue = 50; - return; - } - if(strcmp(color, "forest green") == 0) { - rgb->red = 34; - rgb->green = 139; - rgb->blue = 34; - return; - } - if(strcmp(color, "ForestGreen") == 0) { - rgb->red = 34; - rgb->green = 139; - rgb->blue = 34; - return; - } - if(strcmp(color, "olive drab") == 0) { - rgb->red = 107; - rgb->green = 142; - rgb->blue = 35; - return; - } - if(strcmp(color, "OliveDrab") == 0) { - rgb->red = 107; - rgb->green = 142; - rgb->blue = 35; - return; - } - if(strcmp(color, "dark khaki") == 0) { - rgb->red = 189; - rgb->green = 183; - rgb->blue = 107; - return; - } - if(strcmp(color, "DarkKhaki") == 0) { - rgb->red = 189; - rgb->green = 183; - rgb->blue = 107; - return; - } - if(strcmp(color, "khaki") == 0) { - rgb->red = 240; - rgb->green = 230; - rgb->blue = 140; - return; - } - if(strcmp(color, "pale goldenrod") == 0) { - rgb->red = 238; - rgb->green = 232; - rgb->blue = 170; - return; - } - if(strcmp(color, "PaleGoldenrod") == 0) { - rgb->red = 238; - rgb->green = 232; - rgb->blue = 170; - return; - } - if(strcmp(color, "light goldenrod yellow") == 0) { - rgb->red = 250; - rgb->green = 250; - rgb->blue = 210; - return; - } - if(strcmp(color, "LightGoldenrodYellow") == 0) { - rgb->red = 250; - rgb->green = 250; - rgb->blue = 210; - return; - } - if(strcmp(color, "light yellow") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 224; - return; - } - if(strcmp(color, "LightYellow") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 224; - return; - } - if(strcmp(color, "yellow") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "gold") == 0) { - rgb->red = 255; - rgb->green = 215; - rgb->blue = 0; - return; - } - if(strcmp(color, "light goldenrod") == 0) { - rgb->red = 238; - rgb->green = 221; - rgb->blue = 130; - return; - } - if(strcmp(color, "LightGoldenrod") == 0) { - rgb->red = 238; - rgb->green = 221; - rgb->blue = 130; - return; - } - if(strcmp(color, "goldenrod") == 0) { - rgb->red = 218; - rgb->green = 165; - rgb->blue = 32; - return; - } - if(strcmp(color, "dark goldenrod") == 0) { - rgb->red = 184; - rgb->green = 134; - rgb->blue = 11; - return; - } - if(strcmp(color, "DarkGoldenrod") == 0) { - rgb->red = 184; - rgb->green = 134; - rgb->blue = 11; - return; - } - if(strcmp(color, "rosy brown") == 0) { - rgb->red = 188; - rgb->green = 143; - rgb->blue = 143; - return; - } - if(strcmp(color, "RosyBrown") == 0) { - rgb->red = 188; - rgb->green = 143; - rgb->blue = 143; - return; - } - if(strcmp(color, "indian red") == 0) { - rgb->red = 205; - rgb->green = 92; - rgb->blue = 92; - return; - } - if(strcmp(color, "IndianRed") == 0) { - rgb->red = 205; - rgb->green = 92; - rgb->blue = 92; - return; - } - if(strcmp(color, "saddle brown") == 0) { - rgb->red = 139; - rgb->green = 69; - rgb->blue = 19; - return; - } - if(strcmp(color, "SaddleBrown") == 0) { - rgb->red = 139; - rgb->green = 69; - rgb->blue = 19; - return; - } - if(strcmp(color, "sienna") == 0) { - rgb->red = 160; - rgb->green = 82; - rgb->blue = 45; - return; - } - if(strcmp(color, "peru") == 0) { - rgb->red = 205; - rgb->green = 133; - rgb->blue = 63; - return; - } - if(strcmp(color, "burlywood") == 0) { - rgb->red = 222; - rgb->green = 184; - rgb->blue = 135; - return; - } - if(strcmp(color, "beige") == 0) { - rgb->red = 245; - rgb->green = 245; - rgb->blue = 220; - return; - } - if(strcmp(color, "wheat") == 0) { - rgb->red = 245; - rgb->green = 222; - rgb->blue = 179; - return; - } - if(strcmp(color, "sandy brown") == 0) { - rgb->red = 244; - rgb->green = 164; - rgb->blue = 96; - return; - } - if(strcmp(color, "SandyBrown") == 0) { - rgb->red = 244; - rgb->green = 164; - rgb->blue = 96; - return; - } - if(strcmp(color, "tan") == 0) { - rgb->red = 210; - rgb->green = 180; - rgb->blue = 140; - return; - } - if(strcmp(color, "chocolate") == 0) { - rgb->red = 210; - rgb->green = 105; - rgb->blue = 30; - return; - } - if(strcmp(color, "firebrick") == 0) { - rgb->red = 178; - rgb->green = 34; - rgb->blue = 34; - return; - } - if(strcmp(color, "brown") == 0) { - rgb->red = 165; - rgb->green = 42; - rgb->blue = 42; - return; - } - if(strcmp(color, "dark salmon") == 0) { - rgb->red = 233; - rgb->green = 150; - rgb->blue = 122; - return; - } - if(strcmp(color, "DarkSalmon") == 0) { - rgb->red = 233; - rgb->green = 150; - rgb->blue = 122; - return; - } - if(strcmp(color, "salmon") == 0) { - rgb->red = 250; - rgb->green = 128; - rgb->blue = 114; - return; - } - if(strcmp(color, "light salmon") == 0) { - rgb->red = 255; - rgb->green = 160; - rgb->blue = 122; - return; - } - if(strcmp(color, "LightSalmon") == 0) { - rgb->red = 255; - rgb->green = 160; - rgb->blue = 122; - return; - } - if(strcmp(color, "orange") == 0) { - rgb->red = 255; - rgb->green = 165; - rgb->blue = 0; - return; - } - if(strcmp(color, "dark orange") == 0) { - rgb->red = 255; - rgb->green = 140; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkOrange") == 0) { - rgb->red = 255; - rgb->green = 140; - rgb->blue = 0; - return; - } - if(strcmp(color, "coral") == 0) { - rgb->red = 255; - rgb->green = 127; - rgb->blue = 80; - return; - } - if(strcmp(color, "light coral") == 0) { - rgb->red = 240; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "LightCoral") == 0) { - rgb->red = 240; - rgb->green = 128; - rgb->blue = 128; - return; - } - if(strcmp(color, "tomato") == 0) { - rgb->red = 255; - rgb->green = 99; - rgb->blue = 71; - return; - } - if(strcmp(color, "orange red") == 0) { - rgb->red = 255; - rgb->green = 69; - rgb->blue = 0; - return; - } - if(strcmp(color, "OrangeRed") == 0) { - rgb->red = 255; - rgb->green = 69; - rgb->blue = 0; - return; - } - if(strcmp(color, "red") == 0) { - rgb->red = 255; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "hot pink") == 0) { - rgb->red = 255; - rgb->green = 105; - rgb->blue = 180; - return; - } - if(strcmp(color, "HotPink") == 0) { - rgb->red = 255; - rgb->green = 105; - rgb->blue = 180; - return; - } - if(strcmp(color, "deep pink") == 0) { - rgb->red = 255; - rgb->green = 20; - rgb->blue = 147; - return; - } - if(strcmp(color, "DeepPink") == 0) { - rgb->red = 255; - rgb->green = 20; - rgb->blue = 147; - return; - } - if(strcmp(color, "pink") == 0) { - rgb->red = 255; - rgb->green = 192; - rgb->blue = 203; - return; - } - if(strcmp(color, "light pink") == 0) { - rgb->red = 255; - rgb->green = 182; - rgb->blue = 193; - return; - } - if(strcmp(color, "LightPink") == 0) { - rgb->red = 255; - rgb->green = 182; - rgb->blue = 193; - return; - } - if(strcmp(color, "pale violet red") == 0) { - rgb->red = 219; - rgb->green = 112; - rgb->blue = 147; - return; - } - if(strcmp(color, "PaleVioletRed") == 0) { - rgb->red = 219; - rgb->green = 112; - rgb->blue = 147; - return; - } - if(strcmp(color, "maroon") == 0) { - rgb->red = 176; - rgb->green = 48; - rgb->blue = 96; - return; - } - if(strcmp(color, "x11 maroon") == 0) { - rgb->red = 176; - rgb->green = 48; - rgb->blue = 96; - return; - } - if(strcmp(color, "X11Maroon") == 0) { - rgb->red = 176; - rgb->green = 48; - rgb->blue = 96; - return; - } - if(strcmp(color, "web maroon") == 0) { - rgb->red = 128; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "WebMaroon") == 0) { - rgb->red = 128; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "medium violet red") == 0) { - rgb->red = 199; - rgb->green = 21; - rgb->blue = 133; - return; - } - if(strcmp(color, "MediumVioletRed") == 0) { - rgb->red = 199; - rgb->green = 21; - rgb->blue = 133; - return; - } - if(strcmp(color, "violet red") == 0) { - rgb->red = 208; - rgb->green = 32; - rgb->blue = 144; - return; - } - if(strcmp(color, "VioletRed") == 0) { - rgb->red = 208; - rgb->green = 32; - rgb->blue = 144; - return; - } - if(strcmp(color, "magenta") == 0) { - rgb->red = 255; - rgb->green = 0; - rgb->blue = 255; - return; - } - if(strcmp(color, "fuchsia") == 0) { - rgb->red = 255; - rgb->green = 0; - rgb->blue = 255; - return; - } - if(strcmp(color, "violet") == 0) { - rgb->red = 238; - rgb->green = 130; - rgb->blue = 238; - return; - } - if(strcmp(color, "plum") == 0) { - rgb->red = 221; - rgb->green = 160; - rgb->blue = 221; - return; - } - if(strcmp(color, "orchid") == 0) { - rgb->red = 218; - rgb->green = 112; - rgb->blue = 214; - return; - } - if(strcmp(color, "medium orchid") == 0) { - rgb->red = 186; - rgb->green = 85; - rgb->blue = 211; - return; - } - if(strcmp(color, "MediumOrchid") == 0) { - rgb->red = 186; - rgb->green = 85; - rgb->blue = 211; - return; - } - if(strcmp(color, "dark orchid") == 0) { - rgb->red = 153; - rgb->green = 50; - rgb->blue = 204; - return; - } - if(strcmp(color, "DarkOrchid") == 0) { - rgb->red = 153; - rgb->green = 50; - rgb->blue = 204; - return; - } - if(strcmp(color, "dark violet") == 0) { - rgb->red = 148; - rgb->green = 0; - rgb->blue = 211; - return; - } - if(strcmp(color, "DarkViolet") == 0) { - rgb->red = 148; - rgb->green = 0; - rgb->blue = 211; - return; - } - if(strcmp(color, "blue violet") == 0) { - rgb->red = 138; - rgb->green = 43; - rgb->blue = 226; - return; - } - if(strcmp(color, "BlueViolet") == 0) { - rgb->red = 138; - rgb->green = 43; - rgb->blue = 226; - return; - } - if(strcmp(color, "purple") == 0) { - rgb->red = 160; - rgb->green = 32; - rgb->blue = 240; - return; - } - if(strcmp(color, "x11 purple") == 0) { - rgb->red = 160; - rgb->green = 32; - rgb->blue = 240; - return; - } - if(strcmp(color, "X11Purple") == 0) { - rgb->red = 160; - rgb->green = 32; - rgb->blue = 240; - return; - } - if(strcmp(color, "web purple") == 0) { - rgb->red = 128; - rgb->green = 0; - rgb->blue = 128; - return; - } - if(strcmp(color, "WebPurple") == 0) { - rgb->red = 128; - rgb->green = 0; - rgb->blue = 128; - return; - } - if(strcmp(color, "medium purple") == 0) { - rgb->red = 147; - rgb->green = 112; - rgb->blue = 219; - return; - } - if(strcmp(color, "MediumPurple") == 0) { - rgb->red = 147; - rgb->green = 112; - rgb->blue = 219; - return; - } - if(strcmp(color, "thistle") == 0) { - rgb->red = 216; - rgb->green = 191; - rgb->blue = 216; - return; - } - if(strcmp(color, "snow1") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 250; - return; - } - if(strcmp(color, "snow2") == 0) { - rgb->red = 238; - rgb->green = 233; - rgb->blue = 233; - return; - } - if(strcmp(color, "snow3") == 0) { - rgb->red = 205; - rgb->green = 201; - rgb->blue = 201; - return; - } - if(strcmp(color, "snow4") == 0) { - rgb->red = 139; - rgb->green = 137; - rgb->blue = 137; - return; - } - if(strcmp(color, "seashell1") == 0) { - rgb->red = 255; - rgb->green = 245; - rgb->blue = 238; - return; - } - if(strcmp(color, "seashell2") == 0) { - rgb->red = 238; - rgb->green = 229; - rgb->blue = 222; - return; - } - if(strcmp(color, "seashell3") == 0) { - rgb->red = 205; - rgb->green = 197; - rgb->blue = 191; - return; - } - if(strcmp(color, "seashell4") == 0) { - rgb->red = 139; - rgb->green = 134; - rgb->blue = 130; - return; - } - if(strcmp(color, "AntiqueWhite1") == 0) { - rgb->red = 255; - rgb->green = 239; - rgb->blue = 219; - return; - } - if(strcmp(color, "AntiqueWhite2") == 0) { - rgb->red = 238; - rgb->green = 223; - rgb->blue = 204; - return; - } - if(strcmp(color, "AntiqueWhite3") == 0) { - rgb->red = 205; - rgb->green = 192; - rgb->blue = 176; - return; - } - if(strcmp(color, "AntiqueWhite4") == 0) { - rgb->red = 139; - rgb->green = 131; - rgb->blue = 120; - return; - } - if(strcmp(color, "bisque1") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 196; - return; - } - if(strcmp(color, "bisque2") == 0) { - rgb->red = 238; - rgb->green = 213; - rgb->blue = 183; - return; - } - if(strcmp(color, "bisque3") == 0) { - rgb->red = 205; - rgb->green = 183; - rgb->blue = 158; - return; - } - if(strcmp(color, "bisque4") == 0) { - rgb->red = 139; - rgb->green = 125; - rgb->blue = 107; - return; - } - if(strcmp(color, "PeachPuff1") == 0) { - rgb->red = 255; - rgb->green = 218; - rgb->blue = 185; - return; - } - if(strcmp(color, "PeachPuff2") == 0) { - rgb->red = 238; - rgb->green = 203; - rgb->blue = 173; - return; - } - if(strcmp(color, "PeachPuff3") == 0) { - rgb->red = 205; - rgb->green = 175; - rgb->blue = 149; - return; - } - if(strcmp(color, "PeachPuff4") == 0) { - rgb->red = 139; - rgb->green = 119; - rgb->blue = 101; - return; - } - if(strcmp(color, "NavajoWhite1") == 0) { - rgb->red = 255; - rgb->green = 222; - rgb->blue = 173; - return; - } - if(strcmp(color, "NavajoWhite2") == 0) { - rgb->red = 238; - rgb->green = 207; - rgb->blue = 161; - return; - } - if(strcmp(color, "NavajoWhite3") == 0) { - rgb->red = 205; - rgb->green = 179; - rgb->blue = 139; - return; - } - if(strcmp(color, "NavajoWhite4") == 0) { - rgb->red = 139; - rgb->green = 121; - rgb->blue = 94; - return; - } - if(strcmp(color, "LemonChiffon1") == 0) { - rgb->red = 255; - rgb->green = 250; - rgb->blue = 205; - return; - } - if(strcmp(color, "LemonChiffon2") == 0) { - rgb->red = 238; - rgb->green = 233; - rgb->blue = 191; - return; - } - if(strcmp(color, "LemonChiffon3") == 0) { - rgb->red = 205; - rgb->green = 201; - rgb->blue = 165; - return; - } - if(strcmp(color, "LemonChiffon4") == 0) { - rgb->red = 139; - rgb->green = 137; - rgb->blue = 112; - return; - } - if(strcmp(color, "cornsilk1") == 0) { - rgb->red = 255; - rgb->green = 248; - rgb->blue = 220; - return; - } - if(strcmp(color, "cornsilk2") == 0) { - rgb->red = 238; - rgb->green = 232; - rgb->blue = 205; - return; - } - if(strcmp(color, "cornsilk3") == 0) { - rgb->red = 205; - rgb->green = 200; - rgb->blue = 177; - return; - } - if(strcmp(color, "cornsilk4") == 0) { - rgb->red = 139; - rgb->green = 136; - rgb->blue = 120; - return; - } - if(strcmp(color, "ivory1") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 240; - return; - } - if(strcmp(color, "ivory2") == 0) { - rgb->red = 238; - rgb->green = 238; - rgb->blue = 224; - return; - } - if(strcmp(color, "ivory3") == 0) { - rgb->red = 205; - rgb->green = 205; - rgb->blue = 193; - return; - } - if(strcmp(color, "ivory4") == 0) { - rgb->red = 139; - rgb->green = 139; - rgb->blue = 131; - return; - } - if(strcmp(color, "honeydew1") == 0) { - rgb->red = 240; - rgb->green = 255; - rgb->blue = 240; - return; - } - if(strcmp(color, "honeydew2") == 0) { - rgb->red = 224; - rgb->green = 238; - rgb->blue = 224; - return; - } - if(strcmp(color, "honeydew3") == 0) { - rgb->red = 193; - rgb->green = 205; - rgb->blue = 193; - return; - } - if(strcmp(color, "honeydew4") == 0) { - rgb->red = 131; - rgb->green = 139; - rgb->blue = 131; - return; - } - if(strcmp(color, "LavenderBlush1") == 0) { - rgb->red = 255; - rgb->green = 240; - rgb->blue = 245; - return; - } - if(strcmp(color, "LavenderBlush2") == 0) { - rgb->red = 238; - rgb->green = 224; - rgb->blue = 229; - return; - } - if(strcmp(color, "LavenderBlush3") == 0) { - rgb->red = 205; - rgb->green = 193; - rgb->blue = 197; - return; - } - if(strcmp(color, "LavenderBlush4") == 0) { - rgb->red = 139; - rgb->green = 131; - rgb->blue = 134; - return; - } - if(strcmp(color, "MistyRose1") == 0) { - rgb->red = 255; - rgb->green = 228; - rgb->blue = 225; - return; - } - if(strcmp(color, "MistyRose2") == 0) { - rgb->red = 238; - rgb->green = 213; - rgb->blue = 210; - return; - } - if(strcmp(color, "MistyRose3") == 0) { - rgb->red = 205; - rgb->green = 183; - rgb->blue = 181; - return; - } - if(strcmp(color, "MistyRose4") == 0) { - rgb->red = 139; - rgb->green = 125; - rgb->blue = 123; - return; - } - if(strcmp(color, "azure1") == 0) { - rgb->red = 240; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "azure2") == 0) { - rgb->red = 224; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "azure3") == 0) { - rgb->red = 193; - rgb->green = 205; - rgb->blue = 205; - return; - } - if(strcmp(color, "azure4") == 0) { - rgb->red = 131; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "SlateBlue1") == 0) { - rgb->red = 131; - rgb->green = 111; - rgb->blue = 255; - return; - } - if(strcmp(color, "SlateBlue2") == 0) { - rgb->red = 122; - rgb->green = 103; - rgb->blue = 238; - return; - } - if(strcmp(color, "SlateBlue3") == 0) { - rgb->red = 105; - rgb->green = 89; - rgb->blue = 205; - return; - } - if(strcmp(color, "SlateBlue4") == 0) { - rgb->red = 71; - rgb->green = 60; - rgb->blue = 139; - return; - } - if(strcmp(color, "RoyalBlue1") == 0) { - rgb->red = 72; - rgb->green = 118; - rgb->blue = 255; - return; - } - if(strcmp(color, "RoyalBlue2") == 0) { - rgb->red = 67; - rgb->green = 110; - rgb->blue = 238; - return; - } - if(strcmp(color, "RoyalBlue3") == 0) { - rgb->red = 58; - rgb->green = 95; - rgb->blue = 205; - return; - } - if(strcmp(color, "RoyalBlue4") == 0) { - rgb->red = 39; - rgb->green = 64; - rgb->blue = 139; - return; - } - if(strcmp(color, "blue1") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 255; - return; - } - if(strcmp(color, "blue2") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 238; - return; - } - if(strcmp(color, "blue3") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 205; - return; - } - if(strcmp(color, "blue4") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "DodgerBlue1") == 0) { - rgb->red = 30; - rgb->green = 144; - rgb->blue = 255; - return; - } - if(strcmp(color, "DodgerBlue2") == 0) { - rgb->red = 28; - rgb->green = 134; - rgb->blue = 238; - return; - } - if(strcmp(color, "DodgerBlue3") == 0) { - rgb->red = 24; - rgb->green = 116; - rgb->blue = 205; - return; - } - if(strcmp(color, "DodgerBlue4") == 0) { - rgb->red = 16; - rgb->green = 78; - rgb->blue = 139; - return; - } - if(strcmp(color, "SteelBlue1") == 0) { - rgb->red = 99; - rgb->green = 184; - rgb->blue = 255; - return; - } - if(strcmp(color, "SteelBlue2") == 0) { - rgb->red = 92; - rgb->green = 172; - rgb->blue = 238; - return; - } - if(strcmp(color, "SteelBlue3") == 0) { - rgb->red = 79; - rgb->green = 148; - rgb->blue = 205; - return; - } - if(strcmp(color, "SteelBlue4") == 0) { - rgb->red = 54; - rgb->green = 100; - rgb->blue = 139; - return; - } - if(strcmp(color, "DeepSkyBlue1") == 0) { - rgb->red = 0; - rgb->green = 191; - rgb->blue = 255; - return; - } - if(strcmp(color, "DeepSkyBlue2") == 0) { - rgb->red = 0; - rgb->green = 178; - rgb->blue = 238; - return; - } - if(strcmp(color, "DeepSkyBlue3") == 0) { - rgb->red = 0; - rgb->green = 154; - rgb->blue = 205; - return; - } - if(strcmp(color, "DeepSkyBlue4") == 0) { - rgb->red = 0; - rgb->green = 104; - rgb->blue = 139; - return; - } - if(strcmp(color, "SkyBlue1") == 0) { - rgb->red = 135; - rgb->green = 206; - rgb->blue = 255; - return; - } - if(strcmp(color, "SkyBlue2") == 0) { - rgb->red = 126; - rgb->green = 192; - rgb->blue = 238; - return; - } - if(strcmp(color, "SkyBlue3") == 0) { - rgb->red = 108; - rgb->green = 166; - rgb->blue = 205; - return; - } - if(strcmp(color, "SkyBlue4") == 0) { - rgb->red = 74; - rgb->green = 112; - rgb->blue = 139; - return; - } - if(strcmp(color, "LightSkyBlue1") == 0) { - rgb->red = 176; - rgb->green = 226; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightSkyBlue2") == 0) { - rgb->red = 164; - rgb->green = 211; - rgb->blue = 238; - return; - } - if(strcmp(color, "LightSkyBlue3") == 0) { - rgb->red = 141; - rgb->green = 182; - rgb->blue = 205; - return; - } - if(strcmp(color, "LightSkyBlue4") == 0) { - rgb->red = 96; - rgb->green = 123; - rgb->blue = 139; - return; - } - if(strcmp(color, "SlateGray1") == 0) { - rgb->red = 198; - rgb->green = 226; - rgb->blue = 255; - return; - } - if(strcmp(color, "SlateGray2") == 0) { - rgb->red = 185; - rgb->green = 211; - rgb->blue = 238; - return; - } - if(strcmp(color, "SlateGray3") == 0) { - rgb->red = 159; - rgb->green = 182; - rgb->blue = 205; - return; - } - if(strcmp(color, "SlateGray4") == 0) { - rgb->red = 108; - rgb->green = 123; - rgb->blue = 139; - return; - } - if(strcmp(color, "LightSteelBlue1") == 0) { - rgb->red = 202; - rgb->green = 225; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightSteelBlue2") == 0) { - rgb->red = 188; - rgb->green = 210; - rgb->blue = 238; - return; - } - if(strcmp(color, "LightSteelBlue3") == 0) { - rgb->red = 162; - rgb->green = 181; - rgb->blue = 205; - return; - } - if(strcmp(color, "LightSteelBlue4") == 0) { - rgb->red = 110; - rgb->green = 123; - rgb->blue = 139; - return; - } - if(strcmp(color, "LightBlue1") == 0) { - rgb->red = 191; - rgb->green = 239; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightBlue2") == 0) { - rgb->red = 178; - rgb->green = 223; - rgb->blue = 238; - return; - } - if(strcmp(color, "LightBlue3") == 0) { - rgb->red = 154; - rgb->green = 192; - rgb->blue = 205; - return; - } - if(strcmp(color, "LightBlue4") == 0) { - rgb->red = 104; - rgb->green = 131; - rgb->blue = 139; - return; - } - if(strcmp(color, "LightCyan1") == 0) { - rgb->red = 224; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "LightCyan2") == 0) { - rgb->red = 209; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "LightCyan3") == 0) { - rgb->red = 180; - rgb->green = 205; - rgb->blue = 205; - return; - } - if(strcmp(color, "LightCyan4") == 0) { - rgb->red = 122; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "PaleTurquoise1") == 0) { - rgb->red = 187; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "PaleTurquoise2") == 0) { - rgb->red = 174; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "PaleTurquoise3") == 0) { - rgb->red = 150; - rgb->green = 205; - rgb->blue = 205; - return; - } - if(strcmp(color, "PaleTurquoise4") == 0) { - rgb->red = 102; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "CadetBlue1") == 0) { - rgb->red = 152; - rgb->green = 245; - rgb->blue = 255; - return; - } - if(strcmp(color, "CadetBlue2") == 0) { - rgb->red = 142; - rgb->green = 229; - rgb->blue = 238; - return; - } - if(strcmp(color, "CadetBlue3") == 0) { - rgb->red = 122; - rgb->green = 197; - rgb->blue = 205; - return; - } - if(strcmp(color, "CadetBlue4") == 0) { - rgb->red = 83; - rgb->green = 134; - rgb->blue = 139; - return; - } - if(strcmp(color, "turquoise1") == 0) { - rgb->red = 0; - rgb->green = 245; - rgb->blue = 255; - return; - } - if(strcmp(color, "turquoise2") == 0) { - rgb->red = 0; - rgb->green = 229; - rgb->blue = 238; - return; - } - if(strcmp(color, "turquoise3") == 0) { - rgb->red = 0; - rgb->green = 197; - rgb->blue = 205; - return; - } - if(strcmp(color, "turquoise4") == 0) { - rgb->red = 0; - rgb->green = 134; - rgb->blue = 139; - return; - } - if(strcmp(color, "cyan1") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "cyan2") == 0) { - rgb->red = 0; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "cyan3") == 0) { - rgb->red = 0; - rgb->green = 205; - rgb->blue = 205; - return; - } - if(strcmp(color, "cyan4") == 0) { - rgb->red = 0; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkSlateGray1") == 0) { - rgb->red = 151; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "DarkSlateGray2") == 0) { - rgb->red = 141; - rgb->green = 238; - rgb->blue = 238; - return; - } - if(strcmp(color, "DarkSlateGray3") == 0) { - rgb->red = 121; - rgb->green = 205; - rgb->blue = 205; - return; - } - if(strcmp(color, "DarkSlateGray4") == 0) { - rgb->red = 82; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "aquamarine1") == 0) { - rgb->red = 127; - rgb->green = 255; - rgb->blue = 212; - return; - } - if(strcmp(color, "aquamarine2") == 0) { - rgb->red = 118; - rgb->green = 238; - rgb->blue = 198; - return; - } - if(strcmp(color, "aquamarine3") == 0) { - rgb->red = 102; - rgb->green = 205; - rgb->blue = 170; - return; - } - if(strcmp(color, "aquamarine4") == 0) { - rgb->red = 69; - rgb->green = 139; - rgb->blue = 116; - return; - } - if(strcmp(color, "DarkSeaGreen1") == 0) { - rgb->red = 193; - rgb->green = 255; - rgb->blue = 193; - return; - } - if(strcmp(color, "DarkSeaGreen2") == 0) { - rgb->red = 180; - rgb->green = 238; - rgb->blue = 180; - return; - } - if(strcmp(color, "DarkSeaGreen3") == 0) { - rgb->red = 155; - rgb->green = 205; - rgb->blue = 155; - return; - } - if(strcmp(color, "DarkSeaGreen4") == 0) { - rgb->red = 105; - rgb->green = 139; - rgb->blue = 105; - return; - } - if(strcmp(color, "SeaGreen1") == 0) { - rgb->red = 84; - rgb->green = 255; - rgb->blue = 159; - return; - } - if(strcmp(color, "SeaGreen2") == 0) { - rgb->red = 78; - rgb->green = 238; - rgb->blue = 148; - return; - } - if(strcmp(color, "SeaGreen3") == 0) { - rgb->red = 67; - rgb->green = 205; - rgb->blue = 128; - return; - } - if(strcmp(color, "SeaGreen4") == 0) { - rgb->red = 46; - rgb->green = 139; - rgb->blue = 87; - return; - } - if(strcmp(color, "PaleGreen1") == 0) { - rgb->red = 154; - rgb->green = 255; - rgb->blue = 154; - return; - } - if(strcmp(color, "PaleGreen2") == 0) { - rgb->red = 144; - rgb->green = 238; - rgb->blue = 144; - return; - } - if(strcmp(color, "PaleGreen3") == 0) { - rgb->red = 124; - rgb->green = 205; - rgb->blue = 124; - return; - } - if(strcmp(color, "PaleGreen4") == 0) { - rgb->red = 84; - rgb->green = 139; - rgb->blue = 84; - return; - } - if(strcmp(color, "SpringGreen1") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 127; - return; - } - if(strcmp(color, "SpringGreen2") == 0) { - rgb->red = 0; - rgb->green = 238; - rgb->blue = 118; - return; - } - if(strcmp(color, "SpringGreen3") == 0) { - rgb->red = 0; - rgb->green = 205; - rgb->blue = 102; - return; - } - if(strcmp(color, "SpringGreen4") == 0) { - rgb->red = 0; - rgb->green = 139; - rgb->blue = 69; - return; - } - if(strcmp(color, "green1") == 0) { - rgb->red = 0; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "green2") == 0) { - rgb->red = 0; - rgb->green = 238; - rgb->blue = 0; - return; - } - if(strcmp(color, "green3") == 0) { - rgb->red = 0; - rgb->green = 205; - rgb->blue = 0; - return; - } - if(strcmp(color, "green4") == 0) { - rgb->red = 0; - rgb->green = 139; - rgb->blue = 0; - return; - } - if(strcmp(color, "chartreuse1") == 0) { - rgb->red = 127; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "chartreuse2") == 0) { - rgb->red = 118; - rgb->green = 238; - rgb->blue = 0; - return; - } - if(strcmp(color, "chartreuse3") == 0) { - rgb->red = 102; - rgb->green = 205; - rgb->blue = 0; - return; - } - if(strcmp(color, "chartreuse4") == 0) { - rgb->red = 69; - rgb->green = 139; - rgb->blue = 0; - return; - } - if(strcmp(color, "OliveDrab1") == 0) { - rgb->red = 192; - rgb->green = 255; - rgb->blue = 62; - return; - } - if(strcmp(color, "OliveDrab2") == 0) { - rgb->red = 179; - rgb->green = 238; - rgb->blue = 58; - return; - } - if(strcmp(color, "OliveDrab3") == 0) { - rgb->red = 154; - rgb->green = 205; - rgb->blue = 50; - return; - } - if(strcmp(color, "OliveDrab4") == 0) { - rgb->red = 105; - rgb->green = 139; - rgb->blue = 34; - return; - } - if(strcmp(color, "DarkOliveGreen1") == 0) { - rgb->red = 202; - rgb->green = 255; - rgb->blue = 112; - return; - } - if(strcmp(color, "DarkOliveGreen2") == 0) { - rgb->red = 188; - rgb->green = 238; - rgb->blue = 104; - return; - } - if(strcmp(color, "DarkOliveGreen3") == 0) { - rgb->red = 162; - rgb->green = 205; - rgb->blue = 90; - return; - } - if(strcmp(color, "DarkOliveGreen4") == 0) { - rgb->red = 110; - rgb->green = 139; - rgb->blue = 61; - return; - } - if(strcmp(color, "khaki1") == 0) { - rgb->red = 255; - rgb->green = 246; - rgb->blue = 143; - return; - } - if(strcmp(color, "khaki2") == 0) { - rgb->red = 238; - rgb->green = 230; - rgb->blue = 133; - return; - } - if(strcmp(color, "khaki3") == 0) { - rgb->red = 205; - rgb->green = 198; - rgb->blue = 115; - return; - } - if(strcmp(color, "khaki4") == 0) { - rgb->red = 139; - rgb->green = 134; - rgb->blue = 78; - return; - } - if(strcmp(color, "LightGoldenrod1") == 0) { - rgb->red = 255; - rgb->green = 236; - rgb->blue = 139; - return; - } - if(strcmp(color, "LightGoldenrod2") == 0) { - rgb->red = 238; - rgb->green = 220; - rgb->blue = 130; - return; - } - if(strcmp(color, "LightGoldenrod3") == 0) { - rgb->red = 205; - rgb->green = 190; - rgb->blue = 112; - return; - } - if(strcmp(color, "LightGoldenrod4") == 0) { - rgb->red = 139; - rgb->green = 129; - rgb->blue = 76; - return; - } - if(strcmp(color, "LightYellow1") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 224; - return; - } - if(strcmp(color, "LightYellow2") == 0) { - rgb->red = 238; - rgb->green = 238; - rgb->blue = 209; - return; - } - if(strcmp(color, "LightYellow3") == 0) { - rgb->red = 205; - rgb->green = 205; - rgb->blue = 180; - return; - } - if(strcmp(color, "LightYellow4") == 0) { - rgb->red = 139; - rgb->green = 139; - rgb->blue = 122; - return; - } - if(strcmp(color, "yellow1") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 0; - return; - } - if(strcmp(color, "yellow2") == 0) { - rgb->red = 238; - rgb->green = 238; - rgb->blue = 0; - return; - } - if(strcmp(color, "yellow3") == 0) { - rgb->red = 205; - rgb->green = 205; - rgb->blue = 0; - return; - } - if(strcmp(color, "yellow4") == 0) { - rgb->red = 139; - rgb->green = 139; - rgb->blue = 0; - return; - } - if(strcmp(color, "gold1") == 0) { - rgb->red = 255; - rgb->green = 215; - rgb->blue = 0; - return; - } - if(strcmp(color, "gold2") == 0) { - rgb->red = 238; - rgb->green = 201; - rgb->blue = 0; - return; - } - if(strcmp(color, "gold3") == 0) { - rgb->red = 205; - rgb->green = 173; - rgb->blue = 0; - return; - } - if(strcmp(color, "gold4") == 0) { - rgb->red = 139; - rgb->green = 117; - rgb->blue = 0; - return; - } - if(strcmp(color, "goldenrod1") == 0) { - rgb->red = 255; - rgb->green = 193; - rgb->blue = 37; - return; - } - if(strcmp(color, "goldenrod2") == 0) { - rgb->red = 238; - rgb->green = 180; - rgb->blue = 34; - return; - } - if(strcmp(color, "goldenrod3") == 0) { - rgb->red = 205; - rgb->green = 155; - rgb->blue = 29; - return; - } - if(strcmp(color, "goldenrod4") == 0) { - rgb->red = 139; - rgb->green = 105; - rgb->blue = 20; - return; - } - if(strcmp(color, "DarkGoldenrod1") == 0) { - rgb->red = 255; - rgb->green = 185; - rgb->blue = 15; - return; - } - if(strcmp(color, "DarkGoldenrod2") == 0) { - rgb->red = 238; - rgb->green = 173; - rgb->blue = 14; - return; - } - if(strcmp(color, "DarkGoldenrod3") == 0) { - rgb->red = 205; - rgb->green = 149; - rgb->blue = 12; - return; - } - if(strcmp(color, "DarkGoldenrod4") == 0) { - rgb->red = 139; - rgb->green = 101; - rgb->blue = 8; - return; - } - if(strcmp(color, "RosyBrown1") == 0) { - rgb->red = 255; - rgb->green = 193; - rgb->blue = 193; - return; - } - if(strcmp(color, "RosyBrown2") == 0) { - rgb->red = 238; - rgb->green = 180; - rgb->blue = 180; - return; - } - if(strcmp(color, "RosyBrown3") == 0) { - rgb->red = 205; - rgb->green = 155; - rgb->blue = 155; - return; - } - if(strcmp(color, "RosyBrown4") == 0) { - rgb->red = 139; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "IndianRed1") == 0) { - rgb->red = 255; - rgb->green = 106; - rgb->blue = 106; - return; - } - if(strcmp(color, "IndianRed2") == 0) { - rgb->red = 238; - rgb->green = 99; - rgb->blue = 99; - return; - } - if(strcmp(color, "IndianRed3") == 0) { - rgb->red = 205; - rgb->green = 85; - rgb->blue = 85; - return; - } - if(strcmp(color, "IndianRed4") == 0) { - rgb->red = 139; - rgb->green = 58; - rgb->blue = 58; - return; - } - if(strcmp(color, "sienna1") == 0) { - rgb->red = 255; - rgb->green = 130; - rgb->blue = 71; - return; - } - if(strcmp(color, "sienna2") == 0) { - rgb->red = 238; - rgb->green = 121; - rgb->blue = 66; - return; - } - if(strcmp(color, "sienna3") == 0) { - rgb->red = 205; - rgb->green = 104; - rgb->blue = 57; - return; - } - if(strcmp(color, "sienna4") == 0) { - rgb->red = 139; - rgb->green = 71; - rgb->blue = 38; - return; - } - if(strcmp(color, "burlywood1") == 0) { - rgb->red = 255; - rgb->green = 211; - rgb->blue = 155; - return; - } - if(strcmp(color, "burlywood2") == 0) { - rgb->red = 238; - rgb->green = 197; - rgb->blue = 145; - return; - } - if(strcmp(color, "burlywood3") == 0) { - rgb->red = 205; - rgb->green = 170; - rgb->blue = 125; - return; - } - if(strcmp(color, "burlywood4") == 0) { - rgb->red = 139; - rgb->green = 115; - rgb->blue = 85; - return; - } - if(strcmp(color, "wheat1") == 0) { - rgb->red = 255; - rgb->green = 231; - rgb->blue = 186; - return; - } - if(strcmp(color, "wheat2") == 0) { - rgb->red = 238; - rgb->green = 216; - rgb->blue = 174; - return; - } - if(strcmp(color, "wheat3") == 0) { - rgb->red = 205; - rgb->green = 186; - rgb->blue = 150; - return; - } - if(strcmp(color, "wheat4") == 0) { - rgb->red = 139; - rgb->green = 126; - rgb->blue = 102; - return; - } - if(strcmp(color, "tan1") == 0) { - rgb->red = 255; - rgb->green = 165; - rgb->blue = 79; - return; - } - if(strcmp(color, "tan2") == 0) { - rgb->red = 238; - rgb->green = 154; - rgb->blue = 73; - return; - } - if(strcmp(color, "tan3") == 0) { - rgb->red = 205; - rgb->green = 133; - rgb->blue = 63; - return; - } - if(strcmp(color, "tan4") == 0) { - rgb->red = 139; - rgb->green = 90; - rgb->blue = 43; - return; - } - if(strcmp(color, "chocolate1") == 0) { - rgb->red = 255; - rgb->green = 127; - rgb->blue = 36; - return; - } - if(strcmp(color, "chocolate2") == 0) { - rgb->red = 238; - rgb->green = 118; - rgb->blue = 33; - return; - } - if(strcmp(color, "chocolate3") == 0) { - rgb->red = 205; - rgb->green = 102; - rgb->blue = 29; - return; - } - if(strcmp(color, "chocolate4") == 0) { - rgb->red = 139; - rgb->green = 69; - rgb->blue = 19; - return; - } - if(strcmp(color, "firebrick1") == 0) { - rgb->red = 255; - rgb->green = 48; - rgb->blue = 48; - return; - } - if(strcmp(color, "firebrick2") == 0) { - rgb->red = 238; - rgb->green = 44; - rgb->blue = 44; - return; - } - if(strcmp(color, "firebrick3") == 0) { - rgb->red = 205; - rgb->green = 38; - rgb->blue = 38; - return; - } - if(strcmp(color, "firebrick4") == 0) { - rgb->red = 139; - rgb->green = 26; - rgb->blue = 26; - return; - } - if(strcmp(color, "brown1") == 0) { - rgb->red = 255; - rgb->green = 64; - rgb->blue = 64; - return; - } - if(strcmp(color, "brown2") == 0) { - rgb->red = 238; - rgb->green = 59; - rgb->blue = 59; - return; - } - if(strcmp(color, "brown3") == 0) { - rgb->red = 205; - rgb->green = 51; - rgb->blue = 51; - return; - } - if(strcmp(color, "brown4") == 0) { - rgb->red = 139; - rgb->green = 35; - rgb->blue = 35; - return; - } - if(strcmp(color, "salmon1") == 0) { - rgb->red = 255; - rgb->green = 140; - rgb->blue = 105; - return; - } - if(strcmp(color, "salmon2") == 0) { - rgb->red = 238; - rgb->green = 130; - rgb->blue = 98; - return; - } - if(strcmp(color, "salmon3") == 0) { - rgb->red = 205; - rgb->green = 112; - rgb->blue = 84; - return; - } - if(strcmp(color, "salmon4") == 0) { - rgb->red = 139; - rgb->green = 76; - rgb->blue = 57; - return; - } - if(strcmp(color, "LightSalmon1") == 0) { - rgb->red = 255; - rgb->green = 160; - rgb->blue = 122; - return; - } - if(strcmp(color, "LightSalmon2") == 0) { - rgb->red = 238; - rgb->green = 149; - rgb->blue = 114; - return; - } - if(strcmp(color, "LightSalmon3") == 0) { - rgb->red = 205; - rgb->green = 129; - rgb->blue = 98; - return; - } - if(strcmp(color, "LightSalmon4") == 0) { - rgb->red = 139; - rgb->green = 87; - rgb->blue = 66; - return; - } - if(strcmp(color, "orange1") == 0) { - rgb->red = 255; - rgb->green = 165; - rgb->blue = 0; - return; - } - if(strcmp(color, "orange2") == 0) { - rgb->red = 238; - rgb->green = 154; - rgb->blue = 0; - return; - } - if(strcmp(color, "orange3") == 0) { - rgb->red = 205; - rgb->green = 133; - rgb->blue = 0; - return; - } - if(strcmp(color, "orange4") == 0) { - rgb->red = 139; - rgb->green = 90; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkOrange1") == 0) { - rgb->red = 255; - rgb->green = 127; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkOrange2") == 0) { - rgb->red = 238; - rgb->green = 118; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkOrange3") == 0) { - rgb->red = 205; - rgb->green = 102; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkOrange4") == 0) { - rgb->red = 139; - rgb->green = 69; - rgb->blue = 0; - return; - } - if(strcmp(color, "coral1") == 0) { - rgb->red = 255; - rgb->green = 114; - rgb->blue = 86; - return; - } - if(strcmp(color, "coral2") == 0) { - rgb->red = 238; - rgb->green = 106; - rgb->blue = 80; - return; - } - if(strcmp(color, "coral3") == 0) { - rgb->red = 205; - rgb->green = 91; - rgb->blue = 69; - return; - } - if(strcmp(color, "coral4") == 0) { - rgb->red = 139; - rgb->green = 62; - rgb->blue = 47; - return; - } - if(strcmp(color, "tomato1") == 0) { - rgb->red = 255; - rgb->green = 99; - rgb->blue = 71; - return; - } - if(strcmp(color, "tomato2") == 0) { - rgb->red = 238; - rgb->green = 92; - rgb->blue = 66; - return; - } - if(strcmp(color, "tomato3") == 0) { - rgb->red = 205; - rgb->green = 79; - rgb->blue = 57; - return; - } - if(strcmp(color, "tomato4") == 0) { - rgb->red = 139; - rgb->green = 54; - rgb->blue = 38; - return; - } - if(strcmp(color, "OrangeRed1") == 0) { - rgb->red = 255; - rgb->green = 69; - rgb->blue = 0; - return; - } - if(strcmp(color, "OrangeRed2") == 0) { - rgb->red = 238; - rgb->green = 64; - rgb->blue = 0; - return; - } - if(strcmp(color, "OrangeRed3") == 0) { - rgb->red = 205; - rgb->green = 55; - rgb->blue = 0; - return; - } - if(strcmp(color, "OrangeRed4") == 0) { - rgb->red = 139; - rgb->green = 37; - rgb->blue = 0; - return; - } - if(strcmp(color, "red1") == 0) { - rgb->red = 255; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "red2") == 0) { - rgb->red = 238; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "red3") == 0) { - rgb->red = 205; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "red4") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "DeepPink1") == 0) { - rgb->red = 255; - rgb->green = 20; - rgb->blue = 147; - return; - } - if(strcmp(color, "DeepPink2") == 0) { - rgb->red = 238; - rgb->green = 18; - rgb->blue = 137; - return; - } - if(strcmp(color, "DeepPink3") == 0) { - rgb->red = 205; - rgb->green = 16; - rgb->blue = 118; - return; - } - if(strcmp(color, "DeepPink4") == 0) { - rgb->red = 139; - rgb->green = 10; - rgb->blue = 80; - return; - } - if(strcmp(color, "HotPink1") == 0) { - rgb->red = 255; - rgb->green = 110; - rgb->blue = 180; - return; - } - if(strcmp(color, "HotPink2") == 0) { - rgb->red = 238; - rgb->green = 106; - rgb->blue = 167; - return; - } - if(strcmp(color, "HotPink3") == 0) { - rgb->red = 205; - rgb->green = 96; - rgb->blue = 144; - return; - } - if(strcmp(color, "HotPink4") == 0) { - rgb->red = 139; - rgb->green = 58; - rgb->blue = 98; - return; - } - if(strcmp(color, "pink1") == 0) { - rgb->red = 255; - rgb->green = 181; - rgb->blue = 197; - return; - } - if(strcmp(color, "pink2") == 0) { - rgb->red = 238; - rgb->green = 169; - rgb->blue = 184; - return; - } - if(strcmp(color, "pink3") == 0) { - rgb->red = 205; - rgb->green = 145; - rgb->blue = 158; - return; - } - if(strcmp(color, "pink4") == 0) { - rgb->red = 139; - rgb->green = 99; - rgb->blue = 108; - return; - } - if(strcmp(color, "LightPink1") == 0) { - rgb->red = 255; - rgb->green = 174; - rgb->blue = 185; - return; - } - if(strcmp(color, "LightPink2") == 0) { - rgb->red = 238; - rgb->green = 162; - rgb->blue = 173; - return; - } - if(strcmp(color, "LightPink3") == 0) { - rgb->red = 205; - rgb->green = 140; - rgb->blue = 149; - return; - } - if(strcmp(color, "LightPink4") == 0) { - rgb->red = 139; - rgb->green = 95; - rgb->blue = 101; - return; - } - if(strcmp(color, "PaleVioletRed1") == 0) { - rgb->red = 255; - rgb->green = 130; - rgb->blue = 171; - return; - } - if(strcmp(color, "PaleVioletRed2") == 0) { - rgb->red = 238; - rgb->green = 121; - rgb->blue = 159; - return; - } - if(strcmp(color, "PaleVioletRed3") == 0) { - rgb->red = 205; - rgb->green = 104; - rgb->blue = 137; - return; - } - if(strcmp(color, "PaleVioletRed4") == 0) { - rgb->red = 139; - rgb->green = 71; - rgb->blue = 93; - return; - } - if(strcmp(color, "maroon1") == 0) { - rgb->red = 255; - rgb->green = 52; - rgb->blue = 179; - return; - } - if(strcmp(color, "maroon2") == 0) { - rgb->red = 238; - rgb->green = 48; - rgb->blue = 167; - return; - } - if(strcmp(color, "maroon3") == 0) { - rgb->red = 205; - rgb->green = 41; - rgb->blue = 144; - return; - } - if(strcmp(color, "maroon4") == 0) { - rgb->red = 139; - rgb->green = 28; - rgb->blue = 98; - return; - } - if(strcmp(color, "VioletRed1") == 0) { - rgb->red = 255; - rgb->green = 62; - rgb->blue = 150; - return; - } - if(strcmp(color, "VioletRed2") == 0) { - rgb->red = 238; - rgb->green = 58; - rgb->blue = 140; - return; - } - if(strcmp(color, "VioletRed3") == 0) { - rgb->red = 205; - rgb->green = 50; - rgb->blue = 120; - return; - } - if(strcmp(color, "VioletRed4") == 0) { - rgb->red = 139; - rgb->green = 34; - rgb->blue = 82; - return; - } - if(strcmp(color, "magenta1") == 0) { - rgb->red = 255; - rgb->green = 0; - rgb->blue = 255; - return; - } - if(strcmp(color, "magenta2") == 0) { - rgb->red = 238; - rgb->green = 0; - rgb->blue = 238; - return; - } - if(strcmp(color, "magenta3") == 0) { - rgb->red = 205; - rgb->green = 0; - rgb->blue = 205; - return; - } - if(strcmp(color, "magenta4") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "orchid1") == 0) { - rgb->red = 255; - rgb->green = 131; - rgb->blue = 250; - return; - } - if(strcmp(color, "orchid2") == 0) { - rgb->red = 238; - rgb->green = 122; - rgb->blue = 233; - return; - } - if(strcmp(color, "orchid3") == 0) { - rgb->red = 205; - rgb->green = 105; - rgb->blue = 201; - return; - } - if(strcmp(color, "orchid4") == 0) { - rgb->red = 139; - rgb->green = 71; - rgb->blue = 137; - return; - } - if(strcmp(color, "plum1") == 0) { - rgb->red = 255; - rgb->green = 187; - rgb->blue = 255; - return; - } - if(strcmp(color, "plum2") == 0) { - rgb->red = 238; - rgb->green = 174; - rgb->blue = 238; - return; - } - if(strcmp(color, "plum3") == 0) { - rgb->red = 205; - rgb->green = 150; - rgb->blue = 205; - return; - } - if(strcmp(color, "plum4") == 0) { - rgb->red = 139; - rgb->green = 102; - rgb->blue = 139; - return; - } - if(strcmp(color, "MediumOrchid1") == 0) { - rgb->red = 224; - rgb->green = 102; - rgb->blue = 255; - return; - } - if(strcmp(color, "MediumOrchid2") == 0) { - rgb->red = 209; - rgb->green = 95; - rgb->blue = 238; - return; - } - if(strcmp(color, "MediumOrchid3") == 0) { - rgb->red = 180; - rgb->green = 82; - rgb->blue = 205; - return; - } - if(strcmp(color, "MediumOrchid4") == 0) { - rgb->red = 122; - rgb->green = 55; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkOrchid1") == 0) { - rgb->red = 191; - rgb->green = 62; - rgb->blue = 255; - return; - } - if(strcmp(color, "DarkOrchid2") == 0) { - rgb->red = 178; - rgb->green = 58; - rgb->blue = 238; - return; - } - if(strcmp(color, "DarkOrchid3") == 0) { - rgb->red = 154; - rgb->green = 50; - rgb->blue = 205; - return; - } - if(strcmp(color, "DarkOrchid4") == 0) { - rgb->red = 104; - rgb->green = 34; - rgb->blue = 139; - return; - } - if(strcmp(color, "purple1") == 0) { - rgb->red = 155; - rgb->green = 48; - rgb->blue = 255; - return; - } - if(strcmp(color, "purple2") == 0) { - rgb->red = 145; - rgb->green = 44; - rgb->blue = 238; - return; - } - if(strcmp(color, "purple3") == 0) { - rgb->red = 125; - rgb->green = 38; - rgb->blue = 205; - return; - } - if(strcmp(color, "purple4") == 0) { - rgb->red = 85; - rgb->green = 26; - rgb->blue = 139; - return; - } - if(strcmp(color, "MediumPurple1") == 0) { - rgb->red = 171; - rgb->green = 130; - rgb->blue = 255; - return; - } - if(strcmp(color, "MediumPurple2") == 0) { - rgb->red = 159; - rgb->green = 121; - rgb->blue = 238; - return; - } - if(strcmp(color, "MediumPurple3") == 0) { - rgb->red = 137; - rgb->green = 104; - rgb->blue = 205; - return; - } - if(strcmp(color, "MediumPurple4") == 0) { - rgb->red = 93; - rgb->green = 71; - rgb->blue = 139; - return; - } - if(strcmp(color, "thistle1") == 0) { - rgb->red = 255; - rgb->green = 225; - rgb->blue = 255; - return; - } - if(strcmp(color, "thistle2") == 0) { - rgb->red = 238; - rgb->green = 210; - rgb->blue = 238; - return; - } - if(strcmp(color, "thistle3") == 0) { - rgb->red = 205; - rgb->green = 181; - rgb->blue = 205; - return; - } - if(strcmp(color, "thistle4") == 0) { - rgb->red = 139; - rgb->green = 123; - rgb->blue = 139; - return; - } - if(strcmp(color, "gray0") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "grey0") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "gray1") == 0) { - rgb->red = 3; - rgb->green = 3; - rgb->blue = 3; - return; - } - if(strcmp(color, "grey1") == 0) { - rgb->red = 3; - rgb->green = 3; - rgb->blue = 3; - return; - } - if(strcmp(color, "gray2") == 0) { - rgb->red = 5; - rgb->green = 5; - rgb->blue = 5; - return; - } - if(strcmp(color, "grey2") == 0) { - rgb->red = 5; - rgb->green = 5; - rgb->blue = 5; - return; - } - if(strcmp(color, "gray3") == 0) { - rgb->red = 8; - rgb->green = 8; - rgb->blue = 8; - return; - } - if(strcmp(color, "grey3") == 0) { - rgb->red = 8; - rgb->green = 8; - rgb->blue = 8; - return; - } - if(strcmp(color, "gray4") == 0) { - rgb->red = 10; - rgb->green = 10; - rgb->blue = 10; - return; - } - if(strcmp(color, "grey4") == 0) { - rgb->red = 10; - rgb->green = 10; - rgb->blue = 10; - return; - } - if(strcmp(color, "gray5") == 0) { - rgb->red = 13; - rgb->green = 13; - rgb->blue = 13; - return; - } - if(strcmp(color, "grey5") == 0) { - rgb->red = 13; - rgb->green = 13; - rgb->blue = 13; - return; - } - if(strcmp(color, "gray6") == 0) { - rgb->red = 15; - rgb->green = 15; - rgb->blue = 15; - return; - } - if(strcmp(color, "grey6") == 0) { - rgb->red = 15; - rgb->green = 15; - rgb->blue = 15; - return; - } - if(strcmp(color, "gray7") == 0) { - rgb->red = 18; - rgb->green = 18; - rgb->blue = 18; - return; - } - if(strcmp(color, "grey7") == 0) { - rgb->red = 18; - rgb->green = 18; - rgb->blue = 18; - return; - } - if(strcmp(color, "gray8") == 0) { - rgb->red = 20; - rgb->green = 20; - rgb->blue = 20; - return; - } - if(strcmp(color, "grey8") == 0) { - rgb->red = 20; - rgb->green = 20; - rgb->blue = 20; - return; - } - if(strcmp(color, "gray9") == 0) { - rgb->red = 23; - rgb->green = 23; - rgb->blue = 23; - return; - } - if(strcmp(color, "grey9") == 0) { - rgb->red = 23; - rgb->green = 23; - rgb->blue = 23; - return; - } - if(strcmp(color, "gray10") == 0) { - rgb->red = 26; - rgb->green = 26; - rgb->blue = 26; - return; - } - if(strcmp(color, "grey10") == 0) { - rgb->red = 26; - rgb->green = 26; - rgb->blue = 26; - return; - } - if(strcmp(color, "gray11") == 0) { - rgb->red = 28; - rgb->green = 28; - rgb->blue = 28; - return; - } - if(strcmp(color, "grey11") == 0) { - rgb->red = 28; - rgb->green = 28; - rgb->blue = 28; - return; - } - if(strcmp(color, "gray12") == 0) { - rgb->red = 31; - rgb->green = 31; - rgb->blue = 31; - return; - } - if(strcmp(color, "grey12") == 0) { - rgb->red = 31; - rgb->green = 31; - rgb->blue = 31; - return; - } - if(strcmp(color, "gray13") == 0) { - rgb->red = 33; - rgb->green = 33; - rgb->blue = 33; - return; - } - if(strcmp(color, "grey13") == 0) { - rgb->red = 33; - rgb->green = 33; - rgb->blue = 33; - return; - } - if(strcmp(color, "gray14") == 0) { - rgb->red = 36; - rgb->green = 36; - rgb->blue = 36; - return; - } - if(strcmp(color, "grey14") == 0) { - rgb->red = 36; - rgb->green = 36; - rgb->blue = 36; - return; - } - if(strcmp(color, "gray15") == 0) { - rgb->red = 38; - rgb->green = 38; - rgb->blue = 38; - return; - } - if(strcmp(color, "grey15") == 0) { - rgb->red = 38; - rgb->green = 38; - rgb->blue = 38; - return; - } - if(strcmp(color, "gray16") == 0) { - rgb->red = 41; - rgb->green = 41; - rgb->blue = 41; - return; - } - if(strcmp(color, "grey16") == 0) { - rgb->red = 41; - rgb->green = 41; - rgb->blue = 41; - return; - } - if(strcmp(color, "gray17") == 0) { - rgb->red = 43; - rgb->green = 43; - rgb->blue = 43; - return; - } - if(strcmp(color, "grey17") == 0) { - rgb->red = 43; - rgb->green = 43; - rgb->blue = 43; - return; - } - if(strcmp(color, "gray18") == 0) { - rgb->red = 46; - rgb->green = 46; - rgb->blue = 46; - return; - } - if(strcmp(color, "grey18") == 0) { - rgb->red = 46; - rgb->green = 46; - rgb->blue = 46; - return; - } - if(strcmp(color, "gray19") == 0) { - rgb->red = 48; - rgb->green = 48; - rgb->blue = 48; - return; - } - if(strcmp(color, "grey19") == 0) { - rgb->red = 48; - rgb->green = 48; - rgb->blue = 48; - return; - } - if(strcmp(color, "gray20") == 0) { - rgb->red = 51; - rgb->green = 51; - rgb->blue = 51; - return; - } - if(strcmp(color, "grey20") == 0) { - rgb->red = 51; - rgb->green = 51; - rgb->blue = 51; - return; - } - if(strcmp(color, "gray21") == 0) { - rgb->red = 54; - rgb->green = 54; - rgb->blue = 54; - return; - } - if(strcmp(color, "grey21") == 0) { - rgb->red = 54; - rgb->green = 54; - rgb->blue = 54; - return; - } - if(strcmp(color, "gray22") == 0) { - rgb->red = 56; - rgb->green = 56; - rgb->blue = 56; - return; - } - if(strcmp(color, "grey22") == 0) { - rgb->red = 56; - rgb->green = 56; - rgb->blue = 56; - return; - } - if(strcmp(color, "gray23") == 0) { - rgb->red = 59; - rgb->green = 59; - rgb->blue = 59; - return; - } - if(strcmp(color, "grey23") == 0) { - rgb->red = 59; - rgb->green = 59; - rgb->blue = 59; - return; - } - if(strcmp(color, "gray24") == 0) { - rgb->red = 61; - rgb->green = 61; - rgb->blue = 61; - return; - } - if(strcmp(color, "grey24") == 0) { - rgb->red = 61; - rgb->green = 61; - rgb->blue = 61; - return; - } - if(strcmp(color, "gray25") == 0) { - rgb->red = 64; - rgb->green = 64; - rgb->blue = 64; - return; - } - if(strcmp(color, "grey25") == 0) { - rgb->red = 64; - rgb->green = 64; - rgb->blue = 64; - return; - } - if(strcmp(color, "gray26") == 0) { - rgb->red = 66; - rgb->green = 66; - rgb->blue = 66; - return; - } - if(strcmp(color, "grey26") == 0) { - rgb->red = 66; - rgb->green = 66; - rgb->blue = 66; - return; - } - if(strcmp(color, "gray27") == 0) { - rgb->red = 69; - rgb->green = 69; - rgb->blue = 69; - return; - } - if(strcmp(color, "grey27") == 0) { - rgb->red = 69; - rgb->green = 69; - rgb->blue = 69; - return; - } - if(strcmp(color, "gray28") == 0) { - rgb->red = 71; - rgb->green = 71; - rgb->blue = 71; - return; - } - if(strcmp(color, "grey28") == 0) { - rgb->red = 71; - rgb->green = 71; - rgb->blue = 71; - return; - } - if(strcmp(color, "gray29") == 0) { - rgb->red = 74; - rgb->green = 74; - rgb->blue = 74; - return; - } - if(strcmp(color, "grey29") == 0) { - rgb->red = 74; - rgb->green = 74; - rgb->blue = 74; - return; - } - if(strcmp(color, "gray30") == 0) { - rgb->red = 77; - rgb->green = 77; - rgb->blue = 77; - return; - } - if(strcmp(color, "grey30") == 0) { - rgb->red = 77; - rgb->green = 77; - rgb->blue = 77; - return; - } - if(strcmp(color, "gray31") == 0) { - rgb->red = 79; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "grey31") == 0) { - rgb->red = 79; - rgb->green = 79; - rgb->blue = 79; - return; - } - if(strcmp(color, "gray32") == 0) { - rgb->red = 82; - rgb->green = 82; - rgb->blue = 82; - return; - } - if(strcmp(color, "grey32") == 0) { - rgb->red = 82; - rgb->green = 82; - rgb->blue = 82; - return; - } - if(strcmp(color, "gray33") == 0) { - rgb->red = 84; - rgb->green = 84; - rgb->blue = 84; - return; - } - if(strcmp(color, "grey33") == 0) { - rgb->red = 84; - rgb->green = 84; - rgb->blue = 84; - return; - } - if(strcmp(color, "gray34") == 0) { - rgb->red = 87; - rgb->green = 87; - rgb->blue = 87; - return; - } - if(strcmp(color, "grey34") == 0) { - rgb->red = 87; - rgb->green = 87; - rgb->blue = 87; - return; - } - if(strcmp(color, "gray35") == 0) { - rgb->red = 89; - rgb->green = 89; - rgb->blue = 89; - return; - } - if(strcmp(color, "grey35") == 0) { - rgb->red = 89; - rgb->green = 89; - rgb->blue = 89; - return; - } - if(strcmp(color, "gray36") == 0) { - rgb->red = 92; - rgb->green = 92; - rgb->blue = 92; - return; - } - if(strcmp(color, "grey36") == 0) { - rgb->red = 92; - rgb->green = 92; - rgb->blue = 92; - return; - } - if(strcmp(color, "gray37") == 0) { - rgb->red = 94; - rgb->green = 94; - rgb->blue = 94; - return; - } - if(strcmp(color, "grey37") == 0) { - rgb->red = 94; - rgb->green = 94; - rgb->blue = 94; - return; - } - if(strcmp(color, "gray38") == 0) { - rgb->red = 97; - rgb->green = 97; - rgb->blue = 97; - return; - } - if(strcmp(color, "grey38") == 0) { - rgb->red = 97; - rgb->green = 97; - rgb->blue = 97; - return; - } - if(strcmp(color, "gray39") == 0) { - rgb->red = 99; - rgb->green = 99; - rgb->blue = 99; - return; - } - if(strcmp(color, "grey39") == 0) { - rgb->red = 99; - rgb->green = 99; - rgb->blue = 99; - return; - } - if(strcmp(color, "gray40") == 0) { - rgb->red = 102; - rgb->green = 102; - rgb->blue = 102; - return; - } - if(strcmp(color, "grey40") == 0) { - rgb->red = 102; - rgb->green = 102; - rgb->blue = 102; - return; - } - if(strcmp(color, "gray41") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "grey41") == 0) { - rgb->red = 105; - rgb->green = 105; - rgb->blue = 105; - return; - } - if(strcmp(color, "gray42") == 0) { - rgb->red = 107; - rgb->green = 107; - rgb->blue = 107; - return; - } - if(strcmp(color, "grey42") == 0) { - rgb->red = 107; - rgb->green = 107; - rgb->blue = 107; - return; - } - if(strcmp(color, "gray43") == 0) { - rgb->red = 110; - rgb->green = 110; - rgb->blue = 110; - return; - } - if(strcmp(color, "grey43") == 0) { - rgb->red = 110; - rgb->green = 110; - rgb->blue = 110; - return; - } - if(strcmp(color, "gray44") == 0) { - rgb->red = 112; - rgb->green = 112; - rgb->blue = 112; - return; - } - if(strcmp(color, "grey44") == 0) { - rgb->red = 112; - rgb->green = 112; - rgb->blue = 112; - return; - } - if(strcmp(color, "gray45") == 0) { - rgb->red = 115; - rgb->green = 115; - rgb->blue = 115; - return; - } - if(strcmp(color, "grey45") == 0) { - rgb->red = 115; - rgb->green = 115; - rgb->blue = 115; - return; - } - if(strcmp(color, "gray46") == 0) { - rgb->red = 117; - rgb->green = 117; - rgb->blue = 117; - return; - } - if(strcmp(color, "grey46") == 0) { - rgb->red = 117; - rgb->green = 117; - rgb->blue = 117; - return; - } - if(strcmp(color, "gray47") == 0) { - rgb->red = 120; - rgb->green = 120; - rgb->blue = 120; - return; - } - if(strcmp(color, "grey47") == 0) { - rgb->red = 120; - rgb->green = 120; - rgb->blue = 120; - return; - } - if(strcmp(color, "gray48") == 0) { - rgb->red = 122; - rgb->green = 122; - rgb->blue = 122; - return; - } - if(strcmp(color, "grey48") == 0) { - rgb->red = 122; - rgb->green = 122; - rgb->blue = 122; - return; - } - if(strcmp(color, "gray49") == 0) { - rgb->red = 125; - rgb->green = 125; - rgb->blue = 125; - return; - } - if(strcmp(color, "grey49") == 0) { - rgb->red = 125; - rgb->green = 125; - rgb->blue = 125; - return; - } - if(strcmp(color, "gray50") == 0) { - rgb->red = 127; - rgb->green = 127; - rgb->blue = 127; - return; - } - if(strcmp(color, "grey50") == 0) { - rgb->red = 127; - rgb->green = 127; - rgb->blue = 127; - return; - } - if(strcmp(color, "gray51") == 0) { - rgb->red = 130; - rgb->green = 130; - rgb->blue = 130; - return; - } - if(strcmp(color, "grey51") == 0) { - rgb->red = 130; - rgb->green = 130; - rgb->blue = 130; - return; - } - if(strcmp(color, "gray52") == 0) { - rgb->red = 133; - rgb->green = 133; - rgb->blue = 133; - return; - } - if(strcmp(color, "grey52") == 0) { - rgb->red = 133; - rgb->green = 133; - rgb->blue = 133; - return; - } - if(strcmp(color, "gray53") == 0) { - rgb->red = 135; - rgb->green = 135; - rgb->blue = 135; - return; - } - if(strcmp(color, "grey53") == 0) { - rgb->red = 135; - rgb->green = 135; - rgb->blue = 135; - return; - } - if(strcmp(color, "gray54") == 0) { - rgb->red = 138; - rgb->green = 138; - rgb->blue = 138; - return; - } - if(strcmp(color, "grey54") == 0) { - rgb->red = 138; - rgb->green = 138; - rgb->blue = 138; - return; - } - if(strcmp(color, "gray55") == 0) { - rgb->red = 140; - rgb->green = 140; - rgb->blue = 140; - return; - } - if(strcmp(color, "grey55") == 0) { - rgb->red = 140; - rgb->green = 140; - rgb->blue = 140; - return; - } - if(strcmp(color, "gray56") == 0) { - rgb->red = 143; - rgb->green = 143; - rgb->blue = 143; - return; - } - if(strcmp(color, "grey56") == 0) { - rgb->red = 143; - rgb->green = 143; - rgb->blue = 143; - return; - } - if(strcmp(color, "gray57") == 0) { - rgb->red = 145; - rgb->green = 145; - rgb->blue = 145; - return; - } - if(strcmp(color, "grey57") == 0) { - rgb->red = 145; - rgb->green = 145; - rgb->blue = 145; - return; - } - if(strcmp(color, "gray58") == 0) { - rgb->red = 148; - rgb->green = 148; - rgb->blue = 148; - return; - } - if(strcmp(color, "grey58") == 0) { - rgb->red = 148; - rgb->green = 148; - rgb->blue = 148; - return; - } - if(strcmp(color, "gray59") == 0) { - rgb->red = 150; - rgb->green = 150; - rgb->blue = 150; - return; - } - if(strcmp(color, "grey59") == 0) { - rgb->red = 150; - rgb->green = 150; - rgb->blue = 150; - return; - } - if(strcmp(color, "gray60") == 0) { - rgb->red = 153; - rgb->green = 153; - rgb->blue = 153; - return; - } - if(strcmp(color, "grey60") == 0) { - rgb->red = 153; - rgb->green = 153; - rgb->blue = 153; - return; - } - if(strcmp(color, "gray61") == 0) { - rgb->red = 156; - rgb->green = 156; - rgb->blue = 156; - return; - } - if(strcmp(color, "grey61") == 0) { - rgb->red = 156; - rgb->green = 156; - rgb->blue = 156; - return; - } - if(strcmp(color, "gray62") == 0) { - rgb->red = 158; - rgb->green = 158; - rgb->blue = 158; - return; - } - if(strcmp(color, "grey62") == 0) { - rgb->red = 158; - rgb->green = 158; - rgb->blue = 158; - return; - } - if(strcmp(color, "gray63") == 0) { - rgb->red = 161; - rgb->green = 161; - rgb->blue = 161; - return; - } - if(strcmp(color, "grey63") == 0) { - rgb->red = 161; - rgb->green = 161; - rgb->blue = 161; - return; - } - if(strcmp(color, "gray64") == 0) { - rgb->red = 163; - rgb->green = 163; - rgb->blue = 163; - return; - } - if(strcmp(color, "grey64") == 0) { - rgb->red = 163; - rgb->green = 163; - rgb->blue = 163; - return; - } - if(strcmp(color, "gray65") == 0) { - rgb->red = 166; - rgb->green = 166; - rgb->blue = 166; - return; - } - if(strcmp(color, "grey65") == 0) { - rgb->red = 166; - rgb->green = 166; - rgb->blue = 166; - return; - } - if(strcmp(color, "gray66") == 0) { - rgb->red = 168; - rgb->green = 168; - rgb->blue = 168; - return; - } - if(strcmp(color, "grey66") == 0) { - rgb->red = 168; - rgb->green = 168; - rgb->blue = 168; - return; - } - if(strcmp(color, "gray67") == 0) { - rgb->red = 171; - rgb->green = 171; - rgb->blue = 171; - return; - } - if(strcmp(color, "grey67") == 0) { - rgb->red = 171; - rgb->green = 171; - rgb->blue = 171; - return; - } - if(strcmp(color, "gray68") == 0) { - rgb->red = 173; - rgb->green = 173; - rgb->blue = 173; - return; - } - if(strcmp(color, "grey68") == 0) { - rgb->red = 173; - rgb->green = 173; - rgb->blue = 173; - return; - } - if(strcmp(color, "gray69") == 0) { - rgb->red = 176; - rgb->green = 176; - rgb->blue = 176; - return; - } - if(strcmp(color, "grey69") == 0) { - rgb->red = 176; - rgb->green = 176; - rgb->blue = 176; - return; - } - if(strcmp(color, "gray70") == 0) { - rgb->red = 179; - rgb->green = 179; - rgb->blue = 179; - return; - } - if(strcmp(color, "grey70") == 0) { - rgb->red = 179; - rgb->green = 179; - rgb->blue = 179; - return; - } - if(strcmp(color, "gray71") == 0) { - rgb->red = 181; - rgb->green = 181; - rgb->blue = 181; - return; - } - if(strcmp(color, "grey71") == 0) { - rgb->red = 181; - rgb->green = 181; - rgb->blue = 181; - return; - } - if(strcmp(color, "gray72") == 0) { - rgb->red = 184; - rgb->green = 184; - rgb->blue = 184; - return; - } - if(strcmp(color, "grey72") == 0) { - rgb->red = 184; - rgb->green = 184; - rgb->blue = 184; - return; - } - if(strcmp(color, "gray73") == 0) { - rgb->red = 186; - rgb->green = 186; - rgb->blue = 186; - return; - } - if(strcmp(color, "grey73") == 0) { - rgb->red = 186; - rgb->green = 186; - rgb->blue = 186; - return; - } - if(strcmp(color, "gray74") == 0) { - rgb->red = 189; - rgb->green = 189; - rgb->blue = 189; - return; - } - if(strcmp(color, "grey74") == 0) { - rgb->red = 189; - rgb->green = 189; - rgb->blue = 189; - return; - } - if(strcmp(color, "gray75") == 0) { - rgb->red = 191; - rgb->green = 191; - rgb->blue = 191; - return; - } - if(strcmp(color, "grey75") == 0) { - rgb->red = 191; - rgb->green = 191; - rgb->blue = 191; - return; - } - if(strcmp(color, "gray76") == 0) { - rgb->red = 194; - rgb->green = 194; - rgb->blue = 194; - return; - } - if(strcmp(color, "grey76") == 0) { - rgb->red = 194; - rgb->green = 194; - rgb->blue = 194; - return; - } - if(strcmp(color, "gray77") == 0) { - rgb->red = 196; - rgb->green = 196; - rgb->blue = 196; - return; - } - if(strcmp(color, "grey77") == 0) { - rgb->red = 196; - rgb->green = 196; - rgb->blue = 196; - return; - } - if(strcmp(color, "gray78") == 0) { - rgb->red = 199; - rgb->green = 199; - rgb->blue = 199; - return; - } - if(strcmp(color, "grey78") == 0) { - rgb->red = 199; - rgb->green = 199; - rgb->blue = 199; - return; - } - if(strcmp(color, "gray79") == 0) { - rgb->red = 201; - rgb->green = 201; - rgb->blue = 201; - return; - } - if(strcmp(color, "grey79") == 0) { - rgb->red = 201; - rgb->green = 201; - rgb->blue = 201; - return; - } - if(strcmp(color, "gray80") == 0) { - rgb->red = 204; - rgb->green = 204; - rgb->blue = 204; - return; - } - if(strcmp(color, "grey80") == 0) { - rgb->red = 204; - rgb->green = 204; - rgb->blue = 204; - return; - } - if(strcmp(color, "gray81") == 0) { - rgb->red = 207; - rgb->green = 207; - rgb->blue = 207; - return; - } - if(strcmp(color, "grey81") == 0) { - rgb->red = 207; - rgb->green = 207; - rgb->blue = 207; - return; - } - if(strcmp(color, "gray82") == 0) { - rgb->red = 209; - rgb->green = 209; - rgb->blue = 209; - return; - } - if(strcmp(color, "grey82") == 0) { - rgb->red = 209; - rgb->green = 209; - rgb->blue = 209; - return; - } - if(strcmp(color, "gray83") == 0) { - rgb->red = 212; - rgb->green = 212; - rgb->blue = 212; - return; - } - if(strcmp(color, "grey83") == 0) { - rgb->red = 212; - rgb->green = 212; - rgb->blue = 212; - return; - } - if(strcmp(color, "gray84") == 0) { - rgb->red = 214; - rgb->green = 214; - rgb->blue = 214; - return; - } - if(strcmp(color, "grey84") == 0) { - rgb->red = 214; - rgb->green = 214; - rgb->blue = 214; - return; - } - if(strcmp(color, "gray85") == 0) { - rgb->red = 217; - rgb->green = 217; - rgb->blue = 217; - return; - } - if(strcmp(color, "grey85") == 0) { - rgb->red = 217; - rgb->green = 217; - rgb->blue = 217; - return; - } - if(strcmp(color, "gray86") == 0) { - rgb->red = 219; - rgb->green = 219; - rgb->blue = 219; - return; - } - if(strcmp(color, "grey86") == 0) { - rgb->red = 219; - rgb->green = 219; - rgb->blue = 219; - return; - } - if(strcmp(color, "gray87") == 0) { - rgb->red = 222; - rgb->green = 222; - rgb->blue = 222; - return; - } - if(strcmp(color, "grey87") == 0) { - rgb->red = 222; - rgb->green = 222; - rgb->blue = 222; - return; - } - if(strcmp(color, "gray88") == 0) { - rgb->red = 224; - rgb->green = 224; - rgb->blue = 224; - return; - } - if(strcmp(color, "grey88") == 0) { - rgb->red = 224; - rgb->green = 224; - rgb->blue = 224; - return; - } - if(strcmp(color, "gray89") == 0) { - rgb->red = 227; - rgb->green = 227; - rgb->blue = 227; - return; - } - if(strcmp(color, "grey89") == 0) { - rgb->red = 227; - rgb->green = 227; - rgb->blue = 227; - return; - } - if(strcmp(color, "gray90") == 0) { - rgb->red = 229; - rgb->green = 229; - rgb->blue = 229; - return; - } - if(strcmp(color, "grey90") == 0) { - rgb->red = 229; - rgb->green = 229; - rgb->blue = 229; - return; - } - if(strcmp(color, "gray91") == 0) { - rgb->red = 232; - rgb->green = 232; - rgb->blue = 232; - return; - } - if(strcmp(color, "grey91") == 0) { - rgb->red = 232; - rgb->green = 232; - rgb->blue = 232; - return; - } - if(strcmp(color, "gray92") == 0) { - rgb->red = 235; - rgb->green = 235; - rgb->blue = 235; - return; - } - if(strcmp(color, "grey92") == 0) { - rgb->red = 235; - rgb->green = 235; - rgb->blue = 235; - return; - } - if(strcmp(color, "gray93") == 0) { - rgb->red = 237; - rgb->green = 237; - rgb->blue = 237; - return; - } - if(strcmp(color, "grey93") == 0) { - rgb->red = 237; - rgb->green = 237; - rgb->blue = 237; - return; - } - if(strcmp(color, "gray94") == 0) { - rgb->red = 240; - rgb->green = 240; - rgb->blue = 240; - return; - } - if(strcmp(color, "grey94") == 0) { - rgb->red = 240; - rgb->green = 240; - rgb->blue = 240; - return; - } - if(strcmp(color, "gray95") == 0) { - rgb->red = 242; - rgb->green = 242; - rgb->blue = 242; - return; - } - if(strcmp(color, "grey95") == 0) { - rgb->red = 242; - rgb->green = 242; - rgb->blue = 242; - return; - } - if(strcmp(color, "gray96") == 0) { - rgb->red = 245; - rgb->green = 245; - rgb->blue = 245; - return; - } - if(strcmp(color, "grey96") == 0) { - rgb->red = 245; - rgb->green = 245; - rgb->blue = 245; - return; - } - if(strcmp(color, "gray97") == 0) { - rgb->red = 247; - rgb->green = 247; - rgb->blue = 247; - return; - } - if(strcmp(color, "grey97") == 0) { - rgb->red = 247; - rgb->green = 247; - rgb->blue = 247; - return; - } - if(strcmp(color, "gray98") == 0) { - rgb->red = 250; - rgb->green = 250; - rgb->blue = 250; - return; - } - if(strcmp(color, "grey98") == 0) { - rgb->red = 250; - rgb->green = 250; - rgb->blue = 250; - return; - } - if(strcmp(color, "gray99") == 0) { - rgb->red = 252; - rgb->green = 252; - rgb->blue = 252; - return; - } - if(strcmp(color, "grey99") == 0) { - rgb->red = 252; - rgb->green = 252; - rgb->blue = 252; - return; - } - if(strcmp(color, "gray100") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "grey100") == 0) { - rgb->red = 255; - rgb->green = 255; - rgb->blue = 255; - return; - } - if(strcmp(color, "dark grey") == 0) { - rgb->red = 169; - rgb->green = 169; - rgb->blue = 169; - return; - } - if(strcmp(color, "DarkGrey") == 0) { - rgb->red = 169; - rgb->green = 169; - rgb->blue = 169; - return; - } - if(strcmp(color, "dark gray") == 0) { - rgb->red = 169; - rgb->green = 169; - rgb->blue = 169; - return; - } - if(strcmp(color, "DarkGray") == 0) { - rgb->red = 169; - rgb->green = 169; - rgb->blue = 169; - return; - } - if(strcmp(color, "dark blue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkBlue") == 0) { - rgb->red = 0; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "dark cyan") == 0) { - rgb->red = 0; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkCyan") == 0) { - rgb->red = 0; - rgb->green = 139; - rgb->blue = 139; - return; - } - if(strcmp(color, "dark magenta") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "DarkMagenta") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 139; - return; - } - if(strcmp(color, "dark red") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "DarkRed") == 0) { - rgb->red = 139; - rgb->green = 0; - rgb->blue = 0; - return; - } - if(strcmp(color, "light green") == 0) { - rgb->red = 144; - rgb->green = 238; - rgb->blue = 144; - return; - } - if(strcmp(color, "LightGreen") == 0) { - rgb->red = 144; - rgb->green = 238; - rgb->blue = 144; - return; - } - if(strcmp(color, "crimson") == 0) { - rgb->red = 220; - rgb->green = 20; - rgb->blue = 60; - return; - } - if(strcmp(color, "indigo") == 0) { - rgb->red = 75; - rgb->green = 0; - rgb->blue = 130; - return; - } - if(strcmp(color, "olive") == 0) { - rgb->red = 128; - rgb->green = 128; - rgb->blue = 0; - return; - } - if(strcmp(color, "rebecca purple") == 0) { - rgb->red = 102; - rgb->green = 51; - rgb->blue = 153; - return; - } - if(strcmp(color, "RebeccaPurple") == 0) { - rgb->red = 102; - rgb->green = 51; - rgb->blue = 153; - return; - } - if(strcmp(color, "silver") == 0) { - rgb->red = 192; - rgb->green = 192; - rgb->blue = 192; - return; - } - if(strcmp(color, "teal") == 0) { - rgb->red = 0; - rgb->green = 128; - rgb->blue = 128; - return; - } - rgb->red = 0; - rgb->green = 0; - rgb->blue = 0; + MwU32 v = shget(colors, color); + rgb->red = (v >> 16) & 0xff; + rgb->green = (v >> 8) & 0xff; + rgb->blue = (v >> 0) & 0xff; +} + +static void add_color(const char* name, int red, int green, int blue) { + MwU32 v = (red << 16) | (green << 8) | (blue << 0); + shput(colors, name, v); +} + +void MwColorTableInit(void) { + sh_new_strdup(colors); + shdefault(colors, 0); + add_color("snow", 255, 250, 250); + add_color("ghost white", 248, 248, 255); + add_color("GhostWhite", 248, 248, 255); + add_color("white smoke", 245, 245, 245); + add_color("WhiteSmoke", 245, 245, 245); + add_color("gainsboro", 220, 220, 220); + add_color("floral white", 255, 250, 240); + add_color("FloralWhite", 255, 250, 240); + add_color("old lace", 253, 245, 230); + add_color("OldLace", 253, 245, 230); + add_color("linen", 250, 240, 230); + add_color("antique white", 250, 235, 215); + add_color("AntiqueWhite", 250, 235, 215); + add_color("papaya whip", 255, 239, 213); + add_color("PapayaWhip", 255, 239, 213); + add_color("blanched almond", 255, 235, 205); + add_color("BlanchedAlmond", 255, 235, 205); + add_color("bisque", 255, 228, 196); + add_color("peach puff", 255, 218, 185); + add_color("PeachPuff", 255, 218, 185); + add_color("navajo white", 255, 222, 173); + add_color("NavajoWhite", 255, 222, 173); + add_color("moccasin", 255, 228, 181); + add_color("cornsilk", 255, 248, 220); + add_color("ivory", 255, 255, 240); + add_color("lemon chiffon", 255, 250, 205); + add_color("LemonChiffon", 255, 250, 205); + add_color("seashell", 255, 245, 238); + add_color("honeydew", 240, 255, 240); + add_color("mint cream", 245, 255, 250); + add_color("MintCream", 245, 255, 250); + add_color("azure", 240, 255, 255); + add_color("alice blue", 240, 248, 255); + add_color("AliceBlue", 240, 248, 255); + add_color("lavender", 230, 230, 250); + add_color("lavender blush", 255, 240, 245); + add_color("LavenderBlush", 255, 240, 245); + add_color("misty rose", 255, 228, 225); + add_color("MistyRose", 255, 228, 225); + add_color("white", 255, 255, 255); + add_color("black", 0, 0, 0); + add_color("dark slate gray", 47, 79, 79); + add_color("DarkSlateGray", 47, 79, 79); + add_color("dark slate grey", 47, 79, 79); + add_color("DarkSlateGrey", 47, 79, 79); + add_color("dim gray", 105, 105, 105); + add_color("DimGray", 105, 105, 105); + add_color("dim grey", 105, 105, 105); + add_color("DimGrey", 105, 105, 105); + add_color("slate gray", 112, 128, 144); + add_color("SlateGray", 112, 128, 144); + add_color("slate grey", 112, 128, 144); + add_color("SlateGrey", 112, 128, 144); + add_color("light slate gray", 119, 136, 153); + add_color("LightSlateGray", 119, 136, 153); + add_color("light slate grey", 119, 136, 153); + add_color("LightSlateGrey", 119, 136, 153); + add_color("gray", 190, 190, 190); + add_color("grey", 190, 190, 190); + add_color("x11 gray", 190, 190, 190); + add_color("X11Gray", 190, 190, 190); + add_color("x11 grey", 190, 190, 190); + add_color("X11Grey", 190, 190, 190); + add_color("web gray", 128, 128, 128); + add_color("WebGray", 128, 128, 128); + add_color("web grey", 128, 128, 128); + add_color("WebGrey", 128, 128, 128); + add_color("light grey", 211, 211, 211); + add_color("LightGrey", 211, 211, 211); + add_color("light gray", 211, 211, 211); + add_color("LightGray", 211, 211, 211); + add_color("midnight blue", 25, 25, 112); + add_color("MidnightBlue", 25, 25, 112); + add_color("navy", 0, 0, 128); + add_color("navy blue", 0, 0, 128); + add_color("NavyBlue", 0, 0, 128); + add_color("cornflower blue", 100, 149, 237); + add_color("CornflowerBlue", 100, 149, 237); + add_color("dark slate blue", 72, 61, 139); + add_color("DarkSlateBlue", 72, 61, 139); + add_color("slate blue", 106, 90, 205); + add_color("SlateBlue", 106, 90, 205); + add_color("medium slate blue", 123, 104, 238); + add_color("MediumSlateBlue", 123, 104, 238); + add_color("light slate blue", 132, 112, 255); + add_color("LightSlateBlue", 132, 112, 255); + add_color("medium blue", 0, 0, 205); + add_color("MediumBlue", 0, 0, 205); + add_color("royal blue", 65, 105, 225); + add_color("RoyalBlue", 65, 105, 225); + add_color("blue", 0, 0, 255); + add_color("dodger blue", 30, 144, 255); + add_color("DodgerBlue", 30, 144, 255); + add_color("deep sky blue", 0, 191, 255); + add_color("DeepSkyBlue", 0, 191, 255); + add_color("sky blue", 135, 206, 235); + add_color("SkyBlue", 135, 206, 235); + add_color("light sky blue", 135, 206, 250); + add_color("LightSkyBlue", 135, 206, 250); + add_color("steel blue", 70, 130, 180); + add_color("SteelBlue", 70, 130, 180); + add_color("light steel blue", 176, 196, 222); + add_color("LightSteelBlue", 176, 196, 222); + add_color("light blue", 173, 216, 230); + add_color("LightBlue", 173, 216, 230); + add_color("powder blue", 176, 224, 230); + add_color("PowderBlue", 176, 224, 230); + add_color("pale turquoise", 175, 238, 238); + add_color("PaleTurquoise", 175, 238, 238); + add_color("dark turquoise", 0, 206, 209); + add_color("DarkTurquoise", 0, 206, 209); + add_color("medium turquoise", 72, 209, 204); + add_color("MediumTurquoise", 72, 209, 204); + add_color("turquoise", 64, 224, 208); + add_color("cyan", 0, 255, 255); + add_color("aqua", 0, 255, 255); + add_color("light cyan", 224, 255, 255); + add_color("LightCyan", 224, 255, 255); + add_color("cadet blue", 95, 158, 160); + add_color("CadetBlue", 95, 158, 160); + add_color("medium aquamarine", 102, 205, 170); + add_color("MediumAquamarine", 102, 205, 170); + add_color("aquamarine", 127, 255, 212); + add_color("dark green", 0, 100, 0); + add_color("DarkGreen", 0, 100, 0); + add_color("dark olive green", 85, 107, 47); + add_color("DarkOliveGreen", 85, 107, 47); + add_color("dark sea green", 143, 188, 143); + add_color("DarkSeaGreen", 143, 188, 143); + add_color("sea green", 46, 139, 87); + add_color("SeaGreen", 46, 139, 87); + add_color("medium sea green", 60, 179, 113); + add_color("MediumSeaGreen", 60, 179, 113); + add_color("light sea green", 32, 178, 170); + add_color("LightSeaGreen", 32, 178, 170); + add_color("pale green", 152, 251, 152); + add_color("PaleGreen", 152, 251, 152); + add_color("spring green", 0, 255, 127); + add_color("SpringGreen", 0, 255, 127); + add_color("lawn green", 124, 252, 0); + add_color("LawnGreen", 124, 252, 0); + add_color("green", 0, 255, 0); + add_color("lime", 0, 255, 0); + add_color("x11 green", 0, 255, 0); + add_color("X11Green", 0, 255, 0); + add_color("web green", 0, 128, 0); + add_color("WebGreen", 0, 128, 0); + add_color("chartreuse", 127, 255, 0); + add_color("medium spring green", 0, 250, 154); + add_color("MediumSpringGreen", 0, 250, 154); + add_color("green yellow", 173, 255, 47); + add_color("GreenYellow", 173, 255, 47); + add_color("lime green", 50, 205, 50); + add_color("LimeGreen", 50, 205, 50); + add_color("yellow green", 154, 205, 50); + add_color("YellowGreen", 154, 205, 50); + add_color("forest green", 34, 139, 34); + add_color("ForestGreen", 34, 139, 34); + add_color("olive drab", 107, 142, 35); + add_color("OliveDrab", 107, 142, 35); + add_color("dark khaki", 189, 183, 107); + add_color("DarkKhaki", 189, 183, 107); + add_color("khaki", 240, 230, 140); + add_color("pale goldenrod", 238, 232, 170); + add_color("PaleGoldenrod", 238, 232, 170); + add_color("light goldenrod yellow", 250, 250, 210); + add_color("LightGoldenrodYellow", 250, 250, 210); + add_color("light yellow", 255, 255, 224); + add_color("LightYellow", 255, 255, 224); + add_color("yellow", 255, 255, 0); + add_color("gold", 255, 215, 0); + add_color("light goldenrod", 238, 221, 130); + add_color("LightGoldenrod", 238, 221, 130); + add_color("goldenrod", 218, 165, 32); + add_color("dark goldenrod", 184, 134, 11); + add_color("DarkGoldenrod", 184, 134, 11); + add_color("rosy brown", 188, 143, 143); + add_color("RosyBrown", 188, 143, 143); + add_color("indian red", 205, 92, 92); + add_color("IndianRed", 205, 92, 92); + add_color("saddle brown", 139, 69, 19); + add_color("SaddleBrown", 139, 69, 19); + add_color("sienna", 160, 82, 45); + add_color("peru", 205, 133, 63); + add_color("burlywood", 222, 184, 135); + add_color("beige", 245, 245, 220); + add_color("wheat", 245, 222, 179); + add_color("sandy brown", 244, 164, 96); + add_color("SandyBrown", 244, 164, 96); + add_color("tan", 210, 180, 140); + add_color("chocolate", 210, 105, 30); + add_color("firebrick", 178, 34, 34); + add_color("brown", 165, 42, 42); + add_color("dark salmon", 233, 150, 122); + add_color("DarkSalmon", 233, 150, 122); + add_color("salmon", 250, 128, 114); + add_color("light salmon", 255, 160, 122); + add_color("LightSalmon", 255, 160, 122); + add_color("orange", 255, 165, 0); + add_color("dark orange", 255, 140, 0); + add_color("DarkOrange", 255, 140, 0); + add_color("coral", 255, 127, 80); + add_color("light coral", 240, 128, 128); + add_color("LightCoral", 240, 128, 128); + add_color("tomato", 255, 99, 71); + add_color("orange red", 255, 69, 0); + add_color("OrangeRed", 255, 69, 0); + add_color("red", 255, 0, 0); + add_color("hot pink", 255, 105, 180); + add_color("HotPink", 255, 105, 180); + add_color("deep pink", 255, 20, 147); + add_color("DeepPink", 255, 20, 147); + add_color("pink", 255, 192, 203); + add_color("light pink", 255, 182, 193); + add_color("LightPink", 255, 182, 193); + add_color("pale violet red", 219, 112, 147); + add_color("PaleVioletRed", 219, 112, 147); + add_color("maroon", 176, 48, 96); + add_color("x11 maroon", 176, 48, 96); + add_color("X11Maroon", 176, 48, 96); + add_color("web maroon", 128, 0, 0); + add_color("WebMaroon", 128, 0, 0); + add_color("medium violet red", 199, 21, 133); + add_color("MediumVioletRed", 199, 21, 133); + add_color("violet red", 208, 32, 144); + add_color("VioletRed", 208, 32, 144); + add_color("magenta", 255, 0, 255); + add_color("fuchsia", 255, 0, 255); + add_color("violet", 238, 130, 238); + add_color("plum", 221, 160, 221); + add_color("orchid", 218, 112, 214); + add_color("medium orchid", 186, 85, 211); + add_color("MediumOrchid", 186, 85, 211); + add_color("dark orchid", 153, 50, 204); + add_color("DarkOrchid", 153, 50, 204); + add_color("dark violet", 148, 0, 211); + add_color("DarkViolet", 148, 0, 211); + add_color("blue violet", 138, 43, 226); + add_color("BlueViolet", 138, 43, 226); + add_color("purple", 160, 32, 240); + add_color("x11 purple", 160, 32, 240); + add_color("X11Purple", 160, 32, 240); + add_color("web purple", 128, 0, 128); + add_color("WebPurple", 128, 0, 128); + add_color("medium purple", 147, 112, 219); + add_color("MediumPurple", 147, 112, 219); + add_color("thistle", 216, 191, 216); + add_color("snow1", 255, 250, 250); + add_color("snow2", 238, 233, 233); + add_color("snow3", 205, 201, 201); + add_color("snow4", 139, 137, 137); + add_color("seashell1", 255, 245, 238); + add_color("seashell2", 238, 229, 222); + add_color("seashell3", 205, 197, 191); + add_color("seashell4", 139, 134, 130); + add_color("AntiqueWhite1", 255, 239, 219); + add_color("AntiqueWhite2", 238, 223, 204); + add_color("AntiqueWhite3", 205, 192, 176); + add_color("AntiqueWhite4", 139, 131, 120); + add_color("bisque1", 255, 228, 196); + add_color("bisque2", 238, 213, 183); + add_color("bisque3", 205, 183, 158); + add_color("bisque4", 139, 125, 107); + add_color("PeachPuff1", 255, 218, 185); + add_color("PeachPuff2", 238, 203, 173); + add_color("PeachPuff3", 205, 175, 149); + add_color("PeachPuff4", 139, 119, 101); + add_color("NavajoWhite1", 255, 222, 173); + add_color("NavajoWhite2", 238, 207, 161); + add_color("NavajoWhite3", 205, 179, 139); + add_color("NavajoWhite4", 139, 121, 94); + add_color("LemonChiffon1", 255, 250, 205); + add_color("LemonChiffon2", 238, 233, 191); + add_color("LemonChiffon3", 205, 201, 165); + add_color("LemonChiffon4", 139, 137, 112); + add_color("cornsilk1", 255, 248, 220); + add_color("cornsilk2", 238, 232, 205); + add_color("cornsilk3", 205, 200, 177); + add_color("cornsilk4", 139, 136, 120); + add_color("ivory1", 255, 255, 240); + add_color("ivory2", 238, 238, 224); + add_color("ivory3", 205, 205, 193); + add_color("ivory4", 139, 139, 131); + add_color("honeydew1", 240, 255, 240); + add_color("honeydew2", 224, 238, 224); + add_color("honeydew3", 193, 205, 193); + add_color("honeydew4", 131, 139, 131); + add_color("LavenderBlush1", 255, 240, 245); + add_color("LavenderBlush2", 238, 224, 229); + add_color("LavenderBlush3", 205, 193, 197); + add_color("LavenderBlush4", 139, 131, 134); + add_color("MistyRose1", 255, 228, 225); + add_color("MistyRose2", 238, 213, 210); + add_color("MistyRose3", 205, 183, 181); + add_color("MistyRose4", 139, 125, 123); + add_color("azure1", 240, 255, 255); + add_color("azure2", 224, 238, 238); + add_color("azure3", 193, 205, 205); + add_color("azure4", 131, 139, 139); + add_color("SlateBlue1", 131, 111, 255); + add_color("SlateBlue2", 122, 103, 238); + add_color("SlateBlue3", 105, 89, 205); + add_color("SlateBlue4", 71, 60, 139); + add_color("RoyalBlue1", 72, 118, 255); + add_color("RoyalBlue2", 67, 110, 238); + add_color("RoyalBlue3", 58, 95, 205); + add_color("RoyalBlue4", 39, 64, 139); + add_color("blue1", 0, 0, 255); + add_color("blue2", 0, 0, 238); + add_color("blue3", 0, 0, 205); + add_color("blue4", 0, 0, 139); + add_color("DodgerBlue1", 30, 144, 255); + add_color("DodgerBlue2", 28, 134, 238); + add_color("DodgerBlue3", 24, 116, 205); + add_color("DodgerBlue4", 16, 78, 139); + add_color("SteelBlue1", 99, 184, 255); + add_color("SteelBlue2", 92, 172, 238); + add_color("SteelBlue3", 79, 148, 205); + add_color("SteelBlue4", 54, 100, 139); + add_color("DeepSkyBlue1", 0, 191, 255); + add_color("DeepSkyBlue2", 0, 178, 238); + add_color("DeepSkyBlue3", 0, 154, 205); + add_color("DeepSkyBlue4", 0, 104, 139); + add_color("SkyBlue1", 135, 206, 255); + add_color("SkyBlue2", 126, 192, 238); + add_color("SkyBlue3", 108, 166, 205); + add_color("SkyBlue4", 74, 112, 139); + add_color("LightSkyBlue1", 176, 226, 255); + add_color("LightSkyBlue2", 164, 211, 238); + add_color("LightSkyBlue3", 141, 182, 205); + add_color("LightSkyBlue4", 96, 123, 139); + add_color("SlateGray1", 198, 226, 255); + add_color("SlateGray2", 185, 211, 238); + add_color("SlateGray3", 159, 182, 205); + add_color("SlateGray4", 108, 123, 139); + add_color("LightSteelBlue1", 202, 225, 255); + add_color("LightSteelBlue2", 188, 210, 238); + add_color("LightSteelBlue3", 162, 181, 205); + add_color("LightSteelBlue4", 110, 123, 139); + add_color("LightBlue1", 191, 239, 255); + add_color("LightBlue2", 178, 223, 238); + add_color("LightBlue3", 154, 192, 205); + add_color("LightBlue4", 104, 131, 139); + add_color("LightCyan1", 224, 255, 255); + add_color("LightCyan2", 209, 238, 238); + add_color("LightCyan3", 180, 205, 205); + add_color("LightCyan4", 122, 139, 139); + add_color("PaleTurquoise1", 187, 255, 255); + add_color("PaleTurquoise2", 174, 238, 238); + add_color("PaleTurquoise3", 150, 205, 205); + add_color("PaleTurquoise4", 102, 139, 139); + add_color("CadetBlue1", 152, 245, 255); + add_color("CadetBlue2", 142, 229, 238); + add_color("CadetBlue3", 122, 197, 205); + add_color("CadetBlue4", 83, 134, 139); + add_color("turquoise1", 0, 245, 255); + add_color("turquoise2", 0, 229, 238); + add_color("turquoise3", 0, 197, 205); + add_color("turquoise4", 0, 134, 139); + add_color("cyan1", 0, 255, 255); + add_color("cyan2", 0, 238, 238); + add_color("cyan3", 0, 205, 205); + add_color("cyan4", 0, 139, 139); + add_color("DarkSlateGray1", 151, 255, 255); + add_color("DarkSlateGray2", 141, 238, 238); + add_color("DarkSlateGray3", 121, 205, 205); + add_color("DarkSlateGray4", 82, 139, 139); + add_color("aquamarine1", 127, 255, 212); + add_color("aquamarine2", 118, 238, 198); + add_color("aquamarine3", 102, 205, 170); + add_color("aquamarine4", 69, 139, 116); + add_color("DarkSeaGreen1", 193, 255, 193); + add_color("DarkSeaGreen2", 180, 238, 180); + add_color("DarkSeaGreen3", 155, 205, 155); + add_color("DarkSeaGreen4", 105, 139, 105); + add_color("SeaGreen1", 84, 255, 159); + add_color("SeaGreen2", 78, 238, 148); + add_color("SeaGreen3", 67, 205, 128); + add_color("SeaGreen4", 46, 139, 87); + add_color("PaleGreen1", 154, 255, 154); + add_color("PaleGreen2", 144, 238, 144); + add_color("PaleGreen3", 124, 205, 124); + add_color("PaleGreen4", 84, 139, 84); + add_color("SpringGreen1", 0, 255, 127); + add_color("SpringGreen2", 0, 238, 118); + add_color("SpringGreen3", 0, 205, 102); + add_color("SpringGreen4", 0, 139, 69); + add_color("green1", 0, 255, 0); + add_color("green2", 0, 238, 0); + add_color("green3", 0, 205, 0); + add_color("green4", 0, 139, 0); + add_color("chartreuse1", 127, 255, 0); + add_color("chartreuse2", 118, 238, 0); + add_color("chartreuse3", 102, 205, 0); + add_color("chartreuse4", 69, 139, 0); + add_color("OliveDrab1", 192, 255, 62); + add_color("OliveDrab2", 179, 238, 58); + add_color("OliveDrab3", 154, 205, 50); + add_color("OliveDrab4", 105, 139, 34); + add_color("DarkOliveGreen1", 202, 255, 112); + add_color("DarkOliveGreen2", 188, 238, 104); + add_color("DarkOliveGreen3", 162, 205, 90); + add_color("DarkOliveGreen4", 110, 139, 61); + add_color("khaki1", 255, 246, 143); + add_color("khaki2", 238, 230, 133); + add_color("khaki3", 205, 198, 115); + add_color("khaki4", 139, 134, 78); + add_color("LightGoldenrod1", 255, 236, 139); + add_color("LightGoldenrod2", 238, 220, 130); + add_color("LightGoldenrod3", 205, 190, 112); + add_color("LightGoldenrod4", 139, 129, 76); + add_color("LightYellow1", 255, 255, 224); + add_color("LightYellow2", 238, 238, 209); + add_color("LightYellow3", 205, 205, 180); + add_color("LightYellow4", 139, 139, 122); + add_color("yellow1", 255, 255, 0); + add_color("yellow2", 238, 238, 0); + add_color("yellow3", 205, 205, 0); + add_color("yellow4", 139, 139, 0); + add_color("gold1", 255, 215, 0); + add_color("gold2", 238, 201, 0); + add_color("gold3", 205, 173, 0); + add_color("gold4", 139, 117, 0); + add_color("goldenrod1", 255, 193, 37); + add_color("goldenrod2", 238, 180, 34); + add_color("goldenrod3", 205, 155, 29); + add_color("goldenrod4", 139, 105, 20); + add_color("DarkGoldenrod1", 255, 185, 15); + add_color("DarkGoldenrod2", 238, 173, 14); + add_color("DarkGoldenrod3", 205, 149, 12); + add_color("DarkGoldenrod4", 139, 101, 8); + add_color("RosyBrown1", 255, 193, 193); + add_color("RosyBrown2", 238, 180, 180); + add_color("RosyBrown3", 205, 155, 155); + add_color("RosyBrown4", 139, 105, 105); + add_color("IndianRed1", 255, 106, 106); + add_color("IndianRed2", 238, 99, 99); + add_color("IndianRed3", 205, 85, 85); + add_color("IndianRed4", 139, 58, 58); + add_color("sienna1", 255, 130, 71); + add_color("sienna2", 238, 121, 66); + add_color("sienna3", 205, 104, 57); + add_color("sienna4", 139, 71, 38); + add_color("burlywood1", 255, 211, 155); + add_color("burlywood2", 238, 197, 145); + add_color("burlywood3", 205, 170, 125); + add_color("burlywood4", 139, 115, 85); + add_color("wheat1", 255, 231, 186); + add_color("wheat2", 238, 216, 174); + add_color("wheat3", 205, 186, 150); + add_color("wheat4", 139, 126, 102); + add_color("tan1", 255, 165, 79); + add_color("tan2", 238, 154, 73); + add_color("tan3", 205, 133, 63); + add_color("tan4", 139, 90, 43); + add_color("chocolate1", 255, 127, 36); + add_color("chocolate2", 238, 118, 33); + add_color("chocolate3", 205, 102, 29); + add_color("chocolate4", 139, 69, 19); + add_color("firebrick1", 255, 48, 48); + add_color("firebrick2", 238, 44, 44); + add_color("firebrick3", 205, 38, 38); + add_color("firebrick4", 139, 26, 26); + add_color("brown1", 255, 64, 64); + add_color("brown2", 238, 59, 59); + add_color("brown3", 205, 51, 51); + add_color("brown4", 139, 35, 35); + add_color("salmon1", 255, 140, 105); + add_color("salmon2", 238, 130, 98); + add_color("salmon3", 205, 112, 84); + add_color("salmon4", 139, 76, 57); + add_color("LightSalmon1", 255, 160, 122); + add_color("LightSalmon2", 238, 149, 114); + add_color("LightSalmon3", 205, 129, 98); + add_color("LightSalmon4", 139, 87, 66); + add_color("orange1", 255, 165, 0); + add_color("orange2", 238, 154, 0); + add_color("orange3", 205, 133, 0); + add_color("orange4", 139, 90, 0); + add_color("DarkOrange1", 255, 127, 0); + add_color("DarkOrange2", 238, 118, 0); + add_color("DarkOrange3", 205, 102, 0); + add_color("DarkOrange4", 139, 69, 0); + add_color("coral1", 255, 114, 86); + add_color("coral2", 238, 106, 80); + add_color("coral3", 205, 91, 69); + add_color("coral4", 139, 62, 47); + add_color("tomato1", 255, 99, 71); + add_color("tomato2", 238, 92, 66); + add_color("tomato3", 205, 79, 57); + add_color("tomato4", 139, 54, 38); + add_color("OrangeRed1", 255, 69, 0); + add_color("OrangeRed2", 238, 64, 0); + add_color("OrangeRed3", 205, 55, 0); + add_color("OrangeRed4", 139, 37, 0); + add_color("red1", 255, 0, 0); + add_color("red2", 238, 0, 0); + add_color("red3", 205, 0, 0); + add_color("red4", 139, 0, 0); + add_color("DeepPink1", 255, 20, 147); + add_color("DeepPink2", 238, 18, 137); + add_color("DeepPink3", 205, 16, 118); + add_color("DeepPink4", 139, 10, 80); + add_color("HotPink1", 255, 110, 180); + add_color("HotPink2", 238, 106, 167); + add_color("HotPink3", 205, 96, 144); + add_color("HotPink4", 139, 58, 98); + add_color("pink1", 255, 181, 197); + add_color("pink2", 238, 169, 184); + add_color("pink3", 205, 145, 158); + add_color("pink4", 139, 99, 108); + add_color("LightPink1", 255, 174, 185); + add_color("LightPink2", 238, 162, 173); + add_color("LightPink3", 205, 140, 149); + add_color("LightPink4", 139, 95, 101); + add_color("PaleVioletRed1", 255, 130, 171); + add_color("PaleVioletRed2", 238, 121, 159); + add_color("PaleVioletRed3", 205, 104, 137); + add_color("PaleVioletRed4", 139, 71, 93); + add_color("maroon1", 255, 52, 179); + add_color("maroon2", 238, 48, 167); + add_color("maroon3", 205, 41, 144); + add_color("maroon4", 139, 28, 98); + add_color("VioletRed1", 255, 62, 150); + add_color("VioletRed2", 238, 58, 140); + add_color("VioletRed3", 205, 50, 120); + add_color("VioletRed4", 139, 34, 82); + add_color("magenta1", 255, 0, 255); + add_color("magenta2", 238, 0, 238); + add_color("magenta3", 205, 0, 205); + add_color("magenta4", 139, 0, 139); + add_color("orchid1", 255, 131, 250); + add_color("orchid2", 238, 122, 233); + add_color("orchid3", 205, 105, 201); + add_color("orchid4", 139, 71, 137); + add_color("plum1", 255, 187, 255); + add_color("plum2", 238, 174, 238); + add_color("plum3", 205, 150, 205); + add_color("plum4", 139, 102, 139); + add_color("MediumOrchid1", 224, 102, 255); + add_color("MediumOrchid2", 209, 95, 238); + add_color("MediumOrchid3", 180, 82, 205); + add_color("MediumOrchid4", 122, 55, 139); + add_color("DarkOrchid1", 191, 62, 255); + add_color("DarkOrchid2", 178, 58, 238); + add_color("DarkOrchid3", 154, 50, 205); + add_color("DarkOrchid4", 104, 34, 139); + add_color("purple1", 155, 48, 255); + add_color("purple2", 145, 44, 238); + add_color("purple3", 125, 38, 205); + add_color("purple4", 85, 26, 139); + add_color("MediumPurple1", 171, 130, 255); + add_color("MediumPurple2", 159, 121, 238); + add_color("MediumPurple3", 137, 104, 205); + add_color("MediumPurple4", 93, 71, 139); + add_color("thistle1", 255, 225, 255); + add_color("thistle2", 238, 210, 238); + add_color("thistle3", 205, 181, 205); + add_color("thistle4", 139, 123, 139); + add_color("gray0", 0, 0, 0); + add_color("grey0", 0, 0, 0); + add_color("gray1", 3, 3, 3); + add_color("grey1", 3, 3, 3); + add_color("gray2", 5, 5, 5); + add_color("grey2", 5, 5, 5); + add_color("gray3", 8, 8, 8); + add_color("grey3", 8, 8, 8); + add_color("gray4", 10, 10, 10); + add_color("grey4", 10, 10, 10); + add_color("gray5", 13, 13, 13); + add_color("grey5", 13, 13, 13); + add_color("gray6", 15, 15, 15); + add_color("grey6", 15, 15, 15); + add_color("gray7", 18, 18, 18); + add_color("grey7", 18, 18, 18); + add_color("gray8", 20, 20, 20); + add_color("grey8", 20, 20, 20); + add_color("gray9", 23, 23, 23); + add_color("grey9", 23, 23, 23); + add_color("gray10", 26, 26, 26); + add_color("grey10", 26, 26, 26); + add_color("gray11", 28, 28, 28); + add_color("grey11", 28, 28, 28); + add_color("gray12", 31, 31, 31); + add_color("grey12", 31, 31, 31); + add_color("gray13", 33, 33, 33); + add_color("grey13", 33, 33, 33); + add_color("gray14", 36, 36, 36); + add_color("grey14", 36, 36, 36); + add_color("gray15", 38, 38, 38); + add_color("grey15", 38, 38, 38); + add_color("gray16", 41, 41, 41); + add_color("grey16", 41, 41, 41); + add_color("gray17", 43, 43, 43); + add_color("grey17", 43, 43, 43); + add_color("gray18", 46, 46, 46); + add_color("grey18", 46, 46, 46); + add_color("gray19", 48, 48, 48); + add_color("grey19", 48, 48, 48); + add_color("gray20", 51, 51, 51); + add_color("grey20", 51, 51, 51); + add_color("gray21", 54, 54, 54); + add_color("grey21", 54, 54, 54); + add_color("gray22", 56, 56, 56); + add_color("grey22", 56, 56, 56); + add_color("gray23", 59, 59, 59); + add_color("grey23", 59, 59, 59); + add_color("gray24", 61, 61, 61); + add_color("grey24", 61, 61, 61); + add_color("gray25", 64, 64, 64); + add_color("grey25", 64, 64, 64); + add_color("gray26", 66, 66, 66); + add_color("grey26", 66, 66, 66); + add_color("gray27", 69, 69, 69); + add_color("grey27", 69, 69, 69); + add_color("gray28", 71, 71, 71); + add_color("grey28", 71, 71, 71); + add_color("gray29", 74, 74, 74); + add_color("grey29", 74, 74, 74); + add_color("gray30", 77, 77, 77); + add_color("grey30", 77, 77, 77); + add_color("gray31", 79, 79, 79); + add_color("grey31", 79, 79, 79); + add_color("gray32", 82, 82, 82); + add_color("grey32", 82, 82, 82); + add_color("gray33", 84, 84, 84); + add_color("grey33", 84, 84, 84); + add_color("gray34", 87, 87, 87); + add_color("grey34", 87, 87, 87); + add_color("gray35", 89, 89, 89); + add_color("grey35", 89, 89, 89); + add_color("gray36", 92, 92, 92); + add_color("grey36", 92, 92, 92); + add_color("gray37", 94, 94, 94); + add_color("grey37", 94, 94, 94); + add_color("gray38", 97, 97, 97); + add_color("grey38", 97, 97, 97); + add_color("gray39", 99, 99, 99); + add_color("grey39", 99, 99, 99); + add_color("gray40", 102, 102, 102); + add_color("grey40", 102, 102, 102); + add_color("gray41", 105, 105, 105); + add_color("grey41", 105, 105, 105); + add_color("gray42", 107, 107, 107); + add_color("grey42", 107, 107, 107); + add_color("gray43", 110, 110, 110); + add_color("grey43", 110, 110, 110); + add_color("gray44", 112, 112, 112); + add_color("grey44", 112, 112, 112); + add_color("gray45", 115, 115, 115); + add_color("grey45", 115, 115, 115); + add_color("gray46", 117, 117, 117); + add_color("grey46", 117, 117, 117); + add_color("gray47", 120, 120, 120); + add_color("grey47", 120, 120, 120); + add_color("gray48", 122, 122, 122); + add_color("grey48", 122, 122, 122); + add_color("gray49", 125, 125, 125); + add_color("grey49", 125, 125, 125); + add_color("gray50", 127, 127, 127); + add_color("grey50", 127, 127, 127); + add_color("gray51", 130, 130, 130); + add_color("grey51", 130, 130, 130); + add_color("gray52", 133, 133, 133); + add_color("grey52", 133, 133, 133); + add_color("gray53", 135, 135, 135); + add_color("grey53", 135, 135, 135); + add_color("gray54", 138, 138, 138); + add_color("grey54", 138, 138, 138); + add_color("gray55", 140, 140, 140); + add_color("grey55", 140, 140, 140); + add_color("gray56", 143, 143, 143); + add_color("grey56", 143, 143, 143); + add_color("gray57", 145, 145, 145); + add_color("grey57", 145, 145, 145); + add_color("gray58", 148, 148, 148); + add_color("grey58", 148, 148, 148); + add_color("gray59", 150, 150, 150); + add_color("grey59", 150, 150, 150); + add_color("gray60", 153, 153, 153); + add_color("grey60", 153, 153, 153); + add_color("gray61", 156, 156, 156); + add_color("grey61", 156, 156, 156); + add_color("gray62", 158, 158, 158); + add_color("grey62", 158, 158, 158); + add_color("gray63", 161, 161, 161); + add_color("grey63", 161, 161, 161); + add_color("gray64", 163, 163, 163); + add_color("grey64", 163, 163, 163); + add_color("gray65", 166, 166, 166); + add_color("grey65", 166, 166, 166); + add_color("gray66", 168, 168, 168); + add_color("grey66", 168, 168, 168); + add_color("gray67", 171, 171, 171); + add_color("grey67", 171, 171, 171); + add_color("gray68", 173, 173, 173); + add_color("grey68", 173, 173, 173); + add_color("gray69", 176, 176, 176); + add_color("grey69", 176, 176, 176); + add_color("gray70", 179, 179, 179); + add_color("grey70", 179, 179, 179); + add_color("gray71", 181, 181, 181); + add_color("grey71", 181, 181, 181); + add_color("gray72", 184, 184, 184); + add_color("grey72", 184, 184, 184); + add_color("gray73", 186, 186, 186); + add_color("grey73", 186, 186, 186); + add_color("gray74", 189, 189, 189); + add_color("grey74", 189, 189, 189); + add_color("gray75", 191, 191, 191); + add_color("grey75", 191, 191, 191); + add_color("gray76", 194, 194, 194); + add_color("grey76", 194, 194, 194); + add_color("gray77", 196, 196, 196); + add_color("grey77", 196, 196, 196); + add_color("gray78", 199, 199, 199); + add_color("grey78", 199, 199, 199); + add_color("gray79", 201, 201, 201); + add_color("grey79", 201, 201, 201); + add_color("gray80", 204, 204, 204); + add_color("grey80", 204, 204, 204); + add_color("gray81", 207, 207, 207); + add_color("grey81", 207, 207, 207); + add_color("gray82", 209, 209, 209); + add_color("grey82", 209, 209, 209); + add_color("gray83", 212, 212, 212); + add_color("grey83", 212, 212, 212); + add_color("gray84", 214, 214, 214); + add_color("grey84", 214, 214, 214); + add_color("gray85", 217, 217, 217); + add_color("grey85", 217, 217, 217); + add_color("gray86", 219, 219, 219); + add_color("grey86", 219, 219, 219); + add_color("gray87", 222, 222, 222); + add_color("grey87", 222, 222, 222); + add_color("gray88", 224, 224, 224); + add_color("grey88", 224, 224, 224); + add_color("gray89", 227, 227, 227); + add_color("grey89", 227, 227, 227); + add_color("gray90", 229, 229, 229); + add_color("grey90", 229, 229, 229); + add_color("gray91", 232, 232, 232); + add_color("grey91", 232, 232, 232); + add_color("gray92", 235, 235, 235); + add_color("grey92", 235, 235, 235); + add_color("gray93", 237, 237, 237); + add_color("grey93", 237, 237, 237); + add_color("gray94", 240, 240, 240); + add_color("grey94", 240, 240, 240); + add_color("gray95", 242, 242, 242); + add_color("grey95", 242, 242, 242); + add_color("gray96", 245, 245, 245); + add_color("grey96", 245, 245, 245); + add_color("gray97", 247, 247, 247); + add_color("grey97", 247, 247, 247); + add_color("gray98", 250, 250, 250); + add_color("grey98", 250, 250, 250); + add_color("gray99", 252, 252, 252); + add_color("grey99", 252, 252, 252); + add_color("gray100", 255, 255, 255); + add_color("grey100", 255, 255, 255); + add_color("dark grey", 169, 169, 169); + add_color("DarkGrey", 169, 169, 169); + add_color("dark gray", 169, 169, 169); + add_color("DarkGray", 169, 169, 169); + add_color("dark blue", 0, 0, 139); + add_color("DarkBlue", 0, 0, 139); + add_color("dark cyan", 0, 139, 139); + add_color("DarkCyan", 0, 139, 139); + add_color("dark magenta", 139, 0, 139); + add_color("DarkMagenta", 139, 0, 139); + add_color("dark red", 139, 0, 0); + add_color("DarkRed", 139, 0, 0); + add_color("light green", 144, 238, 144); + add_color("LightGreen", 144, 238, 144); + add_color("crimson", 220, 20, 60); + add_color("indigo", 75, 0, 130); + add_color("olive", 128, 128, 0); + add_color("rebecca purple", 102, 51, 153); + add_color("RebeccaPurple", 102, 51, 153); + add_color("silver", 192, 192, 192); + add_color("teal", 0, 128, 128); } diff --git a/src/core.c b/src/core.c index 6476ccbb..c27b1a60 100644 --- a/src/core.c +++ b/src/core.c @@ -6,6 +6,8 @@ #define PERIODIC #endif +#define RESIZE_ON_TICK + #define DRAW(handle) \ { \ MwLLBeginDraw(handle->lowlevel); \ @@ -18,6 +20,19 @@ MwLLEndDraw(handle->lowlevel); \ } +#define RESIZE(handle) \ + { \ + int RESIZE_i; \ + MwDispatchUserHandler(handle, MwNresizeHandler, NULL); \ + for(RESIZE_i = 0; RESIZE_i < arrlen(handle->children); RESIZE_i++) { \ + MwDispatch(handle->children[RESIZE_i], parent_resize); \ + } \ + MwDispatch(handle, resize); \ + } + +static void MWAPI MwVaListApply_Internal(MwWidget handle, va_list va, int only_early); +static MwWidget MWAPI MwCreateWidget_Internal(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, int do_prop, va_list prop); + static void lldrawhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; #ifdef PERIODIC @@ -54,6 +69,7 @@ static void lldrawhandler(MwLL handle, void* data) { static void lluphandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; MwMouse* p = data; + if(MwGetInteger(h, MwNdisabled) == 1) return; if(p->button == MwMOUSE_LEFT) h->pressed = 0; h->mouse_point.x = p->point.x; @@ -67,6 +83,7 @@ static void lluphandler(MwLL handle, void* data) { static void lldownhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; MwMouse* p = data; + if(MwGetInteger(h, MwNdisabled) == 1) return; if(p->button == MwMOUSE_LEFT) h->pressed = 1; h->mouse_point.x = p->point.x; @@ -78,16 +95,35 @@ static void lldownhandler(MwLL handle, void* data) { static void llresizehandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; - int i; +#ifdef RESIZE_ON_TICK + MwWidget top; +#endif (void)data; - MwDispatchUserHandler(h, MwNresizeHandler, NULL); - for(i = 0; i < arrlen(h->children); i++) { - MwDispatch(h->children[i], parent_resize); - MwDispatch(h->children[i], draw); +#ifdef RESIZE_ON_TICK + top = h; + while(top != NULL) { + if(top->top_step) { + break; + } + + top = top->parent; } - MwDispatch(h, resize); + + if(top == NULL) { + RESIZE(h); /* fallback */ + } else { + int i; + + for(i = 0; i < arrlen(top->resize_queue); i++) { + if(top->resize_queue[i] == h) break; + } + if(i == arrlen(top->resize_queue)) arrput(top->resize_queue, h); + } +#else + RESIZE(h); +#endif } static void llclosehandler(MwLL handle, void* data) { @@ -109,8 +145,9 @@ static void llclosehandler(MwLL handle, void* data) { } static void llmovehandler(MwLL handle, void* data) { - MwWidget h = (MwWidget)handle->common.user; - MwPoint* p = data; + MwWidget h = (MwWidget)handle->common.user; + MwPoint* p = data; + h->mouse_point.x = p->x; h->mouse_point.y = p->y; @@ -121,6 +158,7 @@ static void llmovehandler(MwLL handle, void* data) { static void llkeyhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; int key = *(int*)data; + if(MwGetInteger(h, MwNdisabled) == 1) return; MwDispatch3(h, key, key); MwDispatchUserHandler(h, MwNkeyHandler, data); @@ -128,29 +166,40 @@ static void llkeyhandler(MwLL handle, void* data) { static void llkeyrelhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; MwDispatchUserHandler(h, MwNkeyReleaseHandler, data); } static void llfocusinhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; MwDispatchUserHandler(h, MwNfocusInHandler, data); } static void llfocusouthandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; MwDispatchUserHandler(h, MwNfocusOutHandler, data); } static void llclipboardhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; MwDispatch3(h, clipboard, data); MwDispatchUserHandler(h, MwNclipboardHandler, data); } +static void lldraganddrophandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatchUserHandler(h, MwNdragAndDropHandler, data); +} + /* if both of them are true * 1. widget class is not NULL * 2. parent is NULL @@ -167,67 +216,84 @@ static void llclipboardhandler(MwLL handle, void* data) { static void lldarkthemehandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; int* ptr = data; + int s; - if(IsFirstVisible(h)) { - MwVaApply(h, - MwNdarkTheme, *ptr, - NULL); + if(h->widget_class == MwWindowClass && (shgeti(h->integer, MwNdarkTheme) == -1 || ((s = MwGetInteger(h, MwNdarkThemeAutomatic)) != MwDEFAULT && s))) { + if(MwGetInteger(h, MwNmodernLook)) { + MwVaApply(h, + MwNdarkTheme, *ptr, + MwNdarkThemeAutomatic, 1, + NULL); - MwDispatchUserHandler(h, MwNdarkThemeHandler, data); + MwDispatchUserHandler(h, MwNdarkThemeHandler, data); + } } } -MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { +static MwWidget MwCreateWidget_Internal(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, int do_prop, va_list prop) { MwWidget h = malloc(sizeof(*h)); - h->name = MwStringDuplicate(name); + if(name) + h->name = MwStringDuplicate(name); + else + h->name = NULL; h->parent = parent; h->children = NULL; if(widget_class != NULL) { if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) { - free(h->name); + if(h->name) { + free(h->name); + } free(h); return NULL; } } else { h->lowlevel = NULL; } - h->widget_class = widget_class; - h->pressed = 0; - h->close = 0; - h->destroy_queue = NULL; - h->prop_event = 1; - h->draw_inject = NULL; - h->tick_list = NULL; - h->destroyed = 0; - h->bgcolor = NULL; - h->berserk = 0; + h->widget_class = widget_class; + h->pressed = 0; + h->close = 0; + h->destroy_queue = NULL; + h->prop_event = 1; + h->draw_inject = NULL; + h->destroy_inject = NULL; + h->tick_list = NULL; + h->destroyed = 0; + h->bgcolor = NULL; - h->top_step = 0; - h->draw_queue = NULL; + h->berserk = 0; + h->last_tick = MwTimeGetTick(); + + h->internal = NULL; + h->opaque = NULL; + h->user = NULL; + + h->top_step = 0; + h->draw_queue = NULL; + h->resize_queue = NULL; + h->monitored_entries = NULL; if(parent == NULL) arrput(h->tick_list, h); -#ifdef PERIODIC if(parent == NULL) h->top_step = 1; -#endif if(h->lowlevel != NULL) { - h->lowlevel->common.user = h; - h->lowlevel->common.handler->draw = lldrawhandler; - h->lowlevel->common.handler->up = lluphandler; - h->lowlevel->common.handler->down = lldownhandler; - h->lowlevel->common.handler->resize = llresizehandler; - h->lowlevel->common.handler->close = llclosehandler; - h->lowlevel->common.handler->move = llmovehandler; - h->lowlevel->common.handler->key = llkeyhandler; - h->lowlevel->common.handler->key_released = llkeyrelhandler; - h->lowlevel->common.handler->focus_in = llfocusinhandler; - h->lowlevel->common.handler->focus_out = llfocusouthandler; - h->lowlevel->common.handler->clipboard = llclipboardhandler; - h->lowlevel->common.handler->dark_theme = lldarkthemehandler; + h->lowlevel->common.user = h; + h->lowlevel->common.handler->draw = lldrawhandler; + h->lowlevel->common.handler->up = lluphandler; + h->lowlevel->common.handler->down = lldownhandler; + h->lowlevel->common.handler->resize = llresizehandler; + h->lowlevel->common.handler->close = llclosehandler; + h->lowlevel->common.handler->move = llmovehandler; + h->lowlevel->common.handler->key = llkeyhandler; + h->lowlevel->common.handler->key_released = llkeyrelhandler; + h->lowlevel->common.handler->focus_in = llfocusinhandler; + h->lowlevel->common.handler->focus_out = llfocusouthandler; + h->lowlevel->common.handler->clipboard = llclipboardhandler; + h->lowlevel->common.handler->dark_theme = lldarkthemehandler; + h->lowlevel->common.handler->drag_and_drop = lldraganddrophandler; } if(parent != NULL) arrput(parent->children, h); @@ -242,6 +308,8 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, shdefault(h->handler, NULL); shdefault(h->data, NULL); + if(do_prop) MwVaListApply_Internal(h, prop, 1); + h->prop_event = 0; if(MwDispatch2(h, create) != 0) { h->widget_class = NULL; @@ -257,24 +325,43 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, MwAddTickList(h); } -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) if(IsFirstVisible(h)) { +#ifdef USE_STB_TRUETYPE + font_setup: +#endif h->root_font = MwFontLoad(MwTTFData, MwTTFDataSize); h->root_boldfont = MwFontLoad(MwBoldTTFData, MwBoldTTFDataSize); h->root_monofont = MwFontLoad(MwMonospaceTTFData, MwMonospaceTTFDataSize); h->root_boldmonofont = MwFontLoad(MwBoldMonospaceTTFData, MwBoldMonospaceTTFDataSize); + if(!h->root_font) { +#ifdef USE_STB_TRUETYPE + MwFL_STBTTSetup(); + goto font_setup; +#endif + } } else #endif { - h->root_font = NULL; - h->root_boldfont = NULL; + h->root_font = NULL; + h->root_boldfont = NULL; + h->root_monofont = NULL; + h->root_boldmonofont = NULL; } - if(h->parent != NULL) MwDispatch(h->parent, children_update); + if(h->parent != NULL) MwDispatch4(h->parent, children_update, h, 1); return h; } +MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { + va_list dummy; + + memset(&dummy, 0, sizeof(dummy)); + + return MwCreateWidget_Internal(widget_class, name, parent, x, y, width, height, 0, dummy); +} + MwWidget MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, ...) { MwWidget h; va_list va; @@ -288,14 +375,23 @@ MwWidget MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget paren MwWidget MwVaListCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, va_list va) { MwWidget h; + va_list va2; - h = MwCreateWidget(widget_class, name, parent, x, y, width, height); - MwVaListApply(h, va); +#ifdef va_copy + va_copy(va2, va); +#else + va2 = va; +#endif + + h = MwCreateWidget_Internal(widget_class, name, parent, x, y, width, height, 1, va); + MwVaListApply(h, va2); + + va_end(va2); return h; } -static void MwFreeWidget(MwWidget handle) { +void MwFreeWidget(MwWidget handle) { int i; MwWidget root = handle; MwWidget w; @@ -316,11 +412,13 @@ static void MwFreeWidget(MwWidget handle) { } handle->destroyed = 0; + if(handle->destroy_inject != NULL) handle->destroy_inject(handle); MwDispatch(handle, destroy); for(i = 0; i < arrlen(handle->children); i++) { MwFreeWidget(handle->children[i]); } + arrfree(handle->children); while(root->parent != NULL) root = root->parent; for(i = 0; i < arrlen(root->tick_list); i++) { @@ -330,7 +428,7 @@ static void MwFreeWidget(MwWidget handle) { } } - free(handle->name); + if(handle->name) free(handle->name); if(handle->lowlevel != NULL) MwLLDestroy(handle->lowlevel); @@ -351,9 +449,12 @@ static void MwFreeWidget(MwWidget handle) { arrfree(handle->tick_list); arrfree(handle->draw_queue); + arrfree(handle->resize_queue); if(handle->root_font != NULL) MwFontFree(handle->root_font); if(handle->root_boldfont != NULL) MwFontFree(handle->root_boldfont); + if(handle->root_monofont != NULL) MwFontFree(handle->root_monofont); + if(handle->root_boldmonofont != NULL) MwFontFree(handle->root_boldmonofont); free(handle); } @@ -367,6 +468,8 @@ static void destroy_children(MwWidget handle) { } void MwDestroyWidget(MwWidget handle) { + if(handle->destroyed) return; + if(handle->parent != NULL) { int i; for(i = 0; i < arrlen(handle->parent->destroy_queue); i++) { @@ -376,7 +479,7 @@ void MwDestroyWidget(MwWidget handle) { arrput(handle->parent->destroy_queue, handle); } - MwDispatch(handle->parent, children_update); + MwDispatch4(handle->parent, children_update, handle, 0); } destroy_children(handle); handle->destroyed = 1; @@ -414,25 +517,41 @@ static void clean_destroy_queue(MwWidget handle) { } static void MwAfterStep(MwWidget handle) { + int i; + #ifdef PERIODIC if(handle->top_step) { - int i; - for(i = 0; i < arrlen(handle->draw_queue); i++) { DRAW(handle->draw_queue[i]); } arrfree(handle->draw_queue); } -#else - (void)handle; #endif + +#ifdef RESIZE_ON_TICK + if(handle->top_step) { + for(i = 0; i < arrlen(handle->resize_queue); i++) { + RESIZE(handle->resize_queue[i]); + } + + arrfree(handle->resize_queue); + } +#endif + + if(arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= (MwGetInteger(handle, MwNwaitMS) == MwDEFAULT ? MwWaitMS : MwGetInteger(handle, MwNwaitMS))) { + for(i = 0; i < arrlen(handle->tick_list); i++) { + MwDispatch(handle->tick_list[i], tick); + MwDispatchUserHandler(handle->tick_list[i], MwNtickHandler, NULL); + } + + handle->last_tick = MwTimeGetTick(); + } } int MwStep(MwWidget handle) { int i; MwWidget* widgets = NULL; - if(setjmp(handle->before_step)) return 0; for(i = 0; i < arrlen(handle->children); i++) { arrput(widgets, handle->children[i]); } @@ -454,6 +573,7 @@ int MwStep(MwWidget handle) { MwFreeWidget(handle); return 1; } + return 0; } @@ -462,12 +582,11 @@ int MwPending(MwWidget handle) { for(i = 0; i < arrlen(handle->children); i++) { if(MwPending(handle->children[i])) return 1; } - return (arrlen(handle->destroy_queue) > 0) || (handle->widget_class == NULL ? 0 : MwLLPending(handle->lowlevel)); + return (arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= (MwGetInteger(handle, MwNwaitMS) == MwDEFAULT ? MwWaitMS : MwGetInteger(handle, MwNwaitMS))) || (arrlen(handle->destroy_queue) > 0) || (handle->widget_class == NULL ? 0 : MwLLPending(handle->lowlevel)); } void MwLoop(MwWidget handle) { long tick = MwTimeGetTick(); - int i; long wait = MwGetInteger(handle, MwNwaitMS); long over = 0; if(wait == MwDEFAULT) wait = MwWaitMS; @@ -480,11 +599,6 @@ void MwLoop(MwWidget handle) { } if(v != 0) break; - for(i = 0; i < arrlen(handle->tick_list); i++) { - MwDispatch(handle->tick_list[i], tick); - MwDispatchUserHandler(handle->tick_list[i], MwNtickHandler, NULL); - } - more = over % (wait / 2); t = (tick + wait - more) - (t2 = MwTimeGetTick()); if(t > 0) { @@ -524,9 +638,20 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { shput(handle->integer, key, n); } if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); } + if(strcmp(key, MwNforceInverted) == 0) { MwForceRender(handle); } @@ -537,14 +662,22 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { if(strcmp(key, MwNdarkTheme) == 0) { MwWidget h = handle; - while(h->parent != NULL && h->parent->widget_class != NULL) h = h->parent; + shdel(h->integer, MwNdarkThemeAutomatic); - MwLLSetDarkTheme(h->lowlevel, n); + if(h->widget_class != MwWindowClass) { + while(h->parent != NULL && h->parent->widget_class != MwWindowClass) h = h->parent; + } + + if(h->lowlevel != NULL) MwLLSetDarkTheme(h->lowlevel, n); + } + + if(strcmp(key, MwNacceptsDnD) == 0) { + if(handle->lowlevel != NULL) MwLLSetupDragAndDrop(handle->lowlevel); } } void MwSetText(MwWidget handle, const char* key, const char* value) { - if(strcmp(key, MwNtitle) == 0) { + if(handle->widget_class == MwWindowClass && strcmp(key, MwNtitle) == 0) { MwLLSetTitle(handle->lowlevel, value); } else { char* v = value == NULL ? NULL : MwStringDuplicate(value); @@ -558,16 +691,27 @@ void MwSetText(MwWidget handle, const char* key, const char* value) { } } if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); } + if(strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0) { MwForceRender(handle); } } void MwSetVoid(MwWidget handle, const char* key, void* value) { - if(strcmp(key, MwNiconPixmap) == 0) { + if(IsFirstVisible(handle) && strcmp(key, MwNiconPixmap) == 0) { MwLLSetIcon(handle->lowlevel, value); } else if(strcmp(key, MwNsizeHints) == 0) { MwSizeHints* sz = value; @@ -579,7 +723,17 @@ void MwSetVoid(MwWidget handle, const char* key, void* value) { shput(handle->data, key, value); } if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); } } @@ -607,7 +761,7 @@ int MwGetInteger(MwWidget handle, const char* key) { return MwDEFAULT; } else { if(shgeti(handle->integer, key) == -1) { -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 0); #else if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 1); @@ -615,22 +769,25 @@ int MwGetInteger(MwWidget handle, const char* key) { #ifdef USE_CLASSIC_THEME if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 0); #else - if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 1); + if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, MwLLDoModern(handle->lowlevel)); #endif if(strcmp(key, MwNdarkTheme) == 0) return inherit_integer(handle, key, 0); if(strcmp(key, MwNuseMonospace) == 0) return inherit_integer(handle, key, 0); + if(strcmp(key, MwNdisabled) == 0) return inherit_integer(handle, key, 0); } return shget(handle->integer, key); } } const char* MwGetText(MwWidget handle, const char* key) { - if(shgeti(handle->text, key) == -1 && (strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0)) { + if((shgeti(handle->text, key) == -1 || strcmp(shget(handle->text, key), "DEFAULT") == 0) && (strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0 || strcmp(key, MwNtitleBackground) == 0 || strcmp(key, MwNtitleForeground) == 0)) { const char* v = NULL; - MwWidget h = handle->parent; - while(h != NULL) { - if((v = MwGetText(h, key)) != NULL) break; - h = h->parent; + if(shgeti(handle->text, key) != -1 && strcmp(shget(handle->text, key), "DEFAULT") != 0) { + MwWidget h = handle->parent; + while(h != NULL) { + if((v = MwGetText(h, key)) != NULL) break; + h = h->parent; + } } if(v == NULL) { if(MwGetInteger(handle, MwNdarkTheme)) { @@ -638,11 +795,15 @@ const char* MwGetText(MwWidget handle, const char* key) { if(strcmp(key, MwNforeground) == 0) return MwDefaultDarkForeground; if(strcmp(key, MwNsubBackground) == 0) return MwDefaultDarkSubBackground; if(strcmp(key, MwNsubForeground) == 0) return MwDefaultDarkSubForeground; + if(strcmp(key, MwNtitleBackground) == 0) return MwDefaultDarkTitleBackground; + if(strcmp(key, MwNtitleForeground) == 0) return MwDefaultDarkTitleForeground; } else { if(strcmp(key, MwNbackground) == 0) return MwDefaultBackground; if(strcmp(key, MwNforeground) == 0) return MwDefaultForeground; if(strcmp(key, MwNsubBackground) == 0) return MwDefaultSubBackground; if(strcmp(key, MwNsubForeground) == 0) return MwDefaultSubForeground; + if(strcmp(key, MwNtitleBackground) == 0) return MwDefaultTitleBackground; + if(strcmp(key, MwNtitleForeground) == 0) return MwDefaultTitleForeground; } } return v; @@ -651,7 +812,7 @@ const char* MwGetText(MwWidget handle, const char* key) { return shget(handle->text, key); } -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) static void* inherit_void(MwWidget handle, const char* key) { void* v; @@ -667,7 +828,7 @@ void* MwGetVoid(MwWidget handle, const char* key) { if(v != NULL) return v; -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) if(strcmp(key, MwNfont) == 0 || strcmp(key, MwNboldFont) == 0 || strcmp(key, MwNmonospaceFont) == 0 || strcmp(key, MwNboldMonospaceFont) == 0) { v = inherit_void(handle, key); @@ -702,13 +863,23 @@ void MwVaApply(MwWidget handle, ...) { va_end(va); } -void MwVaListApply(MwWidget handle, va_list va) { - char* key; - int x = MwDEFAULT, y = MwDEFAULT, w = MwDEFAULT, h = MwDEFAULT; +static void MwVaListApply_Internal(MwWidget handle, va_list va, int only_early) { + char* key; + int x = MwDEFAULT, y = MwDEFAULT, w = MwDEFAULT, h = MwDEFAULT; + char** keys = NULL; + int old = handle->prop_event; + int i; + handle->prop_event = 0; while((key = va_arg(va, char*)) != NULL) { + if(!only_early || key[1] == 'E') { + arrput(keys, key); + } + if(key[0] == 'I') { int n = va_arg(va, int); + if(only_early && key[1] != 'E') continue; + if(strcmp(key, MwNx) == 0) { x = n; } else if(strcmp(key, MwNy) == 0) { @@ -722,12 +893,17 @@ void MwVaListApply(MwWidget handle, va_list va) { } } else if(key[0] == 'S') { char* t = va_arg(va, char*); + if(only_early && key[1] != 'E') continue; + MwSetText(handle, key, t); } else if(key[0] == 'C') { MwUserHandler h = va_arg(va, MwUserHandler); + if(only_early && key[1] != 'E') continue; + MwAddUserHandler(handle, key, h, NULL); } else if(key[0] == 'V') { void* v = va_arg(va, void*); + if(only_early && key[1] != 'E') continue; MwSetVoid(handle, key, v); } } @@ -757,6 +933,23 @@ void MwVaListApply(MwWidget handle, va_list va) { MwSetInteger(handle, MwNheight, h); } } + handle->prop_event = old; + + arrput(keys, NULL); + + if(handle->prop_event) { + for(i = 0; keys[i] != NULL; i++) { + MwDispatch3(handle, prop_change, keys[i]); + } + + MwDispatch3(handle, props_change, keys); + } + + arrfree(keys); +} + +void MwVaListApply(MwWidget handle, va_list va) { + MwVaListApply_Internal(handle, va, 0); } void MwSetDefault(MwWidget handle) { @@ -771,6 +964,7 @@ void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data) int ind = shgeti(handle->handler, key); int p = handle->prop_event; int i; + if(ind == -1) return; if(handle->destroyed) return; @@ -823,20 +1017,28 @@ void MwDispatchError(int code, const char* message) { } } -void MwGetBeforeStep(MwWidget handle, jmp_buf* jmpbuf) { - memcpy(jmpbuf, &handle->before_step, sizeof(*jmpbuf)); -} - +#undef MwForceRender void MwForceRender(MwWidget handle) { MwLLForceRender(handle->lowlevel); } +#undef MwForceRender2 void MwForceRender2(MwWidget handle, void* ptr) { (void)ptr; MwForceRender(handle); } +void MwForceRender_Internal(MwWidget handle) { + MwForceRender(handle); +} + +void MwForceRender2_Internal(MwWidget handle, void* ptr) { + (void)ptr; + + MwForceRender(handle); +} + void MwAddTickList(MwWidget handle) { MwWidget root = handle; while(root->parent != NULL) root = root->parent; @@ -867,9 +1069,8 @@ typedef int (*call_t)(void); int MwLibraryInit(void) { call_t calls[] = { #ifdef USE_WAYLAND - MwLLWaylandCallInit, + NULL, /* set in a bit */ #endif -/* x11 has higher priority then cocoa until it works */ #ifdef USE_X11 MwLLX11CallInit, #endif @@ -881,16 +1082,46 @@ int MwLibraryInit(void) { #endif #ifdef CLASSIC_MAC_OS MwLLClassicMacOSCallInit, +#endif +#ifdef USE_HAIKU + MwLLHaikuCallInit, #endif NULL}; int i; +#ifdef _WIN32 + /* + There's no Windows configuration that Milsko supports that doesn't have winmm. + However, uhh, Visual Studio 2022. For some fucking reason. + Thanks for coming to my TED Talk. + */ + MwLL_winmmLib = LoadLibrary("winmm.dll"); + MwLL_PFN_timeGetTime = (void *)GetProcAddress(MwLL_winmmLib, "timeGetTime"); + MwLL_PFN_timeBeginPeriod = (void *)GetProcAddress(MwLL_winmmLib, "timeBeginPeriod"); + + MwLL_PFN_timeBeginPeriod(10); +#endif + +#ifdef USE_WAYLAND + if(MwWaylandCairoOnly) { + calls[0] = MwLLCairoCallInit; + } else { + calls[0] = MwLLWaylandCallInit; + } +#endif + + MwColorTableInit(); + MwFLSetup(); for(i = 0; calls[i] != NULL; i++) { if(calls[i]() == 0) return 0; } +#ifdef __APPLE__ + void MwLLNoCocoaErrorMessage(void); + MwLLNoCocoaErrorMessage(); +#else printf("[WARNING] No suitable GUI backend found! Enabled:" #ifdef USE_COCOA " Cocoa" @@ -908,7 +1139,7 @@ int MwLibraryInit(void) { " ClassicMacOS" #endif "\n"); - +#endif return 1; } @@ -926,13 +1157,23 @@ void MwReparent(MwWidget handle, MwWidget new_parent) { } } - MwDispatch(handle->parent, children_update); + MwDispatch4(handle->parent, children_update, handle, 0); } handle->parent = new_parent; - arrput(new_parent->children, handle); + if(new_parent != NULL) { + arrput(new_parent->children, handle); - MwDispatch(handle->parent, children_update); + MwDispatch4(handle->parent, children_update, handle, 1); + } + + if(new_parent == NULL) { + handle->top_step = 1; + arrput(handle->tick_list, handle); + } else { + handle->top_step = 0; + arrfree(handle->tick_list); + } MwForceRender(handle); } @@ -976,3 +1217,20 @@ int MwGetCoordinateType(MwWidget handle) { void MwGetClipboard(MwWidget handle, int clipboard_type) { MwLLGetClipboard(handle->lowlevel, clipboard_type); } + +void MwSetUser(MwWidget handle, void* user) { + handle->user = user; +} + +void* MwGetUser(MwWidget handle) { + return handle->user; +} + +void MwGetFrame(MwWidget handle, MwRect* rect) { + rect->x = MwGetInteger(handle, MwNx); + rect->y = MwGetInteger(handle, MwNy); + rect->width = MwGetInteger(handle, MwNwidth); + rect->height = MwGetInteger(handle, MwNheight); +} + +const char* MwVersionString = MwVERSION; diff --git a/src/cursor/arrow.c b/src/cursor/arrow.c index ca53c5e4..5a1d9bff 100644 --- a/src/cursor/arrow.c +++ b/src/cursor/arrow.c @@ -1,51 +1,29 @@ #include /** + * Created by bitmaptobdf + * * Copyright notice: - * Copyright (c) Digital Equipment Corporation,1988. All Rights Reserved. - */ -/** - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notices appear in all copies and - * that both those copyright notices and this permission notice appear - * in supporting documentation, and that the name - * Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the software without - * specific, written prior permission. Digital - * Equipment Corporation makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * DIGITAL EQUIPMENT CORPORATION DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * These ""glyphs"" are unencumbered */ MwCursor MwCursorArrow = { - 16, 16, -15, -15, { - 0, /* ................ */ - 6, /* .............##. */ - 30, /* ...........####. */ - 124, /* .........#####.. */ - 508, /* .......#######.. */ - 2040, /* .....########... */ - 8184, /* ...##########... */ - 496, /* .......#####.... */ - 1008, /* ......######.... */ - 1888, /* .....###.##..... */ - 3680, /* ....###..##..... */ - 7232, /* ...###...#...... */ - 14400, /* ..###....#...... */ - 28672, /* .###............ */ - 8192, /* ..#............. */ - 0 /* ................ */ - }}; + 14, 14, -13, -14, {3, /* ............## */ + 15, /* ..........#### */ + 62, /* ........#####. */ + 254, /* ......#######. */ + 1020, /* ....########.. */ + 4092, /* ..##########.. */ + 248, /* ......#####... */ + 504, /* .....######... */ + 944, /* ....###.##.... */ + 1840, /* ...###..##.... */ + 3616, /* ..###...#..... */ + 7200, /* .###....#..... */ + 14336, /* ###........... */ + 4096, /* .#............ */ + 0, 0}}; MwCursor MwCursorArrowMask = { - 16, 16, -15, -15, { + 16, 16, -14, -15, { 7, /* .............### */ 31, /* ...........##### */ 127, /* .........####### */ @@ -53,7 +31,7 @@ MwCursor MwCursorArrowMask = { 2046, /* .....##########. */ 8188, /* ...###########.. */ 16380, /* ..############.. */ - 8184, /* ...##########... */ + 16376, /* ..###########... */ 2040, /* .....########... */ 4080, /* ....########.... */ 8176, /* ...#########.... */ diff --git a/src/cursor/cross.c b/src/cursor/cross.c index 94655103..8c53739b 100644 --- a/src/cursor/cross.c +++ b/src/cursor/cross.c @@ -1,55 +1,8 @@ #include /** + * Created by bitmaptobdf + * * Copyright notice: - * Copyright (c) Digital Equipment Corporation,1988. All Rights Reserved. + * These ""glyphs"" are unencumbered */ -/** - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notices appear in all copies and - * that both those copyright notices and this permission notice appear - * in supporting documentation, and that the name - * Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the software without - * specific, written prior permission. Digital - * Equipment Corporation makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * DIGITAL EQUIPMENT CORPORATION DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -MwCursor MwCursorCross = { - 13, 12, -6, -6, {7175, /* ###.......### */ - 4617, /* #..#.....#..# */ - 2322, /* .#..#...#..#. */ - 1188, /* ..#..#.#..#.. */ - 584, /* ...#..#..#... */ - 272, /* ....#...#.... */ - 272, /* ....#...#.... */ - 584, /* ...#..#..#... */ - 1188, /* ..#..#.#..#.. */ - 2322, /* .#..#...#..#. */ - 4617, /* #..#.....#..# */ - 7175, /* ###.......### */ - 0, 0, 0, 0}}; -MwCursor MwCursorCrossMask = { - 13, 12, -6, -6, {7175, /* ###.......### */ - 7695, /* ####.....#### */ - 3870, /* .####...####. */ - 1980, /* ..####.####.. */ - 1016, /* ...#######... */ - 496, /* ....#####.... */ - 496, /* ....#####.... */ - 1016, /* ...#######... */ - 1980, /* ..####.####.. */ - 3870, /* .####...####. */ - 7695, /* ####.....#### */ - 7175, /* ###.......### */ - 0, 0, 0, 0}}; diff --git a/src/cursor/default.c b/src/cursor/default.c index 1116d907..d4bda3cd 100644 --- a/src/cursor/default.c +++ b/src/cursor/default.c @@ -1,65 +1,43 @@ #include /** + * Created by bitmaptobdf + * * Copyright notice: - * Copyright (c) Digital Equipment Corporation,1988. All Rights Reserved. - */ -/** - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notices appear in all copies and - * that both those copyright notices and this permission notice appear - * in supporting documentation, and that the name - * Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the software without - * specific, written prior permission. Digital - * Equipment Corporation makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * DIGITAL EQUIPMENT CORPORATION DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * These ""glyphs"" are unencumbered */ MwCursor MwCursorDefault = { - 16, 16, 0, -15, { - 0, /* ................ */ - 24576, /* .##............. */ - 30720, /* .####........... */ - 15872, /* ..#####......... */ - 16256, /* ..#######....... */ - 8160, /* ...########..... */ - 8184, /* ...##########... */ - 3968, /* ....#####....... */ - 4032, /* ....######...... */ - 1760, /* .....##.###..... */ - 1648, /* .....##..###.... */ - 568, /* ......#...###... */ - 540, /* ......#....###.. */ - 14, /* ............###. */ - 4, /* .............#.. */ - 0 /* ................ */ - }}; + 8, 14, 0, -14, {128, /* #....... */ + 192, /* ##...... */ + 224, /* ###..... */ + 240, /* ####.... */ + 248, /* #####... */ + 252, /* ######.. */ + 254, /* #######. */ + 255, /* ######## */ + 248, /* #####... */ + 216, /* ##.##... */ + 140, /* #...##.. */ + 12, /* ....##.. */ + 6, /* .....##. */ + 6, /* .....##. */ + 0, 0}}; MwCursor MwCursorDefaultMask = { - 16, 16, 0, -15, { - 57344, /* ###............. */ - 63488, /* #####........... */ - 65024, /* #######......... */ - 32640, /* .########....... */ - 32736, /* .##########..... */ - 16376, /* ..###########... */ - 16380, /* ..############.. */ - 8184, /* ...##########... */ - 8160, /* ...########..... */ - 4080, /* ....########.... */ - 4088, /* ....#########... */ - 1916, /* .....###.#####.. */ - 1854, /* .....###..#####. */ - 543, /* ......#....##### */ - 14, /* ............###. */ - 4 /* .............#.. */ - }}; + 10, 16, -1, -15, { + 768, /* ##........ */ + 896, /* ###....... */ + 960, /* ####...... */ + 992, /* #####..... */ + 1008, /* ######.... */ + 1016, /* #######... */ + 1020, /* ########.. */ + 1022, /* #########. */ + 1023, /* ########## */ + 1023, /* ########## */ + 1016, /* #######... */ + 956, /* ###.####.. */ + 828, /* ##..####.. */ + 30, /* .....####. */ + 30, /* .....####. */ + 12 /* ......##.. */ + }}; diff --git a/src/cursor/text.c b/src/cursor/text.c index 4f0ea94d..855f01a3 100644 --- a/src/cursor/text.c +++ b/src/cursor/text.c @@ -1,65 +1,43 @@ #include /** + * Created by bitmaptobdf + * * Copyright notice: - * Copyright (c) Digital Equipment Corporation,1988. All Rights Reserved. - */ -/** - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notices appear in all copies and - * that both those copyright notices and this permission notice appear - * in supporting documentation, and that the name - * Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the software without - * specific, written prior permission. Digital - * Equipment Corporation makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * DIGITAL EQUIPMENT CORPORATION DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * These ""glyphs"" are unencumbered */ MwCursor MwCursorText = { - 7, 16, -3, -7, { - 0, /* ....... */ - 68, /* #...#.. */ - 40, /* .#.#... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 16, /* ..#.... */ - 40, /* .#.#... */ - 68, /* #...#.. */ - 0 /* ....... */ - }}; + 7, 14, -3, -7, {119, /* ###.### */ + 28, /* ..###.. */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 28, /* ..###.. */ + 119, /* ###.### */ + 0, 0}}; MwCursor MwCursorTextMask = { - 7, 16, -3, -7, { - 0, /* ....... */ - 102, /* ##..##. */ - 60, /* .####.. */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 24, /* ..##... */ - 60, /* .####.. */ - 102, /* ##..##. */ - 0 /* ....... */ + 9, 16, -4, -8, { + 495, /* ####.#### */ + 511, /* ######### */ + 511, /* ######### */ + 124, /* ..#####.. */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 124, /* ..#####.. */ + 511, /* ######### */ + 511, /* ######### */ + 495 /* ####.#### */ }}; diff --git a/src/default.c b/src/default.c index 36537a18..44e4c4d6 100644 --- a/src/default.c +++ b/src/default.c @@ -1,14 +1,18 @@ #include -const char* MwDefaultBackground = "#d2d2d2"; -const char* MwDefaultForeground = "#000"; -const char* MwDefaultSubBackground = "#fff"; -const char* MwDefaultSubForeground = "#000"; +const char* MwDefaultBackground = "#d2d2d2"; +const char* MwDefaultForeground = "#000"; +const char* MwDefaultSubBackground = "#fff"; +const char* MwDefaultSubForeground = "#000"; +const char* MwDefaultTitleBackground = "#008"; +const char* MwDefaultTitleForeground = "#fff"; -const char* MwDefaultDarkBackground = "#333"; -const char* MwDefaultDarkForeground = "#ddd"; -const char* MwDefaultDarkSubBackground = "#333"; -const char* MwDefaultDarkSubForeground = "#ddd"; +const char* MwDefaultDarkBackground = "#333"; +const char* MwDefaultDarkForeground = "#ddd"; +const char* MwDefaultDarkSubBackground = "#333"; +const char* MwDefaultDarkSubForeground = "#ddd"; +const char* MwDefaultDarkTitleBackground = "#008"; +const char* MwDefaultDarkTitleForeground = "#fff"; const int MwDefaultShadow = -32; @@ -17,6 +21,18 @@ int MwDefaultBorderWidth(MwWidget handle) { if(bw != MwDEFAULT) return bw; + if(MwGetInteger(handle, MwNmodernLook)) { + return 2; + } else { + return 2; + } +} + +int MwDefaultThinBorderWidth(MwWidget handle) { + int bw = MwGetInteger(handle, MwNborderWidth); + + if(bw != MwDEFAULT) return bw; + if(MwGetInteger(handle, MwNmodernLook)) { return 1; } else { diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index c08b5358..95fc2838 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -110,9 +110,9 @@ static void color_picker_image_update(color_picker_t* picker) { picker->color_picker_image_data[i + 2] = 0; picker->color_picker_image_data[i + 3] = 0; } else if(dist >= 180.) { - picker->color_picker_image_data[i] = dist; - picker->color_picker_image_data[i + 1] = dist; - picker->color_picker_image_data[i + 2] = dist; + picker->color_picker_image_data[i] = (unsigned char)dist; + picker->color_picker_image_data[i + 1] = (unsigned char)dist; + picker->color_picker_image_data[i + 2] = (unsigned char)dist; picker->color_picker_image_data[i + 3] = 255; } else { MwHSV hsv_v; @@ -121,26 +121,26 @@ static void color_picker_image_update(color_picker_t* picker) { double xd = (M_PI / 180.) * ((double)_x); double yd = (M_PI / 180.) * ((double)_y); - float angle = atan2(yd, xd) - M_PI; - float hue = (angle * 180.) / M_PI; + double angle = atan2(yd, xd) - M_PI; + double hue = (angle * 180.) / M_PI; if(hue < 0.0) { hue += 360; } - hsv_v.h = (hue) * (HSV_HUE_STEPS / 360.); - hsv_v.s = (dist) * (HSV_SAT_MAX / 180.); + hsv_v.h = (MwU8)((hue) * (HSV_HUE_STEPS / 360.)); + hsv_v.s = (MwU8)((dist) * (HSV_SAT_MAX / 180.)); picker->hue_table[n] = hsv_v; picker->hue_table[n].generated = 1; } hsv_v = picker->hue_table[n]; - hsv_v.v = HSV_VAL_MAX - (picker->value * HSV_VAL_MAX); + hsv_v.v = (MwU8)(HSV_VAL_MAX - (picker->value * HSV_VAL_MAX)); hsv2rgb(hsv_v.h, hsv_v.s, hsv_v.v, &color.red, &color.green, &color.blue); - picker->color_picker_image_data[i] = color.red; - picker->color_picker_image_data[i + 1] = color.green; - picker->color_picker_image_data[i + 2] = color.blue; + picker->color_picker_image_data[i] = (unsigned char)color.red; + picker->color_picker_image_data[i + 1] = (unsigned char)color.green; + picker->color_picker_image_data[i + 2] = (unsigned char)color.blue; picker->color_picker_image_data[i + 3] = 255; n++; @@ -158,7 +158,7 @@ static void color_picker_image_update(color_picker_t* picker) { /* printf("%d\n", n); */ } -static void color_picker_click(MwWidget handle, void* user, void* call) { +static void MWAPI color_picker_click(MwWidget handle, void* user, void* call) { color_picker_t* picker = user; MwMouse* mouse = call; char hexColor[8]; @@ -190,8 +190,8 @@ static void color_picker_click(MwWidget handle, void* user, void* call) { MwSetText(picker->color_display_text, MwNbackground, hexColor); MwSetText(picker->color_display_text, MwNtext, hexColor); } -static void color_picker_on_change_value(MwWidget handle, void* user, - void* call) { +static void MWAPI color_picker_on_change_value(MwWidget handle, void* user, + void* call) { color_picker_t* picker = user; int value = MwGetInteger(handle, MwNvalue); @@ -206,8 +206,8 @@ static void color_picker_on_change_value(MwWidget handle, void* user, /* color_picker_image_update(picker); */ } -static void color_picker_tick(MwWidget handle, void* user, - void* call) { +static void MWAPI color_picker_tick(MwWidget handle, void* user, + void* call) { color_picker_t* picker = user; (void)handle; @@ -224,8 +224,8 @@ static void color_picker_destroy(color_picker_t* picker) { free(picker); } -static void color_picker_close(MwWidget handle, void* user, - void* call) { +static void MWAPI color_picker_close(MwWidget handle, void* user, + void* call) { color_picker_t* picker = user; (void)call; @@ -234,8 +234,8 @@ static void color_picker_close(MwWidget handle, void* user, MwDestroyWidget(handle); } -static void color_display_text_change(MwWidget handle, void* user, - void* call) { +static void MWAPI color_display_text_change(MwWidget handle, void* user, + void* call) { color_picker_t* picker = user; char hexColor[9]; char fgColor[9]; @@ -265,8 +265,8 @@ static void color_display_text_change(MwWidget handle, void* user, MwLLFreeColor(color); } -static void color_picker_finish(MwWidget handle, void* user, - void* call) { +static void MWAPI color_picker_finish(MwWidget handle, void* user, + void* call) { color_picker_t* picker = user; (void)call; diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index ff1683c3..138fc6cf 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -50,38 +50,37 @@ static void destroy(MwWidget handle) { MwLLDestroyPixmap(fc->up); MwLLDestroyPixmap(fc->computer); free(handle->opaque); +} + +static void MWAPI filecancel(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + MwDestroyWidget(handle->parent); +} + +static void MWAPI cancel_window(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + MwDestroyWidget(handle); } -static void filecancel(MwWidget handle, void* user, void* call) { +static void MWAPI okay(MwWidget handle, void* user, void* call) { (void)user; (void)call; - destroy(handle->parent); + MwDestroyWidget(handle->parent); } -static void cancel_window(MwWidget handle, void* user, void* call) { +static void MWAPI msgbox_okay(MwWidget handle, void* user, void* call) { (void)user; (void)call; - destroy(handle); + MwDestroyWidget(handle->parent); } -static void okay(MwWidget handle, void* user, void* call) { - (void)user; - (void)call; - - destroy(handle->parent); -} - -static void msgbox_okay(MwWidget handle, void* user, void* call) { - (void)user; - (void)call; - - MwMessageBoxDestroy(handle->parent); -} - -static void files_activate(MwWidget handle, void* user, void* call) { +static void MWAPI files_activate(MwWidget handle, void* user, void* call) { int index = *(int*)call; filechooser_t* fc = handle->parent->opaque; @@ -104,7 +103,7 @@ static void files_activate(MwWidget handle, void* user, void* call) { } } -static void okay_activate(MwWidget handle, void* user, void* call) { +static void MWAPI okay_activate(MwWidget handle, void* user, void* call) { filechooser_t* fc = handle->parent->opaque; char* t = (char*)MwGetText(fc->filename, MwNtext); struct stat s; @@ -140,7 +139,7 @@ static void okay_activate(MwWidget handle, void* user, void* call) { if(p != NULL) free(p); } -static void nav_activate(MwWidget handle, void* user, void* call) { +static void MWAPI nav_activate(MwWidget handle, void* user, void* call) { int index = *(int*)call; const char* e = MwListBoxGet(handle, index); @@ -156,7 +155,7 @@ static void nav_activate(MwWidget handle, void* user, void* call) { } } -static void addr_up_activate(MwWidget handle, void* user, void* call) { +static void MWAPI addr_up_activate(MwWidget handle, void* user, void* call) { filechooser_t* fc = handle->parent->opaque; char* p = MwDirectoryJoin(fc->path, ".."); @@ -168,7 +167,7 @@ static void addr_up_activate(MwWidget handle, void* user, void* call) { free(p); } -static void addr_back_activate(MwWidget handle, void* user, void* call) { +static void MWAPI addr_back_activate(MwWidget handle, void* user, void* call) { filechooser_t* fc = handle->parent->opaque; (void)user; @@ -181,7 +180,7 @@ static void addr_back_activate(MwWidget handle, void* user, void* call) { } } -static void addr_fwd_activate(MwWidget handle, void* user, void* call) { +static void MWAPI addr_fwd_activate(MwWidget handle, void* user, void* call) { filechooser_t* fc = handle->parent->opaque; (void)user; @@ -192,7 +191,7 @@ static void addr_fwd_activate(MwWidget handle, void* user, void* call) { } } -static void addr_activate(MwWidget handle, void* user, void* call) { +static void MWAPI addr_activate(MwWidget handle, void* user, void* call) { (void)user; (void)call; @@ -210,20 +209,16 @@ static void layout(MwWidget handle) { ww = 160; wh = h - 10 - 24 - 5 - 24 - 5 - 24 - 5; if(fc->nav == NULL) { - MwListBoxPacket* p = MwListBoxCreatePacket(); - int index; - - index = MwListBoxPacketInsert(p, -1); - MwListBoxPacketSet(p, index, 0, "Home"); - MwListBoxPacketSetIcon(p, index, fc->computer); + int index; fc->nav = MwVaCreateWidget(MwListBoxClass, "nav", handle, wx, wy, ww, wh, MwNleftPadding, 16, NULL); - MwListBoxInsert(fc->nav, -1, p); - MwAddUserHandler(fc->nav, MwNlistBoxActivateHandler, nav_activate, NULL); - MwListBoxDestroyPacket(p); + index = MwListBoxSet(fc->nav, -1, 0, "Home"); + MwListBoxSetIcon(fc->nav, index, fc->computer); + + MwAddUserHandler(fc->nav, MwNlistBoxActivateHandler, nav_activate, NULL); } else { MwVaApply(fc->nav, MwNx, wx, @@ -394,7 +389,7 @@ static void layout(MwWidget handle) { } } -static void resize(MwWidget handle, void* user, void* call) { +static void MWAPI resize(MwWidget handle, void* user, void* call) { (void)user; (void)call; @@ -409,11 +404,10 @@ static int qsort_files(const void* a, const void* b) { } static void scan(MwWidget handle, const char* path, int record) { - filechooser_t* fc = handle->opaque; - void* dir = MwDirectoryOpen(path); - int i; - MwListBoxPacket* p = MwListBoxCreatePacket(); - int index; + filechooser_t* fc = handle->opaque; + void* dir = MwDirectoryOpen(path); + int i; + int index; if(dir != NULL) { MwDirectoryEntry* entry; @@ -467,74 +461,55 @@ static void scan(MwWidget handle, const char* path, int record) { MwListBoxSetWidth(fc->files, 1, 128); MwListBoxSetWidth(fc->files, 2, 0); - index = MwListBoxPacketInsert(p, -1); - MwListBoxPacketSet(p, index, -1, "Name"); - MwListBoxPacketSet(p, index, -1, "Date modified"); - MwListBoxPacketSet(p, index, -1, "Size"); + index = MwListBoxSet(fc->files, -1, 0, "Name"); + MwListBoxSet(fc->files, index, -1, "Date modified"); + MwListBoxSet(fc->files, index, -1, "Size"); for(i = 0; i < arrlen(fc->entries); i++) { if(strcmp(fc->entries[i]->name, ".") == 0 || strcmp(fc->entries[i]->name, "..") == 0) continue; if(fc->entries[i]->type == MwDIRECTORY_DIRECTORY) { - char date[128]; + char date[128]; + char* n = MwACPToUTF8(fc->entries[i]->name); MwStringTime(date, fc->entries[i]->mtime); - index = MwListBoxPacketInsert(p, -1); - MwListBoxPacketSetIcon(p, index, fc->dir); - MwListBoxPacketSet(p, index, -1, fc->entries[i]->name); - MwListBoxPacketSet(p, index, -1, date); - MwListBoxPacketSet(p, index, -1, NULL); + index = MwListBoxSet(fc->files, -1, 0, n); + MwListBoxSet(fc->files, index, -1, date); + MwListBoxSet(fc->files, index, -1, NULL); + MwListBoxSetIcon(fc->files, index, fc->dir); + + free(n); arrput(fc->sorted_entries, fc->entries[i]); } } for(i = 0; i < arrlen(fc->entries); i++) { if(fc->entries[i]->type == MwDIRECTORY_FILE && !fc->dir_only) { - char date[128]; - char size[128]; + char date[128]; + char size[128]; + char* n = MwACPToUTF8(fc->entries[i]->name); MwStringTime(date, fc->entries[i]->mtime); MwStringSize(size, fc->entries[i]->size); - index = MwListBoxPacketInsert(p, -1); - MwListBoxPacketSetIcon(p, index, fc->file); - MwListBoxPacketSet(p, index, -1, fc->entries[i]->name); - MwListBoxPacketSet(p, index, -1, date); - MwListBoxPacketSet(p, index, -1, size); + index = MwListBoxSet(fc->files, -1, 0, n); + MwListBoxSet(fc->files, index, -1, date); + MwListBoxSet(fc->files, index, -1, size); + MwListBoxSetIcon(fc->files, index, fc->file); + + free(n); arrput(fc->sorted_entries, fc->entries[i]); } } - MwListBoxInsert(fc->files, -1, p); - MwListBoxDestroyPacket(p); } -MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { - MwWidget window; - int w, h; - filechooser_t* fc = malloc(sizeof(*fc)); +static void setup_fallback_filechooser(MwWidget window, int dir) { char* path; MwLLPixmap icon; - int wx; - int wy; - + filechooser_t* fc = malloc(sizeof(*fc)); memset(fc, 0, sizeof(*fc)); - w = 700; - h = w * 2 / 3; - - if(handle == NULL) { - wx = wy = MwDEFAULT; - } else { - wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; - wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; - } - - window = MwVaCreateWidget(MwWindowClass, "filechooser", NULL, wx, wy, w, h, - MwNtitle, title, - NULL); - if(handle != NULL) MwReparent(window, handle); - fc->history_seek = 0; fc->dir = MwLoadIcon(window, MwIconDirectory); @@ -552,6 +527,8 @@ MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { window->opaque = fc; + window->destroy_inject = destroy; + layout(window); MwAddUserHandler(window, MwNresizeHandler, resize, NULL); MwAddUserHandler(window, MwNcloseHandler, cancel_window, NULL); @@ -561,8 +538,32 @@ MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { free(path); MwLLBeginStateChange(window->lowlevel); - MwLLMakePopup(window->lowlevel, handle == NULL ? NULL : handle->lowlevel); + MwLLMakePopup(window->lowlevel, window == NULL ? NULL : window->lowlevel); MwLLEndStateChange(window->lowlevel); +} + +MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { + MwWidget window; + int w, h; + int wx; + int wy; + + w = 700; + h = w * 2 / 3; + + if(handle == NULL) { + wx = wy = MwDEFAULT; + } else { + wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; + wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; + } + + window = MwVaCreateWidget(MwWindowClass, "filechooser", NULL, wx, wy, w, h, + MwNtitle, title, + NULL); + if(handle != NULL) MwReparent(window, handle); + + setup_fallback_filechooser(window, dir); return window; } diff --git a/src/dialog/messagebox.c b/src/dialog/messagebox.c index 1d2b9912..ff72bc84 100644 --- a/src/dialog/messagebox.c +++ b/src/dialog/messagebox.c @@ -18,10 +18,16 @@ static void spawn_button(MwWidget handle, int x, int y, int id, const char* text handle->opaque = mb; } -static void messagebox_close(MwWidget handle, void* user, void* call) { +static void messagebox_destroy_inject(MwWidget handle) { + void* px; + + if((px = MwGetVoid(handle, MwNpixmap)) != NULL) MwLLDestroyPixmap(px); +} + +static void MWAPI messagebox_close(MwWidget handle, void* user, void* call) { (void)user; (void)call; - MwMessageBoxDestroy(handle); + MwDestroyWidget(handle); } MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsigned int flag) { @@ -62,34 +68,40 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi if(flag & MwMB_BUTTONYES) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONYES, "Yes"); if((flag & MwMB_ICONMASK) != 0) { - MwWidget icon; - MwLLPixmap px; - unsigned int* data = NULL; + MwWidget icon; + MwLLPixmap px; + MwU32* data = NULL; icon = MwCreateWidget(MwImageClass, "image", window, 8, (h - 48) / 2, 48, 48); switch(flag & MwMB_ICONMASK) { - case MwMB_ICONWARNING: { + case MwMB_ICONWARNING: + { data = MwIconWarning; break; } - case MwMB_ICONINFO: { + case MwMB_ICONINFO: + { data = MwIconInfo; break; } - case MwMB_ICONNOTE: { + case MwMB_ICONNOTE: + { data = MwIconNote; break; } - case MwMB_ICONNEWS: { + case MwMB_ICONNEWS: + { data = MwIconNews; break; } - case MwMB_ICONERROR: { + case MwMB_ICONERROR: + { data = MwIconError; break; } - case MwMB_ICONCLOCK: { + case MwMB_ICONCLOCK: + { data = MwIconClock; break; } @@ -113,6 +125,7 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi MwLLEndStateChange(window->lowlevel); MwAddUserHandler(window, MwNcloseHandler, messagebox_close, NULL); + window->destroy_inject = messagebox_destroy_inject; return window; } @@ -122,10 +135,3 @@ MwWidget MwMessageBoxGetChild(MwWidget handle, int child) { return hmget(mb, child); } - -void MwMessageBoxDestroy(MwWidget handle) { - void* px; - - if((px = MwGetVoid(handle, MwNpixmap)) != NULL) MwLLDestroyPixmap(px); - MwDestroyWidget(handle); -} diff --git a/src/draw.c b/src/draw.c index 8dde8418..2314c028 100644 --- a/src/draw.c +++ b/src/draw.c @@ -38,6 +38,21 @@ static int hex(const char* txt, int len) { return r; } +static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { + if(MwGetInteger(handle, MwNdisabled) == 1) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + rgb->common.red = (MwU8)(rgb->common.red + (c->common.red - rgb->common.red) * 0.5); + rgb->common.green = (MwU8)(rgb->common.green + (c->common.green - rgb->common.green) * 0.5); + rgb->common.blue = (MwU8)(rgb->common.blue + (c->common.blue - rgb->common.blue) * 0.5); + MwLLColorUpdate(handle->lowlevel, rgb, rgb->common.red, rgb->common.green, rgb->common.blue); + + MwLLFreeColor(c); + } + } +}; + void MwParseColorNoAllocate(const char* text, MwRGB* rgb) { if(text[0] == '#' && strlen(text) == 4) { rgb->red = hex(text + 1, 1); @@ -109,8 +124,11 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; - unsigned char* data = malloc(sz); + unsigned char* data = malloc(sz*2); MwRect r = *rect; + if(!data) { + return; + } if(rect->width <= 0 || rect->height <= 0) { free(data); return; @@ -123,8 +141,9 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { r.height -= 2; for(y = 0; y < rect->height; y++) { - MwLLColor col = MwLightenColor(handle, color, -darken, -darken, -darken); + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); int idx = y * 4; + color_set_disabled_if_disabled(handle, col); data[idx] = col->common.red; data[idx + 1] = col->common.green; data[idx + 2] = col->common.blue; @@ -141,23 +160,35 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { } void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { + MwDrawFrameWithBorder(handle, rect, color, invert, MwDefaultBorderWidth(handle)); +} + +static int translate_border(MwWidget handle, int border) { + if(border == MwDEFAULT) return MwDefaultBorderWidth(handle); + + return border; +} + +void MwDrawFrameWithBorder(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { int inv; + border = translate_border(handle, border); + if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0); + MwDrawFrameEx(handle, rect, color, invert, border, 0, 0); } else { int diff = get_color_diff(handle) / 3 * 2; - if(MwDefaultBorderWidth(handle) >= 2) { + if(border >= 2) { int i; int st = invert ? 1 : 0; for(i = st; i < st + 2; i++) { - if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0); + if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, border - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0); if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0); } } else { - MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0); + MwDrawFrameEx(handle, rect, color, invert, border, 0, 0); } } } @@ -177,15 +208,29 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert } } - MwDrawFrame(handle, rect, color, invert); + MwDrawFrameWithBorder(handle, rect, color, invert, border); + + if(border == MwDEFAULT) { + int d = MwDefaultBorderWidth(handle) - MwDefaultThinBorderWidth(handle); + + rect->x -= d; + rect->y -= d; + rect->width += d * 2; + rect->height += d * 2; + } } - col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; + + if(rect->width <= 0 || rect->height <= 0) return; + + col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + color_set_disabled_if_disabled(handle, col); + if(MwGetInteger(handle, MwNmodernLook)) { MwDrawRectFading(handle, rect, col); } else { MwDrawRect(handle, rect, col); } - if(col != color) MwLLFreeColor(col); + MwLLFreeColor(col); } void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -194,7 +239,10 @@ void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { int ColorDiff = get_color_diff(handle) + (MwGetInteger(handle, MwNmodernLook) ? 48 : 0); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; + MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + color_set_disabled_if_disabled(handle, col); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); p[0].x = rect->x; p[0].y = rect->y + rect->height / 2; @@ -237,20 +285,20 @@ void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); p[0].x = rect->x + rect->width / 2; - p[0].y = border; + p[0].y = rect->y + border; p[1].x = rect->x + rect->width - border; - p[1].y = rect->height / 2; + p[1].y = rect->y + rect->height / 2; p[2].x = rect->x + rect->width / 2; p[2].y = rect->y + rect->height - border; p[3].x = rect->x + border; - p[3].y = rect->height / 2; + p[3].y = rect->y + rect->height / 2; MwLLPolygon(handle->lowlevel, p, 4, col); - if(col != color) MwLLFreeColor(col); + MwLLFreeColor(col); MwLLFreeColor(lighter); MwLLFreeColor(darker); } @@ -260,8 +308,11 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int ColorDiff = get_color_diff(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); - p[0].x = rect->x; - p[0].y = rect->y; + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + + p[0].x = rect->x; + p[0].y = rect->y; p[1].x = rect->x + rect->width; p[1].y = rect->y; @@ -356,13 +407,18 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); MwRect r = *rect; - frame_border_complex(handle, rect, lighter, darker, invert, border, diff, same); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); - r.x += 1; - r.y += 1; - r.width -= 2; - r.height -= 2; - frame_border_complex(handle, &r, lighter, darker, !invert, border, diff, same); + frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same); + + if(border > 1) { + r.x += border / 2; + r.y += border / 2; + r.width -= border; + r.height -= border; + frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same); + } MwLLFreeColor(lighter); MwLLFreeColor(darker); @@ -374,6 +430,8 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color } void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { + border = translate_border(handle, border); + if(MwGetInteger(handle, MwNmodernLook)) { MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same); } else { @@ -387,11 +445,14 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int ColorDiff = get_color_diff(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; + MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + double deg = 30 * ((direction == MwEAST || direction == MwWEST) ? 2 : 1); + double c = cos(deg / 180 * M_PI); + double s = sin(deg / 180 * M_PI); - double deg = 30 * ((direction == MwEAST || direction == MwWEST) ? 2 : 1); - double c = cos(deg / 180 * M_PI); - double s = sin(deg / 180 * M_PI); + color_set_disabled_if_disabled(handle, col); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); if(direction == MwNORTH) { p1[0].x = rect->x + rect->width / 2; @@ -400,11 +461,11 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p1[1].x = rect->x; p1[1].y = rect->y + rect->height; - p1[2].x = rect->x + c * border; - p1[2].y = rect->y + rect->height - s * border; + p1[2].x = (int)(rect->x + c * border); + p1[2].y = (int)(rect->y + rect->height - s * border); p1[3].x = rect->x + rect->width / 2; - p1[3].y = rect->y + border; + p1[3].y = (int)(rect->y + border); p2[0].x = rect->x + rect->width / 2; p2[0].y = rect->y; @@ -412,14 +473,14 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p2[1].x = rect->x + rect->width; p2[1].y = rect->y + rect->height; - p2[2].x = rect->x + rect->width - c * border; - p2[2].y = rect->y + rect->height - s * border; + p2[2].x = (int)(rect->x + rect->width - c * border); + p2[2].y = (int)(rect->y + rect->height - s * border); p2[3].x = rect->x + rect->width / 2; - p2[3].y = rect->y + border; + p2[3].y = (int)(rect->y + border); - p3[0].x = rect->x + c * border; - p3[0].y = rect->y + rect->height - s * border; + p3[0].x = (int)(rect->x + c * border); + p3[0].y = (int)(rect->y + rect->height - s * border); p3[1].x = rect->x; p3[1].y = rect->y + rect->height; @@ -427,30 +488,30 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p3[2].x = rect->x + rect->width; p3[2].y = rect->y + rect->height; - p3[3].x = rect->x + rect->width - c * border; - p3[3].y = rect->y + rect->height - s * border; + p3[3].x = (int)(rect->x + rect->width - c * border); + p3[3].y = (int)(rect->y + rect->height - s * border); MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker); MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); - p4[0].x = rect->x + c * border; - p4[0].y = rect->y + rect->height - s * border; + p4[0].x = (int)(rect->x + c * border); + p4[0].y = (int)(rect->y + rect->height - s * border); - p4[1].x = rect->x + rect->width - c * border; - p4[1].y = rect->y + rect->height - s * border; + p4[1].x = (int)(rect->x + rect->width - c * border); + p4[1].y = (int)(rect->y + rect->height - s * border); p4[2].x = rect->x + rect->width / 2; - p4[2].y = rect->y + border; + p4[2].y = (int)(rect->y + border); } else if(direction == MwSOUTH) { p1[0].x = rect->x; p1[0].y = rect->y; - p1[1].x = rect->x + c * border; - p1[1].y = rect->y + s * border; + p1[1].x = (int)(rect->x + c * border); + p1[1].y = (int)(rect->y + s * border); - p1[2].x = rect->x + rect->width - c * border; - p1[2].y = rect->y + s * border; + p1[2].x = (int)(rect->x + rect->width - c * border); + p1[2].y = (int)(rect->y + s * border); p1[3].x = rect->x + rect->width; p1[3].y = rect->y; @@ -458,11 +519,11 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p2[0].x = rect->x; p2[0].y = rect->y; - p2[1].x = rect->x + c * border; - p2[1].y = rect->y + s * border; + p2[1].x = (int)(rect->x + c * border); + p2[1].y = (int)(rect->y + s * border); p2[2].x = rect->x + rect->width / 2; - p2[2].y = rect->y + rect->height - border; + p2[2].y = (int)(rect->y + rect->height - border); p2[3].x = rect->x + rect->width / 2; p2[3].y = rect->y + rect->height; @@ -474,32 +535,32 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p3[1].y = rect->y + rect->height; p3[2].x = rect->x + rect->width / 2; - p3[2].y = rect->y + rect->height - border; + p3[2].y = (int)(rect->y + rect->height - border); - p3[3].x = rect->x + rect->width - c * border; - p3[3].y = rect->y + s * border; + p3[3].x = (int)(rect->x + rect->width - c * border); + p3[3].y = (int)(rect->y + s * border); MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter); MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); - p4[0].x = rect->x + c * border; - p4[0].y = rect->y + s * border; + p4[0].x = (int)(rect->x + c * border); + p4[0].y = (int)(rect->y + s * border); - p4[1].x = rect->x + rect->width - c * border; - p4[1].y = rect->y + s * border; + p4[1].x = (int)(rect->x + rect->width - c * border); + p4[1].y = (int)(rect->y + s * border); p4[2].x = rect->x + rect->width / 2; - p4[2].y = rect->y + rect->height - border; + p4[2].y = (int)(rect->y + rect->height - border); } else if(direction == MwEAST) { p1[0].x = rect->x; p1[0].y = rect->y; - p1[1].x = rect->x + c * border; - p1[1].y = rect->y + s * border; + p1[1].x = (int)(rect->x + c * border); + p1[1].y = (int)(rect->y + s * border); - p1[2].x = rect->x + c * border; - p1[2].y = rect->y + rect->height - s * border; + p1[2].x = (int)(rect->x + c * border); + p1[2].y = (int)(rect->y + rect->height - s * border); p1[3].x = rect->x; p1[3].y = rect->y + rect->height; @@ -510,14 +571,14 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p2[1].x = rect->x + rect->width; p2[1].y = rect->y + rect->height / 2; - p2[2].x = rect->x + rect->width - border; + p2[2].x = (int)(rect->x + rect->width - border); p2[2].y = rect->y + rect->height / 2; - p2[3].x = rect->x + c * border; - p2[3].y = rect->y + s * border; + p2[3].x = (int)(rect->x + c * border); + p2[3].y = (int)(rect->y + s * border); - p3[0].x = rect->x + c * border; - p3[0].y = rect->y + rect->height - s * border; + p3[0].x = (int)(rect->x + c * border); + p3[0].y = (int)(rect->y + rect->height - s * border); p3[1].x = rect->x; p3[1].y = rect->y + rect->height; @@ -525,30 +586,30 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p3[2].x = rect->x + rect->width; p3[2].y = rect->y + rect->height / 2; - p3[3].x = rect->x + rect->width - border; + p3[3].x = (int)(rect->x + rect->width - border); p3[3].y = rect->y + rect->height / 2; MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter); MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); - p4[0].x = rect->x + rect->width - border; + p4[0].x = (int)(rect->x + rect->width - border); p4[0].y = rect->y + rect->height / 2; - p4[1].x = rect->x + c * border; - p4[1].y = rect->y + rect->height - s * border; + p4[1].x = (int)(rect->x + c * border); + p4[1].y = (int)(rect->y + rect->height - s * border); - p4[2].x = rect->x + c * border; - p4[2].y = rect->y + s * border; + p4[2].x = (int)(rect->x + c * border); + p4[2].y = (int)(rect->y + s * border); } else if(direction == MwWEST) { p1[0].x = rect->x; p1[0].y = rect->y + rect->height / 2; - p1[1].x = rect->x + border; + p1[1].x = (int)(rect->x + border); p1[1].y = rect->y + rect->height / 2; - p1[2].x = rect->x + rect->width - c * border; - p1[2].y = rect->y + s * border; + p1[2].x = (int)(rect->x + rect->width - c * border); + p1[2].y = (int)(rect->y + s * border); p1[3].x = rect->x + rect->width; p1[3].y = rect->y; @@ -556,11 +617,11 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p2[0].x = rect->x; p2[0].y = rect->y + rect->height / 2; - p2[1].x = rect->x + border; + p2[1].x = (int)(rect->x + border); p2[1].y = rect->y + rect->height / 2; - p2[2].x = rect->x + rect->width - c * border; - p2[2].y = rect->y + rect->height - s * border; + p2[2].x = (int)(rect->x + rect->width - c * border); + p2[2].y = (int)(rect->y + rect->height - s * border); p2[3].x = rect->x + rect->width; p2[3].y = rect->y + rect->height; @@ -568,11 +629,11 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p3[0].x = rect->x + rect->width; p3[0].y = rect->y; - p3[1].x = rect->x + rect->width - c * border; - p3[1].y = rect->y + s * border; + p3[1].x = (int)(rect->x + rect->width - c * border); + p3[1].y = (int)(rect->y + s * border); - p3[2].x = rect->x + rect->width - c * border; - p3[2].y = rect->y + rect->height - s * border; + p3[2].x = (int)(rect->x + rect->width - c * border); + p3[2].y = (int)(rect->y + rect->height - s * border); p3[3].x = rect->x + rect->width; p3[3].y = rect->y + rect->height; @@ -581,19 +642,18 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker); MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); - p4[0].x = rect->x + border; + p4[0].x = (int)(rect->x + border); p4[0].y = rect->y + rect->height / 2; - p4[1].x = rect->x + rect->width - c * border; - p4[1].y = rect->y + rect->height - s * border; + p4[1].x = (int)(rect->x + rect->width - c * border); + p4[1].y = (int)(rect->y + rect->height - s * border); - p4[2].x = rect->x + rect->width - c * border; - p4[2].y = rect->y + s * border; + p4[2].x = (int)(rect->x + rect->width - c * border); + p4[2].y = (int)(rect->y + s * border); } MwLLPolygon(handle->lowlevel, p4, 3, col); - if(color != col) MwLLFreeColor(col); - + MwLLFreeColor(col); MwLLFreeColor(lighter); MwLLFreeColor(darker); } @@ -773,13 +833,13 @@ void MwPixmapReloadRaw(MwLLPixmap px, unsigned char* rgb) { a /= 255; if(a != 0) { - pout[0] = pin[0] * a; - pout[1] = pin[1] * a; - pout[2] = pin[2] * a; + pout[0] = (unsigned char)(pin[0] * a); + pout[1] = (unsigned char)(pin[1] * a); + pout[2] = (unsigned char)(pin[2] * a); - pout[0] += base->common.red * (1 - a); - pout[1] += base->common.green * (1 - a); - pout[2] += base->common.blue * (1 - a); + pout[0] += (unsigned char)(base->common.red * (1 - a)); + pout[1] += (unsigned char)(base->common.green * (1 - a)); + pout[2] += (unsigned char)(base->common.blue * (1 - a)); pout[3] = 255; } } @@ -811,6 +871,11 @@ MwLLPixmap MwLoadIcon(MwWidget handle, MwU32* data) { MwLLPixmap px; int i; + if(!rgba) { + printf("Null malloc! out of memory?\n"); + return NULL; + } + memset(rgba, 0, width * height * 4); for(i = 0; i < width * height; i++) { @@ -848,7 +913,11 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { sh_new_strdup(c); +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + sscanf_s(data[0], "%d %d %d %d", &col, &row, &colors, &cpp); +#else sscanf(data[0], "%d %d %d %d", &col, &row, &colors, &cpp); +#endif for(i = 0; i < colors; i++) { char k[128]; @@ -885,6 +954,10 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { rgb = malloc(row * col * 4); comp = malloc(cpp + 1); + if(!rgb || !comp) { + printf("Null malloc! Out of memory?"); + return NULL; + } comp[cpp] = 0; for(y = 0; y < row; y++) { for(x = 0; x < col; x++) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 935bf9b3..2fe15356 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -1,5 +1,11 @@ #include +#ifdef _WIN32 +void *MwLL_winmmLib; +long (__stdcall* MwLL_PFN_timeGetTime)(void); +unsigned int (__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); +#endif + MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height) = NULL; void (*MwLLDestroy)(MwLL handle) = NULL; @@ -50,8 +56,14 @@ void (*MwLLGetClipboard)(MwLL, int clipboard_type) = NULL; void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; +void (*MwLLSetupDragAndDrop)(MwLL handle) = NULL; +void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; -void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; +MwBool (*MwLLDoModern)(MwLL handle) = NULL; + +void (*MwLLRaise)(MwLL handle) = NULL; + +void (*MwLLClip)(MwLL handle, MwRect* rect) = NULL; void MwLLCreateCommon(MwLL handle) { handle->common.handler = malloc(sizeof(*handle->common.handler)); @@ -66,7 +78,11 @@ void MwLLDestroyCommon(MwLL handle) { #ifdef USE_DBUS MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { +#ifdef __APPLE__ + tbl->lib = MwDynamicOpen("libdbus-1.dylib"); +#else tbl->lib = MwDynamicOpen("libdbus-1.so"); +#endif if(!tbl->lib) { fprintf(stderr, "[WARNING] dbus library (libdbus-1.so) not found, will not be able to check for any XDG settings.\n"); return MwFALSE; @@ -82,16 +98,22 @@ MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { DBUS_FUNC(dbus_error_init); DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_bus_add_match); DBUS_FUNC(dbus_error_is_set); DBUS_FUNC(dbus_error_free); DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_is_signal); DBUS_FUNC(dbus_message_iter_init_append); DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_flush); + DBUS_FUNC(dbus_connection_pop_message); + DBUS_FUNC(dbus_connection_read_write); DBUS_FUNC(dbus_connection_send_with_reply_and_block); DBUS_FUNC(dbus_message_unref); DBUS_FUNC(dbus_message_iter_init); DBUS_FUNC(dbus_message_iter_get_arg_type); DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_message_iter_next); DBUS_FUNC(dbus_connection_unref); DBUS_FUNC(dbus_message_iter_get_basic); @@ -121,6 +143,8 @@ MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { }; MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } @@ -135,9 +159,9 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - tbl->dbus_message_iter_init_append(ctx->dbus_msg, &ctx->dbus_args); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &namespace); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &key); + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &dbus_args); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &key); ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); @@ -151,25 +175,35 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &ctx->dbus_args)) { + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &dbus_args)) { fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_args) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - tbl->dbus_message_iter_recurse(&ctx->dbus_args, &ctx->dbus_variant); + tbl->dbus_message_iter_recurse(&dbus_args, &dbus_variant); /* Some portals wrap the value in a second variant */ - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_variant) == 'v') { - tbl->dbus_message_iter_recurse(&ctx->dbus_variant, &ctx->dbus_inner_variant); - tbl->dbus_message_iter_get_basic(&ctx->dbus_inner_variant, out); + arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_variant); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&dbus_variant, &dbus_inner_variant); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_inner_variant)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&dbus_inner_variant, out); + } else if(arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&dbus_variant, out); } else { - tbl->dbus_message_iter_get_basic(&ctx->dbus_variant, out); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; } tbl->dbus_message_unref(ctx->dbus_msg); @@ -177,66 +211,104 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co } MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + char filter_string[2048]; if(!ctx->dbus_conn) { return MwFALSE; } - char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - dbus_connection_flush(ctx->dbus_conn); + tbl->dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + tbl->dbus_connection_flush(ctx->dbus_conn); return MwTRUE; } -// Technically this will swallow all other results, so this is not usable multiple times. -// TODO: Use a hashmap instead +/* Technically this will swallow all other results, so this is not usable multiple times. + TODO: Use a hashmap instead */ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { - DBusMessage* msg; - DBusMessageIter args, msg_value; - const char* msg_namespace; - const char* msg_key; - MwU32 msg_value_content; + DBusMessageIter args, msg_value, msg_value_inner; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } - dbus_connection_read_write(ctx->dbus_conn, 0); - msg = dbus_connection_pop_message(ctx->dbus_conn); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + ctx->dbus_reply = tbl->dbus_connection_pop_message(ctx->dbus_conn); - if (NULL == msg) { + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Poll error: %s\n", portal, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { return MwFALSE; } - // check if the message is a signal from the correct interface and with the correct name - if (dbus_message_is_signal(msg, portal, "SettingChanged")) { - // read the parameters - if (!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "[WARNING] Message has no arguments\n"); - else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "[WARNING] Argument is not string\n"); + /* check if the message is a signal from the correct interface and with the correct name */ + if(tbl->dbus_message_is_signal(ctx->dbus_reply, portal, "SettingChanged")) { + /* read the parameters */ + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &args)) + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged has no arguments\n", portal); else { - dbus_message_iter_get_basic(&args, &msg_namespace); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'namespace', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_namespace); - dbus_message_iter_next(&args); - dbus_message_iter_get_basic(&args, &msg_key); + tbl->dbus_message_iter_next(&args); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'key', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_key); - // Check that key and namespace match - if (strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { - // Assuming the value is a basic type - dbus_message_iter_next(&args); - dbus_message_iter_recurse(&args, &msg_value); - dbus_message_iter_get_basic(&msg_value, &msg_value_content); + /* Check that key and namespace match */ + if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + /* Assuming the value is a basic type */ + tbl->dbus_message_iter_next(&args); + + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&args, &msg_value); + + /* Some portals wrap the value in a second variant */ + arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&msg_value, &msg_value_inner); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value_inner)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&msg_value_inner, &msg_value_content); + } else if(arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&msg_value, &msg_value_content); + } else { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } listener(handle, msg_value_content); } } } - // free the message - dbus_message_unref(msg); + /* free the message */ + tbl->dbus_message_unref(ctx->dbus_reply); + return MwTRUE; } void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { diff --git a/src/string.c b/src/string.c index f56b9acb..c894b9a5 100644 --- a/src/string.c +++ b/src/string.c @@ -1,21 +1,53 @@ #include char* MwStringDuplicate(const char* str) { - char* r = malloc(strlen(str) + 1); + int sz = strlen(str) + 1; + char* r = malloc(sz); + if(!r) { + printf("Out Of Memory\n"); + return NULL; + } + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + strcpy_s(r, sz, str); +#else strcpy(r, str); +#endif return r; } char* MwStringConcat(const char* str1, const char* str2) { - char* r = malloc(strlen(str1) + strlen(str2) + 1); + int sz = strlen(str1) + strlen(str2) + 1; + char* r = malloc(sz); + if(!r) { + printf("Out Of Memory\n"); + return NULL; + } + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + strcpy_s(r, sz, str1); + strcat_s(r, sz, str2); +#else strcpy(r, str1); strcat(r, str2); +#endif return r; } void MwStringSize(char* out, MwOffset size) { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + if(size / 1024 == 0) { + sprintf_s(out, 255, "%d", (int)size); + } else if(size / 1024 / 1024 == 0) { + sprintf_s(out, 255, "%.1fK", (double)size / 1024); + } else if(size / 1024 / 1024 / 1024 == 0) { + sprintf_s(out, 255, "%.1fM", (double)size / 1024 / 1024); + } else { + sprintf_s(out, 255, "%.1fG", (double)size / 1024 / 1024 / 1024); + } +#else if(size / 1024 == 0) { sprintf(out, "%d", (int)size); } else if(size / 1024 / 1024 == 0) { @@ -25,16 +57,28 @@ void MwStringSize(char* out, MwOffset size) { } else { sprintf(out, "%.1fG", (double)size / 1024 / 1024 / 1024); } +#endif } void MwStringTime(char* out, time_t t) { struct tm* tm = localtime(&t); const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if(tm == NULL) { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + sprintf_s(out, 255, "localtime error"); +#else sprintf(out, "localtime error"); +#endif + } else { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + sprintf_s(out, 255, "%s %2d %02d:%02d %d", months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, 1900 + tm->tm_year); +#else sprintf(out, "%s %2d %02d:%02d %d", months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, 1900 + tm->tm_year); +#endif } } void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { @@ -43,6 +87,9 @@ void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { #if __STDC_VERSION__ >= 199901L vsnprintf(out, size, fmt, va); +/* MSVC2022 reports the STDC_VERSION as fucking 1994. Thanks Bill Gates. */ +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + vsprintf_s(out, size, fmt, va); #else vsprintf(out, fmt, va); #endif diff --git a/src/text/font/boldmonottf.c b/src/text/font/boldmonottf.c index 7945831d..8526c1b0 100644 --- a/src/text/font/boldmonottf.c +++ b/src/text/font/boldmonottf.c @@ -1,6 +1,6 @@ #include -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) unsigned char MwBoldMonospaceTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, 0x46, 0x46, 0x54, 0x4d, 0xac, 0x0d, 0xe4, 0x44, 0x00, 0x00, 0x8d, 0x3c, diff --git a/src/text/font/boldttf.c b/src/text/font/boldttf.c index 14b25990..2ec91c7f 100644 --- a/src/text/font/boldttf.c +++ b/src/text/font/boldttf.c @@ -1,6 +1,6 @@ #include -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) unsigned char MwBoldTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04, 0x00, 0x20, 0x46, 0x46, 0x54, 0x4d, 0x94, 0x9f, 0x60, 0x18, 0x00, 0x00, 0x8e, 0xa8, diff --git a/src/text/font/monottf.c b/src/text/font/monottf.c index 8332c4a7..7a89f943 100644 --- a/src/text/font/monottf.c +++ b/src/text/font/monottf.c @@ -1,6 +1,6 @@ #include -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) unsigned char MwMonospaceTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, 0x46, 0x46, 0x54, 0x4d, 0xac, 0x0d, 0xe4, 0x23, 0x00, 0x00, 0x8d, 0x3c, diff --git a/src/text/font/ttf.c b/src/text/font/ttf.c index c5d03b95..7eeea07b 100644 --- a/src/text/font/ttf.c +++ b/src/text/font/ttf.c @@ -1,6 +1,6 @@ #include -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) unsigned char MwTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04, 0x00, 0x20, 0x46, 0x46, 0x54, 0x4d, 0x94, 0x92, 0x79, 0xd4, 0x00, 0x00, 0x89, 0xa4, diff --git a/src/text/ft2.c b/src/text/ft2.c index 32e65877..13e8208c 100644 --- a/src/text/ft2.c +++ b/src/text/ft2.c @@ -49,24 +49,17 @@ static int ft2_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c FT_Bitmap* bmp; int cy, cx; int c, c2; - int l = MwUTF8ToUTF32(text, &c); FT_Vector vec; const char* old_text; - if(l <= 0) break; - text += l; - if(c == '\n') { - x = 0; - y += ttf->face->height * ttf->px / ttf->face->units_per_EM; - continue; - } + text += MwUTF8ToUTF32(text, &c); ft_table.FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); bmp = &ttf->face->glyph->bitmap; for(cy = 0; cy < bmp->rows; cy++) { for(cx = 0; cx < bmp->width; cx++) { - int ox = x + (ttf->face->glyph->metrics.horiBearingX / 64) + cx + ttf->face->glyph->bitmap_left; + int ox = x + cx + ttf->face->glyph->bitmap_left; int oy = y + (ttf->face->height * ttf->px / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * ttf->px / ttf->face->units_per_EM); unsigned char* opx = &px[(oy * tw + ox) * 4]; opx[0] = color->common.red; @@ -81,16 +74,14 @@ static int ft2_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c } } - x += (ttf->face->glyph->advance.x >> 6) + (ttf->face->glyph->metrics.horiBearingX >> 6); + x += (ttf->face->glyph->advance.x >> 6); old_text = text; text += MwUTF8ToUTF32(text, &c2); - if(c2 != '\n') { - ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); + ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); - x += vec.x >> 6; - } + x += vec.x >> 6; text = old_text; } @@ -109,37 +100,36 @@ static int ft2_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c } static int ft2_MwTextWidth(MwFLFont ttf, const char* text) { - int tw = 0, mtw = 0; + int tw = 0; + FT_Vector vec; while(text[0] != 0) { int c, c2; - FT_Vector vec; const char* old_text; text += MwUTF8ToUTF32(text, &c); - if(c == '\n') { - tw = 0; - continue; - } ft_table.FT_Load_Char(ttf->face, c, FT_LOAD_DEFAULT); - tw += (ttf->face->glyph->advance.x >> 6) + (ttf->face->glyph->metrics.horiBearingX >> 6); + tw += ttf->face->glyph->advance.x >> 6; old_text = text; text += MwUTF8ToUTF32(text, &c2); - if(c2 != '\n') { - ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); + ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); - tw += vec.x >> 6; - } + tw += vec.x >> 6; text = old_text; - if(tw > mtw) mtw = tw; } - return mtw + 1; + if(tw > 0) { + tw -= vec.x >> 6; + tw -= ttf->face->glyph->advance.x >> 6; + tw += ttf->face->glyph->bitmap_left + ttf->face->glyph->bitmap.width; + } + + return tw + 1; } static int ft2_MwTextHeight(MwFLFont ttf, int count) { @@ -169,10 +159,14 @@ static void ft2_MwFontFree(void* handle) { free(ttf); } -int MWFL_FT2Setup(void) { +int MwFL_FT2Setup(void) { /* Try and load FreeType2. If it fails, return 1, signifying we default to stbtt. */ void* ftlib; +#ifdef __APPLE__ + if(!(ftlib = MwDynamicOpen("libfreetype.dylib"))) { +#else if(!(ftlib = MwDynamicOpen("libfreetype.so"))) { +#endif return 1; } diff --git a/src/text/gdi.c b/src/text/gdi.c new file mode 100644 index 00000000..97e68709 --- /dev/null +++ b/src/text/gdi.c @@ -0,0 +1,268 @@ +#ifdef USE_GDI_TEXT +#include + +static HANDLE(WINAPI* _AddFontMemResourceEx)(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts) = NULL; +static BOOL(WINAPI* _RemoveFontMemResourceEx)(HANDLE h) = NULL; +static HANDLE WINAPI _AddFontMemResourceExPolyFill(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts); +static BOOL WINAPI _RemoveFontMemResourceExPolyFill(HANDLE h); + +struct _MwFLFont { + HANDLE handle; + HFONT font; + HDC dc; +}; + +static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) { + BITMAPINFOHEADER bmih; + int tw; + int th; + HBITMAP hbm; + RGBQUAD* bits = NULL; + HDC hmdc; + char* t = MwUTF8ToACP(text); + unsigned char* px; + int y, x; + MwRect r; + MwLLPixmap p; + + tw = MwTextWidth(handle, ttf, text); + th = MwTextHeight(handle, ttf, text); + + if(handle->lowlevel->common.type == MwLLBackendGDI) { + HFONT old_font = SelectObject(handle->lowlevel->gdi.hDC, ttf->font); + int old_bkmode = SetBkMode(handle->lowlevel->gdi.hDC, TRANSPARENT); + COLORREF old_color = SetTextColor(handle->lowlevel->gdi.hDC, RGB(color->common.red, color->common.green, color->common.blue)); + + TextOut(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t, strlen(t)); + + SetTextColor(handle->lowlevel->gdi.hDC, old_color); + SetBkMode(handle->lowlevel->gdi.hDC, old_bkmode); + SelectObject(handle->lowlevel->gdi.hDC, old_font); + + free(t); + + return 0; + } + + px = malloc(tw * th * 4); + + bmih.biSize = sizeof(bmih); + bmih.biWidth = tw; + bmih.biHeight = -(LONG)th; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 0; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + hbm = CreateDIBSection(ttf->dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + + hmdc = CreateCompatibleDC(ttf->dc); + SelectObject(hmdc, hbm); + SelectObject(hmdc, ttf->font); + + TextOut(hmdc, 0, 0, t, strlen(t)); + + DeleteDC(hmdc); + + for(y = 0; y < th; y++) { + for(x = 0; x < tw; x++) { + unsigned char* opx = &px[(y * tw + x) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = 255 - bits[y * tw + x].rgbRed; + } + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + DeleteObject(hbm); + free(t); + + return 0; +} + +static int GDI_MwTextWidth(MwFLFont ttf, const char* text) { + char* t = MwUTF8ToACP(text); + SIZE sz; + + GetTextExtentPoint32(ttf->dc, t, strlen(t), &sz); + + free(t); + + return sz.cx; +} + +static int GDI_MwTextHeight(MwFLFont ttf, int count) { + TEXTMETRIC tm; + + GetTextMetrics(ttf->dc, &tm); + + return tm.tmHeight * count; +} + +static void* GDI_MwFontLoad(unsigned char* data, unsigned int size, int px) { + MwFLFont ttf = malloc(sizeof(*ttf)); + DWORD c; + MwTTFInfo info; + + if((info = MwTTFGetInfo(data, size)) == NULL) { + free(ttf); + return NULL; + } + + ttf->dc = GetDC(NULL); + + ttf->handle = NULL; + + if(_AddFontMemResourceEx) { + if((ttf->handle = _AddFontMemResourceEx(data, size, 0, &c)) == NULL) { + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + } /*else { + if((ttf->handle = _AddFontMemResourceExPolyFill(data, size, 0, &c)) == NULL) { + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + }*/ + + if((ttf->font = CreateFont(-px, 0, 0, 0, info->weight, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, ttf->handle ? info->family : "Sans Serif")) == NULL) { + if(_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx(ttf->handle); + } else { + _RemoveFontMemResourceExPolyFill(ttf->handle); + } + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + + MwTTFFreeInfo(info); + + SelectObject(ttf->dc, ttf->font); + + return ttf; +} + +static void GDI_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + DeleteObject(ttf->font); + if(_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx(ttf->handle); + } else { + _RemoveFontMemResourceExPolyFill(ttf->handle); + } + ReleaseDC(NULL, ttf->dc); + free(ttf); +} + +static HANDLE WINAPI _AddFontMemResourceExPolyFill(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts) { + CHAR temp_path_dir[MAX_PATH]; + CHAR temp_path_name[MAX_PATH]; + HANDLE tempFile = NULL; + DWORD hr; + + (void)pvResrved; + + hr = GetTempPathA(MAX_PATH, temp_path_dir); + if(hr == 0) { + printf("GetTempPathA error %08lX\n", hr); + return NULL; + } + hr = GetTempFileNameA(temp_path_dir, TEXT("MILSKO"), 0, temp_path_name); + if(hr == 0) { + printf("GetTempFileNameA error %08lX\n", hr); + return NULL; + } + + printf("extracting mem font to %s\n", temp_path_name); + + tempFile = CreateFileA(temp_path_name, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if(tempFile == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + if(err == ERROR_ALREADY_EXISTS) { + tempFile = CreateFileA(temp_path_name, + GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if(tempFile != INVALID_HANDLE_VALUE) { + goto success; + } else { + err = GetLastError(); + } + } + printf("CreateFileA error %08lX\n", err); + return NULL; + } + +success: + hr = WriteFile(tempFile, pFileView, cjSize, NULL, NULL); + if(hr != 0) { + printf("WriteFile error %08lX\n", hr); + return NULL; + } + + *pNumFonts = AddFontResource(temp_path_name); + + return tempFile; +}; +static BOOL WINAPI _RemoveFontMemResourceExPolyFill(HANDLE h) { + if(h) + CloseHandle(h); + return TRUE; +}; + +int MwFL_GDISetup(void) { + void* gdilib = LoadLibrary("gdi32.dll"); + if(!gdilib) { + printf("gdi32.dll not found(what)\n"); + } else { + _AddFontMemResourceEx = (void*)GetProcAddress(gdilib, "AddFontMemResourceEx"); + if(!_AddFontMemResourceEx) { + _AddFontMemResourceEx = _AddFontMemResourceExPolyFill; + } + _RemoveFontMemResourceEx = (void*)GetProcAddress(gdilib, "RemoveFontMemResourceEx"); + if(!_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx = _RemoveFontMemResourceExPolyFill; + } + } + + MwFLDrawText = GDI_MwDrawText; + MwFLTextWidth = GDI_MwTextWidth; + MwFLTextHeight = GDI_MwTextHeight; + MwFLFontLoad = GDI_MwFontLoad; + MwFLFontFree = GDI_MwFontFree; + return 0; +} + +#endif diff --git a/src/text/stbtt.c b/src/text/stbtt.c index a8419076..bd267414 100644 --- a/src/text/stbtt.c +++ b/src/text/stbtt.c @@ -33,11 +33,6 @@ static int stbtt_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const const char* old_text; text += MwUTF8ToUTF32(text, &c); - if(c == '\n') { - x = 0; - y += ceil((ttf->ascent - ttf->descent) * ttf->scale); - continue; - } stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); @@ -69,11 +64,9 @@ static int stbtt_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const old_text = text; text += MwUTF8ToUTF32(text, &c2); - if(c2 != '\n') { - kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); + kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); - x += ceil(kern * ttf->scale); - } + x += ceil(kern * ttf->scale); text = old_text; @@ -95,18 +88,16 @@ static int stbtt_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const static int stbtt_MwTextWidth(MwFLFont ttf, const char* text) { int ax, lsb; - int tw = 0, mtw = 0; + int tw = 0; + int c; + int x0, y0, x1, y1; + int kern; while(text[0] != 0) { - int kern; - int c, c2; + int c2; const char* old_text; text += MwUTF8ToUTF32(text, &c); - if(c == '\n') { - tw = 0; - continue; - } stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); @@ -115,17 +106,22 @@ static int stbtt_MwTextWidth(MwFLFont ttf, const char* text) { old_text = text; text += MwUTF8ToUTF32(text, &c2); - if(c2 != '\n') { - kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); + kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); - tw += ceil(kern * ttf->scale); - } + tw += ceil(kern * ttf->scale); text = old_text; - if(tw > mtw) mtw = tw; } - return mtw + 1; + if(tw > 0) { + tw -= ceil(kern * ttf->scale); + tw -= ceil(ax * ttf->scale); + stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); + tw += ceil(lsb * ttf->scale); + tw += x1 - x0; + } + + return tw + 1; } static int stbtt_MwTextHeight(MwFLFont ttf, int count) { diff --git a/src/text/text.c b/src/text/text.c index fec0bb44..2bb89b64 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -3,10 +3,11 @@ int (*MwFLDrawText)(MwWidget handle, MwFLFont font, MwPoint* point, const char* text, MwLLColor color) = NULL; int (*MwFLTextWidth)(MwFLFont font, const char* text) = NULL; int (*MwFLTextHeight)(MwFLFont font, int count) = NULL; +int (*MwFLTextHeightWithText)(MwFLFont ttf, const char* text) = NULL; void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px) = NULL; void (*MwFLFontFree)(void* handle) = NULL; -#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) +#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) || defined(USE_GDI_TEXT) #define TTF #endif @@ -15,6 +16,21 @@ void (*MwFLFontFree)(void* handle) = NULL; static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, MwLLColor color); +static int count_nl(const char* text) { + int c = 1; + int i = 0; + while(text[i] != 0) { + int out; + int l = MwUTF8ToUTF32(text + i, &out); + if(l == 0) break; + i += l; + + if(out == '\n') c++; + } + + return c; +} + static int is_bold(MwWidget handle, MwFLFont ttf) { size_t u = (size_t)ttf; int s; @@ -27,6 +43,17 @@ static int is_bold(MwWidget handle, MwFLFont ttf) { } #ifdef TTF +static int is_bitmap(MwWidget handle, MwFLFont ttf) { + size_t u = (size_t)ttf; + int s; + + if(u & MwFLFlagBitmap) return 1; + + s = MwGetInteger(handle, MwNbitmapFont); + if(s == MwDEFAULT) return 0; + return s; +} + static int is_monospace(MwWidget handle, MwFLFont ttf) { size_t u = (size_t)ttf; int s; @@ -42,7 +69,7 @@ static int is_monospace(MwWidget handle, MwFLFont ttf) { #ifdef TTF static MwFLFont assume_ttf(MwWidget handle, MwFLFont ttf) { - if(MwGetInteger(handle, MwNbitmapFont)) return NULL; + if(is_bitmap(handle, ttf)) return NULL; if(is_monospace(handle, ttf)) return is_bold(handle, ttf) ? MwGetVoid(handle, MwNboldMonospaceFont) : MwGetVoid(handle, MwNmonospaceFont); return is_bold(handle, ttf) ? MwGetVoid(handle, MwNboldFont) : MwGetVoid(handle, MwNfont); @@ -50,45 +77,146 @@ static MwFLFont assume_ttf(MwWidget handle, MwFLFont ttf) { #endif void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, int align, MwLLColor color) { - MwPoint p = *point; + MwPoint p = *point; + char* input = (char*)text; + char* last = input; + int cp; + MwLLColor fadedColor = NULL; - if(strlen(text) == 0) return; -#ifdef TTF - if(ttf <= MwFLBuildFont(0xff)) ttf = assume_ttf(handle, ttf); -#endif + if(MwGetInteger(handle, MwNdisabled) == 1) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); - if(align == MwALIGNMENT_CENTER) { - p.x -= MwTextWidth(handle, ttf, text) / 2; - } else if(align == MwALIGNMENT_END) { - p.x -= MwTextWidth(handle, ttf, text); + if(c != NULL) { + fadedColor = MwLLAllocColor(handle->lowlevel, color->common.red, color->common.blue, color->common.green); + fadedColor->common.red = (MwU8)(fadedColor->common.red + (c->common.red - fadedColor->common.red) * 0.5); + fadedColor->common.green = (MwU8)(fadedColor->common.green + (c->common.green - fadedColor->common.green) * 0.5); + fadedColor->common.blue = (MwU8)(fadedColor->common.blue + (c->common.blue - fadedColor->common.blue) * 0.5); + MwLLColorUpdate(handle->lowlevel, fadedColor, fadedColor->common.red, fadedColor->common.green, fadedColor->common.blue); + + MwLLFreeColor(c); + } } #ifdef TTF - if(MwFLDrawText) - if(MwGetInteger(handle, MwNbitmapFont) || ttf == NULL || MwFLDrawText(handle, ttf, &p, text, color)) + if(ttf <= MwFLBuildFont(0xff) && !is_bitmap(handle, ttf)) ttf = assume_ttf(handle, ttf); #endif - bitmap_MwDrawText(handle, &p, text, is_bold(handle, ttf), color); + + p.y -= (MwTextHeight(handle, ttf, text) - (MwTextHeight(handle, ttf, text) / count_nl(text))) / 2; + + while(*input != 0) { + input += MwUTF8ToUTF32(input, &cp); + + if(*input == 0 || cp == '\n') { + char* line = malloc(input - last + 1); + int i; + + if(!line) { + printf("Out Of Memory\n"); + return; + } + + memcpy(line, last, input - last); + + line[input - last] = 0; + + for(i = 0; line[i] != 0; i++) { + if(line[i] == '\r' || line[i] == '\n') { + line[i] = 0; + break; + } + } + + if(strlen(line) == 0) { + free(line); + + last = input; + + continue; + } + + p.x = point->x; + if(align == MwALIGNMENT_CENTER) { + p.x -= MwTextWidth(handle, ttf, line) / 2; + } else if(align == MwALIGNMENT_END) { + p.x -= MwTextWidth(handle, ttf, line); + } + +#ifdef TTF + if(MwFLDrawText) + if(is_bitmap(handle, ttf) || ttf == NULL || MwFLDrawText(handle, ttf, &p, line, fadedColor ? fadedColor : color)) +#endif + bitmap_MwDrawText(handle, &p, line, is_bold(handle, ttf), fadedColor ? fadedColor : color); + + p.y += MwTextHeight(handle, ttf, line); + + free(line); + + last = input; + } + } + + if(fadedColor) { + MwLLFreeColor(fadedColor); + } } int MwTextWidth(MwWidget handle, MwFLFont ttf, const char* text) { - /* TODO: check newline */ -#ifdef TTF - int st; - - if(ttf <= MwFLBuildFont(0xff)) ttf = assume_ttf(handle, ttf); - - if(MwFLTextWidth) - if(!MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextWidth(ttf, text)) != -1) return st; -#else + int len = 0; + int st; + int cp; + char* input = (char*)text; + char* last = input; +#ifndef TTF (void)handle; (void)ttf; #endif - return MwUTF8Length(text) * FontWidth; + +#ifdef TTF + if(ttf <= MwFLBuildFont(0xff)) ttf = assume_ttf(handle, ttf); +#endif + + while(*input != 0) { + input += MwUTF8ToUTF32(input, &cp); + + if(*input == 0 || cp == '\n') { + char* line = malloc(input - last + 1); + int i; + + if(!line) { + printf("Out Of Memory\n"); + return 1; + } + + memcpy(line, last, input - last); + + line[input - last] = 0; + + for(i = 0; line[i] != 0; i++) { + if(line[i] == '\r' || line[i] == '\n') { + line[i] = 0; + break; + } + } + +#ifdef TTF + if(MwFLTextWidth && !MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextWidth(ttf, line)) != -1) { + } else +#endif + st = MwUTF8Length(line) * FontWidth; + + if(st > len) len = st; + + free(line); + + last = input; + } + } + + return len; } int MwTextHeight(MwWidget handle, MwFLFont ttf, const char* text) { - int c = 1; - int i = 0; + int c = count_nl(text); #ifdef TTF int st; #endif @@ -101,17 +229,11 @@ int MwTextHeight(MwWidget handle, MwFLFont ttf, const char* text) { (void)ttf; #endif - while(text[i] != 0) { - int out; - int l = MwUTF8ToUTF32(text + i, &out); - if(l == 0) break; - i += l; - - if(out == '\n') c++; - } #ifdef TTF if(MwFLTextHeight) if(!MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextHeight(ttf, c)) != -1) return st; + if(MwFLTextHeightWithText) + if(!MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextHeightWithText(ttf, text)) != -1) return st; #endif return FontHeight * c; } @@ -138,6 +260,11 @@ static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, th = MwTextHeight(handle, NULL, text); px = malloc(tw * th * 4); + if(!px) { + printf("Out of Memory\n"); + return; + } + memset(px, 0, tw * th * 4); sx = 0; @@ -189,8 +316,11 @@ static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, typedef int (*call_t)(void); void MwFLSetup(void) { call_t calls[] = { +#ifdef USE_GDI_TEXT + MwFL_GDISetup, +#endif #ifdef USE_FREETYPE2 - MWFL_FT2Setup, + MwFL_FT2Setup, #endif #ifdef USE_STB_TRUETYPE MwFL_STBTTSetup, diff --git a/src/truetype.c b/src/truetype.c new file mode 100644 index 00000000..4f2c8196 --- /dev/null +++ b/src/truetype.c @@ -0,0 +1,142 @@ +#include + +#define REMAIN (size - (data - old)) + +MwTTFInfo MwTTFGetInfo(unsigned char* data, int size) { + unsigned short n = 0; + int i; + unsigned char* old = data; + MwTTFInfo info = malloc(sizeof(*info)); + + memset(info, 0, sizeof(*info)); + + if(size < 12) { + MwTTFFreeInfo(info); + return NULL; + } + n |= data[4 + 0]; + n = n << 8; + n |= data[4 + 1]; + + data += 12; + for(i = 0; REMAIN > 0 && i < n; i++) { + unsigned int offset = 0; + unsigned int length = 0; + int j; + + if(REMAIN < (4 + 4 + 4 + 4)) { + MwTTFFreeInfo(info); + return NULL; + } + + for(j = 0; j < 4; j++) { + offset = offset << 8; + offset |= data[4 + 4 + j]; + + length = length << 8; + length |= data[4 + 4 + 4 + j]; + } + + if(memcmp(data, "OS/2", 4) == 0) { + if(length >= 68) { + unsigned char* rev = data; + unsigned short us_weight = 0; + + data = old + offset; + if(REMAIN < 68) { + MwTTFFreeInfo(info); + return NULL; + } + + for(j = 0; j < 2; j++) { + us_weight = us_weight << 8; + us_weight |= data[0x4 + j]; + } + + info->weight = us_weight; + + data = rev; + } + } else if(memcmp(data, "name", 4) == 0) { + if(length >= 6) { + unsigned short count = 0; + unsigned char* rev = data; + unsigned short str_off = 0; + unsigned char* beg; + + data = old + offset; + if(REMAIN < (2 + 2 + 2)) { + MwTTFFreeInfo(info); + return NULL; + } + + beg = data; + + for(j = 0; j < 2; j++) { + count = count << 8; + count |= data[2 + j]; + + str_off = str_off << 8; + str_off |= data[2 + 2 + j]; + } + + data += 2 + 2 + 2; + for(j = 0; j < count; j++) { + unsigned short platform = 0; + unsigned short name = 0; + unsigned short nam_len = 0; + unsigned short nam_off = 0; + int k; + + if(REMAIN < (2 + 2 + 2 + 2 + 2 + 2)) { + MwTTFFreeInfo(info); + return NULL; + } + + for(k = 0; k < 2; k++) { + platform = platform << 8; + platform |= data[0 + k]; + + name = name << 8; + name |= data[2 + 2 + 2 + k]; + + nam_len = nam_len << 8; + nam_len |= data[2 + 2 + 2 + 2 + k]; + + nam_off = nam_off << 8; + nam_off |= data[2 + 2 + 2 + 2 + 2 + k]; + } + + /* FIXME: this does not work with surrogate */ + if((platform == 0 || platform == 3) && name == 1) { + data = beg + str_off + nam_off; + if(REMAIN < nam_len) { + MwTTFFreeInfo(info); + return NULL; + } + + if(info->family != NULL) free(info->family); + + info->family = malloc(nam_len / 2 + 1); + + for(k = 0; k < nam_len / 2; k++) info->family[k] = data[k * 2 + 1]; + info->family[k] = 0; + } + + data += 2 + 2 + 2 + 2 + 2 + 2; + } + + data = rev; + } + } + + data += 4 + 4 + 4 + 4; + } + + return info; +} + +void MwTTFFreeInfo(MwTTFInfo info) { + if(info->family != NULL) free(info->family); + free(info); +} diff --git a/src/widget/box.c b/src/widget/box.c index 6fb89355..00b5723e 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -15,6 +15,7 @@ static int wcreate(MwWidget handle) { MwSetInteger(handle, MwNpadding, 0); MwSetInteger(handle, MwNhasBorder, 0); MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNwaitLayout, 0); b->layout = 0; @@ -78,7 +79,6 @@ static void layout(MwWidget handle) { static void draw(MwWidget handle) { MwRect r; MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwBox b = handle->internal; r.x = 0; r.y = 0; @@ -92,21 +92,43 @@ static void draw(MwWidget handle) { MwDrawRect(handle, &r, base); MwLLFreeColor(base); +} - if(b->layout) { +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNorientation) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNmargin) == 0) { + MwBox b = handle->internal; + b->layout = 1; + + MwForceRender(handle); + } +} + +static void tick(MwWidget handle) { + MwBox b = handle->internal; + + if(b->layout && !MwGetInteger(handle, MwNwaitLayout)) { layout(handle); b->layout = 0; } } -static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNorientation) == 0) { - MwBox b = handle->internal; - b->layout = 1; +static void resize(MwWidget handle) { + MwBox b = handle->internal; + b->layout = 1; - MwForceRender(handle); - } + MwForceRender(handle); +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwBox b = handle->internal; + + (void)child; + (void)new_child; + + b->layout = 1; + + MwForceRender(handle); } static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { @@ -120,20 +142,6 @@ static void children_prop_change(MwWidget handle, MwWidget child, const char* ke } } -static void resize(MwWidget handle) { - MwBox b = handle->internal; - b->layout = 1; - - MwForceRender(handle); -} - -static void children_update(MwWidget handle) { - MwBox b = handle->internal; - b->layout = 1; - - MwForceRender(handle); -} - MwClassRec MwBoxClassRec = { wcreate, /* create */ destroy, /* destroy */ @@ -146,12 +154,12 @@ MwClassRec MwBoxClassRec = { NULL, /* mouse_down */ NULL, /* key */ NULL, /* execute */ - NULL, /* tick */ + tick, /* tick */ resize, /* resize */ children_update, /* children_update */ children_prop_change, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/button.c b/src/widget/button.c index 7287f2a4..7f1da57e 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -8,7 +8,6 @@ static int wcreate(MwWidget handle) { MwSetInteger(handle, MwNflat, 0); MwSetInteger(handle, MwNpadding, 0); MwSetInteger(handle, MwNfillArea, 1); - MwSetInteger(handle, MwNroundness, 5); return 0; } @@ -32,12 +31,12 @@ static void draw(MwWidget handle) { if(MwGetInteger(handle, MwNflat)) { if(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv)) { - MwDrawWidgetBack(handle, &r, base, handle->pressed, 1); + MwDrawWidgetBack(handle, &r, base, handle->pressed, MwDEFAULT); } else { MwDrawRect(handle, &r, base); } } else { - MwDrawWidgetBack(handle, &r, base, handle->pressed, 1); + MwDrawWidgetBack(handle, &r, base, handle->pressed, MwDEFAULT); } if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); if(MwGetInteger(handle, MwNflat) && !(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv))) { @@ -56,11 +55,11 @@ static void draw(MwWidget handle) { double sh = (double)oh / px->common.height; if(sw < sh) { - r.width = px->common.width * sw; - r.height = px->common.height * sw; + r.width = (int)(px->common.width * sw); + r.height = (int)(px->common.height * sw); } else { - r.width = px->common.width * sh; - r.height = px->common.height * sh; + r.width = (int)(px->common.width * sh); + r.height = (int)(px->common.height * sh); } r.width -= MwGetInteger(handle, MwNpadding) * 2; r.height -= MwGetInteger(handle, MwNpadding) * 2; @@ -69,8 +68,8 @@ static void draw(MwWidget handle) { r.height = px->common.height; } - r.x += (double)(ow - r.width) / 2; - r.y += (double)(oh - r.height) / 2; + r.x += (int)((double)(ow - r.width) / 2); + r.y += (int)((double)(oh - r.height) / 2); MwLLDrawPixmap(handle->lowlevel, &r, px); } else { @@ -109,7 +108,7 @@ MwClassRec MwButtonClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/calendar.c b/src/widget/calendar.c new file mode 100644 index 00000000..3fa304b9 --- /dev/null +++ b/src/widget/calendar.c @@ -0,0 +1,248 @@ +#include + +static unsigned int font[] = { + 0x00000000, 0x00401084, 0x0000014a, 0x00afabea, 0x01fa7cbf, 0x01111111, + 0x0126c8a2, 0x00000084, 0x00821088, 0x00221082, 0x015711d5, 0x00427c84, + 0x00220000, 0x00007c00, 0x00400000, 0x00111110, 0x00e9d72e, 0x00421084, + 0x01f2222e, 0x00e8b22e, 0x008fa54c, 0x01f87c3f, 0x00e8bc2e, 0x0042221f, + 0x00e8ba2e, 0x00e87a2e, 0x00020080, 0x00220080, 0x00820888, 0x000f83e0, + 0x00222082, 0x0042222e, 0x00ead72e, 0x011fc544, 0x00f8be2f, 0x00e8862e, + 0x00f8c62f, 0x01f0fc3f, 0x0010bc3f, 0x00e8e42e, 0x0118fe31, 0x00e2108e, + 0x00e8c210, 0x01149d31, 0x01f08421, 0x0118d771, 0x011cd671, 0x00e8c62e, + 0x0010be2f, 0x01ecc62e, 0x0114be2f, 0x00f8383e, 0x0042109f, 0x00e8c631, + 0x00454631, 0x00aad6b5, 0x01151151, 0x00421151, 0x01f1111f, 0x00e1084e, + 0x01041041, 0x00e4210e, 0x00000144, 0x01f00000, 0x00000082, 0x0164a4c0, + 0x00749c20, 0x00e085c0, 0x00e4b908, 0x0060bd26, 0x0042388c, 0x00c8724c, + 0x00a51842, 0x00420080, 0x00621004, 0x00a32842, 0x00421086, 0x015ab800, + 0x00949800, 0x0064a4c0, 0x0013a4c0, 0x008724c0, 0x00108da0, 0x0064104c, + 0x00c23880, 0x0164a520, 0x00452800, 0x00aad400, 0x00a22800, 0x00111140, + 0x00e221c0, 0x00c2088c, 0x00421084, 0x00622086, 0x000022a2}; + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNyear, 1970); + MwSetInteger(handle, MwNmonth, 0); + MwSetInteger(handle, MwNdate, 1); + MwSetInteger(handle, MwNday, 3); + MwSetInteger(handle, MwNscale, 1); + return 0; +} + +static MwLLPixmap blit(MwWidget handle, const char* str, MwLLColor bg, MwLLColor fg, int scale) { + int i; + unsigned char* buf; + MwLLPixmap px; + int w = (5 * strlen(str) + (strlen(str) - 1)) * scale; + int h = 5 * scale; + int y, x, s; + int r, g, b; + + MwColorGet(bg, &r, &g, &b); + + buf = malloc(w * h * 4); + for(i = 0; i < w * h; i++) { + buf[4 * i + 0] = r; + buf[4 * i + 1] = g; + buf[4 * i + 2] = b; + buf[4 * i + 3] = 255; + } + + MwColorGet(fg, &r, &g, &b); + + for(y = 0; y < h; y++) { + for(i = 0; str[i] != 0; i++) { + unsigned int n = font[str[i] - 0x20]; + + n = n >> (5 * (y / scale)); + + for(x = 0; x < 5; x++) { + for(s = 0; s < scale; s++) { + if(n & 1) { + unsigned char* opx = &buf[(y * w + i * (6 * scale) + x * scale + s) * 4]; + + opx[0] = r; + opx[1] = g; + opx[2] = b; + opx[3] = 255; + } + } + + n = n >> 1; + } + } + } + + px = MwLoadRaw(handle, buf, w, h); + + free(buf); + + return px; +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor cf = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor cb = MwParseColor(handle, "#fff"); + MwLLColor cb_g = MwParseColor(handle, "#666"); + MwLLColor ct = MwParseColor(handle, "#000"); + MwRect r, r2, r3; + MwPoint p[6]; + int h = 32 * MwGetInteger(handle, MwNscale); + int pw = h / 16; /* parallelogram width */ + int ph = pw * 3; /* parallelogram height */ + int gh = h / 32; /* gray area height */ + int sh = gh * 5 + gh * 2; /* shift height for year */ + char buf[5]; + const char* months[] = { + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC"}; + const char* days[] = { + "SUN", + "MON", + "TUE", + "WED", + "THU", + "FRI", + "SAT"}; + MwLLPixmap px; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, c); + + p[0].x = (r.width - h) / 2; + p[0].y = (r.height - h - sh) / 2; + p[1].x = p[0].x; + p[1].y = p[0].y + h + gh; + p[2].x = p[1].x + gh * 3; + p[2].y = p[1].y + gh * 3; + p[3].x = p[1].x + h + gh * 7; + p[3].y = p[2].y; + p[4].x = p[3].x; + p[4].y = p[0].y + gh * 7; + p[5].x = p[0].x + h; + p[5].y = p[0].y; + MwLLPolygon(handle->lowlevel, p, 6, cb_g); + + p[0].x = (r.width - h) / 2; + p[0].y = (r.height - h - sh) / 2; + p[1].x = p[0].x; + p[1].y = p[0].y + h + gh; + p[2].x = p[1].x + gh * 2; + p[2].y = p[1].y + gh * 2; + p[3].x = p[1].x + h + gh * 3; + p[3].y = p[2].y; + p[4].x = p[3].x; + p[4].y = p[0].y + gh * 3; + p[5].x = p[0].x + h; + p[5].y = p[0].y; + MwLLPolygon(handle->lowlevel, p, 6, ct); + + r2.width = h; + r2.height = h - ph - gh; + r2.x = (r.width - r2.width) / 2; + r2.y = (r.height - r2.height - ph - gh - sh) / 2; + MwDrawRect(handle, &r2, cb); + + r3.x = r2.x; + r3.y = r2.y + r2.height; + r3.width = r2.width; + r3.height = ph + gh; + MwDrawRect(handle, &r3, cb_g); + + r3.y += r3.height; + r3.height = gh; + MwDrawRect(handle, &r3, cb); + + p[0].x = r2.x; + p[0].y = r2.y + r2.height; + p[1].x = r2.x - pw; + p[1].y = r2.y + r2.height + ph; + p[2].x = r2.x + r2.width - pw; + p[2].y = r2.y + r2.height + ph; + p[3].x = r2.x + r2.width; + p[3].y = r2.y + r2.height; + MwLLPolygon(handle->lowlevel, p, 4, cb); + + p[0].x = r.width / 2; + p[0].y = (r.height - sh) / 2; + MwStringPrintIntoBuffer(buf, 3, "%d", MwGetInteger(handle, MwNdate)); + MwDrawText(handle, MwFLBuildFont(MwFLFlagBold), p, buf, MwALIGNMENT_CENTER, ct); + + r3 = r2; + + px = blit(handle, days[MwGetInteger(handle, MwNday)], cb, ct, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + gh * 2; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + px = blit(handle, months[MwGetInteger(handle, MwNmonth)], cb, ct, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + h - gh * 2 - r2.height; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + MwStringPrintIntoBuffer(buf, 5, "%d", MwGetInteger(handle, MwNyear)); + + px = blit(handle, buf, c, cf, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + h + gh * 6; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + MwLLFreeColor(cf); + MwLLFreeColor(ct); + MwLLFreeColor(cb_g); + MwLLFreeColor(cb); + MwLLFreeColor(c); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNmonth) == 0 || strcmp(key, MwNdate) == 0 || strcmp(key, MwNday) == 0) MwForceRender(handle); +} + +MwClassRec MwCalendarClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwCalendarClass = &MwCalendarClassRec; diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 2301aa0f..f196954d 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -17,8 +17,17 @@ static void draw(MwWidget handle) { r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); - MwDrawWidgetBack(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0, MwTRUE); + if(r.width < r.height) { + r.height = r.width; + } else { + r.width = r.height; + } + r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; + r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; + + MwDrawWidgetBack(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0, MwDEFAULT); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); if(handle->pressed || MwGetInteger(handle, MwNchecked)) { /* TODO: write check mark */ @@ -50,11 +59,11 @@ MwClassRec MwCheckBoxClassRec = { NULL, /* key */ NULL, /* execute */ NULL, /* tick */ - NULL, /* resize */ + MwForceRender, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 4c964f10..e53647dd 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -40,7 +40,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawWidgetBack(handle, &r, base, 0, 1); + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); rc = r; @@ -54,15 +54,6 @@ static void draw(MwWidget handle) { MwDrawText(handle, NULL, &p, cb->list[MwGetInteger(handle, MwNvalue)], MwALIGNMENT_BEGINNING, text); } - r = rc; - r.height /= 5; - r.width = r.height * 3; - r.x = MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) - r.width - MwDefaultBorderWidth(handle) * 2; - r.y = MwDefaultBorderWidth(handle); - r.height = rc.height; - r.width += MwDefaultBorderWidth(handle) * 2; - MwDrawWidgetBack(handle, &r, base, 0, 0); - r = rc; r.width = r.height * 3 / 5; r.height = r.width - MwDefaultBorderWidth(handle) * 2; @@ -78,7 +69,7 @@ static void draw(MwWidget handle) { MwLLFreeColor(base); } -static void listbox_activate(MwWidget handle, void* user, void* client) { +static void MWAPI listbox_activate(MwWidget handle, void* user, void* client) { MwComboBox cb = handle->parent->internal; (void)user; @@ -101,7 +92,6 @@ static void click(MwWidget handle) { if(cb->opened) { MwPoint p; int i; - void* packet; int width = MwGetInteger(handle, MwNwidth); int ent = MwGetInteger(handle, MwNareaShown); @@ -125,15 +115,11 @@ static void click(MwWidget handle) { MwLLSetCursor(((MwListBox)cb->listbox->internal)->frame->lowlevel, &MwCursorArrow, &MwCursorArrowMask); - packet = MwListBoxCreatePacket(); for(i = 0; i < arrlen(cb->list); i++) { - int index = MwListBoxPacketInsert(packet, -1); - MwListBoxPacketSet(packet, index, 0, cb->list[i]); + MwListBoxSet(cb->listbox, -1, 0, cb->list[i]); } - MwListBoxInsert(cb->listbox, -1, packet); - MwListBoxDestroyPacket(packet); - MwAddUserHandler(cb->listbox, MwNactivateHandler, listbox_activate, NULL); + MwAddUserHandler(cb->listbox, MwNlistBoxActivateHandler, listbox_activate, NULL); p.x = 0; p.y = MwGetInteger(handle, MwNheight); @@ -188,12 +174,19 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } } +static void parent_resize(MwWidget handle) { + MwComboBox cb = handle->internal; + if(cb->opened) { + click(handle); + } +} + MwClassRec MwComboBoxClassRec = { wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ click, /* click */ - NULL, /* parent_resize */ + parent_resize, /* parent_resize */ prop_change, /* prop_change */ NULL, /* mouse_move */ MwForceRender2, /* mouse_up */ @@ -205,7 +198,7 @@ MwClassRec MwComboBoxClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/entry.c b/src/widget/entry.c index 41b976e8..9d423bf8 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -1,25 +1,49 @@ #include +#include "../../external/stb_ds.h" static int wcreate(MwWidget handle) { - MwEntry t = malloc(sizeof(*t)); + MwEntry t = malloc(sizeof(*t)); + MwWidget topmost_parent = handle->parent; - t->cursor = 0; - t->right = 0; - t->length = 0; - handle->internal = t; + t->cursor = 0; + t->right = 0; + t->length = 0; + t->cursor_blink_timer = 0; + t->active = 0; + handle->internal = t; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + arrpush(topmost_parent->monitored_entries, handle); MwSetDefault(handle); MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); - MwSetInteger(handle, MwNroundness, 5); return 0; } static void destroy(MwWidget handle) { + int i; + MwWidget topmost_parent = handle->parent; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + for(i = 0; i < arrlen(topmost_parent->monitored_entries); i++) { + if(topmost_parent->monitored_entries[i] == handle) { + arrdel(topmost_parent->monitored_entries, i); + break; + } + } free(handle->internal); } - +static void tick(MwWidget handle) { + MwEntry t = handle->internal; + if(t->active) { + if(++t->cursor_blink_timer >= 30) { + t->cursor_blink_timer = 0; + } + MwForceRender(handle); + } +} static void draw(MwWidget handle) { MwRect r; MwEntry t = handle->internal; @@ -35,7 +59,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth) - t->right; r.height = MwGetInteger(handle, MwNheight); - MwDrawWidgetBack(handle, &r, base, 1, 1); + MwDrawWidgetBack(handle, &r, base, 1, MwDEFAULT); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); if(str != NULL) { int w = MwTextWidth(handle, font, "M"); @@ -72,11 +96,13 @@ static void draw(MwWidget handle) { for(i = 0; i < textlen; i++) show[i] = 'M'; show[i] = 0; - currc.x = p.x + MwTextWidth(handle, font, show); - currc.y = (r.height - h) / 2; - currc.width = 1; - currc.height = h; - MwDrawRect(handle, &currc, text); + if(t->active && t->cursor_blink_timer <= 15) { + currc.x = p.x + MwTextWidth(handle, font, show); + currc.y = (r.height - h) / 2 + MwDefaultBorderWidth(handle); + currc.width = 1; + currc.height = h; + MwDrawRect(handle, &currc, text); + } free(show); } @@ -92,7 +118,7 @@ static void key(MwWidget handle, int code) { char* out; if(str == NULL) str = ""; - if(code == MwLLKeyBackSpace) { + if(code == MwKEY_BACKSPACE) { if(t->cursor == 0) return; out = malloc(strlen(str) + 1); @@ -102,19 +128,20 @@ static void key(MwWidget handle, int code) { MwUTF8Copy(str, t->cursor + 1, out, t->cursor, MwUTF8Length(str) - (t->cursor + 1)); MwSetText(handle, MwNtext, out); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); free(out); - } else if(code == MwLLKeyLeft) { + } else if(code == MwKEY_LEFT) { if(t->cursor == 0) return; t->cursor--; - } else if(code == MwLLKeyRight) { + } else if(code == MwKEY_RIGHT) { if(t->cursor == MwUTF8Length(str)) return; t->cursor++; - } else if(code == MwLLKeyEnter) { + } else if(code == MwKEY_ENTER) { MwDispatchUserHandler(handle, MwNactivateHandler, NULL); - } else if(code == (MwLLControlMask | 'v')) { + } else if(code == (MwKEY_CONTROL_FLAG | 'v')) { MwLLGetClipboard(handle->lowlevel, MwCLIPBOARD_MAIN); - } else if(!(code & MwLLKeyMask)) { + } else if(!(code & MwKEY_FLAG)) { int incr = 0; out = malloc(strlen(str) + 5 + 1); incr += MwUTF8Copy(str, 0, out, 0, t->cursor); @@ -124,6 +151,7 @@ static void key(MwWidget handle, int code) { t->cursor++; MwSetText(handle, MwNtext, out); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); free(out); } @@ -147,6 +175,25 @@ static void mouse_up(MwWidget handle, void* ptr) { #define mouse_up MwForceRender2 #endif +static void mouse_down(MwWidget handle, void* ptr) { + int i = 0; + MwEntry t = handle->internal; + MwWidget topmost_parent = handle->parent; + + (void)ptr; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + + for(i = 0; i < arrlen(topmost_parent->monitored_entries); i++) { + MwEntry t = topmost_parent->monitored_entries[i]->internal; + t->active = MwFALSE; + t->cursor_blink_timer = 0; + MwForceRender(topmost_parent->monitored_entries[i]); + } + t->active = MwTRUE; + MwForceRender2(handle, NULL); +} + static void prop_change(MwWidget handle, const char* prop) { if(strcmp(prop, MwNtext) == 0 || strcmp(prop, MwNhideInput) == 0) MwForceRender(handle); @@ -186,23 +233,23 @@ static void clipboard(MwWidget handle, const char* data) { } MwClassRec MwEntryClassRec = { - wcreate, /* create */ - destroy, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - mouse_up, /* mouse_up */ - MwForceRender2, /* mouse_down */ - key, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - clipboard, /* clipboard */ - NULL, + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + mouse_up, /* mouse_up */ + mouse_down, /* mouse_down */ + key, /* key */ + NULL, /* execute */ + tick, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + clipboard, /* clipboard */ + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/frame.c b/src/widget/frame.c index 0cc0c416..f2af1080 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -62,7 +62,7 @@ MwClassRec MwFrameClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/image.c b/src/widget/image.c index 791570ec..c8e06800 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -58,7 +58,7 @@ MwClassRec MwImageClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/label.c b/src/widget/label.c index 98a0d5fe..a0be9ca5 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -6,8 +6,8 @@ static int wcreate(MwWidget handle) { MwLabel lab = malloc(sizeof(*lab)); + memset(lab, 0, sizeof(*lab)); - lab->segment = NULL; handle->internal = lab; MwSetDefault(handle); @@ -122,18 +122,21 @@ static void draw_h(MwWidget handle, unsigned char* raw, int x, int y, int stride } } -static void draw(MwWidget handle) { - MwRect r; - MwPoint p; - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); - MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); - int align; - const char* str = MwGetText(handle, MwNtext); - MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); - MwLabel lab = handle->internal; - int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); - int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; +static void draw_seven_segment(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); + int align; + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLabel lab = handle->internal; + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + MwLLPixmap px; + unsigned char* raw; + int w = 0, h = s_one * 3 + l_one * 2, i; + int x = 0; if(str == NULL) str = ""; @@ -146,141 +149,117 @@ static void draw(MwWidget handle) { if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); align = MwGetInteger(handle, MwNalignment); - if(MwGetInteger(handle, MwNsevenSegment)) { - MwLLPixmap px; - unsigned char* raw; - int w = 0, h = s_one * 3 + l_one * 2, i; - int x = 0; - /* so - this mode cannot do unicode. - * but you wouldn't show unicode on 7 segment anyways - */ + /* so - this mode cannot do unicode. + * but you wouldn't show unicode on 7 segment anyways + */ - /* L - * S <---> - * - * S - * ^ - * | - * L | - * | - * v - */ + /* L + * S <---> + * + * S + * ^ + * | + * L | + * | + * v + */ - for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { - if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; - if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { - w += l_one + s_one * 2; - } else if(str[i] == ':' || str[i] == ' ') { - w += s_one; - } + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; + if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + w += l_one + s_one * 2; + } else if(str[i] == ':' || str[i] == ' ') { + w += s_one; } + } - w++; - h++; + w++; + h++; - raw = malloc(w * h * 4); - memset(raw, 0, w * h * 4); + raw = malloc(w * h * 4); + memset(raw, 0, w * h * 4); - for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { - if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { - int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; - int j; + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; + int j; - /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ + /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ - if(hmgeti(lab->segment, i) != -1) { - unsigned char c = hmget(lab->segment, i); + if(hmgeti(lab->segment, i) != -1) { + unsigned char c = hmget(lab->segment, i); - if(c & (1 << 0)) la = 1; - if(c & (1 << 1)) lb = 1; - if(c & (1 << 2)) lc = 1; - if(c & (1 << 3)) ld = 1; - if(c & (1 << 4)) le = 1; - if(c & (1 << 5)) lf = 1; - if(c & (1 << 6)) lg = 1; - } else { - if(str[i] == '0') { - la = lb = lc = ld = le = lf = 1; - } else if(str[i] == '1') { - lb = lc = 1; - } else if(str[i] == '2') { - la = lb = ld = le = lg = 1; - } else if(str[i] == '3') { - la = lb = lc = ld = lg = 1; - } else if(str[i] == '4') { - lb = lc = lf = lg = 1; - } else if(str[i] == '5') { - la = lc = ld = lf = lg = 1; - } else if(str[i] == '6') { - la = lc = ld = le = lf = lg = 1; - } else if(str[i] == '7') { - la = lb = lc = 1; - } else if(str[i] == '8') { - la = lb = lc = ld = le = lf = lg = 1; - } else if(str[i] == '9') { - la = lb = lc = ld = lf = lg = 1; - } else if(str[i] == 'A' || str[i] == 'a') { - la = lb = lc = le = lf = lg = 1; - } else if(str[i] == 'B' || str[i] == 'b') { - lc = ld = le = lf = lg = 1; - } else if(str[i] == 'C' || str[i] == 'c') { - ld = le = lg = 1; - } else if(str[i] == 'D' || str[i] == 'd') { - lb = lc = ld = le = lg = 1; - } else if(str[i] == 'E' || str[i] == 'e') { - la = ld = le = lf = lg = 1; - } else if(str[i] == 'F' || str[i] == 'f') { - la = le = lf = lg = 1; - } + if(c & (1 << 0)) la = 1; + if(c & (1 << 1)) lb = 1; + if(c & (1 << 2)) lc = 1; + if(c & (1 << 3)) ld = 1; + if(c & (1 << 4)) le = 1; + if(c & (1 << 5)) lf = 1; + if(c & (1 << 6)) lg = 1; + } else { + if(str[i] == '0') { + la = lb = lc = ld = le = lf = 1; + } else if(str[i] == '1') { + lb = lc = 1; + } else if(str[i] == '2') { + la = lb = ld = le = lg = 1; + } else if(str[i] == '3') { + la = lb = lc = ld = lg = 1; + } else if(str[i] == '4') { + lb = lc = lf = lg = 1; + } else if(str[i] == '5') { + la = lc = ld = lf = lg = 1; + } else if(str[i] == '6') { + la = lc = ld = le = lf = lg = 1; + } else if(str[i] == '7') { + la = lb = lc = 1; + } else if(str[i] == '8') { + la = lb = lc = ld = le = lf = lg = 1; + } else if(str[i] == '9') { + la = lb = lc = ld = lf = lg = 1; + } else if(str[i] == 'A' || str[i] == 'a') { + la = lb = lc = le = lf = lg = 1; + } else if(str[i] == 'B' || str[i] == 'b') { + lc = ld = le = lf = lg = 1; + } else if(str[i] == 'C' || str[i] == 'c') { + ld = le = lg = 1; + } else if(str[i] == 'D' || str[i] == 'd') { + lb = lc = ld = le = lg = 1; + } else if(str[i] == 'E' || str[i] == 'e') { + la = ld = le = lf = lg = 1; + } else if(str[i] == 'F' || str[i] == 'f') { + la = le = lf = lg = 1; } + } - for(j = 1; j >= 0; j--) { - MwLLColor cl = j == 1 ? shadow : text; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; - if(la) draw_h(handle, raw, x + s_one + j, j, w, cl); - if(lb) draw_v(handle, raw, x + s_one + l_one + j, s_one + j, w, cl); - if(lc) draw_v(handle, raw, x + s_one + l_one + j, s_one * 2 + l_one + j, w, cl); - if(ld) draw_h(handle, raw, x + s_one + j, s_one * 2 + l_one * 2 + j, w, cl); - if(le) draw_v(handle, raw, x + j, s_one * 2 + l_one + j, w, cl); - if(lf) draw_v(handle, raw, x + j, s_one + j, w, cl); - if(lg) draw_h(handle, raw, x + s_one + j, s_one + l_one + j, w, cl); - } + if(la) draw_h(handle, raw, x + s_one + j, j, w, cl); + if(lb) draw_v(handle, raw, x + s_one + l_one + j, s_one + j, w, cl); + if(lc) draw_v(handle, raw, x + s_one + l_one + j, s_one * 2 + l_one + j, w, cl); + if(ld) draw_h(handle, raw, x + s_one + j, s_one * 2 + l_one * 2 + j, w, cl); + if(le) draw_v(handle, raw, x + j, s_one * 2 + l_one + j, w, cl); + if(lf) draw_v(handle, raw, x + j, s_one + j, w, cl); + if(lg) draw_h(handle, raw, x + s_one + j, s_one + l_one + j, w, cl); + } - x += l_one + s_one * 2; - } else if(str[i] == ':') { - int cy, cx; - int j; - for(j = 1; j >= 0; j--) { - MwLLColor cl = j == 1 ? shadow : text; - for(cy = 1; cy < h - 1; cy++) { - int h = s_one / 2; - int c = (l_one - h) / 2 + s_one; + x += l_one + s_one * 2; + } else if(str[i] == ':') { + int cy, cx; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = 1; cy < h - 1; cy++) { + int h = s_one / 2; + int c = (l_one - h) / 2 + s_one; - int c1 = (c <= cy && cy <= (c + h)) ? 1 : 0; - int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + h)) ? 1 : 0; + int c1 = (c <= cy && cy <= (c + h)) ? 1 : 0; + int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + h)) ? 1 : 0; - if(c1 || c2) { - for(cx = x; cx < x + s_one; cx++) { - unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; - px[0] = cl->common.red; - px[1] = cl->common.green; - px[2] = cl->common.blue; - px[3] = 255; - } - } - } - } - x += s_one; - } else if(str[i] == ' ') { - x += s_one; - } else if(str[i] == '.') { - int cy, cx; - int j; - for(j = 1; j >= 0; j--) { - MwLLColor cl = j == 1 ? shadow : text; - for(cy = h - (s_one - 1) / 2 - 1; cy < h; cy++) { - for(cx = x - Spacing - (s_one - 1) / 2 - 1; cx < (x - Spacing); cx++) { + if(c1 || c2) { + for(cx = x; cx < x + s_one; cx++) { unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; px[0] = cl->common.red; px[1] = cl->common.green; @@ -289,57 +268,120 @@ static void draw(MwWidget handle) { } } } - continue; } - - x += Spacing; + x += s_one; + } else if(str[i] == ' ') { + x += s_one; + } else if(str[i] == '.') { + int cy, cx; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = h - (s_one - 1) / 2 - 1; cy < h; cy++) { + for(cx = x - Spacing - (s_one - 1) / 2 - 1; cx < (x - Spacing); cx++) { + unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; + px[0] = cl->common.red; + px[1] = cl->common.green; + px[2] = cl->common.blue; + px[3] = 255; + } + } + } + continue; } - px = MwLoadRaw(handle, raw, w, h); - - r.y = (r.height - h) / 2; - r.height = h; - if(align == MwALIGNMENT_CENTER) { - r.x = (r.width - w) / 2; - } else if(align == MwALIGNMENT_BEGINNING) { - r.x = 0; - } else if(align == MwALIGNMENT_END) { - r.x = r.width - w; - } - r.width = w; - MwLLDrawPixmap(handle->lowlevel, &r, px); - - MwLLDestroyPixmap(px); - } else { - r.width -= MwGetInteger(handle, MwNleftPadding); - - if(align == MwALIGNMENT_CENTER) { - p.x = r.width / 2; - } else if(align == MwALIGNMENT_BEGINNING) { - p.x = MwTextWidth(handle, NULL, str) / 2; - } else if(align == MwALIGNMENT_END) { - p.x = r.width - MwTextWidth(handle, NULL, str) / 2; - } - p.y = r.height / 2; - - p.x += MwGetInteger(handle, MwNleftPadding); - - p.x += 1; - p.y += 1; - MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, shadow); - - p.x -= 1; - p.y -= 1; - MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, text); + x += Spacing; } + px = MwLoadRaw(handle, raw, w, h); + + r.y = (r.height - h) / 2; + r.height = h; + if(align == MwALIGNMENT_CENTER) { + r.x = (r.width - w) / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + r.x = 0; + } else if(align == MwALIGNMENT_END) { + r.x = r.width - w; + } + r.width = w; + MwLLDrawPixmap(handle->lowlevel, &r, px); + + free(raw); + + MwLLDestroyPixmap(px); +} + +static void draw_normal(MwWidget handle) { + MwRect r; + MwPoint p; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); + int align; + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + if(str == NULL) str = ""; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, base); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + align = MwGetInteger(handle, MwNalignment); + + r.width -= MwGetInteger(handle, MwNleftPadding); + +#if 1 + if(align == MwALIGNMENT_CENTER) { + p.x = r.width / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + p.x = MwTextWidth(handle, NULL, str) / 2; + } else if(align == MwALIGNMENT_END) { + p.x = r.width - MwTextWidth(handle, NULL, str) / 2; + } +#else + p.x = 0; +#endif + p.y = r.height / 2; + + p.x += MwGetInteger(handle, MwNleftPadding); + + p.x += 1; + p.y += 1; + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, shadow); + + p.x -= 1; + p.y -= 1; + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, text); + MwLLFreeColor(shadow); MwLLFreeColor(text); MwLLFreeColor(base); } +static void draw(MwWidget handle) { + MwLabel lab = handle->internal; + if(!lab->draw) { + lab->draw = draw_normal; + } + lab->draw(handle); +} + static void prop_change(MwWidget handle, const char* key) { if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0 || strcmp(key, MwNlength) == 0 || strcmp(key, MwNleftPadding) == 0) MwForceRender(handle); + + if(strcmp(key, MwNsevenSegment) == 0) { + MwLabel lab = handle->internal; + if(MwGetInteger(handle, MwNsevenSegment)) + lab->draw = draw_seven_segment; + else + lab->draw = draw_normal; + } } static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) { @@ -376,7 +418,7 @@ MwClassRec MwLabelClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 6f2a9db2..cc173628 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -6,61 +6,6 @@ #define Font MwFLBuildFont(MwFLFlagMonospace) -MwListBoxPacket* MwListBoxCreatePacket(void) { - MwListBoxPacket* packet = malloc(sizeof(*packet)); - memset(packet, 0, sizeof(*packet)); - - return packet; -} - -void MwListBoxDestroyPacket(MwListBoxPacket* packet) { - int i; - int j; - - for(i = 0; i < arrlen(packet->names); i++) { - for(j = 0; j < arrlen(packet->names[i]); j++) { - if(packet->names[i][j] != NULL) free(packet->names[i][j]); - } - arrfree(packet->names[i]); - } - - arrfree(packet->names); - arrfree(packet->pixmaps); - - free(packet); -} - -int MwListBoxPacketInsert(MwListBoxPacket* packet, int index) { - int i; - - if(index == -1) index = arrlen(packet->names); - for(i = arrlen(packet->names); i < index; i++) { - arrput(packet->names, NULL); - arrput(packet->pixmaps, NULL); - } - - arrins(packet->names, index, NULL); - arrins(packet->pixmaps, index, NULL); - - return index; -} - -void MwListBoxPacketSet(MwListBoxPacket* packet, int index, int col, const char* text) { - char* t = text == NULL ? NULL : MwStringDuplicate(text); - int i; - - if(col == -1) col = arrlen(packet->names[index]); - for(i = arrlen(packet->names[index]); i < col; i++) { - arrput(packet->names[index], NULL); - } - - arrins(packet->names[index], col, t); -} - -void MwListBoxPacketSetIcon(MwListBoxPacket* packet, int index, MwLLPixmap icon) { - packet->pixmaps[index] = icon; -} - static int get_first_entry(MwWidget handle, MwListBox lb) { int st = 0; int y = MwGetInteger(handle, MwNhasHeading) ? 1 : 0; @@ -109,7 +54,7 @@ static int get_col_width(MwListBox lb, int ind) { return 0; } -static void vscroll_changed(MwWidget handle, void* user, void* call) { +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { MwListBox lb = handle->parent->internal; (void)user; @@ -118,7 +63,7 @@ static void vscroll_changed(MwWidget handle, void* user, void* call) { lb->changed = 1; } -static void frame_mouse_down(MwWidget handle, void* user, void* call) { +static void MWAPI frame_mouse_down(MwWidget handle, void* user, void* call) { MwListBox lb = handle->parent->internal; MwMouse* m = call; @@ -153,7 +98,7 @@ static void frame_mouse_down(MwWidget handle, void* user, void* call) { } } -static void frame_mouse_up(MwWidget handle, void* user, void* call) { +static void MWAPI frame_mouse_up(MwWidget handle, void* user, void* call) { MwListBox lb = handle->parent->internal; MwMouse* m = call; @@ -164,7 +109,7 @@ static void frame_mouse_up(MwWidget handle, void* user, void* call) { } } -static void frame_mouse_move(MwWidget handle, void* user, void* call) { +static void MWAPI frame_mouse_move(MwWidget handle, void* user, void* call) { MwListBox lb = handle->parent->internal; MwPoint* p = call; @@ -242,45 +187,73 @@ static void frame_draw(MwWidget handle) { r2.height = h; MwLLDrawPixmap(handle->lowlevel, &r2, lb->list[i].pixmap); } - p.y += (MwTextHeight(handle, Font, "M") + Padding) / 2; p.x = MwDefaultBorderWidth(handle) + MwGetInteger(handle->parent, MwNleftPadding); for(j = 0; j < arrlen(lb->list[i].name); j++) { - char* t = lb->list[i].name[j]; - char* str; - int l = (j == 0 ? MwGetInteger(handle->parent, MwNleftPadding) : 0); + char* t = lb->list[i].name[j]; + char* str; + int l = (j == 0 ? MwGetInteger(handle->parent, MwNleftPadding) : 0); + MwPoint p2 = p; + p2.y += (MwTextHeight(handle, Font, "M") + Padding) / 2; if(t == NULL) t = ""; str = MwStringDuplicate(t); if(MwUTF8Length(str) > (get_col_width(lb, j) - l) / MwTextWidth(handle, Font, "M")) { - int ind = (get_col_width(lb, j) - l) / MwTextWidth(handle, Font, "M"); - str[ind] = 0; - if(ind > 3) memset(str + ind - 3, '.', 3); + int ind = (get_col_width(lb, j) - l) / MwTextWidth(handle, Font, "M") - 3; + int seek = 0; + int l = 0; + char* old = str; + int sz = strlen(old) + 5; + + if(ind < 0) ind = 0; + + str = malloc(sz); +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + strcpy_s(str, sz, old); +#else + strcpy(str, old); +#endif + free(old); + + while(str[seek] != 0) { + int cp; + if(l == ind) break; + + seek += MwUTF8ToUTF32(str + seek, &cp); + + l++; + } + + memset(str + seek, '.', 3); + str[seek + 3] = 0; } if(j == (arrlen(lb->list[i].name) - 1)) p.x -= MwDefaultBorderWidth(handle); if(arrlen(lb->alignment) <= j || lb->alignment[j] == MwALIGNMENT_BEGINNING) { p.x += 4; - MwDrawText(handle, Font, &p, str, MwALIGNMENT_BEGINNING, selected ? base2 : text2); + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_BEGINNING, selected ? base2 : text2); p.x -= 4; p.x += get_col_width(lb, j); } else if(lb->alignment[j] == MwALIGNMENT_CENTER) { p.x += (get_col_width(lb, j) - l) / 2; - MwDrawText(handle, Font, &p, str, MwALIGNMENT_CENTER, selected ? base2 : text2); + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_CENTER, selected ? base2 : text2); p.x += (get_col_width(lb, j) - l) / 2; p.x += l; } else if(lb->alignment[j] == MwALIGNMENT_END) { p.x += get_col_width(lb, j); p.x -= 4; - MwDrawText(handle, Font, &p, str, MwALIGNMENT_END, selected ? base2 : text2); + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_END, selected ? base2 : text2); p.x += 4; } free(str); if(j == 0) p.x -= MwGetInteger(handle->parent, MwNleftPadding); } - p.y += (MwTextHeight(handle, Font, "M") + Padding) / 2; + p.y += MwTextHeight(handle, Font, "M") + Padding; handle->bgcolor = NULL; } @@ -292,19 +265,19 @@ static void frame_draw(MwWidget handle) { MwLLFreeColor(base); } -static void resize(MwWidget handle) { +static void resize(MwWidget handle, int no_resize) { MwListBox lb = handle->internal; int w = MwGetInteger(handle, MwNwidth); int h = MwGetInteger(handle, MwNheight); int ih, y; int m = 0; - y = MwGetInteger(handle, MwNhasHeading) ? (MwTextHeight(handle, NULL, "M") + MwDefaultBorderWidth(handle) * 2) : 0; + y = MwGetInteger(handle, MwNhasHeading) ? (MwTextHeight(handle, Font, "M") + MwDefaultBorderWidth(handle) * 2) : 0; if(lb->vscroll == NULL) { lb->vscroll = MwVaCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h, NULL); MwAddUserHandler(lb->vscroll, MwNchangedHandler, vscroll_changed, NULL); - } else { + } else if(!no_resize) { MwVaApply(lb->vscroll, MwNx, w - 16, MwNy, 0, @@ -331,7 +304,7 @@ static void resize(MwWidget handle) { MwAddUserHandler(lb->frame, MwNmouseDownHandler, frame_mouse_down, NULL); MwAddUserHandler(lb->frame, MwNmouseUpHandler, frame_mouse_up, NULL); MwAddUserHandler(lb->frame, MwNmouseMoveHandler, frame_mouse_move, NULL); - } else { + } else if(!no_resize || MwGetInteger(lb->frame, MwNwidth) != (w - m)) { MwVaApply(lb->frame, MwNx, 0, MwNy, y, @@ -349,6 +322,11 @@ static void resize(MwWidget handle) { static int wcreate(MwWidget handle) { MwListBox lb = malloc(sizeof(*lb)); + if(!lb) { + printf("Out Of Memory\n"); + return 1; + } + memset(lb, 0, sizeof(*lb)); handle->internal = lb; @@ -360,7 +338,7 @@ static int wcreate(MwWidget handle) { MwSetInteger(handle, MwNleftPadding, 0); MwSetInteger(handle, MwNvalue, -1); - resize(handle); + resize(handle, 0); lb->list = NULL; lb->click_time = 0; lb->width = NULL; @@ -402,7 +380,7 @@ static void draw(MwWidget handle) { r.x = x; r.y = 0; r.width = get_col_width(lb, i); - r.height = MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, NULL, "M"); + r.height = MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, Font, "M"); MwDrawFrame(handle, &r, base, 0); x += MwDefaultBorderWidth(handle); @@ -432,9 +410,8 @@ static void draw(MwWidget handle) { } static void prop_change(MwWidget handle, const char* prop) { - if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0 || strcmp(prop, MwNhasHeading) == 0) resize(handle); + MwListBox lb = handle->internal; if(strcmp(prop, MwNleftPadding) == 0) { - MwListBox lb = handle->internal; MwForceRender(lb->frame); } if(strcmp(prop, MwNhasHeading) == 0) { @@ -442,45 +419,68 @@ static void prop_change(MwWidget handle, const char* prop) { } } -static void mwListBoxInsertImpl(MwWidget handle, int index, MwListBoxPacket* packet) { - int i; +static void redrawIfNeeded(MwWidget handle, int row) { MwListBox lb = handle->internal; - int old; - int max = 0; - if(index == -1) index = arrlen(lb->list); - old = index; - for(i = 0; i < arrlen(packet->names); i++) { - if(arrlen(packet->names[i]) > max) max = arrlen(packet->names[i]); - } - - for(i = 0; i < arrlen(packet->names); i++) { - MwListBoxEntry entry; - char* name; - int j; - - entry.name = NULL; - for(j = 0; j < max; j++) { - if(arrlen(packet->names[i]) > j && packet->names[i][j] != NULL) { - name = MwStringDuplicate(packet->names[i][j]); - arrput(entry.name, name); - } else { - arrput(entry.name, NULL); - } - } - - entry.pixmap = packet->pixmaps[i]; - - arrins(lb->list, index, entry); - index++; - } - - resize(handle); - if(old < (MwGetInteger(lb->vscroll, MwNvalue) + MwGetInteger(lb->vscroll, MwNareaShown))) { + if(MwGetInteger(lb->vscroll, MwNvalue) <= row && row <= (MwGetInteger(lb->vscroll, MwNvalue) + MwGetInteger(lb->vscroll, MwNareaShown))) { MwForceRender(lb->frame); } } +static int mwListBoxSetImpl(MwWidget handle, int row, int col, const char* text) { + MwListBox lb = handle->internal; + MwListBoxEntry entry; + char* t = text == NULL ? NULL : MwStringDuplicate(text); + int new = 0; + if(row == -1) row = arrlen(lb->list); + + entry.name = NULL; + entry.pixmap = NULL; + if(row < arrlen(lb->list)) { + entry = lb->list[row]; + } + + if(col == -1) col = arrlen(entry.name); + arrins(entry.name, col, t); + + if(row < arrlen(lb->list)) { + lb->list[row] = entry; + } else { + arrins(lb->list, row, entry); + new = 1; + } + + if(new) resize(handle, 1); + redrawIfNeeded(handle, row); + + return row; +} + +static void mwListBoxSetIconImpl(MwWidget handle, int index, MwLLPixmap icon) { + MwListBox lb = handle->internal; + MwListBoxEntry entry; + int new = 0; + if(index == -1) index = arrlen(lb->list); + + entry.name = NULL; + entry.pixmap = NULL; + if(index < arrlen(lb->list)) { + entry = lb->list[index]; + } + + entry.pixmap = icon; + + if(index < arrlen(lb->list)) { + lb->list[index] = entry; + } else { + arrins(lb->list, index, entry); + new = 1; + } + + if(new) resize(handle, 1); + redrawIfNeeded(handle, index); +} + static void mwListBoxDeleteImpl(MwWidget handle, int index) { MwListBox lb = handle->internal; int i; @@ -499,7 +499,7 @@ static void mwListBoxDeleteImpl(MwWidget handle, int index) { MwSetInteger(handle, MwNvalue, -1); } - resize(handle); + resize(handle, 1); if(index < (MwGetInteger(lb->vscroll, MwNvalue) + MwGetInteger(lb->vscroll, MwNareaShown))) { MwForceRender(lb->frame); } @@ -521,7 +521,7 @@ static void mwListBoxResetImpl(MwWidget handle) { MwSetInteger(lb->vscroll, MwNvalue, 0); - resize(handle); + resize(handle, 0); MwForceRender(lb->frame); } @@ -578,10 +578,16 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v int alignment = va_arg(va, int); mwListBoxSetAlignmentImpl(handle, index, alignment); } - if(strcmp(name, "mwListBoxInsert") == 0) { - int index = va_arg(va, int); - MwListBoxPacket* packet = va_arg(va, MwListBoxPacket*); - mwListBoxInsertImpl(handle, index, packet); + if(strcmp(name, "mwListBoxSet") == 0) { + int row = va_arg(va, int); + int col = va_arg(va, int); + const char* text = va_arg(va, const char*); + *(int*)out = mwListBoxSetImpl(handle, row, col, text); + } + if(strcmp(name, "mwListBoxSetIcon") == 0) { + int index = va_arg(va, int); + MwLLPixmap icon = va_arg(va, MwLLPixmap); + mwListBoxSetIconImpl(handle, index, icon); } } @@ -594,6 +600,17 @@ static void tick(MwWidget handle) { } } +static void props_change(MwWidget handle, char** props) { + int i; + int rsz = 0; + + for(i = 0; props[i] != NULL; i++) { + if(strcmp(props[i], MwNwidth) == 0 || strcmp(props[i], MwNheight) == 0 || strcmp(props[i], MwNhasHeading) == 0) rsz = 1; + } + + if(rsz) resize(handle, 0); +} + MwClassRec MwListBoxClassRec = { wcreate, /* create */ destroy, /* destroy */ @@ -611,7 +628,7 @@ MwClassRec MwListBoxClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + props_change, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/menu.c b/src/widget/menu.c index 1517591b..8dd3d7a9 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -1,7 +1,6 @@ #include #include "../../external/stb_ds.h" -#include "Mw/TypeDefs.h" static void set_xywh(MwWidget handle) { int height = 0; @@ -25,6 +24,7 @@ static int wcreate(MwWidget handle) { m->wsub = NULL; m->sub = NULL; handle->internal = m; + handle->is_menu = MwTRUE; MwSetDefault(handle); @@ -57,8 +57,10 @@ static void destroy(MwWidget handle) { MwPoint p; \ MwRect r; \ int rx; \ -\ - p.x = 5; \ + int in_area; + +#define MENU_LOOP_INIT \ + p.x = 0; \ p.y = (MwGetInteger(handle, MwNheight) - MwDefaultBorderWidth(handle)) / 2 + MwDefaultBorderWidth(handle); \ \ r.x = 0; \ @@ -66,45 +68,56 @@ static void destroy(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); \ r.height = MwGetInteger(handle, MwNheight); \ \ - rx = r.width - 5; + rx = r.width; #define BEGIN_MENU_LOOP \ for(i = 0; i < arrlen(m->sub); i++) { \ int incr = m->sub[i]->name[0] == '?' ? 1 : 0; \ - int tw = MwTextWidth(handle, NULL, m->sub[i]->name + incr); \ - int th = MwTextHeight(handle, NULL, m->sub[i]->name + incr); \ - int in_area; \ + int tw = MwTextWidth(handle, MwFLBuildFont(MwFLFlagBold), m->sub[i]->name + incr); \ + int th = MwTextHeight(handle, MwFLBuildFont(MwFLFlagBold), m->sub[i]->name + incr); \ \ if(incr) { \ - p.x = rx -= tw; \ - rx -= 10; \ + p.x = rx -= 10 + tw; \ } \ \ - r.x = p.x - 5; \ + r.x = p.x; \ r.y = p.y + ((MwGetInteger(handle, MwNheight) - p.y * 2) - (th + 10)) / 2; \ r.width = tw + 10; \ r.height = th + 10; \ \ - in_area = (r.x <= handle->mouse_point.x && r.y <= handle->mouse_point.y && handle->mouse_point.x <= (int)(r.x + r.width) && handle->mouse_point.y <= (int)(r.y + r.height)) ? 1 : 0; + in_area = (r.x <= handle->mouse_point.x && r.y <= handle->mouse_point.y && handle->mouse_point.x <= (int)(r.x + r.width) && handle->mouse_point.y <= (int)(r.y + r.height)) ? 1 : 0; \ + p.x += 5 + tw / 2; #define END_MENU_LOOP \ - p.x += tw + 20; \ + p.x += tw / 2 + 5; \ } +#define NEW_SUBMENU \ + MwPoint p2; \ +\ + p2.x = p.x - 5 - tw / 2; \ + p2.y = p.y + th / 2 + 5; \ +\ + m->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, MwGetInteger(handle, MwNheight), 0, 0); \ + MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2, 0); \ + m->sub[i]->cleaned = 0; + static void draw(MwWidget handle) { MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); MENU_LOOP_DECL; - MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); + MENU_LOOP_INIT; + + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); BEGIN_MENU_LOOP; if(m->sub[i]->wsub != NULL || (in_area && handle->pressed)) { MwDrawFrame(handle, &r, base, MwFALSE); - MwDrawWidgetBack(handle, &r, base, 0, MwFALSE); + MwDrawWidgetBack(handle, &r, base, 0, 0); } - MwDrawText(handle, MwFLBuildFont((m->sub[i]->wsub != NULL || (in_area && handle->pressed)) ? MwFLFlagBold : 0), &p, m->sub[i]->name + incr, MwALIGNMENT_BEGINNING, text); + MwDrawText(handle, MwFLBuildFont((m->sub[i]->wsub != NULL || (in_area && handle->pressed)) ? MwFLFlagBold : 0), &p, m->sub[i]->name + incr, MwALIGNMENT_CENTER, text); END_MENU_LOOP; MwLLFreeColor(text); @@ -118,47 +131,86 @@ static void parent_resize(MwWidget handle) { static void mouse_down(MwWidget handle, void* ptr) { MENU_LOOP_DECL; + MENU_LOOP_INIT; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; BEGIN_MENU_LOOP; if(in_area) { if(m->sub[i]->wsub == NULL && arrlen(m->sub[i]->sub) > 0) { - MwPoint p2; - - p2.x = p.x - 5; - p2.y = p.y + th / 2 + 5; - - m->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0); - MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2, 0); + NEW_SUBMENU; } else if(m->sub[i]->wsub != NULL && m->sub[i]->keep) { MwDestroyWidget(m->sub[i]->wsub); - m->sub[i]->wsub = NULL; - m->sub[i]->keep = 0; - } else if(arrlen(m->sub[i]->sub) == 0) { - MwDispatchUserHandler(handle, MwNmenuHandler, m->sub[i]); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 1; } } else if(m->sub[i]->keep && m->sub[i]->wsub != NULL) { MwDestroyWidget(m->sub[i]->wsub); - m->sub[i]->wsub = NULL; - m->sub[i]->keep = 0; + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 1; } END_MENU_LOOP; MwForceRender(handle); } +static void mouse_move(MwWidget handle) { + int matched = 0; + MENU_LOOP_DECL; + + MENU_LOOP_INIT; + + if(!handle->pressed) return; + + BEGIN_MENU_LOOP; + if(in_area && m->sub[i]->wsub == NULL) { + matched = 1; + } + END_MENU_LOOP; + + MENU_LOOP_INIT; + BEGIN_MENU_LOOP; + if(matched && m->sub[i]->wsub != NULL) { + MwDestroyWidget(m->sub[i]->wsub); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 0; + } + END_MENU_LOOP; + + MENU_LOOP_INIT; + BEGIN_MENU_LOOP; + if(matched && in_area) { + if(m->sub[i]->wsub == NULL && arrlen(m->sub[i]->sub) > 0 && !m->sub[i]->cleaned) { + NEW_SUBMENU; + } + } + END_MENU_LOOP; + + if(matched) MwForceRender(handle); +} + static void mouse_up(MwWidget handle, void* ptr) { MENU_LOOP_DECL; + MENU_LOOP_INIT; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; BEGIN_MENU_LOOP; if(in_area && m->sub[i]->wsub != NULL) { m->sub[i]->keep = 1; + } else if(in_area) { + if(arrlen(m->sub[i]->sub) == 0) { + MwDispatchUserHandler(handle, MwNmenuHandler, m->sub[i]); + } } else if(m->sub[i]->wsub != NULL) { MwDestroyWidget(m->sub[i]->wsub); - m->sub[i]->wsub = NULL; - m->sub[i]->keep = 0; + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 0; } END_MENU_LOOP; @@ -166,12 +218,13 @@ static void mouse_up(MwWidget handle, void* ptr) { } static MwMenu mwMenuAddImpl(MwWidget handle, MwMenu menu, const char* name) { - MwMenu m = menu == NULL ? handle->internal : menu; - MwMenu new = malloc(sizeof(*new)); - new->name = MwStringDuplicate(name); - new->sub = NULL; - new->wsub = NULL; - new->keep = 0; + MwMenu m = menu == NULL ? handle->internal : menu; + MwMenu new = malloc(sizeof(*new)); + new->name = MwStringDuplicate(name); + new->sub = NULL; + new->wsub = NULL; + new->keep = 0; + new->cleaned = 0; arrput(m->sub, new); @@ -195,7 +248,7 @@ MwClassRec MwMenuClassRec = { NULL, /* click */ parent_resize, /* parent_resize */ NULL, /* prop_change */ - NULL, /* mouse_move */ + mouse_move, /* mouse_move */ mouse_up, /* mouse_up */ mouse_down, /* mouse_down */ NULL, /* key */ @@ -205,7 +258,7 @@ MwClassRec MwMenuClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 69ee4c9d..f3a80e94 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -33,7 +33,7 @@ static void draw(MwWidget handle) { r.y = 0; r.width = e->right; r.height = h / 2; - MwDrawWidgetBack(handle, &r, base, pr, MwTRUE); + MwDrawWidgetBack(handle, &r, base, pr, MwDEFAULT); if(r.width > r.height) { r.width = r.height; @@ -49,7 +49,7 @@ static void draw(MwWidget handle) { r.y = h / 2; r.width = e->right; r.height = h / 2; - MwDrawWidgetBack(handle, &r, base, pr, MwTRUE); + MwDrawWidgetBack(handle, &r, base, pr, MwDEFAULT); if(r.width > r.height) { r.width = r.height; @@ -75,7 +75,7 @@ static void key(MwWidget handle, int code) { ok = 1; } else if(code == '.' && strchr(str, (int)'.') == NULL) { ok = 1; - } else if(code == MwLLKeyBackSpace || code == MwLLKeyLeft || code == MwLLKeyRight) { + } else if(code == MwKEY_BACKSPACE || code == MwKEY_LEFT || code == MwKEY_RIGHT) { ok = 1; } @@ -108,6 +108,8 @@ static void mouse_up(MwWidget handle, void* ptr) { MwStringPrintIntoBuffer(s, 512, "%g", atof(str) + 1); } MwSetText(handle, MwNtext, s); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); } MwForceRender(handle); @@ -144,7 +146,7 @@ MwClassRec MwNumberEntryClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 252d7ad5..30a1cee8 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -55,16 +55,26 @@ typedef struct x11opengl { #ifdef USE_WAYLAND #include #include +#include +#include +/* +Note that for Wayland we create a GBM buffer manually and handle blitting it ourselves instead of using wayland-egl. Doing this allows us greater freedom over event handling; wayland-egl constantly pumps events, making us have to add a weird exception to wayland.c to make this work. Doing this also allows us to clip the OpenGL widget, something that was harder (impossible) with egl wayland. +*/ typedef struct waylandopengl { - EGLNativeWindowType egl_window_native; EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; EGLConfig egl_config; + struct gbm_device* gbm; + struct gbm_surface* gbm_surface; + struct gbm_bo* previous_bo; + int drm_fd; + MwLLPixmap frontbuffer; + MwU8* frontbuffer_data; void* gllib; - void* wlgllib; + void* gbmlib; EGLBoolean (*eglGetConfigs)(EGLDisplay display, EGLConfig* configs, EGLint config_size, @@ -88,21 +98,32 @@ typedef struct waylandopengl { EGLint (*eglGetError)(void); EGLBoolean (*eglBindAPI)(EGLenum api); EGLDisplay (*eglGetDisplay)(NativeDisplayType native_display); - EGLSurface (*eglCreateWindowSurface)(EGLDisplay display, - EGLConfig config, - NativeWindowType native_window, - EGLint const* attrib_list); + EGLDisplay (*eglGetPlatformDisplay)(EGLenum platform, void* native_display, const EGLAttrib* attrib_list); + EGLSurface (*eglCreatePlatformWindowSurface)(EGLDisplay display, + EGLConfig config, + void* native_window, + EGLint const* attrib_list); EGLBoolean (*eglChooseConfig)(EGLDisplay display, EGLint const* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config); + EGLBoolean (*eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value); + EGLBoolean (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + + struct gbm_device* (*gbm_create_device)(int fd); + struct gbm_surface* (*gbm_surface_create)(struct gbm_device* gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); + void (*gbm_surface_destroy)(struct gbm_surface* surface); + + struct gbm_bo* (*gbm_surface_lock_front_buffer)(struct gbm_surface* surface); + union gbm_bo_handle (*gbm_bo_get_handle)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_stride)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_width)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_height)(struct gbm_bo* bo); + void (*gbm_surface_release_buffer)(struct gbm_surface* surface, struct gbm_bo* bo); + void* (*gbm_bo_map)(struct gbm_bo* bo, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t flags, uint32_t* stride, void** map_data); + void (*gbm_bo_unmap)(struct gbm_bo* bo, void* map_data); - struct wl_egl_window* (*wl_egl_window_create)(struct wl_surface* surface, - int width, int height); - void (*wl_egl_window_resize)(struct wl_egl_window* egl_window, - int width, int height, - int dx, int dy); } waylandopengl_t; #endif @@ -129,15 +150,22 @@ static int wcreate(MwWidget handle) { SetPixelFormat(o->dc, pf, &pfd); o->lib = MwDynamicOpen("opengl32.dll"); + if(!o->lib) { + printf("Could not load OpenGL widget under WGL!\n"); + return 1; + } - o->wglCreateContext = - (MWwglCreateContext)(void*)MwDynamicSymbol(o->lib, "wglCreateContext"); - o->wglMakeCurrent = - (MWwglMakeCurrent)(void*)MwDynamicSymbol(o->lib, "wglMakeCurrent"); - o->wglDeleteContext = - (MWwglDeleteContext)(void*)MwDynamicSymbol(o->lib, "wglDeleteContext"); - o->wglGetProcAddress = (MWwglGetProcAddress)(void*)MwDynamicSymbol( - o->lib, "wglGetProcAddress"); +#define WGL_FUNC(x) \ + o->x = MwDynamicSymbol(o->lib, #x); \ + if(o->x == NULL) { \ + printf("Could not load OpenGL widget under WGL! " #x " missing.\n"); \ + return 1; \ + } + + WGL_FUNC(wglCreateContext); + WGL_FUNC(wglMakeCurrent); + WGL_FUNC(wglDeleteContext); + WGL_FUNC(wglGetProcAddress); o->gl = o->wglCreateContext(o->dc); } @@ -183,6 +211,7 @@ static int wcreate(MwWidget handle) { #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { EGLint numConfigs; + EGLint numConfigsMatched; EGLint majorVersion; EGLint minorVersion; EGLContext context; @@ -190,7 +219,7 @@ static int wcreate(MwWidget handle) { EGLint fbAttribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, + EGL_OPENGL_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, @@ -199,8 +228,6 @@ static int wcreate(MwWidget handle) { 8, EGL_DEPTH_SIZE, 24, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_BIT, EGL_NONE}; EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 1, @@ -210,17 +237,19 @@ static int wcreate(MwWidget handle) { 1, EGL_NONE}; EGLDisplay display; - waylandopengl_t* o = r = malloc(sizeof(*o)); - MwWaylandAlwaysRender = MwTRUE; + waylandopengl_t* o = r = malloc(sizeof(*o)); + int gbm_format = 0; + EGLConfig egl_configs[1024]; + memset(o, 0, sizeof(waylandopengl_t)); o->gllib = MwDynamicOpen("libEGL.so"); if(!o->gllib) { printf("Could not load OpenGL widget under Wayland! libEGL.so missing.\n"); return 1; } - o->wlgllib = MwDynamicOpen("libwayland-egl.so"); - if(!o->gllib) { - printf("Could not load OpenGL widget under Wayland! libwayland-egl.so missing.\n"); + o->gbmlib = MwDynamicOpen("libgbm.so"); + if(!o->gbmlib) { + printf("Could not load OpenGL widget under Wayland! libgbm.so missing.\n"); return 1; } #define EGL_FUNC(x) \ @@ -229,8 +258,8 @@ static int wcreate(MwWidget handle) { printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ return 1; \ }; -#define WAYLAND_EGL_FUNC(x) \ - o->x = MwDynamicSymbol(o->wlgllib, #x); \ +#define GBM_FUNC(x) \ + o->x = MwDynamicSymbol(o->gbmlib, #x); \ if(!o->x) { \ printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ return 1; \ @@ -245,10 +274,22 @@ static int wcreate(MwWidget handle) { EGL_FUNC(eglGetError) EGL_FUNC(eglBindAPI) EGL_FUNC(eglGetDisplay) - EGL_FUNC(eglCreateWindowSurface) + EGL_FUNC(eglCreatePlatformWindowSurface) EGL_FUNC(eglChooseConfig) - WAYLAND_EGL_FUNC(wl_egl_window_create) - WAYLAND_EGL_FUNC(wl_egl_window_resize) + EGL_FUNC(eglGetPlatformDisplay) + EGL_FUNC(eglGetConfigAttrib) + EGL_FUNC(eglDestroySurface) + GBM_FUNC(gbm_create_device) + GBM_FUNC(gbm_surface_create) + GBM_FUNC(gbm_surface_destroy) + GBM_FUNC(gbm_surface_lock_front_buffer) + GBM_FUNC(gbm_bo_get_handle) + GBM_FUNC(gbm_bo_get_stride) + GBM_FUNC(gbm_bo_get_width) + GBM_FUNC(gbm_bo_get_height) + GBM_FUNC(gbm_surface_release_buffer) + GBM_FUNC(gbm_bo_map) + GBM_FUNC(gbm_bo_unmap) #define eglGetConfigs o->eglGetConfigs #define eglInitialize o->eglInitialize @@ -258,70 +299,86 @@ static int wcreate(MwWidget handle) { #define eglSwapBuffers o->eglSwapBuffers #define eglSwapInterval o->eglSwapInterval #define eglGetError o->eglGetError -#define wl_egl_window_create o->wl_egl_window_create #define eglBindAPI o->eglBindAPI #define eglGetDisplay o->eglGetDisplay -#define wl_egl_window_resize o->wl_egl_window_resize -#define eglCreateWindowSurface o->eglCreateWindowSurface +#define eglCreatePlatformWindowSurface o->eglCreatePlatformWindowSurface +#define eglDestroySurface o->eglDestroySurface #define eglChooseConfig o->eglChooseConfig +#define eglGetPlatformDisplay o->eglGetPlatformDisplay - display = - eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->wayland.display); + o->drm_fd = open("/dev/dri/renderD128", O_RDWR); + assert(o->drm_fd > 0); + o->gbm = o->gbm_create_device(o->drm_fd); + assert(o->gbm != NULL); + + display = eglGetPlatformDisplay(0x31D7, o->gbm, NULL); if(display == EGL_NO_DISPLAY) { printf("ERROR: eglGetDisplay, %0X\n", eglGetError()); - return MwFALSE; + return 1; } + /* Initialize EGL */ if(!eglInitialize(display, &majorVersion, &minorVersion)) { printf("ERROR: eglInitialize, %0X\n", eglGetError()); - return MwFALSE; - } - - /* Get configs */ - if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || - (numConfigs == 0)) { - printf("ERROR: eglGetConfigs, %0X\n", eglGetError()); - return MwFALSE; - } - - /* Choose config */ - if((eglChooseConfig(display, fbAttribs, &o->egl_config, 1, &numConfigs) != - EGL_TRUE) || - (numConfigs != 1)) { - printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); - return MwFALSE; - } - - o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create( - handle->lowlevel->wayland.framebuffer.surface, - handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); - if(!o->egl_window_native) { - printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); - return MwFALSE; - } - - /* Create a surface */ - surface = eglCreateWindowSurface(display, o->egl_config, - o->egl_window_native, NULL); - if(surface == EGL_NO_SURFACE) { - printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); - return MwFALSE; + return 1; } eglBindAPI(EGL_OPENGL_API); + /* Get configs */ + if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE)) { + printf("ERROR: eglGetConfigs, %0X\n", eglGetError()); + return 1; + } + + /* Choose config */ + if((eglChooseConfig(display, fbAttribs, egl_configs, numConfigs, &numConfigsMatched) != + EGL_TRUE)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return 1; + } + + for(int i = 0; i < numConfigsMatched; i++) { + if(o->eglGetConfigAttrib(display, egl_configs[i], + EGL_NATIVE_VISUAL_ID, + &gbm_format) == EGL_FALSE) { + printf("ERROR: eglGetConfigAttrib, %0X\n", eglGetError()); + } else { + if(gbm_format == GBM_FORMAT_ARGB8888) { + o->egl_config = egl_configs[i]; + break; + } + } + } + /* Create a GL context */ context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, contextAttribs); if(context == EGL_NO_CONTEXT) { printf("ERROR: eglCreateContext, %0X\n", eglGetError()); - return MwFALSE; + return 1; + } + + o->gbm_surface = o->gbm_surface_create(o->gbm, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING); + + /* Create a surface */ + surface = eglCreatePlatformWindowSurface(display, o->egl_config, + o->gbm_surface, NULL); + if(surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreatePlatformWindowSurface, %0X\n", eglGetError()); + return 1; } if(!eglMakeCurrent(display, surface, surface, context)) { printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); } - eglSwapInterval(o->egl_display, 0); + + o->frontbuffer_data = malloc(handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + memset(o->frontbuffer_data, 255, handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + + o->frontbuffer = MwLoadRaw(handle, o->frontbuffer_data, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + + MwVaApply(handle, MwNpixmap, o->frontbuffer, NULL); o->egl_display = display; o->egl_surface = surface; @@ -431,6 +488,8 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { o->egl_context)) { printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); } + + MwLLForceRender(handle->lowlevel); } #endif } @@ -454,13 +513,48 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { waylandopengl_t* o = handle->internal; + struct gbm_bo* bo; eglSwapInterval(o->egl_display, 0); if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); - }; - wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, - handle->lowlevel->wayland.ww, - handle->lowlevel->wayland.wh, 0, 0); + } + bo = o->gbm_surface_lock_front_buffer(o->gbm_surface); + if(bo) { + void* gbmBoMapData = NULL; // Needed for unmapping if gbm_bo_map is used + MwU32 width = o->gbm_bo_get_width(bo); + MwU32 height = o->gbm_bo_get_height(bo); + MwU32 stride = o->gbm_bo_get_stride(bo); + void* map = o->gbm_bo_map(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ, &stride, &gbmBoMapData); + MwU32 size = height * stride; + + if(map) { + for(int y = 0; y < height; y++) { + const MwU8* row = map + y * stride; + for(int x = 0; x < width; x++) { + /* Memory layout per pixel: [B][G][R][A] */ + MwU8 b = row[x * 4 + 0]; + MwU8 g = row[x * 4 + 1]; + MwU8 r = row[x * 4 + 2]; + + int out = (y * width + x) * 4; + o->frontbuffer_data[out + 0] = r; + o->frontbuffer_data[out + 1] = g; + o->frontbuffer_data[out + 2] = b; + o->frontbuffer_data[out + 3] = 255; + } + } + + MwPixmapReloadRaw( + o->frontbuffer, o->frontbuffer_data); + } + o->gbm_bo_unmap(bo, gbmBoMapData); + } + if(o->previous_bo) { + o->gbm_surface_release_buffer(o->gbm_surface, o->previous_bo); + } + o->previous_bo = bo; + + MwForceRender(handle); } #endif } @@ -503,9 +597,65 @@ static void func_handler(MwWidget handle, const char* name, void* out, } } -MwClassRec MwOpenGLClassRec = {wcreate, /* create */ - destroy, /* destroy */ - NULL, /* draw */ +#ifdef USE_WAYLAND +static void frontbuffer_draw(MwWidget handle) { + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + MwRect r; + r.x = 0; + r.y = 0; + r.width = handle->lowlevel->wayland.ww; + r.height = handle->lowlevel->wayland.wh; + MwLLDrawPixmap(handle->lowlevel, &r, o->frontbuffer); + } +} +static void frontbuffer_resize(MwWidget handle) { + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + if(o->frontbuffer_data) { + free(o->frontbuffer_data); + } + if(o->frontbuffer) { + MwLLDestroyPixmap(o->frontbuffer); + } + if(o->gbm_surface) { + o->gbm_surface_destroy(o->gbm_surface); + } + if(o->egl_surface) { + eglDestroySurface(o->egl_display, o->egl_surface); + } + + o->gbm_surface = o->gbm_surface_create(o->gbm, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING); + + /* Create a surface */ + o->egl_surface = eglCreatePlatformWindowSurface(o->egl_display, o->egl_config, + o->gbm_surface, NULL); + if(o->egl_surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreatePlatformWindowSurface, %0X\n", eglGetError()); + } else { + } + + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } + + o->frontbuffer_data = malloc(handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + memset(o->frontbuffer_data, 255, handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + + o->frontbuffer = MwLoadRaw(handle, o->frontbuffer_data, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + + MwVaApply(handle, MwNpixmap, o->frontbuffer, NULL); + } +} +#endif + +MwClassRec MwOpenGLClassRec = {wcreate, /* create */ + destroy, /* destroy */ +#ifdef USE_WAYLAND + frontbuffer_draw, /* draw */ +#else + NULL, /* draw */ +#endif NULL, /* click */ NULL, /* parent_resize */ NULL, /* prop_change */ @@ -515,12 +665,17 @@ MwClassRec MwOpenGLClassRec = {wcreate, /* create */ NULL, /* key */ func_handler, /* execute */ NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, NULL, NULL, NULL}; -MwClass MwOpenGLClass = &MwOpenGLClassRec; +#ifdef USE_WAYLAND + frontbuffer_resize, /* resize */ +#else + NULL, /* resize */ +#endif + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; #else MWDECL MwClass MwOpenGLClass; diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index dedd7a91..8adf0284 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -23,10 +23,10 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawFrame(handle, &r, base, 1); - MwDrawRect(handle, &r, base); w = MwGetInteger(handle, MwNvalue) - MwGetInteger(handle, MwNminValue); w = w / (MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue)); + + MwDrawWidgetBack(handle, &r, base, 1, MwDEFAULT); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); r.x += MwDefaultBorderWidth(handle); @@ -34,7 +34,7 @@ static void draw(MwWidget handle) { r.width -= MwDefaultBorderWidth(handle) * 2; r.height -= MwDefaultBorderWidth(handle) * 2; - r.width = r.width * w; + r.width = (int)(r.width * w); MwDrawRect(handle, &r, fill); MwLLFreeColor(fill); @@ -62,7 +62,7 @@ MwClassRec MwProgressBarClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index 1342232e..c93e054b 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -19,9 +19,17 @@ static void draw(MwWidget handle) { r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawRect(handle, &r, base); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + if(r.width < r.height) { + r.height = r.width; + } else { + r.width = r.height; + } + r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; + r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; + MwDrawDiamond(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0); MwLLFreeColor(base); @@ -63,7 +71,7 @@ MwClassRec MwRadioBoxClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 58ed578b..3bd2fdf3 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -28,7 +28,7 @@ static int calc_length(MwWidget handle) { int area = MwGetInteger(handle, MwNareaShown); if(area > len) area = len; - return max * (double)area / len; + return (int)(max * (double)area / len); } static int calc_position(MwWidget handle) { @@ -36,7 +36,7 @@ static int calc_position(MwWidget handle) { int len = MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue); int val = MwGetInteger(handle, MwNvalue); - return (max - calc_length(handle)) * (double)val / len; + return (int)((max - calc_length(handle)) * (double)val / len); } static void add_value(MwWidget handle, int mul) { @@ -54,7 +54,7 @@ static void add_value(MwWidget handle, int mul) { } static void draw(MwWidget handle) { - MwRect r, rt, rbar; + MwRect r = {0}, rt = {0}, rbar = {0}; MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); MwScrollBar scr = handle->internal; @@ -73,7 +73,7 @@ static void draw(MwWidget handle) { ux = r.height; dx = r.width - r.height; - MwDrawWidgetBack(handle, &r, dark, 1, MwTRUE); + MwDrawWidgetBack(handle, &r, dark, 1, MwDEFAULT); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); rt = r; @@ -131,7 +131,7 @@ static void draw(MwWidget handle) { } } - if(rbar.height >= 0) MwDrawWidgetBack(handle, &rbar, base, 0, MwTRUE); + if(rbar.height >= 0) MwDrawWidgetBack(handle, &rbar, base, 0, MwDEFAULT); MwLLFreeColor(dark); MwLLFreeColor(base); @@ -273,7 +273,7 @@ MwClassRec MwScrollBarClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/separator.c b/src/widget/separator.c index 15919d0e..4e70ccc7 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -51,7 +51,7 @@ MwClassRec MwSeparatorClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/submenu.c b/src/widget/submenu.c index c937a9ca..6bc5d550 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -8,6 +8,8 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNleftPadding, 0); + handle->internal = NULL; + return 0; } @@ -37,7 +39,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); if(menu != NULL) { MwPoint p; @@ -71,7 +73,7 @@ static void draw(MwWidget handle) { r.y = p.y - 3; r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle, MwNleftPadding); r.height = th + 3 * 2; - MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); } p.x = 5 + tw / 2 + MwGetInteger(handle, MwNleftPadding); @@ -99,8 +101,7 @@ static void draw(MwWidget handle) { } static void click(MwWidget handle) { - MwWidget w = handle; - jmp_buf jmp; + MwWidget w = handle; MwMenu menu = handle->internal; if(arrlen(menu->sub) > 0) { @@ -150,7 +151,6 @@ static void click(MwWidget handle) { MwForceRender(handle); } else if(strcmp(menu->sub[i]->name, "----") != 0 && arrlen(menu->sub[i]->sub) == 0) { while(w->parent->widget_class == MwSubMenuClass) w = w->parent; - MwGetBeforeStep(w, &jmp); MwDestroyWidget(w); ((MwMenu)w->internal)->wsub = NULL; @@ -257,7 +257,7 @@ MwClassRec MwSubMenuClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/subwindow.c b/src/widget/subwindow.c new file mode 100644 index 00000000..81b53921 --- /dev/null +++ b/src/widget/subwindow.c @@ -0,0 +1,425 @@ +#include + +#include "../../external/stb_ds.h" + +#define TitleHeight 20 +#define ButtonSize 14 + +static void resize(MwWidget handle); + +static void close_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = w - bw * 2 - 1; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x++; + p[1].x--; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = w - bw * 2 - 1; + p[0].y = bw * 2; + p[1].x = bw * 2; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x--; + p[1].x++; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static void MWAPI close_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + + (void)handle; + (void)client; + + MwDispatchUserHandler(w, MwNcloseHandler, NULL); + + MwLLRaise(w->lowlevel); +} + +static void maximize_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = w - bw * 2 - 1; + p[1].y = bw * 2; + MwLLLine(handle->lowlevel, p, c); + + p[0].y = p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].y = p[1].y = bw * 2 + 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = bw * 2; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = p[1].x = w - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static void MWAPI maximize_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + MwSubWindow sw = w->internal; + + (void)handle; + (void)client; + + if(sw->minimized) return; + + if(sw->maximized) { + MwVaApply(user, + MwNx, sw->x, + MwNy, sw->y, + MwNwidth, sw->width, + MwNheight, sw->height, + NULL); + } else { + sw->x = MwGetInteger(w, MwNx); + sw->y = MwGetInteger(w, MwNy); + sw->width = MwGetInteger(w, MwNwidth); + sw->height = MwGetInteger(w, MwNheight); + + MwVaApply(user, + MwNx, 0, + MwNy, 0, + MwNwidth, MwGetInteger(w->parent, MwNwidth), + MwNheight, MwGetInteger(w->parent, MwNheight), + NULL); + } + sw->maximized = !sw->maximized; + + MwLLRaise(w->lowlevel); +} + +static void minimize_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = h - bw * 2 - 1; + p[1].x = w - bw * 2 - 1; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].y--; + p[1].y--; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static int sort_subwindow(const void* _a, const void* _b) { + MwWidget a = *(MwWidget*)_a; + MwWidget b = *(MwWidget*)_b; + int ax = MwGetInteger(a, MwNx); + int bx = MwGetInteger(b, MwNx); + + if(ax < bx) return -1; + if(ax > bx) return 1; + return 0; +} + +static void MWAPI minimize_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + MwSubWindow sw = w->internal; + + (void)handle; + (void)client; + + if(sw->maximized) return; + + if(sw->minimized) { + int i; + MwWidget* ws = NULL; + int p = 0; + + for(i = 0; i < arrlen(w->parent->children); i++) { + MwWidget c = w->parent->children[i]; + if(c->widget_class == MwSubWindowClass) { + MwSubWindow csw = c->internal; + + if(!csw->minimized) continue; + + arrput(ws, c); + } + } + + if(ws != NULL) { + qsort(ws, arrlen(ws), sizeof(*ws), sort_subwindow); + + for(i = 0; i < arrlen(ws); i++) { + if(p) { + MwVaApply(ws[i], + MwNx, MwGetInteger(ws[i], MwNx) - MwGetInteger(w, MwNwidth), + NULL); + } else if(ws[i] == w) { + p = 1; + } + } + } + arrfree(ws); + + MwVaApply(user, + MwNx, sw->x, + MwNy, sw->y, + NULL); + } else { + int x = 0; + int i; + + for(i = 0; i < arrlen(w->parent->children); i++) { + MwWidget c = w->parent->children[i]; + + if(c->widget_class == MwSubWindowClass) { + MwSubWindow cw = c->internal; + + if(cw->minimized) x += MwGetInteger(c, MwNwidth); + } + } + + sw->x = MwGetInteger(w, MwNx); + sw->y = MwGetInteger(w, MwNy); + + MwVaApply(user, + MwNx, x, + MwNy, MwGetInteger(w->parent, MwNheight) - TitleHeight - MwDefaultBorderWidth(handle), + NULL); + } + sw->minimized = !sw->minimized; + + MwLLRaise(w->lowlevel); +} + +static void resize(MwWidget handle) { + MwSubWindow sw = handle->internal; + int x, y, w, h; + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int bw = MwDefaultBorderWidth(handle); + int p; + + x = bw * 2; + y = bw * 2 + TitleHeight; + w = ww - bw * 4; + h = wh - bw * 4 - TitleHeight; + if(sw->frame == NULL) { + sw->frame = MwCreateWidget(MwFrameClass, "frame", handle, x, y, w, h); + } else { + MwVaApply(sw->frame, + MwNx, x, + MwNy, y, + MwNwidth, w, + MwNheight, h, + NULL); + } + + p = (TitleHeight - ButtonSize) / 2; + x = ww - bw - p; + y = bw + p; + w = ButtonSize; + h = ButtonSize; + +#define BUTTON(name) \ + x -= ButtonSize; \ + if(sw->name == NULL) { \ + sw->name = MwCreateWidget(MwButtonClass, #name, handle, x, y, w, h); \ + sw->name->draw_inject = name##_draw; \ + MwAddUserHandler(sw->name, MwNactivateHandler, name##_activate, handle); \ + } else { \ + MwVaApply(sw->name, \ + MwNx, x, \ + MwNy, y, \ + MwNwidth, w, \ + MwNheight, h, \ + NULL); \ + } \ + x -= p; + + BUTTON(close); + BUTTON(maximize); + BUTTON(minimize); +} + +static int wcreate(MwWidget handle) { + MwSubWindow sw = malloc(sizeof(*sw)); + memset(sw, 0, sizeof(*sw)); + + sw->maximized = 0; + sw->minimized = 0; + handle->internal = sw; + + resize(handle); + + MwSetDefault(handle); + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor tb = MwParseColor(handle, MwGetText(handle, MwNtitleBackground)); + MwLLColor tf = MwParseColor(handle, MwGetText(handle, MwNtitleForeground)); + MwRect r, r2, r3; + const char* title = MwGetText(handle, MwNtitle); + int incr = 0; + MwLLPixmap px = MwGetVoid(handle, MwNiconPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawFrame(handle, &r, c, 0); + MwDrawRect(handle, &r, c); + + r2 = r; + r2.height = TitleHeight; + MwDrawRect(handle, &r2, tb); + + if(px != NULL) { + r3 = r2; + incr = (TitleHeight - ButtonSize) / 2; + + r3.x += incr; + r3.y += incr; + r3.width = ButtonSize; + r3.height = ButtonSize; + MwLLDrawPixmap(handle->lowlevel, &r3, px); + + incr += ButtonSize; + } + + if(title != NULL) { + MwPoint p; + p.x = r2.x + (TitleHeight - ButtonSize) / 2 + incr; + p.y = r2.y + TitleHeight / 2; + handle->bgcolor = tb; + MwDrawText(handle, NULL, &p, title, MwALIGNMENT_BEGINNING, tf); + handle->bgcolor = NULL; + } + + r2.width = ButtonSize * 3 + (TitleHeight - ButtonSize) / 2 * 4; + r2.x = r.width - r2.width; + MwDrawRect(handle, &r2, tb); + + r.y += TitleHeight; + r.height -= TitleHeight; + MwDrawFrame(handle, &r, c, 1); + + MwLLFreeColor(tf); + MwLLFreeColor(tb); + MwLLFreeColor(c); +} + +static void parent_resize(MwWidget handle) { + MwSubWindow sw = handle->internal; + + if(sw->maximized) { + MwVaApply(handle, + MwNwidth, MwGetInteger(handle->parent, MwNwidth), + MwNheight, MwGetInteger(handle->parent, MwNheight), + NULL); + } else if(sw->minimized) { + MwVaApply(handle, + MwNy, MwGetInteger(handle->parent, MwNheight) - TitleHeight - MwDefaultBorderWidth(handle), + NULL); + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNtitle) == 0 || strcmp(key, MwNiconPixmap) == 0) MwForceRender(handle); +} + +static MwWidget mwSubWindowGetFrameImpl(MwWidget handle) { + MwSubWindow sw = handle->internal; + + return sw->frame; +} + +static void mouse_down(MwWidget handle, void* ptr) { + MwSubWindow sw = handle->internal; + MwMouse* m = ptr; + + if(m->button == MwMOUSE_LEFT && !sw->minimized && !sw->maximized) { + MwGetCursorCoord(handle, &sw->cursor_start); + sw->base.x = MwGetInteger(handle, MwNx); + sw->base.y = MwGetInteger(handle, MwNy); + } + + MwLLRaise(handle->lowlevel); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)va; + + if(strcmp(name, "mwSubWindowGetFrame") == 0) { + *(MwWidget*)out = mwSubWindowGetFrameImpl(handle); + } +} + +static void tick(MwWidget handle) { + MwSubWindow sw = handle->internal; + + if(handle->pressed && !sw->minimized && !sw->maximized) { + MwPoint p; + + MwGetCursorCoord(handle, &p); + + MwVaApply(handle, + MwNx, sw->base.x + p.x - sw->cursor_start.x, + MwNy, sw->base.y + p.y - sw->cursor_start.y, + NULL); + } +} + +MwClassRec MwSubWindowClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + parent_resize, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + mouse_down, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + tick, /* tick */ + resize, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwSubWindowClass = &MwSubWindowClassRec; diff --git a/src/widget/tab.c b/src/widget/tab.c new file mode 100644 index 00000000..e5d2a3ea --- /dev/null +++ b/src/widget/tab.c @@ -0,0 +1,375 @@ +#include + +#include "../../external/stb_ds.h" + +static void resize(MwWidget handle); + +static int wcreate(MwWidget handle) { + MwTab t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + + handle->internal = t; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNvalue, -1); + + return 0; +} + +static void destroy(MwWidget handle) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + free(t->names[i]); + } + + arrfree(t->names); + arrfree(t->frames); + + free(handle->internal); +} + +static int tab_width(MwWidget handle, const char* text) { + return MwTextWidth(handle, NULL, text) + 20; +} + +static int tab_height(MwWidget handle) { + return MwTextHeight(handle, NULL, "M") + 10; +} + +static int icon_width(MwWidget handle, const char* text) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], text) == 0) { + MwLLPixmap px = MwGetVoid(t->frames[i], MwNiconPixmap); + + if(px == NULL) return 0; + + return px->common.width * tab_height(handle) / px->common.height; + } + } + + return 0; +} + +static void draw(MwWidget handle) { + MwTab t = handle->internal; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor ct = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r, r2; + int h = tab_height(handle); + int i; + int n; + int x = 0; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, c); + + for(n = 0; n < 2; n++) { + x = 0; + for(i = 0; i < arrlen(t->names); i++) { + int render = 0; + int iw = icon_width(handle, t->names[i]); + + if(i == MwGetInteger(handle, MwNvalue) && n == 1) { + r.y += h; + r.height -= h; + MwDrawFrame(handle, &r, c, 0); + + render = 1; + } else if(n == 0) { + render = 1; + } + + r2.x = x; + r2.y = 0; + r2.width = tab_width(handle, t->names[i]) + iw; + r2.height = tab_height(handle) + MwDefaultBorderWidth(handle); + + x += r2.width; + + if(iw > 0) { + MwLLPixmap px = MwGetVoid(t->frames[i], MwNiconPixmap); + MwRect rp; + + rp = r2; + + rp.x += 5; + rp.y += 5; + + rp.width = iw - 10; + rp.height = rp.height * (iw - 10) / iw; + + MwLLDrawPixmap(handle->lowlevel, &rp, px); + } + + if(render) { + MwPoint p; + + if(n == 1 && i > 0) { + MwRect r3 = r2; + + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.x -= r3.width; + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } else if(n == 1 && i == 0) { + MwRect r3 = r2; + + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.x -= r3.width; + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 3; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1 && i < (arrlen(t->names) - 1)) { + MwRect r3 = r2; + + r3.x += r2.width - MwDefaultBorderWidth(handle); + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1) { + MwRect r3 = r2; + + r3.height -= MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + } + + MwDrawFrame(handle, &r2, c, 0); + + MwLLClip(handle->lowlevel, NULL); + + if(n == 1) { + MwRect r3 = r2; + + r3.y += r3.height; + r3.height = MwDefaultBorderWidth(handle); + + MwDrawRect(handle, &r3, c); + } + + p.x = r2.x + (r2.width + iw / 2) / 2; + p.y = r2.y + r2.height / 2; + MwDrawText(handle, NULL, &p, t->names[i], MwALIGNMENT_CENTER, ct); + } + } + } + + MwLLFreeColor(ct); + MwLLFreeColor(c); +} + +static void show_frame(MwWidget handle) { + resize(handle); + + MwForceRender(handle); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void click(MwWidget handle) { + MwTab t = handle->internal; + int i; + int x = 0; + int h = tab_height(handle); + + for(i = 0; i < arrlen(t->names); i++) { + int w = tab_width(handle, t->names[i]); + int iw = icon_width(handle, t->names[i]); + + w += iw; + + if(MwGetInteger(handle, MwNvalue) != i && x <= handle->mouse_point.x && handle->mouse_point.x <= (x + w) && 0 <= handle->mouse_point.y && handle->mouse_point.y <= h) { + MwSetInteger(handle, MwNvalue, i); + show_frame(handle); + } + + x += w; + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNvalue) == 0) { + show_frame(handle); + } +} + +static MwWidget mwTabAddImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + MwWidget f = MwCreateWidget(MwFrameClass, "tabframe", handle, MwDefaultBorderWidth(handle), tab_height(handle) + MwDefaultBorderWidth(handle), MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) * 2, MwGetInteger(handle, MwNheight) - tab_height(handle) - MwDefaultBorderWidth(handle) * 2); + char* n = MwStringDuplicate(name); + + arrput(t->frames, f); + arrput(t->names, n); + + MwForceRender(handle); + + if(MwGetInteger(handle, MwNvalue) == -1) { + MwSetInteger(handle, MwNvalue, arrlen(t->frames) - 1); + show_frame(handle); + } else { + MwLLShow(f->lowlevel, 0); + } + + return f; +} + +static MwWidget mwTabGetFrameImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], name) == 0) return t->frames[i]; + } + + return NULL; +} + +static void mwTabFocusImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], name) == 0) { + MwSetInteger(handle, MwNvalue, i); + show_frame(handle); + break; + } + } +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwTabAdd") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabAddImpl(handle, name); + } else if(strcmp(name, "mwTabGetFrame") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabGetFrameImpl(handle, name); + } else if(strcmp(name, "mwTabFocus") == 0) { + const char* name = va_arg(va, const char*); + + mwTabFocusImpl(handle, name); + } +} + +static void resize(MwWidget handle) { + MwTab t = handle->internal; + int v = MwGetInteger(handle, MwNvalue); + int i; + + for(i = 0; i < arrlen(t->frames); i++) { + int y = MwGetInteger(handle, MwNheight); + + MwLLShow(t->frames[i]->lowlevel, i == v); + if(i == v) y = tab_height(handle) + MwDefaultBorderWidth(handle); + + MwVaApply(t->frames[i], + MwNx, MwDefaultBorderWidth(handle), + MwNy, y, + MwNwidth, MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) * 2, + MwNheight, MwGetInteger(handle, MwNheight) - tab_height(handle) - MwDefaultBorderWidth(handle) * 2, + NULL); + } +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwTab t = handle->internal; + int v = MwGetInteger(handle, MwNvalue); + int n; + int i; + + if(new_child) return; + + for(i = 0; i < arrlen(t->frames); i++) { + if(t->frames[i] == child) { + n = i; + break; + } + } + + free(t->names[n]); + + arrdel(t->frames, n); + arrdel(t->names, n); + + if(n <= v) { + if(v > 0) v--; + + MwSetInteger(handle, MwNvalue, v); + show_frame(handle); + } else { + MwSetInteger(handle, MwNvalue, v); + show_frame(handle); + } + + MwForceRender(handle); +} + +static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { + (void)child; + + if(strcmp(key, MwNiconPixmap) == 0) { + MwForceRender(handle); + } +} + +MwClassRec MwTabClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + resize, /* resize */ + children_update, /* children_update */ + children_prop_change, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTabClass = &MwTabClassRec; diff --git a/src/widget/table.c b/src/widget/table.c new file mode 100644 index 00000000..788d5cc8 --- /dev/null +++ b/src/widget/table.c @@ -0,0 +1,227 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwTable t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + + handle->internal = t; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNcolumns, 1); + MwSetInteger(handle, MwNmargin, 0); + MwSetInteger(handle, MwNpadding, 0); + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNwaitLayout, 0); + + t->layout = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + MwTable t = handle->internal; + + arrfree(t->widgets); + + free(t); +} + +typedef struct intkv { + int key; + int value; +} intkv_t; + +static void put_intkv(intkv_t** kv, int x, int y, int c, int r) { + int k = (x << 16) | y; + int v = (c << 16) | r; + + hmput(*kv, k, v); +} + +static int get_intkv(intkv_t* kv, int x, int y) { + int k = (x << 16) | y; + + return hmget(kv, k); +} + +#define LAYOUT_BEGIN \ + hmfree(kv); \ + hmdefault(kv, 0); \ + n = 0; \ + x = bw; \ + y = bw; \ + for(i = 0; i < arrlen(handle->children); i++) { \ + MwRect rc; \ + MwWidget hc = handle->children[i]; \ + int cs = MwGetInteger(hc, MwNcolumnSpan); \ + int rs = MwGetInteger(hc, MwNrowSpan); \ + int w, h; \ + int cy; \ + int s = MwGetInteger(handle, MwNmargin); \ + int v = n; \ +\ + if(cs == MwDEFAULT) cs = 1; \ + if(rs == MwDEFAULT) rs = 1; \ +\ + w = cs * cw + (cs - 1) * s; \ + h = rs * ch + (rs - 1) * s; \ +\ + MwGetFrame(hc, &rc); \ +\ + if(hc == child || rc.x != x || rc.y != y || rc.width != w || rc.height != h) { + +#define LAYOUT_END(label) \ + } \ +\ + put_intkv(&kv, n % c, n / c, cs, rs); \ +\ + n += cs; \ + repeat_##label :; \ + if((n % c) == 0) { \ + x = bw; \ + y += ch + s; \ + } else { \ + for(; v < n; v++) { \ + x += cw + s; \ + } \ + } \ +\ + for(cy = (n / c); cy >= 0; cy--) { \ + int v = get_intkv(kv, n % c, cy) & 0xffff; \ +\ + if(cy <= (n / c) && (n / c) <= (cy + v - 1)) { \ + v = n; \ + n += get_intkv(kv, n % c, cy) >> 16; \ + goto repeat_##label; \ + } \ + } \ + } + +static void layout_widget(MwWidget handle, MwWidget child) { + int i; + int c = MwGetInteger(handle, MwNcolumns); + int bw = (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0) + MwGetInteger(handle, MwNpadding); + int m = MwGetInteger(handle, MwNmargin); + int n, x, y, cw = 0, ch = 0; + int gcs; + intkv_t* kv = NULL; + + LAYOUT_BEGIN; + LAYOUT_END(1); + + gcs = (n + c - 1) / c; + cw = (MwGetInteger(handle, MwNwidth) - bw * 2 - (m * (c - 1))) / c; + ch = (MwGetInteger(handle, MwNheight) - m * (gcs - 1) - bw * 2) / gcs; + + LAYOUT_BEGIN; + MwVaApply(hc, + MwNx, x, + MwNy, y, + MwNwidth, w, + MwNheight, h, + NULL); + LAYOUT_END(2); + + hmfree(kv); +} + +static void layout(MwWidget handle) { + MwTable t = handle->internal; + int i; + + if(arrlen(t->widgets) > 0) { + for(i = 0; i < arrlen(t->widgets); i++) layout_widget(handle, t->widgets[i]); + } else { + for(i = 0; i < arrlen(handle->children[i]); i++) layout_widget(handle, handle->children[i]); + } +} + +static void draw(MwWidget handle) { + MwBoxClass->draw(handle); +} + +static void tick(MwWidget handle) { + MwTable t = handle->internal; + + if(t->layout && !MwGetInteger(handle, MwNwaitLayout)) { + layout(handle); + + t->layout = 0; + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNcolumns) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNmargin) == 0) { + MwTable t = handle->internal; + t->layout = 1; + + MwForceRender(handle); + } +} + +static void resize(MwWidget handle) { + MwTable t = handle->internal; + t->layout = 1; + + MwForceRender(handle); +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwTable t = handle->internal; + t->layout = 1; + + if(new_child) { + arrput(t->widgets, child); + } else { + int i; + + for(i = 0; i < arrlen(t->widgets); i++) { + if(t->widgets[i] == child) { + arrdel(t->widgets, i); + i = -1; + } + } + } + + MwForceRender(handle); +} + +static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { + (void)child; + + if(strcmp(key, MwNcolumnSpan) == 0 || strcmp(key, MwNrowSpan) == 0) { + MwTable t = handle->internal; + t->layout = 1; + + arrput(t->widgets, child); + + MwForceRender(handle); + } +} + +MwClassRec MwTableClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + tick, /* tick */ + resize, /* resize */ + children_update, /* children_update */ + children_prop_change, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTableClass = &MwTableClassRec; diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 99f12e27..3fba309e 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -2,11 +2,13 @@ #include "../../external/stb_ds.h" -#define OpenerSize 10 +#define OpenerSize 11 #define LineSpace 16 #define LinePadding 4 -static void vscroll_changed(MwWidget handle, void* user, void* call) { +#define Font MwFLBuildFont(MwFLFlagMonospace) + +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { MwTreeView tv = handle->parent->internal; (void)user; @@ -30,11 +32,11 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** if((*skip) > 0) { (*skip)--; skipped = 1; - if(p->y == MwDefaultBorderWidth(handle)) p->y -= MwTextHeight(handle, NULL, "M"); - } else if((*shared) < (MwGetInteger(handle, MwNheight) / MwTextHeight(handle, NULL, "M") + 2)) { + if(p->y == MwDefaultBorderWidth(handle)) p->y -= MwTextHeight(handle, Font, "M"); + } else if((*shared) < (MwGetInteger(handle, MwNheight) / MwTextHeight(handle, Font, "M") + 2)) { MwRect r; p->x += shift; - p->y += MwTextHeight(handle, NULL, "M") / 2 + LinePadding; + p->y += MwTextHeight(handle, Font, "M") / 2 + LinePadding; if(tree->tree != NULL || shift > LineSpace) { l[0] = *p; @@ -47,9 +49,9 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** l[0] = *p; l[0].x -= LineSpace / 2; l[1] = l[0]; - l[0].y -= MwTextHeight(handle, NULL, "M") / 2 + LinePadding; + l[0].y -= MwTextHeight(handle, Font, "M") / 2 + LinePadding; if(next) { - l[1].y += MwTextHeight(handle, NULL, "M") / 2; + l[1].y += MwTextHeight(handle, Font, "M") / 2; } if(draw) MwLLLine(handle->lowlevel, &l[0], text2); } @@ -57,7 +59,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** r.width = OpenerSize; r.height = OpenerSize; r.x = p->x - LineSpace + (LineSpace - r.width) / 2; - r.y = p->y - MwTextHeight(handle, NULL, "M") / 2 + (MwTextHeight(handle, NULL, "M") - r.height) / 2; + r.y = p->y - MwTextHeight(handle, Font, "M") / 2 + (MwTextHeight(handle, Font, "M") - r.height) / 2; if(draw) { MwLLColor col = tree->opened ? MwLightenColor(handle, base, -8, -8, -8) : base; MwRect r2 = r; @@ -66,7 +68,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** MwDrawRect(handle, &r, col); MwDrawFrame(handle, &r, base, tree->opened); if(tree->opened) { - l[0].x = r.x + (r.width - len) / 2; + l[0].x = r.x + (r.width - 1 - len) / 2; l[0].y = r.y + r.height / 2; l[1].x = l[0].x + len; @@ -101,11 +103,11 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** } } if(tree->pixmap != NULL) { - r.height = MwTextHeight(handle, NULL, "M"); + r.height = MwTextHeight(handle, Font, "M"); r.width = r.height * tree->pixmap->common.width / tree->pixmap->common.height; - r.x = p->x; - r.y = p->y - MwTextHeight(handle, NULL, "M") / 2; + r.x = p->x + (MwGetInteger(handle->parent, MwNleftPadding) - r.width) / 2; + r.y = p->y - MwTextHeight(handle, Font, "M") / 2; if(draw) MwLLDrawPixmap(handle->lowlevel, &r, tree->pixmap); } @@ -113,16 +115,16 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** if(draw) { if(tree->selected) { r.x = p->x; - r.y = p->y - MwTextHeight(handle, NULL, "M") / 2; - r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle, MwNleftPadding) - shift; - r.height = MwTextHeight(handle, NULL, "M"); + r.y = p->y - MwTextHeight(handle, Font, "M") / 2; + r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle->parent, MwNleftPadding) - shift; + r.height = MwTextHeight(handle, Font, "M"); MwDrawRect(handle, &r, text2); } handle->bgcolor = tree->selected ? text2 : base2; - MwDrawText(handle, NULL, p, tree->label, MwALIGNMENT_BEGINNING, tree->selected ? base2 : text2); + MwDrawText(handle, Font, p, tree->label, MwALIGNMENT_BEGINNING, tree->selected ? base2 : text2); handle->bgcolor = NULL; } else { - if(p->x <= mouse->x && mouse->x <= (p->x + MwTextWidth(handle, NULL, tree->label)) && (p->y - MwTextHeight(handle, NULL, "M") / 2) <= mouse->y && mouse->y <= (p->y + MwTextHeight(handle, NULL, "M") / 2)) { + if(p->x <= mouse->x && mouse->x <= (p->x + MwTextWidth(handle, Font, tree->label)) && (p->y - MwTextHeight(handle, Font, "M") / 2) <= mouse->y && mouse->y <= (p->y + MwTextHeight(handle, Font, "M") / 2)) { unsigned long t; set_all(root, 0); @@ -136,7 +138,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** } p->x -= MwGetInteger(handle->parent, MwNleftPadding); - p->y += MwTextHeight(handle, NULL, "M") / 2; + p->y += MwTextHeight(handle, Font, "M") / 2; p->x -= shift; (*shared)++; @@ -145,7 +147,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** for(i = 0; i < arrlen(tree->tree); i++) { l[0] = *p; l[0].x += shift + LineSpace / 2; - l[0].y += MwTextHeight(handle, NULL, "M") - (MwTextHeight(handle, NULL, "M") - OpenerSize) / 2; + l[0].y += MwTextHeight(handle, Font, "M") - (MwTextHeight(handle, Font, "M") - OpenerSize) / 2; if(tree->tree[i]->tree != NULL) { l[0].y += OpenerSize / 2; } @@ -189,7 +191,7 @@ static void frame_draw(MwWidget handle) { r = r2; for(i = 0; i < arrlen(tv->tree); i++) { - if(shared > (r.height / MwTextHeight(handle, NULL, "M"))) break; + if(shared > (r.height / MwTextHeight(handle, Font, "M"))) break; recursion(handle, tv->tree[i], tv->tree, base, text, base2, text2, &p, 0, LineSpace, &skip, &shared, 1, NULL); } @@ -211,7 +213,7 @@ static int recursive_length(MwTreeViewEntry** e) { return l; } -static void frame_mouse_down(MwWidget handle, void* user, void* call) { +static void MWAPI frame_mouse_down(MwWidget handle, void* user, void* call) { MwTreeView tv = handle->parent->internal; MwMouse* mouse = call; @@ -220,9 +222,9 @@ static void frame_mouse_down(MwWidget handle, void* user, void* call) { if(mouse->button == MwMOUSE_LEFT) tv->pressed = mouse->point; } -static void resize(MwWidget handle); +static void resize(MwWidget handle, int no_resize); -static void frame_mouse_up(MwWidget handle, void* user, void* call) { +static void MWAPI frame_mouse_up(MwWidget handle, void* user, void* call) { MwTreeView tv = handle->parent->internal; int shared = 0; int skip = MwGetInteger(tv->vscroll, MwNvalue) * (MwGetInteger(tv->vscroll, MwNmaxValue) - MwGetInteger(tv->vscroll, MwNareaShown)) / MwGetInteger(tv->vscroll, MwNmaxValue); @@ -236,15 +238,15 @@ static void frame_mouse_up(MwWidget handle, void* user, void* call) { p.x = MwDefaultBorderWidth(tv->frame); p.y = MwDefaultBorderWidth(tv->frame); for(i = 0; i < arrlen(tv->tree); i++) { - if(shared > (MwGetInteger(tv->frame, MwNheight) / MwTextHeight(tv->frame, NULL, "M"))) break; + if(shared > (MwGetInteger(tv->frame, MwNheight) / MwTextHeight(tv->frame, Font, "M"))) break; recursion(tv->frame, tv->tree[i], tv->tree, NULL, NULL, NULL, NULL, &p, 0, LineSpace, &skip, &shared, 0, &tv->pressed); } - resize(handle->parent); + resize(handle->parent, 1); MwForceRender(tv->frame); } } -static void resize(MwWidget handle) { +static void resize(MwWidget handle, int no_resize) { MwTreeView tv = handle->internal; int w = MwGetInteger(handle, MwNwidth); int h = MwGetInteger(handle, MwNheight); @@ -255,7 +257,7 @@ static void resize(MwWidget handle) { tv->vscroll = MwCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h); MwAddUserHandler(tv->vscroll, MwNchangedHandler, vscroll_changed, NULL); MwSetInteger(tv->vscroll, MwNvalue, 5); - } else { + } else if(!no_resize) { MwVaApply(tv->vscroll, MwNx, w - 16, MwNy, 0, @@ -267,7 +269,7 @@ static void resize(MwWidget handle) { ih = recursive_length(tv->tree); if(ih == 0) ih = 1; - if(ih <= (h / (LinePadding + MwTextHeight(handle, NULL, "M")))) { + if(ih <= (h / (LinePadding + MwTextHeight(handle, Font, "M")))) { MwLLShow(tv->vscroll->lowlevel, 0); } else { MwLLShow(tv->vscroll->lowlevel, 1); @@ -282,7 +284,7 @@ static void resize(MwWidget handle) { tv->frame->draw_inject = frame_draw; MwAddUserHandler(tv->frame, MwNmouseDownHandler, frame_mouse_down, NULL); MwAddUserHandler(tv->frame, MwNmouseUpHandler, frame_mouse_up, NULL); - } else { + } else if(!no_resize || MwGetInteger(tv->frame, MwNwidth) != (w - m)) { MwVaApply(tv->frame, MwNx, 0, MwNy, 0, @@ -292,7 +294,7 @@ static void resize(MwWidget handle) { } MwVaApply(tv->vscroll, - MwNareaShown, h / (LinePadding + MwTextHeight(handle, NULL, "M")), + MwNareaShown, h / (LinePadding + MwTextHeight(handle, Font, "M")), MwNmaxValue, ih, NULL); } @@ -308,7 +310,7 @@ static int wcreate(MwWidget handle) { MwSetInteger(handle, MwNsingleClickSelectable, 0); MwSetInteger(handle, MwNleftPadding, 0); - resize(handle); + resize(handle, 0); tv->changed = 0; return 0; @@ -331,10 +333,6 @@ static void draw(MwWidget handle) { MwLLFreeColor(c); } -static void prop_change(MwWidget handle, const char* prop) { - if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0) resize(handle); -} - static void* mwTreeViewAddImpl(MwWidget handle, void* parent, MwLLPixmap pixmap, const char* item) { MwTreeView tv = handle->internal; MwTreeViewEntry* t = malloc(sizeof(*t)); @@ -354,7 +352,7 @@ static void* mwTreeViewAddImpl(MwWidget handle, void* parent, MwLLPixmap pixmap, arrput(e->tree, t); } - resize(handle); + resize(handle, 1); MwForceRender(tv->frame); return t; @@ -379,6 +377,7 @@ static void mwTreeViewDeleteImpl(MwWidget handle, void* item) { free_all(p->tree); p->tree = NULL; + resize(handle, 1); MwForceRender(tv->frame); } @@ -387,7 +386,7 @@ static void mwTreeViewResetImpl(MwWidget handle) { free_all(tv->tree); tv->tree = NULL; - resize(handle); + resize(handle, 1); MwForceRender(tv->frame); } @@ -407,7 +406,7 @@ static void mwTreeViewSetLabelImpl(MwWidget handle, void* item, const char* labe e->label = MwStringDuplicate(label); if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { - resize(handle); + resize(handle, 1); MwForceRender(tv->frame); } } @@ -419,7 +418,7 @@ static void mwTreeViewSetPixmapImpl(MwWidget handle, void* item, MwLLPixmap pixm e->pixmap = pixmap; if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { - resize(handle); + resize(handle, 1); MwForceRender(tv->frame); } } @@ -431,11 +430,19 @@ static void mwTreeViewSetOpenedImpl(MwWidget handle, void* item, int opened) { e->opened = opened; if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { - resize(handle); + resize(handle, 1); MwForceRender(tv->frame); } } +static int mwTreeViewGetOpenedImpl(MwWidget handle, void* item) { + MwTreeViewEntry* e = item; + + (void)handle; + + return e->opened; +} + static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwTreeViewAdd") == 0) { void* parent = va_arg(va, void*); @@ -469,6 +476,10 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v int opened = va_arg(va, int); mwTreeViewSetOpenedImpl(handle, item, opened); } + if(strcmp(name, "mwTreeViewGetOpened") == 0) { + void* item = va_arg(va, void*); + *(int*)out = mwTreeViewGetOpenedImpl(handle, item); + } } static void tick(MwWidget handle) { @@ -480,13 +491,24 @@ static void tick(MwWidget handle) { } } +static void props_change(MwWidget handle, char** props) { + int i; + int rsz = 0; + + for(i = 0; props[i] != NULL; i++) { + if(strcmp(props[i], MwNwidth) == 0 || strcmp(props[i], MwNheight) == 0) rsz = 1; + } + + if(rsz) resize(handle, 0); +} + MwClassRec MwTreeViewClassRec = { wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ NULL, /* parent_resize */ - prop_change, /* prop_change */ + NULL, /* prop_change */ NULL, /* mouse_move */ NULL, /* mouse_up */ NULL, /* mouse_down */ @@ -497,7 +519,7 @@ MwClassRec MwTreeViewClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + props_change, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/viewport.c b/src/widget/viewport.c index f05b18d5..803c4243 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -1,6 +1,6 @@ #include -static void vscroll_changed(MwWidget handle, void* user, void* call) { +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { MwViewport vp = user; (void)handle; @@ -9,7 +9,7 @@ static void vscroll_changed(MwWidget handle, void* user, void* call) { vp->vchanged = 1; } -static void hscroll_changed(MwWidget handle, void* user, void* call) { +static void MWAPI hscroll_changed(MwWidget handle, void* user, void* call) { MwViewport vp = user; (void)handle; @@ -76,6 +76,12 @@ static void resize(MwWidget handle) { static int wcreate(MwWidget handle) { MwViewport vp = malloc(sizeof(*vp)); + + if(!vp) { + printf("Out Of Memory\n"); + return 1; + } + memset(vp, 0, sizeof(*vp)); handle->internal = vp; @@ -151,7 +157,7 @@ static void tick(MwWidget handle) { v = MwGetInteger(vp->vscroll, MwNvalue); mv = MwGetInteger(vp->vscroll, MwNmaxValue); l = MwGetInteger(vp->frame, MwNheight); - v = (mv - l) * (double)v / mv; + v = (int)((mv - l) * (double)v / mv); if(v < 0) v = 0; MwVaApply(vp->inframe, @@ -166,7 +172,7 @@ static void tick(MwWidget handle) { v = MwGetInteger(vp->hscroll, MwNvalue); mv = MwGetInteger(vp->hscroll, MwNmaxValue); l = MwGetInteger(vp->frame, MwNwidth); - v = (mv - l) * (double)v / mv; + v = (int)((mv - l) * (double)v / mv); if(v < 0) v = 0; MwVaApply(vp->inframe, @@ -192,7 +198,7 @@ MwClassRec MwViewportClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 1e67ea92..f4c53402 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -44,12 +44,6 @@ #include "../../external/stb_ds.h" -MwVulkanConfig vulkan_config = { - .api_version = VK_API_VERSION_1_0, - .vk_version = VK_VERSION_1_0, - .validation_layers = VK_FALSE, -}; - /* convienence macro for handling vulkan errors */ #ifdef HAS_VK_ENUM_STRING_HELPER #define VK_CMD(func) \ @@ -85,9 +79,6 @@ MwVulkanConfig vulkan_config = { return 1; \ } -const char** enabledExtensions; -const char** enabledLayers; - typedef enum vulkan_supported_state_t { VULKAN_SUPPORTED_UNKNOWN, VULKAN_SUPPORTED_YES, @@ -102,6 +93,8 @@ typedef struct vulkan { VkInstance vkInstance; VkSurfaceKHR vkSurface; + MwVulkanConfig vulkan_config; + VkPhysicalDevice vkPhysicalDevice; VkDevice vkLogicalDevice; VkQueue vkGraphicsQueue; @@ -115,6 +108,10 @@ typedef struct vulkan { int vkInstanceExtensionCount; int vkDeviceExtensionCount; int vkLayerCount; + + const char** enabledExtensions; + const char** enabledLayers; + } vulkan_t; static int vulkan_instance_setup(MwWidget handle, vulkan_t* o); @@ -122,27 +119,33 @@ static int vulkan_surface_setup(MwWidget handle, vulkan_t* o); static int vulkan_devices_setup(MwWidget handle, vulkan_t* o); static int wcreate(MwWidget handle) { - vulkan_t* o = malloc(sizeof(*o)); - int err; + int err; + if(!handle->internal) { + vulkan_t* o; + handle->internal = malloc(sizeof(vulkan_t)); + memset(handle->internal, 0, sizeof(vulkan_t)); - memset(o, 0, sizeof(*o)); + o = handle->internal; + o->vulkan_config.api_version = VK_API_VERSION_1_0; + o->vulkan_config.vk_version = VK_VERSION_1_0; + o->vulkan_config.validation_layers = VK_FALSE; + } - err = vulkan_instance_setup(handle, o); + err = vulkan_instance_setup(handle, handle->internal); if(err != 0) { return 1; } - err = vulkan_surface_setup(handle, o); + err = vulkan_surface_setup(handle, handle->internal); if(err != 0) { return 1; } - err = vulkan_devices_setup(handle, o); + err = vulkan_devices_setup(handle, handle->internal); if(err != 0) { return 1; } handle->lowlevel->common.copy_buffer = 0; - handle->internal = o; MwSetDefault(handle); return 0; @@ -185,8 +188,8 @@ static void* vulkan_lib_load() { } static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { - uint32_t vulkan_version = vulkan_config.vk_version; - uint32_t api_version = vulkan_config.api_version; + uint32_t vulkan_version = o->vulkan_config.vk_version; + uint32_t api_version = o->vulkan_config.api_version; uint32_t extension_count = 0; uint32_t layer_count = 0; unsigned long i = 0; @@ -224,27 +227,27 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { VK_ASSERT(_vkCreateInstance); /* setup enabled extensions */ - arrput(enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME); + arrput(o->enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME); #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { - arrput(enabledExtensions, VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + arrput(o->enabledExtensions, VK_KHR_WIN32_SURFACE_EXTENSION_NAME); } #endif #ifdef USE_X11 if(handle->lowlevel->common.type == MwLLBackendX11) { - arrput(enabledExtensions, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + arrput(o->enabledExtensions, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); } #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - arrput(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + arrput(o->enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ - MwWaylandAlwaysRender = MwTRUE; + MwWaylandVulkan = MwTRUE; } #endif #ifdef USE_COCOA if(handle->lowlevel->common.type == MwLLBackendCocoa) { - arrput(enabledExtensions, VK_EXT_METAL_SURFACE_EXTENSION_NAME); + arrput(o->enabledExtensions, VK_EXT_METAL_SURFACE_EXTENSION_NAME); } #endif @@ -252,11 +255,11 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL)); ext_props = malloc(sizeof(VkExtensionProperties) * extension_count); VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, ext_props)); - o->vkInstanceExtensions = malloc(sizeof(const char*) * (arrlen(enabledExtensions) + 1)); + o->vkInstanceExtensions = malloc(sizeof(const char*) * (arrlen(o->enabledExtensions) + 1)); for(i = 0; i < extension_count; i++) { - for(n = 0; n < (unsigned long)arrlen(enabledExtensions); n++) { - if(strcmp(ext_props[i].extensionName, enabledExtensions[n]) == 0) { + for(n = 0; n < (unsigned long)arrlen(o->enabledExtensions); n++) { + if(strcmp(ext_props[i].extensionName, o->enabledExtensions[n]) == 0) { printf("[Vulkan Widget] Enabling extension %s\n", ext_props[i].extensionName); o->vkInstanceExtensions[o->vkInstanceExtensionCount] = ext_props[i].extensionName; o->vkInstanceExtensionCount++; @@ -278,14 +281,14 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, NULL)); layer_props = malloc(sizeof(VkLayerProperties) * layer_count); VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, layer_props)); - o->vkLayers = malloc(256 * (arrlen(enabledLayers) + 1)); + o->vkLayers = malloc(256 * (arrlen(o->enabledLayers) + 1)); - if(vulkan_config.validation_layers) { - arrput(enabledLayers, "VK_LAYER_KHRONOS_validation"); + if(o->vulkan_config.validation_layers) { + arrput(o->enabledLayers, "VK_LAYER_KHRONOS_validation"); } for(i = 0; i < layer_count; i++) { - for(n = 0; n < (unsigned long)arrlen(enabledLayers); n++) { - if(strcmp(layer_props[i].layerName, enabledLayers[n]) == 0) { + for(n = 0; n < (unsigned long)arrlen(o->enabledLayers); n++) { + if(strcmp(layer_props[i].layerName, o->enabledLayers[n]) == 0) { printf("[Vulkan Widget] Enabling layer %s\n", layer_props[i].layerName); o->vkLayers[o->vkLayerCount] = layer_props[i].layerName; o->vkLayerCount++; @@ -452,11 +455,11 @@ static int vulkan_devices_setup(MwWidget handle, vulkan_t* o) { VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, NULL)); ext_props = malloc(sizeof(VkExtensionProperties) * extension_count); VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, ext_props)); - o->vkDeviceExtensions = malloc(sizeof(const char*) * (arrlen(enabledExtensions) + 1)); + o->vkDeviceExtensions = malloc(sizeof(const char*) * (arrlen(o->enabledExtensions) + 1)); for(i = 0; i < extension_count; i++) { - for(n = 0; n < (unsigned long)arrlen(enabledExtensions); n++) { - if(strcmp(ext_props[i].extensionName, enabledExtensions[n]) == 0) { + for(n = 0; n < (unsigned long)arrlen(o->enabledExtensions); n++) { + if(strcmp(ext_props[i].extensionName, o->enabledExtensions[n]) == 0) { o->vkDeviceExtensions[o->vkDeviceExtensionCount] = ext_props[i].extensionName; o->vkDeviceExtensionCount++; break; @@ -489,18 +492,6 @@ static int vulkan_devices_setup(MwWidget handle, vulkan_t* o) { return 0; } -void MwVulkanConfigure(MwVulkanConfig* cfg) { - vulkan_config = *cfg; -} - -void MwVulkanEnableExtension(const char* name) { - arrput(enabledExtensions, name); -} - -void MwVulkanEnableLayer(const char* name) { - arrput(enabledLayers, name); -} - int MwVulkanSupported(void) { if(vulkan_supported == VULKAN_SUPPORTED_UNKNOWN) { void* lib = vulkan_lib_load(); @@ -552,12 +543,36 @@ static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* err) { if(err != NULL) { *err = 0; } -}; +} + +static void prop_change(MwWidget handle, const char* prop) { + vulkan_t* o = (vulkan_t*)handle->internal; + if(!o) { + handle->internal = malloc(sizeof(vulkan_t)); + o = (vulkan_t*)handle->internal; + memset(o, 0, sizeof(vulkan_t)); + o->vulkan_config.api_version = VK_API_VERSION_1_0; + o->vulkan_config.vk_version = VK_VERSION_1_0; + o->vulkan_config.validation_layers = VK_FALSE; + } + + if(strcmp(prop, MwNvulkanExtension) == 0) { + char* str = MwStringDuplicate(MwGetText(handle, MwNvulkanExtension)); + + arrput(o->enabledExtensions, str); + } else if(strcmp(prop, MwNvulkanLayer) == 0) { + char* str = MwStringDuplicate(MwGetText(handle, MwNvulkanExtension)); + + arrput(o->enabledLayers, str); + } else if(strcmp(prop, MwNvulkanConfig) == 0) { + memcpy(&o->vulkan_config, MwGetVoid(handle, MwNvulkanConfig), sizeof(MwVulkanConfig)); + } +} static void func_handler(MwWidget handle, const char* name, void* output, va_list va) { if(strcmp(name, "mwVulkanGetField") == 0) { - int field = va_arg(va, int); - int* err = va_arg(va, int*); + int field = va_arg(va, int); + int* err = va_arg(va, int*); *(void**)output = mwVulkanGetFieldImpl(handle, field, err); } } @@ -568,7 +583,7 @@ MwClassRec MwVulkanClassRec = { NULL, /* draw */ NULL, /* click */ NULL, /* parent_resize */ - NULL, /* prop_change */ + prop_change, /* prop_change */ NULL, /* mouse_move */ NULL, /* mouse_up */ NULL, /* mouse_down */ @@ -579,7 +594,7 @@ MwClassRec MwVulkanClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; @@ -587,14 +602,6 @@ MwClass MwVulkanClass = &MwVulkanClassRec; #else MwClass MwVulkanClass = NULL; -void MwVulkanEnableExtension(const char* ext_name) { - (void)ext_name; -} - -void MwVulkanEnableLayer(const char* ext_name) { - (void)ext_name; -} - void MwVulkanConfigure(MwVulkanConfig* cfg) { (void)cfg; } diff --git a/src/widget/window.c b/src/widget/window.c index 2b596b50..3d0afe25 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -35,6 +35,10 @@ static void mwWindowMakeBorderlessImpl(MwWidget handle, int toggle) { MwLLEndStateChange(handle->lowlevel); } +static void mwWindowShouldCloseImpl(MwWidget handle, MwBool* out) { + *out = handle->close; +} + static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { (void)out; @@ -42,6 +46,10 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v int toggle = va_arg(va, int); mwWindowMakeBorderlessImpl(handle, toggle); } + if(strcmp(name, "mwWindowShouldClose") == 0) { + MwBool* out = va_arg(va, MwBool*); + mwWindowShouldCloseImpl(handle, out); + } } MwClassRec MwWindowClassRec = { wcreate, /* create */ @@ -60,7 +68,7 @@ MwClassRec MwWindowClassRec = { NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ - NULL, + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/tools/Makefile b/tools/Makefile index ef863683..036e3658 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,21 +1,24 @@ CC = gcc -CFLAGS = `freetype-config --cflags` +CFLAGS = `pkg-config --cflags freetype2` -I../include LDFLAGS = -LIBS = `freetype-config --libs` +LIBS = `pkg-config --libs freetype2` .PHONY: all clean .SUFFIXES: .c .o -all: fuzzer font +all: fuzzer font icon-converter icon-converter fuzzer: fuzzer.o - $(CC) -g -L../src/ -Wl,-R../src -lMw -o $@ fuzzer.o + $(CC) -g -L../src/ -Wl,-R../src -o $@ fuzzer.o -lMw font: font.o $(CC) $(LDFLAGS) -o $@ font.o $(LIBS) +icon-converter: icon-converter.o + $(CC) -o $@ icon-converter.o -lm + .c.o: $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f *.o font fuzzer + rm -f *.o font fuzzer icon-converter diff --git a/tools/color.pl b/tools/color.pl index e872ead2..eca072ca 100755 --- a/tools/color.pl +++ b/tools/color.pl @@ -4,6 +4,15 @@ open(OUT, ">", "src/color.c"); print(OUT "#include \n"); print(OUT "\n"); +print(OUT "#include \"../external/stb_ds.h\"\n"); +print(OUT "\n"); +print(OUT "struct color {\n"); +print(OUT " char* key;\n"); +print(OUT " MwU32 value;\n"); +print(OUT "};\n"); +print(OUT "\n"); +print(OUT "static struct color* colors = NULL;\n"); +print(OUT "\n"); print(OUT "MwLLColor MwParseColorName(MwWidget handle, const char* color){\n"); print(OUT " MwRGB rgb;\n"); print(OUT " MwParseColorNameNoAllocate(color, &rgb);\n"); @@ -13,21 +22,29 @@ print(OUT print(OUT "}\n"); print(OUT "\n"); print(OUT "void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb){\n"); +print(OUT " MwU32 v = shget(colors, color);"); +print(OUT " rgb->red = (v >> 16) & 0xff;"); +print(OUT " rgb->green = (v >> 8) & 0xff;"); +print(OUT " rgb->blue = (v >> 0) & 0xff;"); +print(OUT "}\n"); +print(OUT "\n"); +print(OUT + "static void add_color(const char* name, int red, int green, int blue){\n" +); +print(OUT " MwU32 v = (red << 16) | (green << 8) | (blue << 0);\n"); +print(OUT " shput(colors, name, v);\n"); +print(OUT "}\n"); +print(OUT "\n"); +print(OUT "void MwColorTableInit(void){\n"); +print(OUT " sh_new_strdup(colors);\n"); +print(OUT " shdefault(colors, 0);\n"); while (my $l = ) { $l =~ s/\r?\n$//; if ($l =~ /^[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+(.+)$/) { - print(OUT " if(strcmp(color, \"$4\") == 0){\n"); - print(OUT " rgb->red = $1;\n"); - print(OUT " rgb->green = $2;\n"); - print(OUT " rgb->blue = $3;\n"); - print(OUT " return;\n"); - print(OUT " }\n"); + print(OUT " add_color(\"$4\", $1, $2, $3);\n"); } } -print(OUT " rgb->red = 0;\n"); -print(OUT " rgb->green = 0;\n"); -print(OUT " rgb->blue = 0;\n"); print(OUT "}\n"); close(OUT); diff --git a/tools/fuzzer.c b/tools/fuzzer.c index 5b4224e9..dae1dde2 100644 --- a/tools/fuzzer.c +++ b/tools/fuzzer.c @@ -1,85 +1,76 @@ #include +#include -#define WIDGET_AMOUNT 1 +#define WIDGET_AMOUNT 16 + +#define H(h) {&h, #h} + +typedef struct cls_pair { + MwClass* cls; + const char* name; +} cls_pair_t; + +cls_pair_t classes[] = {H(MwBoxClass), H(MwButtonClass), H(MwCheckBoxClass), H(MwComboBoxClass), H(MwEntryClass), H(MwFrameClass), H(MwImageClass), H(MwLabelClass), H(MwListBoxClass), H(MwMenuClass), H(MwNumberEntryClass), H(MwProgressBarClass), H(MwRadioBoxClass), H(MwScrollBarClass), H(MwSeparatorClass), H(MwTreeViewClass), H(MwViewportClass)}; +char* int_params[] = {/*MwNx, MwNy, MwNwidth, MwNheight,*/ MwNorientation, MwNminValue, MwNmaxValue, MwNvalue, MwNchangedBy, MwNareaShown, MwNchecked, MwNalignment, MwNbold, MwNmain, MwNleftPadding, MwNhasHeading, MwNhasBorder, MwNinverted, MwNmodernLook, MwNwaitMS, MwNhideInput, MwNsingleClickSelectable, MwNflat, MwNshowArrows, MwNpadding, MwNborderWidth, MwNfillArea, MwNratio, MwNfixedSize, MwNmargin, MwNbitmapFont, MwNsevenSegment, MwNlength, MwNforceInverted, MwNisRounded, MwNdarkTheme}; +unsigned long maxxes[] = {UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX}; int main() { - MwWidget window, widget; + int i, j = 0, max = 0; + char input; + MwWidget window, widget; + unsigned long upper_limit; + + printf("How many iteration do you want to do? Type -1 if you wanna run it forever.\n"); + scanf("%d", &max); + + printf("What upper limit of int params do you want to test?\n"); + for(i = 0; i < (sizeof(maxxes) / sizeof(unsigned long)); i++) { + printf("%d) %lu\n", i, maxxes[i]); + } +get_input: + input = getchar(); + switch(input) { + case '0': + upper_limit = maxxes[0]; + break; + case '1': + upper_limit = maxxes[1]; + break; + case '2': + upper_limit = maxxes[2]; + break; + case '3': + upper_limit = maxxes[3]; + break; + default: + upper_limit = maxxes[0]; + // printf("Invalid value. Pick 0-3.\n"); + // goto get_input; + } MwLibraryInit(); window = MwCreateWidget(MwWindowClass, "window", NULL, 0, 0, 400, 400); - while(true) { - int r = rand() % WIDGET_AMOUNT; - MwClass cls; - switch(r) { - case 0: - cls = MwBoxClass; - break; - case 1: - cls = MwButtonClass; - break; - case 2: - cls = MwCheckBoxClass; - break; - case 3: - cls = MwComboBoxClass; - break; - case 4: - cls = MwEntryClass; - break; - case 5: - cls = MwFrameClass; - break; - case 6: - cls = MwImageClass; - break; - case 7: - cls = MwLabelClass; - break; - case 8: - cls = MwListBoxClass; - break; - case 9: - cls = MwMenuClass; - break; - case 10: - cls = MwNumberEntryClass; - break; - case 12: - cls = MwProgressBarClass; - break; - case 13: - cls = MwRadioBoxClass; - break; - case 14: - cls = MwScrollBarClass; - break; - case 15: - cls = MwSeparatorClass; - break; - // case 16: - // cls = MwSubMenuClass; - // break; - case 17: - cls = MwTreeViewClass; - break; - case 18: - cls = MwViewportClass; - break; - default: - cls = NULL; - break; - } - if(cls) { - widget = MwCreateWidget(cls, "Cls", window, 0, 0, 100, 100); - } + while(MwPending(window) && (max == -1 || j < max)) { + int class_num = rand() % (sizeof(classes) / sizeof(cls_pair_t)); + widget = MwCreateWidget(*classes[class_num].cls, classes[class_num].name, window, 0, 0, 100, 100); - if(MwPending(window)) { - MwStep(window); - } - if(cls) { - MwDestroyWidget(widget); + printf("%s\n", classes[class_num].name); + /* apply int params with random scale */ + for(i = 0; i < (sizeof(int_params) / sizeof(void*)); i++) { + unsigned long number = rand() % upper_limit; + printf("> %s = %lu\n", int_params[i], number); + MwVaApply(widget, int_params[i], number, NULL); } + MwStep(window); + + MwDestroyWidget(widget); + + printf("\n"); + + j++; } + + MwFreeWidget(window); } diff --git a/tools/genmk.pl b/tools/genmk.pl index ae03d9f7..689e09ef 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -1,5 +1,6 @@ #!/usr/bin/env perl -my @cfiles = (); +my @cfiles = (); +my @examples = (); sub scan { opendir(DIR, $_[0]); @@ -15,6 +16,20 @@ sub scan { closedir(DIR); } +sub scan_examples { + opendir(DIR, $_[0]); + my @files = readdir(DIR); + foreach my $f (@files) { + if ($f =~ /^glutlayer\.c$/) { + next; + } + if ($f =~ /\.c$/) { + push(@examples, $_[0] . "/" . $f); + } + } + closedir(DIR); +} + sub cobjs { my $r = ""; foreach my $f (@cfiles) { @@ -39,9 +54,12 @@ sub generate { my $del = "del /f /q"; my $out = ""; my $dllout = ""; + my $exeout = ""; my $def = ""; my $inc = ""; + my $cdll = ""; my $dll = ""; + my $exe = ""; my $prefobj = ""; my $needlibs = ""; my $lib = ""; @@ -53,6 +71,7 @@ sub generate { $link = "bcc32"; $out = "-o"; $dllout = "-e"; + $exeout = "-e"; $def = "-D"; $inc = "-I"; $dll = "-tWD"; @@ -65,18 +84,22 @@ sub generate { $link = "link /nologo"; $out = "/Fo"; $dllout = "/OUT:"; + $exeout = "/OUT:"; $def = "/D"; $inc = "/I"; $dll = "/DLL"; } elsif ($type eq "Watcom") { - $cc = "wcc386 -bt=nt -q -bd"; + $cc = "wcc386 -bt=nt -q"; $link = "wlink option quiet"; $out = "-fo="; $dllout = "name "; + $exeout = "name "; $def = "-d"; $inc = "-i="; + $cdll = "-bd"; $dll = "system nt_dll"; + $exe = "system nt"; $lib = "library "; $suffix = 0; # watcom suffix rule works kinda strange @@ -93,15 +116,33 @@ sub generate { print(OUT "LD = $link\n"); print(OUT "\n"); print(OUT -"CFLAGS = ${inc}include ${inc}external${dir}libz${dir}include ${def}_MILSKO ${def}USE_GDI ${def}USE_STB_TRUETYPE ${def}USE_STB_IMAGE ${def}STBI_NO_SIMD\n" +"MW_CFLAGS = ${cdll} ${inc}include ${inc}external${dir}libz${dir}include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}USE_STB_IMAGE ${def}STBI_NO_SIMD ${def}USE_GDI_TEXT ${def}MW_OPENGL\n" ); - print(OUT "LDFLAGS = $dll"); + print(OUT "MW_LDFLAGS = $dll\n"); + print(OUT "EXE_CFLAGS = ${inc}include\n"); + print(OUT "EXE_LDFLAGS = $exe"); print(OUT "\n"); if ($suffix) { print(OUT ".SUFFIXES: .obj .c\n"); } - print(OUT "all: src${dir}Mw.dll\n"); + print(OUT "all: src${dir}Mw.dll"); + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $b"); + } + print(OUT "\n"); + print(OUT "lib: src${dir}Mw.dll\n"); + print(OUT "examples:"); + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $b"); + } + print(OUT "\n"); print(OUT "clean: $symbolic\n"); foreach my $f (@cfiles) { my $b = $f; @@ -109,26 +150,54 @@ sub generate { $b =~ s/\//$dir/g; print(OUT " $del $b\n"); } - foreach my $f (@cxxfiles) { + print(OUT " $del src${dir}Mw.dll\n"); + print(OUT " $del src${dir}Mw.lib\n"); + foreach my $f (@examples) { my $b = $f; $b =~ s/\.c$/.obj/; $b =~ s/\//$dir/g; print(OUT " $del $b\n"); } - print(OUT " $del src${dir}Mw.dll\n"); - print(OUT " $del src${dir}Mw.lib\n"); + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $del $b\n"); + } + print(OUT "\n"); + foreach my $f (@examples) { + my $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + my $o = $f; + $o =~ s/\.c$/.obj/; + $o =~ s/\//$dir/g; + print(OUT "$b: $o src${dir}Mw.dll\n"); + print(OUT +" \$(LD) \$(EXE_LDFLAGS) $exeout\$@ $prefobj$o $needlibs ${lib}src${dir}Mw.lib" + ); + + if ($f =~ /gldemos/) { + print(OUT " ${lib}opengl32.lib ${lib}glu32.lib"); + } + print(OUT "\n"); + print(OUT "\n"); + print(OUT "$o: $f\n"); + print(OUT " \$(CC) \$(EXE_CFLAGS) ${out}\$@ $f\n"); + print(OUT "\n"); + } print(OUT "\n"); print(OUT "src${dir}Mw.dll: " . cobjs($dir) . "\n"); - print( OUT " \$(LD) \$(LDFLAGS) $c_dllout $dllout\$@ " + print( OUT " \$(LD) \$(MW_LDFLAGS) $c_dllout $dllout\$@ " . cobjs($dir, $prefobj) - . " $needlibs ${lib}opengl32.lib ${lib}gdi32.lib ${lib}user32.lib ${lib}advapi32.lib\n" + . " $needlibs ${lib}opengl32.lib ${lib}gdi32.lib ${lib}ole32.lib ${lib}uuid.lib ${lib}user32.lib ${lib}advapi32.lib\n" ); print(OUT " $c_dllafter\n"); print(OUT "\n"); if ($suffix) { print(OUT ".c.obj:\n"); - print(OUT " \$(CC) \$(CFLAGS) ${out}\$@ \$<\n"); + print(OUT " \$(CC) \$(MW_CFLAGS) ${out}\$@ \$<\n"); } else { print(OUT "\n"); @@ -136,7 +205,7 @@ sub generate { my $o = $f; $o =~ s/\.c$/.obj/; print(OUT "$o: $f\n"); - print(OUT " \$(CC) \$(CFLAGS) ${out}\$@ \$<\n"); + print(OUT " \$(CC) \$(MW_CFLAGS) ${out}\$@ $f\n"); } } close(OUT); @@ -156,6 +225,11 @@ push(@cfiles, "src/backend/gdi.c"); @cfiles = sort(@cfiles); +scan_examples("examples/basic"); +scan_examples("examples/gldemos"); + +@examples = sort(@examples); + generate("BorMakefile", "Borland"); generate("NTMakefile", "MSVC"); generate("WatMakefile", "Watcom"); diff --git a/tools/icon-converter.c b/tools/icon-converter.c new file mode 100644 index 00000000..11dc4510 --- /dev/null +++ b/tools/icon-converter.c @@ -0,0 +1,36 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "../external/stb_image.h" + +#include + +int main(int argc, char** argv) { + unsigned char* rgba; + int width, height, bpp; + int i; + + if(argc != 3) { + printf("Usage: %s input name\n", argv[0]); + return 1; + } + + rgba = stbi_load(argv[1], &width, &height, &bpp, 4); + + printf("MwU32 %s[] = {\n", argv[2]); + printf(" (%d << 16) | %d,\n", width, height); + for(i = 0; i < width * height; i++) { + unsigned char* px = &rgba[i * 4]; + unsigned int p = 0; + int j; + + for(j = 0; j < 4; j++) { + p = p << 8; + p = p | px[j]; + } + + printf(" 0x%x,\n", p); + } + printf(" 0\n"); + printf("};\n"); + + free(rgba); +} diff --git a/tools/logo.sh b/tools/logo.sh index b2f2f6c7..9d346018 100755 --- a/tools/logo.sh +++ b/tools/logo.sh @@ -1,8 +1,9 @@ #!/bin/sh povray +A +W256 +H256 +Ologo.png resource/logo/logo.pov povray +A +W1280 +H640 +Obanner.png resource/logo/banner.pov +povray +A +W1280 +H640 +Obanner-nodejs.png Declare=NODEJS=1 resource/logo/banner.pov povray +A +W102 +H47 +O102x47.png resource/logo/102x47.pov -mv logo.png banner.png resource/logo/ +mv logo.png banner.png banner-nodejs.png resource/logo/ magick resource/logo/logo.png -scale x64 resource/logo/logo64.png magick 102x47.png resource/logo/overlay-102x47.png -compose over -composite resource/logo/102x47.png rm -f 102x47.png diff --git a/tools/readme.pl b/tools/readme.pl index 653184c1..d7c1909a 100755 --- a/tools/readme.pl +++ b/tools/readme.pl @@ -60,8 +60,9 @@ c("Requirements"); l(""); l(" Milsko requires either"); l(" * A Windows environment with GDI (so anything NT or 9x)"); -l(" * A MacOS environment with Cocoa (10.4 or above supported)"); -l(" * A Unix-like environment with X11 for runtime."); + +#l(" * A MacOS environment with Cocoa (10.4 or above supported)"); +l(" * A Unix-like environment with Wayland and/or X11 for runtime."); l(""); l(" To build Milsko for Windows, you must have one of following compilers:"); l(" * Visual C++ 6.0 or newer"); @@ -106,8 +107,11 @@ l("1) Run `wmake -f WatMakefile'."); h("D. MinGW-w64/GCC/Clang"); l("1) Determine if you need Vulkan and/or OpenGL."); l(""); -l("2) Run `./configure'."); -l(" For help, run `./configure --help'."); +l("2) Either:"); +l(" a.) Run `./configure'. For help, run `./configure --help'."); +l( +" b.) Use CMake; i.e. `cmake -B build`. (if contributing, name the build folder build as that's what's included in the .gitignore)" +); l(""); l("3) Run `make'."); l(""); diff --git a/tools/watcom-pack.sh b/tools/watcom-pack.sh index 81626dbf..e9bfb604 100755 --- a/tools/watcom-pack.sh +++ b/tools/watcom-pack.sh @@ -4,20 +4,10 @@ wmake -f WatMakefile rm -rf milsko mkdir -p milsko-examples cp src/Mw.dll milsko-examples/ -cd examples/basic -for i in *.c; do - owcc -bnt -I../../include ../../src/Mw.lib -o../../milsko-examples/`echo $i | cut -d. -f1`.exe $i +cp examples/basic/*.exe milsko-examples/ +for i in examples/gldemos/*.exe; do + cp $i milsko-examples/gl`echo $i | rev | cut -d/ -f1 | rev` done -cd ../.. -cd examples/gldemos -for i in *.c; do - if [ "$i" = "glutlayer.c" ]; then - continue - fi - owcc -bnt -I../../include ../../src/Mw.lib -o../../milsko-examples/gl`echo $i | cut -d. -f1`.exe $i opengl32.lib glu32.lib -done -cd ../.. rm -f milsko-examples.zip cp resource/logo/logo.png examples/picture.jpg examples/picture.png milsko-examples/ zip -rv milsko-examples.zip milsko-examples -rm -rf milsko-examples diff --git a/vms/build.com b/vms/build.com deleted file mode 100644 index 06467b32..00000000 --- a/vms/build.com +++ /dev/null @@ -1,346 +0,0 @@ -$ if f$search("[.src]color.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]color.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]color.obj [.src]color.c -$ endif -$ if f$search("[.src]draw.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]draw.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]draw.obj [.src]draw.c -$ endif -$ if f$search("[.src]lowlevel.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]lowlevel.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]lowlevel.obj [.src]lowlevel.c -$ endif -$ if f$search("[.src]string.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]string.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]string.obj [.src]string.c -$ endif -$ if f$search("[.src]unicode.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]unicode.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]unicode.obj [.src]unicode.c -$ endif -$ if f$search("[.src]core.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]core.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]core.obj [.src]core.c -$ endif -$ if f$search("[.src]default.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src]default.obj" -$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]default.obj [.src]default.c -$ endif -$ if f$search("[.src.cursor]hidden.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.cursor]hidden.obj" -$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]hidden.obj [.src.cursor]hidden.c -$ endif -$ if f$search("[.src.cursor]arrow.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.cursor]arrow.obj" -$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]arrow.obj [.src.cursor]arrow.c -$ endif -$ if f$search("[.src.cursor]cross.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.cursor]cross.obj" -$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]cross.obj [.src.cursor]cross.c -$ endif -$ if f$search("[.src.cursor]text.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.cursor]text.obj" -$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]text.obj [.src.cursor]text.c -$ endif -$ if f$search("[.src.cursor]default.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.cursor]default.obj" -$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]default.obj [.src.cursor]default.c -$ endif -$ if f$search("[.src.widget]menu.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]menu.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]menu.obj [.src.widget]menu.c -$ endif -$ if f$search("[.src.widget]image.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]image.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]image.obj [.src.widget]image.c -$ endif -$ if f$search("[.src.widget]viewport.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]viewport.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]viewport.obj [.src.widget]viewport.c -$ endif -$ if f$search("[.src.widget]treeview.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]treeview.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]treeview.obj [.src.widget]treeview.c -$ endif -$ if f$search("[.src.widget]button.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]button.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]button.obj [.src.widget]button.c -$ endif -$ if f$search("[.src.widget]radiobox.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]radiobox.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]radiobox.obj [.src.widget]radiobox.c -$ endif -$ if f$search("[.src.widget]scrollbar.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]scrollbar.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]scrollbar.obj [.src.widget]scrollbar.c -$ endif -$ if f$search("[.src.widget]progressbar.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]progressbar.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]progressbar.obj [.src.widget]progressbar.c -$ endif -$ if f$search("[.src.widget]submenu.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]submenu.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]submenu.obj [.src.widget]submenu.c -$ endif -$ if f$search("[.src.widget]checkbox.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]checkbox.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]checkbox.obj [.src.widget]checkbox.c -$ endif -$ if f$search("[.src.widget]entry.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]entry.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]entry.obj [.src.widget]entry.c -$ endif -$ if f$search("[.src.widget]window.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]window.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]window.obj [.src.widget]window.c -$ endif -$ if f$search("[.src.widget]label.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]label.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]label.obj [.src.widget]label.c -$ endif -$ if f$search("[.src.widget]separator.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]separator.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]separator.obj [.src.widget]separator.c -$ endif -$ if f$search("[.src.widget]combobox.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]combobox.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]combobox.obj [.src.widget]combobox.c -$ endif -$ if f$search("[.src.widget]numberentry.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]numberentry.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]numberentry.obj [.src.widget]numberentry.c -$ endif -$ if f$search("[.src.widget]frame.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]frame.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]frame.obj [.src.widget]frame.c -$ endif -$ if f$search("[.src.widget]listbox.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]listbox.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]listbox.obj [.src.widget]listbox.c -$ endif -$ if f$search("[.src.widget]box.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.widget]box.obj" -$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]box.obj [.src.widget]box.c -$ endif -$ if f$search("[.src.dialog]directorychooser.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.dialog]directorychooser.obj" -$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]directorychooser.obj [.src.dialog]directorychooser.c -$ endif -$ if f$search("[.src.dialog]filechooser.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.dialog]filechooser.obj" -$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]filechooser.obj [.src.dialog]filechooser.c -$ endif -$ if f$search("[.src.dialog]messagebox.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.dialog]messagebox.obj" -$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]messagebox.obj [.src.dialog]messagebox.c -$ endif -$ if f$search("[.src.dialog]colorpicker.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.dialog]colorpicker.obj" -$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]colorpicker.obj [.src.dialog]colorpicker.c -$ endif -$ if f$search("[.src.icon]right.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]right.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]right.obj [.src.icon]right.c -$ endif -$ if f$search("[.src.icon]info.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]info.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]info.obj [.src.icon]info.c -$ endif -$ if f$search("[.src.icon]computer.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]computer.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]computer.obj [.src.icon]computer.c -$ endif -$ if f$search("[.src.icon]forward.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]forward.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]forward.obj [.src.icon]forward.c -$ endif -$ if f$search("[.src.icon]left.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]left.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]left.obj [.src.icon]left.c -$ endif -$ if f$search("[.src.icon]clock.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]clock.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]clock.obj [.src.icon]clock.c -$ endif -$ if f$search("[.src.icon]warning.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]warning.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]warning.obj [.src.icon]warning.c -$ endif -$ if f$search("[.src.icon]directory.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]directory.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]directory.obj [.src.icon]directory.c -$ endif -$ if f$search("[.src.icon]file.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]file.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]file.obj [.src.icon]file.c -$ endif -$ if f$search("[.src.icon]back.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]back.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]back.obj [.src.icon]back.c -$ endif -$ if f$search("[.src.icon]down.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]down.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]down.obj [.src.icon]down.c -$ endif -$ if f$search("[.src.icon]news.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]news.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]news.obj [.src.icon]news.c -$ endif -$ if f$search("[.src.icon]error.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]error.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]error.obj [.src.icon]error.c -$ endif -$ if f$search("[.src.icon]note.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]note.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]note.obj [.src.icon]note.c -$ endif -$ if f$search("[.src.icon]search.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]search.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]search.obj [.src.icon]search.c -$ endif -$ if f$search("[.src.icon]up.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.icon]up.obj" -$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]up.obj [.src.icon]up.c -$ endif -$ if f$search("[.src.abstract]time.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.abstract]time.obj" -$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]time.obj [.src.abstract]time.c -$ endif -$ if f$search("[.src.abstract]directory.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.abstract]directory.obj" -$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]directory.obj [.src.abstract]directory.c -$ endif -$ if f$search("[.src.abstract]dynamic.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.abstract]dynamic.obj" -$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]dynamic.obj [.src.abstract]dynamic.c -$ endif -$ if f$search("[.external]stb_ds.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.external]stb_ds.obj" -$ cc /include_directory=("./include","./external") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.external]stb_ds.obj [.external]stb_ds.c -$ endif -$ if f$search("[.src.backend]x11.obj;*") .eqs. "" -$ then -$ write sys$output "CC [.src.backend]x11.obj" -$ cc /include_directory=("./include","./src/backend") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.backend]x11.obj [.src.backend]x11.c -$ endif -$ if f$search("[.src]MwSHR.exe;*") .eqs. "" -$ then -$ write sys$output "LINK [.src]MwSHR.exe" -$ OPEN /WRITE LINK_OPT LINK.OPT -$ WRITE LINK_OPT "[.src]color.obj" -$ WRITE LINK_OPT "[.src]draw.obj" -$ WRITE LINK_OPT "[.src]lowlevel.obj" -$ WRITE LINK_OPT "[.src]string.obj" -$ WRITE LINK_OPT "[.src]unicode.obj" -$ WRITE LINK_OPT "[.src]core.obj" -$ WRITE LINK_OPT "[.src]default.obj" -$ WRITE LINK_OPT "[.src.cursor]hidden.obj" -$ WRITE LINK_OPT "[.src.cursor]arrow.obj" -$ WRITE LINK_OPT "[.src.cursor]cross.obj" -$ WRITE LINK_OPT "[.src.cursor]text.obj" -$ WRITE LINK_OPT "[.src.cursor]default.obj" -$ WRITE LINK_OPT "[.src.widget]menu.obj" -$ WRITE LINK_OPT "[.src.widget]image.obj" -$ WRITE LINK_OPT "[.src.widget]viewport.obj" -$ WRITE LINK_OPT "[.src.widget]treeview.obj" -$ WRITE LINK_OPT "[.src.widget]button.obj" -$ WRITE LINK_OPT "[.src.widget]radiobox.obj" -$ WRITE LINK_OPT "[.src.widget]scrollbar.obj" -$ WRITE LINK_OPT "[.src.widget]progressbar.obj" -$ WRITE LINK_OPT "[.src.widget]submenu.obj" -$ WRITE LINK_OPT "[.src.widget]checkbox.obj" -$ WRITE LINK_OPT "[.src.widget]entry.obj" -$ WRITE LINK_OPT "[.src.widget]window.obj" -$ WRITE LINK_OPT "[.src.widget]label.obj" -$ WRITE LINK_OPT "[.src.widget]separator.obj" -$ WRITE LINK_OPT "[.src.widget]combobox.obj" -$ WRITE LINK_OPT "[.src.widget]numberentry.obj" -$ WRITE LINK_OPT "[.src.widget]frame.obj" -$ WRITE LINK_OPT "[.src.widget]listbox.obj" -$ WRITE LINK_OPT "[.src.widget]box.obj" -$ WRITE LINK_OPT "[.src.dialog]directorychooser.obj" -$ WRITE LINK_OPT "[.src.dialog]filechooser.obj" -$ WRITE LINK_OPT "[.src.dialog]messagebox.obj" -$ WRITE LINK_OPT "[.src.dialog]colorpicker.obj" -$ WRITE LINK_OPT "[.src.icon]right.obj" -$ WRITE LINK_OPT "[.src.icon]info.obj" -$ WRITE LINK_OPT "[.src.icon]computer.obj" -$ WRITE LINK_OPT "[.src.icon]forward.obj" -$ WRITE LINK_OPT "[.src.icon]left.obj" -$ WRITE LINK_OPT "[.src.icon]clock.obj" -$ WRITE LINK_OPT "[.src.icon]warning.obj" -$ WRITE LINK_OPT "[.src.icon]directory.obj" -$ WRITE LINK_OPT "[.src.icon]file.obj" -$ WRITE LINK_OPT "[.src.icon]back.obj" -$ WRITE LINK_OPT "[.src.icon]down.obj" -$ WRITE LINK_OPT "[.src.icon]news.obj" -$ WRITE LINK_OPT "[.src.icon]error.obj" -$ WRITE LINK_OPT "[.src.icon]note.obj" -$ WRITE LINK_OPT "[.src.icon]search.obj" -$ WRITE LINK_OPT "[.src.icon]up.obj" -$ WRITE LINK_OPT "[.src.abstract]time.obj" -$ WRITE LINK_OPT "[.src.abstract]directory.obj" -$ WRITE LINK_OPT "[.src.abstract]dynamic.obj" -$ WRITE LINK_OPT "[.external]stb_ds.obj" -$ WRITE LINK_OPT "[.src.backend]x11.obj" -$ WRITE LINK_OPT "SYS$LIBRARY:DECW$XLIBSHR/SHARE" -$ WRITE LINK_OPT "SYS$LIBRARY:DPML$SHR/SHARE" -$ CLOSE LINK_OPT -$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options -$ DELETE LINK.OPT;* -$ endif diff --git a/vms/clean.com b/vms/clean.com deleted file mode 100644 index 45b54d4b..00000000 --- a/vms/clean.com +++ /dev/null @@ -1,57 +0,0 @@ -$ if f$search("[.src]color.obj") .nes. "" then delete [.src]color.obj;* -$ if f$search("[.src]draw.obj") .nes. "" then delete [.src]draw.obj;* -$ if f$search("[.src]lowlevel.obj") .nes. "" then delete [.src]lowlevel.obj;* -$ if f$search("[.src]string.obj") .nes. "" then delete [.src]string.obj;* -$ if f$search("[.src]unicode.obj") .nes. "" then delete [.src]unicode.obj;* -$ if f$search("[.src]core.obj") .nes. "" then delete [.src]core.obj;* -$ if f$search("[.src]default.obj") .nes. "" then delete [.src]default.obj;* -$ if f$search("[.src.cursor]hidden.obj") .nes. "" then delete [.src.cursor]hidden.obj;* -$ if f$search("[.src.cursor]arrow.obj") .nes. "" then delete [.src.cursor]arrow.obj;* -$ if f$search("[.src.cursor]cross.obj") .nes. "" then delete [.src.cursor]cross.obj;* -$ if f$search("[.src.cursor]text.obj") .nes. "" then delete [.src.cursor]text.obj;* -$ if f$search("[.src.cursor]default.obj") .nes. "" then delete [.src.cursor]default.obj;* -$ if f$search("[.src.widget]menu.obj") .nes. "" then delete [.src.widget]menu.obj;* -$ if f$search("[.src.widget]image.obj") .nes. "" then delete [.src.widget]image.obj;* -$ if f$search("[.src.widget]viewport.obj") .nes. "" then delete [.src.widget]viewport.obj;* -$ if f$search("[.src.widget]treeview.obj") .nes. "" then delete [.src.widget]treeview.obj;* -$ if f$search("[.src.widget]button.obj") .nes. "" then delete [.src.widget]button.obj;* -$ if f$search("[.src.widget]radiobox.obj") .nes. "" then delete [.src.widget]radiobox.obj;* -$ if f$search("[.src.widget]scrollbar.obj") .nes. "" then delete [.src.widget]scrollbar.obj;* -$ if f$search("[.src.widget]progressbar.obj") .nes. "" then delete [.src.widget]progressbar.obj;* -$ if f$search("[.src.widget]submenu.obj") .nes. "" then delete [.src.widget]submenu.obj;* -$ if f$search("[.src.widget]checkbox.obj") .nes. "" then delete [.src.widget]checkbox.obj;* -$ if f$search("[.src.widget]entry.obj") .nes. "" then delete [.src.widget]entry.obj;* -$ if f$search("[.src.widget]window.obj") .nes. "" then delete [.src.widget]window.obj;* -$ if f$search("[.src.widget]label.obj") .nes. "" then delete [.src.widget]label.obj;* -$ if f$search("[.src.widget]separator.obj") .nes. "" then delete [.src.widget]separator.obj;* -$ if f$search("[.src.widget]combobox.obj") .nes. "" then delete [.src.widget]combobox.obj;* -$ if f$search("[.src.widget]numberentry.obj") .nes. "" then delete [.src.widget]numberentry.obj;* -$ if f$search("[.src.widget]frame.obj") .nes. "" then delete [.src.widget]frame.obj;* -$ if f$search("[.src.widget]listbox.obj") .nes. "" then delete [.src.widget]listbox.obj;* -$ if f$search("[.src.widget]box.obj") .nes. "" then delete [.src.widget]box.obj;* -$ if f$search("[.src.dialog]directorychooser.obj") .nes. "" then delete [.src.dialog]directorychooser.obj;* -$ if f$search("[.src.dialog]filechooser.obj") .nes. "" then delete [.src.dialog]filechooser.obj;* -$ if f$search("[.src.dialog]messagebox.obj") .nes. "" then delete [.src.dialog]messagebox.obj;* -$ if f$search("[.src.dialog]colorpicker.obj") .nes. "" then delete [.src.dialog]colorpicker.obj;* -$ if f$search("[.src.icon]right.obj") .nes. "" then delete [.src.icon]right.obj;* -$ if f$search("[.src.icon]info.obj") .nes. "" then delete [.src.icon]info.obj;* -$ if f$search("[.src.icon]computer.obj") .nes. "" then delete [.src.icon]computer.obj;* -$ if f$search("[.src.icon]forward.obj") .nes. "" then delete [.src.icon]forward.obj;* -$ if f$search("[.src.icon]left.obj") .nes. "" then delete [.src.icon]left.obj;* -$ if f$search("[.src.icon]clock.obj") .nes. "" then delete [.src.icon]clock.obj;* -$ if f$search("[.src.icon]warning.obj") .nes. "" then delete [.src.icon]warning.obj;* -$ if f$search("[.src.icon]directory.obj") .nes. "" then delete [.src.icon]directory.obj;* -$ if f$search("[.src.icon]file.obj") .nes. "" then delete [.src.icon]file.obj;* -$ if f$search("[.src.icon]back.obj") .nes. "" then delete [.src.icon]back.obj;* -$ if f$search("[.src.icon]down.obj") .nes. "" then delete [.src.icon]down.obj;* -$ if f$search("[.src.icon]news.obj") .nes. "" then delete [.src.icon]news.obj;* -$ if f$search("[.src.icon]error.obj") .nes. "" then delete [.src.icon]error.obj;* -$ if f$search("[.src.icon]note.obj") .nes. "" then delete [.src.icon]note.obj;* -$ if f$search("[.src.icon]search.obj") .nes. "" then delete [.src.icon]search.obj;* -$ if f$search("[.src.icon]up.obj") .nes. "" then delete [.src.icon]up.obj;* -$ if f$search("[.src.abstract]time.obj") .nes. "" then delete [.src.abstract]time.obj;* -$ if f$search("[.src.abstract]directory.obj") .nes. "" then delete [.src.abstract]directory.obj;* -$ if f$search("[.src.abstract]dynamic.obj") .nes. "" then delete [.src.abstract]dynamic.obj;* -$ if f$search("[.external]stb_ds.obj") .nes. "" then delete [.external]stb_ds.obj;* -$ if f$search("[.src.backend]x11.obj") .nes. "" then delete [.src.backend]x11.obj;* -$ if f$search("[.src]MwSHR.exe") .nes. "" then delete [.src]MwSHR.exe;*