diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 8b8f6f2..fbe812b 100755 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -13,9 +13,26 @@ "compilerPath": "/usr/bin/clang++", "cStandard": "c17", "cppStandard": "c++20", - "intelliSenseMode": "linux-clang-x64", - "compileCommands": "${workspaceFolder}/Debug/compile_commands.json" + "intelliSenseMode": "linux-clang-x64" + //"compileCommands": "${workspaceFolder}/compile_commands.json" + }, + { + "name": "Windows", + "includePath": [ + "${default}", + "${workspaceRoot}/src/vendor/GLAD", + "${workspaceRoot}/src/vendor", + "${workspaceRoot}/src/ostd", + "${workspaceRoot}/src" + ], + "defines": [], + "compilerPath": "C:\\msys64\\ucrt64\\bin\\clang++", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "linux-clang-x64" + //"compileCommands": "${workspaceFolder}/compile_commands.json" } ], "version": 4 -} \ No newline at end of file +} + diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d1a83..9584b99 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ #Setup #----------------------------------------------------------------------------------------- set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER "clang") cmake_minimum_required(VERSION 3.18) project(${PROJ_NAME} LANGUAGES C CXX) set(CMAKE_BUILD_TYPE Debug) @@ -27,33 +28,18 @@ message("** Building ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}") #Sources #----------------------------------------------------------------------------------------- -list(APPEND OSTD_VENDOR_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/image.cpp -) -list(APPEND OGFX_VENDOR_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD/glad.c -) - list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src/ostd ${CMAKE_CURRENT_LIST_DIR}/src/vendor ${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD ) - list(APPEND TEST_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/test/main.cpp ${CMAKE_CURRENT_LIST_DIR}/src/test/TestApp2D.cpp ${CMAKE_CURRENT_LIST_DIR}/src/test/TestApp3D.cpp ${CMAKE_CURRENT_LIST_DIR}/src/test/TetrisApp.cpp ) -list(APPEND OSH_SOURCE_FILES - ${CMAKE_CURRENT_LIST_DIR}/src/osh/commandShell.cpp -) -list(APPEND OXGE_SOURCE_FILES - ${CMAKE_CURRENT_LIST_DIR}/src/oxge/iso/Engine.cpp -) list(APPEND OGFX_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/BitmapFont.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/BlendRenderer.cpp @@ -73,8 +59,8 @@ list(APPEND OGFX_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Texture.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Window.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Widgets.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/DebugTools.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD/glad.c ) list(APPEND OSTD_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ostd/BaseObject.cpp @@ -99,24 +85,8 @@ list(APPEND OSTD_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ostd/StringEditor.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Utils.cpp ) - -if (WIN32) - list(APPEND OSTD_VENDOR_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip_win.cpp - ) -endif (WIN32) -if (UNIX) - list(APPEND OSTD_VENDOR_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip_x11.cpp - ) -endif (UNIX) - -list(APPEND OSTD_SOURCE_FILES ${OSTD_VENDOR_SOURCES}) -list(APPEND OGFX_SOURCE_FILES ${OGFX_VENDOR_SOURCES}) #----------------------------------------------------------------------------------------- - - #Targets #----------------------------------------------------------------------------------------- add_library(${OMNIA_STD_LIB} SHARED ${OSTD_SOURCE_FILES}) @@ -140,8 +110,6 @@ endif (UNIX) target_link_libraries(${OMNIA_GFX_LIB} PUBLIC sfml-system sfml-window sfml-graphics) #----------------------------------------------------------------------------------------- - - #Linking Targets #----------------------------------------------------------------------------------------- target_link_libraries(${OMNIA_GFX_LIB} PUBLIC ${OMNIA_STD_LIB}) @@ -150,8 +118,6 @@ target_link_libraries(${TEST_TARGET} PUBLIC ${OMNIA_STD_LIB}) target_link_libraries(${TEST_TARGET} PUBLIC ${OMNIA_GFX_LIB}) #----------------------------------------------------------------------------------------- - - #BuildNumber Target #----------------------------------------------------------------------------------------- if (WIN32) @@ -174,8 +140,7 @@ add_custom_target( #----------------------------------------------------------------------------------------- - -#Install +#Finalize #----------------------------------------------------------------------------------------- #TODO: Change TEST_TARGET to last lib built, for release config add_custom_command(TARGET ${TEST_TARGET} POST_BUILD @@ -183,12 +148,6 @@ add_custom_command(TARGET ${TEST_TARGET} POST_BUILD ${CMAKE_SOURCE_DIR}/extra/ $ VERBATIM ) - -set(CMAKE_INSTALL_MESSAGE NEVER) -install(TARGETS ${OMNIA_STD_LIB} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build/bin) -install(TARGETS ${OMNIA_GFX_LIB} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build/bin) -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/licences DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build) - add_custom_target(FinalMessage ALL ${CMAKE_COMMAND} -E cmake_echo_color --cyan "[100%] Built ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}") add_dependencies(FinalMessage ${TEST_TARGET}) #----------------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ed4f9a --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# OmniaFramework + +Compile instructions on Windows + +**Step 1:** +download MSYS2 from https://www.msys2.org/ and install it + +**Step 2:** +run MSYS2, and in the terminal run: +``` +pacman -Syuu +pacman -S --needed base-devel mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-gdb mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-sfml mingw-w64-ucrt-x86_64-make +``` + +**Step 3:** +open a UCRT64/MSYS2 command prompt inside the root directory of the project + +**Step 4:** +execute this command: +``` +./compile +``` diff --git a/compile b/compile index 1892174..b7df819 100755 --- a/compile +++ b/compile @@ -1,14 +1,15 @@ #/bin/bash -rm -r Build rm -r bin -#export CXX=/usr/bin/clang++ -cmake -B bin -S ./ -cd bin -make install -cd .. -if [ $? -eq 0 ]; then - printf "Installing includes...\n" - python ./tools/create_includes.py - printf "Done!\n" -fi + +if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then + cmake -B bin -S ./ + cd bin + make + cd .. +elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then + cmake -B bin -S ./ -G "MinGW Makefiles" + cd bin + mingw32-make.exe + cd .. +fi \ No newline at end of file diff --git a/src/ostd/File.cpp b/src/ostd/File.cpp index a7047cf..06817ab 100755 --- a/src/ostd/File.cpp +++ b/src/ostd/File.cpp @@ -24,10 +24,10 @@ namespace ostd if (!file.is_open()) return *this; m_buffer = { std::istreambuf_iterator(file), std::istreambuf_iterator() }; - m_extension = filePath.extension(); - m_fullPath = filePath; - m_fullName = filePath.filename(); - m_name = filePath.stem(); + m_extension = filePath.extension().string(); + m_fullPath = filePath.string(); + m_fullName = filePath.filename().string(); + m_name = filePath.stem().string(); StringEditor pathEditor(m_fullPath); if (pathEditor.contains('/')) m_directoryPath = pathEditor.substr(0, pathEditor.lastIndexOf('/')); diff --git a/src/ostd/Utils.cpp b/src/ostd/Utils.cpp index 91a83c0..856496e 100755 --- a/src/ostd/Utils.cpp +++ b/src/ostd/Utils.cpp @@ -1,7 +1,7 @@ #include "Utils.hpp" #include "Defines.hpp" #include -#include +//#include #include #include #include @@ -682,7 +682,7 @@ namespace ostd return std::chrono::duration_cast (std::chrono::system_clock::now().time_since_epoch()).count() - Utils::s_startTime_ms; } - bool Utils::setClipboardText(String text) + /*bool Utils::setClipboardText(String text) { return clip::set_text(text); } @@ -692,7 +692,7 @@ namespace ostd String text = ""; if (!clip::get_text(text)) return ""; return text; - } + }*/ float Utils::map_value(float input, float input_start, float input_end, float output_start, float output_end) { diff --git a/src/ostd/Utils.hpp b/src/ostd/Utils.hpp index 0c96091..ef79e7b 100755 --- a/src/ostd/Utils.hpp +++ b/src/ostd/Utils.hpp @@ -150,8 +150,9 @@ namespace ostd static String duplicateChar(unsigned char c, uint16_t count); static void sleep(uint32_t __time, eTimeUnits __unit = eTimeUnits::Milliseconds); static uint64_t getRunningTime_ms(void); - static bool setClipboardText(String text); - static String getClipboardText(void); + //TODO: Doesn't work on Windows + //static bool setClipboardText(String text); + //static String getClipboardText(void); static float map_value(float input, float input_start, float input_end, float output_start, float output_end); static bool loadFileFromHppResource(String output_file_path, const char* resource_buffer, unsigned int size); static void printByteStream(const ByteStream& data, StreamIndex start, uint8_t line_len, uint16_t n_rows, IOutputHandler& out, int32_t addrHighlight = -1, uint32_t highlightRange = 1, const String& title = ""); diff --git a/src/vendor/clip/clip.cpp b/src/vendor/clip/clip.cpp deleted file mode 100755 index bd221fc..0000000 --- a/src/vendor/clip/clip.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// Clip Library -// Copyright (c) 2015-2018 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#include "clip.h" -#include "clip_lock_impl.h" - -#include -#include - -namespace clip { - -namespace { - -void default_error_handler(ErrorCode code) { - static const char* err[] = { - "Cannot lock clipboard", - "Image format is not supported" - }; - throw std::runtime_error(err[static_cast(code)]); -} - -} // anonymous namespace - -error_handler g_error_handler = default_error_handler; - -lock::lock(void* native_window_handle) - : p(new impl(native_window_handle)) { -} - -lock::~lock() = default; - -bool lock::locked() const { - return p->locked(); -} - -bool lock::clear() { - return p->clear(); -} - -bool lock::is_convertible(format f) const { - return p->is_convertible(f); -} - -bool lock::set_data(format f, const char* buf, size_t length) { - return p->set_data(f, buf, length); -} - -bool lock::get_data(format f, char* buf, size_t len) const { - return p->get_data(f, buf, len); -} - -size_t lock::get_data_length(format f) const { - return p->get_data_length(f); -} - -bool lock::set_image(const image& img) { - return p->set_image(img); -} - -bool lock::get_image(image& img) const { - return p->get_image(img); -} - -bool lock::get_image_spec(image_spec& spec) const { - return p->get_image_spec(spec); -} - -format empty_format() { return 0; } -format text_format() { return 1; } -format image_format() { return 2; } - -bool has(format f) { - lock l; - if (l.locked()) - return l.is_convertible(f); - else - return false; -} - -bool clear() { - lock l; - if (l.locked()) - return l.clear(); - else - return false; -} - -bool set_text(const std::string& value) { - lock l; - if (l.locked()) { - l.clear(); - return l.set_data(text_format(), value.c_str(), value.size()); - } - else - return false; -} - -bool get_text(std::string& value) { - lock l; - if (!l.locked()) - return false; - - format f = text_format(); - if (!l.is_convertible(f)) - return false; - - size_t len = l.get_data_length(f); - if (len > 0) { - std::vector buf(len); - l.get_data(f, &buf[0], len); - value = &buf[0]; - return true; - } - else { - value.clear(); - return true; - } -} - -bool set_image(const image& img) { - lock l; - if (l.locked()) { - l.clear(); - return l.set_image(img); - } - else - return false; -} - -bool get_image(image& img) { - lock l; - if (!l.locked()) - return false; - - format f = image_format(); - if (!l.is_convertible(f)) - return false; - - return l.get_image(img); -} - -bool get_image_spec(image_spec& spec) { - lock l; - if (!l.locked()) - return false; - - format f = image_format(); - if (!l.is_convertible(f)) - return false; - - return l.get_image_spec(spec); -} - -void set_error_handler(error_handler handler) { - g_error_handler = handler; -} - -error_handler get_error_handler() { - return g_error_handler; -} - -#ifdef HAVE_XCB_XLIB_H -static int g_x11_timeout = 1000; -void set_x11_wait_timeout(int msecs) { g_x11_timeout = msecs; } -int get_x11_wait_timeout() { return g_x11_timeout; } -#else -void set_x11_wait_timeout(int) { } -int get_x11_wait_timeout() { return 1000; } -#endif - -} // namespace clip diff --git a/src/vendor/clip/clip.h b/src/vendor/clip/clip.h deleted file mode 100755 index bf3c9fd..0000000 --- a/src/vendor/clip/clip.h +++ /dev/null @@ -1,180 +0,0 @@ -// Clip Library -// Copyright (c) 2015-2022 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifndef CLIP_H_INCLUDED -#define CLIP_H_INCLUDED -#pragma once - -#include -#include -#include - -namespace clip { - - // ====================================================================== - // Low-level API to lock the clipboard/pasteboard and modify it - // ====================================================================== - - // Clipboard format identifier. - typedef size_t format; - - class image; - struct image_spec; - - class lock { - public: - // You can give your current HWND as the "native_window_handle." - // Windows clipboard functions use this handle to open/close - // (lock/unlock) the clipboard. From the MSDN documentation we - // need this handler so SetClipboardData() doesn't fail after a - // EmptyClipboard() call. Anyway it looks to work just fine if we - // call OpenClipboard() with a null HWND. - lock(void* native_window_handle = nullptr); - ~lock(); - - // Returns true if we've locked the clipboard successfully in - // lock() constructor. - bool locked() const; - - // Clears the clipboard content. If you don't clear the content, - // previous clipboard content (in unknown formats) could persist - // after the unlock. - bool clear(); - - // Returns true if the clipboard can be converted to the given - // format. - bool is_convertible(format f) const; - bool set_data(format f, const char* buf, size_t len); - bool get_data(format f, char* buf, size_t len) const; - size_t get_data_length(format f) const; - - // For images - bool set_image(const image& image); - bool get_image(image& image) const; - bool get_image_spec(image_spec& spec) const; - - private: - class impl; - std::unique_ptr p; - }; - - format register_format(const std::string& name); - - // This format is when the clipboard has no content. - format empty_format(); - - // When the clipboard has UTF8 text. - format text_format(); - - // When the clipboard has an image. - format image_format(); - - // Returns true if the clipboard has content of the given type. - bool has(format f); - - // Clears the clipboard content. - bool clear(); - - // ====================================================================== - // Error handling - // ====================================================================== - - enum class ErrorCode { - CannotLock, - ImageNotSupported, - }; - - typedef void (*error_handler)(ErrorCode code); - - void set_error_handler(error_handler f); - error_handler get_error_handler(); - - // ====================================================================== - // Text - // ====================================================================== - - // High-level API to put/get UTF8 text in/from the clipboard. These - // functions returns false in case of error. - bool set_text(const std::string& value); - bool get_text(std::string& value); - - // ====================================================================== - // Image - // ====================================================================== - - struct image_spec { - unsigned long width = 0; - unsigned long height = 0; - unsigned long bits_per_pixel = 0; - unsigned long bytes_per_row = 0; - unsigned long red_mask = 0; - unsigned long green_mask = 0; - unsigned long blue_mask = 0; - unsigned long alpha_mask = 0; - unsigned long red_shift = 0; - unsigned long green_shift = 0; - unsigned long blue_shift = 0; - unsigned long alpha_shift = 0; - - unsigned long required_data_size() const; - }; - - // The image data must contain straight RGB values - // (non-premultiplied by alpha). The image retrieved from the - // clipboard will be non-premultiplied too. Basically you will be - // always dealing with straight alpha images. - // - // Details: Windows expects premultiplied images on its clipboard - // content, so the library code make the proper conversion - // automatically. macOS handles straight alpha directly, so there is - // no conversion at all. Linux/X11 images are transferred in - // image/png format which are specified in straight alpha. - class image { - public: - image(); - image(const image_spec& spec); - image(const void* data, const image_spec& spec); - image(const image& image); - image(image&& image); - ~image(); - - image& operator=(const image& image); - image& operator=(image&& image); - - char* data() const { return m_data; } - const image_spec& spec() const { return m_spec; } - - bool is_valid() const { return m_data != nullptr; } - void reset(); - - private: - void copy_image(const image& image); - void move_image(image&& image); - - bool m_own_data; - char* m_data; - image_spec m_spec; - }; - - // High-level API to set/get an image in/from the clipboard. These - // functions returns false in case of error. - bool set_image(const image& img); - bool get_image(image& img); - bool get_image_spec(image_spec& spec); - - // ====================================================================== - // Platform-specific - // ====================================================================== - - // Only for X11: Sets the time (in milliseconds) that we must wait - // for the selection/clipboard owner to receive the content. This - // value is 1000 (one second) by default. - void set_x11_wait_timeout(int msecs); - int get_x11_wait_timeout(); - -} // namespace clip - -#endif // CLIP_H_INCLUDED diff --git a/src/vendor/clip/clip_common.h b/src/vendor/clip/clip_common.h deleted file mode 100755 index ebe0d72..0000000 --- a/src/vendor/clip/clip_common.h +++ /dev/null @@ -1,76 +0,0 @@ -// Clip Library -// Copyright (C) 2020 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifndef CLIP_COMMON_H_INCLUDED -#define CLIP_COMMON_H_INCLUDED -#pragma once - -namespace clip { -namespace details { - -inline void divide_rgb_by_alpha(image& img, - bool hasAlphaGreaterThanZero = false) { - const image_spec& spec = img.spec(); - - bool hasValidPremultipliedAlpha = true; - - for (unsigned long y=0; y> spec.red_shift ); - const int g = ((c & spec.green_mask) >> spec.green_shift); - const int b = ((c & spec.blue_mask ) >> spec.blue_shift ); - const int a = ((c & spec.alpha_mask) >> spec.alpha_shift); - - if (a > 0) - hasAlphaGreaterThanZero = true; - if (r > a || g > a || b > a) - hasValidPremultipliedAlpha = false; - } - } - - for (unsigned long y=0; y> spec.red_shift ); - int g = ((c & spec.green_mask) >> spec.green_shift); - int b = ((c & spec.blue_mask ) >> spec.blue_shift ); - int a = ((c & spec.alpha_mask) >> spec.alpha_shift); - - // If all alpha values = 0, we make the image opaque. - if (!hasAlphaGreaterThanZero) { - a = 255; - - // We cannot change the image spec (e.g. spec.alpha_mask=0) to - // make the image opaque, because the "spec" of the image is - // read-only. The image spec used by the client is the one - // returned by get_image_spec(). - } - // If there is alpha information and it's pre-multiplied alpha - else if (hasValidPremultipliedAlpha) { - if (a > 0) { - // Convert it to straight alpha - r = r * 255 / a; - g = g * 255 / a; - b = b * 255 / a; - } - } - - *dst = - (r << spec.red_shift ) | - (g << spec.green_shift) | - (b << spec.blue_shift ) | - (a << spec.alpha_shift); - } - } -} - -} // namespace details -} // namespace clip - -#endif // CLIP_H_INCLUDED diff --git a/src/vendor/clip/clip_lock_impl.h b/src/vendor/clip/clip_lock_impl.h deleted file mode 100755 index 3f08af7..0000000 --- a/src/vendor/clip/clip_lock_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -// Clip Library -// Copyright (c) 2015-2018 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifndef CLIP_LOCK_IMPL_H_INCLUDED -#define CLIP_LOCK_IMPL_H_INCLUDED - -namespace clip { - -class lock::impl { -public: - impl(void* native_window_handle); - ~impl(); - - bool locked() const { return m_locked; } - bool clear(); - bool is_convertible(format f) const; - bool set_data(format f, const char* buf, size_t len); - bool get_data(format f, char* buf, size_t len) const; - size_t get_data_length(format f) const; - bool set_image(const image& image); - bool get_image(image& image) const; - bool get_image_spec(image_spec& spec) const; - -private: - bool m_locked; -}; - -} // namespace clip - -#endif diff --git a/src/vendor/clip/clip_win.cpp b/src/vendor/clip/clip_win.cpp deleted file mode 100755 index 4fabb7e..0000000 --- a/src/vendor/clip/clip_win.cpp +++ /dev/null @@ -1,646 +0,0 @@ -// Clip Library -// Copyright (C) 2015-2020 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#include "clip.h" -#include "clip_common.h" -#include "clip_lock_impl.h" - -#include -#include -#include -#include -#include - -#include - -#include "clip_win_wic.h" - -#ifndef LCS_WINDOWS_COLOR_SPACE -#define LCS_WINDOWS_COLOR_SPACE 'Win ' -#endif - -#ifndef CF_DIBV5 -#define CF_DIBV5 17 -#endif - -namespace clip { - -namespace { - -// Data type used as header for custom formats to indicate the exact -// size of the user custom data. This is necessary because it looks -// like GlobalSize() might not return the exact size, but a greater -// value. -typedef uint64_t CustomSizeT; - -unsigned long get_shift_from_mask(unsigned long mask) { - unsigned long shift = 0; - for (shift=0; shiftbV5BitCount == 32 && - ((b5->bV5Compression == BI_RGB) || - (b5->bV5Compression == BI_BITFIELDS && - b5->bV5RedMask && b5->bV5GreenMask && - b5->bV5BlueMask && b5->bV5AlphaMask))) { - width = b5->bV5Width; - height = b5->bV5Height; - bit_count = b5->bV5BitCount; - compression = b5->bV5Compression; - if (compression == BI_BITFIELDS) { - red_mask = b5->bV5RedMask; - green_mask = b5->bV5GreenMask; - blue_mask = b5->bV5BlueMask; - alpha_mask = b5->bV5AlphaMask; - } - else { - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - alpha_mask = 0xff000000; - } - return; - } - } - - if (IsClipboardFormatAvailable(CF_DIB)) - bi = (BITMAPINFO*)GetClipboardData(CF_DIB); - if (!bi) - return; - - width = bi->bmiHeader.biWidth; - height = bi->bmiHeader.biHeight; - bit_count = bi->bmiHeader.biBitCount; - compression = bi->bmiHeader.biCompression; - - if (compression == BI_BITFIELDS) { - red_mask = *((uint32_t*)&bi->bmiColors[0]); - green_mask = *((uint32_t*)&bi->bmiColors[1]); - blue_mask = *((uint32_t*)&bi->bmiColors[2]); - if (bit_count == 32) - alpha_mask = 0xff000000; - } - else if (compression == BI_RGB) { - switch (bit_count) { - case 32: - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - alpha_mask = 0xff000000; - break; - case 24: - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - break; - case 16: - red_mask = 0x7c00; - green_mask = 0x03e0; - blue_mask = 0x001f; - break; - } - } - } - - bool is_valid() const { - return (b5 || bi); - } - - void fill_spec(image_spec& spec) { - spec.width = width; - spec.height = (height >= 0 ? height: -height); - // We convert indexed to 24bpp RGB images to match the OS X behavior - spec.bits_per_pixel = bit_count; - if (spec.bits_per_pixel <= 8) - spec.bits_per_pixel = 24; - spec.bytes_per_row = width*((spec.bits_per_pixel+7)/8); - spec.red_mask = red_mask; - spec.green_mask = green_mask; - spec.blue_mask = blue_mask; - spec.alpha_mask = alpha_mask; - - switch (spec.bits_per_pixel) { - - case 24: { - // We need one extra byte to avoid a crash updating the last - // pixel on last row using: - // - // *((uint32_t*)ptr) = pixel24bpp; - // - ++spec.bytes_per_row; - - // Align each row to 32bpp - int padding = (4-(spec.bytes_per_row&3))&3; - spec.bytes_per_row += padding; - break; - } - - case 16: { - int padding = (4-(spec.bytes_per_row&3))&3; - spec.bytes_per_row += padding; - break; - } - } - - unsigned long* masks = &spec.red_mask; - unsigned long* shifts = &spec.red_shift; - for (unsigned long* shift=shifts, *mask=masks; shift 0) { - int reqsize = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); - if (reqsize > 0) { - ++reqsize; - - Hglobal hglobal(sizeof(WCHAR)*reqsize); - LPWSTR lpstr = static_cast(GlobalLock(hglobal)); - MultiByteToWideChar(CP_UTF8, 0, buf, len, lpstr, reqsize); - GlobalUnlock(hglobal); - - result = (SetClipboardData(CF_UNICODETEXT, hglobal)) ? true: false; - if (result) - hglobal.release(); - } - } - } - else { - Hglobal hglobal(len+sizeof(CustomSizeT)); - if (hglobal) { - auto dst = (uint8_t*)GlobalLock(hglobal); - if (dst) { - *((CustomSizeT*)dst) = len; - memcpy(dst+sizeof(CustomSizeT), buf, len); - GlobalUnlock(hglobal); - result = (SetClipboardData(f, hglobal) ? true: false); - if (result) - hglobal.release(); - } - } - } - - return result; -} - -bool lock::impl::get_data(format f, char* buf, size_t len) const { - assert(buf); - - if (!buf || !is_convertible(f)) - return false; - - bool result = false; - - if (f == text_format()) { - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { - HGLOBAL hglobal = GetClipboardData(CF_UNICODETEXT); - if (hglobal) { - LPWSTR lpstr = static_cast(GlobalLock(hglobal)); - if (lpstr) { - size_t reqsize = - WideCharToMultiByte(CP_UTF8, 0, lpstr, -1, - nullptr, 0, nullptr, nullptr); - - assert(reqsize <= len); - if (reqsize <= len) { - WideCharToMultiByte(CP_UTF8, 0, lpstr, -1, - buf, reqsize, nullptr, nullptr); - result = true; - } - GlobalUnlock(hglobal); - } - } - } - else if (IsClipboardFormatAvailable(CF_TEXT)) { - HGLOBAL hglobal = GetClipboardData(CF_TEXT); - if (hglobal) { - LPSTR lpstr = static_cast(GlobalLock(hglobal)); - if (lpstr) { - // TODO check length - memcpy(buf, lpstr, len); - result = true; - GlobalUnlock(hglobal); - } - } - } - } - else { - if (IsClipboardFormatAvailable(f)) { - HGLOBAL hglobal = GetClipboardData(f); - if (hglobal) { - const SIZE_T total_size = GlobalSize(hglobal); - auto ptr = (const uint8_t*)GlobalLock(hglobal); - if (ptr) { - CustomSizeT reqsize = *((CustomSizeT*)ptr); - - // If the registered length of data in the first CustomSizeT - // number of bytes of the hglobal data is greater than the - // GlobalSize(hglobal), something is wrong, it should not - // happen. - assert(reqsize <= total_size); - if (reqsize > total_size) - reqsize = total_size - sizeof(CustomSizeT); - - if (reqsize <= len) { - memcpy(buf, ptr+sizeof(CustomSizeT), reqsize); - result = true; - } - GlobalUnlock(hglobal); - } - } - } - } - - return result; -} - -size_t lock::impl::get_data_length(format f) const { - size_t len = 0; - - if (f == text_format()) { - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { - HGLOBAL hglobal = GetClipboardData(CF_UNICODETEXT); - if (hglobal) { - LPWSTR lpstr = static_cast(GlobalLock(hglobal)); - if (lpstr) { - len = - WideCharToMultiByte(CP_UTF8, 0, lpstr, -1, - nullptr, 0, nullptr, nullptr); - GlobalUnlock(hglobal); - } - } - } - else if (IsClipboardFormatAvailable(CF_TEXT)) { - HGLOBAL hglobal = GetClipboardData(CF_TEXT); - if (hglobal) { - LPSTR lpstr = (LPSTR)GlobalLock(hglobal); - if (lpstr) { - len = strlen(lpstr) + 1; - GlobalUnlock(hglobal); - } - } - } - } - else if (f != empty_format()) { - if (IsClipboardFormatAvailable(f)) { - HGLOBAL hglobal = GetClipboardData(f); - if (hglobal) { - const SIZE_T total_size = GlobalSize(hglobal); - auto ptr = (const uint8_t*)GlobalLock(hglobal); - if (ptr) { - len = *((CustomSizeT*)ptr); - - assert(len <= total_size); - if (len > total_size) - len = total_size - sizeof(CustomSizeT); - - GlobalUnlock(hglobal); - } - } - } - } - - return len; -} - -bool lock::impl::set_image(const image& image) { - const image_spec& spec = image.spec(); - - // Add the PNG clipboard format for images with alpha channel - // (useful to communicate with some Windows programs that only use - // alpha data from PNG clipboard format) - if (spec.bits_per_pixel == 32 && - spec.alpha_mask) { - UINT png_format = RegisterClipboardFormatA("PNG"); - if (png_format) { - Hglobal png_handle(win::write_png(image)); - if (png_handle) - SetClipboardData(png_format, png_handle); - } - } - - image_spec out_spec = spec; - - int palette_colors = 0; - int padding = 0; - switch (spec.bits_per_pixel) { - case 24: padding = (4-((spec.width*3)&3))&3; break; - case 16: padding = ((4-((spec.width*2)&3))&3)/2; break; - case 8: padding = (4-(spec.width&3))&3; break; - } - out_spec.bytes_per_row += padding; - - // Create the BITMAPV5HEADER structure - Hglobal hmem( - GlobalAlloc( - GHND, - sizeof(BITMAPV5HEADER) - + palette_colors*sizeof(RGBQUAD) - + out_spec.bytes_per_row*out_spec.height)); - if (!hmem) - return false; - - out_spec.red_mask = 0x00ff0000; - out_spec.green_mask = 0xff00; - out_spec.blue_mask = 0xff; - out_spec.alpha_mask = 0xff000000; - out_spec.red_shift = 16; - out_spec.green_shift = 8; - out_spec.blue_shift = 0; - out_spec.alpha_shift = 24; - - BITMAPV5HEADER* bi = (BITMAPV5HEADER*)GlobalLock(hmem); - bi->bV5Size = sizeof(BITMAPV5HEADER); - bi->bV5Width = out_spec.width; - bi->bV5Height = out_spec.height; - bi->bV5Planes = 1; - bi->bV5BitCount = (WORD)out_spec.bits_per_pixel; - bi->bV5Compression = BI_RGB; - bi->bV5SizeImage = out_spec.bytes_per_row*spec.height; - bi->bV5RedMask = out_spec.red_mask; - bi->bV5GreenMask = out_spec.green_mask; - bi->bV5BlueMask = out_spec.blue_mask; - bi->bV5AlphaMask = out_spec.alpha_mask; - bi->bV5CSType = LCS_WINDOWS_COLOR_SPACE; - bi->bV5Intent = LCS_GM_GRAPHICS; - bi->bV5ClrUsed = 0; - - switch (spec.bits_per_pixel) { - case 32: { - const char* src = image.data(); - char* dst = (((char*)bi)+bi->bV5Size) + (out_spec.height-1)*out_spec.bytes_per_row; - for (long y=spec.height-1; y>=0; --y) { - const uint32_t* src_x = (const uint32_t*)src; - uint32_t* dst_x = (uint32_t*)dst; - - for (unsigned long x=0; x> spec.red_shift ); - int g = ((c & spec.green_mask) >> spec.green_shift); - int b = ((c & spec.blue_mask ) >> spec.blue_shift ); - int a = ((c & spec.alpha_mask) >> spec.alpha_shift); - - // Windows requires premultiplied RGBA values - r = r * a / 255; - g = g * a / 255; - b = b * a / 255; - - *dst_x = - (r << out_spec.red_shift ) | - (g << out_spec.green_shift) | - (b << out_spec.blue_shift ) | - (a << out_spec.alpha_shift); - } - - src += spec.bytes_per_row; - dst -= out_spec.bytes_per_row; - } - break; - } - default: - error_handler e = get_error_handler(); - if (e) - e(ErrorCode::ImageNotSupported); - return false; - } - - GlobalUnlock(hmem); - SetClipboardData(CF_DIBV5, hmem); - return true; -} - -bool lock::impl::get_image(image& output_img) const { - // Get the "PNG" clipboard format (this is useful only for 32bpp - // images with alpha channel, in other case we can use the regular - // DIB format) - UINT png_format = RegisterClipboardFormatA("PNG"); - if (png_format && IsClipboardFormatAvailable(png_format)) { - HANDLE png_handle = GetClipboardData(png_format); - if (png_handle) { - size_t png_size = GlobalSize(png_handle); - uint8_t* png_data = (uint8_t*)GlobalLock(png_handle); - bool result = win::read_png(png_data, png_size, &output_img, nullptr); - GlobalUnlock(png_handle); - if (result) - return true; - } - } - - BitmapInfo bi; - if (!bi.is_valid()) { - // There is no image at all in the clipboard, no need to report - // this as an error, just return false. - return false; - } - - image_spec spec; - bi.fill_spec(spec); - image img(spec); - - switch (bi.bit_count) { - - case 32: - case 24: - case 16: { - const uint8_t* src = nullptr; - - if (bi.compression == BI_RGB || - bi.compression == BI_BITFIELDS) { - if (bi.b5) - src = ((uint8_t*)bi.b5) + bi.b5->bV5Size; - else - src = ((uint8_t*)bi.bi) + bi.bi->bmiHeader.biSize; - if (bi.compression == BI_BITFIELDS) - src += sizeof(RGBQUAD)*3; - } - - if (src) { - const int src_bytes_per_row = spec.width*((bi.bit_count+7)/8); - const int padding = (4-(src_bytes_per_row&3))&3; - - for (long y=spec.height-1; y>=0; --y, src+=src_bytes_per_row+padding) { - char* dst = img.data()+y*spec.bytes_per_row; - std::copy(src, src+src_bytes_per_row, dst); - } - } - - // Windows uses premultiplied RGB values, and we use straight - // alpha. So we have to divide all RGB values by its alpha. - if (bi.bit_count == 32 && spec.alpha_mask) { - details::divide_rgb_by_alpha(img); - } - break; - } - - case 8: { - assert(bi.bi); - - const int colors = (bi.bi->bmiHeader.biClrUsed > 0 ? bi.bi->bmiHeader.biClrUsed: 256); - std::vector palette(colors); - for (int c=0; cbmiColors[c].rgbRed << spec.red_shift) | - (bi.bi->bmiColors[c].rgbGreen << spec.green_shift) | - (bi.bi->bmiColors[c].rgbBlue << spec.blue_shift); - } - - const uint8_t* src = (((uint8_t*)bi.bi) + bi.bi->bmiHeader.biSize + sizeof(RGBQUAD)*colors); - const int padding = (4-(spec.width&3))&3; - - for (long y=spec.height-1; y>=0; --y, src+=padding) { - char* dst = img.data()+y*spec.bytes_per_row; - - for (unsigned long x=0; x= colors) - idx = colors-1; - - *((uint32_t*)dst) = palette[idx]; - } - } - break; - } - } - - std::swap(output_img, img); - return true; -} - -bool lock::impl::get_image_spec(image_spec& spec) const { - UINT png_format = RegisterClipboardFormatA("PNG"); - if (png_format && IsClipboardFormatAvailable(png_format)) { - HANDLE png_handle = GetClipboardData(png_format); - if (png_handle) { - size_t png_size = GlobalSize(png_handle); - uint8_t* png_data = (uint8_t*)GlobalLock(png_handle); - bool result = win::read_png(png_data, png_size, nullptr, &spec); - GlobalUnlock(png_handle); - if (result) - return true; - } - } - - BitmapInfo bi; - if (!bi.is_valid()) - return false; - bi.fill_spec(spec); - return true; -} - -format register_format(const std::string& name) { - int reqsize = 1+MultiByteToWideChar(CP_UTF8, 0, - name.c_str(), name.size(), NULL, 0); - std::vector buf(reqsize); - MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name.size(), - &buf[0], reqsize); - - // From MSDN, registered clipboard formats are identified by values - // in the range 0xC000 through 0xFFFF. - return (format)RegisterClipboardFormatW(&buf[0]); -} - -} // namespace clip diff --git a/src/vendor/clip/clip_win_wic.h b/src/vendor/clip/clip_win_wic.h deleted file mode 100755 index c0dbc9b..0000000 --- a/src/vendor/clip/clip_win_wic.h +++ /dev/null @@ -1,246 +0,0 @@ -// Clip Library -// Copyright (c) 2020 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#include "clip.h" - -#include -#include - -#include -#include - -namespace clip { -namespace win { - -// Successful calls to CoInitialize() (S_OK or S_FALSE) must match -// the calls to CoUninitialize(). -// From: https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize#remarks -struct coinit { - HRESULT hr; - coinit() { - hr = CoInitialize(nullptr); - } - ~coinit() { - if (hr == S_OK || hr == S_FALSE) - CoUninitialize(); - } -}; - -template -class comptr { -public: - comptr() : m_ptr(nullptr) { } - explicit comptr(T* ptr) : m_ptr(ptr) { } - comptr(const comptr&) = delete; - comptr& operator=(const comptr&) = delete; - ~comptr() { reset(); } - - T** operator&() { return &m_ptr; } - T* operator->() { return m_ptr; } - bool operator!() const { return !m_ptr; } - - T* get() { return m_ptr; } - void reset() { - if (m_ptr) { - m_ptr->Release(); - m_ptr = nullptr; - } - } -private: - T* m_ptr; -}; - -////////////////////////////////////////////////////////////////////// -// Encode the image as PNG format - -bool write_png_on_stream(const image& image, - IStream* stream) { - const image_spec& spec = image.spec(); - - comptr encoder; - HRESULT hr = CoCreateInstance(CLSID_WICPngEncoder, - nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&encoder)); - if (FAILED(hr)) - return false; - - hr = encoder->Initialize(stream, WICBitmapEncoderNoCache); - if (FAILED(hr)) - return false; - - comptr frame; - comptr options; - hr = encoder->CreateNewFrame(&frame, &options); - if (FAILED(hr)) - return false; - - hr = frame->Initialize(options.get()); - if (FAILED(hr)) - return false; - - // PNG encoder (and decoder) only supports GUID_WICPixelFormat32bppBGRA for 32bpp. - // See: https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#png-native-codec - WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat32bppBGRA; - hr = frame->SetPixelFormat(&pixelFormat); - if (FAILED(hr)) - return false; - - hr = frame->SetSize(spec.width, spec.height); - if (FAILED(hr)) - return false; - - std::vector buf; - uint8_t* ptr = (uint8_t*)image.data(); - int bytes_per_row = spec.bytes_per_row; - - // Convert to GUID_WICPixelFormat32bppBGRA if needed - if (spec.red_mask != 0xff0000 || - spec.green_mask != 0xff00 || - spec.blue_mask != 0xff || - spec.alpha_mask != 0xff000000) { - buf.resize(spec.width * spec.height); - uint32_t* dst = (uint32_t*)&buf[0]; - uint32_t* src = (uint32_t*)image.data(); - for (int y=0; y> spec.red_shift ) << 16) | - (((c & spec.green_mask) >> spec.green_shift) << 8) | - (((c & spec.blue_mask ) >> spec.blue_shift ) ) | - (((c & spec.alpha_mask) >> spec.alpha_shift) << 24)); - ++dst; - ++src; - } - src = (uint32_t*)(((uint8_t*)src_line_start) + spec.bytes_per_row); - } - ptr = (uint8_t*)&buf[0]; - bytes_per_row = 4 * spec.width; - } - - hr = frame->WritePixels(spec.height, - bytes_per_row, - bytes_per_row * spec.height, - (BYTE*)ptr); - if (FAILED(hr)) - return false; - - hr = frame->Commit(); - if (FAILED(hr)) - return false; - - hr = encoder->Commit(); - if (FAILED(hr)) - return false; - - return true; -} - -HGLOBAL write_png(const image& image) { - coinit com; - - comptr stream; - HRESULT hr = CreateStreamOnHGlobal(nullptr, false, &stream); - if (FAILED(hr)) - return nullptr; - - bool result = write_png_on_stream(image, stream.get()); - - HGLOBAL handle; - hr = GetHGlobalFromStream(stream.get(), &handle); - if (result) - return handle; - - GlobalFree(handle); - return nullptr; -} - -////////////////////////////////////////////////////////////////////// -// Decode the clipboard data from PNG format - -bool read_png(const uint8_t* buf, - const UINT len, - image* output_image, - image_spec* output_spec) { - coinit com; - - comptr stream(SHCreateMemStream(buf, len)); - if (!stream) - return false; - - comptr decoder; - HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder2, - nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&decoder)); - if (FAILED(hr)) { - hr = CoCreateInstance(CLSID_WICPngDecoder1, - nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&decoder)); - if (FAILED(hr)) - return false; - } - - hr = decoder->Initialize(stream.get(), WICDecodeMetadataCacheOnDemand); - if (FAILED(hr)) - return false; - - comptr frame; - hr = decoder->GetFrame(0, &frame); - if (FAILED(hr)) - return false; - - WICPixelFormatGUID pixelFormat; - hr = frame->GetPixelFormat(&pixelFormat); - if (FAILED(hr)) - return false; - - // Only support this pixel format - // TODO add support for more pixel formats - if (pixelFormat != GUID_WICPixelFormat32bppBGRA) - return false; - - UINT width = 0, height = 0; - hr = frame->GetSize(&width, &height); - if (FAILED(hr)) - return false; - - image_spec spec; - spec.width = width; - spec.height = height; - spec.bits_per_pixel = 32; - spec.bytes_per_row = 4 * width; - spec.red_mask = 0xff0000; - spec.green_mask = 0xff00; - spec.blue_mask = 0xff; - spec.alpha_mask = 0xff000000; - spec.red_shift = 16; - spec.green_shift = 8; - spec.blue_shift = 0; - spec.alpha_shift = 24; - - if (output_spec) - *output_spec = spec; - - if (output_image) { - image img(spec); - - hr = frame->CopyPixels( - nullptr, // Entire bitmap - spec.bytes_per_row, - spec.bytes_per_row * spec.height, - (BYTE*)img.data()); - if (FAILED(hr)) { - return false; - } - - std::swap(*output_image, img); - } - - return true; -} - -} // namespace win -} // namespace clip diff --git a/src/vendor/clip/clip_x11.cpp b/src/vendor/clip/clip_x11.cpp deleted file mode 100755 index 842105b..0000000 --- a/src/vendor/clip/clip_x11.cpp +++ /dev/null @@ -1,1094 +0,0 @@ -// Clip Library -// Copyright (c) 2018-2022 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#include "clip.h" -#include "clip_lock_impl.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PNG_H - #include "clip_x11_png.h" -#endif - -#define CLIP_SUPPORT_SAVE_TARGETS 1 - -namespace clip { - -namespace { - -enum CommonAtom { - ATOM, - INCR, - TARGETS, - CLIPBOARD, -#ifdef HAVE_PNG_H - MIME_IMAGE_PNG, -#endif -#ifdef CLIP_SUPPORT_SAVE_TARGETS - ATOM_PAIR, - SAVE_TARGETS, - MULTIPLE, - CLIPBOARD_MANAGER, -#endif -}; - -const char* kCommonAtomNames[] = { - "ATOM", - "INCR", - "TARGETS", - "CLIPBOARD", -#ifdef HAVE_PNG_H - "image/png", -#endif -#ifdef CLIP_SUPPORT_SAVE_TARGETS - "ATOM_PAIR", - "SAVE_TARGETS", - "MULTIPLE", - "CLIPBOARD_MANAGER", -#endif -}; - -const int kBaseForCustomFormats = 100; - -class Manager { -public: - typedef std::shared_ptr> buffer_ptr; - typedef std::vector atoms; - typedef std::function notify_callback; - - Manager() - : m_lock(m_mutex, std::defer_lock) - , m_connection(xcb_connect(nullptr, nullptr)) - , m_window(0) - , m_incr_process(false) { - if (!m_connection) - return; - - const xcb_setup_t* setup = xcb_get_setup(m_connection); - if (!setup) - return; - - xcb_screen_t* screen = xcb_setup_roots_iterator(setup).data; - if (!screen) - return; - - uint32_t event_mask = - // Just in case that some program reports SelectionNotify events - // with XCB_EVENT_MASK_PROPERTY_CHANGE mask. - XCB_EVENT_MASK_PROPERTY_CHANGE | - // To receive DestroyNotify event and stop the message loop. - XCB_EVENT_MASK_STRUCTURE_NOTIFY; - - m_window = xcb_generate_id(m_connection); - xcb_create_window(m_connection, 0, - m_window, - screen->root, - 0, 0, 1, 1, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - screen->root_visual, - XCB_CW_EVENT_MASK, - &event_mask); - - m_thread = std::thread( - [this]{ - process_x11_events(); - }); - } - - ~Manager() { -#ifdef CLIP_SUPPORT_SAVE_TARGETS - if (!m_data.empty() && - m_window && - m_window == get_x11_selection_owner()) { - // If the CLIPBOARD_MANAGER atom is not 0, we assume that there - // is a clipboard manager available were we can leave our data. - xcb_atom_t x11_clipboard_manager = get_atom(CLIPBOARD_MANAGER); - if (x11_clipboard_manager) { - // We have to lock the m_lock mutex that will be used to wait - // the m_cv condition in get_data_from_selection_owner(). - if (try_lock()) { - // Start the SAVE_TARGETS mechanism so the X11 - // CLIPBOARD_MANAGER will save our clipboard data - // from now on. - get_data_from_selection_owner( - { get_atom(SAVE_TARGETS) }, - []() -> bool { return true; }, - x11_clipboard_manager); - } - } - } -#endif - - if (m_window) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); - } - - if (m_thread.joinable()) - m_thread.join(); - - if (m_connection) - xcb_disconnect(m_connection); - } - - bool try_lock() { - bool res = m_lock.try_lock(); - if (!res) { - // TODO make this configurable (the same for Windows retries) - for (int i=0; i<5 && !res; ++i) { - res = m_lock.try_lock(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } - } - return res; - } - - void unlock() { - m_lock.unlock(); - } - - // Clear our data - void clear_data() { - m_data.clear(); - m_image.reset(); - } - - void clear() { - clear_data(); - - // As we want to clear the clipboard content, we set us as the new - // clipboard owner (with an empty clipboard). If this fails, we'll - // try to send a XCB_SELECTION_CLEAR request to the real owner - // (but that can fail anyway because it's a request that the owner - // could ignore). - if (set_x11_selection_owner()) - return; - - // Clear the clipboard data from the selection owner - const xcb_window_t owner = get_x11_selection_owner(); - if (m_window != owner) { - xcb_selection_clear_event_t event; - event.response_type = XCB_SELECTION_CLEAR; - event.pad0 = 0; - event.sequence = 0; - event.time = XCB_CURRENT_TIME; - event.owner = owner; - event.selection = get_atom(CLIPBOARD); - - xcb_send_event(m_connection, false, - owner, - XCB_EVENT_MASK_NO_EVENT, - (const char*)&event); - - xcb_flush(m_connection); - } - } - - bool is_convertible(format f) const { - const atoms atoms = get_format_atoms(f); - const xcb_window_t owner = get_x11_selection_owner(); - - // If we are the owner, we just can check the m_data map - if (owner == m_window) { - for (xcb_atom_t atom : atoms) { - auto it = m_data.find(atom); - if (it != m_data.end()) - return true; - } - } - // Ask to the selection owner the available formats/atoms/targets. - else if (owner) { - return - get_data_from_selection_owner( - { get_atom(TARGETS) }, - [this, &atoms]() -> bool { - assert(m_reply_data); - if (!m_reply_data) - return false; - - const xcb_atom_t* sel_atoms = (const xcb_atom_t*)&(*m_reply_data)[0]; - int sel_natoms = m_reply_data->size() / sizeof(xcb_atom_t); - auto atoms_begin = atoms.begin(); - auto atoms_end = atoms.end(); - for (int i=0; i>(len); - std::copy(buf, - buf+len, - shared_data_buf->begin()); - for (xcb_atom_t atom : atoms) - m_data[atom] = shared_data_buf; - - return true; - } - - bool get_data(format f, char* buf, size_t len) const { - const atoms atoms = get_format_atoms(f); - const xcb_window_t owner = get_x11_selection_owner(); - if (owner == m_window) { - for (xcb_atom_t atom : atoms) { - auto it = m_data.find(atom); - if (it != m_data.end()) { - size_t n = std::min(len, it->second->size()); - std::copy(it->second->begin(), - it->second->begin()+n, - buf); - - if (f == text_format()) { - // Add an extra null char - if (n < len) - buf[n] = 0; - } - - return true; - } - } - } - else if (owner) { - if (get_data_from_selection_owner( - atoms, - [this, buf, len, f]() -> bool { - size_t n = std::min(len, m_reply_data->size()); - std::copy(m_reply_data->begin(), - m_reply_data->begin()+n, - buf); - - if (f == text_format()) { - if (n < len) - buf[n] = 0; // Include a null character - } - - return true; - })) { - return true; - } - } - return false; - } - - size_t get_data_length(format f) const { - size_t len = 0; - const atoms atoms = get_format_atoms(f); - const xcb_window_t owner = get_x11_selection_owner(); - if (owner == m_window) { - for (xcb_atom_t atom : atoms) { - auto it = m_data.find(atom); - if (it != m_data.end()) { - len = it->second->size(); - break; - } - } - } - else if (owner) { - if (!get_data_from_selection_owner( - atoms, - [this, &len]() -> bool { - len = m_reply_data->size(); - return true; - })) { - // Error getting data length - return 0; - } - } - if (f == text_format() && len > 0) { - ++len; // Add an extra byte for the null char - } - return len; - } - - bool set_image(const image& image) { - if (!set_x11_selection_owner()) - return false; - - m_image = image; - -#ifdef HAVE_PNG_H - // Put a nullptr in the m_data for image/png format and then we'll - // encode the png data when the image is requested in this format. - m_data[get_atom(MIME_IMAGE_PNG)] = buffer_ptr(); -#endif - - return true; - } - - bool get_image(image& output_img) const { - const xcb_window_t owner = get_x11_selection_owner(); - if (owner == m_window) { - if (m_image.is_valid()) { - output_img = m_image; - return true; - } - } -#ifdef HAVE_PNG_H - else if (owner && - get_data_from_selection_owner( - { get_atom(MIME_IMAGE_PNG) }, - [this, &output_img]() -> bool { - return x11::read_png(&(*m_reply_data)[0], - m_reply_data->size(), - &output_img, nullptr); - })) { - return true; - } -#endif - return false; - } - - bool get_image_spec(image_spec& spec) const { - const xcb_window_t owner = get_x11_selection_owner(); - if (owner == m_window) { - if (m_image.is_valid()) { - spec = m_image.spec(); - return true; - } - } -#ifdef HAVE_PNG_H - else if (owner && - get_data_from_selection_owner( - { get_atom(MIME_IMAGE_PNG) }, - [this, &spec]() -> bool { - return x11::read_png(&(*m_reply_data)[0], - m_reply_data->size(), - nullptr, &spec); - })) { - return true; - } -#endif - return false; - } - - format register_format(const std::string& name) { - xcb_atom_t atom = get_atom(name.c_str()); - m_custom_formats.push_back(atom); - return (format)(m_custom_formats.size()-1) + kBaseForCustomFormats; - } - -private: - - void process_x11_events() { - bool stop = false; - xcb_generic_event_t* event; - while (!stop && (event = xcb_wait_for_event(m_connection))) { - int type = (event->response_type & ~0x80); - - switch (type) { - - case XCB_DESTROY_NOTIFY: - // To stop the message loop we can just destroy the window - stop = true; - break; - - // Someone else has new content in the clipboard, so is - // notifying us that we should delete our data now. - case XCB_SELECTION_CLEAR: - handle_selection_clear_event( - (xcb_selection_clear_event_t*)event); - break; - - // Someone is requesting the clipboard content from us. - case XCB_SELECTION_REQUEST: - handle_selection_request_event( - (xcb_selection_request_event_t*)event); - break; - - // We've requested the clipboard content and this is the - // answer. - case XCB_SELECTION_NOTIFY: - handle_selection_notify_event( - (xcb_selection_notify_event_t*)event); - break; - - case XCB_PROPERTY_NOTIFY: - handle_property_notify_event( - (xcb_property_notify_event_t*)event); - break; - - } - - free(event); - } - } - - void handle_selection_clear_event(xcb_selection_clear_event_t* event) { - if (event->selection == get_atom(CLIPBOARD)) { - std::lock_guard lock(m_mutex); - clear_data(); // Clear our clipboard data - } - } - - void handle_selection_request_event(xcb_selection_request_event_t* event) { - std::lock_guard lock(m_mutex); - - if (event->target == get_atom(TARGETS)) { - atoms targets; - targets.push_back(get_atom(TARGETS)); -#ifdef CLIP_SUPPORT_SAVE_TARGETS - targets.push_back(get_atom(SAVE_TARGETS)); - targets.push_back(get_atom(MULTIPLE)); -#endif - for (const auto& it : m_data) - targets.push_back(it.first); - - // Set the "property" of "requestor" with the clipboard - // formats ("targets", atoms) that we provide. - xcb_change_property( - m_connection, - XCB_PROP_MODE_REPLACE, - event->requestor, - event->property, - get_atom(ATOM), - 8*sizeof(xcb_atom_t), - targets.size(), - &targets[0]); - } -#ifdef CLIP_SUPPORT_SAVE_TARGETS - else if (event->target == get_atom(SAVE_TARGETS)) { - // Do nothing - } - else if (event->target == get_atom(MULTIPLE)) { - xcb_get_property_reply_t* reply = - get_and_delete_property(event->requestor, - event->property, - get_atom(ATOM_PAIR), - false); - if (reply) { - for (xcb_atom_t - *ptr=(xcb_atom_t*)xcb_get_property_value(reply), - *end=ptr + (xcb_get_property_value_length(reply)/sizeof(xcb_atom_t)); - ptrrequestor, - property, - target)) { - xcb_change_property( - m_connection, - XCB_PROP_MODE_REPLACE, - event->requestor, - event->property, - XCB_ATOM_NONE, 0, 0, nullptr); - } - } - - free(reply); - } - } -#endif // CLIP_SUPPORT_SAVE_TARGETS - else { - if (!set_requestor_property_with_clipboard_content( - event->requestor, - event->property, - event->target)) { - return; - } - } - - // Notify the "requestor" that we've already updated the property. - xcb_selection_notify_event_t notify; - notify.response_type = XCB_SELECTION_NOTIFY; - notify.pad0 = 0; - notify.sequence = 0; - notify.time = event->time; - notify.requestor = event->requestor; - notify.selection = event->selection; - notify.target = event->target; - notify.property = event->property; - - xcb_send_event(m_connection, false, - event->requestor, - XCB_EVENT_MASK_NO_EVENT, // SelectionNotify events go without mask - (const char*)¬ify); - - xcb_flush(m_connection); - } - - bool set_requestor_property_with_clipboard_content(const xcb_atom_t requestor, - const xcb_atom_t property, - const xcb_atom_t target) { - auto it = m_data.find(target); - if (it == m_data.end()) { - // Nothing to do (unsupported target) - return false; - } - - // This can be null of the data was set from an image but we - // didn't encode the image yet (e.g. to image/png format). - if (!it->second) { - encode_data_on_demand(*it); - - // Return nothing, the given "target" cannot be constructed - // (maybe by some encoding error). - if (!it->second) - return false; - } - - // Set the "property" of "requestor" with the - // clipboard content in the requested format ("target"). - xcb_change_property( - m_connection, - XCB_PROP_MODE_REPLACE, - requestor, - property, - target, - 8, - it->second->size(), - &(*it->second)[0]); - return true; - } - - void handle_selection_notify_event(xcb_selection_notify_event_t* event) { - assert(event->requestor == m_window); - - if (event->target == get_atom(TARGETS)) - m_target_atom = get_atom(ATOM); - else - m_target_atom = event->target; - - xcb_get_property_reply_t* reply = - get_and_delete_property(event->requestor, - event->property, - m_target_atom); - if (reply) { - // In this case, We're going to receive the clipboard content in - // chunks of data with several PropertyNotify events. - if (reply->type == get_atom(INCR)) { - free(reply); - - reply = get_and_delete_property(event->requestor, - event->property, - get_atom(INCR)); - if (reply) { - if (xcb_get_property_value_length(reply) == 4) { - uint32_t n = *(uint32_t*)xcb_get_property_value(reply); - m_reply_data = std::make_shared>(n); - m_reply_offset = 0; - m_incr_process = true; - m_incr_received = true; - } - free(reply); - } - } - else { - // Simple case, the whole clipboard content in just one reply - // (without the INCR method). - m_reply_data.reset(); - m_reply_offset = 0; - copy_reply_data(reply); - - call_callback(reply); - - free(reply); - } - } - } - - void handle_property_notify_event(xcb_property_notify_event_t* event) { - if (m_incr_process && - event->state == XCB_PROPERTY_NEW_VALUE && - event->atom == get_atom(CLIPBOARD)) { - xcb_get_property_reply_t* reply = - get_and_delete_property(event->window, - event->atom, - m_target_atom); - if (reply) { - m_incr_received = true; - - // When the length is 0 it means that the content was - // completely sent by the selection owner. - if (xcb_get_property_value_length(reply) > 0) { - copy_reply_data(reply); - } - else { - // Now that m_reply_data has the complete clipboard content, - // we can call the m_callback. - call_callback(reply); - m_incr_process = false; - } - free(reply); - } - } - } - - xcb_get_property_reply_t* get_and_delete_property(xcb_window_t window, - xcb_atom_t property, - xcb_atom_t atom, - bool delete_prop = true) { - xcb_get_property_cookie_t cookie = - xcb_get_property(m_connection, - delete_prop, - window, - property, - atom, - 0, 0x1fffffff); // 0x1fffffff = INT32_MAX / 4 - - xcb_generic_error_t* err = nullptr; - xcb_get_property_reply_t* reply = - xcb_get_property_reply(m_connection, cookie, &err); - if (err) { - // TODO report error - free(err); - } - return reply; - } - - // Concatenates the new data received in "reply" into "m_reply_data" - // buffer. - void copy_reply_data(xcb_get_property_reply_t* reply) { - const uint8_t* src = (const uint8_t*)xcb_get_property_value(reply); - // n = length of "src" in bytes - size_t n = xcb_get_property_value_length(reply); - - size_t req = m_reply_offset+n; - if (!m_reply_data) { - m_reply_data = std::make_shared>(req); - } - // The "m_reply_data" size can be smaller because the size - // specified in INCR property is just a lower bound. - else if (req > m_reply_data->size()) { - m_reply_data->resize(req); - } - - std::copy(src, src+n, m_reply_data->begin()+m_reply_offset); - m_reply_offset += n; - } - - // Calls the current m_callback() to handle the clipboard content - // received from the owner. - void call_callback(xcb_get_property_reply_t* reply) { - m_callback_result = false; - if (m_callback) - m_callback_result = m_callback(); - - m_cv.notify_one(); - - m_reply_data.reset(); - } - - bool get_data_from_selection_owner(const atoms& atoms, - const notify_callback&& callback, - xcb_atom_t selection = 0) const { - if (!selection) - selection = get_atom(CLIPBOARD); - - // Put the callback on "m_callback" so we can call it on - // SelectionNotify event. - m_callback = std::move(callback); - - // Clear data if we are not the selection owner. - if (m_window != get_x11_selection_owner()) - m_data.clear(); - - // Ask to the selection owner for its content on each known - // text format/atom. - for (xcb_atom_t atom : atoms) { - xcb_convert_selection(m_connection, - m_window, // Send us the result - selection, // Clipboard selection - atom, // The clipboard format that we're requesting - get_atom(CLIPBOARD), // Leave result in this window's property - XCB_CURRENT_TIME); - - xcb_flush(m_connection); - - // We use the "m_incr_received" to wait several timeouts in case - // that we've received the INCR SelectionNotify or - // PropertyNotify events. - do { - m_incr_received = false; - - // Wait a response for 100 milliseconds - std::cv_status status = - m_cv.wait_for(m_lock, - std::chrono::milliseconds(get_x11_wait_timeout())); - if (status == std::cv_status::no_timeout) { - // If the condition variable was notified, it means that the - // callback was called correctly. - return m_callback_result; - } - } while (m_incr_received); - } - - // Reset callback - m_callback = notify_callback(); - return false; - } - - atoms get_atoms(const char** names, - const int n) const { - atoms result(n, 0); - std::vector cookies(n); - - for (int i=0; isecond; - else - cookies[i] = xcb_intern_atom( - m_connection, 0, - std::strlen(names[i]), names[i]); - } - - for (int i=0; iatom; - free(reply); - } - } - } - - return result; - } - - xcb_atom_t get_atom(const char* name) const { - auto it = m_atoms.find(name); - if (it != m_atoms.end()) - return it->second; - - xcb_atom_t result = 0; - xcb_intern_atom_cookie_t cookie = - xcb_intern_atom(m_connection, 0, - std::strlen(name), name); - - xcb_intern_atom_reply_t* reply = - xcb_intern_atom_reply(m_connection, - cookie, - nullptr); - if (reply) { - result = m_atoms[name] = reply->atom; - free(reply); - } - return result; - } - - xcb_atom_t get_atom(CommonAtom i) const { - if (m_common_atoms.empty()) { - m_common_atoms = - get_atoms(kCommonAtomNames, - sizeof(kCommonAtomNames) / sizeof(kCommonAtomNames[0])); - } - return m_common_atoms[i]; - } - - const atoms& get_text_format_atoms() const { - if (m_text_atoms.empty()) { - const char* names[] = { - // Prefer utf-8 formats first - "UTF8_STRING", - "text/plain;charset=utf-8", - "text/plain;charset=UTF-8", - "GTK_TEXT_BUFFER_CONTENTS", // Required for gedit (and maybe gtk+ apps) - // ANSI C strings? - "STRING", - "TEXT", - "text/plain", - }; - m_text_atoms = get_atoms(names, sizeof(names) / sizeof(names[0])); - } - return m_text_atoms; - } - - const atoms& get_image_format_atoms() const { - if (m_image_atoms.empty()) { -#ifdef HAVE_PNG_H - m_image_atoms.push_back(get_atom(MIME_IMAGE_PNG)); -#endif - } - return m_image_atoms; - } - - atoms get_format_atoms(const format f) const { - atoms atoms; - if (f == text_format()) { - atoms = get_text_format_atoms(); - } - else if (f == image_format()) { - atoms = get_image_format_atoms(); - } - else { - xcb_atom_t atom = get_format_atom(f); - if (atom) - atoms.push_back(atom); - } - return atoms; - } - -#if !defined(NDEBUG) - // This can be used to print debugging messages. - std::string get_atom_name(xcb_atom_t atom) const { - std::string result; - xcb_get_atom_name_cookie_t cookie = - xcb_get_atom_name(m_connection, atom); - xcb_generic_error_t* err = nullptr; - xcb_get_atom_name_reply_t* reply = - xcb_get_atom_name_reply(m_connection, cookie, &err); - if (err) { - free(err); - } - if (reply) { - int len = xcb_get_atom_name_name_length(reply); - if (len > 0) { - result.resize(len); - char* name = xcb_get_atom_name_name(reply); - if (name) - std::copy(name, name+len, result.begin()); - } - free(reply); - } - return result; - } -#endif - - bool set_x11_selection_owner() const { - xcb_void_cookie_t cookie = - xcb_set_selection_owner_checked(m_connection, - m_window, - get_atom(CLIPBOARD), - XCB_CURRENT_TIME); - xcb_generic_error_t* err = - xcb_request_check(m_connection, - cookie); - if (err) { - free(err); - return false; - } - return true; - } - - xcb_window_t get_x11_selection_owner() const { - xcb_window_t result = 0; - xcb_get_selection_owner_cookie_t cookie = - xcb_get_selection_owner(m_connection, - get_atom(CLIPBOARD)); - - xcb_get_selection_owner_reply_t* reply = - xcb_get_selection_owner_reply(m_connection, cookie, nullptr); - if (reply) { - result = reply->owner; - free(reply); - } - return result; - } - - xcb_atom_t get_format_atom(const format f) const { - int i = f - kBaseForCustomFormats; - if (i >= 0 && i < int(m_custom_formats.size())) - return m_custom_formats[i]; - else - return 0; - } - - void encode_data_on_demand(std::pair& e) { -#ifdef HAVE_PNG_H - if (e.first == get_atom(MIME_IMAGE_PNG)) { - assert(m_image.is_valid()); - if (!m_image.is_valid()) - return; - - std::vector output; - if (x11::write_png(m_image, output)) { - e.second = - std::make_shared>( - std::move(output)); - } - // else { TODO report png conversion errors } - } -#endif - } - - // Access to the whole Manager - std::mutex m_mutex; - - // Lock used in the main thread using the Manager (i.e. by lock::impl) - mutable std::unique_lock m_lock; - - // Connection to X11 server - xcb_connection_t* m_connection; - - // Temporal background window used to own the clipboard and process - // all events related about the clipboard in a background thread - xcb_window_t m_window; - - // Used to wait/notify the arrival of the SelectionNotify event when - // we requested the clipboard content from other selection owner. - mutable std::condition_variable m_cv; - - // Thread used to run a background message loop to wait X11 events - // about clipboard. The X11 selection owner will be a hidden window - // created by us just for the clipboard purpose/communication. - std::thread m_thread; - - // Internal callback used when a SelectionNotify is received (or the - // whole data content is received by the INCR method). So this - // callback can use the notification by different purposes (e.g. get - // the data length only, or get/process the data content, etc.). - mutable notify_callback m_callback; - - // Result returned by the m_callback. Used as return value in the - // get_data_from_selection_owner() function. For example, if the - // callback must read a "image/png" file from the clipboard data and - // fails, the callback can return false and finally the get_image() - // will return false (i.e. there is data, but it's not a valid image - // format). - std::atomic m_callback_result; - - // Cache of known atoms - mutable std::map m_atoms; - - // Cache of common used atoms by us - mutable atoms m_common_atoms; - - // Cache of atoms related to text or image content - mutable atoms m_text_atoms; - mutable atoms m_image_atoms; - - // Actual clipboard data generated by us (when we "copy" content in - // the clipboard, it means that we own the X11 "CLIPBOARD" - // selection, and in case of SelectionRequest events, we've to - // return the data stored in this "m_data" field) - mutable std::map m_data; - - // Copied image in the clipboard. As we have to transfer the image - // in some specific format (e.g. image/png) we want to keep a copy - // of the image and make the conversion when the clipboard data is - // requested by other process. - mutable image m_image; - - // True if we have received an INCR notification so we're going to - // process several PropertyNotify to concatenate all data chunks. - bool m_incr_process; - - // Variable used to wait more time if we've received an INCR - // notification, which means that we're going to receive large - // amounts of data from the selection owner. - mutable bool m_incr_received; - - // Target/selection format used in the SelectionNotify. Used in the - // INCR method to get data from the same property in the same format - // (target) on each PropertyNotify. - xcb_atom_t m_target_atom; - - // Each time we receive data from the selection owner, we put that - // data in this buffer. If we get the data with the INCR method, - // we'll concatenate chunks of data in this buffer to complete the - // whole clipboard content. - buffer_ptr m_reply_data; - - // Used to concatenate chunks of data in "m_reply_data" from several - // PropertyNotify when we are getting the selection owner data with - // the INCR method. - size_t m_reply_offset; - - // List of user-defined formats/atoms. - std::vector m_custom_formats; -}; - -Manager* manager = nullptr; - -void delete_manager_atexit() { - if (manager) { - delete manager; - manager = nullptr; - } -} - -Manager* get_manager() { - if (!manager) { - manager = new Manager; - std::atexit(delete_manager_atexit); - } - return manager; -} - -} // anonymous namespace - -lock::impl::impl(void*) : m_locked(false) { - m_locked = get_manager()->try_lock(); -} - -lock::impl::~impl() { - if (m_locked) - manager->unlock(); -} - -bool lock::impl::clear() { - manager->clear(); - return true; -} - -bool lock::impl::is_convertible(format f) const { - return manager->is_convertible(f); -} - -bool lock::impl::set_data(format f, const char* buf, size_t len) { - return manager->set_data(f, buf, len); -} - -bool lock::impl::get_data(format f, char* buf, size_t len) const { - return manager->get_data(f, buf, len); -} - -size_t lock::impl::get_data_length(format f) const { - return manager->get_data_length(f); -} - -bool lock::impl::set_image(const image& image) { - return manager->set_image(image); -} - -bool lock::impl::get_image(image& output_img) const { - return manager->get_image(output_img); -} - -bool lock::impl::get_image_spec(image_spec& spec) const { - return manager->get_image_spec(spec); -} - -format register_format(const std::string& name) { - return get_manager()->register_format(name); -} - -} // namespace clip diff --git a/src/vendor/clip/clip_x11_png.h b/src/vendor/clip/clip_x11_png.h deleted file mode 100755 index cf3b514..0000000 --- a/src/vendor/clip/clip_x11_png.h +++ /dev/null @@ -1,230 +0,0 @@ -// Clip Library -// Copyright (c) 2018-2021 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#include "clip.h" - -#include -#include - -#include "png.h" - -namespace clip { -namespace x11 { - -////////////////////////////////////////////////////////////////////// -// Functions to convert clip::image into png data to store it in the -// clipboard. - -void write_data_fn(png_structp png, png_bytep buf, png_size_t len) { - std::vector& output = *(std::vector*)png_get_io_ptr(png); - const size_t i = output.size(); - output.resize(i+len); - std::copy(buf, buf+len, output.begin()+i); -} - -bool write_png(const image& image, - std::vector& output) { - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, - nullptr, nullptr, nullptr); - if (!png) - return false; - - png_infop info = png_create_info_struct(png); - if (!info) { - png_destroy_write_struct(&png, nullptr); - return false; - } - - if (setjmp(png_jmpbuf(png))) { - png_destroy_write_struct(&png, &info); - return false; - } - - png_set_write_fn(png, - (png_voidp)&output, - write_data_fn, - nullptr); // No need for a flush function - - const image_spec& spec = image.spec(); - int color_type = (spec.alpha_mask ? - PNG_COLOR_TYPE_RGB_ALPHA: - PNG_COLOR_TYPE_RGB); - - png_set_IHDR(png, info, - spec.width, spec.height, 8, color_type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_write_info(png, info); - png_set_packing(png); - - png_bytep row = - (png_bytep)png_malloc(png, png_get_rowbytes(png, info)); - - for (png_uint_32 y=0; y> spec.red_shift; - *(dst++) = (c & spec.green_mask) >> spec.green_shift; - *(dst++) = (c & spec.blue_mask ) >> spec.blue_shift; - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - *(dst++) = (c & spec.alpha_mask) >> spec.alpha_shift; - } - - png_write_rows(png, &row, 1); - } - - png_free(png, row); - png_write_end(png, info); - png_destroy_write_struct(&png, &info); - return true; -} - -////////////////////////////////////////////////////////////////////// -// Functions to convert png data stored in the clipboard to a -// clip::image. - -struct read_png_io { - const uint8_t* buf; - size_t len; - size_t pos; -}; - -void read_data_fn(png_structp png, png_bytep buf, png_size_t len) { - read_png_io& io = *(read_png_io*)png_get_io_ptr(png); - if (io.pos < io.len) { - size_t n = std::min(len, io.len-io.pos); - if (n > 0) { - std::copy(io.buf+io.pos, - io.buf+io.pos+n, - buf); - io.pos += n; - } - } -} - -bool read_png(const uint8_t* buf, - const size_t len, - image* output_image, - image_spec* output_spec) { - png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, - nullptr, nullptr, nullptr); - if (!png) - return false; - - png_infop info = png_create_info_struct(png); - if (!info) { - png_destroy_read_struct(&png, nullptr, nullptr); - return false; - } - - if (setjmp(png_jmpbuf(png))) { - png_destroy_read_struct(&png, &info, nullptr); - return false; - } - - read_png_io io = { buf, len, 0 }; - png_set_read_fn(png, (png_voidp)&io, read_data_fn); - - png_read_info(png, info); - - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_get_IHDR(png, info, &width, &height, - &bit_depth, &color_type, - &interlace_type, - nullptr, nullptr); - - image_spec spec; - spec.width = width; - spec.height = height; - spec.bits_per_pixel = 32; - - // Don't use png_get_rowbytes(png, info) here because this is the - // bytes_per_row of the output clip::image (the png file could - // contain 24bpp but we want to return a 32bpp anyway with alpha=255 - // in that case). - spec.bytes_per_row = 4*width; - - spec.red_mask = 0x000000ff; - spec.green_mask = 0x0000ff00; - spec.blue_mask = 0x00ff0000; - spec.red_shift = 0; - spec.green_shift = 8; - spec.blue_shift = 16; - - if ((color_type & PNG_COLOR_MASK_ALPHA) == PNG_COLOR_MASK_ALPHA) { - spec.alpha_mask = 0xff000000; - spec.alpha_shift = 24; - } - else { - spec.alpha_mask = 0; - spec.alpha_shift = 0; - } - - if (output_spec) - *output_spec = spec; - - if (output_image && - width > 0 && - height > 0) { - image img(spec); - - // We want RGB 24-bit or RGBA 32-bit as a result - png_set_strip_16(png); // Down to 8-bit (TODO we might support 16-bit values) - png_set_packing(png); // Use one byte if color depth < 8-bit - png_set_expand_gray_1_2_4_to_8(png); - png_set_palette_to_rgb(png); - png_set_gray_to_rgb(png); - png_set_tRNS_to_alpha(png); - - int number_passes = png_set_interlace_handling(png); - png_read_update_info(png, info); - - const int src_bytes_per_row = png_get_rowbytes(png, info); - png_bytepp rows = (png_bytepp)png_malloc(png, sizeof(png_bytep)*height); - png_uint_32 y; - for (y=0; y 0) - n += 4 - (n % 4); - else - ++n; - } - - return n; -} - -image::image() - : m_own_data(false), - m_data(nullptr) -{ -} - -image::image(const image_spec& spec) - : m_own_data(true), - m_data(new char[spec.required_data_size()]), - m_spec(spec) { -} - -image::image(const void* data, const image_spec& spec) - : m_own_data(false), - m_data((char*)data), - m_spec(spec) { -} - -image::image(const image& image) - : m_own_data(false), - m_data(nullptr), - m_spec(image.m_spec) { - copy_image(image); -} - -image::image(image&& image) - : m_own_data(false), - m_data(nullptr) { - move_image(std::move(image)); -} - -image::~image() { - reset(); -} - -image& image::operator=(const image& image) { - copy_image(image); - return *this; -} - -image& image::operator=(image&& image) { - move_image(std::move(image)); - return *this; -} - -void image::reset() { - if (m_own_data) { - delete[] m_data; - m_own_data = false; - m_data = nullptr; - } -} - -void image::copy_image(const image& image) { - reset(); - - m_spec = image.spec(); - std::size_t n = m_spec.required_data_size(); - - m_own_data = true; - m_data = new char[n]; - std::copy(image.data(), - image.data()+n, - m_data); -} - -void image::move_image(image&& image) { - std::swap(m_own_data, image.m_own_data); - std::swap(m_data, image.m_data); - std::swap(m_spec, image.m_spec); -} - -} // namespace clip diff --git a/tools/build.nr b/tools/build.nr index f754216..d75c403 100755 --- a/tools/build.nr +++ b/tools/build.nr @@ -1 +1 @@ -1716 \ No newline at end of file +1718 diff --git a/tools/create_includes.py b/tools/create_includes.py deleted file mode 100755 index 38ed9a3..0000000 --- a/tools/create_includes.py +++ /dev/null @@ -1,80 +0,0 @@ -# Note: This file is meant to be ran by CMake -# and it should not be ran manually. -# -# It uses hardcoded paths, relative to -# the root of the project (the OmniaX directory) -# therefore it is only meant to run directly -# from that directory and not form the -# OmniaX/tools directory (in which it is located). - -import os -import shutil -import os.path -import sys -from os import path - -verbose = False - -def run_fast_scandir(dir, ext): - subfolders, files = [], [] - - for f in os.scandir(dir): - if f.is_dir(): - subfolders.append(f.path) - if f.is_file(): - if os.path.splitext(f.name)[1].lower() in ext: - files.append(f.path) - - - for dir in list(subfolders): - sf, f = run_fast_scandir(dir, ext) - subfolders.extend(sf) - files.extend(f) - return subfolders, files - -def install_includes(source_dir, include_dir, exception_dirs): - _list = run_fast_scandir(source_dir, [".hpp", ".h", ".inl", ".cpp", ".c"]) - if path.exists(include_dir): - if verbose: - print("Removing old include directory...") - shutil.rmtree(include_dir) - os.mkdir(include_dir) - - for elem in _list[0]: - elem = elem[len(source_dir) + 1:] - elem = os.path.join(include_dir, elem) - #elem = include_dir + "/" + elem - os.mkdir(elem) - if verbose: - print("Creating Directory: " + elem) - - if verbose: - print("\n") - - for elem in _list[1]: - #new_elem = include_dir + "/" + elem[len(source_dir):] - new_elem = os.path.join(include_dir, elem[len(source_dir) + 1:]) - found = True - if elem.endswith(".c") or elem.endswith(".cpp"): - found = False - for exep in exception_dirs: - if new_elem.startswith(exep): - found = True - break - if found: - shutil.copy(elem, new_elem) - if verbose: - print("Creating File: " + new_elem) - - -if __name__ == "__main__": - if len(sys.argv) > 1 and sys.argv[1] == "--verbose": - verbose = True - #src_dir = "./src/omniax/" - #inc_dir = "./Build/include" - #excep_dirs = [inc_dir + "/vendor/GLAD", inc_dir + "/vendor/glm"] - src_dir = os.path.join(".", "src") - inc_dir = os.path.join(".", "Build", "include") - excep_dirs = [os.path.join(inc_dir, "vendor", "GLAD"), os.path.join(inc_dir, "vendor", "glm"), os.path.join(inc_dir, "vendor", "clip"), os.path.join(inc_dir, "vendor", "MiniAudio")] - install_includes(src_dir, inc_dir, excep_dirs) - diff --git a/tools/inc_bnr b/tools/inc_bnr index 0bd20cf..4a0e37b 100755 Binary files a/tools/inc_bnr and b/tools/inc_bnr differ diff --git a/tools/inc_bnr.exe b/tools/inc_bnr.exe index 2449335..ba3b943 100755 Binary files a/tools/inc_bnr.exe and b/tools/inc_bnr.exe differ