diff --git a/.gitignore b/.gitignore index 4e56495..58b172a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ compile_flags.txt .DS_Store /vms /BorMakefile +*.err +*.zip *.pef *.dsk diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 0000000..83daed8 --- /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 2f6d830..5441692 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,12 +35,18 @@ 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 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() @@ -69,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() @@ -132,10 +144,10 @@ if(MW_USE_FREETYPE2) if(Freetype_FOUND) message(STATUS "FreeType2 found") target_compile_definitions( - Mw - PRIVATE - USE_FREETYPE2 - ) + Mw + PRIVATE + USE_FREETYPE2 + ) list(APPEND INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS}) list(APPEND LIBRARY_DIRS ${FREETYPE_LIBRARY_DIRS}) @@ -144,6 +156,15 @@ if(MW_USE_FREETYPE2) 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( @@ -296,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 @@ -307,12 +329,14 @@ 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 @@ -336,6 +360,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") -framework Cocoa ) elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") + target_sources( Mw PRIVATE @@ -354,6 +379,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") CLASSIC_MAC_OS ) else() + find_package(PkgConfig) find_package(X11) pkg_check_modules(DBUS dbus-1) @@ -386,23 +412,26 @@ else() 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() -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 - ) + +if(UNIX) + list(APPEND LIBRARIES m) endif() -list(APPEND LIBRARIES m) - - target_include_directories( Mw PRIVATE @@ -437,11 +466,14 @@ 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( @@ -457,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/NTMakefile b/NTMakefile index b4943e7..63a4a2c 100644 --- a/NTMakefile +++ b/NTMakefile @@ -1,7 +1,7 @@ CC = cl /TC /c /nologo LD = link /nologo -MW_CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /D_MILSKO_BUILD /DUSE_GDI /DUSE_STB_TRUETYPE /DUSE_STB_IMAGE /DSTBI_NO_SIMD +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 = @@ -71,8 +71,10 @@ 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 @@ -318,8 +320,8 @@ 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\stbtt.obj src\text\text.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\stbtt.obj src\text\text.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 user32.lib advapi32.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\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: diff --git a/README.txt b/README.txt index fbf3732..0f57f90 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version 1.3) +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. diff --git a/WatMakefile b/WatMakefile index bd32d9b..4533f3c 100644 --- a/WatMakefile +++ b/WatMakefile @@ -1,7 +1,7 @@ CC = wcc386 -bt=nt -q LD = wlink option quiet -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD +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 @@ -70,8 +70,10 @@ 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 @@ -317,8 +319,8 @@ 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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 user32.lib library advapi32.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/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 @@ -444,10 +446,14 @@ src/text/font/ttf.obj: src/text/font/ttf.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c src/text/ft2.obj: src/text/ft2.c $(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) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c src/text/text.obj: src/text/text.c $(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) $(MW_CFLAGS) -fo=$@ src/unicode.c src/widget/box.obj: src/widget/box.c diff --git a/configure b/configure index 0192a22..44db66d 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 =~ /^--.+$/) { } @@ -39,14 +44,12 @@ 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); param_set("shared", 1); param_set("static", 1); param_set("examples", 1); -param_set("dbus", 1); # (option that only makes sense on x11) param_set("allow-sloppy-focus", 0); @@ -56,7 +59,8 @@ my %features = ( "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", @@ -69,7 +73,7 @@ my %features = ( ); my @features_keys = ( "1classic-theme", "1stb-image", - "1stb-truetype", "1freetype2", + "1stb-truetype", "1freetype2", "1gdi-text", "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", "1shared", "1static", @@ -78,7 +82,10 @@ my @features_keys = ( ); sub def_platform { - if($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Windows" and $target ne "Haiku") { + 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 { @@ -87,13 +94,20 @@ sub def_platform { } 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) { diff --git a/examples/vkdemos/CMakeLists.txt b/examples/vkdemos/CMakeLists.txt index 41f832c..9f37e0f 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 2d03030..9060a97 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 diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 54f1b89..6647672 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -205,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 { @@ -315,6 +316,12 @@ 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 @@ -339,18 +346,29 @@ MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); 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/Wayland.h b/include/Mw/LowLevel/Wayland.h index 1de48b3..ccd1f2f 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -320,6 +320,7 @@ struct _MwLLWayland { MwRect clipping_rect; MwBool no; + MwBool changing; MwBool detatching; MwPoint detach_point; diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 0415b4c..4c98b24 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -25,6 +25,7 @@ #ifdef _MILSKO #include +#include #ifndef GWLP_USERDATA #define GWLP_USERDATA GWL_USERDATA #define GWLP_WNDPROC GWL_WNDPROC diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index f7b4b49..9860990 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index b95fe93..6ad4e46 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -53,6 +53,7 @@ #define MwNcolumnSpan "IcolumnSpan" #define MwNrowSpan "IrowSpan" #define MwNdisabled "Idisabled" +#define MwNacceptsDnD "IacceptsDnD" #define MwNtitle "Stitle" #define MwNtext "Stext" @@ -98,5 +99,6 @@ #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 0000000..eea90c9 --- /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 b31c4b4..ad072a3 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -31,6 +31,7 @@ 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 @@ -116,6 +117,7 @@ struct _MwWidget { int top_step; MwWidget* draw_queue; MwWidget* resize_queue; + MwWidget* monitored_entries; int berserk; long last_tick; @@ -137,6 +139,8 @@ struct _MwEntry { int cursor; int right; int length; + int active; + int cursor_blink_timer; MwPoint mouse; }; @@ -247,6 +251,11 @@ struct _MwMouse { int button; }; +struct _MwTTFInfo { + char* family; + int weight; +}; + struct _MwClass { MwHandlerWithStatus create; MwHandler destroy; @@ -265,7 +274,7 @@ struct _MwClass { MwHandlerChildrenProp children_prop_change; MwHandlerClipboardReceived clipboard; MwHandlerProps props_change; - void* reserved1; + MwHandler drag_and_drop; void* reserved2; void* reserved3; }; diff --git a/include/Mw/Version.h b/include/Mw/Version.h index 5fb57f6..9821dc6 100644 --- a/include/Mw/Version.h +++ b/include/Mw/Version.h @@ -23,7 +23,7 @@ /*! * @brief Version in string */ -#define MwVERSION "1.3" +#define MwVERSION "1.4" /*! * @brief Version in string diff --git a/include/Mw/Widget/Window.h b/include/Mw/Widget/Window.h index 24b7153..6a98b68 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/pl/ostype/Windows.pl b/pl/ostype/Windows.pl index 29bdc98..e2ed1ab 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 bb6fa25..89f13e9 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -66,7 +66,8 @@ 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"); + scan_wayland_protocol_from_file("wlr-layer-shell", + "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; } @@ -134,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"); } diff --git a/pl/utils.pl b/pl/utils.pl index 23e16f0..504e8dc 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -125,21 +125,19 @@ sub scan_wayland_protocol { } } - sub scan_wayland_protocol_from_file { - my $proto = $_[0]; - my $file = $_[1]; + 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}" + "wayland-scanner private-code ./resource/wayland/${file} ${proto_c}" ) != 0 ) { print( -"^ Error on getting private code for ./resource/wayland/${file}\n" - ); + "^ Error on getting private code for ./resource/wayland/${file}\n"); } else { new_object($proto_c); @@ -151,12 +149,11 @@ sub scan_wayland_protocol_from_file { ) { print( -"^ Error on getting client header for ./resource/wayland/${file}\n" + "^ Error on getting client header for ./resource/wayland/${file}\n" ); } } - our %params = (); sub param_set { diff --git a/resource/milsko.pc.in b/resource/milsko.pc.in new file mode 100644 index 0000000..9cdc61e --- /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/src/abstract/charset.c b/src/abstract/charset.c index 47cc9a2..3bd7625 100644 --- a/src/abstract/charset.c +++ b/src/abstract/charset.c @@ -64,7 +64,7 @@ char* MwUTF8ToACP(const char* input) { return MwStringDuplicate(input); } - wout = malloc(wbytes); + wout = malloc(wbytes + sizeof(wchar_t)); len = wbytes / sizeof(wchar_t); memset(wout, 0, wbytes); diff --git a/src/abstract/directory.c b/src/abstract/directory.c index ac5a382..ddf10e1 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/time.c b/src/abstract/time.c index d1ddb83..892cd32 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) { diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 7b92d00..65380fb 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -212,8 +212,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -255,11 +255,12 @@ static MwBool MwLLDoModernImpl(MwLL handle) { } 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; + 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 f84247f..0deffb4 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -52,8 +52,9 @@ MwLLSetClipboard = MwLLSetClipboardImpl; \ MwLLGetClipboard = MwLLGetClipboardImpl; \ \ - MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ - MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ + MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ + MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ + MwLLSetupDragAndDrop = MwLLSetupDragAndDropImpl; \ \ MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ MwLLDoModern = MwLLDoModernImpl; \ diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index fb2549e..f063551 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); @@ -132,9 +132,23 @@ static void MwLLNextEventImpl(MwLL handle) { switch(event.what) { case updateEvt: { - } - // MwLLDispatch(handle, draw, NULL); - break; + /* + 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: @@ -333,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); } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index e07eb64..85b8b5b 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1146,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); } diff --git a/src/backend/gdi.c b/src/backend/gdi.c index bbab256..eace1d3 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,8 +12,14 @@ 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; @@ -67,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; @@ -98,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); @@ -113,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); @@ -127,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); @@ -141,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); @@ -169,19 +218,37 @@ 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; @@ -193,24 +260,61 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { if(msg == WM_SYSCHAR) n |= MwKEY_ALT_FLAG; if((0x20 <= n && n <= 0x7f) || (n & MwKEY_FLAG)) MwLLDispatch(u->ll, key, &n); - } else if(msg == WM_SETFOCUS) { + 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 = MwKEY_LEFT; - if(wp == VK_RIGHT) n = MwKEY_RIGHT; - if(wp == VK_UP) n = MwKEY_UP; - if(wp == VK_DOWN) n = MwKEY_DOWN; - if(wp == VK_RETURN) n = MwKEY_ENTER; - if(wp == VK_BACK) n = MwKEY_BACKSPACE; - if(wp == VK_ESCAPE) n = MwKEY_ESCAPE; - if(wp == VK_LSHIFT) n = MwKEY_LEFTSHIFT; - if(wp == VK_RSHIFT) n = MwKEY_RIGHTSHIFT; - if(wp == VK_MENU) n = MwKEY_ALT; - if(wp == VK_CONTROL) n = MwKEY_CONTROL; + 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 |= MwKEY_ALT_FLAG; @@ -222,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; @@ -253,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; } @@ -277,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; @@ -362,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; @@ -396,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); @@ -404,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; @@ -413,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; @@ -470,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(); @@ -490,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); + } } } @@ -502,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; @@ -542,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++) { @@ -793,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); @@ -905,6 +1088,10 @@ static void MwLLClipImpl(MwLL handle, MwRect* rect) { } } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + wsymtbl.DragAcceptFiles(handle->gdi.hWnd, TRUE); +} + static int MwLLGDICallInitImpl(void) { void* ntdll; @@ -920,6 +1107,28 @@ static int MwLLGDICallInitImpl(void) { 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 index 8c4f8bf..2c796d6 100644 --- a/src/backend/haiku.cc +++ b/src/backend/haiku.cc @@ -879,6 +879,10 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { delete screen; } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 278b453..839e9ac 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -177,6 +177,11 @@ static void xdg_toplevel_configure(void* data, } } + 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; @@ -451,6 +456,9 @@ static void popup_configure(void* data, 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; @@ -600,6 +608,9 @@ static void layer_shell_configure(void* data, 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; @@ -1106,14 +1117,14 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } /* 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) { + 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; } @@ -1593,6 +1604,7 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { p = p->wayland.parent; } + handle->wayland.changing = MwTRUE; handle->wayland.detatching = MwTRUE; handle->wayland.detach_point = *point; handle->wayland.detach_point.x += x; @@ -1626,6 +1638,9 @@ static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int 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); } } @@ -1742,6 +1757,8 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { } else { handle->wayland.type_to_be = MwLL_WAYLAND_POPUP; } + + handle->wayland.changing = MwTRUE; } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { @@ -1762,6 +1779,10 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { rect->height = handle->wayland.mh; } +static void MwLLSetupDragAndDropImpl(MwLL handle) { + (void)handle; +} + static void MwLLBeginStateChangeImpl(MwLL handle) { (void)handle; /* no-op */ @@ -1772,6 +1793,11 @@ static void MwLLEndStateChangeImpl(MwLL handle) { 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; diff --git a/src/backend/x11.c b/src/backend/x11.c index 79ce429..cc4d22b 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1361,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); } diff --git a/src/core.c b/src/core.c index 0366443..c27b1a6 100644 --- a/src/core.c +++ b/src/core.c @@ -145,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; @@ -192,6 +193,13 @@ static void llclipboardhandler(MwLL handle, void* 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 @@ -225,14 +233,19 @@ static void lldarkthemehandler(MwLL handle, void* data) { 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; } @@ -257,28 +270,30 @@ static MwWidget MwCreateWidget_Internal(MwClass widget_class, const char* name, h->opaque = NULL; h->user = NULL; - h->top_step = 0; - h->draw_queue = NULL; - h->resize_queue = 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); if(parent == NULL) h->top_step = 1; 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); @@ -310,12 +325,21 @@ static MwWidget MwCreateWidget_Internal(MwClass widget_class, const char* name, 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 { @@ -404,7 +428,7 @@ void MwFreeWidget(MwWidget handle) { } } - free(handle->name); + if(handle->name) free(handle->name); if(handle->lowlevel != NULL) MwLLDestroy(handle->lowlevel); @@ -515,7 +539,7 @@ static void MwAfterStep(MwWidget handle) { } #endif - if(arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= MwWaitMS) { + 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); @@ -549,6 +573,7 @@ int MwStep(MwWidget handle) { MwFreeWidget(handle); return 1; } + return 0; } @@ -557,7 +582,7 @@ int MwPending(MwWidget handle) { for(i = 0; i < arrlen(handle->children); i++) { if(MwPending(handle->children[i])) return 1; } - return (arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= MwWaitMS) || (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) { @@ -645,6 +670,10 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { 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) { @@ -732,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); @@ -783,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; @@ -799,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); @@ -1060,6 +1089,19 @@ int MwLibraryInit(void) { 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; @@ -1127,8 +1169,10 @@ void MwReparent(MwWidget handle, MwWidget new_parent) { if(new_parent == NULL) { handle->top_step = 1; + arrput(handle->tick_list, handle); } else { handle->top_step = 0; + arrfree(handle->tick_list); } MwForceRender(handle); diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 926fddc..95fc283 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++; diff --git a/src/dialog/messagebox.c b/src/dialog/messagebox.c index f7084ab..ff72bc8 100644 --- a/src/dialog/messagebox.c +++ b/src/dialog/messagebox.c @@ -68,9 +68,9 @@ 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); diff --git a/src/draw.c b/src/draw.c index ce86d90..2314c02 100644 --- a/src/draw.c +++ b/src/draw.c @@ -43,9 +43,9 @@ static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); if(c != NULL) { - rgb->common.red = rgb->common.red + (c->common.red - rgb->common.red) * 0.5; - rgb->common.green = rgb->common.green + (c->common.green - rgb->common.green) * 0.5; - rgb->common.blue = rgb->common.blue + (c->common.blue - rgb->common.blue) * 0.5; + 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); @@ -124,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; @@ -138,7 +141,7 @@ 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; @@ -458,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; @@ -470,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; @@ -485,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; @@ -516,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; @@ -532,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; @@ -568,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; @@ -583,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; @@ -614,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; @@ -626,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; @@ -639,14 +642,14 @@ 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); @@ -830,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; } } @@ -868,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++) { @@ -905,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]; @@ -942,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 bc9e55b..2fe1535 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,8 @@ void (*MwLLGetClipboard)(MwLL, int clipboard_type) = NULL; void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; - -void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; +void (*MwLLSetupDragAndDrop)(MwLL handle) = NULL; +void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; MwBool (*MwLLDoModern)(MwLL handle) = NULL; diff --git a/src/string.c b/src/string.c index f56b9ac..c894b9a 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 7945831..8526c1b 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 14b2599..2ec91c7 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 8332c4a..7a89f94 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 c5d03b9..7eeea07 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 b83b06c..13e8208 100644 --- a/src/text/ft2.c +++ b/src/text/ft2.c @@ -159,7 +159,7 @@ 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__ diff --git a/src/text/gdi.c b/src/text/gdi.c new file mode 100644 index 0000000..97e6870 --- /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/text.c b/src/text/text.c index 786089b..2bb89b6 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 @@ -87,9 +88,10 @@ void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, if(c != NULL) { fadedColor = MwLLAllocColor(handle->lowlevel, color->common.red, color->common.blue, color->common.green); - fadedColor->common.red = fadedColor->common.red + (c->common.red - fadedColor->common.red) * 0.5; - fadedColor->common.green = fadedColor->common.green + (c->common.green - fadedColor->common.green) * 0.5; - fadedColor->common.blue = fadedColor->common.blue + (c->common.blue - fadedColor->common.blue) * 0.5; + 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); } @@ -108,6 +110,11 @@ void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, 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; @@ -175,6 +182,11 @@ int MwTextWidth(MwWidget handle, MwFLFont ttf, const char* text) { 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; @@ -220,6 +232,8 @@ int MwTextHeight(MwWidget handle, MwFLFont ttf, const char* text) { #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; } @@ -246,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; @@ -297,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 0000000..4f2c819 --- /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/button.c b/src/widget/button.c index 51337e6..7f1da57 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -55,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; @@ -68,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 { diff --git a/src/widget/entry.c b/src/widget/entry.c index 8580768..9d423bf 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -1,12 +1,19 @@ #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); @@ -16,9 +23,27 @@ static int wcreate(MwWidget handle) { } 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; @@ -71,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 + MwDefaultBorderWidth(handle); - 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); } @@ -148,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); @@ -187,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, /* props_change */ + 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/label.c b/src/widget/label.c index 5a165e7..a0be9ca 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -336,7 +336,7 @@ static void draw_normal(MwWidget handle) { r.width -= MwGetInteger(handle, MwNleftPadding); -#if 0 +#if 1 if(align == MwALIGNMENT_CENTER) { p.x = r.width / 2; } else if(align == MwALIGNMENT_BEGINNING) { @@ -353,11 +353,11 @@ static void draw_normal(MwWidget handle) { p.x += 1; p.y += 1; - MwDrawText(handle, NULL, &p, str, MwALIGNMENT_BEGINNING, shadow); + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, shadow); p.x -= 1; p.y -= 1; - MwDrawText(handle, NULL, &p, str, MwALIGNMENT_BEGINNING, text); + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, text); MwLLFreeColor(shadow); MwLLFreeColor(text); diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 32be887..cc17362 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -203,11 +203,16 @@ static void frame_draw(MwWidget handle) { int seek = 0; int l = 0; char* old = str; + int sz = strlen(old) + 5; if(ind < 0) ind = 0; - str = malloc(strlen(old) + 5); + 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) { @@ -317,6 +322,11 @@ static void resize(MwWidget handle, int no_resize) { 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; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index db839ea..30a1cee 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -682,4 +682,4 @@ MWDECL MwClass MwOpenGLClass; MwClass MwOpenGLClass = NULL; #endif -#endif \ No newline at end of file +#endif diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index 3185c23..8adf028 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -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); diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 346f818..3bd2fdf 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; diff --git a/src/widget/viewport.c b/src/widget/viewport.c index 2541b65..803c424 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -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, diff --git a/src/widget/window.c b/src/widget/window.c index 7178d3f..3d0afe2 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 */ diff --git a/tools/color.pl b/tools/color.pl index 0e7c6bb..eca072c 100755 --- a/tools/color.pl +++ b/tools/color.pl @@ -28,7 +28,9 @@ 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 + "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"); @@ -36,10 +38,11 @@ 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 " add_color(\"$4\", $1, $2, $3);\n"); + print(OUT " add_color(\"$4\", $1, $2, $3);\n"); } } print(OUT "}\n"); diff --git a/tools/genmk.pl b/tools/genmk.pl index 6977df2..689e09e 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -116,7 +116,7 @@ sub generate { print(OUT "LD = $link\n"); print(OUT "\n"); print(OUT -"MW_CFLAGS = ${cdll} ${inc}include ${inc}external${dir}libz${dir}include ${def}_MILSKO ${def}_MILSKO_BUILD ${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 "MW_LDFLAGS = $dll\n"); print(OUT "EXE_CFLAGS = ${inc}include\n"); @@ -190,7 +190,7 @@ sub generate { print(OUT "src${dir}Mw.dll: " . cobjs($dir) . "\n"); 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");