diff options
| author | maxim nikonov <maxim.nikonov@hqo.co> | 2026-02-05 15:21:34 +0500 |
|---|---|---|
| committer | maxim nikonov <maxim.nikonov@hqo.co> | 2026-02-05 15:21:34 +0500 |
| commit | db214d1145e46d527a46d1fc2519548d2c4d23f1 (patch) | |
| tree | cf0fd9922e4d54f6beb63888f9b28c8e2a787bdf | |
| parent | 75fc94d6c71fe686f6dde5b41ad91cba2f6bdd6f (diff) | |
wip: fork
186 files changed, 2813 insertions, 52943 deletions
diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..3d5dbc8a6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +> FLTK a.k.a. Fast Light Toolkit (see https://www.fltk.org/) +is a C++ widget library, initially written fully within > the subset of C++ we consider acceptable. +> Unfortunately, starting with versions 1.4.*, some 'new developers' moved the project to CMake, which is too bad already, and since 1.5.*, they started to "use more modern C++ features", which roughly means for us the project is dead. If we still want to have it, then we have to make a fork, perhaps basing on the latest 1.3.* version. +> Evaluation of the sources is still to be done to understand our options. It is very possible we'll have to drop the support for platforms we don't work with, may be even making it X-Window-only. What we really need is to bundle the sources with the part of Xlib on which FLTK depends, and get rid of external tools other than the compiler and make, if any. + + + +Restrictions for C++ + +No C++ standard library + +The so-called standard library of C++ must not be used in any form. Simply speaking, you must not include any header files that have no “.h” suffix and you must not use any names from that damn “namespace std”, neither with explicit std:: prefix, nor with the using namespace directive (as we'll see in the next section, the using directive is prohibited as such, because namespaces themselves are prohibited). + +Compilers usually provide “legacy” headers such as iostream.h, vector.h and the like. These are prohibited, too. + +Definitely it is strictly forbidden to include “plain C compatibility” headers such as cstdio, cstring and so on. As we already mentioned, some header files from the plain C standard library are not allowed, but many of them are allowed — and they must be included exactly as you would do it in plain C. + +People often ask one (stupid) question: okay, but what to use instead of the standard library? Sometimes it is possible to answer this question correctly. Instead of iostream, either plain C “high-level” input-output may be used (that is, the functions and types declared in stdio.h), or you can use i/o system calls such as open, close, read, write etc. directly. Instead of the (very stupid and ugly) string class, each particular software project may invent its own implementation. + +It is very important to understand (and accept!) that no replacement for STL templates (containers and algorithms) allowed, neither from other libraries, nor written by yoursef. Data structures are built exactly the same way as in plain C, manually, for every particular task. There is no such thing as “generic” data structures. Period. + +No standard-invented “features” + +None of the “features” introduced by the so-called “standards” is allowed here. Just to start with, your code must not contain any of the following keywords: using, namespace, typename (the class keyword is to be used in template arguments that represent types), nullptr (the numerical 0 must be used to denote the null address), auto (damn if you feel you need it, you're wrong: don't prevent the compiler from detecting your errors!), constexpr, consteval, constinit, noexcept, final, override, import, module, requires, export, co_yield, co_return, co_await, wchar_t, char8_t, char16_t, char32_t, alignas, alignof, register, static_assert, thread_local... + +Something may be missing from this list, but you've got the idea: if a new keyword is “added” by another damn “standard” or its meaning changed, then the keyword is prohibited here. + +Not only keywords are prohibited; all the “concepts” introduced in these “standards” are prohibited, too. Don't even think about all these lambdas, coroutines, structured bindings, move semantic (it is when a type for constructor's argument is declared with &&), variadic templates etc. + +Once again: everything that comes from C++ “standards” is prohibited. No exceptions from this rule are to be made, ever. + +No loop var definition within for head + +Please don't do this: + + for (int i = 0; i < 10; ++i) { +Instead, define your loop variable right before the loop head, like this: + + int i; + for (i = 0; i < 10; i++) { +Beware of exception handling + +C++ exception handling sometimes may save a lot of time and effort; actually, exceptions don't come from “standards”, and despite their terrible inefficiency, sometimes it is okay to use them. + +However, the idea behind the C++ exception handling (which is that a particular exceptional situation is to be identified by a type) is weird; furhtermore, implementation of C++ exceptions is a bloated piece of runtime, costs a lot of machine code being added to your functions, and all this mess is definitely no good; disabling exceptions with the compiler's flags may be desirable in many cases. + +So, a decision is to be made for each particular software project whether it will use exceptions or no. + +Please be specially careful with the decision if your project (or a part of it) is a software library. Using exceptions in a library means the library can't be used by projects that decide not to have exceptions. Perhaps the very minimum for a library must be a possibility to get rid of exceptions with a compile-time option, but if you implement such an option, you'll see there's no longer any gain from exceptions as you have to implement traditional error handling anyway. So it is always a better option for a library not to rely on exception handling. + +No RTTI nor dynamic_cast + +These are not from standards, too, but RTTI is too monstrous, and dynamic_cast is too slow. Don't use them both. + +No member pointers + +There is absolutely nothing wrong with member pointers, except for one thing: if you really need a member pointer, then your class (or structure, heh?) is overcomplicated. Instead of member pointers, better try to refactor your classes and methods so that they stop being that complicated. + +Default argument values + +Default values for arguments of functions and methods are discouraged but still allowed. However, we restrict what can serve as the default value. The standards are too liberal on this. Within the RebuildWorld project, only explicit compile-time constants may be used in this role. These include explicit numerical, char and string literals, macros that are known to expand to such literals, and enum constants. Nothing else is allowed. + +Templates are okay, but not for containers + +Many similar guides prohibit templates altogether. This might surprize you, but here we disagree: within the RebuildWorld project, templates as such are allowed. What is not allowed is using templates to create generic container classes and “algorithms” for them, like STL does. + +People often ask smth. like "hey, but what else templates can be used for?!" Okay, if you don't know the answer, then simply don't use templates at all. However, once you encounter a small task where templates can make things better (not being used to create another damn generic container), then, well, recall this section. + +For both languages + +#include"" vs. #include<> + +Before the committees touched all this stuff with their dirty hands, the difference between #include "" and #include <> was obvious: the form #include "" was used for the headers that belong to your program itself, while #include <> was for the header files external to your program, that is, headers from libraries, no matter whether it is the so-called “standard” library or any other. So this is the principle we continue to use, no matter what these brainless irresponsible terrorists invent (all these 'modules', 'system directories' etc). + +In particular, all the libraries included within the source tarball are still libraries, so their headers must be included with #include <>. + +The #include "" form is only to be used for headers that belong to the main part of the program's code, that is, the part which the author or authors don't consider as libraries. Typically the main code is placed in its own directory. + +No GNU extensions + +Well, do we really have to mention that horrible things like nested functions, VLAs in C++ (which were initially introduced for plain C only, starting with the C99 'standard') and lots of other monsters that gcc supports as “extensions” are not to be used? Heh, actually they are so ugly that even damn standard committees don't want to adopt them.
\ No newline at end of file diff --git a/CMake/FLTK-Functions.cmake b/CMake/FLTK-Functions.cmake deleted file mode 100644 index a8d339fac..000000000 --- a/CMake/FLTK-Functions.cmake +++ /dev/null @@ -1,85 +0,0 @@ -# -# FLTK-Functions.cmake -# Originally written by Michael Surette -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -################################################################################ -# functions used by the build system and exported for the end-user -################################################################################ - -################################################################################ -# -# fltk_run_fluid: Run fluid to compile fluid (.fl) files -# -# Usage: fltk_run_fluid(SOURCES "FLUID_SOURCE [.. FLUID_SOURCE]") -# -# Input: The CMake variable "FL_FILES" must contain a list of input -# file names. Only names ending in ".fl" are considered and -# compiled to their ".cxx" and ".h" files which are stored -# in the current build directory. -# -# Output: "SOURCES" is used as a CMake variable name that is assigned the -# names of the compiled ".cxx" files as a ";" separated list in the -# parent scope (the caller's scope). -# -################################################################################ - -function(fltk_run_fluid SOURCES FL_FILES) - - if(NOT FLTK_FLUID_EXECUTABLE) - message(WARNING "Not building ${FL_FILES}. FLUID executable not found.") - return() - endif() - - set(CXX_FILES) - foreach(src ${FL_FILES}) - if("${src}" MATCHES "\\.fl$") - string(REGEX REPLACE "(.*).fl" \\1 basename ${src}) - add_custom_command( - OUTPUT "${basename}.cxx" "${basename}.h" - COMMAND ${FLTK_FLUID_EXECUTABLE} -c ${CMAKE_CURRENT_SOURCE_DIR}/${src} - DEPENDS ${src} - MAIN_DEPENDENCY ${src} - ) - list(APPEND CXX_FILES "${basename}.cxx") - endif() - endforeach() - set(${SOURCES} ${CXX_FILES} PARENT_SCOPE) - -endfunction(fltk_run_fluid SOURCES FL_FILES) - - -################################################################################ -# -# fltk_set_bundle_icon: Set the bundle icon for macOS bundles -# -# This function sets macOS specific target properties. These properties are -# ignored on other platforms. -# -# Usage: fltk_set_bundle_icon(TARGET ICON_PATH) -# -# TARGET must be a valid CMake target that has been created before this -# function is called. It must not be an alias name. -# -################################################################################ - -function(fltk_set_bundle_icon TARGET ICON_PATH) - get_filename_component(ICON_NAME "${ICON_PATH}" NAME) - set_target_properties(${TARGET} - PROPERTIES - MACOSX_BUNDLE_ICON_FILE "${ICON_NAME}" - RESOURCE "${ICON_PATH}" - ) -endfunction(fltk_set_bundle_icon TARGET ICON_PATH) diff --git a/CMake/FLTKConfig.cmake.in b/CMake/FLTKConfig.cmake.in deleted file mode 100644 index b183bc80f..000000000 --- a/CMake/FLTKConfig.cmake.in +++ /dev/null @@ -1,144 +0,0 @@ -# -# FLTKConfig.cmake - FLTK CMake configuration file for external projects. -# -# This file is generated by CMake and used to load FLTK's settings for -# an external project, i.e. a project using FLTK. -# -# It defines the following variables: -# -# FLTK_VERSION - FLTK version string ("x.y.z") -# FLTK_INCLUDE_DIRS - FLTK include directories -# FLTK_LIBRARIES - list of built FLTK libraries -# FLTK_FLUID_EXECUTABLE - needed by the function FLTK_RUN_FLUID -# (or the deprecated fltk_wrap_ui() CMake command) -# -# It defines the following deprecated variables for backwards -# compatibility (do not use for new projects): -# -# FLTK_INCLUDE_DIR - FLTK include directories (same as FLTK_INCLUDE_DIRS) -# -# Important note: FLTK's CMake build files are not yet complete and may be -# changed in future versions. This includes the list of defined variables -# above that may be changed if necessary. -# -# Note: FLTK 1.4.0 introduced "Modern CMake", therefore usage of most if not -# all of the variables mentioned above is no longer needed in user projects. -# Please use the CMake target names fltk::fltk, fltk::images, etc. instead. -# Please see README.CMake.txt for more info on how to do this. -# - -# Optional: Create backwards compatible aliases for libraries and fluid. -# This is enabled in FLTK 1.4.0 to simplify migration of user projects -# from "classic" (1.3.x) to "modern" CMake and will likely be removed -# in a later FLTK version (maybe 1.4.x, x>2, or 1.5.0). - -set(FLTK_CREATE_COMPATIBILITY_ALIASES TRUE) - -set(FLTK_VERSION @FLTK_VERSION@) - -include(${CMAKE_CURRENT_LIST_DIR}/FLTK-Targets.cmake) - -set(FLTK_INCLUDE_DIRS "@INCLUDE_DIRS@") -set(FLTK_LIBRARIES "@FLTK_LIBRARIES@") - -# For compatibility with CMake's FindFLTK.cmake: - -set(FLTK_INCLUDE_DIR "${FLTK_INCLUDE_DIRS}") - -if(CMAKE_CROSSCOMPILING) - - # Find a fluid executable on the build host to be able to build fluid programs - - find_program(FLTK_FLUID_HOST - NAMES fluid fluid.exe - PATHS ENV PATH - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH - ) - - if(FLTK_FLUID_HOST) - - if(0) # Experimental: currently not used - # Import a special 'fluid' target called 'fluid-host' (fltk::fluid-host) - # Note: this is "the same as" the CMake variable FLTK_FLUID_EXECUTABLE - add_executable(fluid-host IMPORTED) - set_target_properties(fluid-host - PROPERTIES IMPORTED_LOCATION ${FLTK_FLUID_HOST} - ) - add_executable(fltk::fluid-host ALIAS fluid-host) - set(FLTK_FLUID_EXECUTABLE fltk::fluid-host) - - else() - - set(FLTK_FLUID_EXECUTABLE "${FLTK_FLUID_HOST}") - - endif() - - else() # fluid not found on build host - - message(STATUS "FLTKConfig.cmake (cross-compiling): fluid not found on the build host") - # note: this assigns "FLTK_FLUID_HOST-NOTFOUND" and running fluid will fail - set(FLTK_FLUID_EXECUTABLE "${FLTK_FLUID_HOST}") - - endif() - -else(CMAKE_CROSSCOMPILING) - - if(FLTK_CREATE_COMPATIBILITY_ALIASES) - - function(_fltk_make_alias target from) - if(TARGET ${from} AND NOT TARGET ${target}) - # message(STATUS "FLTKConfig.cmake - create alias: ${target} from ${from}") - - # promote imported target to global visibility (CMake < 3.18 only) - if(CMAKE_VERSION VERSION_LESS "3.18") - set_target_properties(${from} PROPERTIES IMPORTED_GLOBAL TRUE) - endif() - - get_target_property(ttype ${from} TYPE) - if(ttype STREQUAL "EXECUTABLE") - add_executable(${target} ALIAS ${from}) - else() - add_library(${target} ALIAS ${from}) - endif() - endif() - endfunction(_fltk_make_alias target) - - if(NOT TARGET fltk::fltk) - message(FATAL "FLTKConfig.cmake: target fltk::fltk does not exist!") - endif() - - _fltk_make_alias(fltk fltk::fltk) - _fltk_make_alias(fltk-shared fltk::fltk-shared) - - _fltk_make_alias(fluid fltk::fluid) - _fltk_make_alias(fluid-cmd fltk::fluid-cmd) - - _fltk_make_alias(fltk-options fltk::options) - _fltk_make_alias(fltk-options-cmd fltk::options-cmd) - - foreach(target forms gl images jpeg png z) - _fltk_make_alias(fltk_${target} fltk::${target}) - _fltk_make_alias(fltk_${target}-shared fltk::${target}-shared) - endforeach() - - endif() # Create aliases ... - - # set FLTK_FLUID_EXECUTABLE: try to use the fltk::target name if it - # exists and fall back to 'fluid-cmd' or 'fluid' if not. This will - # eventually call the build host's fluid if found in the users's PATH - - if(TARGET fltk::fluid-cmd) # Windows only - set(FLTK_FLUID_EXECUTABLE fltk::fluid-cmd) - elseif(TARGET fltk::fluid) - set(FLTK_FLUID_EXECUTABLE fltk::fluid) - elseif(WIN32) - set(FLTK_FLUID_EXECUTABLE fluid-cmd) - else() - set(FLTK_FLUID_EXECUTABLE fluid) - endif() - -endif(CMAKE_CROSSCOMPILING) - -# Debug: should be commented out -# message(STATUS "FLTKConfig.cmake: FLTK_FLUID_EXECUTABLE = '${FLTK_FLUID_EXECUTABLE}'") diff --git a/CMake/MacOSXBundleInfo.plist.in b/CMake/MacOSXBundleInfo.plist.in deleted file mode 100644 index c5b643d6e..000000000 --- a/CMake/MacOSXBundleInfo.plist.in +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleExecutable</key> - <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string> - <key>CFBundleGetInfoString</key> - <string>${MACOSX_BUNDLE_INFO_STRING}</string> - <key>CFBundleIconFile</key> - <string>${MACOSX_BUNDLE_ICON_FILE}</string> - <key>CFBundleIdentifier</key> - <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleLongVersionString</key> - <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string> - <key>CFBundleName</key> - <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> - <key>CFBundleSignature</key> - <string>????</string> - <key>CFBundleVersion</key> - <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string> - <key>CSResourcesFileMapped</key> - <true/> - <key>NSHumanReadableCopyright</key> - <string>${MACOSX_BUNDLE_COPYRIGHT}</string> - <key>NSHighResolutionCapable</key> - <true/> -</dict> -</plist> diff --git a/CMake/cmake_uninstall.cmake.in b/CMake/cmake_uninstall.cmake.in deleted file mode 100644 index efd90e47f..000000000 --- a/CMake/cmake_uninstall.cmake.in +++ /dev/null @@ -1,57 +0,0 @@ -# -# Support file to uninstall the FLTK project using CMake -# -# Originally written by Michael Surette -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR - "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -endif() - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") - -# Note 1: 'cmake -E remove [-f]' is deprecated since CMake 3.17 and the docs -# state: "The implementation was buggy and always returned 0. It cannot be -# fixed without breaking backwards compatibility. Use rm instead." -# Note 2: 'cmake -E rm [-f]' has been added in CMake 3.17 -# Note 3: -# Remove this distinction if: cmake_minimum_required(VERSION 3.17) or higher. - -if(CMAKE_VERSION VERSION_LESS 3.17) - set(rm_cmd remove) -else() - set(rm_cmd rm) -endif() - -foreach(file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - execute_process( - COMMAND "${CMAKE_COMMAND}" -E ${rm_cmd} -f "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - ERROR_VARIABLE rm_err - RESULT_VARIABLE rm_retval - ) - - if(NOT "${rm_retval}" STREQUAL 0) - message(STATUS "Error removing \"$ENV{DESTDIR}${file}\"") - message(STATUS " Status = '${rm_retval}'") - message(STATUS " Output = '${rm_out}'") - message(STATUS " Error = '${rm_err}'") - message(FATAL_ERROR "Exiting - uninstall may be incomplete.") - endif() - -endforeach(file) diff --git a/CMake/compatibility.cmake b/CMake/compatibility.cmake deleted file mode 100644 index ba48d80e9..000000000 --- a/CMake/compatibility.cmake +++ /dev/null @@ -1,70 +0,0 @@ -# -# CMake compatibility functions and macros for the Fast Light Tool Kit (FLTK) -# -# Copyright 1998-2023 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -################################################################################ -# -# The functions and maybe macros in this file are defined to simplify CMake -# code that uses features not available in all supported CMake versions. -# Functions should be preferred (rather than macros) because functions -# have their own variable scope. -# -# The function must apply a workaround for older versions or not add code -# at all if there is no suitable workaround. -# -# The functions included here may be removed (with according changes of the -# calling code) or the workaround code may be removed from the implementation -# after cmake_minimum_required() has been raised to a version number greater -# than or equal to the required version. -# -# Current cmake_minimum_required() version: see <fltk-root>/CMakeLists.txt -# -################################################################################ - - -# Right now we don't need compatibility functions -# This file is currently "empty" but left for documentation purposes -# An example function documentation follows... - - -################################################################################ -# -# function fl_target_link_directories - add link directories to target -# -# Requires CMake version: 3.13 -# https://cmake.org/cmake/help/latest/command/target_link_directories.html -# -# Input: -# -# - TARGET: target to add link directories to, e.g. fluid -# -# - SCOPE: one of <INTERFACE|PUBLIC|PRIVATE> (see CMake docs) -# -# - DIRS: quoted list of link directories (separated by ';') -# -# The 'DIRS' argument takes a standard CMake list of directories, i.e. the -# individual members must be separated by ';'. The list may be empty (""). -# If more than one directory is to be added or if the list of directories -# can be empty it *must* be quoted. This function may be called more than -# once. Each invocation adds zero, one, or more directories. -# -# Example: -# -# fl_target_link_directories(fluid PRIVATE "${PKG_CAIRO_LIBRARY_DIRS}") -# -# In this example 'PKG_CAIRO_LIBRARY_DIRS' is platform dependent and -# can be an empty list. -# -################################################################################ diff --git a/CMake/export.cmake b/CMake/export.cmake deleted file mode 100644 index 407b24933..000000000 --- a/CMake/export.cmake +++ /dev/null @@ -1,150 +0,0 @@ -# -# Export CMake file to build the FLTK project using CMake -# -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# final config and export -####################################################################### - -# Set the fluid executable path used to create .cxx/.h from .fl files - -if(FLTK_BUILD_FLUID AND NOT CMAKE_CROSSCOMPILING) - # Use the fluid executable we build using its namespaced target name - if(WIN32) - set(FLTK_FLUID_EXECUTABLE fltk::fluid-cmd) - set(FLUID_EXPORT fluid fluid-cmd) # export fluid and fluid-cmd - else() - set(FLTK_FLUID_EXECUTABLE fltk::fluid) - set(FLUID_EXPORT fluid) # export fluid - endif() -else() - # We don't build fluid /or/ we are cross-compiling (or both): - # we need to find a fluid executable on the build host. - # The search is restricted to the user's PATH (environment). - find_program(FLTK_FLUID_HOST - NAMES fluid fluid.exe - PATHS ENV PATH - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH - ) - if(NOT FLTK_FLUID_HOST) - message(STATUS "Warning: fluid not found on the build system!") - endif() - # Note: this *may* assign "FLTK_FLUID_HOST-NOTFOUND" - set(FLTK_FLUID_EXECUTABLE "${FLTK_FLUID_HOST}") - set(FLUID_EXPORT "") # don't export fluid -endif(FLTK_BUILD_FLUID AND NOT CMAKE_CROSSCOMPILING) - -if(0) # Debug - message(STATUS "##############################################################") - message(STATUS "[export.cmake] INFO: Did we find fluid?") - fl_debug_var(FLTK_FLUID_HOST) - fl_debug_var(FLTK_FLUID_EXECUTABLE) - fl_debug_var(FLTK_BUILD_FLUID) - fl_debug_var(CMAKE_CROSSCOMPILING) - message(STATUS "##############################################################") -endif() - -# set fltk-options export names (built or not, Windows) -if(FLTK_BUILD_FLTK_OPTIONS) - set(FLTK_OPTIONS_EXPORT fltk-options) - if(WIN32) - list(APPEND FLTK_OPTIONS_EXPORT fltk-options-cmd) - endif() -else() - set(FLTK_OPTIONS_EXPORT) -endif() - -# generate FLTK-Targets.cmake for build directory use -set(export_targets - ${FLTK_LIBRARIES} - ${FLTK_LIBRARIES_SHARED} - ${FLUID_EXPORT} - ${FLTK_OPTIONS_EXPORT} -) -export(TARGETS - ${export_targets} - FILE - ${CMAKE_CURRENT_BINARY_DIR}/FLTK-Targets.cmake - NAMESPACE - fltk::) - -# generate FLTK-Functions.cmake for build directory use -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/FLTK-Functions.cmake - ${CMAKE_CURRENT_BINARY_DIR}/FLTK-Functions.cmake - COPYONLY -) - -# generate FLTKConfig.cmake for build directory use -set(INCLUDE_DIRS "${FLTK_INCLUDE_DIRS}") -if(FLTK_HAVE_CAIRO OR FLTK_USE_CAIRO) - list(APPEND INCLUDE_DIRS ${PKG_CAIRO_INCLUDE_DIRS}) -endif() -list(REMOVE_DUPLICATES INCLUDE_DIRS) -set(CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR}) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/FLTKConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/FLTKConfig.cmake - @ONLY -) - -# generate fltk-config for build directory use -set(prefix ${CMAKE_CURRENT_BINARY_DIR}) -set(exec_prefix "\${prefix}") -set(includedir "${CMAKE_CURRENT_SOURCE_DIR}") -set(BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") -set(libdir "\${exec_prefix}/lib") -set(srcdir ".") - -set(LIBNAME "${libdir}/libfltk.a") - -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/fltk-config.in" - "${CMAKE_CURRENT_BINARY_DIR}/fltk-config" - @ONLY -) - -# Set execute permissions on fltk-config in the build directory. -# Note: file(CHMOD) is available since CMake 3.19, -# use fallback before CMake 3.19 - -if(CMAKE_VERSION VERSION_LESS 3.19) - if(UNIX OR MSYS OR MINGW) - execute_process(COMMAND chmod 755 fltk-config - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() -else(CMAKE_VERSION VERSION_LESS 3.19) - file(CHMOD "${CMAKE_CURRENT_BINARY_DIR}/fltk-config" - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE) -endif(CMAKE_VERSION VERSION_LESS 3.19) - -if(FLTK_INSTALL_LINKS) - # Set PREFIX_INCLUDE to the proper value. - if(IS_ABSOLUTE ${FLTK_INCLUDEDIR}) - set(PREFIX_INCLUDE ${FLTK_INCLUDEDIR}) - else() - set(PREFIX_INCLUDE "${CMAKE_INSTALL_PREFIX}/${FLTK_INCLUDEDIR}") - endif(IS_ABSOLUTE ${FLTK_INCLUDEDIR}) - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/CMake/install-symlinks.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/install-symlinks.cmake" - @ONLY) -endif(FLTK_INSTALL_LINKS) diff --git a/CMake/fl_add_library.cmake b/CMake/fl_add_library.cmake deleted file mode 100644 index 8806de191..000000000 --- a/CMake/fl_add_library.cmake +++ /dev/null @@ -1,257 +0,0 @@ -# -# Macro used by the CMake build system for the Fast Light Tool Kit (FLTK). -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# fl_add_library - add a static or shared library to the build -#====================================================================== -# -# Input: -# -# LIBNAME: name of the library, including 'fltk_' prefix if applicable. -# -# LIBTYPE: either "STATIC" or "SHARED" -# -# SOURCES: Files needed to build the library -# -# Output: -# -# FLTK_LIBRARIES or FLTK_LIBRARIES_SHARED (in parent scope) -# -# This function adds the given library to the build, adds it to -# either FLTK_LIBRARIES or FLTK_LIBRARIES_SHARED, respectively, -# and "exports" the modified variable to the parent scope. -# -# For each library an alias is defined (see comment below). -# -####################################################################### - -function(fl_add_library LIBNAME LIBTYPE SOURCES) - - # message(STATUS "Building library **************** ${LIBNAME} ${LIBTYPE}") - - set(suffix "") - if(LIBTYPE STREQUAL "SHARED") - set(suffix "-shared") - endif() - - set(TARGET_NAME ${LIBNAME}${suffix}) - - ## Strip 'fltk_' from target name (if it exists in the name) - ## and use the result as EXPORT_NAME property. This makes it - ## easy to export library targets fltk::fltk and fltk::images - ## rather than fltk::fltk_images. - - string(REPLACE "fltk_" "" EXPORT_NAME ${TARGET_NAME}) - - if(MSVC) - set(OUTPUT_NAME_DEBUG "${LIBNAME}d") - else() - set(OUTPUT_NAME_DEBUG "${LIBNAME}") - endif(MSVC) - - set(OUTPUT_NAME_RELEASE "${LIBNAME}") - - add_library(${TARGET_NAME} ${LIBTYPE} ${SOURCES}) - - # Create an alias 'fltk::alias_name' for the library - # where 'alias_name' is the library name without the prefix 'fltk_' - # - # e.g. 'fltk' -> 'fltk::fltk' - # and 'fltk-shared' -> 'fltk::fltk-shared' - # but 'fltk_images' -> 'fltk::images' - # and 'fltk_images-shared' -> 'fltk::images-shared' - - if(NOT (LIBNAME STREQUAL "fltk")) - string(REPLACE "fltk_" "" alias_name ${LIBNAME}) - else() - set(alias_name ${LIBNAME}) - endif() - set(alias_name "fltk::${alias_name}${suffix}") - - add_library(${alias_name} ALIAS ${TARGET_NAME}) - - if(0) - fl_debug_var(TARGET_NAME) - fl_debug_var(LIBTYPE) - fl_debug_var(alias_name) - # fl_debug_var(SOURCES) - endif() - - # Target properties for all libraries - - # Set 'PRIVATE' target compile definitions for the library - # so they are not inherited by consumers - - target_compile_definitions(${TARGET_NAME} PRIVATE "FL_LIBRARY") - - # Set PUBLIC properties, e.g. C++ standard and include and linker directories. - # These properties are inherited by consumers of the libraries - - target_compile_features(${TARGET_NAME} PUBLIC "cxx_std_${CMAKE_CXX_STANDARD}") - - if(0) # DEBUG - message(STATUS "fl_add_library and alias : fltk::${alias_name} ALIAS ${TARGET_NAME}") - fl_debug_var(TARGET_NAME) - fl_debug_var(FLTK_INCLUDE_DIRS) - fl_debug_var(CMAKE_CURRENT_BINARY_DIR) - fl_debug_var(CMAKE_CURRENT_SOURCE_DIR) - fl_debug_var(FLTK_BUILD_INCLUDE_DIRECTORIES) - endif() - - # Special handling for the core 'fltk' library, - # no matter if it's SHARED or STATIC - # FIXME: maybe this should be in src/CMakeLists.txt (?) - - if(LIBNAME STREQUAL "fltk") - - target_include_directories(${TARGET_NAME} PUBLIC - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..> - $<INSTALL_INTERFACE:include> - ) - - ### FIXME: why does the simplified else() block not work? - ### Needs investigation, using 'if(1)' for now... - - if(1) - - foreach(dir ${FLTK_BUILD_INCLUDE_DIRECTORIES}) - target_include_directories(${TARGET_NAME} PRIVATE - $<BUILD_INTERFACE:${dir}> - ) - endforeach() - - else() - - ### This generates a wrong string in property INTERFACE_INCLUDE_DIRECTORIES: - ### ... $<INSTALL_INTERFACE:include>;/git/fltk/modern-cmake/src/$<BUILD_INTERFACE:/usr/include/freetype2; ... - ### ... --- OK ---------------------^^^^^^^ WRONG ^^^^^^^^^^^^^^-------- would be OK -------------------- ... - ### End of string: ';/usr/include/libpng16' (WRONG: missing '>') - ### I don't see anything wrong with this statement though but - ### maybe I'm missing something. Albrecht, Jan 22 2024 - - target_include_directories(${TARGET_NAME} PRIVATE - $<BUILD_INTERFACE:${FLTK_BUILD_INCLUDE_DIRECTORIES}> - ) - - endif() - - target_link_directories(${TARGET_NAME} PUBLIC - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../lib> - $<INSTALL_INTERFACE:lib> - ) - - if(APPLE AND NOT FLTK_BACKEND_X11) - foreach(item ${FLTK_COCOA_FRAMEWORKS}) - target_link_libraries(${TARGET_NAME} PUBLIC "${item}") - endforeach() - endif() - - # we must link fltk with cairo if Cairo or Wayland is enabled (or both) - if(FLTK_HAVE_CAIRO OR FLTK_USE_CAIRO) - target_include_directories(${TARGET_NAME} PUBLIC ${PKG_CAIRO_INCLUDE_DIRS}) - target_link_directories (${TARGET_NAME} PUBLIC ${PKG_CAIRO_LIBRARY_DIRS}) - target_link_libraries (${TARGET_NAME} PUBLIC ${PKG_CAIRO_LIBRARIES}) - endif() - - endif(LIBNAME STREQUAL "fltk") - - # Set additional target properties for static libraries - - if(LIBTYPE STREQUAL "STATIC") - set_target_properties(${TARGET_NAME} - PROPERTIES - OUTPUT_NAME ${LIBNAME} - OUTPUT_NAME_DEBUG ${OUTPUT_NAME_DEBUG} - OUTPUT_NAME_RELEASE ${OUTPUT_NAME_RELEASE} - EXPORT_NAME ${EXPORT_NAME} - ) - endif(LIBTYPE STREQUAL "STATIC") - - # Set additional target properties for shared (dynamic) libraries (DLL's) - - if(LIBTYPE STREQUAL "SHARED") - set_target_properties(${TARGET_NAME} PROPERTIES - VERSION ${FLTK_VERSION} - SOVERSION ${FLTK_VERSION_MAJOR}.${FLTK_VERSION_MINOR} - OUTPUT_NAME ${LIBNAME} - OUTPUT_NAME_DEBUG ${OUTPUT_NAME_DEBUG} - OUTPUT_NAME_RELEASE ${OUTPUT_NAME_RELEASE} - EXPORT_NAME ${EXPORT_NAME} - ) - # Visual Studio only: - if(MSVC) - set_target_properties(${TARGET_NAME} PROPERTIES - OUTPUT_NAME ${LIBNAME}_dll - OUTPUT_NAME_DEBUG ${LIBNAME}_dlld - OUTPUT_NAME_RELEASE ${LIBNAME}_dll - ) - target_compile_definitions(${TARGET_NAME} PUBLIC FL_DLL) - endif(MSVC) - endif(LIBTYPE STREQUAL "SHARED") - - # Debug library output names (optional) - set(DEBUG_ONAME 0) - - if(DEBUG_ONAME) - get_target_property(XX_NAME ${TARGET_NAME} NAME) - get_target_property(XX_ONAME ${TARGET_NAME} OUTPUT_NAME) - get_target_property(XX_ONAME_DEBUG ${TARGET_NAME} OUTPUT_NAME_DEBUG) - get_target_property(XX_ONAME_RELEASE ${TARGET_NAME} OUTPUT_NAME_RELEASE) - get_target_property(XX_EXPORT_NAME ${TARGET_NAME} EXPORT_NAME) - - message(STATUS "--- DEBUG_ONAME ---") - fl_debug_var(TARGET_NAME) - fl_debug_var(XX_NAME) - fl_debug_var(XX_ONAME) - fl_debug_var(XX_ONAME_DEBUG) - fl_debug_var(XX_ONAME_RELEASE) - fl_debug_var(XX_EXPORT_NAME) - message(STATUS "--- /DEBUG_ONAME ---") - endif(DEBUG_ONAME) - - if(MSVC) - if(FLTK_OPTION_LARGE_FILE) - set_target_properties(${TARGET_NAME} PROPERTIES - LINK_FLAGS /LARGEADDRESSAWARE - ) - endif(FLTK_OPTION_LARGE_FILE) - endif(MSVC) - - install(TARGETS ${TARGET_NAME} EXPORT FLTK-Targets - RUNTIME DESTINATION ${FLTK_BINDIR} - LIBRARY DESTINATION ${FLTK_LIBDIR} - ARCHIVE DESTINATION ${FLTK_LIBDIR} - ) - - if(LIBTYPE STREQUAL "SHARED") - list(APPEND FLTK_LIBRARIES_SHARED "${TARGET_NAME}") - set(FLTK_LIBRARIES_SHARED "${FLTK_LIBRARIES_SHARED}" PARENT_SCOPE) - else() - list(APPEND FLTK_LIBRARIES "${TARGET_NAME}") - set(FLTK_LIBRARIES "${FLTK_LIBRARIES}" PARENT_SCOPE) - endif() - - if(0) - fl_debug_var(fl_add_library_DEBUG) - fl_debug_var(FLTK_LIBRARIES) - fl_debug_var(FLTK_LIBRARIES_SHARED) - fl_debug_var(fl_add_library_END) - message("") - endif() - -endfunction(fl_add_library LIBNAME LIBTYPE SOURCES) diff --git a/CMake/fl_create_example.cmake b/CMake/fl_create_example.cmake deleted file mode 100644 index 571e33b43..000000000 --- a/CMake/fl_create_example.cmake +++ /dev/null @@ -1,173 +0,0 @@ -# -# A function used by the CMake build system for the Fast Light Tool Kit (FLTK). -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -################################################################################ -# -# function fl_create_example - Create a test/demo (example) program -# -# Input: -# -# - NAME: program name, e.g. 'hello' -# -# - SOURCES: list of source files, separated by ';' (needs quotes) -# Sources can be: -# - .c/.cxx files, e.g. 'hello.cxx' -# - .fl (fluid) files, e.g. 'radio.fl' -# - .plist file(macOS), e.g. 'editor.plist' -# - .icns file(macOS Icon), e.g. 'checkers.icns' -# - .rc file(Windows resource file, e.g. icon definition) -# -# Order of sources doesn't matter, multiple .cxx and .fl files are -# supported, but only one .plist and one .icns file. -# -# File name (type), e.g. '.icns' matters, it is parsed internally: -# File types .fl, .plist, and .icns are treated specifically, -# all other file types are added to the target's source files. -# -# macOS specific .icns and .plist files are ignored on other platforms. -# These files must reside in the subdirectory 'mac-resources'. -# -# - LIBRARIES: -# List of libraries (CMake target names), separated by ';'. Must be -# quoted if more than one library is required, e.g. "fltk::gl;fltk::images" -# -################################################################################ - -function(fl_create_example NAME SOURCES LIBRARIES) - - set(srcs) # source files - set(flsrcs) # fluid source (.fl) files - set(TARGET_NAME ${NAME}) # CMake target name - set(ICON_NAME) # macOS icon (max. one) - set(PLIST) # macOS .plist file(max. one) - set(ICON_PATH) # macOS icon resource path - - # create macOS bundle? 0 = no, 1 = yes - - if(APPLE AND NOT FLTK_BACKEND_X11) - set(MAC_BUNDLE 1) - else() - set(MAC_BUNDLE 0) - endif() - - # filter input files for different handling (fluid, icon, plist, source) - - foreach(src ${SOURCES}) - if("${src}" MATCHES "\\.fl$") - list(APPEND flsrcs ${src}) - elseif("${src}" MATCHES "\\.icns$") - set(ICON_NAME "${src}") - elseif("${src}" MATCHES "\\.plist$") - set(PLIST "${src}") - else() - list(APPEND srcs ${src}) - endif("${src}" MATCHES "\\.fl$") - endforeach(src) - - # generate source files from .fl files, add output to sources - - if(flsrcs) - if(NOT FLTK_FLUID_EXECUTABLE) - message(STATUS "Example app \"${NAME}\" will not be built. FLUID executable not found.") - return () - endif() - FLTK_RUN_FLUID (FLUID_SOURCES "${flsrcs}") - list(APPEND srcs ${FLUID_SOURCES}) - unset(FLUID_SOURCES) - endif(flsrcs) - - # set macOS (icon) resource path if applicable - - if(MAC_BUNDLE AND ICON_NAME) - set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/mac-resources/${ICON_NAME}") - endif(MAC_BUNDLE AND ICON_NAME) - - ############################################################################## - # add executable target and set properties (all platforms) - ############################################################################## - - if(MAC_BUNDLE) - add_executable (${TARGET_NAME} MACOSX_BUNDLE ${srcs} ${ICON_PATH}) - else() - add_executable (${TARGET_NAME} WIN32 ${srcs}) - endif(MAC_BUNDLE) - - set_target_properties (${TARGET_NAME} PROPERTIES OUTPUT_NAME ${NAME}) - target_link_libraries (${TARGET_NAME} PRIVATE ${LIBRARIES}) - - # make sure we're "exporting" global symbols like 'fl_disable_wayland', - # see also README.Wayland.txt and CMake policy CMP0065. - - set_target_properties (${TARGET_NAME} PROPERTIES ENABLE_EXPORTS TRUE) - - - # Search the current binary directory for header files created by CMake - # or fluid and the source folder for other headers included by test programs - - target_include_directories(${TARGET_NAME} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ) - - if(MAC_BUNDLE) - if(PLIST) - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST - "${CMAKE_CURRENT_SOURCE_DIR}/mac-resources/${PLIST}") - endif() - - string(REPLACE "_" "-" FLTK_BUNDLE_ID "org.fltk.${TARGET_NAME}") - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "${TARGET_NAME}") - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "${FLTK_BUNDLE_ID}") - set_target_properties(${TARGET_NAME} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${FLTK_BUNDLE_ID}") - - if(ICON_NAME) - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE ${ICON_NAME}) - set_target_properties(${TARGET_NAME} PROPERTIES RESOURCE ${ICON_PATH}) - endif() - endif() - - ############################################################################## - # Copy macOS "bundle wrapper" (shell script) to target directory. - # The "custom command" will be executed "POST_BUILD". - ############################################################################## - - if(MAC_BUNDLE) - set(WRAPPER "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/${TARGET_NAME}") - - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND cp ${FLTK_SOURCE_DIR}/CMake/macOS-bundle-wrapper.in ${WRAPPER} - COMMAND chmod u+x,g+x,o+x ${WRAPPER} - BYPRODUCTS ${WRAPPER} - # COMMENT "Creating macOS bundle wrapper script ${WRAPPER}" - VERBATIM - ) - unset(WRAPPER) - endif(MAC_BUNDLE) - - ############################################################################## - # MSVC: Add fltk-shared (DLL) path to Environment 'PATH' for debugging - ############################################################################## - - if(MSVC AND TARGET fltk-shared) - set(DllDir "$<SHELL_PATH:$<TARGET_FILE_DIR:fltk-shared>>") - set_target_properties(${TARGET_NAME} PROPERTIES - VS_DEBUGGER_ENVIRONMENT "PATH=${DllDir};$ENV{PATH}" - ) - endif() - -endfunction() diff --git a/CMake/fl_debug_pkg.cmake b/CMake/fl_debug_pkg.cmake deleted file mode 100644 index 4e4030102..000000000 --- a/CMake/fl_debug_pkg.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# -# Macro used by the CMake build system for the Fast Light Tool Kit (FLTK). -# -# Copyright 2022 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# fl_debug_pkg - a macro to output pkgconfig debugging info -####################################################################### -# -# This macro displays the name and value of some CMake variables -# defined by pkg_check_modules(). -# -# Syntax: -# -# fl_debug_pkg(PREFIX NAME) -# -# Example for package "cairo": -# -# pkg_check_modules (CAIRO cairo) -# fl_debug_pkg(CAIRO cairo) -# -# The first command searches for pkg 'cairo' and stores the results -# in CMake variables with prefix 'CAIRO_'. -# -# The second command displays all relevant variables if the package has -# been found, otherwise only 'CAIRO_FOUND' (empty or false). -# -####################################################################### - -macro(fl_debug_pkg PREFIX NAME) - message("") - message(STATUS "Results of pkg_check_modules(${PREFIX}, ${NAME}):") - fl_debug_var(${PREFIX}_FOUND) - if(${PREFIX}_FOUND) - - fl_debug_var(${PREFIX}_INCLUDE_DIRS) - fl_debug_var(${PREFIX}_CFLAGS) - fl_debug_var(${PREFIX}_LIBRARIES) - fl_debug_var(${PREFIX}_LINK_LIBRARIES) - fl_debug_var(${PREFIX}_LIBRARY_DIRS) - fl_debug_var(${PREFIX}_LDFLAGS) - fl_debug_var(${PREFIX}_LDFLAGS_OTHER) - fl_debug_var(${PREFIX}_CFLAGS_OTHER) - - fl_debug_var(${PREFIX}_STATIC_INCLUDE_DIRS) - fl_debug_var(${PREFIX}_STATIC_CFLAGS) - fl_debug_var(${PREFIX}_STATIC_LIBRARIES) - fl_debug_var(${PREFIX}_STATIC_LINK_LIBRARIES) - fl_debug_var(${PREFIX}_STATIC_LIBRARY_DIRS) - - fl_debug_var(${PREFIX}_VERSION) - fl_debug_var(${PREFIX}_PREFIX) - fl_debug_var(${PREFIX}_INCLUDEDIR) - fl_debug_var(${PREFIX}_LIBDIR) - - endif() - message("") -endmacro(fl_debug_pkg) diff --git a/CMake/fl_debug_var.cmake b/CMake/fl_debug_var.cmake deleted file mode 100644 index d583d7d0c..000000000 --- a/CMake/fl_debug_var.cmake +++ /dev/null @@ -1,144 +0,0 @@ -# -# Function used by the CMake build system for the Fast Light Tool Kit (FLTK). -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# fl_expand_name - a function to expand a variable name with spaces -####################################################################### -# -# This function returns a string comprising of the given name and -# enough spaces to have at least the given minimal length (min_len). -# Currently min_len must not be greater than 50. -# -# If the string is already at least min_len it is not changed, -# otherwise the string is returned to the given variable (out) -# in the parent scope. -# -# Syntax: -# fl_expand_name (out in min_len) -# -# Example: -# fl_expand_name (var WIN32 30) -# fl_expand_name (var UNIX 40) -# -####################################################################### - -function(fl_expand_name out in min_len) - string(LENGTH "${in}" len) - if(len LESS min_len) - set(spaces " ") - set(temp "${in}") - set(temp "${in}${spaces}${spaces}") - string(SUBSTRING "${temp}" 0 ${min_len} temp) - set(${out} "${temp}" PARENT_SCOPE) - else() - set(${out} "${in}" PARENT_SCOPE) - endif() -endfunction(fl_expand_name) - -####################################################################### -# fl_debug_var - a function to output debugging info -####################################################################### -# -# This function displays the name and value of a CMake variable. -# The variable name is expanded with spaces to be (at least) -# <min_len> (currently 30) characters wide for better readability. -# VARNAME must be a string literal, e.g. WIN32 or "WIN32". -# -# Syntax: -# fl_debug_var(VARNAME) -# -# Example: -# fl_debug_var(WIN32) -# fl_debug_var("UNIX") -# -####################################################################### - -function(fl_debug_var name) - set(var "${name}") - fl_expand_name(var "${name}" 40) - message(STATUS "${var} = '${${name}}'") -endfunction(fl_debug_var) - - -####################################################################### -# fl_debug_target - a function to output info about a target -####################################################################### -# -# This function displays properties of a CMake target. -# -# Currently there's a fixed number of properties. -# -# Syntax: -# fl_debug_target(target) -# -# Example: -# fl_debug_target(fltk) -# fl_debug_target(fluid) -# fl_debug_target(fltk_image) -# fl_debug_target(fltk::forms) -# -####################################################################### - -function(fl_debug_target name) - message(STATUS "+++ fl_debug_target(${name})") - set(var "${name}") - fl_expand_name(var "${name}" 40) - - if(NOT TARGET ${name}) - message(STATUS "${var} = <not a target>") - message(STATUS "") - return() - endif() - - get_target_property(_type ${name} TYPE) - # message(STATUS "${var} = target, type = ${_type}") - - # these properties are always supported: - set(_props NAME TYPE ALIASED_TARGET) - - # these properties can't be read from executable target types - ### if(NOT _type STREQUAL "EXECUTABLE") - ### list(APPEND _props - ### LOCATION - ### IMPORTED_LOCATION - ### INTERFACE_LOCATION) - ### endif() - - if(NOT _type STREQUAL "INTERFACE_LIBRARY" OR CMAKE_VERSION VERSION_GREATER_EQUAL "3.19") - # Before 3.19: "INTERFACE_LIBRARY targets may only have whitelisted properties" - list(APPEND _props - INCLUDE_DIRECTORIES - LINK_DIRECTORIES - LINK_LIBRARIES - COMPILE_DEFINITIONS) - endif() - - list(APPEND _props - INTERFACE_COMPILE_DEFINITIONS - INTERFACE_INCLUDE_DIRECTORIES - INTERFACE_LINK_DIRECTORIES - INTERFACE_LINK_LIBRARIES) - - foreach(prop ${_props}) - get_target_property(${prop} ${name} ${prop}) - if(NOT ${prop}) - set(${prop} "") - endif() - fl_debug_var(${prop}) - endforeach() - message(STATUS "") - -endfunction(fl_debug_target) diff --git a/CMake/fl_summary.cmake b/CMake/fl_summary.cmake deleted file mode 100644 index 2026e096e..000000000 --- a/CMake/fl_summary.cmake +++ /dev/null @@ -1,89 +0,0 @@ -# -# Macros used by the CMake build system for the Fast Light Tool Kit (FLTK). -# -# Copyright 2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -######################################################################## -# The macros in this file are used to generate the CMake build summary. -# Fixed widths of title fields are intentionally hard coded in two of -# these macros so we can easily change the alignment. -######################################################################## - -include(${CMAKE_CURRENT_LIST_DIR}/fl_debug_var.cmake) - -######################################################################## -# Output a summary line like "<title> <value>" -######################################################################## -# <title> will be expanded to a fixed width (can be empty) -# <value> text to be displayed -######################################################################## - -macro(fl_summary title value) - fl_expand_name(label "${title}" 30) - message(STATUS "${label} ${value}") -endmacro(fl_summary title value) - -######################################################################## -# Output a summary line like "<title> will be built ..." -# or "<title> will not be built ..." -######################################################################## -# title will be expanded to a fixed width (must not be empty) -# subdir = relative build directory (e.g. lib or bin/test) -# build = CMake variable name (bool): whether <title> is built -# option = option name the user can set to build <title> -######################################################################## - -macro(fl_summary_build title subdir build option) - if(${build}) - set(value "will be built in: ${CMAKE_CURRENT_BINARY_DIR}/${subdir}") - else() - set(value "will not be built (set ${option}=ON to build)") - endif() - fl_expand_name(label "${title}" 19) - message(STATUS "${label} ${value}") -endmacro(fl_summary_build title var subdir) - -######################################################################## -# Output a simple summary line like "<title> {Yes|No}" -######################################################################## -# title will be expanded to a fixed width (must not be empty) -# var = CMake variable name, must evaluate to true or false -######################################################################## - -macro(fl_summary_yn title var) - if(${var}) - set(value "Yes") - else() - set(value "No") - endif() - fl_summary("${title}" ${value}) -endmacro(fl_summary_yn title var) - -######################################################################## -# Output summary line for image libs (bundled or system libs) -######################################################################## -# title = "Image Libraries" or empty -# name = displayed name = { JPEG | PNG | ZLIB } -# lib = CMake library name (system library, if it was found) -######################################################################## - -macro(fl_summary_image title name lib) - fl_expand_name(name4 "${name}" 8) - if(FLTK_USE_BUNDLED_${name}) - set(value "${name4} = Bundled") - else() - set(value "${name4} = System: ${${lib}}") - endif() - fl_summary("${title}" "${value}") -endmacro(fl_summary_image title name lib) diff --git a/CMake/gen_config.cmake b/CMake/gen_config.cmake deleted file mode 100644 index 719b804d2..000000000 --- a/CMake/gen_config.cmake +++ /dev/null @@ -1,109 +0,0 @@ -# -# Generate version numbers and configure header files -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# Calculate limits and check FL_ABI_VERSION syntax -####################################################################### - -# Initialize FL_ABI_VERSION -set(FL_ABI_VERSION "${FLTK_ABI_VERSION}") - -# These are the limits (min/max) FL_ABI_VERSION is allowed to have -math(EXPR abi_version_min "${FLTK_VERSION_MAJOR} * 10000 + ${FLTK_VERSION_MINOR} * 100") -math(EXPR abi_version_max "${abi_version_min} + ${FLTK_VERSION_PATCH} + 1") - -if(FL_ABI_VERSION STREQUAL "") - - # no version set, silently use default - set(FL_ABI_VERSION "${abi_version_min}") - -else() - - # check syntax of reuested ABI version (five digits) - - string(REGEX MATCH "[1-9][0-9][0-9][0-9][0-9]" reg_match "${FL_ABI_VERSION}") - if(NOT reg_match STREQUAL "${FL_ABI_VERSION}") - message(STATUS "FLTK_ABI_VERSION \"${FLTK_ABI_VERSION}\" is invalid. Using default = ${abi_version_min}") - set(FL_ABI_VERSION "${abi_version_min}") - endif() - - # check minor version (first three numbers must match) - - string(SUBSTRING "${abi_version_min}" 0 3 abi_version_minor) - string(SUBSTRING "${FL_ABI_VERSION}" 0 3 abi_version_temp) - - if(NOT abi_version_temp STREQUAL ${abi_version_minor}) - set(FL_ABI_VERSION "${abi_version_min}") - message(STATUS "FLTK_ABI_VERSION \"${FLTK_ABI_VERSION}\" doesn't match minor version. Using default = ${abi_version_min}") - set(FL_ABI_VERSION "${abi_version_min}") - endif() - -endif() - -if(FL_ABI_VERSION STRLESS ${abi_version_min}) - # should never happen - set(FL_ABI_VERSION "${abi_version_min}") -elseif(FL_ABI_VERSION STRGREATER ${abi_version_max}) - # accept w/o warning - set(FL_ABI_VERSION "${abi_version_max}") -endif() - -# reset all temporary variables - -unset(abi_version_min) -unset(abi_version_max) -unset(abi_version_minor) -unset(abi_version_temp) -unset(reg_match) - -####################################################################### -# configure the header file "FL/fl_config.h" in the build tree -####################################################################### - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/fl_config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/FL/fl_config.h - @ONLY -) - -####################################################################### -# generate the header file "config.h" in the build tree -####################################################################### - -# prepare some variables for config.h - -if(IS_ABSOLUTE "${FLTK_DATADIR}") - set(PREFIX_DATA "${FLTK_DATADIR}/fltk") -else(IS_ABSOLUTE "${FLTK_DATADIR}") - set(PREFIX_DATA "${CMAKE_INSTALL_PREFIX}/${FLTK_DATADIR}/fltk") -endif(IS_ABSOLUTE "${FLTK_DATADIR}") - -if(IS_ABSOLUTE "${FLTK_DOCDIR}") - set(PREFIX_DOC "${FLTK_DOCDIR}/fltk") -else(IS_ABSOLUTE "${FLTK_DOCDIR}") - set(PREFIX_DOC "${CMAKE_INSTALL_PREFIX}/${FLTK_DOCDIR}/fltk") -endif(IS_ABSOLUTE "${FLTK_DOCDIR}") - -set(CONFIG_H_IN config.h.in) -set(CONFIG_H config.h) - -# generate the header file - -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/${CONFIG_H_IN}" - "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_H}" - @ONLY -) diff --git a/CMake/install-symlinks.cmake.in b/CMake/install-symlinks.cmake.in deleted file mode 100644 index e1c7a9e86..000000000 --- a/CMake/install-symlinks.cmake.in +++ /dev/null @@ -1,33 +0,0 @@ -# -# Installation script to create symlinks for the FLTK project using CMake -# -# Copyright 1998-2021 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php - -# On UNIX create backward compatibility symlinks -if(NOT EXISTS $ENV{DESTDIR}@PREFIX_INCLUDE@/Fl) - EXECUTE_PROCESS( - COMMAND ln -s FL Fl - WORKING_DIRECTORY $ENV{DESTDIR}@PREFIX_INCLUDE@ - ) -endif(NOT EXISTS $ENV{DESTDIR}@PREFIX_INCLUDE@/Fl) - -file(GLOB FLTK_HEADER_FILES $ENV{DESTDIR}@PREFIX_INCLUDE@/FL/*.H) -foreach(file ${FLTK_HEADER_FILES}) - GET_FILENAME_COMPONENT(nameWE ${file} NAME_WE) - if(NOT EXISTS $ENV{DESTDIR}@PREFIX_INCLUDE@/FL/${nameWE}.h) - EXECUTE_PROCESS( - COMMAND ln -s ${nameWE}.H ${nameWE}.h - WORKING_DIRECTORY $ENV{DESTDIR}@PREFIX_INCLUDE@/FL - ) - endif(NOT EXISTS $ENV{DESTDIR}@PREFIX_INCLUDE@/FL/${nameWE}.h) -endforeach(file) diff --git a/CMake/install.cmake b/CMake/install.cmake deleted file mode 100644 index abd80c5c6..000000000 --- a/CMake/install.cmake +++ /dev/null @@ -1,156 +0,0 @@ -# -# Installation support for building the FLTK project using CMake (www.cmake.org) -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# installation -####################################################################### - -# generate uninstall target -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - @ONLY -) -add_custom_target(uninstall - "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" -) - -install(DIRECTORY - ${CMAKE_CURRENT_SOURCE_DIR}/FL - DESTINATION ${FLTK_INCLUDEDIR} USE_SOURCE_PERMISSIONS - FILES_MATCHING - PATTERN "*.[hH]" - PATTERN "fl_config.h" EXCLUDE -) - -install(DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/FL - DESTINATION ${FLTK_INCLUDEDIR} USE_SOURCE_PERMISSIONS - FILES_MATCHING - PATTERN "*.[hH]" -) - -if(FLTK_INSTALL_LINKS) - install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/install-symlinks.cmake) -endif(FLTK_INSTALL_LINKS) - -# generate FLTKConfig.cmake for installed directory use -set(INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include) -if(FLTK_HAVE_CAIRO) - list(APPEND INCLUDE_DIRS ${PKG_CAIRO_INCLUDE_DIRS}) -endif() - -set(CONFIG_PATH ${CMAKE_INSTALL_PREFIX}/${FLTK_CONFIG_PATH}) - -install(EXPORT FLTK-Targets - DESTINATION ${FLTK_CONFIG_PATH} - FILE FLTK-Targets.cmake - NAMESPACE fltk:: -) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/FLTKConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/etc/FLTKConfig.cmake - @ONLY -) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/etc/FLTKConfig.cmake - DESTINATION ${FLTK_CONFIG_PATH} -) - -install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/FLTK-Functions.cmake - DESTINATION ${FLTK_CONFIG_PATH} -) - -# Generate fltk-config - -set(prefix ${CMAKE_INSTALL_PREFIX}) -set(exec_prefix "\${prefix}") -set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") -set(BINARY_DIR) -set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") -set(srcdir ".") - -set(LIBNAME "${libdir}/libfltk.a") - -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/fltk-config.in" - "${CMAKE_CURRENT_BINARY_DIR}/bin/fltk-config" - @ONLY -) - -# Install fltk-config -# Note: no need to set execute perms, install(PROGRAMS) does this - -install(PROGRAMS - ${CMAKE_CURRENT_BINARY_DIR}/bin/fltk-config - DESTINATION ${FLTK_BINDIR} -) - -# Install man pages of fluid and fltk-options - -macro(INSTALL_MAN FILE LEVEL) - install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/documentation/src/${FILE}.man - DESTINATION ${FLTK_MANDIR}/man${LEVEL} - RENAME ${FILE}.${LEVEL} - ) -endmacro(INSTALL_MAN FILE LEVEL) - -if(FLTK_BUILD_FLUID) - INSTALL_MAN (fluid 1) -endif(FLTK_BUILD_FLUID) -if(FLTK_BUILD_FLTK_OPTIONS) - INSTALL_MAN (fltk-options 1) -endif(FLTK_BUILD_FLTK_OPTIONS) -INSTALL_MAN (fltk-config 1) -INSTALL_MAN (fltk 3) - -# Install the games - -if(FLTK_BUILD_TEST) # "OR FLTK_BUILD_GAMES" (not yet implemented) - - set(games_ blocks sudoku) - if(FLTK_BUILD_FLUID) - list(APPEND games_ checkers) - endif(FLTK_BUILD_FLUID) - if(FLTK_USE_GL) - list(APPEND games_ glpuzzle) - endif() - - foreach(game_ ${games_}) - if(FLTK_BUILD_SHARED_LIBS) - set(tgt_ "${game_}-shared") - set_target_properties(${tgt_} PROPERTIES RUNTIME_OUTPUT_NAME ${game_}) - else() - set(tgt_ ${game_}) - endif() - install(TARGETS ${tgt_} - EXPORT FLTK-Targets - RUNTIME DESTINATION ${FLTK_BINDIR} - LIBRARY DESTINATION ${FLTK_LIBDIR} - ARCHIVE DESTINATION ${FLTK_LIBDIR} - BUNDLE DESTINATION ${FLTK_BINDIR} # macOS: bundles - ) - # install man page - INSTALL_MAN (${game_} 6) - endforeach() - unset(game_) - unset(games_) -endif() diff --git a/CMake/macOS-bundle-wrapper.in b/CMake/macOS-bundle-wrapper.in deleted file mode 100644 index 2f31e4886..000000000 --- a/CMake/macOS-bundle-wrapper.in +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# Run the executable of a macOS bundle for the Fast Light Tool Kit (FLTK). -# -# Copyright 1998-2020 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# -# -# Install this script side by side with the macOS bundle with the same name: -# -# - dir/prog.app macOS bundle (directory) -# - dir/prog this script: runs the executable 'prog' inside the bundle -# -prog="`basename \"$0\"`" -dir="`dirname \"$0\"`" -exec "$dir/$prog.app/Contents/MacOS/$prog" "$@" diff --git a/CMake/macOSMaxAllowed.c b/CMake/macOSMaxAllowed.c deleted file mode 100644 index 4628348d3..000000000 --- a/CMake/macOSMaxAllowed.c +++ /dev/null @@ -1,6 +0,0 @@ - -#include <AvailabilityMacros.h> -#if MAC_OS_X_VERSION_MAX_ALLOWED < SDK_VERSION_CHECK -#error MAC_OS_X_VERSION_MAX_ALLOWED < SDK_VERSION_CHECK -#endif -int main(int argc, char** argv) { return 0; } diff --git a/CMake/options.cmake b/CMake/options.cmake deleted file mode 100644 index f005f8b0e..000000000 --- a/CMake/options.cmake +++ /dev/null @@ -1,1098 +0,0 @@ -# -# Main CMakeLists.txt to build the FLTK project using CMake (www.cmake.org) -# Originally written by Michael Surette -# -# Copyright 1998-2026 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# Important implementation note for FLTK developers -####################################################################### -# -# *FIXME* In the current version of FLTK's CMake build files we're -# using 'include_directories()' to define directories that must be -# used in compile commands (typically "-Idirectories"). -# -# include_directories() is a global command that affects *all* source -# files in the current directory and all subdirectories. This can lead -# to conflicts and should be replaced with target_include_directories() -# which can be applied to particular targets and source files only. -# -# This could remove some of these potential build conflicts, for -# instance if the bundled image libs and Cairo or Pango are used -# together (Pango depends on Cairo and Cairo depends on libpng). -# However, this is not a proper solution! -# -# That said, order of "-I..." switches matters, and therefore the -# bundled libraries (png, jpeg, zlib) *must* appear before any other -# include_directories() statements that might introduce conflicts. -# Currently 'resources.cmake' is included before this file and thus -# 'include_directories(${FREETYPE_PATH})' is executed before this -# file but this doesn't matter. -# -# This *MUST* be fixed using target_include_directories() as -# appropriate but this would need a major rework. -# -# Albrecht-S April 6, 2022 -# -####################################################################### - -set(DEBUG_OPTIONS_CMAKE 0) -if(DEBUG_OPTIONS_CMAKE) - message(STATUS "[** options.cmake **]") - fl_debug_var(WIN32) - fl_debug_var(FLTK_LDLIBS) -endif(DEBUG_OPTIONS_CMAKE) - -####################################################################### -# options -####################################################################### -set(FLTK_OPTION_OPTIM "" - CACHE STRING - "custom optimization flags" -) -# *FIXME* add_definitions() -add_definitions(${FLTK_OPTION_OPTIM}) - -####################################################################### -set(FLTK_ARCHFLAGS "" - CACHE STRING - "custom architecture flags" -) -# *FIXME* add_definitions() -add_definitions(${FLTK_ARCHFLAGS}) - -####################################################################### -set(FLTK_ABI_VERSION "" - CACHE STRING - "FLTK ABI Version FL_ABI_VERSION: 1xxyy for 1.x.y (xx,yy with leading zeroes)" -) -# see also CMake/gen_config.cmake - -####################################################################### -# Select MSVC (Visual Studio) Runtime: DLL (/MDx) or static (/MTx) -# where x = 'd' for Debug builds, empty ('') for non-Debug builds. -# Note: this might be handled better by the 'MSVC_RUNTIME_LIBRARY' -# target property for each target rather than setting a global -# CMake variable - but this version does the latter. -# This also applies when using LLVM/clang on Windows (#1058). -####################################################################### - -if(WIN32 AND NOT MINGW AND NOT MSYS) - option(FLTK_MSVC_RUNTIME_DLL "use MSVC Runtime-DLL (/MDx)" ON) - if(FLTK_MSVC_RUNTIME_DLL) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") - else() - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") - endif() -else(WIN32 AND NOT MINGW AND NOT MSYS) - # suppress CMake warning if the user sets FLTK_MSVC_RUNTIME_DLL on other platforms - if(DEFINED FLTK_MSVC_RUNTIME_DLL) - unset(FLTK_MSVC_RUNTIME_DLL) - unset(FLTK_MSVC_RUNTIME_DLL CACHE) - endif() -endif(WIN32 AND NOT MINGW AND NOT MSYS) - -####################################################################### - -if(APPLE) - option(FLTK_BACKEND_X11 "use X11" OFF) - if(CMAKE_OSX_SYSROOT) - list(APPEND FLTK_CFLAGS "-isysroot ${CMAKE_OSX_SYSROOT}") - endif(CMAKE_OSX_SYSROOT) -elseif(UNIX) - option(FLTK_BACKEND_X11 "use X11" ON) -endif(APPLE) - -####################################################################### -# Bundled Library Options -####################################################################### - -if(WIN32 OR (APPLE AND NOT FLTK_BACKEND_X11)) - option(FLTK_USE_SYSTEM_LIBJPEG "use system libjpeg" OFF) - option(FLTK_USE_SYSTEM_LIBPNG "use system libpng" OFF) - option(FLTK_USE_SYSTEM_ZLIB "use system zlib" OFF) -else() - option(FLTK_USE_SYSTEM_LIBJPEG "use system libjpeg" ON) - option(FLTK_USE_SYSTEM_LIBPNG "use system libpng" ON) - option(FLTK_USE_SYSTEM_ZLIB "use system zlib" ON) -endif() - -# Set default values of internal build options - -set(FLTK_USE_BUNDLED_JPEG FALSE) -set(FLTK_USE_BUNDLED_PNG FALSE) -set(FLTK_USE_BUNDLED_ZLIB FALSE) - -# Collect libraries to build fltk_images (starting empty) - -set(FLTK_IMAGE_LIBRARIES "") - -####################################################################### -# Ensure that png and zlib are both system or both local for compatibility -####################################################################### - -if(FLTK_USE_SYSTEM_ZLIB) - find_package(ZLIB) - if(NOT ZLIB_FOUND) - set(FLTK_USE_BUNDLED_ZLIB TRUE) - endif() -else() - set(FLTK_USE_BUNDLED_ZLIB TRUE) -endif() - -if(FLTK_USE_SYSTEM_LIBPNG AND NOT FLTK_USE_BUNDLED_ZLIB) - find_package(PNG) - if(NOT PNG_FOUND) - set(FLTK_USE_BUNDLED_PNG TRUE) - set(FLTK_USE_BUNDLED_ZLIB TRUE) - endif() -else() - set(FLTK_USE_BUNDLED_PNG TRUE) - set(FLTK_USE_BUNDLED_ZLIB TRUE) -endif() - -# Issue warnings if we deviate from the user's choice - -if(FLTK_USE_SYSTEM_LIBPNG AND FLTK_USE_BUNDLED_PNG) - message(STATUS "System PNG or ZLIB not usable, falling back to local PNG for compatibility.") -endif() - -if(FLTK_USE_SYSTEM_ZLIB AND FLTK_USE_BUNDLED_ZLIB) - message(STATUS "System PNG or ZLIB not usable, falling back to local ZLIB for compatibility.") -endif() - -####################################################################### -# Bundled Compression Library : zlib -####################################################################### - -if(FLTK_USE_BUNDLED_ZLIB) - - add_subdirectory(zlib) - - set(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib) - - # FIXME - include_directories() - include_directories(${ZLIB_INCLUDE_DIR}) - -endif() - -set(HAVE_LIBZ 1) - -####################################################################### -# Bundled Image Library : libpng -####################################################################### - -if(FLTK_USE_BUNDLED_PNG) - - add_subdirectory(png) - set(FLTK_PNG_LIBRARIES fltk::png) - list(APPEND FLTK_IMAGE_LIBRARIES fltk::png) - - # Definitions for 'config.h' - do we still need this? - # See also png/CMakeLists.txt (target_compile_definitions). - # Note: config.h is generated by CMake (or configure in 1.4), hence - # we support it in 1.4.x, but this may be changed in 1.5.0. (?) - - set(HAVE_PNG_H 1) - set(HAVE_PNG_GET_VALID 1) - set(HAVE_PNG_SET_TRNS_TO_ALPHA 1) - - # *FIXME* include_directories() - include_directories(${FLTK_SOURCE_DIR}/png) - -else() # use system libpng and zlib - - set(FLTK_PNG_LIBRARIES ${PNG_LIBRARIES}) - list(APPEND FLTK_IMAGE_LIBRARIES ${PNG_LIBRARIES}) - - # *FIXME* include_directories() - include_directories(${PNG_INCLUDE_DIRS}) - - set(_INCLUDE_SAVED ${CMAKE_REQUIRED_INCLUDES}) - list(APPEND CMAKE_REQUIRED_INCLUDES ${PNG_INCLUDE_DIRS}) - - # Note: we do not check for <libpng/png.h> explicitly. - # This is assumed to exist if we have PNG_FOUND and don't find <png.h> - - # FIXME - Force search by unsetting the chache variable. Maybe use - # FIXME - another cache variable to check for option changes? - # unset(HAVE_PNG_H CACHE) # force search - - check_include_file(png.h HAVE_PNG_H) - mark_as_advanced(HAVE_PNG_H) - - set(CMAKE_REQUIRED_INCLUDES ${_INCLUDE_SAVED}) - unset(_INCLUDE_SAVED) - -endif() - -set(HAVE_LIBPNG 1) - -####################################################################### -# Bundled Image Library : libjpeg -####################################################################### - -if(FLTK_USE_SYSTEM_LIBJPEG) - find_package(JPEG) - if(NOT JPEG_FOUND) - set(FLTK_USE_BUNDLED_JPEG TRUE) - message(STATUS "cannot find system jpeg library - using built-in") - endif() -else() - set(FLTK_USE_BUNDLED_JPEG TRUE) -endif() - -if(FLTK_USE_BUNDLED_JPEG) - - add_subdirectory(jpeg) - set(FLTK_JPEG_LIBRARIES fltk::jpeg) - # list(APPEND FLTK_IMAGE_LIBRARIES fltk::jpeg) - - # *FIXME* include_directories - include_directories(${FLTK_SOURCE_DIR}/jpeg) - -else() - - set(FLTK_JPEG_LIBRARIES ${JPEG_LIBRARIES}) - list(APPEND FLTK_IMAGE_LIBRARIES ${JPEG_LIBRARIES}) - -endif() - -set(HAVE_LIBJPEG 1) - -####################################################################### - -if(UNIX) - option(FLTK_INSTALL_LINKS "create backwards compatibility links" OFF) - list(APPEND FLTK_LDLIBS -lm) - - if(NOT APPLE) - option(FLTK_BACKEND_WAYLAND "support the Wayland backend" ON) - endif(NOT APPLE) - - # Check Wayland requirements and set the result variable FLTK_USE_WAYLAND. - # FLTK_USE_WAYLAND *must* be used *everywhere* else after these checks. - - if(FLTK_BACKEND_WAYLAND) - message(STATUS "Checking Wayland requirements ...") - set(FLTK_USE_WAYLAND FALSE) # assume Wayland not OK ... - - if(NOT PKG_CONFIG_FOUND) - message(FATAL_ERROR "Option FLTK_BACKEND_WAYLAND requires pkg-config on the build host.") - endif() - - pkg_check_modules(WLDCLIENT IMPORTED_TARGET wayland-client>=1.18) - pkg_check_modules(WLDCURSOR IMPORTED_TARGET wayland-cursor) - pkg_check_modules(WLDPROTO IMPORTED_TARGET wayland-protocols>=1.15) - pkg_check_modules(XKBCOMMON IMPORTED_TARGET xkbcommon) - - if(WLDCLIENT_FOUND AND WLDCURSOR_FOUND AND WLDPROTO_FOUND AND XKBCOMMON_FOUND) - set(FLTK_USE_WAYLAND TRUE) # OK, Wayland can be used - message(STATUS "Checking Wayland requirements: OK") - else() - message(NOTICE "Checking Wayland requirements FAILED!") - message(NOTICE " Not all required software modules for Wayland are present.") - message(NOTICE " The Wayland backend was requested but can't be built.") - message(NOTICE " Please check Wayland requirements (see above) or") - message(NOTICE " set FLTK_BACKEND_WAYLAND=OFF to silence this warning.") - endif() - endif(FLTK_BACKEND_WAYLAND) - - if(FLTK_USE_WAYLAND) - pkg_get_variable(PROTOCOLS wayland-protocols pkgdatadir) - string(REPLACE "//" "/" PROTOCOLS ${PROTOCOLS}) - if(EXISTS ${PROTOCOLS}/staging/xdg-dialog/xdg-dialog-v1.xml) - set(HAVE_XDG_DIALOG 1) - message(STATUS "Found dev files for Wayland protocol 'XDG dialog windows'") - else() - set(HAVE_XDG_DIALOG 0) - endif() - if(EXISTS ${PROTOCOLS}/staging/cursor-shape/cursor-shape-v1.xml AND - EXISTS ${PROTOCOLS}/stable/tablet/tablet-v2.xml) - set(HAVE_CURSOR_SHAPE 1) - message(STATUS "Found dev files for Wayland protocols 'Cursor shape' and 'Tablet'") - message(STATUS " ==> option FLTK_USE_DBUS can be turned OFF if 'Cursor shape'-enabled wayland compositor is used.") - else() - set(HAVE_CURSOR_SHAPE 0) - endif() - if(FLTK_BACKEND_X11) - include(FindX11) - endif() - if(FLTK_BACKEND_X11 AND X11_FOUND) - set(FLTK_USE_X11 1) # build a hybrid Wayland/X11 library - else() - set(FLTK_USE_X11 0) # build a Wayland-only library - endif() - unset(FLTK_GRAPHICS_CAIRO CACHE) - set(FLTK_GRAPHICS_CAIRO TRUE CACHE BOOL "all drawing to X11 windows uses Cairo") - option(FLTK_USE_DBUS "use D-Bus - required to detect the cursor theme" ON) - option(FLTK_USE_SYSTEM_LIBDECOR "use libdecor from the system" ON) - set(USE_SYSTEM_LIBDECOR 1) - unset(FLTK_USE_XRENDER CACHE) - unset(FLTK_USE_XINERAMA CACHE) - unset(FLTK_USE_XFT CACHE) - unset(FLTK_USE_XCURSOR CACHE) - unset(FLTK_USE_XFIXES CACHE) - if(X11_FOUND) - if(NOT X11_Xfixes_FOUND) - message(WARNING "Install development headers for libXfixes (e.g., libxfixes-dev)") - endif() - set(HAVE_XFIXES 1) - if(NOT X11_Xrender_FOUND) - message(WARNING "Install development headers for libXrender (e.g., libxrender-dev)") - endif() - set(HAVE_XRENDER 1) - if(NOT X11_Xft_FOUND) - message(WARNING "Install development headers for libXft (e.g., libxft-dev)") - endif() - if(NOT X11_Xcursor_FOUND) - message(WARNING "Install development headers for libXcursor (e.g., libxcursor-dev)") - endif() - set(HAVE_XCURSOR 1) - if(NOT X11_Xinerama_FOUND) - message(WARNING "Install development headers for libXinerama (e.g., libxinerama-dev)") - endif() - set(HAVE_XINERAMA 1) - if(NOT (X11_Xfixes_FOUND AND X11_Xrender_FOUND AND X11_Xft_FOUND AND X11_Xcursor_FOUND - AND X11_Xinerama_FOUND)) - message(FATAL_ERROR "*** Terminating: one or more required software package(s) missing.") - endif() - endif(X11_FOUND) - unset(FLTK_USE_PANGO CACHE) - set(FLTK_USE_PANGO TRUE CACHE BOOL "use lib Pango") - if(FLTK_USE_SYSTEM_LIBDECOR) - pkg_check_modules(SYSTEM_LIBDECOR IMPORTED_TARGET libdecor-0>=0.2.0 QUIET) - if(NOT SYSTEM_LIBDECOR_FOUND) - message(STATUS "Warning: system libdecor doesn't satisfy version ≥ 0.2.0,") - message(STATUS " using bundled libdecor library instead.") - set(USE_SYSTEM_LIBDECOR 0) - else() - pkg_get_variable(LIBDECOR_LIBDIR libdecor-0 libdir) - set(LIBDECOR_PLUGIN_DIR ${LIBDECOR_LIBDIR}/libdecor/plugins-1) - if(EXISTS ${LIBDECOR_PLUGIN_DIR} AND IS_DIRECTORY ${LIBDECOR_PLUGIN_DIR}) - set(LIBDECOR_PLUGIN_DIR "\"${LIBDECOR_PLUGIN_DIR}\"" ) - else() - set(USE_SYSTEM_LIBDECOR 0) - endif() - endif(NOT SYSTEM_LIBDECOR_FOUND) - else() - set(USE_SYSTEM_LIBDECOR 0) - endif(FLTK_USE_SYSTEM_LIBDECOR) - - if(USE_SYSTEM_LIBDECOR) - set(FLTK_USE_LIBDECOR_GTK ON) - else() - option(FLTK_USE_LIBDECOR_GTK "Allow to use libdecor's GTK plugin" ON) - endif(USE_SYSTEM_LIBDECOR) - - if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "FreeBSD") - check_include_file(linux/input.h LINUX_INPUT_H) - if(NOT LINUX_INPUT_H) - message(FATAL_ERROR "Required include file 'linux/input.h' is missing. Please install package 'evdev-proto'") - endif(NOT LINUX_INPUT_H) - endif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "FreeBSD") - - endif(FLTK_USE_WAYLAND) -endif(UNIX) - -if(WIN32) - option(FLTK_GRAPHICS_GDIPLUS "use GDI+ when possible for antialiased graphics" ON) - if(FLTK_GRAPHICS_GDIPLUS) - set(USE_GDIPLUS TRUE) - if(NOT MSVC) - list(APPEND FLTK_LDLIBS "-lgdiplus") - endif(NOT MSVC) - endif(FLTK_GRAPHICS_GDIPLUS) -endif(WIN32) - -####################################################################### - -# find X11 libraries and headers -set(PATH_TO_XLIBS) -if(FLTK_BACKEND_X11) - include(FindX11) - if(X11_FOUND) - set(FLTK_USE_X11 1) - list(APPEND FLTK_LDLIBS -lX11) - if(X11_Xext_FOUND) - list(APPEND FLTK_LDLIBS -lXext) - endif(X11_Xext_FOUND) - get_filename_component(PATH_TO_XLIBS ${X11_X11_LIB} PATH) - endif(X11_FOUND) -endif() - -if(APPLE AND FLTK_BACKEND_X11) - if(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) # a.k.a. macOS version ≥ 10.13 - list(APPEND FLTK_CFLAGS "-D_LIBCPP_HAS_THREAD_API_PTHREAD") - endif(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) - # FIXME: include_directories(!) - # FIXME: how can we implement "AFTER SYSTEM" ? - include_directories(AFTER SYSTEM /opt/X11/include/freetype2) - include_directories(AFTER SYSTEM /opt/X11/include) # for Xft.h - if(PATH_TO_XLIBS) - set(LDFLAGS "-L${PATH_TO_XLIBS} ${LDFLAGS}") - endif(PATH_TO_XLIBS) - if(X11_INCLUDE_DIR) - set(TEMP_INCLUDE_DIR ${X11_INCLUDE_DIR}) - list(TRANSFORM TEMP_INCLUDE_DIR PREPEND "-I") - list(APPEND FLTK_CFLAGS "${TEMP_INCLUDE_DIR}") - endif(X11_INCLUDE_DIR) -endif(APPLE AND FLTK_BACKEND_X11) - -####################################################################### -option(FLTK_USE_POLL "use poll if available" OFF) -mark_as_advanced(FLTK_USE_POLL) - -if(FLTK_USE_POLL) - check_symbol_exists(poll "poll.h" USE_POLL) -endif(FLTK_USE_POLL) - -####################################################################### -option(FLTK_BUILD_SHARED_LIBS - "Build shared libraries in addition to static libraries" - OFF -) - -####################################################################### - -option(FLTK_OPTION_PRINT_SUPPORT "allow print support" ON) -option(FLTK_OPTION_FILESYSTEM_SUPPORT "allow file system support" ON) -option(FLTK_OPTION_PEN_SUPPORT "include Pen/Tablet support" ON) - -option(FLTK_BUILD_FORMS "Build forms compatibility library" OFF) -option(FLTK_BUILD_FLUID "Build FLUID" ON) -option(FLTK_BUILD_FLTK_OPTIONS "Build fltk-options" ON) -option(FLTK_BUILD_EXAMPLES "Build example programs" OFF) -option(FLTK_BUILD_SCREENSHOTS "Build screenshot programs for docs" OFF) - -if(FLTK_IS_TOPLEVEL) - option(FLTK_BUILD_TEST "Build test/demo programs" ON) -else() - option(FLTK_BUILD_TEST "Build test/demo programs" OFF) -endif() - - -# set variables to generate config.h or fl_config.h - -if(FLTK_BUILD_FORMS) - set(FLTK_HAVE_FORMS 1) -else() - set(FLTK_HAVE_FORMS 0) -endif() - -# Note: on some Windows build systems (notably "classic" MinGW 32-bit) -# Pen/Tablet support is not available, hence we use try_compile() to -# figure this out. -# -# CMake variables: -# - FLTK_OPTION_PEN_SUPPORT: user option (cache; default ON/TRUE) -# - PEN_DRIVER_SUPPORTED : Windows only; result of try_compile() -# - FLTK_HAVE_PEN_SUPPORT : final result for building Pen/Tablet support, -# also used to set config variable in config.h - -if(FLTK_OPTION_PEN_SUPPORT) - if(WIN32) - try_compile(PEN_DRIVER_SUPPORTED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/pen-support.c - ) - # fl_debug_var(PEN_DRIVER_SUPPORTED) - if(PEN_DRIVER_SUPPORTED) - set(FLTK_HAVE_PEN_SUPPORT 1) - else() - set(FLTK_HAVE_PEN_SUPPORT 0) - endif() - else(WIN32) # all other platforms - set(FLTK_HAVE_PEN_SUPPORT 1) - endif(WIN32) - - # generate a warning if Pen/Tablet support was requested but can't be compiled - - if(NOT FLTK_HAVE_PEN_SUPPORT) - message(STATUS "WARNING: Pen/Tablet support requested (FLTK_OPTION_PEN_SUPPORT) but not available") - message(STATUS " ... Pen/Tablet support has been disabled!") - endif() - -else(FLTK_OPTION_PEN_SUPPORT) # option disabled by user - set(FLTK_HAVE_PEN_SUPPORT 0) -endif(FLTK_OPTION_PEN_SUPPORT) - -####################################################################### -if(DOXYGEN_FOUND) - option(FLTK_BUILD_HTML_DOCS "build html docs" ON) - option(FLTK_INSTALL_HTML_DOCS "install html docs" OFF) - option(FLTK_BUILD_FLUID_DOCS "build FLUID docs" OFF) - option(FLTK_INSTALL_FLUID_DOCS "install FLUID docs" OFF) - - option(FLTK_INCLUDE_DRIVER_DOCS "include driver (developer) docs" OFF) - mark_as_advanced(FLTK_INCLUDE_DRIVER_DOCS) - - if(LATEX_FOUND) - option(FLTK_BUILD_PDF_DOCS "build pdf docs" ON) - option(FLTK_INSTALL_PDF_DOCS "install pdf docs" OFF) - endif(LATEX_FOUND) -endif(DOXYGEN_FOUND) - -if(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS) - add_subdirectory(documentation) -endif(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS) - -if(FLTK_BUILD_FLUID_DOCS) - add_subdirectory(fluid/documentation) -endif(FLTK_BUILD_FLUID_DOCS) - -####################################################################### -# Include optional Cairo support -####################################################################### - -option(FLTK_OPTION_CAIRO_WINDOW "add support for Fl_Cairo_Window" OFF) -option(FLTK_OPTION_CAIRO_EXT - "use FLTK code instrumentation for Cairo extended use" OFF -) - -set(FLTK_HAVE_CAIRO 0) -set(FLTK_HAVE_CAIROEXT 0) - -if(FLTK_OPTION_CAIRO_WINDOW OR FLTK_OPTION_CAIRO_EXT) - - # On Windows we don't use pkg-config *if* FLTK_CAIRO_DIR is set - # to prevent that CMake finds the system lib(s). - - if(WIN32 AND FLTK_CAIRO_DIR) - set(PKG_CAIRO_FOUND FALSE) - else() - pkg_search_module(PKG_CAIRO cairo) - endif() - - if(PKG_CAIRO_FOUND) - set(FLTK_HAVE_CAIRO 1) - if(FLTK_OPTION_CAIRO_EXT) - set(FLTK_HAVE_CAIROEXT 1) - endif(FLTK_OPTION_CAIRO_EXT) - - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${PKG_CAIRO_INCLUDE_DIRS}) - - # Cairo libs and flags for fltk-config - - # Hint: use either PKG_CAIRO_* or PKG_CAIRO_STATIC_* variables to - # create the list of libraries used to link programs with Cairo - # by running fltk-config --use-cairo --compile ... - # Currently we're using the non-STATIC variables to link Cairo shared. - - set(CAIROLIBS) - foreach(lib ${PKG_CAIRO_LIBRARIES}) - list(APPEND CAIROLIBS "-l${lib}") - endforeach() - - string(REPLACE ";" " " CAIROLIBS "${CAIROLIBS}") - string(REPLACE ";" " " CAIROFLAGS "${PKG_CAIRO_CFLAGS}") - - else(PKG_CAIRO_FOUND) - - if(NOT WIN32) - message(STATUS "*** Cairo was requested but not found - please check your Cairo installation") - message(STATUS "*** or disable options FLTK_OPTION_CAIRO_WINDOW and FLTK_OPTION_CAIRO_EXT.") - message(FATAL_ERROR "*** Terminating: missing Cairo libs or headers.") - endif() - - # Tweak Cairo includes / libs / paths for Windows (TEMPORARY solution). - # Todo: find a better way to set the required variables and flags! - # The current version was tested with 32-bit (MinGW) and 64-bit (Visual - # Studio and MSYS2). The latter can also be used with the Cairo library - # provided by MSYS2, but then the build depends on the MSYS2 installation. - # AlbrechtS (05/2024) - - message(STATUS "--- Cairo not found: trying to find Cairo for Windows ...") - - if(CMAKE_SIZEOF_VOID_P STREQUAL "8") - set(_cairo_suffix x64) - else() - set(_cairo_suffix x86) - endif() - - find_library(FLTK_CAIRO_LIB cairo - PATHS ${FLTK_CAIRO_DIR} - PATH_SUFFIXES lib lib/${_cairo_suffix} - NO_DEFAULT_PATH - ) - - if(NOT FLTK_CAIRO_DIR AND NOT FLTK_CAIRO_LIB) - message(STATUS "--- Please set FLTK_CAIRO_DIR to point to the Cairo installation folder ...") - message(STATUS " ... with files 'include/cairo.h' and 'lib/${_cairo_suffix}/cairo.lib'") - message(STATUS "--- Example: cmake -DFLTK_CAIRO_DIR=\"C:/cairo-windows\" ...") - message(STATUS "--- Note: this may be changed in the future.") - message(FATAL_ERROR "*** Terminating: missing Cairo libs or headers.") - endif() - - set(CAIROLIBS "-lcairo") # should be correct: needs cairo.lib - - # Simulate results of 'pkg_search_module (PKG_CAIRO cairo)' and more (above). - # These variables will be used later - - set(PKG_CAIRO_LIBRARIES "cairo") - set(PKG_CAIRO_INCLUDE_DIRS "${FLTK_CAIRO_DIR}/include") - set(PKG_CAIRO_LIBRARY_DIRS "${FLTK_CAIRO_DIR}/lib/${_cairo_suffix}/") - - # FIXME - include_directories() - include_directories(${PKG_CAIRO_INCLUDE_DIRS}) - - set(FLTK_HAVE_CAIRO 1) - if(FLTK_OPTION_CAIRO_EXT) - set(FLTK_HAVE_CAIROEXT 1) - endif(FLTK_OPTION_CAIRO_EXT) - - endif(PKG_CAIRO_FOUND) - - if(0) # 1 = DEBUG, 0 = no output - message(STATUS "--- options.cmake: Cairo related variables ---") - if(WIN32) - fl_debug_var(FLTK_CAIRO_DIR) - fl_debug_var(_cairo_suffix) - endif() - fl_debug_pkg(PKG_CAIRO cairo) - message(STATUS "--- fltk-config/Cairo variables ---") - fl_debug_var(FLTK_LDLIBS) - fl_debug_var(CAIROFLAGS) - fl_debug_var(CAIROLIBS) - message(STATUS "--- End of Cairo related variables ---") - endif() # 1 = DEBUG, ... - - unset(_cairo_suffix) - -endif(FLTK_OPTION_CAIRO_WINDOW OR FLTK_OPTION_CAIRO_EXT) - -####################################################################### - -option(FLTK_OPTION_SVG "read/write SVG image files" ON) - -if(FLTK_OPTION_SVG) - set(FLTK_USE_SVG 1) -else() - set(FLTK_USE_SVG 0) -endif(FLTK_OPTION_SVG) - -####################################################################### - -# FIXME: GLU libs have already been searched in resources.cmake - -set(HAVE_GL LIB_GL OR LIB_MesaGL) -set(FLTK_USE_GL FALSE) - -if(HAVE_GL) - option(FLTK_BUILD_GL "use OpenGL and build fltk_gl library" ON) - if(FLTK_BUILD_GL) - set(FLTK_USE_GL TRUE) - endif() -endif() - -if(FLTK_BUILD_GL) - if(FLTK_USE_WAYLAND) - pkg_check_modules(WLD_EGL IMPORTED_TARGET wayland-egl) - pkg_check_modules(PKG_EGL IMPORTED_TARGET egl) - if(FLTK_BACKEND_X11) - pkg_check_modules(PKG_GL IMPORTED_TARGET gl) - else() - pkg_check_modules(PKG_GL IMPORTED_TARGET opengl) - endif() - pkg_check_modules(PKG_GLU IMPORTED_TARGET glu) - - if(NOT (WLD_EGL_FOUND AND PKG_EGL_FOUND AND PKG_GL_FOUND AND PKG_GLU_FOUND)) - message(STATUS "Modules 'wayland-egl, egl, gl (or opengl), and glu' are required to build for the Wayland backend.") - message(FATAL_ERROR "*** Aborting ***") - endif() - - endif(FLTK_USE_WAYLAND) - - if(FLTK_BACKEND_X11 OR FLTK_USE_WAYLAND) - set(OPENGL_FOUND TRUE) - if(FLTK_BACKEND_X11) - find_library(OPENGL_LIB GL) - else() - find_library(OPENGL_LIB OpenGL) - endif(FLTK_BACKEND_X11) - get_filename_component(PATH_TO_GLLIB ${OPENGL_LIB} DIRECTORY) - find_library(GLU_LIB GLU) - get_filename_component(PATH_TO_GLULIB ${GLU_LIB} DIRECTORY) - set(OPENGL_LIBRARIES -L${PATH_TO_GLULIB} -L${PATH_TO_GLLIB}) - if(APPLE) - # FIXME: we should find a better way to resolve this issue: - # with GL, must use XQuartz libX11 else "Insufficient GL support" - set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} -lX11) - endif(APPLE) - set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} -lGLU) - if(FLTK_BACKEND_X11) - set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} -lGL) - else() - set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} -lOpenGL) - endif(FLTK_BACKEND_X11) - find_path(OPENGL_INCLUDE_DIR NAMES GL/gl.h OpenGL/gl.h HINTS ${X11_INCLUDE_DIR}) - unset(HAVE_GL_GLU_H CACHE) - find_file(HAVE_GL_GLU_H GL/glu.h PATHS ${X11_INCLUDE_DIR}) - else() - find_package(OpenGL) - if(APPLE) - set(HAVE_GL_GLU_H ${HAVE_OPENGL_GLU_H}) - endif(APPLE) - endif(FLTK_BACKEND_X11 OR FLTK_USE_WAYLAND) -else(FLTK_BUILD_GL) - set(OPENGL_FOUND FALSE) - set(HAVE_GL FALSE) - set(HAVE_GL_GLU_H FALSE) - set(HAVE_GLXGETPROCADDRESSARB FALSE) -endif(FLTK_BUILD_GL) - -mark_as_advanced(OPENGL_LIB) # internal cache variable, not relevant for users - -# FIXME: the following is necessary because this variable may have been removed -# from the cache above. It has been marked "advanced" before in resources.cmake. -mark_as_advanced(HAVE_GL_GLU_H) - -# Note: GLLIBS is a CMake 'list' and is used exclusively to generate fltk-config ! - -# FIXME, this should be improved! -# We should probably deduct this from OPENGL_LIBRARIES but it turned -# out to be difficult since FindOpenGL seems to return different -# syntax depending on the platform (and maybe also CMake version). -# Hence we use the following code... - -set(GLLIBS) -set(FLTK_GL_FOUND FALSE) - -if(OPENGL_FOUND) - set(FLTK_GL_FOUND TRUE) - find_path(FLTK_OPENGL_GLU_INCLUDE_DIR NAMES GL/glu.h OpenGL/glu.h HINTS ${OPENGL_INCLUDE_DIR} ${X11_INCLUDE_DIR}) - set(CMAKE_REQUIRED_INCLUDES ${OPENGL_INCLUDE_DIR}/GL ${FLTK_OPENGL_GLU_INCLUDE_DIR}) - - if(WIN32) - list(APPEND GLLIBS -lglu32 -lopengl32) - elseif(APPLE AND NOT FLTK_BACKEND_X11) - list(APPEND GLLIBS "-framework OpenGL") - elseif(FLTK_USE_WAYLAND) - foreach(_lib WLD_EGL PKG_EGL PKG_GLU PKG_GL) - list(APPEND GLLIBS ${${_lib}_LDFLAGS}) - endforeach(_lib ) - else() - list(APPEND GLLIBS -lGLU -lGL) - endif(WIN32) - - if (FLTK_BACKEND_X11) - # check if function glXGetProcAddressARB exists - set(TEMP_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_LIBRARIES}) - check_symbol_exists(glXGetProcAddressARB "glx.h" HAVE_GLXGETPROCADDRESSARB) - set(CMAKE_REQUIRED_LIBRARIES ${TEMP_REQUIRED_LIBRARIES}) - unset(TEMP_REQUIRED_LIBRARIES) - else() - unset(HAVE_GLXGETPROCADDRESSARB CACHE) - endif(FLTK_BACKEND_X11) -endif(OPENGL_FOUND) - -####################################################################### -option(FLTK_OPTION_LARGE_FILE "enable large file support" ON) - -if(FLTK_OPTION_LARGE_FILE) - if(NOT MSVC) - add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) - list(APPEND FLTK_CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) - endif(NOT MSVC) -endif(FLTK_OPTION_LARGE_FILE) - -####################################################################### -# Create an option whether we want to check for pthreads. -# We must not do it on Windows unless we run under Cygwin, since we -# always use native threads on Windows (even if libpthread is available). - -# Note: HAVE_PTHREAD_H has already been determined in resources.cmake -# before this file is included (or set to 0 for WIN32). - -if(WIN32 AND NOT CYGWIN) - # set(HAVE_PTHREAD_H 0) # (see resources.cmake) - set(FLTK_USE_PTHREADS FALSE) -else() - option(FLTK_USE_PTHREADS "use multi-threading with pthreads" ON) -endif(WIN32 AND NOT CYGWIN) - -# initialize more variables -set(USE_THREADS 0) -set(HAVE_PTHREAD 0) -set(FLTK_PTHREADS_FOUND FALSE) - -if(FLTK_USE_PTHREADS) - - include(FindThreads) - - if(Threads_FOUND) - add_definitions("-D_THREAD_SAFE -D_REENTRANT") - set(USE_THREADS 1) - set(FLTK_THREADS_FOUND TRUE) - endif(Threads_FOUND) - - if(CMAKE_USE_PTHREADS_INIT AND NOT WIN32) - set(HAVE_PTHREAD 1) - if(NOT APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") - endif(NOT APPLE) - list(APPEND FLTK_LDLIBS -lpthread) - list(APPEND FLTK_CFLAGS -D_THREAD_SAFE -D_REENTRANT) - set(FLTK_PTHREADS_FOUND TRUE) - else() - set(HAVE_PTHREAD 0) - set(HAVE_PTHREAD_H 0) - set(FLTK_PTHREADS_FOUND FALSE) - endif(CMAKE_USE_PTHREADS_INIT AND NOT WIN32) - -else(FLTK_USE_PTHREADS) - - set(HAVE_PTHREAD_H 0) - -endif(FLTK_USE_PTHREADS) - -set(debug_threads 0) # set to 1 to show debug info -if(debug_threads) - message("") - message(STATUS "options.cmake: set debug_threads to 0 to disable the following info:") - fl_debug_var(FLTK_USE_PTHREADS) - fl_debug_var(HAVE_PTHREAD) - fl_debug_var(HAVE_PTHREAD_H) - fl_debug_var(FLTK_THREADS_FOUND) - fl_debug_var(CMAKE_EXE_LINKER_FLAGS) - message(STATUS "options.cmake: end of debug_threads info.") -endif(debug_threads) -unset(debug_threads) - - -####################################################################### -if(X11_Xinerama_FOUND) - option(FLTK_USE_XINERAMA "use lib Xinerama" ON) -endif(X11_Xinerama_FOUND) - -if(FLTK_USE_XINERAMA) - set(HAVE_XINERAMA ${X11_Xinerama_FOUND}) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${X11_Xinerama_INCLUDE_PATH}) - list(APPEND FLTK_LDLIBS -lXinerama) - set(FLTK_XINERAMA_FOUND TRUE) -else() - set(FLTK_XINERAMA_FOUND FALSE) -endif(FLTK_USE_XINERAMA) - -####################################################################### -if(X11_Xfixes_FOUND) - option(FLTK_USE_XFIXES "use lib Xfixes" ON) -endif(X11_Xfixes_FOUND) - -if(FLTK_USE_XFIXES) - set(HAVE_XFIXES ${X11_Xfixes_FOUND}) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${X11_Xfixes_INCLUDE_PATH}) - list(APPEND FLTK_LDLIBS -lXfixes) - set(FLTK_XFIXES_FOUND TRUE) -else() - set(FLTK_XFIXES_FOUND FALSE) -endif(FLTK_USE_XFIXES) - -####################################################################### -if(X11_Xcursor_FOUND) - option(FLTK_USE_XCURSOR "use lib Xcursor" ON) -endif(X11_Xcursor_FOUND) - -if(FLTK_USE_XCURSOR) - set(HAVE_XCURSOR ${X11_Xcursor_FOUND}) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${X11_Xcursor_INCLUDE_PATH}) - list(APPEND FLTK_LDLIBS -lXcursor) - set(FLTK_XCURSOR_FOUND TRUE) -else() - set(FLTK_XCURSOR_FOUND FALSE) -endif(FLTK_USE_XCURSOR) - -####################################################################### -if(X11_Xft_FOUND) - option(FLTK_USE_PANGO "use lib Pango" OFF) - if(NOT FLTK_USE_WAYLAND) - option(FLTK_GRAPHICS_CAIRO "all drawing to X11 windows uses Cairo" OFF) - endif(NOT FLTK_USE_WAYLAND) - if(NOT FLTK_GRAPHICS_CAIRO) - option(FLTK_USE_XFT "use lib Xft" ON) - endif() -endif(X11_Xft_FOUND) - -# test option compatibility: Cairo for Xlib requires Pango -if(FLTK_GRAPHICS_CAIRO) - unset(FLTK_USE_PANGO CACHE) - set(FLTK_USE_PANGO TRUE CACHE BOOL "use lib Pango") -endif(FLTK_GRAPHICS_CAIRO) - -if(FLTK_USE_X11 AND FLTK_USE_PANGO AND NOT FLTK_GRAPHICS_CAIRO) - set(USE_PANGOXFT true) -endif() - -# test option compatibility: PangoXft requires Xft -if(USE_PANGOXFT) - if(NOT X11_Xft_FOUND) - message(STATUS "PangoXft requires Xft but Xft library or headers could not be found.") - message(STATUS "Please install Xft development files and try again or disable FLTK_USE_PANGO.") - message(FATAL_ERROR "*** Aborting ***") - else() - if(NOT FLTK_USE_XFT) - message(STATUS "PangoXft requires Xft but usage of Xft was disabled.") - message(STATUS "Please enable FLTK_USE_XFT and try again or disable FLTK_USE_PANGO.") - message(FATAL_ERROR "*** Aborting ***") - endif(NOT FLTK_USE_XFT) - endif(NOT X11_Xft_FOUND) -endif(USE_PANGOXFT) - -####################################################################### -if((X11_Xft_FOUND OR NOT USE_PANGOXFT) AND FLTK_USE_PANGO) - if(NOT PKG_CONFIG_FOUND) - message(FATAL_ERROR "Option FLTK_USE_PANGO requires availability of pkg-config on the build machine.") - endif(NOT PKG_CONFIG_FOUND) - pkg_check_modules(CAIRO IMPORTED_TARGET cairo) - if(USE_PANGOXFT) - pkg_check_modules(PANGOXFT IMPORTED_TARGET pangoxft) - endif(USE_PANGOXFT) - pkg_check_modules(PANGOCAIRO IMPORTED_TARGET pangocairo) - - if((PANGOXFT_FOUND OR NOT USE_PANGOXFT) AND PANGOCAIRO_FOUND AND CAIRO_FOUND) - if(USE_PANGOXFT) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${PANGOXFT_INCLUDE_DIRS}) - else() - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${PANGOCAIRO_INCLUDE_DIRS}) - endif(USE_PANGOXFT) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${CAIRO_INCLUDE_DIRS}) - - set(USE_PANGO TRUE) - - # add required libraries to fltk-config ... - if(USE_PANGOXFT) - list(APPEND FLTK_LDLIBS ${PANGOXFT_LDFLAGS}) - endif(USE_PANGOXFT) - list(APPEND FLTK_LDLIBS ${PANGOCAIRO_LDFLAGS}) - - endif((PANGOXFT_FOUND OR NOT USE_PANGOXFT) AND PANGOCAIRO_FOUND AND CAIRO_FOUND) - - if(USE_PANGO AND (FLTK_GRAPHICS_CAIRO OR FLTK_USE_WAYLAND)) - set(FLTK_USE_CAIRO 1) - # fl_debug_var(FLTK_USE_CAIRO) - endif() - -endif((X11_Xft_FOUND OR NOT USE_PANGOXFT) AND FLTK_USE_PANGO) - -if(FLTK_USE_WAYLAND) - - # Note: Disable FLTK_USE_LIBDECOR_GTK to get cairo titlebars rather than GTK - if(FLTK_USE_LIBDECOR_GTK AND NOT USE_SYSTEM_LIBDECOR) - pkg_check_modules(GTK IMPORTED_TARGET gtk+-3.0) - if(GTK_FOUND) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${GTK_INCLUDE_DIRS}) - list(APPEND FLTK_LDLIBS ${GTK_LDFLAGS}) - else() - message(WARNING "Installation of the development files for the GTK library " - "(e.g., libgtk-3-dev) is recommended when using the gnome desktop.") - endif(GTK_FOUND) - endif(FLTK_USE_LIBDECOR_GTK AND NOT USE_SYSTEM_LIBDECOR) - -endif() - -if(FLTK_USE_XFT) - set(USE_XFT X11_Xft_FOUND) - list(APPEND FLTK_LDLIBS -lXft) - set(FLTK_XFT_FOUND TRUE) - if(APPLE AND FLTK_BACKEND_X11) - find_library(LIB_fontconfig fontconfig "/opt/X11/lib") - endif() -else() - set(FLTK_XFT_FOUND FALSE) -endif(FLTK_USE_XFT) - -####################################################################### -if(X11_Xrender_FOUND) - option(FLTK_USE_XRENDER "use lib Xrender" ON) -endif(X11_Xrender_FOUND) - -if(FLTK_USE_XRENDER) - set(HAVE_XRENDER ${X11_Xrender_FOUND}) - if(HAVE_XRENDER) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${X11_Xrender_INCLUDE_PATH}) - list(APPEND FLTK_LDLIBS -lXrender) - set(FLTK_XRENDER_FOUND TRUE) - else(HAVE_XRENDER) - set(FLTK_XRENDER_FOUND FALSE) - endif(HAVE_XRENDER) -else(FLTK_USE_XRENDER) - set(FLTK_XRENDER_FOUND FALSE) -endif(FLTK_USE_XRENDER) - -####################################################################### -set(FL_NO_PRINT_SUPPORT FALSE) -if(X11_FOUND AND NOT FLTK_OPTION_PRINT_SUPPORT) - set(FL_NO_PRINT_SUPPORT TRUE) -endif(X11_FOUND AND NOT FLTK_OPTION_PRINT_SUPPORT) -####################################################################### - -####################################################################### -set(FL_CFG_NO_FILESYSTEM_SUPPORT TRUE) -if(FLTK_OPTION_FILESYSTEM_SUPPORT) - set(FL_CFG_NO_FILESYSTEM_SUPPORT FALSE) -endif(FLTK_OPTION_FILESYSTEM_SUPPORT) -####################################################################### - -####################################################################### -option(CMAKE_SUPPRESS_REGENERATION "suppress rules to re-run CMake on rebuild" OFF) -mark_as_advanced(CMAKE_SUPPRESS_REGENERATION) - -####################################################################### -# Clean up ... - -# *** FIXME *** Do we need all these variables ? - -list(REMOVE_DUPLICATES FLTK_BUILD_INCLUDE_DIRECTORIES) -list(REMOVE_DUPLICATES FLTK_IMAGE_INCLUDE_DIRECTORIES) -list(REMOVE_DUPLICATES FLTK_IMAGE_LIBRARIES) - -####################################################################### -# Debugging ... - -if(DEBUG_OPTIONS_CMAKE) - message(STATUS "") # empty line - fl_debug_var(WIN32) - fl_debug_var(LIBS) - fl_debug_var(GLLIBS) - fl_debug_var(FLTK_LDLIBS) - fl_debug_var(OPENGL_FOUND) - fl_debug_var(OPENGL_INCLUDE_DIR) - fl_debug_var(OPENGL_LIBRARIES) - fl_debug_var(CMAKE_MSVC_RUNTIME_LIBRARY) - message("--- bundled libraries ---") - fl_debug_var(FLTK_USE_SYSTEM_LIBJPEG) - fl_debug_var(FLTK_USE_SYSTEM_LIBPNG) - fl_debug_var(FLTK_USE_SYSTEM_ZLIB) - fl_debug_var(FLTK_USE_BUNDLED_JPEG) - fl_debug_var(FLTK_USE_BUNDLED_PNG) - fl_debug_var(FLTK_USE_BUNDLED_ZLIB) - - message(STATUS "--- *FIXME* include directories ---") - fl_debug_var(FLTK_BUILD_INCLUDE_DIRECTORIES) - fl_debug_var(FLTK_IMAGE_INCLUDE_DIRECTORIES) - - message("--- X11 ---") - fl_debug_var(X11_FOUND) - fl_debug_var(X11_INCLUDE_DIR) - fl_debug_var(X11_LIBRARIES) - fl_debug_var(X11_X11_LIB) - fl_debug_var(X11_X11_INCLUDE_PATH) - fl_debug_var(X11_Xft_INCLUDE_PATH) - fl_debug_var(X11_Xft_LIB) - fl_debug_var(X11_Xft_FOUND) - fl_debug_var(PATH_TO_XLIBS) - message(STATUS "[** end of options.cmake **]") -endif(DEBUG_OPTIONS_CMAKE) -unset(DEBUG_OPTIONS_CMAKE) diff --git a/CMake/pen-support.c b/CMake/pen-support.c deleted file mode 100644 index 3c3bed0be..000000000 --- a/CMake/pen-support.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - Test Pen/Tablet support availability (Windows). - - Copyright 2026 by Bill Spitzak and others. - - This library is free software. Distribution and use rights are outlined in - the file "COPYING" which should have been included with this file. If this - file is missing or damaged, see the license at: - - https://www.fltk.org/COPYING.php - - Please see the following page on how to report bugs and issues: - - https://www.fltk.org/bugs.php -*/ - -/* - CMake test function: test if this can be compiled. - If compilation fails, then Pen/Tablet support can't be built and is disabled. -*/ - -/* We require Windows 8 or later features for Pen/Tablet support */ - -# if !defined(WINVER) || (WINVER < 0x0602) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0602 -# endif -# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0602 -# endif - -#include <windows.h> - -int main() { - return POINTER_CHANGE_FIRSTBUTTON_DOWN; /* required symbol */ -} diff --git a/CMake/posixScandir.cxx b/CMake/posixScandir.cxx deleted file mode 100644 index 8b91428b5..000000000 --- a/CMake/posixScandir.cxx +++ /dev/null @@ -1,11 +0,0 @@ - -#include <dirent.h> - -int func (const char *d, dirent ***list, void *sort) { - int n = scandir(d, list, 0, (int(*)(const dirent **, const dirent **))sort); - return n; -} - -int main() { - return 0; -} diff --git a/CMake/pthread_mutex_recursive.c b/CMake/pthread_mutex_recursive.c deleted file mode 100644 index 2a058822f..000000000 --- a/CMake/pthread_mutex_recursive.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - FLTK feature test: do we have PTHREAD_MUTEX_RECURSIVE ? -*/ -#include <pthread.h> -int main() { - return PTHREAD_MUTEX_RECURSIVE; -} diff --git a/CMake/resources.cmake b/CMake/resources.cmake deleted file mode 100644 index bad4279be..000000000 --- a/CMake/resources.cmake +++ /dev/null @@ -1,344 +0,0 @@ -# -# Resource definitions to build the FLTK project using CMake (www.cmake.org) -# Originally written by Michael Surette -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# check for headers, libraries and functions -####################################################################### - -# If CMAKE_REQUIRED_QUIET is 1 (default) the search is mostly quiet, -# if it is 0 (or not defined) check_include_files() is more verbose -# and the result of the search is logged with fl_debug_var(). -# This is useful for debugging. - -set(CMAKE_REQUIRED_QUIET 1) - -include(CheckIncludeFiles) -include(CheckSymbolExists) - - -macro(fl_find_header VAR HEADER) - check_include_files("${HEADER}" ${VAR}) - if(NOT CMAKE_REQUIRED_QUIET) - fl_debug_var(${VAR}) - endif(NOT CMAKE_REQUIRED_QUIET) -endmacro(fl_find_header) - - -####################################################################### -# find git revision and store it in the CMake cache for reference -####################################################################### - -# (1) Get current Git revision from `git rev-parse ...` -# (2) Read Git revision from file `fltk_git_rev.dat` -# -# (1) This can fail if the FLTK source directory is not a Git checkout, -# i.e. FLTK was downloaded as a distro (tarball). -# (2) If (1) fails the file `fltk_git_rev.dat` is read. This file is -# generated by the process to generate the distribution (makesrcdist). -# - -set(git_rev_file ${FLTK_SOURCE_DIR}/fltk_git_rev.dat) - -set(git_revision "") # temporary variable - -execute_process(COMMAND - git rev-parse HEAD # --short=${git_rev_size} HEAD - OUTPUT_VARIABLE git_revision - OUTPUT_STRIP_TRAILING_WHITESPACE - WORKING_DIRECTORY ${FLTK_SOURCE_DIR} - ERROR_QUIET -) - -if(git_revision STREQUAL "") - - # Read git revision from a file generated by makesrcdist. - # This file is located in the FLTK source directory - - if(EXISTS ${git_rev_file}) - file(READ ${git_rev_file} git_revision) - string(STRIP "${git_revision}" git_revision) - else() - set(git_revision "unknown") - endif() -endif() - -set(FLTK_GIT_REVISION "${git_revision}" - CACHE STRING - "FLTK Git revision (do not change)" - FORCE) - -# debug and unset temporary variables -# fl_debug_var(git_revision) -unset(git_rev_file) -unset(git_revision) - -####################################################################### -# Include FindPkgConfig for later use of pkg-config -####################################################################### - -include(FindPkgConfig) - -# fl_debug_var(PKG_CONFIG_FOUND) -# fl_debug_var(PKG_CONFIG_EXECUTABLE) -# fl_debug_var(PKG_CONFIG_VERSION_STRING) - -####################################################################### -# GitHub Issue #1001: try to "repair" the CMake Cache -# GitHub Issue #1046: don't try "too hard" (see GitHub Issue) -####################################################################### -# -# Note: we renamed "our" CMake cache variable OPENGL_GLU_INCLUDE_DIR -# to FLTK_OPENGL_GLU_INCLUDE_DIR because the former is now defined -# in find_package(OpenGL) (FindOpenGL.cmake) since CMake 3.29.0. -# -# We remove "our" cache variable if OPENGL_GLU_INCLUDE_DIR is defined -# but FLTK_OPENGL_GLU_INCLUDE_DIR is not yet defined which indicates -# the first execution after the rename. -# -# FIXME: we can remove this code some time after the release of FLTK 1.4.0. - -if(DEFINED OPENGL_GLU_INCLUDE_DIR AND NOT DEFINED FLTK_OPENGL_GLU_INCLUDE_DIR) - unset(OPENGL_GLU_INCLUDE_DIR) - unset(OPENGL_GLU_INCLUDE_DIR CACHE) -endif() # (DEFINED OPENGL_GLU_INCLUDE_DIR AND NOT ...) - -####################################################################### -# Find header files... -####################################################################### - -if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "FreeBSD") - list(APPEND CMAKE_REQUIRED_INCLUDES /usr/local/include) -endif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "FreeBSD") - -fl_find_header(HAVE_ALSA_ASOUNDLIB_H alsa/asoundlib.h) -fl_find_header(HAVE_DLFCN_H dlfcn.h) -fl_find_header(HAVE_GL_GLU_H GL/glu.h) -fl_find_header(HAVE_LOCALE_H locale.h) -fl_find_header(HAVE_OPENGL_GLU_H OpenGL/glu.h) -fl_find_header(HAVE_STDIO_H stdio.h) -fl_find_header(HAVE_STRINGS_H strings.h) -fl_find_header(HAVE_SYS_SELECT_H sys/select.h) -fl_find_header(HAVE_SYS_STDTYPES_H sys/stdtypes.h) - -fl_find_header(HAVE_X11_XREGION_H "X11/Xlib.h;X11/Xregion.h") - -if(WIN32 AND NOT CYGWIN) - # we don't use pthreads on Windows (except for Cygwin, see options.cmake) - set(HAVE_PTHREAD_H 0) -else() - fl_find_header(HAVE_PTHREAD_H pthread.h) -endif(WIN32 AND NOT CYGWIN) - -# Do we have PTHREAD_MUTEX_RECURSIVE ? - -if(HAVE_PTHREAD_H) - try_compile(HAVE_PTHREAD_MUTEX_RECURSIVE - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/pthread_mutex_recursive.c - ) -else() - set(HAVE_PTHREAD_MUTEX_RECURSIVE 0) -endif() - -# Special case for Microsoft Visual Studio generator (MSVC): -# -# The header files <GL/glu.h> and <locale.h> are located in the SDK's -# for Visual Studio. If CMake is invoked from a desktop icon or the Windows -# menu it doesn't have the correct paths to find these header files. -# The CMake folks recommend not to search for these files at all, because -# they must always be there, but we do anyway. -# If we don't find them we issue a warning and continue anyway. -# -# Note: these cache variables can only be seen in "advanced" mode. - -if(MSVC) - - if(NOT HAVE_GL_GLU_H) - message(STATUS "Info: Header file GL/glu.h was not found. Continuing...") - set(HAVE_GL_GLU_H 1) - endif(NOT HAVE_GL_GLU_H) - - if(NOT HAVE_LOCALE_H) - message(STATUS "Info: Header file locale.h was not found. Continuing...") - set(HAVE_LOCALE_H 1) - endif(NOT HAVE_LOCALE_H) - -endif(MSVC) - -# Simulate the behavior of autoconf macro AC_HEADER_DIRENT, see: -# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Headers.html -# "Check for the following header files. For the first one that is found -# and defines 'DIR', define the listed C preprocessor macro ..." -# -# Note: we don't check if it really defines 'DIR', but we stop processing -# once we found the first suitable header file. - -fl_find_header(HAVE_DIRENT_H dirent.h) - -if(NOT HAVE_DIRENT_H) - fl_find_header(HAVE_SYS_NDIR_H sys/ndir.h) - if(NOT HAVE_SYS_NDIR_H) - fl_find_header(HAVE_SYS_DIR_H sys/dir.h) - if(NOT HAVE_SYS_DIR_H) - fl_find_header(HAVE_NDIR_H ndir.h) - endif(NOT HAVE_SYS_DIR_H) - endif(NOT HAVE_SYS_NDIR_H) -endif(NOT HAVE_DIRENT_H) - -#---------------------------------------------------------------------- -# The following code is used to find the include path for freetype -# headers to be able to #include <ft2build.h> in Xft.h. - -# where to find freetype headers - -find_path(FREETYPE_PATH freetype.h PATH_SUFFIXES freetype2) -find_path(FREETYPE_PATH freetype/freetype.h PATH_SUFFIXES freetype2) - -if(FREETYPE_PATH AND ((NOT APPLE) OR FLTK_BACKEND_X11)) - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${FREETYPE_PATH}) -endif(FREETYPE_PATH AND ((NOT APPLE) OR FLTK_BACKEND_X11)) - -mark_as_advanced(FREETYPE_PATH) - -####################################################################### -# libraries -find_library(LIB_dl dl) -if((NOT APPLE) OR FLTK_BACKEND_X11) - find_library(LIB_fontconfig fontconfig) -endif((NOT APPLE) OR FLTK_BACKEND_X11) -find_library(LIB_freetype freetype) -find_library(LIB_GL GL) -find_library(LIB_MesaGL MesaGL) -find_library(LIB_jpeg jpeg) -find_library(LIB_png png) -find_library(LIB_zlib z) -find_library(LIB_m m) - -mark_as_advanced(LIB_dl LIB_fontconfig LIB_freetype) -mark_as_advanced(LIB_GL LIB_MesaGL) -mark_as_advanced(LIB_jpeg LIB_png LIB_zlib) -mark_as_advanced(LIB_m) - -####################################################################### -# functions -include(CheckFunctionExists) - -# Save CMAKE_REQUIRED_LIBRARIES -# Note: CMAKE_REQUIRED_LIBRARIES must be set for each search and -# reset after the search to avoid to influence subsequent searches. -# The original value is restored after all searches. - -if(DEFINED CMAKE_REQUIRED_LIBRARIES) - set(SAVED_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) -else() - unset(SAVED_REQUIRED_LIBRARIES) -endif() -set(CMAKE_REQUIRED_LIBRARIES) - -if(HAVE_DLFCN_H) - set(HAVE_DLFCN_H 1) -endif(HAVE_DLFCN_H) - -set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) -check_symbol_exists(dlsym "dlfcn.h" HAVE_DLSYM) -set(CMAKE_REQUIRED_LIBRARIES) - -check_symbol_exists(localeconv "locale.h" HAVE_LOCALECONV) - -if(LIB_png) - set(CMAKE_REQUIRED_LIBRARIES ${LIB_png}) - check_symbol_exists(png_get_valid "png.h" HAVE_PNG_GET_VALID) - check_symbol_exists(png_set_tRNS_to_alpha "png.h" HAVE_PNG_SET_TRNS_TO_ALPHA) - set(CMAKE_REQUIRED_LIBRARIES) -endif(LIB_png) - -check_symbol_exists(scandir "dirent.h" HAVE_SCANDIR) -check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) - -# not really true but we convert strcasecmp calls to _stricmp calls in flstring.h -if(MSVC) - set(HAVE_STRCASECMP 1) -endif(MSVC) - -check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) - -check_symbol_exists(strlcat "string.h" HAVE_STRLCAT) -check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) -check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) - -check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) - -# Windows doesn't require '-lm' for trunc(), other platforms do -if(LIB_m AND NOT WIN32) - set(CMAKE_REQUIRED_LIBRARIES ${LIB_m}) -endif() - -check_symbol_exists(trunc "math.h" HAVE_TRUNC) - -set(CMAKE_REQUIRED_LIBRARIES) - -if(HAVE_SCANDIR AND NOT HAVE_SCANDIR_POSIX) - set(MSG "POSIX compatible scandir") - message(STATUS "Looking for ${MSG}") - try_compile(V - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/posixScandir.cxx - ) - if(V) - message(STATUS "${MSG} - found") - set(HAVE_SCANDIR_POSIX 1 CACHE INTERNAL "") - else() - message(STATUS "${MSG} - not found") - set(HAVE_SCANDIR_POSIX HAVE_SCANDIR_POSIX-NOTFOUND) - endif(V) -endif(HAVE_SCANDIR AND NOT HAVE_SCANDIR_POSIX) -mark_as_advanced(HAVE_SCANDIR_POSIX) - -# restore CMAKE_REQUIRED_LIBRARIES -if(DEFINED SAVED_REQUIRED_LIBRARIES) - set(CMAKE_REQUIRED_LIBRARIES ${SAVED_REQUIRED_LIBRARIES}) - unset(SAVED_REQUIRED_LIBRARIES) -else() - unset(CMAKE_REQUIRED_LIBRARIES) -endif() - -####################################################################### -# packages - -# Doxygen: necessary for HTML and PDF docs -find_package(Doxygen) - -# LaTex: necessary for PDF docs (note: FindLATEX doesn't return LATEX_FOUND) - -# Note: we only check existence of `latex' (LATEX_COMPILER), hence -# building the pdf docs may still fail because of other missing tools. - -set(LATEX_FOUND) -if(DOXYGEN_FOUND) - find_package(LATEX) - if(LATEX_COMPILER AND NOT LATEX_FOUND) - set(LATEX_FOUND YES) - endif(LATEX_COMPILER AND NOT LATEX_FOUND) -endif(DOXYGEN_FOUND) - -# message("Doxygen found : ${DOXYGEN_FOUND}") -# message("LaTex found : ${LATEX_FOUND}") -# message("LaTex Compiler : ${LATEX_COMPILER}") - -# Cleanup: unset local variables - -unset(CMAKE_REQUIRED_QUIET) diff --git a/CMake/setup.cmake b/CMake/setup.cmake deleted file mode 100644 index 266e1299a..000000000 --- a/CMake/setup.cmake +++ /dev/null @@ -1,209 +0,0 @@ -# -# CMakeLists.txt to build the FLTK project using CMake (www.cmake.org) -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# basic setup -####################################################################### - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin) -set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib) -set(ARCHIVE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib) - -# Search for modules in the FLTK source dir first -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") - -# Setup install locations (requires CMake 2.8.4) - -include(GNUInstallDirs) - -set(FLTK_BINDIR ${CMAKE_INSTALL_BINDIR} CACHE PATH - "Binary install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") -set(FLTK_LIBDIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH - "Library install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") -set(FLTK_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH - "Public header install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") -set(FLTK_DATADIR ${CMAKE_INSTALL_DATADIR} CACHE PATH - "Non-arch data install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") -set(FLTK_MANDIR ${CMAKE_INSTALL_MANDIR} CACHE PATH - "Manual install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") -set(FLTK_DOCDIR ${CMAKE_INSTALL_DATADIR}/doc CACHE PATH - "Non-arch doc install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.") - - -####################################################################### -# Initialize variables needed to collect include directories etc.. -# Some of these variables are used to *append* other values later -####################################################################### - -set(FLTK_BUILD_INCLUDE_DIRECTORIES "") -set(FLTK_IMAGE_INCLUDE_DIRECTORIES "") -set(FLTK_IMAGE_LIBRARIES "") -set(FLTK_IMAGE_LIBRARIES_SHARED "") - -set(FLTK_CFLAGS "") -set(FLTK_LIBRARIES "") -set(FLTK_LIBRARIES_SHARED "") - -# Remember root of FLTK source directory in case we're later in a subdirectory. -# Used for instance to find the source directory for doxygen docs - -set(FLTK_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - -if(FLTK_SOURCE_DIR STREQUAL ${CMAKE_SOURCE_DIR}) - set(FLTK_IS_TOPLEVEL TRUE) -else() - set(FLTK_IS_TOPLEVEL FALSE) -endif() - -# Note: FLTK_INCLUDE_DIRS is used to export the required include directories -# in FLTKConfig.cmake etc. -# ### FIXME ### check if we really need this ... - -set(FLTK_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - -# FLTK_BUILD_INCLUDE_DIRECTORIES is used to build the main FLTK lib - -set(FLTK_BUILD_INCLUDE_DIRECTORIES) - -# Some of these variables are used to *append* other values later - -set(FLTK_LDLIBS "") -set(FLTK_LIBRARIES "") -set(IMAGELIBS "") -set(LDFLAGS "") -set(LINK_LIBS "") -set(STATICIMAGELIBS "") - -####################################################################### -# platform dependent information -####################################################################### - -# set where config files go -if(WIN32 AND NOT CYGWIN) - set(FLTK_CONFIG_PATH CMake) -elseif(APPLE AND NOT FLTK_BACKEND_X11) - set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) -else() - set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) -endif(WIN32 AND NOT CYGWIN) - -include(TestBigEndian) -TEST_BIG_ENDIAN(WORDS_BIGENDIAN) - -if(CMAKE_GENERATOR MATCHES "Xcode") - # Tell Xcode to regenerate scheme information automatically whenever the - # CMake configuration changes without asking the user - set(CMAKE_XCODE_GENERATE_SCHEME 1) -endif() - -if(APPLE) - # Check if the __MAC_OS_X_VERSION_MAX_ALLOWED compile time macro is at least - # the version encoded in SDK_VERSION and return TRUE or FALSE in RESULT. - # Note 1: try_compile() always creates an *internal* CMake cache variable for - # the result which we set to 'FLTK_CHECK_OSX_MAX_ALLOWED_${SDK_VERSION}'. - # Note 2: 'FLTK_' to avoid polluting the cache if FLTK is built as a subproject. - # Note 3: We don't care about the cache, i.e. we run try_compile() unconditionally - # so users can switch SDK's, particularly if they *upgrade* Xcode. - - function(CHECK_OSX_MAX_ALLOWED SDK_VERSION RESULT) - set(_result FLTK_CHECK_OSX_MAX_ALLOWED_${SDK_VERSION}) - try_compile(${_result} - ${CMAKE_CURRENT_BINARY_DIR}/CHECK_OSX_MAX_ALLOWED_${SDK_VERSION} - SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CMake/macOSMaxAllowed.c - COMPILE_DEFINITIONS -DSDK_VERSION_CHECK=${SDK_VERSION} - ) - set(${RESULT} ${${_result}} PARENT_SCOPE) - endfunction() - - # APPLE macOS setup - set(HAVE_STRCASECMP 1) - set(HAVE_DIRENT_H 1) - set(HAVE_SNPRINTF 1) - set(HAVE_VSNPRINTF 1) - set(HAVE_SCANDIR 1) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated") - if(FLTK_BACKEND_X11) - if(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) # a.k.a. macOS version ≥ 10.13 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LIBCPP_HAS_THREAD_API_PTHREAD") - endif(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) - else() - set(FLTK_COCOA_FRAMEWORKS "-framework Cocoa") - if (NOT (CMAKE_OSX_ARCHITECTURES STREQUAL "ppc" OR CMAKE_OSX_ARCHITECTURES STREQUAL "i386")) - CHECK_OSX_MAX_ALLOWED(150000 SDK_15_AVAILABLE) # at least SDK 15.0.0 ? - if (SDK_15_AVAILABLE) - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework ScreenCaptureKit") # 15.0 - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework UniformTypeIdentifiers") # 11.0 - else(SDK_15_AVAILABLE) - CHECK_OSX_MAX_ALLOWED(110000 SDK_11_AVAILABLE) # at least SDK 11.0.0 ? - if (SDK_11_AVAILABLE) - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework UniformTypeIdentifiers") - endif(SDK_11_AVAILABLE) - endif(SDK_15_AVAILABLE) - endif() - endif(FLTK_BACKEND_X11) -endif(APPLE) - -if(WIN32) - # we do no longer define WIN32 or _WIN32 (since FLTK 1.4.0) - # ... but if we did, we'd define _WIN32 (since FLTK 1.4.0) - # add_definitions (-D_WIN32) - if(MSVC) - add_definitions (-DWIN32_LEAN_AND_MEAN) - add_definitions (-D_CRT_SECURE_NO_WARNINGS) - if(NOT MSVC_VERSION VERSION_LESS 1900) # Visual Studio 2015 - add_compile_options (/utf-8) # equivalent to `/source-charset:utf-8 /execution-charset:utf-8` - endif() - set(BORDER_WIDTH 2) - endif(MSVC) - - # Don't use the following code, it breaks building with MSYS2/UCRT64 - # See GitHub PR #1167. Solution is to remove the entire block! - - ### if(MINGW AND EXISTS /mingw) - ### list(APPEND CMAKE_PREFIX_PATH /mingw) - ### endif(MINGW AND EXISTS /mingw) - -endif(WIN32) - -####################################################################### -# size of ints -include(CheckTypeSize) - -CHECK_TYPE_SIZE(short SIZEOF_SHORT) -CHECK_TYPE_SIZE(int SIZEOF_INT) -CHECK_TYPE_SIZE(long SIZEOF_LONG) -CHECK_TYPE_SIZE("long long" HAVE_LONG_LONG) - -if(${SIZEOF_SHORT} MATCHES "^2$") - set(U16 "unsigned short") -endif(${SIZEOF_SHORT} MATCHES "^2$") - -if(${SIZEOF_INT} MATCHES "^4$") - set(U32 "unsigned") -else() - if(${SIZEOF_LONG} MATCHES "^4$") - set(U32 "unsigned long") - endif(${SIZEOF_LONG} MATCHES "^4$") -endif(${SIZEOF_INT} MATCHES "^4$") - -if(${SIZEOF_INT} MATCHES "^8$") - set(U64 "unsigned") -else() - if(${SIZEOF_LONG} MATCHES "^8$") - set(U64 "unsigned long") - endif(${SIZEOF_LONG} MATCHES "^8$") -endif(${SIZEOF_INT} MATCHES "^8$") diff --git a/CMake/variables.cmake b/CMake/variables.cmake deleted file mode 100644 index 6fcaed395..000000000 --- a/CMake/variables.cmake +++ /dev/null @@ -1,177 +0,0 @@ -# -# This file sets variables for common use in export.cmake and install.cmake -# Originally written by Michael Surette -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### - -set(DEBUG_VARIABLES_CMAKE 0) -if(DEBUG_VARIABLES_CMAKE) - message(STATUS "[** variables.cmake **]") - fl_debug_var(HAVE_DLSYM) - fl_debug_var(CMAKE_DL_LIBS) - fl_debug_var(CMAKE_EXE_LINKER_FLAGS) - fl_debug_var(LDFLAGS) - fl_debug_var(GLLIBS) - fl_debug_var(IMAGELIBS) - fl_debug_var(STATICIMAGELIBS) - fl_debug_var(FLTK_LDLIBS) - fl_debug_var(LIB_jpeg) - fl_debug_var(LIB_png) - fl_debug_var(LIB_zlib) - fl_debug_var(FLTK_LIBRARIES) -endif(DEBUG_VARIABLES_CMAKE) - -####################################################################### -# add several libraries -# FIXME: libraries may need reordering. -# FIXME: check fontconfig conditions (only if Xft is used or ...) - -if(WIN32) - list(APPEND FLTK_LDLIBS -lole32 -luuid -lcomctl32 -lws2_32 -lwinspool) -elseif(APPLE AND NOT FLTK_BACKEND_X11) - list(APPEND FLTK_LDLIBS ${FLTK_COCOA_FRAMEWORKS}) -elseif(FLTK_USE_WAYLAND) - foreach(_lib WLDCURSOR WLDCLIENT XKBCOMMON) - list(APPEND FLTK_LDLIBS "${${_lib}_LDFLAGS}") - endforeach() - if(FLTK_USE_DBUS AND DBUS_FOUND) - list(APPEND FLTK_LDLIBS "${DBUS_LDFLAGS}") - endif() - if(USE_SYSTEM_LIBDECOR) - list(APPEND FLTK_LDLIBS ${SYSTEM_LIBDECOR_LDFLAGS}) - endif(USE_SYSTEM_LIBDECOR) -else() - list(APPEND FLTK_LDLIBS -lm) -endif(WIN32) - -if(LIB_fontconfig) - list(APPEND FLTK_LDLIBS -lfontconfig) -endif(LIB_fontconfig) - -# add "-ldl" or whatever is necessary according to CMake (CMAKE_DL_LIBS) -if(HAVE_DLSYM) - foreach(LIB ${CMAKE_DL_LIBS}) - list(APPEND FLTK_LDLIBS "-l${LIB}") - endforeach() -endif(HAVE_DLSYM) - -####################################################################### -# Set variables for fltk-config (generated from fltk-config.in) -####################################################################### - -# Variables in fltk-config.in (@VAR@) are used in configure(.ac) -# and in CMake so their names and usage must be synchronized. -# CMake generates two instances of fltk-config, one that can be used -# directly in the build tree (see export.cmake) and one that is copied -# to the installation directory (see install.cmake). Common variables -# should be set here, whereas variables with different values should -# be set in install.cmake or export.cmake, respectively. - -if(WIN32) - set(LDFLAGS "${CMAKE_EXE_LINKER_FLAGS} -mwindows") -endif() - -set(IMAGELIBS) -set(STATICIMAGELIBS) - -if(FLTK_USE_BUNDLED_JPEG) - list(APPEND IMAGELIBS -lfltk_jpeg) - list(APPEND STATICIMAGELIBS \$libdir/libfltk_jpeg.a) -else() - if(LIB_jpeg) - # fl_debug_var(LIB_jpeg) - list(APPEND IMAGELIBS ${LIB_jpeg}) - list(APPEND STATICIMAGELIBS ${LIB_jpeg}) - endif(LIB_jpeg) -endif(FLTK_USE_BUNDLED_JPEG) - -if(FLTK_USE_BUNDLED_PNG) - list(APPEND IMAGELIBS -lfltk_png) - list(APPEND STATICIMAGELIBS \$libdir/libfltk_png.a) -else() - if(LIB_png) - # fl_debug_var(LIB_png) - list(APPEND IMAGELIBS ${LIB_png}) - list(APPEND STATICIMAGELIBS ${LIB_png}) - endif(LIB_png) -endif(FLTK_USE_BUNDLED_PNG) - -if(FLTK_USE_BUNDLED_ZLIB) - list(APPEND IMAGELIBS -lfltk_z) - list(APPEND STATICIMAGELIBS \$libdir/libfltk_z.a) -else() - if(LIB_zlib) - list(APPEND IMAGELIBS ${LIB_zlib}) - list(APPEND STATICIMAGELIBS ${LIB_zlib}) - endif(LIB_zlib) -endif(FLTK_USE_BUNDLED_ZLIB) - -# remove duplicates from CMake "list" variables for fltk-config - -list(REMOVE_DUPLICATES GLLIBS) -list(REMOVE_DUPLICATES FLTK_LDLIBS) -list(REMOVE_DUPLICATES IMAGELIBS) -list(REMOVE_DUPLICATES STATICIMAGELIBS) - -# convert CMake lists to strings with spaces for fltk-config - -string(REPLACE ";" " " GLLIBS "${GLLIBS}") -string(REPLACE ";" " " LIBS "${FLTK_LDLIBS}") -string(REPLACE ";" " " IMAGELIBS "${IMAGELIBS}") -string(REPLACE ";" " " STATICIMAGELIBS "${STATICIMAGELIBS}") - -####################################################################### -set(CC ${CMAKE_C_COMPILER}) -set(CXX ${CMAKE_CXX_COMPILER}) - -set(ARCHFLAGS ${FLTK_ARCHFLAGS}) - -string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_UPPER) -if(${BUILD_UPPER}) - set(CFLAGS "${CMAKE_C_FLAGS_${BUILD_UPPER}} ${CFLAGS}") -endif(${BUILD_UPPER}) - -set(CFLAGS "${FLTK_OPTION_OPTIM} ${CMAKE_C_FLAGS} ${CFLAGS}") -foreach(arg ${FLTK_CFLAGS}) - set(CFLAGS "${CFLAGS} ${arg}") -endforeach(arg ${FLTK_CFLAGS}) - -set(CXXFLAGS "${CFLAGS}") - -if(${CMAKE_SYSTEM_NAME} STREQUAL "AIX") - set(SHAREDSUFFIX "_s") -else() - set(SHAREDSUFFIX "") -endif(${CMAKE_SYSTEM_NAME} STREQUAL "AIX") - -if(DEBUG_VARIABLES_CMAKE) - message(STATUS "") # empty line - fl_debug_var(HAVE_DLSYM) - fl_debug_var(CMAKE_DL_LIBS) - fl_debug_var(CMAKE_EXE_LINKER_FLAGS) - fl_debug_var(LDFLAGS) - fl_debug_var(FLTK_LDLIBS) - fl_debug_var(LIBS) - fl_debug_var(GLLIBS) - fl_debug_var(IMAGELIBS) - fl_debug_var(STATICIMAGELIBS) - fl_debug_var(LIB_jpeg) - fl_debug_var(LIB_png) - fl_debug_var(LIB_zlib) - fl_debug_var(FLTK_LIBRARIES) - message(STATUS "[** end of variables.cmake **]") -endif(DEBUG_VARIABLES_CMAKE) -unset(DEBUG_VARIABLES_CMAKE) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 347324563..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,493 +0,0 @@ -# -# Main CMakeLists.txt to build the FLTK project using CMake -# Originally written by Michael Surette -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -####################################################################### -# Prevent building in the source tree - don't pollute the sources -####################################################################### - -if("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") - message("") - message(STATUS "=======================================================================") - message(STATUS " NOTE: In-source builds of FLTK are disabled to prevent writing to the") - message(STATUS " NOTE: source tree. Please create a subfolder (e.g. 'build') and use") - message(STATUS " NOTE: `cmake ..` inside it or use for instance `cmake . -B build`.") - message(STATUS " NOTE: CMake will, however, create CMakeCache.txt and CMakeFiles/* .") - message(STATUS " NOTE: You must delete CMakeCache.txt and CMakeFiles/* manually.") - message(STATUS "=======================================================================") - message("") - message(FATAL_ERROR "*** In-source builds are disabled, please read notes above! ***") -endif() - -####################################################################### -# Set CMake minimum version first: must be set before `project()` -####################################################################### - -# Minimum CMake version required by FLTK 1.5 - -# Note 1: Currently the same as for FLTK 1.4.x but will likely be raised -# depending on new features introduced in FLTK 1.5. - -cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR) - -# Since CMake 3.4: enable symbol export from all executable targets -# cmake_policy(SET CMP0065 OLD) - -####################################################################### -# define the FLTK project and version -####################################################################### - -project(FLTK VERSION 1.5.0) - -####################################################################### -# set the required C++ standard -- may be overridden by the user -####################################################################### - -# Note 1: We don't check if the user sets a standard older than C++11, -# but if they do, the build will fail. -# Note 2: For optimal portability we disable compiler specific -# extensions, but this can also be overridden by the user. -# Note 3: This code is experimental and intentionally undocumented. -# It may be removed or changed w/o notice. - -if(DEFINED CMAKE_CXX_STANDARD) - if(CMAKE_CXX_STANDARD EQUAL 98 OR CMAKE_CXX_STANDARD LESS 11) - message(FATAL_ERROR "The FLTK project requires at least C++11") - endif() -else() - set(CMAKE_CXX_STANDARD 11 CACHE STRING "Minimal C++ Standard") -endif() - -if(NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED) - set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Minimal C++ Standard Required?") -endif() - -if(NOT DEFINED CMAKE_CXX_EXTENSIONS) - set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Use Compiler Specific C++ Extensions") -endif() - -####################################################################### -# include macro and function definitions for general usage -####################################################################### - -include(CMake/fl_debug_var.cmake) -include(CMake/fl_debug_pkg.cmake) -include(CMake/fl_add_library.cmake) - -# right now we don't use compatibility functions -# include(CMake/compatibility.cmake) - -if(0) # debug most important CMake variables and features - # FLTK version - fl_debug_var(FLTK_VERSION_MAJOR) - fl_debug_var(FLTK_VERSION_MINOR) - fl_debug_var(FLTK_VERSION_PATCH) - fl_debug_var(FLTK_VERSION) - # CMake version and C++ standard - fl_debug_var(CMAKE_VERSION) - fl_debug_var(CMAKE_CXX_STANDARD) - fl_debug_var(CMAKE_CXX_STANDARD_REQUIRED) - fl_debug_var(CMAKE_CXX_EXTENSIONS) - # Build platform - fl_debug_var(MSVC) - fl_debug_var(MINGW) - fl_debug_var(MSYS) - fl_debug_var(UNIX) - fl_debug_var(APPLE) - fl_debug_var(CMAKE_CROSSCOMPILING) -endif() - -# Set FLTK_VERSION in the cache so user projects can access it, -# for instance if FLTK is built as a subproject (FetchContent) - -set(FLTK_VERSION ${FLTK_VERSION} CACHE STRING - "FLTK version: generated by CMake, do not change" FORCE) - -####################################################################### -# basic setup -####################################################################### -include(CMake/setup.cmake) - -####################################################################### -# check for headers, libraries and functions -####################################################################### -include(CMake/resources.cmake) - -####################################################################### -# options -####################################################################### -include(CMake/options.cmake) - -####################################################################### -# generate version numbers and config headers -####################################################################### - -include(CMake/gen_config.cmake) - -####################################################################### -# Disable automatic code signing on macOS when using Xcode. -# This *MUST* be done after including CMake/options.cmake. -# Users can still enable code signing if they have a valid certificate. -# Details about code signing are beyond the scope of this document. -####################################################################### -# FIXME: some of the conditions below may be redundant, and the code -# below should be improved in a later version. -####################################################################### - -if(APPLE) # AND NOT FLTK_BACKEND_X11 AND CMAKE_GENERATOR STREQUAL "Xcode") - if(NOT DEFINED CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED) - set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED OFF CACHE BOOL - "Allow Code Signing when using Xcode") - endif() -endif() - -####################################################################### -# print (debug) several build variables and options -####################################################################### - -set(debug_build 0) # set to 1 to show debug info - -if(debug_build) - message("") - message(STATUS "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt: set 'debug_build' to 0 to disable the following info:") - fl_debug_var(WIN32) - fl_debug_var(MINGW) - fl_debug_var(CYGWIN) - fl_debug_var(MSVC) - fl_debug_var(UNIX) - fl_debug_var(APPLE) - fl_debug_var(CMAKE_BUILD_TYPE) - fl_debug_var(CMAKE_SIZEOF_VOID_P) - fl_debug_var(FLTK_OPTION_OPTIM) - fl_debug_var(CMAKE_C_FLAGS) - fl_debug_var(CMAKE_CXX_FLAGS) - fl_debug_var(CMAKE_EXE_LINKER_FLAGS) - message(STATUS "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt: end of debug_build info.") -endif(debug_build) - -unset(debug_build) - -####################################################################### -# build the standard FLTK libraries -####################################################################### - -add_subdirectory(src) - -####################################################################### -# MSVC only: build a special object library for shared libs -####################################################################### - -# When linking programs against the shared FLTK libraries we need to -# compile and link with fl_call_main.c, but this must not be compiled -# with macro FL_DLL, whereas all the other source file(s) *must* be -# compiled with macro FL_DLL to link against the shared libs. -# The latter is ensured by CMake properties of the shared libraries. -# -# Solution: build an extra object library with just this one file and -# link all the "shared" executables additionally against this object -# library to resolve the symbol 'WinMain()'. -# -# The object library is called 'call_main' and is available for fluid, -# fltk-options, and all test programs that link against shared FLTK -# libraries when using MSVC (Microsoft Visual Studio). -# -# ;-) I *love* Visual Studio ;-) - -if(FLTK_BUILD_SHARED_LIBS AND MSVC) - add_library(call_main OBJECT EXCLUDE_FROM_ALL src/fl_call_main.c) -endif() - -####################################################################### -# set CMAKE_INSTALL_RPATH for shared libraries on macOS before -# building executables. This assumes standard install locations like -# - prefix/bin executable (path part 2) or bundle (path part 3) -# - prefix/lib shared library -# These RPATH settings are effective when executables and shared libs -# are *installed*, they don't affect executables in the build folder. -# Affected executables (when linked against the shared FLTK libs): -# - fluid -# - fltk-options -# - test/* (e.g. games) -# Note: Path part 1 ("@loader_path") is used to find shared libraries -# in the same folder as the executable file (everywhere). -####################################################################### - -if(FLTK_BUILD_SHARED_LIBS AND APPLE AND NOT FLTK_BACKEND_X11) - set(CMAKE_INSTALL_RPATH - @loader_path - @loader_path/../lib - @loader_path/../../../../lib) -endif() - -####################################################################### -# build fluid (optional) -####################################################################### - -set(FLTK_FLUID_EXECUTABLE "") - -if(FLTK_BUILD_FLUID) - add_subdirectory(fluid) -endif(FLTK_BUILD_FLUID) - -# Set FLTK_FLUID_EXECUTABLE in the cache for user projects. -# This can be used if FLTK has been built as a subproject. - -set(FLTK_FLUID_EXECUTABLE - "${FLTK_FLUID_EXECUTABLE}" CACHE STRING - "FLTK's 'fluid' executable") - -####################################################################### -# build fltk-options -####################################################################### - -if(FLTK_BUILD_FLTK_OPTIONS) - add_subdirectory(fltk-options) -endif(FLTK_BUILD_FLTK_OPTIONS) - -####################################################################### -# build utilities -####################################################################### - -add_subdirectory(util) - -####################################################################### -# variables shared by export and install -# export.cmake creates configuration files for direct use in a built but uninstalled FLTK -# install.cmake creates these files for an installed FLTK -# these two would only differ in paths, so common variables are set here -####################################################################### - -include(CMake/variables.cmake) - -####################################################################### -# final config and export -####################################################################### - -include(CMake/export.cmake) - -####################################################################### -# options to build test/demo and example programs -####################################################################### - -# general test programs for FLTK development - -if(FLTK_BUILD_TEST) - add_subdirectory(test) -endif(FLTK_BUILD_TEST) - -# example programs for FLTK users - -if(FLTK_BUILD_EXAMPLES) - add_subdirectory(examples) -endif(FLTK_BUILD_EXAMPLES) - -# screenshot programs for FLTK developers - -if(FLTK_BUILD_SCREENSHOTS) - add_subdirectory(screenshots) -endif(FLTK_BUILD_SCREENSHOTS) - -####################################################################### -# Create and install version config file 'FLTKConfigVersion.cmake' -####################################################################### - -include(CMakePackageConfigHelpers) - -write_basic_package_version_file(FLTKConfigVersion.cmake - # [VERSION requiredVersion] # defaults to project version - COMPATIBILITY SameMinorVersion -) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/FLTKConfigVersion.cmake - DESTINATION ${FLTK_CONFIG_PATH} -) - -####################################################################### -# installation -####################################################################### - -include(CMake/install.cmake) - -####################################################################### -# Generate Library Export Headers *** EXPERIMENTAL *** WIP *** -####################################################################### - -# Enable (1) or disable (0) generation of experimental headers (WIP) -set(GENERATE_EXPORT_HEADERS 0) - -if(FLTK_BUILD_SHARED_LIBS AND GENERATE_EXPORT_HEADERS) - - include(GenerateExportHeader) - - generate_export_header(fltk_SHARED - BASE_NAME fl - EXPORT_FILE_NAME FL/fltk_export.h - STATIC_DEFINE FL_STATIC_LIB - ) - - if(NOT MSVC) - - # Visual Studio builds only one shared lib (DLL) - - generate_export_header(fltk_images_SHARED - BASE_NAME fl_images - EXPORT_FILE_NAME FL/fltk_images_export.h - STATIC_DEFINE FL_STATIC_LIB - ) - - generate_export_header(fltk_forms_SHARED - BASE_NAME fl_forms - EXPORT_FILE_NAME FL/fltk_forms_export.h - STATIC_DEFINE FL_STATIC_LIB - ) - - generate_export_header(fltk_gl_SHARED - BASE_NAME fl_gl - EXPORT_FILE_NAME FL/fltk_gl_export.h - STATIC_DEFINE FL_STATIC_LIB - ) - - endif(NOT MSVC) - -endif(FLTK_BUILD_SHARED_LIBS AND GENERATE_EXPORT_HEADERS) - -####################################################################### -# Configure CPack only if this is the top level project. -# The logic may be extended if including CPack is made optional. -# Currently it is included unconditionally for testing purposes. -####################################################################### - -if(FLTK_IS_TOPLEVEL) - - add_subdirectory(package) - -endif() - -####################################################################### -# Output Build Configuration Summary -####################################################################### - -include(FeatureSummary) # CMake Feature Summary -include(CMake/fl_summary.cmake) # special FLTK summary macros - -# CMake Feature Summary - -message("") -set(_descr "${PROJECT_NAME} ${FLTK_VERSION} generated by CMake ${CMAKE_VERSION}") -feature_summary(WHAT ALL DESCRIPTION "Configuration Summary for ${_descr} --\n") - -# FLTK specific build configuration and options (see macros in fl_summary.cmake) - -# "title" dir build (bool) option to set -fl_summary_build("Static libraries" lib TRUE "n/a") -fl_summary_build("Shared libraries" lib FLTK_BUILD_SHARED_LIBS FLTK_BUILD_SHARED_LIBS) -fl_summary_build("The forms library" lib FLTK_BUILD_FORMS FLTK_BUILD_FORMS) -fl_summary_build("The OpenGL library" lib FLTK_USE_GL FLTK_BUILD_GL) -fl_summary_build("Pen/tablet support" lib FLTK_HAVE_PEN_SUPPORT FLTK_OPTION_PEN_SUPPORT) - -message(STATUS "") - -fl_summary_build("fluid" bin FLTK_BUILD_FLUID FLTK_BUILD_FLUID) -fl_summary_build("fltk-options" bin FLTK_BUILD_FLTK_OPTIONS FLTK_BUILD_FLTK_OPTIONS) -fl_summary_build("Test programs" bin/test FLTK_BUILD_TEST FLTK_BUILD_TEST) -fl_summary_build("Example programs" bin/examples FLTK_BUILD_EXAMPLES FLTK_BUILD_EXAMPLES) -fl_summary_build("Screenshot programs" bin/screenshots FLTK_BUILD_SCREENSHOTS FLTK_BUILD_SCREENSHOTS) - -message(STATUS "") - -fl_summary("FLTK Library (API) version" "${FLTK_VERSION}") -fl_summary("ABI version (FL_ABI_VERSION)" "${FL_ABI_VERSION}") - -if(CMAKE_BUILD_TYPE STREQUAL "") - fl_summary("Build configuration" "<unspecified>") -else() - fl_summary("Build configuration" "${CMAKE_BUILD_TYPE}") -endif() -fl_summary("Installation prefix" "${CMAKE_INSTALL_PREFIX}") - -message("") -# "title" name system library if used -fl_summary_image("Bundled Libraries" JPEG LIB_jpeg) -fl_summary_image("" PNG LIB_png) -fl_summary_image("" ZLIB LIB_zlib) - -if(FLTK_USE_WAYLAND) - if(USE_SYSTEM_LIBDECOR) - fl_summary("" "Libdecor = System: ${SYSTEM_LIBDECOR_LINK_LIBRARIES}") - else() - fl_summary("" "Libdecor = Bundled") - endif() - fl_summary_yn("Use DBUS" DBUS_FOUND) -endif(FLTK_USE_WAYLAND) - -message("") - -if(UNIX AND NOT (APPLE AND NOT FLTK_BACKEND_X11)) - - if(FLTK_USE_WAYLAND) - if(FLTK_BACKEND_X11) - fl_summary("Use Wayland" "Yes (can also run as X11 client)") - else() - fl_summary("Use Wayland" "Yes (cannot run as X11 client)") - endif(FLTK_BACKEND_X11) - else() - fl_summary("Use Wayland" "No (X11 is used)") - endif(FLTK_USE_WAYLAND) - - fl_summary_yn("All drawing uses Cairo" FLTK_USE_CAIRO) - - fl_summary_yn("Use Pango" USE_PANGO) - if(NOT USE_PANGO) - fl_summary_yn("Use Xft" USE_XFT) - endif() - -endif() - -set(title "Fl_Cairo_Window support") -if(FLTK_HAVE_CAIROEXT) - fl_summary("${title}" "Yes (extended)") -elseif(FLTK_HAVE_CAIRO) - fl_summary("${title}" "Yes (standard)") -else() - fl_summary("${title}" "No") -endif() - -message("") - -fl_summary( "CMAKE_CXX_STANDARD" "${CMAKE_CXX_STANDARD}") -fl_summary_yn("CMAKE_CXX_STANDARD_REQUIRED" CMAKE_CXX_STANDARD_REQUIRED) -fl_summary_yn("CMAKE_CXX_EXTENSIONS" CMAKE_CXX_EXTENSIONS) - -message("") -message(STATUS "End of Configuration Summary --\n") - -# optional info for "modern CMake" - -if(0) # debug built library and fluid targets - message(STATUS "------------------------ TARGETS ------------------------") - foreach(tgt fltk fluid fluid-cmd options options-cmd images gl forms jpeg png z) - if(TARGET fltk::${tgt}) - message("Target: fltk::${tgt}") - # fl_debug_target(fltk::${tgt}) - endif() - if(TARGET fltk::${tgt}-shared) - message("Target: fltk::${tgt}-shared") - # fl_debug_target(fltk::${tgt}-shared) - endif() - endforeach() - message(STATUS "---------------------------------------------------------") -endif() diff --git a/FL/2026-02-05-claudemd.txt b/FL/2026-02-05-claudemd.txt new file mode 100644 index 000000000..7a4c1a861 --- /dev/null +++ b/FL/2026-02-05-claudemd.txt @@ -0,0 +1,1962 @@ + +╭─── Claude Code v2.1.6 ───────────────────────────────────────────────────────╮ +│ │ Tips for getting │ +│ Welcome back Maxim! │ started │ +│ │ Run /init to create a … │ +│ ▗ ▗ ▖ ▖ │ ─────────────────────── │ +│ │ Recent activity │ +│ ▘▘ ▝▝ │ No recent activity │ +│ │ │ +│ Opus 4.5 · Claude Max · │ │ +│ maksimgrinberg01@gmail.com's Organization │ │ +│ ~/Desktop/fltk/FL │ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +══════════════════ Conversation compacted · ctrl+o for history ═════════════════ + ⎿ Referenced file ../CMake/options.cmake + ⎿ Read ../CMakeLists.txt (405 lines) + ⎿ Referenced file ../src/CMakeLists.txt + ⎿ Read platform.H (72 lines) + ⎿ Todo list read (10 items) + ⎿ Plan file referenced (~/.claude/plans/compiled-petting-babbage.md) + +⏺ Продолжаю работу над Фазой 1. Нужно дочистить CMake/options.cmake, затем + перейти к очистке #ifdef мёртвых веток в исходниках. + +⏺ Read(~/Desktop/fltk/CMake/options.cmake) + ⎿ Read 749 lines + +⏺ Вижу оставшиеся проблемы в options.cmake. Нужно убрать: + 1. set(FLTK_USE_WAYLAND FALSE) (строка 240) + 2. if(NOT FLTK_USE_WAYLAND) guard (строка 570) + 3. FLTK_USE_WAYLAND в условии Pango (строка 632) + 4. Весь блок if(FLTK_USE_WAYLAND) для GTK (строки 639-653) + 5. if(APPLE AND FLTK_BACKEND_X11) для fontconfig (строки 659-661) + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Removed 1 line + 237 ############################################################## + ######### + 238 + 239 list(APPEND FLTK_LDLIBS -lm) + 240 -set(FLTK_USE_WAYLAND FALSE) + 240 + 241 ############################################################## + ######### + 242 + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Added 1 line, removed 3 lines + 566 ############################################################## + ######### + 567 if(X11_Xft_FOUND) + 568 option(FLTK_USE_PANGO "use lib Pango" OFF) + 569 - if(NOT FLTK_USE_WAYLAND) + 570 - option(FLTK_GRAPHICS_CAIRO "all drawing to X11 windows use + -s Cairo" OFF) + 571 - endif(NOT FLTK_USE_WAYLAND) + 569 + option(FLTK_GRAPHICS_CAIRO "all drawing to X11 windows uses + +Cairo" OFF) + 570 if(NOT FLTK_GRAPHICS_CAIRO) + 571 option(FLTK_USE_XFT "use lib Xft" ON) + 572 endif() + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Added 1 line, removed 18 lines + 626 + 627 endif((PANGOXFT_FOUND OR NOT USE_PANGOXFT) AND PANGOCAIRO_FO + UND AND CAIRO_FOUND) + 628 + 629 - if(USE_PANGO AND (FLTK_GRAPHICS_CAIRO OR FLTK_USE_WAYLAND)) + 629 + if(USE_PANGO AND FLTK_GRAPHICS_CAIRO) + 630 set(FLTK_USE_CAIRO 1) + 631 - # fl_debug_var(FLTK_USE_CAIRO) + 631 endif() + 632 + 633 endif((X11_Xft_FOUND OR NOT USE_PANGOXFT) AND FLTK_USE_PANGO) + 634 + 636 -if(FLTK_USE_WAYLAND) + 637 - + 638 - # Note: Disable FLTK_USE_LIBDECOR_GTK to get cairo titlebars + - rather than GTK + 639 - if(FLTK_USE_LIBDECOR_GTK AND NOT USE_SYSTEM_LIBDECOR) + 640 - pkg_check_modules(GTK IMPORTED_TARGET gtk+-3.0) + 641 - if(GTK_FOUND) + 642 - list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${GTK_INCLUDE + -_DIRS}) + 643 - list(APPEND FLTK_LDLIBS ${GTK_LDFLAGS}) + 644 - else() + 645 - message(WARNING "Installation of the development files f + -or the GTK library " + 646 - "(e.g., libgtk-3-dev) is recommended when using the gnom + -e desktop.") + 647 - endif(GTK_FOUND) + 648 - endif(FLTK_USE_LIBDECOR_GTK AND NOT USE_SYSTEM_LIBDECOR) + 649 - + 650 -endif() + 651 - + 635 if(FLTK_USE_XFT) + 636 set(USE_XFT X11_Xft_FOUND) + 637 list(APPEND FLTK_LDLIBS -lXft) + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Removed 3 lines + 636 set(USE_XFT X11_Xft_FOUND) + 637 list(APPEND FLTK_LDLIBS -lXft) + 638 set(FLTK_XFT_FOUND TRUE) + 639 - if(APPLE AND FLTK_BACKEND_X11) + 640 - find_library(LIB_fontconfig fontconfig "/opt/X11/lib") + 641 - endif() + 639 else() + 640 set(FLTK_XFT_FOUND FALSE) + 641 endif(FLTK_USE_XFT) + +⏺ Также уберу ссылку на CMAKE_MSVC_RUNTIME_LIBRARY в секции debug: + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Removed 1 line + 697 fl_debug_var(OPENGL_FOUND) + 698 fl_debug_var(OPENGL_INCLUDE_DIR) + 699 fl_debug_var(OPENGL_LIBRARIES) + 700 - fl_debug_var(CMAKE_MSVC_RUNTIME_LIBRARY) + 700 message("--- bundled libraries ---") + 701 fl_debug_var(FLTK_USE_SYSTEM_LIBJPEG) + 702 fl_debug_var(FLTK_USE_SYSTEM_LIBPNG) + +⏺ Теперь проверю, что в файле больше нет ссылок на Wayland и APPLE: + +⏺ Search(pattern: "WAYLAND|__APPLE__|APPLE|_WIN32|MSVC|CYGWIN|MINGW", path: + "~/Desktop/fltk/CMake/options.cmake", output_mode: "content") + ⎿ Found 0 lines + +⏺ options.cmake полностью очищен. Помечу задачу как завершённую и перейду к + следующей. + +⏺ Теперь нужно найти файлы с #ifdef _WIN32, #ifdef __APPLE__, FLTK_USE_WAYLAND в + src/ и FL/. Запущу поиск параллельно. + +⏺ Search(pattern: "_WIN32|WIN32", path: "~/Desktop/fltk/src") + ⎿ Found 5 files (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32", path: "~/Desktop/fltk/FL") + ⎿ Found 6 files (ctrl+o to expand) + +⏺ Search(pattern: "__APPLE__", path: "~/Desktop/fltk/src") + ⎿ Found 1 file (ctrl+o to expand) + +⏺ Search(pattern: "__APPLE__", path: "~/Desktop/fltk/FL") + ⎿ Found 3 files (ctrl+o to expand) + +⏺ Search(pattern: "FLTK_USE_WAYLAND|USE_WAYLAND", path: "~/Desktop/fltk/src") + ⎿ Found 3 files (ctrl+o to expand) + +⏺ Search(pattern: "FLTK_USE_WAYLAND|USE_WAYLAND", path: "~/Desktop/fltk/FL") + ⎿ Found 0 files + +⏺ Файлов не так много. Запущу параллельное чтение нужных файлов, чтобы увидеть + контекст #ifdef веток и удалить мёртвый код. + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: + "~/Desktop/fltk/src/Fl.cxx", output_mode: "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: + "~/Desktop/fltk/src/Fl_Cairo.cxx", output_mode: "content") + ⎿ Found 86 lines (ctrl+o to expand) + +⏺ Нужно прочитать все затронутые файлы. Запущу чтение параллельно. + +⏺ Read(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Read 338 lines + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: + "~/Desktop/fltk/src/flstring.h", output_mode: "content") + ⎿ Found 14 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: + "~/Desktop/fltk/src/forms_fselect.cxx", output_mode: "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: + "~/Desktop/fltk/src/fl_call_main.c", output_mode: "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Теперь прочитаю заголовки FL/ с платформо-специфичным кодом. + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "math.h", output_mode: + "content") + ⎿ Found 13 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "platform_types.h", + output_mode: "content") + ⎿ Found 12 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "fl_utf8.h", + output_mode: "content") + ⎿ Found 18 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "gl.h", output_mode: + "content") + ⎿ Found 31 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "glu.h", output_mode: + "content") + ⎿ Found 22 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "Fl_Window.H", + output_mode: "content") + ⎿ Found 23 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32|WIN32|__APPLE__|WAYLAND", path: "Fl.H", output_mode: + "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Нашёл все файлы с платформо-специфичным кодом. Начну очистку — сначала простые + файлы параллельно. + +⏺ Update(math.h) + ⎿ File must be read first + +⏺ Read(math.h) + ⎿ Read 51 lines + +⏺ Read(platform_types.h) + ⎿ Read 153 lines + +⏺ Read(fl_utf8.h) + ⎿ Read 30 lines + +⏺ Read(gl.h) + ⎿ Read 100 lines + +⏺ Read(glu.h) + ⎿ Read 46 lines + +⏺ Read(Fl_Window.H) + ⎿ Read 50 lines + +⏺ Read(Fl.H) + ⎿ Read 20 lines + +⏺ Read(~/Desktop/fltk/src/flstring.h) + ⎿ Read 102 lines + +⏺ Read(~/Desktop/fltk/src/forms_fselect.cxx) + ⎿ Read 20 lines + +⏺ Read(~/Desktop/fltk/src/fl_call_main.c) + ⎿ Read 159 lines + +⏺ Теперь применю все правки. Начну с простых файлов параллельно. + +⏺ Update(math.h) + ⎿ Removed 8 lines + 14 // https://www.fltk.org/bugs.php + 15 // + 16 + 17 -// Xcode on macOS includes files by recursing down into directo + -ries. + 18 -// This code catches the cycle and directly includes the requir + -ed file. + 19 -#ifdef fl_math_h_cyclic_include + 20 -# include "/usr/include/math.h" + 21 -#endif + 22 - + 17 #ifndef fl_math_h + 18 # define fl_math_h + 19 + 26 -# define fl_math_h_cyclic_include + 20 # include <math.h> + 28 -# undef fl_math_h_cyclic_include + 21 + 22 # ifndef M_PI + 23 # define M_PI 3.14159265358979323846 + +⏺ Update(math.h) + ⎿ Removed 7 lines + 32 # define M_SQRT1_2 0.70710678118654752440 + 33 # endif // !M_SQRT2 + 34 + 35 -# if (defined(_WIN32) || defined(CRAY)) && !defined(__MINGW32_ + -_) + 36 - + 37 -inline double rint(double v) {return floor(v+.5);} + 38 -inline double copysign(double a, double b) {return b<0 ? -a : a + -;} + 39 - + 40 -# endif // (_WIN32 || CRAY) && !__MINGW32__ + 41 - + 35 #endif // !fl_math_h + +⏺ Update(fl_utf8.h) + ⎿ Removed 8 lines + 116 FL_EXPORT unsigned fl_utf8from_mb(char *dst, unsigned dstlen, + const char *src, unsigned srclen); + 117 + 118 /************************************************************* + ****************/ + 119 -#ifdef _WIN32 + 120 -/* these two Windows-only functions are kept for API compatibi + -lity */ + 121 -/* OD: Attempt to convert the UTF-8 string to the current loca + -le */ + 122 -FL_EXPORT char *fl_utf8_to_locale(const char *s, int len, unsi + -gned int codepage); + 119 + 124 -/* OD: Attempt to convert a string in the current locale to UT + -F-8 */ + 125 -FL_EXPORT char *fl_locale_to_utf8(const char *s, int len, unsi + -gned int codepage); + 126 -#endif /* _WIN32 */ + 127 - + 120 /************************************************************* + **************** + 121 * The following functions are intended to provide portable, U + TF-8 aware + 122 * versions of standard functions + +⏺ Update(gl.h) + ⎿ Added 2 lines, removed 18 lines + 43 # define FL_gl_H + 44 + 45 # include "Enumerations.H" // for color names + 46 -# ifdef _WIN32 + 47 -# include <windows.h> + 48 -# endif + 46 # ifndef APIENTRY + 50 -# if defined(__CYGWIN__) + 51 -# define APIENTRY __attribute__ ((__stdcall__)) + 52 -# else + 53 -# define APIENTRY + 54 -# endif + 47 +# define APIENTRY + 48 # endif + 49 + 57 -# ifdef __APPLE__ // PORTME: OpenGL path abstraction + 58 -# ifndef GL_SILENCE_DEPRECATION + 59 -# define GL_SILENCE_DEPRECATION 1 + 60 -# endif + 61 -# if !defined(__gl3_h_) // make sure OpenGL/gl3.h was not in + -cluded before + 62 -# include <OpenGL/gl.h> + 63 -# endif + 64 -# else + 65 -# include <GL/gl.h> + 66 -# endif // __APPLE__ // PORTME: OpenGL Path abstraction + 50 +# include <GL/gl.h> + 51 + 52 FL_EXPORT void gl_start(); + 53 FL_EXPORT void gl_finish(); + +⏺ Update(glu.h) + ⎿ Added 2 lines, removed 13 lines + 25 # define FL_glu_H + 26 + 27 # include "Enumerations.H" // for color names + 28 -# ifdef _WIN32 + 29 -# include <windows.h> + 30 -# endif + 28 # ifndef APIENTRY + 32 -# if defined(__CYGWIN__) + 33 -# define APIENTRY __attribute__ ((__stdcall__)) + 34 -# else + 35 -# define APIENTRY + 36 -# endif + 29 +# define APIENTRY + 30 # endif + 31 + 39 -# ifdef __APPLE__ // PORTME: OpenGL Path abstraction + 40 -# include <OpenGL/glu.h> + 41 -# else + 42 -# include <GL/glu.h> + 43 -# endif + 32 +# include <GL/glu.h> + 33 + 34 #endif // !FL_glu_H + +⏺ Update(Fl.H) + ⎿ Removed 5 lines + 77 FL_EXPORT extern Fl_Screen_Driver *screen_driver(); + 78 FL_EXPORT extern Fl_System_Driver *system_driver(); + 79 + 80 -#ifdef __APPLE__ // deprecated in 1.4 - only for compatibility + -with 1.3 + 81 -FL_EXPORT extern void reset_marked_text(); + 82 -FL_EXPORT extern void insertion_point_location(int x, int y, in + -t height); + 83 -#endif + 84 - + 80 FL_EXPORT extern int box_shadow_width(); + 81 FL_EXPORT extern void box_shadow_width(int W); + 82 + +⏺ Update(~/Desktop/fltk/src/flstring.h) + ⎿ Removed 5 lines + 53 * Some of these functions are also defined in ISO C99... + 54 */ + 55 + 56 -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MIN + -GW32__) + 57 -# define strcasecmp(s,t) _stricmp((s), (t)) + 58 -# define strncasecmp(s,t,n) _strnicmp((s), (t), (n)) + 59 -# endif /* _WIN32 && ... */ + 60 - + 56 # ifdef __cplusplus + 57 extern "C" { + 58 # endif /* __cplusplus */ + +⏺ Update(~/Desktop/fltk/src/forms_fselect.cxx) + ⎿ Added 2 lines, removed 5 lines + 29 if (pat && pat[0]) fl_pattern = pat; + 30 if (fname && fname[0]) strlcpy(fl_filename,fname,sizeof(fl_fi + lename)); + 31 char *p = fl_directory+strlen(fl_directory); + 32 - if (p > fl_directory && *(p-1)!='/' + 33 -#ifdef _WIN32 + 34 - && *(p-1)!='\\' && *(p-1)!=':' + 35 -#endif + 36 - ) *p++ = '/'; + 32 + if (p > fl_directory && *(p-1)!='/') + 33 + *p++ = '/'; + 34 strlcpy(p,fl_filename,sizeof(fl_directory) - (p - fl_director + y)); + 35 const char *q = fl_file_chooser(message,fl_pattern,fl_directo + ry); + 36 if (!q) return 0; + ⎿ Found 20 new diagnostic issues in 5 files (ctrl+o to expand) + +⏺ Теперь обработаю FL/platform_types.h — уберу Windows-специфичный код. + +⏺ Update(platform_types.h) + ⎿ Removed 15 lines + 95 different signedness of socket numbers on *some* platforms + . + 96 */ + 97 + 98 -#ifdef _WIN64 + 99 - + 100 -#if defined(_MSC_VER) && (_MSC_VER < 1600) + 101 -# include <stddef.h> /* stdint.h not available before VS 2010 + - (1600) */ + 102 -#else + 103 -# include <stdint.h> + 104 -#endif + 105 - + 106 -typedef intptr_t fl_intptr_t; + 107 -typedef uintptr_t fl_uintptr_t; + 108 - + 109 -#else /* ! _WIN64 */ + 110 - + 98 typedef long fl_intptr_t; + 99 typedef unsigned long fl_uintptr_t; + 100 + 114 -#endif /* _WIN64 */ + 115 - + 101 typedef void *GLContext; + 102 typedef void *Fl_Region; + 103 typedef fl_uintptr_t Fl_Offscreen; + +⏺ Update(platform_types.h) + ⎿ Added 1 line, removed 10 lines + 102 typedef void *Fl_Region; + 103 typedef fl_uintptr_t Fl_Offscreen; + 104 + 105 -/* Allows all hybrid combinations except WIN32 + X11 with MSVC + - */ + 106 -#if defined(_WIN32) && !defined(__MINGW32__) + 107 - struct dirent {char d_name[1];}; + 108 -#else + 109 -# include <dirent.h> + 110 -#endif + 105 +#include <dirent.h> + 106 + 112 -# if defined(_WIN64) && defined(_MSC_VER) + 113 -typedef unsigned __int64 FL_SOCKET; /* *FIXME* - FL_SOCKET + - (see above) */ + 114 -# else + 107 typedef int FL_SOCKET; + 116 -# endif + 108 + 109 #include <FL/Fl_Export.H> + 110 extern FL_EXPORT int fl_command_modifier(); + ⎿ Found 4 new diagnostic issues in 2 files (ctrl+o to expand) + +⏺ Теперь удалю HICON-блок из Fl_Window.H и удалю fl_call_main.c. + +⏺ Update(Fl_Window.H) + ⎿ Removed 37 lines + 385 void icon(const Fl_RGB_Image*); + 386 void icons(const Fl_RGB_Image*[], int); + 387 + 388 -#if defined(_WIN32) || defined(FL_DOXYGEN) + 389 - typedef struct HICON__* HICON; + 390 - // These 2 member functions break the driver model but are k + -ept for back compatibility. + 391 - // They are implemented in Fl_win32.cxx + 392 - + 393 - /** Sets the default window icons (Windows platform only). + 394 - + 395 - Convenience function to set the default icons using Windows + -' + 396 - native HICON icon handles. + 397 - + 398 - The given icons are copied. You can free the icons immediat + -ely after + 399 - this call. + 400 - + 401 - \param[in] big_icon default large icon for all windows + 402 - subsequently created + 403 - \param[in] small_icon default small icon for all windows + 404 - subsequently created + 405 - + 406 - \see Fl_Window::default_icon(const Fl_RGB_Image *) + 407 - \see Fl_Window::default_icons(const Fl_RGB_Image *[], int) + 408 - \see Fl_Window::icon(const Fl_RGB_Image *) + 409 - \see Fl_Window::icons(const Fl_RGB_Image *[], int) + 410 - \see Fl_Window::icons(HICON, HICON) + 411 - */ + 412 - static void default_icons(HICON big_icon, HICON small_icon); + 413 - + 414 - /** Sets the window icons using HICON handles (Windows platf + -orm only). + 415 - + 416 - The given icons are copied. You can free the icons immediat + -ely after + 417 - this call. + 418 - + 419 - \param[in] big_icon large window icon + 420 - \param[in] small_icon small window icon + 421 - */ + 422 - void icons(HICON big_icon, HICON small_icon); + 423 -#endif // defined(_WIN32) || defined(FL_DOXYGEN) + 424 - + 388 /* for legacy compatibility */ + 389 const void* icon() const; + 390 void icon(const void * ic); + +⏺ Bash(rm /Users/mnik01/Desktop/fltk/src/fl_call_main.c) + ⎿ /Users/mnik01/.zprofile:source:3: no such file or directory: /Users/mni + k01/Desktop/hobby/emsdk/emsdk_env.sh + + ⎿ Found 4 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Теперь самое сложное — src/Fl_Cairo.cxx. Упрощу его до X11-only. + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 1 line, removed 29 lines + 27 + 28 #ifdef FLTK_HAVE_CAIRO + 29 + 30 -// Define USE_MAC_OS for convenience (below). We use macOS spec + -ific features + 31 -// if USE_MAC_OS is defined, otherwise we're using X11 (XQuartz + -) on macOS + 32 - + 33 -#if defined __APPLE__ && !defined(FLTK_USE_X11) + 34 -#define USE_MAC_OS + 35 -#include <ApplicationServices/ApplicationServices.h> + 36 -#endif + 37 - + 30 #include <FL/platform.H> + 31 #include <FL/Fl_Window.H> + 32 +#include <cairo-xlib.h> + 33 + 41 -// Cairo is currently supported for the following platforms: + 42 -// Windows, macOS (Apple Quartz), X11, Wayland + 43 - + 44 -#if defined(_WIN32) // Windows + 45 -# include <cairo-win32.h> + 46 -#elif defined(FLTK_USE_WAYLAND) // Wayland or hybrid + 47 -# include "../src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H + -" + 48 -# include "../src/drivers/Wayland/Fl_Wayland_Window_Driver.H" + 49 -# if defined(FLTK_USE_X11) + 50 -# include <cairo-xlib.h> + 51 -# else + 52 - static void *fl_gc = NULL; + 53 -# endif + 54 -#elif defined(FLTK_USE_X11) // X11 + 55 -# include <cairo-xlib.h> + 56 -#elif defined(__APPLE__) // macOS + 57 -# include <cairo-quartz.h> + 58 -#else + 59 -# error Cairo is not supported on this platform. + 60 -#endif + 61 - + 34 // static initialization + 35 + 36 Fl_Cairo_State Fl::Private::cairo_state_; ///< current Cairo co + ntext information + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Removed 11 lines + 119 return NULL; + 120 cairo_t *cairo_ctxt; + 121 + 122 -#if defined(FLTK_USE_WAYLAND) + 123 - if (fl_wl_display()) { // true means using wayland backend + 124 - struct wld_window *xid = fl_wl_xid(wi); + 125 - if (!xid || !xid->buffer) + 126 - return NULL; // this may happen with GL windows or if wi + -ndow is not shown + 127 - cairo_ctxt = xid->buffer->draw_buffer.cairo_; + 128 - Fl::Private::cairo_state_.cc(cairo_ctxt, false); + 129 - return cairo_ctxt; + 130 - } + 131 -#endif + 132 - + 122 if (fl_gc == 0) { // means remove current cc + 123 Fl::cairo_cc(0); // destroy any previous cc + 124 Fl::Private::cairo_state_.window(0); + ⎿ Found 3 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 2 lines, removed 15 lines + 129 if (fl_gc == Fl::Private::cairo_state_.gc() && fl_xid(wi) == + (Window)Fl::Private::cairo_state_.window()) + 130 return Fl::cairo_cc(); + 131 + 132 - // Scale the Cairo context appropriately. This is platform d + -ependent + 133 - + 134 -#if !defined(USE_MAC_OS) + 135 - float scale = Fl::screen_scale(wi->screen_num()); // get the + - screen scaling factor + 136 -#endif + 137 - + 138 -#if defined(FLTK_USE_X11) + 132 + // Scale the Cairo context appropriately + 133 + float scale = Fl::screen_scale(wi->screen_num()); + 134 cairo_ctxt = Fl::Private::cairo_make_current(0, wi->w() * sc + ale, wi->h() * scale); + 140 -#else + 141 - // on macOS, scaling is done before by Fl_Window::make_curre + -nt(), on Windows, the size is not used + 142 - cairo_ctxt = Fl::Private::cairo_make_current(fl_gc, wi->w(), + - wi->h()); + 143 -#endif + 144 - + 135 Fl::Private::cairo_state_.window((void *)fl_xid(wi)); + 146 - + 147 -#if !defined(USE_MAC_OS) + 136 cairo_scale(cairo_ctxt, scale, scale); + 149 -#endif + 137 return cairo_ctxt; + 138 } + 139 + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Removed 10 lines + 144 */ + 145 + 146 static cairo_surface_t *cairo_create_surface(void *gc, int W, + int H) { + 147 -#if defined(FLTK_USE_X11) + 147 return cairo_xlib_surface_create(fl_display, fl_window, fl_v + isual->visual, W, H); + 149 -#elif defined(FLTK_USE_WAYLAND) + 150 - return NULL; + 151 -#elif defined(_WIN32) + 152 - return cairo_win32_surface_create((HDC)gc); + 153 -#elif defined(__APPLE__) + 154 - return cairo_quartz_surface_create_for_cg_context((CGContext + -Ref)gc, W, H); + 155 -#else + 156 -#error Cairo is not supported on this platform. + 157 -#endif + 148 } + 149 + 150 + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Теперь очищу блок #if 0 (мёртвый код — неиспользуемая функция) и блок с + USE_MAC_OS: + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Removed 45 lines + 148 } + 149 + 150 + 151 -#if 0 // this non-public function appears not to be used anywh + -ere in FLTK + 151 /** + 153 - Creates a Cairo context from a \a gc only, gets its window s + -ize or + 154 - offscreen size if fl_window is null. + 155 - + 156 - \note Only available if CMake FLTK_OPTION_CAIRO_WINDOW is en + -abled. + 157 -*/ + 158 -cairo_t *Fl::Private::cairo_make_current(void *gc) { + 159 - int W = 0, H = 0; + 160 -#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) + 161 - // FIXME X11 get W,H + 162 - // gc will be the window handle here + 163 - // # warning FIXME get W,H for cairo_make_current(void*) + 164 -#elif defined(__APPLE__) + 165 - if (fl_window) { + 166 - W = Fl_Window::current()->w(); + 167 - H = Fl_Window::current()->h(); + 168 - } else { + 169 - W = CGBitmapContextGetWidth(fl_gc); + 170 - H = CGBitmapContextGetHeight(fl_gc); + 171 - } + 172 -#elif defined(_WIN32) + 173 - // we don't need any W,H for Windows + 174 -#else + 175 -#error Cairo is not supported on this platform. + 176 -#endif + 177 - + 178 - if (!gc) { + 179 - Fl::cairo_cc(0); + 180 - cairo_state_.gc(0); // keep track for next time + 181 - return 0; + 182 - } + 183 - if (gc == Fl::Private::cairo_state_.gc() && + 184 - fl_window == (Window)Fl::Private::cairo_state_.window() + -&& + 185 - cairo_state_.cc() != 0) + 186 - return Fl::cairo_cc(); + 187 - cairo_state_.gc(fl_gc); // keep track for next time + 188 - cairo_surface_t *s = cairo_create_surface(gc, W, H); + 189 - cairo_t *c = cairo_create(s); + 190 - cairo_surface_destroy(s); + 191 - cairo_state_.cc(c); + 192 - return c; + 193 -} + 194 -#endif + 195 - + 196 -/** + 152 Creates a Cairo context from a \p gc and the given size. + 153 + 154 \note Only available if CMake FLTK_OPTION_CAIRO_WINDOW is en + abled. + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Теперь уберу оставшийся USE_MAC_OS блок в cairo_make_current(void*, int, int): + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Removed 12 lines + 162 // we need to (re-)create a fresh cc ... + 163 cairo_state_.gc(gc); // keep track for next time + 164 cairo_surface_t *s = cairo_create_surface(gc, W, H); + 165 - + 166 -#if defined(USE_MAC_OS) && defined(FLTK_HAVE_CAIROEXT) + 167 - CGAffineTransform at = CGContextGetCTM((CGContextRef)gc); + 168 - CGContextSaveGState((CGContextRef)gc); + 169 - CGContextConcatCTM((CGContextRef)gc, CGAffineTransformInvert + -(at)); + 170 -#endif + 171 - + 165 cairo_t *c = cairo_create(s); + 173 - + 174 -#if defined(USE_MAC_OS) && defined(FLTK_HAVE_CAIROEXT) + 175 - CGContextRestoreGState((CGContextRef)gc); + 176 -#endif + 177 - + 166 cairo_state_.cc(c); // and purge any previously owned conte + xt + 167 cairo_surface_destroy(s); + 168 return c; + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Теперь обработаю два оставшихся файла с WAYLAND-ссылками. + +⏺ Search(pattern: "WAYLAND|_WIN32|__APPLE__", path: + "~/Desktop/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx", + output_mode: "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "WAYLAND|_WIN32|__APPLE__", path: + "~/Desktop/fltk/src/drivers/PostScript/Fl_PostScript.cxx", output_mode: + "content") + ⎿ Found 23 lines (ctrl+o to expand) + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Read(~/Desktop/fltk/src/drivers/PostScript/Fl_PostScript.cxx) + ⎿ Read 30 lines + +⏺ Update(~/Desktop/fltk/src/drivers/PostScript/Fl_PostScript.cxx) + ⎿ Added 1 line, removed 1 line + 1470 fprintf(output, "GR GR\n"); + 1471 } + 1472 + 1473 -#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) + 1473 +#if defined(FLTK_USE_X11) + 1474 + 1475 Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surfac + e_(const char ***pfname) { + 1476 *pfname = NULL; + +⏺ Update(~/Desktop/fltk/src/drivers/PostScript/Fl_PostScript.cxx) + ⎿ Added 1 line, removed 1 line + 1492 return begin_job(NULL, perr_message); + 1493 } + 1494 + 1495 -#endif // defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) + 1495 +#endif // defined(FLTK_USE_X11) + 1496 + 1497 # else // USE_PANGO + 1498 + ⎿ Found 10 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Все диагностики — LSP-ошибки из-за отсутствия сгенерированных файлов + (config.h, fl_config.h). Это нормально. + + Также почищу документацию в Fl_Cairo.cxx (убрал ссылки на другие платформы в + комментариях). Проверю, остались ли ещё ссылки на Wayland в комментарии: + +⏺ Search(pattern: "Wayland|Windows|macOS|WIN32|__APPLE__|USE_MAC_OS", path: + "~/Desktop/fltk/src/Fl_Cairo.cxx", output_mode: "content") + ⎿ Found 5 lines (ctrl+o to expand) + ⎿ Found 10 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Осталось только в комментариях. Почищу комментарии. + +⏺ Read(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Read 15 lines + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 1 line, removed 1 line + 112 \note Only available when CMake option '-D FLTK_OPTION_CAIRO + _WINDOW' is set. + 113 + 114 \return The valid cairo_t *cairo context associated to this + window. + 115 - \retval NULL if \a wi is NULL or maybe with GL windows under + - Wayland + 115 + \retval NULL if \a wi is NULL + 116 */ + 117 cairo_t *Fl::cairo_make_current(Fl_Window *wi) { + 118 if (!wi) + +⏺ Read(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Read 10 lines + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 1 line, removed 3 lines + 138 } + 139 + 140 /* + 141 - Creates transparently a cairo_surface_t object. + 142 - gc is an HDC context in Windows, a CGContext* in Quartz, and + 143 - a display on X11 (not used on this platform) + 141 + Creates a cairo_surface_t object using X11/Xlib. + 142 */ + 143 + 144 static cairo_surface_t *cairo_create_surface(void *gc, int W, + int H) { + +⏺ Read(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Read 50 lines + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 1 line, removed 4 lines + 167 } + 168 + 169 /** Flush Cairo drawings on Cairo context \p c. + 170 - This is \b required on Windows if you use the Cairo context + -provided + 171 - by the "Cairo autolink" option. Call this when all your draw + -ings on + 172 - the Cairo context are finished. This is maybe not necessary + -on other + 173 - platforms than Windows but it does no harm if you call it al + -ways. + 170 + Call this when all your drawings on the Cairo context are fi + +nished. + 171 + 172 You don't need to use this if you use an Fl_Cairo_Window whi + ch does + 173 this automatically after the draw callback returns. + +⏺ Update(~/Desktop/fltk/src/Fl_Cairo.cxx) + ⎿ Added 1 line, removed 1 line + 197 \see Fl::cairo_make_current(Fl_Window*); + 198 */ + 199 FL_EXPORT extern void Fl::cairo_flush(cairo_t *c) { + 200 - // flush Cairo drawings: necessary at least for Windows + 200 + // flush Cairo drawings + 201 cairo_surface_t *s = cairo_get_target(c); + 202 cairo_surface_flush(s); + 203 } + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Теперь также очищу Doxygen-документацию в FL/platform_types.h от упоминаний + других платформ: + +⏺ Update(platform_types.h) + ⎿ Added 1 line, removed 5 lines + 37 + 38 /** + 39 Platform-specific value representing an offscreen drawing buff + er. + 40 - \note This value can be safely cast to these types on each pl + -atform: + 41 - \li X11: Pixmap + 42 - \li Wayland: cairo_t * + 43 - \li Windows: HBITMAP + 44 - \li macOS: CGContextRef + 40 + \note This value can be safely cast to Pixmap on X11. + 41 */ + 42 typedef opaque Fl_Offscreen; + 43 + +⏺ Update(platform_types.h) + ⎿ Added 1 line, removed 5 lines + 43 + 44 /** + 45 Pointer to a platform-specific structure representing a collec + tion of rectangles. + 46 - \note This pointer can be safely cast to these types on each + -platform: + 47 - \li X11: Region as defined by X11 + 48 - \li Wayland: cairo_region_t * + 49 - \li Windows: HRGN + 50 - \li macOS: struct flCocoaRegion * + 46 + \note This pointer can be safely cast to Region as defined by + + X11. + 47 */ + 48 typedef struct opaque *Fl_Region; + 49 typedef opaque FL_SOCKET; /**< socket or file descriptor */ + +⏺ Update(platform_types.h) + ⎿ Added 1 line, removed 5 lines + 49 typedef opaque FL_SOCKET; /**< socket or file descriptor */ + 50 /** + 51 Pointer to a platform-specific structure representing the wind + ow's OpenGL rendering context. + 52 - \note This pointer can be safely cast to these types on each + -platform: + 53 - \li X11: GLXContext + 54 - \li Wayland: EGLContext + 55 - \li Windows: HGLRC + 56 - \li macOS: NSOpenGLContext * + 52 + \note This pointer can be safely cast to GLXContext on X11. + 53 */ + 54 typedef struct opaque *GLContext; + 55 + ⎿ Found 2 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Также уберу FL_COMMAND/FL_CONTROL документацию о MacOS: + +⏺ Update(platform_types.h) + ⎿ Added 2 lines, removed 2 lines + 60 */ + 61 typedef opaque Fl_Timestamp; + 62 + 63 -# define FL_COMMAND opaque /**< An alias for FL_CTRL on Win + -dows and X11, or FL_META on MacOS X */ + 64 -# define FL_CONTROL opaque /**< An alias for FL_META on Win + -dows and X11, or FL_CTRL on MacOS X */ + 63 +# define FL_COMMAND opaque /**< An alias for FL_CTRL on X11 + + */ + 64 +# define FL_CONTROL opaque /**< An alias for FL_META on X11 + + */ + 65 + 66 #else /* FL_DOXYGEN */ + 67 + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Основные файлы обработаны. Теперь помечу задачу как завершённую и запущу + верификационный grep. + +⏺ Запускаю верификацию — поиск оставшихся _WIN32, __APPLE__, FLTK_USE_WAYLAND в + src/ и FL/. + +⏺ Search(pattern: "#\s*if.*_WIN32|#\s*ifdef\s+_WIN32|#\s*if.*WIN32", path: + "~/Desktop/fltk/src", output_mode: "content") + ⎿ Found 1 line (ctrl+o to expand) + +⏺ Search(pattern: "#\s*if.*_WIN32|#\s*ifdef\s+_WIN32|#\s*if.*WIN32", path: + "~/Desktop/fltk/FL", output_mode: "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "#\s*if.*__APPLE__", path: "~/Desktop/fltk/src", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "#\s*if.*__APPLE__", path: "~/Desktop/fltk/FL", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "FLTK_USE_WAYLAND", path: "~/Desktop/fltk/src", output_mode: + "content") + ⎿ Found 1 line (ctrl+o to expand) + +⏺ Search(pattern: "FLTK_USE_WAYLAND", path: "~/Desktop/fltk/FL", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Осталось 2 вхождения. Исправлю оба. + +⏺ Search(pattern: "FLTK_USE_WAYLAND", path: + "~/Desktop/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx", + output_mode: "content") + ⎿ Found 21 lines (ctrl+o to expand) + +⏺ Search(pattern: "_WIN32", path: "~/Desktop/fltk/src/Fl.cxx", output_mode: + "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Read(~/Desktop/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx) + ⎿ Read 10 lines + +⏺ Read(~/Desktop/fltk/src/Fl.cxx) + ⎿ Read 30 lines + +⏺ Update(~/Desktop/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx) + ⎿ Removed 2 lines + 40 } + 41 }; + 42 + 43 -#ifndef FLTK_USE_WAYLAND + 43 Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_ + Gl_Window *w) + 44 { + 45 return new Fl_X11_Gl_Window_Driver(w); + 46 } + 48 -#endif + 47 + 48 void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* st + r, int n) { + 49 draw_string_legacy_get_list(str, n); + +⏺ Теперь обновлю комментарий в Fl.cxx — функция args_to_utf8 на X11 ничего не + делает (это noop для не-Windows). Упрощу комментарий. + +⏺ Read(~/Desktop/fltk/src/Fl.cxx) + ⎿ Read 50 lines + ⎿ Found 1 new diagnostic issue in 1 file (ctrl+o to expand) + +⏺ Read(~/Desktop/fltk/src/Fl.cxx) + ⎿ Read 24 lines + +⏺ Update(~/Desktop/fltk/src/Fl.cxx) + ⎿ Added 5 lines, removed 62 lines + 2572 FL_EXPORT const char* fl_local_ctrl = Fl::system_driver()->c + ontrol_name(); + 2573 + 2574 /** + 2575 - Convert Windows commandline arguments to UTF-8. + 2575 + Ensure commandline arguments are UTF-8 encoded. + 2576 + 2577 - \note This function does nothing on other (non-Windows) pla + -tforms, hence + 2578 - you may call it on all platforms or only on Windows by us + -ing platform + 2579 - specific code like <tt>'\#ifdef _WIN32'</tt> etc. - it's + -your choice. + 2580 - Calling it on other platforms returns quickly w/o wasting + - much CPU time. + 2577 + On X11 this is a no-op since arguments are already in the l + +ocale encoding + 2578 + which is typically UTF-8 on modern systems. + 2579 + 2582 - This function <i>must be called <b>on Windows platforms</b> + -</i> in \c main() + 2583 - before the array \c argv is used if your program uses any c + -ommandline + 2584 - argument strings (these should be UTF-8 encoded). + 2585 - This applies also to standard FLTK commandline arguments li + -ke + 2586 - "-name" (class name) and "-title" (window title in the titl + -e bar). + 2587 - + 2588 - Unfortunately Windows \b neither provides commandline argum + -ents in UTF-8 + 2589 - encoding \b nor as Windows "Wide Character" strings in the + -standard + 2590 - \c main() and/or the Windows specific \c WinMain() function + -. + 2591 - + 2592 - On Windows platforms (no matter which build system) this fu + -nction calls + 2593 - a Windows specific function to retrieve commandline argumen + -ts as Windows + 2594 - "Wide Character" strings, converts these strings to an inte + -rnally allocated + 2595 - buffer (or multiple buffers) and returns the result in \c a + -rgv. + 2596 - For implementation details please refer to the source code; + - however these + 2597 - details may be changed in the future. + 2598 - + 2599 - Note that \c argv is provided by reference so it can be ove + -rwritten. + 2600 - + 2601 - In the recommended simple form the function overwrites the + -variable + 2602 - \c argv and allocates a new array of strings pointed to by + -\c argv. + 2603 - You may use this form on all platforms and it is as simple + -as adding + 2604 - one line to old programs to make them work with internation + -al (UTF-8) + 2605 - commandline arguments. + 2606 - + 2607 - \code + 2608 - int main(int argc, char **argv) { + 2609 - Fl::args_to_utf8(argc, argv); // add this line + 2610 - // ... use argc and argv, e.g. for commandline parsing + 2611 - window->show(argc, argv); + 2612 - return Fl::run(); + 2613 - } + 2614 - \endcode + 2615 - + 2616 - For an example see 'examples/howto-parse-args.cxx' in the F + -LTK sources. + 2617 - + 2618 - If you want to retain the original \c argc and \c argv vari + -ables the + 2619 - following slightly longer and more complicated code works a + -s well on + 2620 - all platforms. + 2621 - + 2622 - \code + 2623 - int main(int argc, char **argv) { + 2624 - char **argvn = argv; // must copy argv to wo + -rk on all platforms + 2625 - int argcn = Fl::args_to_utf8(argc, argvn); + 2626 - // ... use argcn and argvn, e.g. for commandline parsin + -g + 2627 - window->show(argcn, argvn); + 2628 - return Fl::run(); + 2629 - } + 2630 - \endcode + 2631 - + 2632 - \param[in] argc used only on non-Windows platforms + 2633 - \param[out] argv modified only on Windows platforms + 2580 + \param[in] argc argument count + 2581 + \param[out] argv argument array + 2582 \returns argument count (always the same as argc) + 2583 + 2584 \since 1.4.0 + 2637 - + 2638 - \internal This function must not open the display, otherwis + -e + 2639 - commandline processing (e.g. by fluid) would open the dis + -play. + 2640 - OTOH calling it when the display is opened wouldn't work + -either + 2641 - for the same reasons ('fluid -c' doesn't open the display + -). + 2585 */ + 2586 int Fl::args_to_utf8(int argc, char ** &argv) { + 2587 return Fl::system_driver()->args_to_utf8(argc, argv); + +⏺ Теперь повторю верификационный grep: + +⏺ Search(pattern: "#\s*if.*(_WIN32|WIN32\b)|#\s*ifdef\s+(_WIN32|WIN32\b)", path: + "~/Desktop/fltk/src", output_mode: "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "#\s*if.*(_WIN32|WIN32\b)|#\s*ifdef\s+(_WIN32|WIN32\b)", path: + "~/Desktop/fltk/FL", output_mode: "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "#\s*if.*__APPLE__", path: "~/Desktop/fltk/src", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "#\s*if.*__APPLE__", path: "~/Desktop/fltk/FL", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "FLTK_USE_WAYLAND", path: "~/Desktop/fltk/src", output_mode: + "content") + ⎿ Found 0 lines + +⏺ Search(pattern: "FLTK_USE_WAYLAND", path: "~/Desktop/fltk/FL", output_mode: + "content") + ⎿ Found 0 lines + ⎿ Found 10 new diagnostic issues in 1 file (ctrl+o to expand) + +⏺ Все 0 результатов — _WIN32, __APPLE__ и FLTK_USE_WAYLAND полностью удалены из + src/ и FL/. Также проверю CMake/ и другие ключевые директории: + +⏺ Search(pattern: "#\s*if.*(_WIN32|__APPLE__|FLTK_USE_WAYLAND)", path: + "~/Desktop/fltk/CMake", output_mode: "content") + ⎿ Found 2 lines (ctrl+o to expand) + +⏺ Search(pattern: "APPLE|WIN32|MSVC|WAYLAND", path: "~/Desktop/fltk/CMake") + ⎿ Found 10 files (ctrl+o to expand) + +⏺ Есть остатки в CMake файлах. Запущу агент для их глубокой проверки. + +⏺ Explore(Find platform refs in CMake) + ⎿ Done (16 tool uses · 22.4k tokens · 55s) + +⏺ Осталось много платформо-специфичного кода в CMake файлах. Почищу их. Начну с + чтения файлов параллельно. + +⏺ Read(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Read 345 lines + +⏺ Read(~/Desktop/fltk/CMake/setup.cmake) + ⎿ Read 210 lines + +⏺ Read(~/Desktop/fltk/CMake/variables.cmake) + ⎿ Read 178 lines + +⏺ Буду чистить CMake файлы. Начну с параллельных правок. + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Added 1 line, removed 6 lines + 136 + 137 fl_find_header(HAVE_X11_XREGION_H "X11/Xlib.h;X11/Xregion.h") + 138 + 139 -if(WIN32 AND NOT CYGWIN) + 140 - # we don't use pthreads on Windows (except for Cygwin, see o + -ptions.cmake) + 141 - set(HAVE_PTHREAD_H 0) + 142 -else() + 143 - fl_find_header(HAVE_PTHREAD_H pthread.h) + 144 -endif(WIN32 AND NOT CYGWIN) + 139 +fl_find_header(HAVE_PTHREAD_H pthread.h) + 140 + 141 # Do we have PTHREAD_MUTEX_RECURSIVE ? + 142 + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Removed 25 lines + 149 set(HAVE_PTHREAD_MUTEX_RECURSIVE 0) + 150 endif() + 151 + 152 -# Special case for Microsoft Visual Studio generator (MSVC): + 153 -# + 154 -# The header files <GL/glu.h> and <locale.h> are located in th + -e SDK's + 155 -# for Visual Studio. If CMake is invoked from a desktop icon o + -r the Windows + 156 -# menu it doesn't have the correct paths to find these header + -files. + 157 -# The CMake folks recommend not to search for these files at a + -ll, because + 158 -# they must always be there, but we do anyway. + 159 -# If we don't find them we issue a warning and continue anyway + -. + 160 -# + 161 -# Note: these cache variables can only be seen in "advanced" m + -ode. + 162 - + 163 -if(MSVC) + 164 - + 165 - if(NOT HAVE_GL_GLU_H) + 166 - message(STATUS "Info: Header file GL/glu.h was not found. + -Continuing...") + 167 - set(HAVE_GL_GLU_H 1) + 168 - endif(NOT HAVE_GL_GLU_H) + 169 - + 170 - if(NOT HAVE_LOCALE_H) + 171 - message(STATUS "Info: Header file locale.h was not found. + -Continuing...") + 172 - set(HAVE_LOCALE_H 1) + 173 - endif(NOT HAVE_LOCALE_H) + 174 - + 175 -endif(MSVC) + 176 - + 152 # Simulate the behavior of autoconf macro AC_HEADER_DIRENT, se + e: + 153 # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/h + tml_node/Particular-Headers.html + 154 # "Check for the following header files. For the first one tha + t is found + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Added 2 lines, removed 2 lines + 178 find_path(FREETYPE_PATH freetype.h PATH_SUFFIXES freetype2) + 179 find_path(FREETYPE_PATH freetype/freetype.h PATH_SUFFIXES free + type2) + 180 + 181 -if(FREETYPE_PATH AND ((NOT APPLE) OR FLTK_BACKEND_X11)) + 181 +if(FREETYPE_PATH) + 182 list(APPEND FLTK_BUILD_INCLUDE_DIRECTORIES ${FREETYPE_PATH}) + 183 -endif(FREETYPE_PATH AND ((NOT APPLE) OR FLTK_BACKEND_X11)) + 183 +endif(FREETYPE_PATH) + 184 + 185 mark_as_advanced(FREETYPE_PATH) + 186 + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Added 1 line, removed 3 lines + 187 ############################################################## + ######### + 188 # libraries + 189 find_library(LIB_dl dl) + 190 -if((NOT APPLE) OR FLTK_BACKEND_X11) + 191 - find_library(LIB_fontconfig fontconfig) + 192 -endif((NOT APPLE) OR FLTK_BACKEND_X11) + 190 +find_library(LIB_fontconfig fontconfig) + 191 find_library(LIB_freetype freetype) + 192 find_library(LIB_GL GL) + 193 find_library(LIB_MesaGL MesaGL) + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Removed 5 lines + 237 check_symbol_exists(scandir "dirent.h" HAVE_SCA + NDIR) + 238 check_symbol_exists(snprintf "stdio.h" HAVE_SNP + RINTF) + 239 + 240 -# not really true but we convert strcasecmp calls to _stricmp + -calls in flstring.h + 241 -if(MSVC) + 242 - set(HAVE_STRCASECMP 1) + 243 -endif(MSVC) + 244 - + 240 check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASEC + MP) + 241 + 242 check_symbol_exists(strlcat "string.h" HAVE_STRLCAT) + +⏺ Update(~/Desktop/fltk/CMake/resources.cmake) + ⎿ Added 1 line, removed 2 lines + 245 + 246 check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) + 247 + 248 -# Windows doesn't require '-lm' for trunc(), other platforms d + -o + 249 -if(LIB_m AND NOT WIN32) + 248 +if(LIB_m) + 249 set(CMAKE_REQUIRED_LIBRARIES ${LIB_m}) + 250 endif() + 251 + +⏺ Теперь setup.cmake: + +⏺ Update(~/Desktop/fltk/CMake/setup.cmake) + ⎿ Added 1 line, removed 7 lines + 93 ############################################################## + ######### + 94 + 95 # set where config files go + 96 -if(WIN32 AND NOT CYGWIN) + 97 - set(FLTK_CONFIG_PATH CMake) + 98 -elseif(APPLE AND NOT FLTK_BACKEND_X11) + 99 - set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) + 100 -else() + 101 - set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) + 102 -endif(WIN32 AND NOT CYGWIN) + 96 +set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) + 97 + 98 include(TestBigEndian) + 99 TEST_BIG_ENDIAN(WORDS_BIGENDIAN) + +⏺ Update(~/Desktop/fltk/CMake/setup.cmake) + ⎿ Removed 69 lines + 104 set(CMAKE_XCODE_GENERATE_SCHEME 1) + 105 endif() + 106 + 107 -if(APPLE) + 108 - # Check if the __MAC_OS_X_VERSION_MAX_ALLOWED compile time m + -acro is at least + 109 - # the version encoded in SDK_VERSION and return TRUE or FALS + -E in RESULT. + 110 - # Note 1: try_compile() always creates an *internal* CMake c + -ache variable for + 111 - # the result which we set to 'FLTK_CHECK_OSX_MAX_ALL + -OWED_${SDK_VERSION}'. + 112 - # Note 2: 'FLTK_' to avoid polluting the cache if FLTK is bu + -ilt as a subproject. + 113 - # Note 3: We don't care about the cache, i.e. we run try_com + -pile() unconditionally + 114 - # so users can switch SDK's, particularly if they *u + -pgrade* Xcode. + 115 - + 116 - function(CHECK_OSX_MAX_ALLOWED SDK_VERSION RESULT) + 117 - set(_result FLTK_CHECK_OSX_MAX_ALLOWED_${SDK_VERSION}) + 118 - try_compile(${_result} + 119 - ${CMAKE_CURRENT_BINARY_DIR}/CHECK_OSX_MAX_ALLOWED_${SDK_ + -VERSION} + 120 - SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CMake/macOSMaxAllowe + -d.c + 121 - COMPILE_DEFINITIONS -DSDK_VERSION_CHECK=${SDK_VERSION} + 122 - ) + 123 - set(${RESULT} ${${_result}} PARENT_SCOPE) + 124 - endfunction() + 125 - + 126 - # APPLE macOS setup + 127 - set(HAVE_STRCASECMP 1) + 128 - set(HAVE_DIRENT_H 1) + 129 - set(HAVE_SNPRINTF 1) + 130 - set(HAVE_VSNPRINTF 1) + 131 - set(HAVE_SCANDIR 1) + 132 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated") + 133 - if(FLTK_BACKEND_X11) + 134 - if(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) # a.k + -.a. macOS version ≥ 10.13 + 135 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LIBCPP_HAS_TH + -READ_API_PTHREAD") + 136 - endif(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) + 137 - else() + 138 - set(FLTK_COCOA_FRAMEWORKS "-framework Cocoa") + 139 - if (NOT (CMAKE_OSX_ARCHITECTURES STREQUAL "ppc" OR CMAKE_O + -SX_ARCHITECTURES STREQUAL "i386")) + 140 - CHECK_OSX_MAX_ALLOWED(150000 SDK_15_AVAILABLE) # at leas + -t SDK 15.0.0 ? + 141 - if (SDK_15_AVAILABLE) + 142 - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework Scr + -eenCaptureKit") # 15.0 + 143 - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework Uni + -formTypeIdentifiers") # 11.0 + 144 - else(SDK_15_AVAILABLE) + 145 - CHECK_OSX_MAX_ALLOWED(110000 SDK_11_AVAILABLE) # at le + -ast SDK 11.0.0 ? + 146 - if (SDK_11_AVAILABLE) + 147 - list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework U + -niformTypeIdentifiers") + 148 - endif(SDK_11_AVAILABLE) + 149 - endif(SDK_15_AVAILABLE) + 150 - endif() + 151 - endif(FLTK_BACKEND_X11) + 152 -endif(APPLE) + 153 - + 154 -if(WIN32) + 155 - # we do no longer define WIN32 or _WIN32 (since FLTK 1.4.0) + 156 - # ... but if we did, we'd define _WIN32 (since FLTK 1.4.0) + 157 - # add_definitions (-D_WIN32) + 158 - if(MSVC) + 159 - add_definitions (-DWIN32_LEAN_AND_MEAN) + 160 - add_definitions (-D_CRT_SECURE_NO_WARNINGS) + 161 - if(NOT MSVC_VERSION VERSION_LESS 1900) # Visual Studio 201 + -5 + 162 - add_compile_options (/utf-8) # equivalent to `/s + -ource-charset:utf-8 /execution-charset:utf-8` + 163 - endif() + 164 - set(BORDER_WIDTH 2) + 165 - endif(MSVC) + 166 - + 167 - # Don't use the following code, it breaks building with MSYS + -2/UCRT64 + 168 - # See GitHub PR #1167. Solution is to remove the entire bloc + -k! + 169 - + 170 - ### if(MINGW AND EXISTS /mingw) + 171 - ### list(APPEND CMAKE_PREFIX_PATH /mingw) + 172 - ### endif(MINGW AND EXISTS /mingw) + 173 - + 174 -endif(WIN32) + 175 - + 107 ############################################################## + ######### + 108 # size of ints + 109 include(CheckTypeSize) + +⏺ Теперь variables.cmake: + +⏺ Update(~/Desktop/fltk/CMake/variables.cmake) + ⎿ Added 1 line, removed 17 lines + 39 # FIXME: libraries may need reordering. + 40 # FIXME: check fontconfig conditions (only if Xft is used or .. + .) + 41 + 42 -if(WIN32) + 43 - list(APPEND FLTK_LDLIBS -lole32 -luuid -lcomctl32 -lws2_32 -l + -winspool) + 44 -elseif(APPLE AND NOT FLTK_BACKEND_X11) + 45 - list(APPEND FLTK_LDLIBS ${FLTK_COCOA_FRAMEWORKS}) + 46 -elseif(FLTK_USE_WAYLAND) + 47 - foreach(_lib WLDCURSOR WLDCLIENT XKBCOMMON) + 48 - list(APPEND FLTK_LDLIBS "${${_lib}_LDFLAGS}") + 49 - endforeach() + 50 - if(FLTK_USE_DBUS AND DBUS_FOUND) + 51 - list(APPEND FLTK_LDLIBS "${DBUS_LDFLAGS}") + 52 - endif() + 53 - if(USE_SYSTEM_LIBDECOR) + 54 - list(APPEND FLTK_LDLIBS ${SYSTEM_LIBDECOR_LDFLAGS}) + 55 - endif(USE_SYSTEM_LIBDECOR) + 56 -else() + 57 - list(APPEND FLTK_LDLIBS -lm) + 58 -endif(WIN32) + 42 +list(APPEND FLTK_LDLIBS -lm) + 43 + 44 if(LIB_fontconfig) + 45 list(APPEND FLTK_LDLIBS -lfontconfig) + +⏺ Update(~/Desktop/fltk/CMake/variables.cmake) + ⎿ Removed 4 lines + 64 # should be set here, whereas variables with different values s + hould + 65 # be set in install.cmake or export.cmake, respectively. + 66 + 67 -if(WIN32) + 68 - set(LDFLAGS "${CMAKE_EXE_LINKER_FLAGS} -mwindows") + 69 -endif() + 70 - + 67 set(IMAGELIBS) + 68 set(STATICIMAGELIBS) + 69 + +⏺ Теперь прочитаю и почищу оставшиеся CMake файлы. + +⏺ Read(~/Desktop/fltk/CMake/export.cmake) + ⎿ Read 151 lines + +⏺ Read(~/Desktop/fltk/CMake/fl_add_library.cmake) + ⎿ Read 258 lines + +⏺ Read(~/Desktop/fltk/CMake/fl_create_example.cmake) + ⎿ Read 174 lines + +⏺ Теперь применю правки к export.cmake, fl_add_library.cmake и + fl_create_example.cmake параллельно, а также удалю Windows-only файл. + +⏺ Update(~/Desktop/fltk/CMake/export.cmake) + ⎿ Added 2 lines, removed 7 lines + 24 + 25 if(FLTK_BUILD_FLUID AND NOT CMAKE_CROSSCOMPILING) + 26 # Use the fluid executable we build using its namespaced targ + et name + 27 - if(WIN32) + 28 - set(FLTK_FLUID_EXECUTABLE fltk::fluid-cmd) + 29 - set(FLUID_EXPORT fluid fluid-cmd) # export fluid and f + -luid-cmd + 30 - else() + 31 - set(FLTK_FLUID_EXECUTABLE fltk::fluid) + 32 - set(FLUID_EXPORT fluid) # export fluid + 33 - endif() + 27 + set(FLTK_FLUID_EXECUTABLE fltk::fluid) + 28 + set(FLUID_EXPORT fluid) # export fluid + 29 else() + 30 # We don't build fluid /or/ we are cross-compiling (or both): + 31 # we need to find a fluid executable on the build host. + +⏺ Update(~/Desktop/fltk/CMake/export.cmake) + ⎿ Removed 3 lines + 57 # set fltk-options export names (built or not, Windows) + 58 if(FLTK_BUILD_FLTK_OPTIONS) + 59 set(FLTK_OPTIONS_EXPORT fltk-options) + 60 - if(WIN32) + 61 - list(APPEND FLTK_OPTIONS_EXPORT fltk-options-cmd) + 62 - endif() + 60 else() + 61 set(FLTK_OPTIONS_EXPORT) + 62 endif() + +⏺ Update(~/Desktop/fltk/CMake/export.cmake) + ⎿ Added 2 lines, removed 4 lines + 117 # use fallback before CMake 3.19 + 118 + 119 if(CMAKE_VERSION VERSION_LESS 3.19) + 120 - if(UNIX OR MSYS OR MINGW) + 121 - execute_process(COMMAND chmod 755 fltk-config + 122 - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + 123 - endif() + 120 + execute_process(COMMAND chmod 755 fltk-config + 121 + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + 122 else(CMAKE_VERSION VERSION_LESS 3.19) + 123 file(CHMOD "${CMAKE_CURRENT_BINARY_DIR}/fltk-config" + 124 PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + +⏺ Update(~/Desktop/fltk/CMake/fl_add_library.cmake) + ⎿ Added 1 line, removed 5 lines + 57 + 58 string(REPLACE "fltk_" "" EXPORT_NAME ${TARGET_NAME}) + 59 + 60 - if(MSVC) + 61 - set(OUTPUT_NAME_DEBUG "${LIBNAME}d") + 62 - else() + 63 - set(OUTPUT_NAME_DEBUG "${LIBNAME}") + 64 - endif(MSVC) + 60 + set(OUTPUT_NAME_DEBUG "${LIBNAME}") + 61 + 62 set(OUTPUT_NAME_RELEASE "${LIBNAME}") + 63 + +⏺ Update(~/Desktop/fltk/CMake/fl_add_library.cmake) + ⎿ Added 1 line, removed 7 lines + 151 $<INSTALL_INTERFACE:lib> + 152 ) + 153 + 154 - if(APPLE AND NOT FLTK_BACKEND_X11) + 155 - foreach(item ${FLTK_COCOA_FRAMEWORKS}) + 156 - target_link_libraries(${TARGET_NAME} PUBLIC "${item}") + 157 - endforeach() + 158 - endif() + 159 - + 160 - # we must link fltk with cairo if Cairo or Wayland is enab + -led (or both) + 154 + # we must link fltk with cairo if Cairo is enabled + 155 if(FLTK_HAVE_CAIRO OR FLTK_USE_CAIRO) + 156 target_include_directories(${TARGET_NAME} PUBLIC ${PKG_C + AIRO_INCLUDE_DIRS}) + 157 target_link_directories (${TARGET_NAME} PUBLIC ${PKG_C + AIRO_LIBRARY_DIRS}) + +⏺ Update(~/Desktop/fltk/CMake/fl_add_library.cmake) + ⎿ Removed 9 lines + 183 OUTPUT_NAME_RELEASE ${OUTPUT_NAME_RELEASE} + 184 EXPORT_NAME ${EXPORT_NAME} + 185 ) + 186 - # Visual Studio only: + 187 - if(MSVC) + 188 - set_target_properties(${TARGET_NAME} PROPERTIES + 189 - OUTPUT_NAME ${LIBNAME}_dll + 190 - OUTPUT_NAME_DEBUG ${LIBNAME}_dlld + 191 - OUTPUT_NAME_RELEASE ${LIBNAME}_dll + 192 - ) + 193 - target_compile_definitions(${TARGET_NAME} PUBLIC FL_DLL) + 194 - endif(MSVC) + 186 endif(LIBTYPE STREQUAL "SHARED") + 187 + 188 # Debug library output names (optional) + +⏺ Update(~/Desktop/fltk/CMake/fl_add_library.cmake) + ⎿ Removed 8 lines + 205 message(STATUS "--- /DEBUG_ONAME ---") + 206 endif(DEBUG_ONAME) + 207 + 208 - if(MSVC) + 209 - if(FLTK_OPTION_LARGE_FILE) + 210 - set_target_properties(${TARGET_NAME} PROPERTIES + 211 - LINK_FLAGS /LARGEADDRESSAWARE + 212 - ) + 213 - endif(FLTK_OPTION_LARGE_FILE) + 214 - endif(MSVC) + 215 - + 208 install(TARGETS ${TARGET_NAME} EXPORT FLTK-Targets + 209 RUNTIME DESTINATION ${FLTK_BINDIR} + 210 LIBRARY DESTINATION ${FLTK_LIBDIR} + +⏺ Теперь fl_create_example.cmake: + +⏺ Update(~/Desktop/fltk/CMake/fl_create_example.cmake) + ⎿ Added 1 line, removed 13 lines + 56 set(PLIST) # macOS .plist file(max. one) + 57 set(ICON_PATH) # macOS icon resource path + 58 + 59 - # create macOS bundle? 0 = no, 1 = yes + 59 + # filter input files for different handling (fluid, source) + 60 + 61 - if(APPLE AND NOT FLTK_BACKEND_X11) + 62 - set(MAC_BUNDLE 1) + 63 - else() + 64 - set(MAC_BUNDLE 0) + 65 - endif() + 66 - + 67 - # filter input files for different handling (fluid, icon, pli + -st, source) + 68 - + 61 foreach(src ${SOURCES}) + 62 if("${src}" MATCHES "\\.fl$") + 63 list(APPEND flsrcs ${src}) + 72 - elseif("${src}" MATCHES "\\.icns$") + 73 - set(ICON_NAME "${src}") + 74 - elseif("${src}" MATCHES "\\.plist$") + 75 - set(PLIST "${src}") + 64 else() + 65 list(APPEND srcs ${src}) + 66 endif("${src}" MATCHES "\\.fl$") + +⏺ Update(~/Desktop/fltk/CMake/fl_create_example.cmake) + ⎿ Added 2 lines, removed 12 lines + 78 unset(FLUID_SOURCES) + 79 endif(flsrcs) + 80 + 81 - # set macOS (icon) resource path if applicable + 82 - + 83 - if(MAC_BUNDLE AND ICON_NAME) + 84 - set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/mac-resources/${ + -ICON_NAME}") + 85 - endif(MAC_BUNDLE AND ICON_NAME) + 86 - + 81 ############################################################# + ################# + 88 - # add executable target and set properties (all platforms) + 82 + # add executable target and set properties + 83 ############################################################# + ################# + 84 + 91 - if(MAC_BUNDLE) + 92 - add_executable (${TARGET_NAME} MACOSX_BUNDLE ${srcs} + - ${ICON_PATH}) + 93 - else() + 94 - add_executable (${TARGET_NAME} WIN32 ${srcs}) + 95 - endif(MAC_BUNDLE) + 85 + add_executable (${TARGET_NAME} ${srcs}) + 86 + 87 set_target_properties (${TARGET_NAME} PROPERTIES OUTPUT_NAM + E ${NAME}) + 88 target_link_libraries (${TARGET_NAME} PRIVATE ${LIBRARIES}) + +⏺ Update(~/Desktop/fltk/CMake/fl_create_example.cmake) + ⎿ Removed 4 lines + 87 set_target_properties (${TARGET_NAME} PROPERTIES OUTPUT_NAM + E ${NAME}) + 88 target_link_libraries (${TARGET_NAME} PRIVATE ${LIBRARIES}) + 89 + 90 - # make sure we're "exporting" global symbols like 'fl_disable + -_wayland', + 91 - # see also README.Wayland.txt and CMake policy CMP0065. + 92 - + 90 set_target_properties (${TARGET_NAME} PROPERTIES ENABLE_EXP + ORTS TRUE) + 91 + 95 - + 92 # Search the current binary directory for header files create + d by CMake + 93 # or fluid and the source folder for other headers included b + y test programs + 94 + +⏺ Update(~/Desktop/fltk/CMake/fl_create_example.cmake) + ⎿ Removed 47 lines + 97 ${CMAKE_CURRENT_SOURCE_DIR} + 98 ) + 99 + 100 - if(MAC_BUNDLE) + 101 - if(PLIST) + 102 - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_B + -UNDLE_INFO_PLIST + 103 - "${CMAKE_CURRENT_SOURCE_DIR}/mac-r + -esources/${PLIST}") + 104 - endif() + 105 - + 106 - string(REPLACE "_" "-" FLTK_BUNDLE_ID "org.fltk.${TARGET_N + -AME}") + 107 - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUN + -DLE_BUNDLE_NAME "${TARGET_NAME}") + 108 - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUN + -DLE_GUI_IDENTIFIER "${FLTK_BUNDLE_ID}") + 109 - set_target_properties(${TARGET_NAME} PROPERTIES XCODE_ATTR + -IBUTE_PRODUCT_BUNDLE_IDENTIFIER "${FLTK_BUNDLE_ID}") + 110 - + 111 - if(ICON_NAME) + 112 - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_B + -UNDLE_ICON_FILE ${ICON_NAME}) + 113 - set_target_properties(${TARGET_NAME} PROPERTIES RESOURCE + - ${ICON_PATH}) + 114 - endif() + 115 - endif() + 116 - + 117 - ############################################################ + -################## + 118 - # Copy macOS "bundle wrapper" (shell script) to target direc + -tory. + 119 - # The "custom command" will be executed "POST_BUILD". + 120 - ############################################################ + -################## + 121 - + 122 - if(MAC_BUNDLE) + 123 - set(WRAPPER "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} + -/${TARGET_NAME}") + 124 - + 125 - add_custom_command( + 126 - TARGET ${TARGET_NAME} POST_BUILD + 127 - COMMAND cp ${FLTK_SOURCE_DIR}/CMake/macOS-bundle-wrapper + -.in ${WRAPPER} + 128 - COMMAND chmod u+x,g+x,o+x ${WRAPPER} + 129 - BYPRODUCTS ${WRAPPER} + 130 - # COMMENT "Creating macOS bundle wrapper script ${WRAPPE + -R}" + 131 - VERBATIM + 132 - ) + 133 - unset(WRAPPER) + 134 - endif(MAC_BUNDLE) + 135 - + 136 - ############################################################ + -################## + 137 - # MSVC: Add fltk-shared (DLL) path to Environment 'PATH' for + - debugging + 138 - ############################################################ + -################## + 139 - + 140 - if(MSVC AND TARGET fltk-shared) + 141 - set(DllDir "$<SHELL_PATH:$<TARGET_FILE_DIR:fltk-shared>>") + 142 - set_target_properties(${TARGET_NAME} PROPERTIES + 143 - VS_DEBUGGER_ENVIRONMENT "PATH=${DllDir};$ENV{PATH}" + 144 - ) + 145 - endif() + 146 - + 100 endfunction() + +⏺ Удалю Windows-only файл pen-support.c и проверю FLTKConfig.cmake.in: + +⏺ Bash(rm /Users/mnik01/Desktop/fltk/CMake/pen-support.c) + ⎿ /Users/mnik01/.zprofile:source:3: no such file or directory: /Users/mni + k01/Desktop/hobby/emsdk/emsdk_env.sh + + +⏺ Search(pattern: "APPLE|WIN32|MSVC|WAYLAND|MINGW|CYGWIN", path: + "~/Desktop/fltk/CMake/FLTKConfig.cmake.in", output_mode: "content") + ⎿ Found 7 lines (ctrl+o to expand) + +⏺ Read(~/Desktop/fltk/CMake/FLTKConfig.cmake.in) + ⎿ Read 20 lines + +⏺ Update(~/Desktop/fltk/CMake/FLTKConfig.cmake.in) + ⎿ Added 2 lines, removed 7 lines + 125 endif() # Create aliases ... + 126 + 127 # set FLTK_FLUID_EXECUTABLE: try to use the fltk::target nam + e if it + 128 - # exists and fall back to 'fluid-cmd' or 'fluid' if not. Thi + -s will + 129 - # eventually call the build host's fluid if found in the use + -rs's PATH + 128 + # exists and fall back to 'fluid' if not. + 129 + 131 - if(TARGET fltk::fluid-cmd) # Windows only + 132 - set(FLTK_FLUID_EXECUTABLE fltk::fluid-cmd) + 133 - elseif(TARGET fltk::fluid) + 130 + if(TARGET fltk::fluid) + 131 set(FLTK_FLUID_EXECUTABLE fltk::fluid) + 135 - elseif(WIN32) + 136 - set(FLTK_FLUID_EXECUTABLE fluid-cmd) + 132 else() + 133 set(FLTK_FLUID_EXECUTABLE fluid) + 134 endif() + +⏺ Теперь проверю, не осталось ли ещё ссылок на удалённый check_mac_sdk.c: + +⏺ Search(pattern: "check_mac_sdk|macOSMaxAllowed|CHECK_OSX_MAX_ALLOWED", path: + "~/Desktop/fltk/CMake") + ⎿ Found 0 files + +⏺ Финальная верификация — поиск платформо-специфичных ссылок во всех CMake + файлах: + +⏺ Search(pattern: "\bAPPLE\b|\bWIN32\b|\bMSVC\b|\bWAYLAND\b|\bMINGW\b|\bCYGWIN\b + |\b__APPLE__\b|\b_WIN32\b", path: "~/Desktop/fltk/CMake", output_mode: + "content") + ⎿ Found 6 lines (ctrl+o to expand) + +⏺ Остались только ссылки в комментариях и debug-блоках — это неопасно. Почищу + debug-блоки в options.cmake: + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Added 2 lines, removed 2 lines + 50 set(DEBUG_OPTIONS_CMAKE 0) + 51 if(DEBUG_OPTIONS_CMAKE) + 52 message(STATUS "[** options.cmake **]") + 53 - fl_debug_var(WIN32) + 53 + # fl_debug_var(WIN32) # removed: X11-only + 54 fl_debug_var(FLTK_LDLIBS) + 55 endif(DEBUG_OPTIONS_CMAKE) + 56 + ... + 690 + 691 if(DEBUG_OPTIONS_CMAKE) + 692 message(STATUS "") # empty line + 693 - fl_debug_var(WIN32) + 693 + # fl_debug_var(WIN32) # removed: X11-only + 694 fl_debug_var(LIBS) + 695 fl_debug_var(GLLIBS) + 696 fl_debug_var(FLTK_LDLIBS) + +⏺ Update(~/Desktop/fltk/CMake/options.cmake) + ⎿ Added 1 line, removed 1 line + 470 # always use native threads on Windows (even if libpthread is + available). + 471 + 472 # Note: HAVE_PTHREAD_H has already been determined in resource + s.cmake + 473 -# before this file is included (or set to 0 for WIN32). + 473 +# before this file is included. + 474 + 475 option(FLTK_USE_PTHREADS "use multi-threading with pthreads" O + N) + 476 + +⏺ Также проверю, нет ли ссылок на fl_call_main.c в CMakeLists файлах (мы его + удалили): + +⏺ Search(pattern: "fl_call_main", path: "~/Desktop/fltk", glob: "*.cmake") + ⎿ Found 0 files + +⏺ Search(pattern: "fl_call_main", path: "~/Desktop/fltk", glob: + "CMakeLists.txt") + ⎿ Found 0 files + +⏺ Отлично. Также нужно проверить fluid/ и test/ на платформо-специфичные #ifdef + ветки — но эти директории не входили в текущую задачу Фазы 1. Проверю только + остатки в ключевых директориях: + +⏺ Search(pattern: "\bAPPLE\b|\bWIN32\b|\bMSVC\b|\bWAYLAND\b", path: + "~/Desktop/fltk/CMake", glob: "*.cmake", output_mode: "content") + ⎿ Found 5 lines (ctrl+o to expand) + +⏺ Только комментарии. Верификация src/ и FL/: + +⏺ Search(pattern: "#\s*if.*(WIN32|_WIN32|__APPLE__|WAYLAND|MSVC|CYGWIN|MINGW)", + path: "~/Desktop/fltk/src", output_mode: "count") + ⎿ Found 3 matches across 2 files (ctrl+o to expand) + +⏺ Search(pattern: "#\s*if.*(WIN32|_WIN32|__APPLE__|WAYLAND|MSVC|CYGWIN|MINGW)", + path: "~/Desktop/fltk/FL", output_mode: "count") + ⎿ Found 0 matches across 0 files + +⏺ Search(pattern: "#\s*if.*(WIN32|_WIN32|__APPLE__|WAYLAND|MSVC|CYGWIN|MINGW)", + path: + "~/Desktop/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx", + output_mode: "content") + ⎿ Found 15 lines (ctrl+o to expand) + +⏺ Search(pattern: "#\s*if.*(WIN32|_WIN32|__APPLE__|WAYLAND|MSVC|CYGWIN|MINGW)", + path: "~/Desktop/fltk/src/Fl_JPEG_Image.cxx", output_mode: "content") + ⎿ Found 11 lines (ctrl+o to expand) + +⏺ Остались 3 __CYGWIN__ ссылки — Cygwin технически является X11-платформой (Xft + обработка разной ширины wchar_t), поэтому это допустимо. Все основные + платформо-специфичные ветки _WIN32, __APPLE__, FLTK_USE_WAYLAND полностью + удалены. + +⏺ Фаза 1 завершена. Вот итоговая сводка выполненной работы: + + Фаза 1: Удаление не-X11 платформ — Завершено + + Удалённые директории (~70 файлов): + + - src/drivers/Cocoa/, src/drivers/Darwin/, src/drivers/GDI/, + src/drivers/Quartz/, src/drivers/Wayland/, src/drivers/WinAPI/, libdecor/ + + Удалённые исходные файлы: + + - src/: Fl_win32.cxx, fl_dnd_win32.cxx, Fl_get_key_win32.cxx, Fl_cocoa.mm, + Fl_get_key_mac.cxx, Fl_MacOS_Sys_Menu_Bar.mm, + Fl_Native_File_Chooser_WIN32.cxx, Fl_Native_File_Chooser_MAC.mm, + fl_encoding_mac_roman.cxx, scandir_win32.c, fl_call_main.c + - FL/: win32.H, mac.H, wayland.H + - CMake/: pen-support.c, MacOSXBundleInfo.plist.in, macOS-bundle-wrapper.in, + macOSMaxAllowed.c + - README.macOS.md, README.Windows.txt, README.Wayland.txt + - fluid/tools/ExternalCodeEditor_WIN32.cxx + + Упрощённые файлы: + + - FL/platform.H — только #include "x11.H" + - FL/math.h — убран macOS cyclic include и WIN32/CRAY блок + - FL/gl.h, FL/glu.h — убраны WIN32/APPLE пути, только <GL/gl.h> + - FL/fl_utf8.h — убран WIN32 блок + - FL/Fl_Window.H — убран HICON блок (36 строк) + - FL/Fl.H — убран APPLE блок + - FL/platform_types.h — убраны WIN64/WIN32 типы и dirent + - src/Fl_Cairo.cxx — упрощён до X11-only (убрано ~80 строк + платформо-зависимого кода) + - src/Fl.cxx — упрощена документация args_to_utf8 + - src/flstring.h — убран WIN32 strcasecmp хак + - src/forms_fselect.cxx — убрана WIN32 проверка пути + - src/CMakeLists.txt — убрано ~400 строк платформо-зависимого кода + - CMakeLists.txt — убраны macOS/MSVC/Wayland секции + - CMake/options.cmake — убраны Wayland, WIN32, APPLE опции и детекция + - CMake/resources.cmake — убраны WIN32/MSVC/APPLE блоки + - CMake/setup.cmake — убраны APPLE и WIN32 секции (~60 строк) + - CMake/variables.cmake — упрощено до X11 линковки + - CMake/export.cmake — убраны WIN32 пути для fluid/fltk-options + - CMake/fl_add_library.cmake — убраны MSVC/APPLE секции + - CMake/fl_create_example.cmake — убраны MAC_BUNDLE/WIN32/MSVC секции + - CMake/FLTKConfig.cmake.in — убран WIN32 fluid-cmd + + Результат верификации: + + - #ifdef _WIN32 в src/, FL/ → 0 результатов + - #ifdef __APPLE__ в src/, FL/ → 0 результатов + - FLTK_USE_WAYLAND в src/, FL/ → 0 результатов + - Платформо-специфичный CMake код в CMake/ → только комментарии + + Следующая фаза по плану — Фаза 2: Замена CMake на Makefile. + +✻ Crunched for 33m 46s + @@ -77,11 +77,6 @@ namespace Fl { FL_EXPORT extern Fl_Screen_Driver *screen_driver(); FL_EXPORT extern Fl_System_Driver *system_driver(); -#ifdef __APPLE__ // deprecated in 1.4 - only for compatibility with 1.3 -FL_EXPORT extern void reset_marked_text(); -FL_EXPORT extern void insertion_point_location(int x, int y, int height); -#endif - FL_EXPORT extern int box_shadow_width(); FL_EXPORT extern void box_shadow_width(int W); diff --git a/FL/Fl_Window.H b/FL/Fl_Window.H index 54ecf0f5d..d832b1b88 100644 --- a/FL/Fl_Window.H +++ b/FL/Fl_Window.H @@ -385,43 +385,6 @@ public: void icon(const Fl_RGB_Image*); void icons(const Fl_RGB_Image*[], int); -#if defined(_WIN32) || defined(FL_DOXYGEN) - typedef struct HICON__* HICON; - // These 2 member functions break the driver model but are kept for back compatibility. - // They are implemented in Fl_win32.cxx - - /** Sets the default window icons (Windows platform only). - - Convenience function to set the default icons using Windows' - native HICON icon handles. - - The given icons are copied. You can free the icons immediately after - this call. - - \param[in] big_icon default large icon for all windows - subsequently created - \param[in] small_icon default small icon for all windows - subsequently created - - \see Fl_Window::default_icon(const Fl_RGB_Image *) - \see Fl_Window::default_icons(const Fl_RGB_Image *[], int) - \see Fl_Window::icon(const Fl_RGB_Image *) - \see Fl_Window::icons(const Fl_RGB_Image *[], int) - \see Fl_Window::icons(HICON, HICON) - */ - static void default_icons(HICON big_icon, HICON small_icon); - - /** Sets the window icons using HICON handles (Windows platform only). - - The given icons are copied. You can free the icons immediately after - this call. - - \param[in] big_icon large window icon - \param[in] small_icon small window icon - */ - void icons(HICON big_icon, HICON small_icon); -#endif // defined(_WIN32) || defined(FL_DOXYGEN) - /* for legacy compatibility */ const void* icon() const; void icon(const void * ic); diff --git a/FL/fl_utf8.h b/FL/fl_utf8.h index c55db12e9..bd55f655d 100644 --- a/FL/fl_utf8.h +++ b/FL/fl_utf8.h @@ -116,14 +116,6 @@ FL_EXPORT char* fl_utf2mbcs(const char *src); FL_EXPORT unsigned fl_utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen); /*****************************************************************************/ -#ifdef _WIN32 -/* these two Windows-only functions are kept for API compatibility */ -/* OD: Attempt to convert the UTF-8 string to the current locale */ -FL_EXPORT char *fl_utf8_to_locale(const char *s, int len, unsigned int codepage); - -/* OD: Attempt to convert a string in the current locale to UTF-8 */ -FL_EXPORT char *fl_locale_to_utf8(const char *s, int len, unsigned int codepage); -#endif /* _WIN32 */ /***************************************************************************** * The following functions are intended to provide portable, UTF-8 aware @@ -43,27 +43,11 @@ # define FL_gl_H # include "Enumerations.H" // for color names -# ifdef _WIN32 -# include <windows.h> -# endif # ifndef APIENTRY -# if defined(__CYGWIN__) -# define APIENTRY __attribute__ ((__stdcall__)) -# else -# define APIENTRY -# endif +# define APIENTRY # endif -# ifdef __APPLE__ // PORTME: OpenGL path abstraction -# ifndef GL_SILENCE_DEPRECATION -# define GL_SILENCE_DEPRECATION 1 -# endif -# if !defined(__gl3_h_) // make sure OpenGL/gl3.h was not included before -# include <OpenGL/gl.h> -# endif -# else -# include <GL/gl.h> -# endif // __APPLE__ // PORTME: OpenGL Path abstraction +# include <GL/gl.h> FL_EXPORT void gl_start(); FL_EXPORT void gl_finish(); @@ -25,21 +25,10 @@ # define FL_glu_H # include "Enumerations.H" // for color names -# ifdef _WIN32 -# include <windows.h> -# endif # ifndef APIENTRY -# if defined(__CYGWIN__) -# define APIENTRY __attribute__ ((__stdcall__)) -# else -# define APIENTRY -# endif +# define APIENTRY # endif -# ifdef __APPLE__ // PORTME: OpenGL Path abstraction -# include <OpenGL/glu.h> -# else -# include <GL/glu.h> -# endif +# include <GL/glu.h> #endif // !FL_glu_H diff --git a/FL/mac.H b/FL/mac.H deleted file mode 100644 index 5133a6ce8..000000000 --- a/FL/mac.H +++ /dev/null @@ -1,204 +0,0 @@ -// -// Mac header file for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Do not directly include this file, instead use <FL/platform.H>. It will -// include this file if "__APPLE__" is defined. This is to encourage -// portability of even the system-specific code... -#ifndef FL_DOXYGEN - -#if !defined(FL_PLATFORM_H) -# error "Never use <FL/mac.H> directly; include <FL/platform.H> instead." -#endif // !FL_PLATFORM_H - -#ifdef __OBJC__ - @class NSOpenGLContext; -# ifndef GL_SILENCE_DEPRECATION -# define GL_SILENCE_DEPRECATION 1 -# endif -#elif defined(__cplusplus) - class NSOpenGLContext; -#endif /* __OBJC__ */ -extern NSOpenGLContext *fl_mac_glcontext(GLContext rc); - -#ifdef __OBJC__ -@class FLWindow; // a subclass of the NSWindow Cocoa class -typedef FLWindow *Window; -#else -typedef class FLWindow *Window; // pointer to the FLWindow objective-c class -#endif // __OBJC__ - -#include <FL/Fl_Widget.H> // for Fl_Callback - -#if (defined(FL_LIBRARY) || defined(FL_INTERNALS)) // this part must be compiled when building the FLTK libraries - -// Standard MacOS C/C++ includes... -#include <ApplicationServices/ApplicationServices.h> -#undef check // because of Fl::check() - -#ifndef MAC_OS_X_VERSION_10_4 -#define MAC_OS_X_VERSION_10_4 1040 -#endif -#ifndef MAC_OS_X_VERSION_10_5 -#define MAC_OS_X_VERSION_10_5 1050 -#endif -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif -#ifndef MAC_OS_X_VERSION_10_7 -#define MAC_OS_X_VERSION_10_7 1070 -#endif -#ifndef MAC_OS_X_VERSION_10_8 -#define MAC_OS_X_VERSION_10_8 1080 -#endif -#ifndef MAC_OS_X_VERSION_10_9 -#define MAC_OS_X_VERSION_10_9 1090 -#endif -#ifndef MAC_OS_X_VERSION_10_10 -#define MAC_OS_X_VERSION_10_10 101000 -#endif -#ifndef MAC_OS_X_VERSION_10_11 -#define MAC_OS_X_VERSION_10_11 101100 -#endif -#ifndef MAC_OS_X_VERSION_10_12 -#define MAC_OS_X_VERSION_10_12 101200 -#endif -#ifndef MAC_OS_X_VERSION_10_13 -#define MAC_OS_X_VERSION_10_13 101300 -#endif -#ifndef MAC_OS_X_VERSION_10_14 -#define MAC_OS_X_VERSION_10_14 101400 -#endif -#ifndef MAC_OS_X_VERSION_10_15 -#define MAC_OS_X_VERSION_10_15 101500 -#endif -#ifndef MAC_OS_X_VERSION_10_16 -#define MAC_OS_X_VERSION_10_16 101600 -#endif -#ifndef MAC_OS_VERSION_11_0 -#define MAC_OS_VERSION_11_0 110000 -#endif -#ifndef MAC_OS_VERSION_12_0 -#define MAC_OS_VERSION_12_0 120000 -#endif -#ifndef MAC_OS_VERSION_13_0 -#define MAC_OS_VERSION_13_0 130000 -#endif -#ifndef MAC_OS_VERSION_14_0 -#define MAC_OS_VERSION_14_0 140000 -#endif -#ifndef MAC_OS_VERSION_15_0 -#define MAC_OS_VERSION_15_0 150000 -#endif - - -#ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h -#if defined(__LP64__) && __LP64__ -typedef long NSInteger; -typedef unsigned long NSUInteger; -#else -typedef int NSInteger; -typedef unsigned int NSUInteger; -#endif -#endif - -struct flCocoaRegion { - int count; - CGRect *rects; -}; // a region is the union of a series of rectangles - -#ifndef CGFLOAT_DEFINED //appears with 10.5 in CGBase.h -#if defined(__LP64__) && __LP64__ -typedef double CGFloat; -#else -typedef float CGFloat; -#endif -#endif // CGFLOAT_DEFINED - -#else - -typedef struct CGContext* CGContextRef; - -#endif // FL_LIBRARY || FL_INTERNALS - -extern CGContextRef fl_gc; - -#endif // FL_DOXYGEN -/** \file - Mac OS X-specific symbols. - */ - -/** \defgroup group_macosx Mac OS X-specific symbols - Mac OS X-specific symbols declared in <FL/platform.H> - \sa \ref osissues_macos - \{ */ - -/** - Attaches a callback to the "About myprog" item of the system application menu. - For back-compatibility. - Equivalent to Fl_Sys_Menu_Bar::about(Fl_Callback *cb, void *user_data). - */ -void fl_mac_set_about(Fl_Callback *cb, void *user_data, int shortcut = 0); - -/** Returns the macOS-specific graphics context for the current window */ -extern CGContextRef fl_mac_gc(); -/** Returns the macOS-specific window reference corresponding to the given Fl_Window object */ -extern FLWindow *fl_mac_xid(const Fl_Window *win); -/** Returns the Fl_Window corresponding to the given macOS-specific window reference */ -extern Fl_Window *fl_mac_find(FLWindow *); -class Fl_Gl_Window; - -/** The version number of the running Mac OS X (e.g., 100604 for 10.6.4, 101300 for 10.13, 140102 for 14.1.2). - FLTK initializes this global variable before main() begins running. If - the value is needed in a static initializer, a previous call to Fl::system_driver() - makes sure \ref fl_mac_os_version has been initialized. - */ -extern int fl_mac_os_version; - -struct Fl_Menu_Item; - -class Fl_Mac_App_Menu { -public: - /** Localizable text for the "About xxx" application menu item */ - static const char *about; - /** Localizable text for the "Print Front Window" application menu item. - This menu item and next one won't be displayed if Fl_Mac_App_Menu::print - is set to an empty string. - */ - static const char *print; - /** Localizable text for the "Print Front Window" application menu item. */ - static const char *print_no_titlebar; - /** Localizable text for the "Toggle print titlebar" application menu item. */ - static const char *toggle_print_titlebar; - /** Localizable text for the "Services" application menu item */ - static const char *services; - /** Localizable text for the "Hide xxx" application menu item */ - static const char *hide; - /** Localizable text for the "Hide Others" application menu item */ - static const char *hide_others; - /** Localizable text for the "Show All" application menu item */ - static const char *show; - /** Localizable text for the "Quit xxx" application menu item */ - static const char *quit; - /** Adds custom menu item(s) to the application menu of the system menu bar. - They are positioned after the "Print Front Window / Toggle printing of titlebar" items, or at their place - if they were removed with <tt>Fl_Mac_App_Menu::print = ""</tt>. - \param m zero-ending array of Fl_Menu_Item 's. - */ - static void custom_application_menu_items(const Fl_Menu_Item *m); -}; - -/** @} */ - @@ -14,18 +14,10 @@ // https://www.fltk.org/bugs.php // -// Xcode on macOS includes files by recursing down into directories. -// This code catches the cycle and directly includes the required file. -#ifdef fl_math_h_cyclic_include -# include "/usr/include/math.h" -#endif - #ifndef fl_math_h # define fl_math_h -# define fl_math_h_cyclic_include # include <math.h> -# undef fl_math_h_cyclic_include # ifndef M_PI # define M_PI 3.14159265358979323846 @@ -40,11 +32,4 @@ # define M_SQRT1_2 0.70710678118654752440 # endif // !M_SQRT2 -# if (defined(_WIN32) || defined(CRAY)) && !defined(__MINGW32__) - -inline double rint(double v) {return floor(v+.5);} -inline double copysign(double a, double b) {return b<0 ? -a : a;} - -# endif // (_WIN32 || CRAY) && !__MINGW32__ - #endif // !fl_math_h diff --git a/FL/platform.H b/FL/platform.H index 715a10c64..3e19cb64a 100644 --- a/FL/platform.H +++ b/FL/platform.H @@ -33,15 +33,7 @@ # include <FL/fl_types.h> // for uchar class Fl_Window; -# ifdef _WIN32 -# include "win32.H" -# elif defined(FLTK_USE_WAYLAND) -# include "wayland.H" -# elif defined(FLTK_USE_X11) -# include "x11.H" -# elif defined(__APPLE__) -# include "mac.H" -# endif // _WIN32 +# include "x11.H" // // cross-platform declarations @@ -58,11 +50,9 @@ public: // static variables, static functions and member functions static Fl_X* first; static Fl_X* flx(const Fl_Window* w) {return w ? (Fl_X*)w->flx_ : 0;} -# if defined(FLTK_USE_X11) && FLTK_USE_X11 // for backward compatibility static void make_xid(Fl_Window*, XVisualInfo* =fl_visual, Colormap=fl_colormap); static Fl_X* set_xid(Fl_Window*, Window); static inline Fl_X* i(const Fl_Window* w) {return flx(w);} -# endif }; inline Window fl_xid(const Fl_Window* w) { Fl_X *xTemp = Fl_X::flx(w); return xTemp ? (Window)xTemp->xid : 0; } diff --git a/FL/platform_types.h b/FL/platform_types.h index 67656b72a..0109050cb 100644 --- a/FL/platform_types.h +++ b/FL/platform_types.h @@ -37,31 +37,19 @@ typedef opaque fl_uintptr_t; /** Platform-specific value representing an offscreen drawing buffer. - \note This value can be safely cast to these types on each platform: - \li X11: Pixmap - \li Wayland: cairo_t * - \li Windows: HBITMAP - \li macOS: CGContextRef + \note This value can be safely cast to Pixmap on X11. */ typedef opaque Fl_Offscreen; /** Pointer to a platform-specific structure representing a collection of rectangles. - \note This pointer can be safely cast to these types on each platform: - \li X11: Region as defined by X11 - \li Wayland: cairo_region_t * - \li Windows: HRGN - \li macOS: struct flCocoaRegion * + \note This pointer can be safely cast to Region as defined by X11. */ typedef struct opaque *Fl_Region; typedef opaque FL_SOCKET; /**< socket or file descriptor */ /** Pointer to a platform-specific structure representing the window's OpenGL rendering context. - \note This pointer can be safely cast to these types on each platform: - \li X11: GLXContext - \li Wayland: EGLContext - \li Windows: HGLRC - \li macOS: NSOpenGLContext * + \note This pointer can be safely cast to GLXContext on X11. */ typedef struct opaque *GLContext; @@ -72,8 +60,8 @@ typedef struct opaque *GLContext; */ typedef opaque Fl_Timestamp; -# define FL_COMMAND opaque /**< An alias for FL_CTRL on Windows and X11, or FL_META on MacOS X */ -# define FL_CONTROL opaque /**< An alias for FL_META on Windows and X11, or FL_CTRL on MacOS X */ +# define FL_COMMAND opaque /**< An alias for FL_CTRL on X11 */ +# define FL_CONTROL opaque /**< An alias for FL_META on X11 */ #else /* FL_DOXYGEN */ @@ -95,40 +83,16 @@ typedef opaque Fl_Timestamp; different signedness of socket numbers on *some* platforms. */ -#ifdef _WIN64 - -#if defined(_MSC_VER) && (_MSC_VER < 1600) -# include <stddef.h> /* stdint.h not available before VS 2010 (1600) */ -#else -# include <stdint.h> -#endif - -typedef intptr_t fl_intptr_t; -typedef uintptr_t fl_uintptr_t; - -#else /* ! _WIN64 */ - typedef long fl_intptr_t; typedef unsigned long fl_uintptr_t; -#endif /* _WIN64 */ - typedef void *GLContext; typedef void *Fl_Region; typedef fl_uintptr_t Fl_Offscreen; -/* Allows all hybrid combinations except WIN32 + X11 with MSVC */ -#if defined(_WIN32) && !defined(__MINGW32__) - struct dirent {char d_name[1];}; -#else -# include <dirent.h> -#endif +#include <dirent.h> -# if defined(_WIN64) && defined(_MSC_VER) -typedef unsigned __int64 FL_SOCKET; /* *FIXME* - FL_SOCKET (see above) */ -# else typedef int FL_SOCKET; -# endif #include <FL/Fl_Export.H> extern FL_EXPORT int fl_command_modifier(); diff --git a/FL/wayland.H b/FL/wayland.H deleted file mode 100644 index 6d1f0e771..000000000 --- a/FL/wayland.H +++ /dev/null @@ -1,62 +0,0 @@ -// -// Wayland/X11 hybrid platform header file for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#if !defined(FL_PLATFORM_H) -# error "Never use <FL/wayland.H> directly; include <FL/platform.H> instead." -#endif // !FL_PLATFORM_H - -/** \file - \anchor wayland_H Definitions of functions specific to the Wayland platform. -*/ - -// *********** for Wayland component *********** - -typedef struct _cairo cairo_t; - -/** Returns the Wayland display in use */ -extern FL_EXPORT struct wl_display *fl_wl_display(); -/** Returns the wl_surface associated to a shown window */ -extern FL_EXPORT struct wl_surface *fl_wl_surface(struct wld_window *xid); -/** Returns a platform-specific reference associated to a shown window */ -extern FL_EXPORT struct wld_window *fl_wl_xid(const Fl_Window *win); -/** Returns the Fl_Window corresponding to a given the platform-specific window reference */ -extern FL_EXPORT Fl_Window *fl_wl_find(struct wld_window *); -/** Returns the cairo context associated to the current window or Fl_Image_Surface. - Usable both when the Wayland/X11 hybrid FLTK library runs as a Wayland client and when it runs as an X11 client. */ -extern FL_EXPORT cairo_t *fl_wl_gc(); -/** Returns the wl_compositor of the current Wayland session. - This allows, for example, to create a wl_surface with - \code - struct wl_surface *my_wl_surface = wl_compositor_create_surface(fl_wl_compositor()); - \endcode - */ -extern FL_EXPORT struct wl_compositor *fl_wl_compositor(); -/** Returns the current buffer scaling factor for \p window. */ -extern FL_EXPORT int fl_wl_buffer_scale(Fl_Window *window); -typedef void *EGLContext; -/** Returns the EGLContext corresponding to the given GLContext */ -extern FL_EXPORT EGLContext fl_wl_glcontext(GLContext rc); - -#ifndef FL_DOXYGEN - -# ifdef FLTK_USE_X11 -// *********** for X11 component *********** -# include "x11.H" -# else - typedef struct wld_window *Window; -# endif - -#endif // FL_DOXYGEN diff --git a/FL/win32.H b/FL/win32.H deleted file mode 100644 index d7bfd5c18..000000000 --- a/FL/win32.H +++ /dev/null @@ -1,93 +0,0 @@ -// -// Windows platform header file for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Do not directly include this file, instead use <FL/platform.H>. It will -// include this file if _WIN32 is defined. This is to encourage -// portability of even the system-specific code... - -#ifdef FL_DOXYGEN - -/** \file - Definitions of functions specific to the Windows platform. -*/ - -/** Returns the Windows-specific window reference corresponding to the given Fl_Window object */ -extern HWND fl_win32_xid(const Fl_Window *win); -/** Returns the Fl_Window corresponding to the given Windows-specific window reference */ -extern Fl_Window *fl_win32_find(HWND); -/** Returns the Windows-specific GL rendering context corresponding to the given GLContext */ -extern HGLRC fl_win32_glcontext(GLContext rc); -/** Returns the Windows-specific graphics context for the current window */ -extern HDC fl_win32_gc(); -/** Returns the Windows-specific display in use */ -extern HINSTANCE fl_win32_display(); - -#else - -#ifndef FL_PLATFORM_H -# error "Never use <FL/win32.H> directly; include <FL/platform.H> instead." -#endif // !FL_PLATFORM_H - -#include <windows.h> -typedef HWND Window; - -typedef struct HGLRC__ *HGLRC; -extern FL_EXPORT HGLRC fl_win32_glcontext(GLContext rc); -extern FL_EXPORT HWND fl_win32_xid(const Fl_Window *win); -extern FL_EXPORT Fl_Window *fl_win32_find(HWND); - -// this part is included only when compiling the FLTK library or if requested explicitly -#if defined(FL_LIBRARY) || defined(FL_INTERNALS) - -// In some of the distributions, the gcc header files are missing some stuff: -#ifndef LPMINMAXINFO -#define LPMINMAXINFO MINMAXINFO* -#endif -#ifndef VK_LWIN -#define VK_LWIN 0x5B -#define VK_RWIN 0x5C -#define VK_APPS 0x5D -#endif - -extern FL_EXPORT UINT fl_wake_msg; -extern FL_EXPORT char fl_override_redirect; // hack into Fl_Window::make_xid() -extern FL_EXPORT HPALETTE fl_palette; // non-zero only on 8-bit displays! -extern void fl_release_dc(HWND w, HDC dc); -extern FL_EXPORT void fl_save_dc( HWND w, HDC dc); - -#endif // FL_LIBRARY || FL_INTERNALS - -// most recent fl_color() or fl_rgbcolor() points at one of these: -extern FL_EXPORT struct Fl_XMap { - COLORREF rgb; // this should be the type the RGB() macro returns - HPEN pen; // pen, 0 if none created yet - int brush; // ref to solid brush, 0 if none created yet - int pwidth; // the width of the pen, if present -} *fl_current_xmap; -inline COLORREF fl_RGB() {return fl_current_xmap->rgb;} -inline HPEN fl_pen() {return fl_current_xmap->pen;} -FL_EXPORT HBRUSH fl_brush(); // allocates a brush if necessary -FL_EXPORT HBRUSH fl_brush_action(int); // now does the real work - -extern FL_EXPORT HINSTANCE fl_display; -extern FL_EXPORT HINSTANCE fl_win32_display(); -extern FL_EXPORT HDC fl_gc; -extern FL_EXPORT HDC fl_win32_gc(); -extern FL_EXPORT MSG fl_msg; -extern FL_EXPORT HDC fl_GetDC(Window); -extern FL_EXPORT HDC fl_makeDC(HBITMAP); - -#endif // FL_DOXYGEN diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..8739b9460 --- /dev/null +++ b/Makefile @@ -0,0 +1,656 @@ +# +# Makefile for FLTK (Fast Light Toolkit) +# +# X11-only build with Cairo/Pango support. +# No CMake, no autoconf. +# +# Copyright 1998-2026 by Bill Spitzak and others. +# +# This library is free software. Distribution and use rights are outlined in +# the file "COPYING" which should have been included with this file. +# + +####################################################################### +# Configuration +####################################################################### + +PREFIX = /usr/local +BINDIR = $(PREFIX)/bin +LIBDIR = $(PREFIX)/lib +INCLUDEDIR = $(PREFIX)/include + +# Compiler settings +CXX = g++ +CC = gcc +AR = ar +RANLIB = ranlib + +# Base flags +CFLAGS = -O2 -Wall -fPIC +CXXFLAGS = -O2 -Wall -fPIC -std=c++11 + +# FLTK-specific defines +DEFINES = -DFL_LIBRARY + +# Include directories +# Note: -I./fluid is needed for fluid sources that use relative includes +INCLUDES = -I. -I./src -I./jpeg -I./png -I./zlib -I./fluid + +# Platform detection and X11 paths +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + # macOS with XQuartz + X11_CFLAGS = -I/opt/X11/include + X11_LIBS = -L/opt/X11/lib -lX11 -lXext -lXft -lXinerama -lXcursor -lXfixes -lXrender +else + # Linux - use pkg-config + X11_CFLAGS = $(shell pkg-config --cflags x11 xext xft xinerama xcursor xfixes xrender) + X11_LIBS = $(shell pkg-config --libs x11 xext xft xinerama xcursor xfixes xrender) +endif + +CAIRO_CFLAGS = $(shell pkg-config --cflags cairo pangocairo pango) +CAIRO_LIBS = $(shell pkg-config --libs cairo pangocairo pango gobject-2.0) + +GL_CFLAGS = $(shell pkg-config --cflags gl glu) +GL_LIBS = $(shell pkg-config --libs gl glu) + +# We use bundled jpeg/png/zlib, no system library needed +PNG_LIBS = +JPEG_LIBS = + +# Combined flags +ALL_CFLAGS = $(CFLAGS) $(DEFINES) $(INCLUDES) $(X11_CFLAGS) $(CAIRO_CFLAGS) +ALL_CXXFLAGS = $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(X11_CFLAGS) $(CAIRO_CFLAGS) + +# Libraries for linking +FLTK_LDLIBS = $(X11_LIBS) $(CAIRO_LIBS) -lm -ldl -lpthread + +####################################################################### +# Source files for libfltk.a (core library) +####################################################################### + +CORE_SRCS = \ + src/Fl.cxx \ + src/Fl_Adjuster.cxx \ + src/Fl_Bitmap.cxx \ + src/Fl_Browser.cxx \ + src/Fl_Browser_.cxx \ + src/Fl_Browser_load.cxx \ + src/Fl_Box.cxx \ + src/Fl_Button.cxx \ + src/Fl_Cairo.cxx \ + src/Fl_Chart.cxx \ + src/Fl_Check_Browser.cxx \ + src/Fl_Check_Button.cxx \ + src/Fl_Choice.cxx \ + src/Fl_Clock.cxx \ + src/Fl_Color_Chooser.cxx \ + src/Fl_Copy_Surface.cxx \ + src/Fl_Counter.cxx \ + src/Fl_Device.cxx \ + src/Fl_Dial.cxx \ + src/Fl_Double_Window.cxx \ + src/Fl_File_Browser.cxx \ + src/Fl_File_Chooser.cxx \ + src/Fl_File_Chooser2.cxx \ + src/Fl_File_Icon.cxx \ + src/Fl_File_Input.cxx \ + src/Fl_Flex.cxx \ + src/Fl_Graphics_Driver.cxx \ + src/Fl_Grid.cxx \ + src/Fl_Group.cxx \ + src/Fl_Help_View.cxx \ + src/Fl_Image.cxx \ + src/Fl_Image_Surface.cxx \ + src/Fl_Input.cxx \ + src/Fl_Input_.cxx \ + src/Fl_Input_Choice.cxx \ + src/Fl_Light_Button.cxx \ + src/Fl_Menu.cxx \ + src/Fl_Menu_.cxx \ + src/Fl_Menu_Bar.cxx \ + src/Fl_Menu_Button.cxx \ + src/Fl_Menu_Window.cxx \ + src/Fl_Menu_add.cxx \ + src/Fl_Menu_global.cxx \ + src/Fl_Message.cxx \ + src/Fl_Multi_Label.cxx \ + src/Fl_Native_File_Chooser.cxx \ + src/Fl_Overlay_Window.cxx \ + src/Fl_Pack.cxx \ + src/Fl_Paged_Device.cxx \ + src/Fl_Pixmap.cxx \ + src/Fl_Positioner.cxx \ + src/Fl_Preferences.cxx \ + src/Fl_Printer.cxx \ + src/Fl_Progress.cxx \ + src/Fl_Repeat_Button.cxx \ + src/Fl_Return_Button.cxx \ + src/Fl_Roller.cxx \ + src/Fl_Round_Button.cxx \ + src/Fl_Scheme.cxx \ + src/Fl_Scheme_Choice.cxx \ + src/Fl_Screen_Driver.cxx \ + src/Fl_Scroll.cxx \ + src/Fl_Scrollbar.cxx \ + src/Fl_Shared_Image.cxx \ + src/Fl_Shortcut_Button.cxx \ + src/Fl_Single_Window.cxx \ + src/Fl_Slider.cxx \ + src/Fl_Spinner.cxx \ + src/Fl_Sys_Menu_Bar.cxx \ + src/Fl_System_Driver.cxx \ + src/Fl_Table.cxx \ + src/Fl_Table_Row.cxx \ + src/Fl_Tabs.cxx \ + src/Fl_Terminal.cxx \ + src/Fl_Text_Buffer.cxx \ + src/Fl_Text_Display.cxx \ + src/Fl_Text_Editor.cxx \ + src/Fl_Tile.cxx \ + src/Fl_Tiled_Image.cxx \ + src/Fl_Timeout.cxx \ + src/Fl_Tooltip.cxx \ + src/Fl_Tree.cxx \ + src/Fl_Tree_Item_Array.cxx \ + src/Fl_Tree_Item.cxx \ + src/Fl_Tree_Prefs.cxx \ + src/Fl_Valuator.cxx \ + src/Fl_Value_Input.cxx \ + src/Fl_Value_Output.cxx \ + src/Fl_Value_Slider.cxx \ + src/Fl_Widget.cxx \ + src/Fl_Widget_Surface.cxx \ + src/Fl_Window.cxx \ + src/Fl_Window_Driver.cxx \ + src/Fl_Window_fullscreen.cxx \ + src/Fl_Window_hotspot.cxx \ + src/Fl_Window_iconize.cxx \ + src/Fl_Wizard.cxx \ + src/Fl_XBM_Image.cxx \ + src/Fl_XPM_Image.cxx \ + src/Fl_abort.cxx \ + src/Fl_add_idle.cxx \ + src/Fl_arg.cxx \ + src/Fl_compose.cxx \ + src/Fl_display.cxx \ + src/Fl_get_system_colors.cxx \ + src/Fl_grab.cxx \ + src/Fl_lock.cxx \ + src/Fl_own_colormap.cxx \ + src/Fl_visual.cxx \ + src/filename_absolute.cxx \ + src/filename_expand.cxx \ + src/filename_ext.cxx \ + src/filename_isdir.cxx \ + src/filename_list.cxx \ + src/filename_match.cxx \ + src/filename_setext.cxx \ + src/fl_arc.cxx \ + src/fl_ask.cxx \ + src/fl_boxtype.cxx \ + src/fl_color.cxx \ + src/fl_contrast.cxx \ + src/fl_cursor.cxx \ + src/fl_curve.cxx \ + src/fl_diamond_box.cxx \ + src/fl_draw.cxx \ + src/fl_draw_arrow.cxx \ + src/fl_draw_pixmap.cxx \ + src/fl_encoding_latin1.cxx \ + src/fl_engraved_label.cxx \ + src/fl_file_dir.cxx \ + src/fl_font.cxx \ + src/fl_gleam.cxx \ + src/fl_gtk.cxx \ + src/fl_labeltype.cxx \ + src/fl_open_uri.cxx \ + src/fl_oval_box.cxx \ + src/fl_overlay.cxx \ + src/fl_oxy.cxx \ + src/fl_plastic.cxx \ + src/fl_read_image.cxx \ + src/fl_rect.cxx \ + src/fl_round_box.cxx \ + src/fl_rounded_box.cxx \ + src/fl_set_font.cxx \ + src/fl_scroll_area.cxx \ + src/fl_shadow_box.cxx \ + src/fl_shortcut.cxx \ + src/fl_show_colormap.cxx \ + src/fl_string_functions.cxx \ + src/fl_symbols.cxx \ + src/fl_utf8.cxx \ + src/fl_vertex.cxx \ + src/print_button.cxx \ + src/screen_xywh.cxx + +# X11 driver files +DRIVER_SRCS = \ + src/Fl_x.cxx \ + src/fl_dnd_x.cxx \ + src/Fl_get_key.cxx \ + src/Fl_Native_File_Chooser_FLTK.cxx \ + src/Fl_Native_File_Chooser_GTK.cxx \ + src/Fl_Native_File_Chooser_Kdialog.cxx \ + src/Fl_Native_File_Chooser_Zenity.cxx \ + src/drivers/Posix/Fl_Posix_Printer_Driver.cxx \ + src/drivers/Posix/Fl_Posix_System_Driver.cxx \ + src/drivers/Unix/Fl_Unix_Screen_Driver.cxx \ + src/drivers/Unix/Fl_Unix_System_Driver.cxx \ + src/drivers/X11/Fl_X11_Screen_Driver.cxx \ + src/drivers/X11/Fl_X11_Window_Driver.cxx \ + src/drivers/X11/fl_X11_platform_init.cxx \ + src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx \ + src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx \ + src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx \ + src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx + +# PostScript driver +PS_SRCS = \ + src/drivers/PostScript/Fl_PostScript.cxx \ + src/drivers/PostScript/Fl_PostScript_image.cxx + +# C source files +CORE_C_SRCS = \ + src/flstring.c \ + src/numericsort.c \ + src/vsnprintf.c \ + src/scandir_posix.c \ + src/xutf8/is_right2left.c \ + src/xutf8/is_spacing.c \ + src/xutf8/case.c \ + src/xutf8/keysym2Ucs.c + +# All core sources +LIBFLTK_SRCS = $(CORE_SRCS) $(DRIVER_SRCS) $(PS_SRCS) +LIBFLTK_C_SRCS = $(CORE_C_SRCS) + +####################################################################### +# Source files for libfltk_images.a +####################################################################### + +IMG_SRCS = \ + src/fl_images_core.cxx \ + src/fl_write_png.cxx \ + src/Fl_BMP_Image.cxx \ + src/Fl_File_Icon2.cxx \ + src/Fl_GIF_Image.cxx \ + src/Fl_Anim_GIF_Image.cxx \ + src/Fl_Help_Dialog.cxx \ + src/Fl_ICO_Image.cxx \ + src/Fl_JPEG_Image.cxx \ + src/Fl_PNG_Image.cxx \ + src/Fl_PNM_Image.cxx \ + src/Fl_Image_Reader.cxx \ + src/Fl_SVG_Image.cxx \ + src/nanosvg.cxx \ + src/drivers/SVG/Fl_SVG_File_Surface.cxx + +####################################################################### +# Source files for libfltk_forms.a +####################################################################### + +FORMS_SRCS = \ + src/forms_compatibility.cxx \ + src/forms_bitmap.cxx \ + src/forms_free.cxx \ + src/forms_fselect.cxx \ + src/forms_pixmap.cxx \ + src/forms_timer.cxx + +####################################################################### +# Source files for libfltk_gl.a +####################################################################### + +GL_SRCS = \ + src/Fl_Gl_Choice.cxx \ + src/Fl_Gl_Device_Plugin.cxx \ + src/Fl_Gl_Overlay.cxx \ + src/Fl_Gl_Window.cxx \ + src/freeglut_geometry.cxx \ + src/freeglut_stroke_mono_roman.cxx \ + src/freeglut_stroke_roman.cxx \ + src/freeglut_teapot.cxx \ + src/gl_draw.cxx \ + src/gl_start.cxx \ + src/glut_compatibility.cxx \ + src/glut_font.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx \ + src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx \ + src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx + +####################################################################### +# Source files for fluid +####################################################################### + +FLUID_SRCS = \ + fluid/main.cxx \ + fluid/Fluid.cxx \ + fluid/Project.cxx \ + fluid/app/args.cxx \ + fluid/app/Snap_Action.cxx \ + fluid/app/Image_Asset.cxx \ + fluid/app/history.cxx \ + fluid/app/Menu.cxx \ + fluid/app/shell_command.cxx \ + fluid/app/templates.cxx \ + fluid/io/Code_Writer.cxx \ + fluid/io/Project_Writer.cxx \ + fluid/io/Project_Reader.cxx \ + fluid/io/String_Writer.cxx \ + fluid/nodes/Tree.cxx \ + fluid/nodes/Button_Node.cxx \ + fluid/nodes/Function_Node.cxx \ + fluid/nodes/Grid_Node.cxx \ + fluid/nodes/Group_Node.cxx \ + fluid/nodes/Menu_Node.cxx \ + fluid/nodes/Node.cxx \ + fluid/nodes/Widget_Node.cxx \ + fluid/nodes/Window_Node.cxx \ + fluid/nodes/callbacks.cxx \ + fluid/nodes/factory.cxx \ + fluid/panels/about_panel.cxx \ + fluid/panels/codeview_panel.cxx \ + fluid/panels/function_panel.cxx \ + fluid/panels/settings_panel.cxx \ + fluid/panels/template_panel.cxx \ + fluid/panels/widget_panel.cxx \ + fluid/panels/widget_panel/Grid_Tab.cxx \ + fluid/panels/widget_panel/Grid_Child_Tab.cxx \ + fluid/proj/align_widget.cxx \ + fluid/proj/i18n.cxx \ + fluid/proj/mergeback.cxx \ + fluid/proj/undo.cxx \ + fluid/rsrcs/pixmaps.cxx \ + fluid/tools/ExternalCodeEditor_UNIX.cxx \ + fluid/tools/autodoc.cxx \ + fluid/tools/filename.cxx \ + fluid/widgets/App_Menu_Bar.cxx \ + fluid/widgets/Code_Editor.cxx \ + fluid/widgets/Code_Viewer.cxx \ + fluid/widgets/Text_Viewer.cxx \ + fluid/widgets/Formula_Input.cxx \ + fluid/widgets/Bin_Button.cxx \ + fluid/widgets/Style_Parser.cxx \ + fluid/widgets/Node_Browser.cxx + +####################################################################### +# Bundled libraries source files +####################################################################### + +JPEG_SRCS = \ + jpeg/jaricom.c \ + jpeg/jcapimin.c \ + jpeg/jcapistd.c \ + jpeg/jcarith.c \ + jpeg/jccoefct.c \ + jpeg/jccolor.c \ + jpeg/jcdctmgr.c \ + jpeg/jchuff.c \ + jpeg/jcinit.c \ + jpeg/jcmainct.c \ + jpeg/jcmarker.c \ + jpeg/jcmaster.c \ + jpeg/jcomapi.c \ + jpeg/jcparam.c \ + jpeg/jcprepct.c \ + jpeg/jcsample.c \ + jpeg/jctrans.c \ + jpeg/jdapimin.c \ + jpeg/jdapistd.c \ + jpeg/jdarith.c \ + jpeg/jdatadst.c \ + jpeg/jdatasrc.c \ + jpeg/jdcoefct.c \ + jpeg/jdcolor.c \ + jpeg/jddctmgr.c \ + jpeg/jdhuff.c \ + jpeg/jdinput.c \ + jpeg/jdmainct.c \ + jpeg/jdmarker.c \ + jpeg/jdmaster.c \ + jpeg/jdmerge.c \ + jpeg/jdpostct.c \ + jpeg/jdsample.c \ + jpeg/jdtrans.c \ + jpeg/jerror.c \ + jpeg/jfdctflt.c \ + jpeg/jfdctfst.c \ + jpeg/jfdctint.c \ + jpeg/jidctflt.c \ + jpeg/jidctfst.c \ + jpeg/jidctint.c \ + jpeg/jmemmgr.c \ + jpeg/jmemnobs.c \ + jpeg/jquant1.c \ + jpeg/jquant2.c \ + jpeg/jutils.c + +PNG_SRCS = \ + png/png.c \ + png/pngerror.c \ + png/pngget.c \ + png/pngmem.c \ + png/pngpread.c \ + png/pngread.c \ + png/pngrio.c \ + png/pngrtran.c \ + png/pngrutil.c \ + png/pngset.c \ + png/pngtrans.c \ + png/pngwio.c \ + png/pngwrite.c \ + png/pngwtran.c \ + png/pngwutil.c \ + png/arm/arm_init.c \ + png/arm/filter_neon_intrinsics.c \ + png/arm/palette_neon_intrinsics.c + +ZLIB_SRCS = \ + zlib/adler32.c \ + zlib/compress.c \ + zlib/crc32.c \ + zlib/deflate.c \ + zlib/gzclose.c \ + zlib/gzlib.c \ + zlib/gzread.c \ + zlib/gzwrite.c \ + zlib/infback.c \ + zlib/inffast.c \ + zlib/inflate.c \ + zlib/inftrees.c \ + zlib/trees.c \ + zlib/uncompr.c \ + zlib/zutil.c + +####################################################################### +# Object files +####################################################################### + +LIBFLTK_OBJS = $(LIBFLTK_SRCS:.cxx=.o) +LIBFLTK_C_OBJS = $(LIBFLTK_C_SRCS:.c=.o) +IMG_OBJS = $(IMG_SRCS:.cxx=.o) +FORMS_OBJS = $(FORMS_SRCS:.cxx=.o) +GL_OBJS = $(GL_SRCS:.cxx=.o) +FLUID_OBJS = $(FLUID_SRCS:.cxx=.o) + +JPEG_OBJS = $(JPEG_SRCS:.c=.o) +PNG_OBJS = $(PNG_SRCS:.c=.o) +ZLIB_OBJS = $(ZLIB_SRCS:.c=.o) + +####################################################################### +# Targets +####################################################################### + +.PHONY: all clean install libs fluid + +all: libs fluid + +libs: lib/libfltk.a lib/libfltk_images.a lib/libfltk_forms.a lib/libfltk_gl.a \ + lib/libfltk_jpeg.a lib/libfltk_png.a lib/libfltk_z.a + +fluid: bin/fluid + +####################################################################### +# Directory creation +####################################################################### + +lib: + mkdir -p lib + +bin: + mkdir -p bin + +####################################################################### +# Core library +####################################################################### + +lib/libfltk.a: lib $(LIBFLTK_OBJS) $(LIBFLTK_C_OBJS) + $(AR) rcs $@ $(LIBFLTK_OBJS) $(LIBFLTK_C_OBJS) + $(RANLIB) $@ + +####################################################################### +# Image library +####################################################################### + +lib/libfltk_images.a: lib $(IMG_OBJS) + $(AR) rcs $@ $(IMG_OBJS) + $(RANLIB) $@ + +####################################################################### +# Forms library +####################################################################### + +lib/libfltk_forms.a: lib $(FORMS_OBJS) + $(AR) rcs $@ $(FORMS_OBJS) + $(RANLIB) $@ + +####################################################################### +# OpenGL library +####################################################################### + +lib/libfltk_gl.a: lib $(GL_OBJS) + $(AR) rcs $@ $(GL_OBJS) + $(RANLIB) $@ + +####################################################################### +# Bundled JPEG library +####################################################################### + +lib/libfltk_jpeg.a: lib $(JPEG_OBJS) + $(AR) rcs $@ $(JPEG_OBJS) + $(RANLIB) $@ + +####################################################################### +# Bundled PNG library +####################################################################### + +lib/libfltk_png.a: lib $(PNG_OBJS) + $(AR) rcs $@ $(PNG_OBJS) + $(RANLIB) $@ + +####################################################################### +# Bundled zlib library +####################################################################### + +lib/libfltk_z.a: lib $(ZLIB_OBJS) + $(AR) rcs $@ $(ZLIB_OBJS) + $(RANLIB) $@ + +####################################################################### +# Fluid executable +####################################################################### + +bin/fluid: bin lib/libfltk.a lib/libfltk_images.a $(FLUID_OBJS) + $(CXX) $(CXXFLAGS) -o $@ $(FLUID_OBJS) \ + -Llib -lfltk_images -lfltk -lfltk_jpeg -lfltk_png -lfltk_z \ + $(FLTK_LDLIBS) $(PNG_LIBS) $(JPEG_LIBS) + +####################################################################### +# Compilation rules +####################################################################### + +# C++ files +%.o: %.cxx + $(CXX) $(ALL_CXXFLAGS) -c -o $@ $< + +# C files +%.o: %.c + $(CC) $(ALL_CFLAGS) -c -o $@ $< + +# FLUID include flags +FLUID_CXXFLAGS = $(ALL_CXXFLAGS) -I./fluid + +# Special rules for fluid sources (need fluid include path) +# Pattern rules don't match subdirectories, so we need explicit rules +fluid/%.o: fluid/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/app/%.o: fluid/app/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/io/%.o: fluid/io/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/nodes/%.o: fluid/nodes/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/panels/%.o: fluid/panels/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/panels/widget_panel/%.o: fluid/panels/widget_panel/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/proj/%.o: fluid/proj/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/rsrcs/%.o: fluid/rsrcs/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/tools/%.o: fluid/tools/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +fluid/widgets/%.o: fluid/widgets/%.cxx + $(CXX) $(FLUID_CXXFLAGS) -c -o $@ $< + +# Special rule for jpeg (needs its own include path) +jpeg/%.o: jpeg/%.c + $(CC) $(CFLAGS) -I./jpeg -c -o $@ $< + +# Special rule for png (needs zlib include path) +png/%.o: png/%.c + $(CC) $(CFLAGS) -I./png -I./zlib -c -o $@ $< + +# Special rule for zlib +zlib/%.o: zlib/%.c + $(CC) $(CFLAGS) -I./zlib -c -o $@ $< + +####################################################################### +# Clean +####################################################################### + +clean: + rm -f $(LIBFLTK_OBJS) $(LIBFLTK_C_OBJS) + rm -f $(IMG_OBJS) $(FORMS_OBJS) $(GL_OBJS) + rm -f $(FLUID_OBJS) + rm -f $(JPEG_OBJS) $(PNG_OBJS) $(ZLIB_OBJS) + rm -f lib/*.a + rm -f bin/fluid + +####################################################################### +# Install +####################################################################### + +install: all + mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(INCLUDEDIR)/FL + mkdir -p $(DESTDIR)$(BINDIR) + cp lib/*.a $(DESTDIR)$(LIBDIR)/ + cp FL/*.H FL/*.h $(DESTDIR)$(INCLUDEDIR)/FL/ + cp bin/fluid $(DESTDIR)$(BINDIR)/ diff --git a/README.CMake.txt b/README.CMake.txt deleted file mode 100644 index 7043b13de..000000000 --- a/README.CMake.txt +++ /dev/null @@ -1,1122 +0,0 @@ -README.CMake.txt - Building and Using FLTK with CMake ------------------------------------------------------- - - - CONTENTS -========== - - 1 Introduction to CMake - - 2 Using CMake to Build FLTK - - 2.1 Prerequisites - 2.2 Options - 2.2.1 CMake Specific Configuration Options - 2.2.2 FLTK Specific Configuration Options - 2.2.3 Documentation Options - 2.2.4 Special Options - 2.2.5 Other CMake Cache Variables - 2.3 Building FLTK with CMake (all Platforms) - 2.4 Building under Linux with Unix Makefiles - 2.5 Building under Windows with Visual Studio and/or NMake - 2.5.1 Building under Windows with Visual Studio - 2.5.2 Building under Windows with NMake - 2.6 Building under Windows with MinGW using Makefiles - 2.7 Building under Windows WSL with Clang using Makefiles - 2.8 Building under macOS with Xcode - 2.9 Crosscompiling - - 3 Using CMake with FLTK - - 3.1 Library Names - 3.2 Library Aliases - 3.3 Exported and Imported Targets - 3.4 Building a Simple "Hello World" Program with FLTK - 3.5 Building a Program Using Fluid Files - 3.6 Building a Program Using CMake's FetchContent Module - - - 4 FindFLTK.cmake and find_package(FLTK) - - 1. Introduction to CMake -=========================== - -CMake was designed to let you create build files for a project once and -then compile the project on multiple platforms. - -Using it on any platform consists of the same steps. Create the -CMakeLists.txt build file(s). Run one of the CMake executables, picking -your source directory, build directory, and build target. The "cmake" -executable is a one-step process with everything specified on the command -line. The others let you select options interactively, then configure -and generate your platform-specific target. You then run the resulting -Makefile / project file / solution file as you normally would. - -CMake can be run in up to three ways, depending on your platform. "cmake" -is the basic command line tool. "ccmake" is the curses based interactive -tool. "cmake-gui" is the gui-based interactive tool. Each of these will -take command line options in the form of -DOPTION=VALUE. ccmake and -cmake-gui will also let you change options interactively. - -CMake not only supports, but works best with out-of-tree builds. This means -that your build directory is not the same as your source directory or with a -complex project, not the same as your source root directory. Note that the -build directory is where, in this case, FLTK will be built, not its final -installation point. If you want to build for multiple targets, such as -VC++ and MinGW on Windows, or do some cross-compiling you must use out-of-tree -builds exclusively. In-tree builds will gum up the works by putting a -CMakeCache.txt file in the source root. - -FLTK does not allow in-tree builds since version 1.5.0 for safety reasons. - -More information on CMake can be found on its web site https://www.cmake.org. - - - - 2. Using CMake to Build FLTK -=============================== - - - 2.1 Prerequisites --------------------- - -The prerequisites for building FLTK with CMake are staightforward: -CMake 3.15 or later and a recent FLTK release, snapshot, or Git download -(working copy). Installation of CMake is covered on its web site. - -This howto will cover building FLTK with the default options using CMake -under Linux and MinGW with Unix Makefiles. Chapter 2.5 shows how to use -a MinGW cross compiling toolchain to build a FLTK library for Windows -under Linux. Other platforms are just as easy to use. - - - 2.2 Options --------------- - -Options can be specified to CMake with the -D flag: - - cmake -D <OPTION_NAME>=<OPTION_VALUE> - -Example: - - cmake -D CMAKE_BUILD_TYPE=Debug - -Notes: the space between '-D' and the option name can be omitted. -Option values must be quoted if they contain spaces. - -Other CMake tools are `ccmake` and `cmake-gui` but these are not -described here. - -All options have sensible defaults so you won't usually need to specify -them explicitly. - - - 2.2.1 CMake Specific Configuration Options ---------------------------------------------- - -There are only a few CMake options that you typically want to specify. -Each option has a specific ":type" setting which is kind of optional -but should usually be specified in scripts. - --G "Generator" - This specifies the build system you want to use. In most cases the - platform specific default can be used, but you may want to use - another generator, e.g. "Ninja" on Unix-like platforms (Linux) where - "Unix Makefiles" is the default. On Windows the default is - "Visual Studio xxxx ..." if it is installed, on macOS it is - "Unix Makefiles" like on other Unix-like platforms but you can use - "Xcode" if you like. Other build systems (generators) may be available - on your platform, but these are out of the scope of this document. - The command `cmake --help` outputs a list of available generators. - --D CMAKE_BUILD_TYPE:STRING=... - This specifies what kind of build this is i.e. Release, Debug... - Platform specific compile/link flags/options are automatically selected - by CMake depending on this value. Some generators, notably IDE systems - (e.g. Visual Studio on Windows, Xcode on macOS) ignore this option. You - can specify the build type at build time with these generators. - --D CMAKE_INSTALL_PREFIX:PATH=... - Where everything will go on install. Defaults are /usr/local for Unix - and C:\Program Files\FLTK for Windows. - --D CMAKE_OSX_ARCHITECTURES:STRING=... - This is macOS specific and ignored on other platforms. - Set this to either "arm64", "x86_64", or a list of both "arm64;x86_64". - The latter will build "universal apps" on macOS, whereas the former - will either build Intel (x86_64) or Apple Silicon aka M1 (arm64) apps. - The default is to build for the host processor architecture. - --D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=<macOS version> - default EMPTY - This is macOS specific and ignored on other platforms. - Set this to any macOS version that is supported by the SDK used to - build the FLTK library, e.g. '15.4' or '26.0', leave it empty, or - don't set it at all. This delimits the macOS version where the - programs built with this library can run. - - -Note: the CMake variable BUILD_SHARED_LIBS is ignored by FLTK. FLTK builds - static libs by default and can optionally build shared libs as well. - Please see FLTK_BUILD_SHARED_LIBS instead. - - - 2.2.2 FLTK Specific Configuration Options --------------------------------------------- - -Following are the FLTK specific options. Platform specific options are -ignored on other platforms. For convenience the list of options is ordered -alphabetically except "Documentation Options" and "Special Options" that -follow in their own sections below. - - -FLTK_ABI_VERSION - default EMPTY - Use a numeric value corresponding to the FLTK ABI version you want to - build in the form 1xxyy for FLTK 1.x.y (xx and yy with leading zeroes). - The default ABI version is 1xx00 (the stable ABI throughout all patch - releases of one minor FLTK version). The highest ABI version you may - choose is 1xxyy + 1 for FLTK 1.x.y (again with leading zeroes), i.e. - - 1xx00 <= FL_ABI_VERSION <= FL_API_VERSION + 1 - - since FLTK 1.4.2. In prior versions the highest ABI version that - could be set was the same as FL_API_VERSION. The option to set the ABI - version one greater than the current API version allows to build FLTK - from Git or from a snapshot with the latest ABI features designated - for the next higher version as long as the API version is the old - version of the latest release. - Please see README.abi-version.txt for more details. - -FLTK_ARCHFLAGS - default EMPTY - Extra "architecture" flags used as C and C++ compiler flags. - These flags are also "exported" to fltk-config. - -FLTK_BACKEND_WAYLAND - default ON (only Unix/Linux, not on macOS) - Enable the Wayland backend for all window operations, Cairo for all - graphics, and Pango for text drawing (Linux+FreeBSD only). Resulting FLTK - apps use Wayland when a Wayland compositor is available at runtime, and - use X11 for their window operations otherwise (unless FLTK_BACKEND_X11 - is OFF), but keep using Cairo and Pango - see README.Wayland.txt. - If FLTK_BACKEND_X11 has been turned OFF and there is no Wayland - compositor at runtime, then FLTK programs fail to start. - -FLTK_BACKEND_X11 - default ON on Unix/Linux, OFF elsewhere (Windows, macOS). - Enable or disable the X11 backend on platforms that support it. - - Unix/Linux: enable or disable the X11 backend when building with - Wayland (FLTK_BACKEND_WAYLAND), otherwise this option must be ON. - - macOS: enable the X11 backend instead of standard system graphics. - This requires XQuartz or a similar X11 installation. This option is - tested only with XQuartz by the FLTK team. - Use this only if you know what you do and if you have installed X11. - - Windows/Cygwin: enable X11 backend for Cygwin platforms. This option - is currently (as of FLTK 1.4.0) not supported on Windows. - -Note: On platforms that support Wayland you may set FLTK_BACKEND_WAYLAND=ON - (this is the default) and FLTK_BACKEND_X11=OFF to build a Wayland-only - library or vice versa for an X11-only library. - -FLTK_BUILD_EXAMPLES - default OFF - Build the example programs in the 'examples' directory. - -FLTK_BUILD_FLTK_OPTIONS - default ON - Build the FLTK options editor ("fltk-options"). - -FLTK_BUILD_FLUID - default ON - Build the Fast Light User-Interface Designer ("fluid"). - -FLTK_BUILD_FORMS - default OFF since 1.5.0, ON in prior versions - Build the (X)Forms compatibility library. This option is OFF by default - because most FLTK software doesn't need it. You can turn this option - on for backwards compatibility if you need (X)Forms compatibility. - -FLTK_BUILD_GL - default ON - Build the OpenGL support library fltk_gl (fltk::gl) and enable OpenGL - support in user programs using fltk_gl. - -FLTK_BUILD_SCREENSHOTS - default OFF - Build the programs in the "screenshots" directory for developers - who want to create or modify screenshots for documentation. - Please see 'screenshots/README.txt' for details and instructions. - -FLTK_BUILD_SHARED_LIBS - default OFF - Normally FLTK is built as static libraries which makes more portable - binaries. If you want to use shared libraries, setting this option ON - will build them too. You can use shared FLTK libs in your own CMake - projects by appending "-shared" to FLTK target names as described in - sections 3.1 and 3.2. - -FLTK_BUILD_TEST - default ON in top-level build, OFF in sub-build - Build the test and demo programs in the 'test' directory. The default - is ON if FLTK is built in a top-level project so all test and demo - programs are built. If FLTK is built as a subproject only the library - and the tools (fluid and fltk-config) are built by default. - -FLTK_GRAPHICS_CAIRO - meaningful when building for Wayland, X11 or both. - Default: ON when FLTK_BACKEND_WAYLAND is ON (explicitly or by default), - OFF otherwise. - Make all drawing operations use the Cairo library (rather than Xlib), - producing antialiased graphics. When using Wayland this option is - always ON. Implies FLTK_USE_PANGO. - -FLTK_GRAPHICS_GDIPLUS - default ON (Windows only). - Make FLTK use GDI+ to draw oblique lines and curves resulting in - antialiased graphics. If this option is OFF standard GDI is used. - -FLTK_MSVC_RUNTIME_DLL - default ON (Windows: Visual Studio, NMake, clang). - Select whether the build uses the MS runtime DLL (ON) or not (OFF). - Default is ON: either /MD or /MDd for Release or Debug, respectively. - Select OFF for either /MT or /MTd for Release or Debug, respectively. - If this variable is defined on other platforms it is silently ignored. - -FLTK_OPTION_CAIRO_EXT - default OFF - Enable extended libcairo support. Setting this to ON is not recommended, - see README.Cairo.txt. - -FLTK_OPTION_CAIRO_WINDOW - default OFF - Enable support of class Fl_Cairo_Window (all platforms, requires the - Cairo library) - see README.Cairo.txt. - -FLTK_OPTION_FILESYSTEM_SUPPORT - default ON - -FLTK_OPTION_LARGE_FILE - default ON - Enables large file (>2G) support. - -FLTK_OPTION_OPTIM - default EMPTY - Extra optimization flags for the C and C++ compilers, for instance - "-Wall -Wno-deprecated-declarations". Example: - cmake -D FLTK_BUILD_EXAMPLES=on -D FLTK_OPTION_OPTIM="-Wall -Wextra -pedantic" .. - -FLTK_OPTION_PEN_SUPPORT - default ON - Pen support is relatively small and should be included by default, but - this option allows to switch it off if not needed. - Note: on some older systems or build platforms (notably "classic" MinGW) - compiling and building pen support may not be possible. As of this writing - (Jan. 2026) we don't use dynamic (CMake) tests to find out whether building - is possible or not. Instead users are encouraged to report build errors and - switch this option off to allow to proceed building FLTK 1.5.0. - Note: this option is WIP and may be removed later w/o further notice. - -FLTK_OPTION_PRINT_SUPPORT - default ON - When turned off, the Fl_Printer class does nothing and the - Fl_PostScript_File_Device class cannot be used, but the FLTK library - is somewhat smaller. This option makes sense only on the Unix/Linux - platform or on macOS when FLTK_BACKEND_X11 is ON. - -FLTK_OPTION_STD - removed in FLTK 1.5 - This option allowed FLTK 1.4 to use some specific C++11 features like - std::string in the public API of FLTK 1.4.x. - This option has been removed in FLTK 1.5 which uses std::string - and other C++11 features by default. - You may safely remove this CMake option from your configuration. - -FLTK_OPTION_SVG - default ON - FLTK has a built-in SVG library and can create (write) SVG image files. - Turning this option off disables SVG (read and write) support. - -FLTK_USE_DBUS - default ON (Wayland only). - Meaningful only under Wayland. Allows FLTK to detect the current cursor theme. - -FLTK_USE_LIBDECOR_GTK - default ON (Wayland only). - Meaningful only under Wayland and if FLTK_USE_SYSTEM_LIBDECOR is 'OFF'. - Allows to use libdecor's GTK plugin to draw window titlebars. Otherwise - FLTK does not use GTK and apps will not need linking to GTK. - -FLTK_USE_PANGO - default OFF (see note below) - This option is highly recommended under X11 if FLTK is expected to draw - text that does not use the latin alphabet. - Enables use of the Pango library for drawing text. Pango supports all - unicode-defined scripts and gives FLTK limited support of right-to-left - scripts. This option makes sense only under X11 or Wayland, and also - requires Xft. - This option is ignored (always ON) if Wayland or FLTK_GRAPHICS_CAIRO - is ON. - -FLTK_USE_POLL - default OFF - Deprecated: don't turn this option ON. - -FLTK_USE_PTHREADS - default ON except on Windows. - Enables multithreaded support with pthreads if available. - This option is ignored (switched OFF internally) on Windows except - when using Cygwin. - -FLTK_USE_SYSTEM_LIBDECOR - default ON (Wayland only) - This option makes FLTK use package libdecor-0-dev to draw window titlebars - under Wayland. When OFF or when this package has a version < 0.2.0, FLTK - uses its bundled copy of libdecor to draw window titlebars. - -FLTK_USE_SYSTEM_LIBJPEG - default ON (macOS and Windows: OFF) -FLTK_USE_SYSTEM_LIBPNG - default ON (macOS and Windows: OFF) -FLTK_USE_SYSTEM_ZLIB - default ON (macOS and Windows: OFF) - FLTK has built-in jpeg, zlib, and png libraries. These options let you - use system libraries instead, unless CMake can't find them. If you set - any of these options to OFF, then the built-in library will be used. - The default is ON on Linux/Unix platforms but OFF on Windows and macOS - because of potential incompatibilities on Windows and macOS whereas - the system libraries can typically be used on Linux/Unix. - Note: if any one of libpng or zlib is not found on the system, both - libraries are built using the bundled ones and a warning is issued. - -FLTK_USE_XCURSOR - default ON -FLTK_USE_XFIXES - default ON -FLTK_USE_XFT - default ON -FLTK_USE_XINERAMA - default ON -FLTK_USE_XRENDER - default ON - These are X11 extended libraries. These libs are used if found on the - build system unless the respective option is turned off. - - - 2.2.3 Documentation Options ------------------------------- - - These options are only available if `doxygen' is installed and found. - PDF related options require also `latex'. - -FLTK_BUILD_HTML_DOCS - default ON -FLTK_BUILD_PDF_DOCS - default ON - These options can be used to enable HTML documentation generation with - doxygen. If these are ON the build targets 'html', 'pdf', and 'docs' - are generated but must be built explicitly. The target 'docs' is a - shortcut for 'html' and 'docs'. Technically the CMake build targets - are generated but excluded from 'ALL'. - You can safely leave these two options ON if you want to save build - time because the docs are not built automatically. This may change - in a future release. - -FLTK_BUILD_FLUID_DOCS - default OFF - If this option is ON, the FLUID user documentation can be built (target - 'fluid_docs'). If FLTK_BUILD_PDF_DOCS (see above) is ON, the FLUID - documentation can also be created in PDF form (target 'fluid_pdf'). - To generate the screen shots used in the handbook, the CMake build - type must be set to "Debug". - You can safely set these two options ON if you want to save build - time because the docs are not built automatically. This may change - in a future release. - -FLTK_INCLUDE_DRIVER_DOCS - default OFF - This option adds driver documentation to HTML and PDF docs (if ON). - This option is marked as "advanced" since it is only useful for FLTK - developers and advanced users. It is only used if at least one of the - documentation options above is ON as well. - -FLTK_INSTALL_HTML_DOCS - default OFF -FLTK_INSTALL_FLUID_DOCS - default OFF -FLTK_INSTALL_PDF_DOCS - default OFF - If these options are ON then the HTML, FLUID, and/or PDF docs are - installed when the 'install' target is executed, e.g. `make install'. - You need to select above options FLTK_BUILD_*_DOCS as well and build - the documentation manually (this may be improved in a later version). - - - 2.2.4 Special Options ------------------------- - -FLTK_INSTALL_LINKS - default OFF - Deprecated: install "compatibility" links to compensate for typos in - include statements (for case sensitive file systems only). - You should not use this option, please fix the sources instead for - better cross-platform compatibility. - - - 2.2.5 Other CMake Cache Variables ------------------------------------- - -The following CMake cache variables can be used to view their computed values -in the CMake cache or to change the build behavior in special cases. To view -the variables - - - use `cmake -LA` or - - use `cmake-gui` (switch 'Advanced' view ON) or - - use `ccmake` (hit 't' to "Toggle advanced mode") - - search the CMake cache 'CMakeCache.txt' with your favorite tool. - -Use either the `cmake` commandline, `cmake-gui`, or `ccmake` to change these -variables if needed. - -CMake cache variables can also be preset using a toolchain file (see below) -and on the commandline. - - -FLTK_FLUID_EXECUTABLE - default = fltk::fluid (see exceptions below) - - This represents the `fluid` executable or CMake target that is used - to "compile" fluid `.fl` files to source (.cxx) and header (.h) files. - - The default `fltk::fluid` is used when `fluid` is built and not - cross-compiled, i.e. the fluid executable that is built can be used. - On Windows and macOS `fltk::fluid-cmd` (the console program) is used - instead. - - When cross-compiling this variable should be a compatible `fluid` - executable on the build host. For details see chapter 2.9. - -FLTK_FLUID_HOST - default = fluid executable on the build host - - This variable is used if `fluid` is not built (FLTK_BUILD_FLUID=OFF) - or if cross-compiling. It can be preset by the CMake commandline to - point the build at a compatible `fluid` executable. - -FLUID_PATH - obsolete (FLTK 1.3.x): predecessor of FLTK_FLUID_HOST - - This variable can safely be deleted from the CMake cache if it exists. - - - 2.3 Building FLTK with CMake (all Platforms) ------------------------------------------------ - -CMake is used to generate a build system that will subsequently be used -to build and install the FLTK library and test and demo applications. - -Note that "installing" FLTK is optional: you can skip this step if you -like to build your own applications directly from the FLTK build tree. -This has advantages if you are building FLTK with different options or -are developing FLTK (changing sources) or if you pull new FLTK versions -from git frequently. - -The following generic commands may need some changes on Windows where -you may not have an adequate (POSIX) shell (command window). - -(1) Generate the build system in the FLTK root directory: - - cmake -B build [ -G "Generator" -D "Options" … ] - - This command creates the 'build' subdirectory if it does not exist yet - and generates the build (project) files in the 'build' directory. - See above for usable options. - - Note: Although this 'build' directory is part of the source tree it - is considered an out-of-source build because CMake does not create - any files in source directories. You can also use CMake to build FLTK - in an arbitrary build folder elsewhere on the system: - - cmake -B /path/to/my-fltk-build [ -G "Generator" -D "Options" … ] - - Commandline elements in […] are optional. - - Use `cmake --help` to find out which generators are available on your - platform. The default generator is marked with '*'. - -(2) Build FLTK with the generated build system: - - No matter which generator you selected in (1), the following CMake - command can always be used to build the library: - - cmake --build build - - This uses the previously generated build system in the 'build' folder. - This works even with Visual Studio where the build will be executed - without opening the Visual Studio GUI, similar to NMake. - - Instead of using the above command you can also `cd build` and run - the native build command, for instance `make -j7` or `ninja`, or - you can open the IDE project (Xcode, Visual Studio, ...). - -(3) Install FLTK (optional): - - cmake --install build - - This command installs the previously built library and headers in the - installation folder. On Unix/Linux/macOS systems this requires root - privileges if the target is a system directory. - -The following chapters describe some special cases in more detail. Skip -chapters you don't need... - - - 2.4 Building under Linux with Unix Makefiles ------------------------------------------------ - -After unpacking the FLTK source, go to the root of the FLTK tree and type -the following. - - cmake -B build -G "Unix Makefiles" [options] - cd build - make [ -j 3 ] - sudo make install (optional) - -This will build and optionally install a default configuration FLTK. - -Some flags can be changed during the 'make' command, such as: - - make VERBOSE=on - -which builds in verbose mode, so you can see all the compile/link commands. - -Hint: if you intend to build several different versions of FLTK, e.g. -a Debug and a Release version, or multiple libraries with different ABI -versions or options, or cross-compile for another platform we recommend -to use subdirectories in the build folder, like this: - - mkdir build - cd build - mkdir debug - cd debug - cmake -D 'CMAKE_BUILD_TYPE=Debug' ../.. - make - sudo make install (optional) - - - 2.5 Building under Windows with Visual Studio and/or NMake -------------------------------------------------------------- - -Building with CMake under Visual Studio may require to specify the CMake -generator with the -G"Visual Studio ..." command line switch, or the -generator can be selected interactively in the GUI (cmake-gui). If you -are not sure which one to select use `cmake --help` which lists all -generators known to CMake on your system. - - - 2.5.1 Building under Windows with Visual Studio -------------------------------------------------- - -CMake often finds an installed Visual Studio generator and uses it w/o -using the commandline switch, particularly if you are using a special -"Visual Studio Command Prompt": - - - Hit the "Windows" key - - - Type "developer command ..." - ... until you see something like "Developer Command Prompt for VS xxxx" - (replace 'xxxx' with your installed Visual Studio version) - - - Activate the "app" to execute the command prompt (like an old "DOS" shell) - - - Inside this command prompt window, run your installed `cmake` (command - line) or `cmake-gui` (GUI) program. You may need to specify the full path - to this program. - - If you use `cmake-gui` you can select the source and the build folders in - the GUI, otherwise change directory to where you downloaded and installed - the FLTK sources and execute: - - `cmake` -G "Visual Studio xxx..." -B build - cd build - - This creates the Visual Studio project files (FLTK.sln and more) in the - 'build' directory. - - Open Visual Studio, choose File -> Open -> Project, and pick the "FLTK.sln" - created in the previous step. - - (Or, if only one version of the Visual Studio compiler is installed, - you can just run from DOS: .\FLTK.sln) - - Make sure the pulldown menu has either "Release" or "Debug" selected - in the "Solution Configurations" pulldown menu. - - In the "Solution Explorer", right click on: - - Solution 'FLTK' (## projects) - - ... and in the popup menu, choose "Build Solution" - - or choose 'Build/Build Solution' or 'Build/Rebuild Solution' from the - menu at the top of the window. - - That's it, that should build FLTK. - - The test programs (*.exe) can be found relative to the 'build' folder in - - build\bin\test\Release\*.exe - build\bin\test\Debug\*.exe - - ... and the FLTK include files (*.H & *.h) your own apps can - compile with can be found in: - - build\FL - - *and* [1] in the source folder where you downloaded FLTK, e.g. in - - C:\fltk-1.4.x\FL - - ... and the FLTK library files (*.lib) which your own apps can - link with can be found in: - - Release: build\lib\Release\*.lib - Debug: build\lib\Debug\*.lib - - [1] If you want to build your own FLTK application directly using - the build directories (i.e. without "installation") you need - to include both the build tree (first) and then the FLTK source - tree in the compiler's header search list. - - - 2.5.2 Building under Windows with NMake ------------------------------------------ - - This example uses cmake to generate + build FLTK in Release mode using nmake, - using purely the command line (never need to open the Visual Studio IDE) - using the static Multithreaded runtime (/MT): - - mkdir build-nmake - cd build-nmake - cmake -G "NMake Makefiles" -D CMAKE_BUILD_TYPE=Release -D FLTK_MSVC_RUNTIME_DLL=off .. - nmake - - which results in a colorful percentage output crawl similar to what we see - with unix 'make'. - - Instead of running `nmake` directly you can also use cmake to build: - - cmake --build . - - - 2.6 Building under Windows with MinGW using Makefiles --------------------------------------------------------- - -Building with CMake under MinGW requires you to specify the CMake Generator -with the -G command line switch. Using - - cmake -G "Unix Makefiles" /path/to/fltk - -is recommended by the FLTK team if you have installed MinGW with the MSYS -environment. You can use the stock Windows CMake executables, but you must -run the CMake executables from within the MinGW environment so CMake can -use your MinGW PATH to find the compilers and build tools. Example: - - alias cmake='/c/CMake/bin/cmake' - alias cmake-gui='/c/CMake/bin/cmake-gui' - - mkdir build - cd build - cmake -G "Unix Makefiles" -D 'CMAKE_BUILD_TYPE=Debug' .. - -Note the path to FLTK ".." in the last command line. Depending on where you -installed CMake you may need to adjust the path's in the alias commands. - - - 2.7 Building under Windows WSL with Clang and Makefiles ----------------------------------------------------------- - -WSL, the Windows Subsystem for Linux allows developers to run a Linux -environment without the need for a separate virtual machine or dual booting. -WSL 2 runs inside a managed virtual machine that implements the full -Linux kernel. WSL requires Windows 11. - -FLTK apps generated using WSL are Linux compatible binaries. To run those -binaries on Windows, WSL comes with a limited built-in X11 server. Third -party X11 servers can be installed that better support all features of FLTK. - -1) Install WSL from PowerShell with admin privileges: - > wsl --install - -2) Reboot and open the Linux terminal. You will need to install the following - Linux packages to compile FLTK - > sudo apt update - > sudo apt install clang cmake freeglut3-dev - -3) Change to the directory containing the FLTK project. For example: - > cd ~/dev/fltk-1.4.x - -4) Use CMake to configure the build system - > cmake -B build - -5) Use CMake to build the demo app and all dependencies - > cmake --build build - -6) Run the demo app - > ./build/bin/test/demo - - -2.8 Building under macOS with Xcode -------------------------------------- - -Building with CMake under Xcode requires the CMake generator with -the -G command line switch. This step need to be done only once. If any -of the CMake related files are updated, Xcode will rerun CMake for you. - -1) Open the macOS Terminal - -2) Change to the directory containing the FLTK project. For example: - > cd ~/dev/fltk-1.4.x - -3) Create a build directory - > mkdir build - > cd build - -4) If you plan different build versions, it is useful to create another - subdirectory level - > mkdir Xcode - > cd Xcode - -5) Let CMake create the required IDE files - > cmake -G Xcode ../.. - This step should end in the message: - -- Build files have been written to: .../dev/fltk-1.4.x/build/Xcode - -5a) To build the Release version of FLTK, use - > cmake -G Xcode -D CMAKE_BUILD_TYPE=Release ../.. - -6) Launch Xcode from the Finder or from the Terminal: - > open ./FLTK.xcodeproj - When Xcode starts, it asks if it should "Autocreate Schemes". Click on - "Automatically Create Schemes" to confirm. - -7) To build and test FLTK, select the scheme "ALL_BUILD" and hit Cmd-B to - build. Then select the scheme "demo" and hit Cmd-R to run the FLTK Demo. - -8) The interactive user interface tool "Fluid" will be located in - build/Xcode/bin/Debug. The example apps are in .../bin/examples/Debug. - Static libraries are in .../lib/Debug/. - Replace 'Debug' with 'Release' for a Release build. - -9) The "install" Scheme may fail because it is run with user permissions. - You may want to configure the build to install in a folder below your - home directory. - - - 2.9 Crosscompiling ---------------------- - -Once you have a crosscompiler going, to use CMake to build FLTK you need -two more things. You need a toolchain file which tells CMake where your -build tools are. The CMake website is a good source of information on -this file. Here's one for MinGW (64-bit) under Linux. - ----- -# CMake Toolchain File for MinGW-w64 (64-bit) Cross Compilation - -# the name of the target operating system -set(CMAKE_SYSTEM_NAME Windows) - -# which tools to use -set(CMAKE_C_COMPILER /usr/bin/x86_64-w64-mingw32-gcc) -set(CMAKE_CXX_COMPILER /usr/bin/x86_64-w64-mingw32-g++) -set(CMAKE_RC_COMPILER /usr/bin/x86_64-w64-mingw32-windres) - -# here is where the target environment located -set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) - -# adjust the default behavior of the FIND_XXX() commands: - -# search programs in the host environment -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - -# search headers and libraries in the target environment -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -set(CMAKE_INSTALL_PREFIX ${CMAKE_FIND_ROOT_PATH}/usr CACHE FILEPATH - "install path prefix") - -# initialize required linker flags to build compatible Windows programs -set(CMAKE_EXE_LINKER_FLAGS_INIT "-static-libgcc -static-libstdc++") - -# end of toolchain file ----- - -Not too tough. The other thing you need is a native installation of FLTK -on your build platform. This is to supply the fluid executable which will -compile the *.fl into C++ source and header files. This is only needed if -the test/* and/or example/* demo programs are built. - -CMake finds the fluid executable on the build host automatically when -cross-compiling if it exists and is in the user's PATH. On systems that -provide multiple fluid versions (e.g. 1.3.x and 1.4.x) or if only an older -version is installed (e.g. 1.3.x) you can set the variable `FLTK_FLUID_HOST` -on the cmake commandline like - - cmake -B mingw -S . [ -G "Ninja" ] \ - -D CMAKE_BUILD_TYPE=Debug \ - -D CMAKE_TOOLCHAIN_FILE=<toolchain-file> \ - -D FLTK_FLUID_HOST=/path/to/fluid [.. more parameters ..] - -Note: replace '-G "Ninja" ' with the build tool of your choice or omit this -argument to use the default generator of your platform. - -Theoretically the variable FLTK_FLUID_HOST can also be set in a toolchain -file. This has been tested successfully but is not recommended because the -toolchain file should be independent of the project using it. - -After generating the build system (above), build and optionally install the -library: - - cmake --build mingw - [sudo] cmake --install mingw # optional - -This will create a default configuration FLTK suitable for mingw/msys and -install it in the /usr/x86_64-w64-mingw32/usr tree. - -Note: replace 'x86_64-w64-mingw32' with your cross toolchain location as -required. - - - 3. Using CMake with FLTK -=========================== - -The CMake Export/Import facility can be thought of as an automated -fltk-config. For example, if you link your program to the FLTK -library, it will automatically link in all of its dependencies. This -includes any special flags, i.e. on Linux it includes the -lpthread flag. - -This howto assumes that you have FLTK libraries which were built using CMake, -installed. Building them with CMake generates some CMake helper files which -are installed in standard locations, making FLTK easy to find and use. - -If FLTK is not installed in a standard system location where it is found -automatically, you may need to set a CMake variable to point CMake to the -right location. - -In the following examples we set the CMake cache variable 'FLTK_DIR' so -CMake knows where to find the FLTK configuration file 'FLTKConfig.cmake'. -It is important (recommended practice) to set this as a CMake cache variable -which enables the user executing 'cmake' to override this path either on the -commandline or interactively using the CMake GUI 'cmake-gui' or 'ccmake' on -Unix/Linux, for instance like this: - - $ cd my-project - $ mkdir build - $ cd build - $ cmake -G "Unix Makefiles" -S.. -D "FLTK_DIR=/home/me/fltk" - - - 3.1 Library Names --------------------- - -When you use the target_link_libraries() command, CMake uses its own internal -"target names" for libraries. The original fltk library names in the build -tree are: - - fltk fltk_forms fltk_images fltk_gl - -The bundled image and zlib libraries (if built): - - fltk_jpeg fltk_png fltk_z - -Append suffix "-shared" for shared libraries (Windows: DLL's). - -These library names are used to construct the filename on disk with system -specific prefixes and postfixes. For instance, on Linux/Unix 'fltk' is libfltk.a -and the shared library (fltk-shared) is libfltk.so.1.4.0 (in FLTK 1.4.0) with -additional system specific links. - -Note: since FLTK 1.5.0 the library fltk_cairo is no longer necessary and -must be removed from CMake files of user projects. fltk_cairo was an empty -library solely for backwards compatibility in FLTK 1.4 and has been removed -from FLTK 1.5. - - - 3.2 Library Aliases ----------------------- - -Since FLTK 1.4.0 "aliases" for all libraries in the FLTK build tree are -created in the namespace "fltk::". These aliases should always be used by -consumer projects (projects that use FLTK) for several reasons which are -beyond the scope of this README file. The following table shows the FLTK -libraries and their aliases in the FLTK build tree. - - Library Name Alias Shared Library Alias Notes - -------------------------------------------------------------- - fltk fltk::fltk fltk::fltk-shared [1] - fltk_forms fltk::forms fltk::forms-shared [2] - fltk_gl fltk::gl fltk::gl-shared [2] - fltk_images fltk::images fltk::images-shared [2] - fltk_jpeg fltk::jpeg fltk::jpeg-shared [3] - fltk_png fltk::png fltk::png-shared [3] - fltk_z fltk::z fltk::z-shared [3] - - [1] The basic FLTK library. Use this if you don't need any of the other - libraries for your application. - [2] Use one or more of these libraries if you have specific needs, - e.g. if you need to read images (fltk::images), OpenGL (fltk::gl), - or (X)Forms compatibility (fltk::forms). If you use one of these - libraries in your CMakeLists.txt then fltk::fltk will be included - automatically. - [3] The bundled libraries are only built if requested and are usually - not needed in user projects. They are linked in with fltk::images - automatically if they were built together with FLTK. - The only reason you may need them would be if you used libpng, - libjpeg, or zlib functions directly in your application and need - to use the bundled FLTK libs (e.g. on Windows). - - - 3.3 Exported and Imported Targets ------------------------------------- - -CMake terminology is to "export" and "import" library "targets". FLTK's -CMake files export targets and its CONFIG module FLTKConfig.cmake imports -targets so user projects can use them. Hence, if you use CMake's CONFIG -mode to find FLTK all library targets will be defined using the namespace -convention listed above in the "Alias" column. This is what user projects -are recommended to use. - -In addition to the library targets FLTK defines the "imported target" -'fltk::fluid' which can be used to generate source (.cxx) and header (.h) -files from fluid (.fl) files. - -Another target fltk::fltk-config can be used to set (e.g.) system or user -specific FLTK options. This would usually be executed in the installation -process of a user project but should rarely be needed and is beyound the -scope of this documentation. - - - 3.4 Building a Simple "Hello World" Program with FLTK --------------------------------------------------------- - -Here is a basic CMakeLists.txt file using FLTK. It is important that -this file can only be used as simple as it is if you use find_package() -in `CONFIG` mode as shown below. This requires that the FLTK library -itself has been built with CMake. - ---- -cmake_minimum_required(VERSION 3.15) - -project(hello) - -# optional (see below): -set(FLTK_DIR "/path/to/fltk" - CACHE FILEPATH "FLTK installation or build directory") - -find_package(FLTK 1.4 CONFIG REQUIRED) - -add_executable (hello WIN32 MACOSX_BUNDLE hello.cxx) -target_link_libraries(hello PRIVATE fltk::fltk) ---- - -We recommend to use `cmake_minimum_required(VERSION 3.15)` or higher for -building projects that use FLTK. Lower CMake versions may work for user -projects but this is not tested by FLTK developers. - -The optional `set(FLTK_DIR ...)` command is a superhint to the find_package -command. This is useful if you don't install FLTK or have a non-standard -install location. The path you give to it must be that of a directory that -contains the file FLTKConfig.cmake. - -You can omit this statement if CMake finds the required FLTK version -without it. This variable is stored in the CMake Cache so users can change -it with the ususal CMake GUI interfaces (ccmake, cmake-gui) or on the -CMake commandline (-D FLTK_DIR=...). - -The find_package command tells CMake to find the package FLTK, '1.4' says -that we want FLTK 1.4.x: any patch version of 1.4 will match. 'REQUIRED' -means that it is an error if it's not found. 'CONFIG' tells it to search -only for the FLTKConfig.cmake file, not using the FindFLTK.cmake "module" -supplied with CMake, which doesn't work with this version of FLTK. Since -we specify a version (1.4) the file 'FLTKConfigVersion.cmake' must also -be found. This file is created since FLTK 1.3.10. - -"WIN32 MACOSX_BUNDLE" in the add_executable() command tells CMake that -this is a GUI app. It is ignored on other platforms than Windows or macOS, -respectively, and should always be present with FLTK GUI programs for -better portability - unless you explicitly need to build a "console program" -on Windows. - -Once the package is found (in CONFIG mode, as described above) all built -FLTK libraries are "imported" as CMake "targets" or aliases and can be used -directly. These CMake library targets contain all necessary informations to -be used without having to know about additional include directories or -other library dependencies. This is what is called "Modern CMake". - -Older FLTK versions required to use the variables FLTK_INCLUDE_DIRS and -FLTK_LIBRARIES (among others). These variables and related commands are -no longer necessary if your project (CMakeLists.txt) uses CMake's -CONFIG mode as described in this file. - -The target_link_libraries() command is used to specify all necessary FLTK -libraries. Thus you may use fltk::fltk, fltk::images, fltk::gl, fltk::forms, -or any combination. fltk::fltk is linked automatically if any of the other -libs is included. - - - 3.5 Building a Program Using Fluid Files -------------------------------------------- - -CMake has a command named fltk_wrap_ui which helps deal with fluid *.fl -files. Unfortunately it is broken in CMake 3.4.x but it seems to work in -3.5 and later CMake versions. We recommend to use add_custom_command() -to achieve the same result in a more explicit and well-defined way. -This is a more basic approach and should work for all CMake versions. -It is described below. - -Here is a sample CMakeLists.txt which compiles the CubeView example from -a directory you've copied the test/Cube* files to. - ---- -cmake_minimum_required(VERSION 3.15) - -project(CubeView) - -# change this to your fltk build directory -set(FLTK_DIR "/path/to/fltk" - CACHE FILEPATH "FLTK installation or build directory") - -find_package(FLTK 1.4 CONFIG REQUIRED) - -# run fluid -c to generate CubeViewUI.cxx and CubeViewUI.h files -add_custom_command( - OUTPUT "CubeViewUI.cxx" "CubeViewUI.h" - COMMAND fltk::fluid -c ${CMAKE_CURRENT_SOURCE_DIR}/CubeViewUI.fl -) - -add_executable(CubeView WIN32 MACOSX_BUNDLE - CubeMain.cxx CubeView.cxx CubeViewUI.cxx) - -target_include_directories(CubeView PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_include_directories(CubeView PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - -target_link_libraries (CubeView PRIVATE fltk::gl) ---- - -You can repeat the add_custom_command for each fluid file or if you -have a large number of them see the fltk_run_fluid() function in -CMake/FLTK-Functions.cmake for an example of how to run it in a loop. - -The two lines - - target_include_directories(CubeView PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - target_include_directories(CubeView PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - -add the current build ("binary") and source directories as include directories. -This is necessary for the compiler to find the local header files since the -fluid-generated files (CubeViewUI.cxx and CubeViewUI.h) are created in the -current build directory and other header files may be in the source directory -(depending on your project). - - - 3.6 Building a Program Using CMake's FetchContent Module ------------------------------------------------------------ - -FLTK can be downloaded and built within a user project using CMake's -FetchContent module. A sample CMakeLists.txt file follows. - -You may need to adjust it to your configuration. - ---- -cmake_minimum_required(VERSION 3.15) -project(hello) - -include(FetchContent) - -FetchContent_Declare(FLTK - GIT_REPOSITORY https://github.com/fltk/fltk - GIT_TAG master - GIT_SHALLOW TRUE -) - -message(STATUS "Download and build FLTK if necessary, please wait...") -FetchContent_MakeAvailable(FLTK) -message(STATUS "Download and build FLTK - done.") - -add_executable (hello WIN32 MACOSX_BUNDLE hello.cxx) -target_link_libraries(hello PRIVATE fltk::fltk) ---- - -This is as simple as it can be. The CMake FetchContent module is used to -download the FLTK sources from their Git repository and to build them. -Note that this will download and build the FLTK library during the CMake -configure phase which can take some time. Therefore the statement -`FetchContent_MakeAvailable()` is wrapped in `message(STATUS "...")` -commands to let the user know what's going on. - - - 4 FindFLTK.cmake and find_package(FLTK) -========================================== - -The FindFLTK.cmake module provided by CMake which is also used in the -CMake command find_package(FLTK) does not yet support FLTK's new "Modern -CMake" features. - -Unfortunately this module has to be used if the FLTK library wasn't built -with CMake and thus CONFIG mode can't be used. In this case CMake falls back -to MODULE mode and find_package() uses this old CMake module. - -There are plans to provide a FindFLTK.cmake module with a later FLTK release. -Look here for further info if you need it... diff --git a/README.CPack.txt b/README.CPack.txt deleted file mode 100644 index e9f11dd85..000000000 --- a/README.CPack.txt +++ /dev/null @@ -1,83 +0,0 @@ -README.CPack.txt - Building Binary Packages with CPack -------------------------------------------------------- - -Intended Audience ------------------ - -"Packagers" (maintainers) of Linux distributions or users who want to -deploy FLTK binary packages on multiple systems, e.g. companies using -FLTK for their software development. - - -Introduction ------------- - -In previous FLTK versions binary packages could be created using EPM -(an external tool) or `rpmbuild` on Linux. Both tools used files no -longer provided by FLTK: 'fltk.list' (EPM) and 'fltk.spec' (RPM). - -FLTK 1.5 and later supports CPack to create binary "packages". The new -approach using CPack is more flexible and supports many more package -formats. CPack is usually installed together with CMake. - -CPack support is still experimental and may be improved in the future. -The documentation below may be enhanced later if required. - - -How To Build Binary Packages ----------------------------- - -On some platforms and with some "generators" CMake creates the target -'package' so you can execute e.g. `make package` after building FLTK. -This creates the default set of packages for the given platform. - -On other platforms, or to use more flexible options, `cpack` may be run -from the commandline after building FLTK to generate a particular package -format. For details please refer to the CMake and CPack documentation. - - -Example Commands On Linux Using Ninja -------------------------------------- - -1. Build the FLTK library: - -$ cd /path-to-fltk -$ cmake -G Ninja -D CMAKE_BUILD_TYPE=Release -B build -$ cmake --build build - -2. Create one or more binary packages: - -$ cmake --build build --target package - -... or ... - -$ cd build -$ ninja package # or `make package` if you're using Makefiles - -... or to build (only) the RPM package: - -$ cpack -G RPM - -... or to build a .tar.gz package: - -$ cpack -G TGZ - -See `cpack --help` for possible package formats ("Generators"). - -Note: you need to install the package format specific tools on your system -to create some package formats, e.g. `rpmbuild` for RPM packages. - - -Further Reading ---------------- - -More information on this topic can be found in the CMake and CPack -documentation or by executing `cpack --help`. - - -Links: To Documentation ------------------------ - -https://cmake.org/cmake/help/latest/index.html -https://cmake.org/cmake/help/latest/manual/cmake.1.html -https://cmake.org/cmake/help/latest/manual/cpack.1.html diff --git a/README.Wayland.txt b/README.Wayland.txt deleted file mode 100644 index 87d5164ce..000000000 --- a/README.Wayland.txt +++ /dev/null @@ -1,246 +0,0 @@ -README.Wayland.txt - Wayland Platform Support for FLTK ------------------------------------------------------- - - -Contents -======== - - 1 Introduction - - 2 Wayland Support for FLTK - 2.1 Disabling Wayland for Backwards Compatibility - 2.2 Configuration - 2.3 Known Limitations - - 3 Platform Specific Notes - 3.1 Debian and Derivatives (like Ubuntu, Mint, RaspberryPiOS) - 3.2 Fedora - 3.3 FreeBSD - - -1 Introduction -============== - -Version 1.4 of the FLTK library introduces support of the public FLTK API on -the Wayland platform. It requires a Wayland-equipped OS, namely Linux or FreeBSD. -Pre-existing platform-independent source code for FLTK 1.3.x should build and -run unchanged with FLTK 1.4 and the Wayland platform. -The code has been tested on Debian, Ubuntu, RaspberryPiOS and Fedora with -3 distinct Wayland compositors: Mutter (Gnome's compositor), Weston, and KWin. -The code has also been tested under FreeBSD and the Sway Wayland compositor. -CJK text-input methods, as well as dead and compose keys are supported. - - -2 Wayland Support for FLTK -========================== - -On Linux and FreeBSD systems, the FLTK library is by default configured so FLTK -apps do all their windowing through the Wayland protocol, all their graphics -with Cairo or EGL, and all text-drawing with Pango. If no Wayland compositor -is available at run-time, FLTK apps fall back to using X11 for windowing. -Cairo and Pango remain used for graphics and text, respectively. - -Environment variable FLTK_BACKEND can be used to control whether Wayland or -X11 is used at run time as follows: -- if FLTK_BACKEND is not defined, Wayland is used when possible, otherwise - X11 is used; -- if $FLTK_BACKEND equals "wayland", the library stops with error if no - Wayland compositor is available; -- if $FLTK_BACKEND equals "x11", the library uses X11 even if a Wayland - compositor is available; -- if $FLTK_BACKEND has another value, the library stops with error. - -On pure Wayland systems without the X11 headers and libraries, FLTK can be built -with its Wayland backend only (see below). - - - 2.1 Disabling Wayland for Backwards Compatibility ---------------------------------------------------- - -Programs using X11 specific functions may need to disable the automatic -detection of Wayland at runtime so they fall back to X11 only. - -It is possible to force a program linked to a Wayland-enabled FLTK library -to use X11 in all situations by putting this declaration somewhere in the -source code: - - FL_EXPORT bool fl_disable_wayland = true; - -FLTK source code and also X11-specific source code conceived for FLTK 1.3 -should run with a Wayland-enabled FLTK 1.4 library with this single change. - - -Note 1: this may require some linker flags to enable exporting symbols -from *executable* programs which FLTK uses to "read" the global symbol -'fl_disable_wayland'. For GNU `ld` or any GNU compiler this would -be "-rdynamic". - - -Note 2: When building a user project with CMake 3.4 or higher, i.e. using - - cmake_minimum_required (VERSION 3.4) - -or any higher (minimum) CMake version users need to use at least one of -the following techniques: - -Option 1: Set target property 'ENABLE_EXPORTS' on all executable - targets that require to disable the Wayland backend. - This is the preferred solution because it works per target. - - CMake example: - - set_target_properties(myprog PROPERTIES ENABLE_EXPORTS TRUE) - -Option 2: Set CMake policy CMP0065 to 'OLD' (i.e. pre-3.4 behavior). - This is a quick solution but discouraged because setting - CMake policies to 'OLD' is "deprecated by definition". - CMake may issue warnings or ignore this in the future. - - CMake code: - - cmake_policy(SET CMP0065 OLD) - -Option 3: Set CMake variable 'CMAKE_ENABLE_EXPORTS' to 'TRUE'. - Note: use this to be compatible with CMake < 3.27. - -Option 4: Set CMake variable 'CMAKE_EXECUTABLE_ENABLE_EXPORTS' to 'TRUE'. - Note: new in CMake 3.27, ignored in older versions. - -Options 3 and 4 can be used as quick solutions like option 2 but these -options affect all targets that are created while the CMake variable is -set. As said above, option 1 should be preferred. - -This applies to the FLTK test and demo programs as well, hence we use -option 1 in our build system. - - - 2.2 Configuration ------------------- - -On Linux and FreeBSD systems equipped with the adequate software packages -(see section 3 below), the default building procedure produces a Wayland/X11 -hybrid library. On systems lacking all or part of Wayland-required packages, -the default building procedure produces a X11-based library. - -Use "-D FLTK_BACKEND_WAYLAND=OFF" with CMake to build FLTK for the X11 -library when the default would build for Wayland. - -CMake option FLTK_BACKEND_X11=OFF can be used to produce a Wayland-only -library which can be useful, e.g., when cross-compiling for systems that -lack X11 headers and libraries. - -The FLTK Wayland platform uses a library called libdecor which handles window decorations -(i.e., titlebars, shade). On very recent Linux distributions (e.g., Debian trixie) -libdecor is available as Linux packages (libdecor-0-dev and libdecor-0-plugin-1-gtk). -FLTK requires version 0.2.0 or more recent of these packages. -When libdecor is not available or not recent enough, FLTK uses a copy of libdecor -bundled in the FLTK source code. -FLTK equipped with libdecor supports both the client-side decoration mode (CSD) and the -server-side decoration mode (SSD) as determined by the active Wayland compositor. -Mutter (gnome's Wayland compositor) and Weston use CSD mode, KWin and Sway use SSD mode. -Furthermore, setting environment variable LIBDECOR_FORCE_CSD to 1 will make FLTK use CSD -mode even if the compositor would have selected SSD mode. - - 2.3 Known Limitations ----------------------- - -* A deliberate design trait of Wayland makes application windows ignorant of their exact -placement on screen. It's possible, though, to position a popup window relatively to -another window. This allows FLTK to properly position menu and tooltip windows. But -Fl_Window::position() has no effect on other top-level windows. - -* With Wayland, there is no way to know if a window is currently minimized, nor is there any -way to programmatically unset minimization of a window. Consequently, Fl_Window::show() of -a minimized window has no effect. - -* Although the FLTK API to read from and write to the system clipboard is fully functional, -it's currently not possible for an app to be notified of changes to the content of -the system clipboard, that is, Fl::add_clipboard_notify() has no effect. - -* Copying data to the clipboard is best done when the app has focus. Any copy operation -performed when the app did not get the focus yet does not change the clipboard. A copy -operation performed when the app has lost the focus is successful only if the type of -the copied data, that is, text or image, is the same as the last data type copied when -the app had the focus. - -* Narrow windows with a titlebar are silently forced to be wide enough -for the titlebar to display window buttons and a few letters of the title. - -* Text input methods are known to work well for Chinese and Japanese. -Feedback for other writing systems would be helpful. - -* Using OpenGL inside Wayland windows doesn't seem to work on RaspberryPi hardware, -although it works inside X11 windows on the same hardware. - -* Drag-and-drop initiation from a subwindow doesn't work under the KDE/Plasma desktop. -That is most probably a KWin bug because no such problem occurs with 3 other -Wayland compositors (Mutter, Weston, Sway). A workaround is proposed in issue #997 -of the FLTK github repository (https://github.com/fltk/fltk/issues/997). - -3 Platform Specific Notes -========================= - -The following are notes about building FLTK for the Wayland platform -on the various supported Linux distributions/OS. - -3.1 Debian and Derivatives (like Ubuntu, Mint, RaspberryPiOS) -------------------------------------------------------------- - -Under Debian, the Wayland platform requires version 11 (a.k.a. Bullseye) or more recent. -Under Ubuntu, the Wayland platform requires version 20.04 (focal fossa) or more recent. - -These packages are necessary to build the FLTK library, in addition to those listed -in section 2.1 of file README.Unix.txt : - - sudo apt-get install libpango1.0-dev - sudo apt-get install libwayland-dev - sudo apt-get install wayland-protocols - sudo apt-get install libxkbcommon-dev - sudo apt-get install libxinerama-dev # except if option FLTK_BACKEND_X11=off is used - sudo apt-get install libdbus-1-dev # recommended to query current cursor theme - sudo apt-get install libglew-dev # necessary to use OpenGL version 3 or above - sudo apt-get install libdecor-0-dev # recommended if available and if in version ≥ 0.2.0 - sudo apt-get install libgtk-3-dev # highly recommended if libdecor-0-dev is not installed - -These packages allow to run FLTK apps under the Gnome-Wayland desktop: - - sudo apt-get install gnome-core - sudo apt-get install libdecor-0-plugin-1-gtk # install if libdecor-0-dev is installed - -These packages allow to run FLTK apps under the KDE/Plasma-Wayland desktop: - - sudo apt-get install kde-plasma-desktop - - -3.2 Fedora ----------- - -The Wayland platform is known to work with Fedora version 35 or more recent. - -These packages are necessary to build the FLTK library, in addition to -package groups listed in section 2.2 of file README.Unix.txt : - - sudo yum install wayland-devel - sudo yum install wayland-protocols-devel - sudo yum install cairo-devel - sudo yum install libxkbcommon-devel - sudo yum install pango-devel - sudo yum install mesa-libGLU-devel - sudo yum install dbus-devel # recommended to query current cursor theme - sudo yum install libdecor-devel # recommended, draws window titlebars - sudo yum install gtk3-devel # highly recommended if libdecor-devel is not installed - sudo yum install glew-devel # necessary to use OpenGL version 3 or above - -Package installation command: sudo yum install <package-name ...> - - -3.3 FreeBSD ------------ - -The Wayland platform is known to work with FreeBSD version 13.1 and the Sway compositor. - -These packages are necessary to build the FLTK library and use the Sway compositor: - - git autoconf pkgconf xorg urwfonts gnome glew seatd sway dmenu-wayland dmenu evdev-proto - -Package installation command: sudo pkg install <package-name ...> diff --git a/README.Windows.txt b/README.Windows.txt deleted file mode 100644 index 2c35e85ab..000000000 --- a/README.Windows.txt +++ /dev/null @@ -1,604 +0,0 @@ - README.Windows.txt - Building FLTK under Microsoft Windows ------------------------------------------------------------- - - -–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– -*** CAUTION: This file is outdated. This needs a major rework! *** -–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– - - - - CONTENTS -========== - - 1 INTRODUCTION - - 2 HOW TO BUILD FLTK USING MinGW AND Cygwin - - 2.1 The Tools - 2.2 Recommended Command Line Build Environment - 2.3 Prerequisites - 2.4 Downloading and Unpacking - 2.5 Configuring FLTK - 2.6 Building FLTK - 2.7 Testing FLTK - 2.8 Installing FLTK - 2.9 Creating new Projects - - 3 HOW TO BUILD FLTK USING MICROSOFT VISUAL STUDIO - - 3.1 Prerequisites - 3.2 Downloading and Unpacking - 3.3 Configuring FLTK - 3.4 Building FLTK - 3.5 Testing FLTK - 3.6 Installing FLTK - 3.7 Creating new Projects - - 4 FREQUENTLY ASKED QUESTIONS - - 5 LINKS - - 6 DOCUMENT HISTORY - - - 1 INTRODUCTION -================== - -FLTK 1.3 and later is officially supported on Windows (2000,) 2003, -XP, and later. Older Windows versions are not officially supported, -but may still work. The main reason is that the OS version needs -to support UTF-8. FLTK 1.3 is known to work on Windows Vista, Windows 7, -Windows 8/8.1, Windows 10, and Windows 11. - -FLTK 1.4 and later versions may require Windows 10 or later. - -FLTK currently supports the following development -environments on the Windows platform: - - - Free Microsoft "Visual C++ 2008 Express" or later or "Visual Studio - Community 2013" or later. The Visual Studio project files must be - generated using CMake. Visual Studio 2017 includes CMake support: - - "Visual Studio 2017 introduces built-in support for handling CMake - projects. This makes it a lot simpler to develop C++ projects built - with CMake without the need to generate VS projects and solutions - from the command line. This post gives you an overview of the CMake - support, how to easily get started and stay productive in Visual Studio." - - Citation from: - https://devblogs.microsoft.com/cppblog/cmake-support-in-visual-studio/ - - As of this writing (07/2017) the FLTK team did not yet test and - verify the functionality of Microsoft's included CMake features. - - - GNU toolsets (Cygwin or MinGW) hosted on Windows. - -CAUTION: Libraries built by any one of these environments can not be mixed -with object files from any other environment! - - - 2 HOW TO BUILD FLTK USING MinGW AND Cygwin -============================================== - -This chapter of this document gives a brief overview of -compiling and using FLTK with the Cygwin and MinGW compiler -toolkits. Both toolkits provide a build environment based -around the GNU C/C++ compiler. Further information is -available from the FLTK website at https://www.fltk.org, such -as this Howto note: https://www.fltk.org/articles.php?L598 - -The Cygwin build environment supplies a library (the Cygwin -DLL) that is primarily intended to provide a number of -Unix-like POSIX facilities for programs being ported to the -Windows environment (Win32 or WinNT). Cygwin also supplies -a very Unix-like build environment for Windows, including -the "BASH" Bourne-compatible shell and all of the standard -Unix file utilities (ls, cat, grep, etc.). - -Cygwin is developed by Cygnus (now part of RedHat, Inc). -Although provided for free download under the GPL, distributing -programs that require the Cygwin DLL under a license other than -the GPL requires a commercial license for the Cygwin DLL. - -Native Windows programs that do not require the Cygwin DLL -(cross-compiled and linked with the MinGW gcc/g++ cross compilers -supplied with Cygwin) may be released under any license freely. - -Currently you would have to install mingw64-i686-gcc-g++ for -32-bit Windows applications (despite its name!), and/or -mingw64-x86_64-gcc-g++ for 64-bit applications. You may also -need to install the corresponding '-headers' packages as well. - -Currently these tools support gcc 4.5 or newer. The setup for -FLTK is somewhat more complicated because you must configure -this as a cross compiler, but it works well. - -The MinGW distribution (Minimalist GNU for Windows) provides -a similar toolset but geared solely towards native Windows -development without the Unix-like POSIX library. The lack of -any libraries under the GPL or any other restrictive license -means that programs built with the MinGW environment may -always be released under any license freely. MinGW also -supplies a Unix-like build environment for Windows, -including MSYS (a Bourne-compatible shell) and the standard -Unix file utilities (ls, cat, grep, etc.) - -If you are not familiar with these GNU-like toolkits please -refer to the links section later in this note. In particular, -check out their license conditions carefully before use. - - - The Tools ------------ - -There are currently four main configurations supported by -FLTK with the GNU tools: - - 1. Cygwin: Built using the Cygwin toolset and using the Unix-like - POSIX compatibility layer provided by the Cygwin DLL. - License: GPL or non-free commercial license (ask Redhat). - Note: no longer tested by the FLTK team. - - 2. Cygwin using the MinGW cross compiler suite: Built using - the Cygwin tools but not using the Cygwin DLL. - License: freely distributable on all Windows systems. - Note: no longer tested by the FLTK team. - - 3. MinGW: Built using the MinGW utilities, compiler and tools. This - is, in many aspects, analogous to (2.). This is the recommended - one if you want to build native Windows programs only. - License: freely distributable on all Windows systems. - - 4. MSYS2/Mingw-w64: Built using the MSYS2 utilities, compiler and tools. - This similar to (3.) but may need some fiddling with the setup if - you want to build native Windows programs only because the built - executables *may* depend on some MSYS2 dll's. - License: freely distributable on all Windows systems. - - - Recommended Command Line Build Environment --------------------------------------------- - -Our recommendation is to: - - 1. Get the current Cygwin toolset. - - This can either produce executables that do or do not - rely on the Cygwin DLL (check licensing) at your choice. - - 2. Get the latest MinGW toolset. It is recommended that you - also get the MSYS shell and the msysDTK developer toolset. - - This will only produce normal Windows native executables - without any Unix or POSIX compatibility layer. - - 3. Get the latest MSYS2/Mingw-w64 toolset. - - See the links section below for more information. - -Either option can generate Windows native executables and option 1 can -provide a Unix-like POSIX portability layer that is reliant on a GPLed library. - -See the later sections for detailed information about using -one of these configurations. - - - Prerequisites ---------------- - -In order to build FLTK from the command line, you need to install the MinGW -environment. The graphical installer "mingw-get-inst" can be downloaded for -free. - - NOTE: as of Dec 07, 2024 MinGW development seems to be dormant or dead. - According to Wikipedia (https://en.wikipedia.org/wiki/MinGW) - "MinGW migrated to OSDN". See link section below. - -Launch the installer and follow the instructions. In the "Select Components" -dialog, add "C++ Compiler", "MSYS Basic System", and "MinGW Developer Toolkit". -Wait for the installer to finish. - -After downloading and installing, you need to launch the MinGW Shell through -the Start menu. - - - Downloading and Unpacking ---------------------------- - -Download FLTK from here: - - https://www.fltk.org/software.php - -into your home folder. The default location as seen from Windows is similar -to - - C:\MinGW\msys\1.0\home\matt\ - -If you are familiar with "git" and like to stay current with your -version, you will find the git access parameters at the bottom of -that page. Unpack FLTK into a convenient location. I like to have everything -in my dev directory: - - cd - mkdir dev - cd dev - tar xvzf fltk-1.x.y-source.tar.gz - cd fltk-1.x.y - - - Configuring FLTK ------------------- - -If you got FLTK via git then you need one extra step. Otherwise skip -over this part. Stay in your FLTK source-code directory and type the -following: - - autoconf - -Now configure your FLTK installation: - - ./configure - -Hint: Instead of executing `autoconf` and `configure` followed by `make` -to build FLTK (see next section) you can also run `make` directly which -will create and execute the 'configure' script with default parameters -and build FLTK with the default configuration. - -ADVANCED: type "./configure --help" to get a complete list of optional -configuration parameters. These should be pretty self-explanatory. Some -more details can be found in README. -:END_ADVANCED - -The configuration script will check your machine for the required resources -which should all have been part of your MinGW installation. Review the -Configuration Summary, maybe take some notes. - -ADVANCED: some versions of MinGW/Msys are broken and complain about a missing ---enable-auto-import. The solution is to upgrade to the current release. If -that is not possible, you can include the --enable-auto-import flag when -linking: - ./configure <config flags> LDFLAGS=-Wl,--enable-auto-import -:END_ADVANCED - - -Known Problems: - - There is a known incompatibility with some Windows git tools that - may not set the correct line endings for autoconf. If you get strange - error messages when running ./configure or make, you may need to convert - configh.in to "Unix line endings" (LF-only). These error messages are - unspecific, e.g. compilation errors like: - - error: 'U32' does not name a type - error: 'bmibuffer' was not declared in this scope - - You can fix the line endings with the MinGW/msys tool 'unix2dos' (u2d) - or with your favorite editor, if it allows to change the line endings, - then run autoconf and ./configure again. - - We don't know if this issue is still relevant with current Git tools. - It has been reported when we were still using Subversion (svn). - - For further information see this bug report (regarding svn) - - https://www.fltk.org/newsgroups.php?gfltk.bugs+v:10197 - - - Building FLTK ---------------- - -Now this is easy. Stay in your FLTK source-code directory and type: - - make - -The entire FLTK toolkit including many test programs will be built for you. -No warnings should appear. - - - Testing FLTK --------------- - -After a successful build, you can test FLTK's capabilities: - - test/demo - - - Installing FLTK ------------------ - -If you did not change any of the configuration settings, FLTK will be -installed in "/usr/local/include" and "/usr/local/lib" by typing - - make install - -It is possible to install FLTK in user space by changing the installation path -to a location within the user account by adding the "--prefix=PREFIX" parameter -to the "./configure" command. - - - Creating new Projects ------------------------ - -FLTK provides a neat script named "fltk-config" that can provide all the flags -needed to build FLTK applications using the same flags that were used to build -the library itself. Running "fltk-config" without arguments will print a list -of options. The easiest call to compile an FLTK application from a single -source file is: - - fltk-config --compile myProgram.cxx - -"fltk-config" and "fluid" will be installed in "/usr/local/bin/" by default. -We recommend that you add it to the command search path. - - - - 3 HOW TO BUILD FLTK USING MICROSOFT VISUAL STUDIO -===================================================== - - - Prerequisites ---------------- - -In order to build FLTK from within Visual Studio, you need to install the -Visual C++ developer environment from the Microsoft web site. The "Express" -or "Community" edition is free of charge and sufficient to develop FLTK -applications: - - https://visualstudio.microsoft.com/free-developer-offers/ - -If you intend to use an older (maybe commercial) version you need at least -a version that is supported by the version of CMake you are using to generate -the project files. You should make sure that all available service packs are -installed or building FLTK may fail. - -As of Juli 2017 the FLTK team recommend at least Visual Studio 2008 with -current service packs. Visual Studio 2008, 2010, 2013, 2015, and 2017 are -known to work with FLTK 1.4.0 (Git master, as of Juli 2017). - -For development of FLTK 1.4 or higher Visual Studio 2019 Community or later -versions are highly recommended. - -You may also need to install CMake (cmake-gui) from: - - https://cmake.org/download/ - -Visual Studio 2017 (and later) has internal CMake support (so you may not -need to install CMake separately). -There is an option to "open a folder" with a CMakeLists.txt file - in our -case the FLTK root folder. You may want to try this. - -Note that this has not yet been tested thoroughly by the FLTK team. - - - Downloading and Unpacking FLTK --------------------------------- - -Download FLTK from here: - - https://www.fltk.org/software.php - -If you are familiar with "git" and like to stay current with your version, -you will find the git access parameters at the bottom of that page. - -Unpack FLTK by using an appropriate unpacker and copy the new folder into a -convenient location, for instance a "dev" folder in your home folder. - - - Configuring FLTK ------------------- - -Note: Configuration with Visual Studio 2017's internal CMake support is -not yet included in this document. You may try yourself... - -Please refer to README.CMake.txt for how to configure FLTK with CMake. - -Once you have followed the instructions you should have created a new -build directory with the Visual Studio Solution (project files) for FLTK. - -Launch Visual Studio and open the project file (FLTK.sln) or double-click -on FLTK.sln in the Windows Explorer. - -Choose "Debug" or "Release" mode from the "Solution Configurations" menu. - - - Building FLTK ---------------- - -Use the context menu of the "demo" project to "Set as StartUp Project". Then -select "Build Solution" from the "Build" menu or press F7 to build all -libraries. - - - Testing FLTK --------------- - -Select "Start Debugging" from the "Debug" menu or just press F5 to run the -Demo program. Use "Demo" to explore all test programs. - - - Installing FLTK ------------------ - -******************************************************************************** - The information in this chapter is NO LONGER RECOMMENDED by the FLTK team. -******************************************************************************** - -The default location for VisualC 2008 libraries and headers is here: - - C:\Program Files\Microsoft Visual Studio 9.0\VC\ - -It is possible to move the FLTK libraries, headers, and Fluid into the -respective subdirectories, so that they are available for future development -without adding link and include paths to the solution. - - copy the entire FL directory into the include path - - add <build_dir>/FL/fl_config.h - - copy all .lib files from the fltk build directory to the VC lib directory - - copy fluid.exe in the fluid directory to the bin directory - -We highly discourage using dll's (dynamically linking libraries) on Windows -because they will require an installation process and likely cause version -conflicts. Use the static .lib libraries instead. - - - Creating new Projects ------------------------ - -******************************************************************************** - The information in this chapter is NO LONGER RECOMMENDED by the FLTK team. -******************************************************************************** - -This chapter assumes that libraries and headers were copied into - - C:\Program Files\Microsoft Visual Studio 9.0\VC\ - -Create a new project of type "General", "Empty Project" and add a simple "C++" -file to it. The FLTK "hello" source code is a good base. - -Now open the Project Properties dialog and add "Comctl32.lib" and all the FLTK -libraries that you want to use (at least "fltk.lib") to Additional Dependencies -(Configuration Properties > Linker > Additional Dependencies). - -Compile and run your test program with F5. - -You can also include .fl resources: add a new Header file to your project, but -let the name end in .fl. Right-click and select "Open with...". Add "fluid.exe" -from the "bin" directory and set it as the default editor. - -To automatically compile .fl files, open the Properties editor and set the -Custom Build Steps to: - - Command Line: fluid.exe -c $(InputPath) - Description: Compiling Fluid .fl file - Outputs: $(InputDir)$(InputName).cxx; $(InputDir)$(InputName).h - -Now add the generated .cxx file to your project as well. Whenever the .fl file -is changed, the corresponding .cxx file will be recompiled. - - - - 4 FREQUENTLY ASKED QUESTIONS -================================ - - - Why does a console window appear when I run my program? ---------------------------------------------------------- - -Windows has a flag that determines whether an application -runs in the foreground with a console or in the background -without a console. - -If you're using gcc (i.e. MinGW or Cygwin), then use the -linker option "-mwindows" to make your application run in -the background and "-mconsole" to run in the foreground. Use -fltk-config --ldflags to see appropriate linker flags, or use -fltk-config --compile to compile a single source file. - -If you're using MS VC++, then you must set the linker option -"/subsystem:windows" to create a "Windows" program (w/o console -window), or set the linker option "/subsystem:console" for a -console program, i.e. with a console window. These options -are set differently in the FLTK project files, depending on -whether you select a "Debug" or "Release" build. - -Other compilers and build systems may have different options. - -Keep in mind that a windows application cannot send output -to stdout, even if you run it from an existing console -application. -(Note: A special case of this exists if running a MinGW -application from the command line of an MSYS shell, when an -application is able to write to stdout, even if compiled with -"-mwindows". The same applies to Cygwin.) - - - How do I get OpenGL to work? ------------------------------- - -Both builds should automatically support OpenGL. - -The configuration file config.h has a number of settings -which control compile-time compilation. One such setting is -"HAVE_GL". This may be set to 0 to disable Open GL operation. -Changing the line in config.h to - - #define HAVE_GL 1 - -will change this to compile and link in OpenGL. - - - - 5 LINKS -=========== - -The following links may be of use: - - 1. Cygwin Homepage: - - https://www.cygwin.com/ - - - 2. MinGW Homepage - see Wikipedia: - - https://en.wikipedia.org/wiki/MinGW (English) - https://de.wikipedia.org/wiki/MinGW (German, see links) - - -------------------------------------------------------------------- - IMPORTANT: As of Dec 07, 2024 the links below could not be verified: - -------------------------------------------------------------------- - - Repository : https://osdn.net/projects/mingw/scm/ - Website (1): https://osdn.net/projects/mingw/ - Website (2): https://mingw.osdn.io/ - - - 3. MSYS2/Mingw-w64 Wikipedia and Homepage: - - https://en.wikipedia.org/wiki/Mingw-w64 - https://mingw-w64.org/ - https://www.msys2.org/ - - - 4. Check out the FLTK newsgroups at the FLTK homepage: - - https://www.fltk.org/ - - Its archival search facilities are EXTREMELY useful - to check back through previous problems with this - sort of configuration before posting new questions. - - - 5. GNU Compiler Collection (GCC) compiler homepage: - - https://gcc.gnu.org/ - - - 6. OpenGL page - for OpenGL and GLUT libs - - https://www.opengl.org/ - - - 7. CMake homepage: - - https://cmake.org/ - - - Note 1: all links in this document have been checked and verified - on Dec 07, 2024 except where noted above. - - Note 2: We can't guarantee that these links will be valid any time later. - - - 6 DOCUMENT HISTORY -====================== - - The document history is no longer maintained in this document. - Please consult the Git history instead. - Examples: - git log -- README.Windows.txt - git log -- README.MSWindows.txt (previous, renamed version) - gitk -- README.Windows.txt diff --git a/README.macOS.md b/README.macOS.md deleted file mode 100644 index 7619ed056..000000000 --- a/README.macOS.md +++ /dev/null @@ -1,345 +0,0 @@ -_README.macOS.md - Building FLTK under Apple macOS_ - - -<a name="contents"></a> -## Contents - -* [Contents](#contents) -* [Introduction](#introduction) - -* [How to Build FLTK using _CMake_ and _Xcode_](#build_cmake_xcode) - * [Prerequisites](#bcx_prerequisites) - * [Downloading FLTK and Unpacking](#bcx_download) - * [Configuring FLTK](#bcx_config) - * [Building FLTK](#bcx_build) - * [Testing FLTK](#bcx_test) - * [Installing FLTK](#bcx_install) - * [Creating new Projects](#bcx_new_projects) - -* [How to Build FLTK using _CMake_ and _make_](#build_cmake_make) - * [Prerequisites](#bcm_prerequisites) - * [Downloading FLTK and Unpacking](#bcm_download) - * [Configuring FLTK](#bcm_config) - * [Building FLTK](#bcm_build) - * [Testing FLTK](#bcm_test) - * [Installing FLTK](#bcm_install) - * [Creating new Projects](#bcm_new_projects) - -* [Make an Application Launchable by Dropping Files on its Icon](#dropstart) -* [Document History](#doc_history) - - -<a name="introduction"></a> -## Introduction - -FLTK supports macOS version 10.3 Panther and above. At the time of writing (Feb. 2022), -FLTK compiles and runs fine on the most recent macOS 12 Monterey for both Intel -processors and Apple Silicon. - -FLTK 1.5 supports the following build environments on the macOS -platform: - -* [_cmake_ and _Xcode_](#build_cmake_xcode), no shell needed -* [_cmake_ and _make_](#build_cmake_make) from the command line - -All environments will generate Unix style static libraries and macOS style app bundles. - - -<a name="build_cmake_xcode"></a> -## How to Build FLTK Using _CMake_ and _Xcode_ - -This option is best for users who like to develop their apps using Apple's Xcode IDE. There -is no need to ever use a command line shell in this configuration. - -This option requires an Apple ID and the Administrator password. - -<a name="bcx_prerequisites"></a> -### Prerequisites (CMake, Xcode) - -In order to build FLTK, you need to install _CMake_ and _Xcode_. - -_Xcode_ is Apple's IDE (Integrated Developer Environment) and can be downloaded via the -[App Store](https://itunes.apple.com/de/app/xcode/id497799835?l=en&mt=12). You will -need an Apple ID and administrator right for this. Installing _Xcode_ needs little to no -user input, but will likely take well over an hour. - -"CMake is used to control the software compilation process using simple platform and -compiler independent configuration files, and generate native makefiles and workspaces -that can be used in the compiler environment of your choice." - -Please download and install the macOS version of _CMake_ from -[www.cmake.org](https://cmake.org/download/). Download the .dmg file, click it, and when -the Finder window opens, drag the _CMake_ icon into the Applications folder. - -<a name="bcx_download"></a> -### Downloading FLTK and Unpacking (CMake, Xcode) - -FLTK 1.5 is currently (as of Mar 2025) available as a source code repository via GitHub. -You will need to clone the repository to check out the source code onto your machine. This -has the great benefit that the source code can be updated later simply by telling _git_ to -_pull_ the newest release. - -Weekly snapshots ("tarballs") can be downloaded from https://www.fltk.org/software.php . - -If you want to use _Xcode_ to clone the FLTK GitHub repository, you will have to give _Xcode_ -access to your GitHub Account in the _Xcode_ preferences. If you don't have a GitHub -account, or don't want to share your credentials with _Xcode_, you can use still the command -line `git clone https://github.com/fltk/fltk.git fltk-1.5` -to check out the repo. - -Start _Xcode_. Select `Source Control >> Clone...` in the main menu. - -A dialog box will open with a search field and a list of repositories. Enter `fltk/fltk` in -the search field. A list of matching repositories appears. The first one should be named `fltk` -and be owned by `fltk`. Select it and click _Clone_. - -A file chooser appears. Navigate to your home directory. Create a new folder named -`dev`. Enter `fltk-1.5` in the _Save As:_ field and click _Clone_, then _Done_ in the -previous dialog. - -The local copy of your repository can be updated by loading it into _Xcode_ and selecting -`Source Control >> Pull...` in the main menu. - -<a name="bcx_config"></a> -### Configuring FLTK (CMake, Xcode) - -Launch _CMake_ by pressing Command+Spacebar, then type _CMake_ and press return. -_CMake_ should open with a large dialog box. - -The first input field is labeled with _Where is the source code:_ . Click on _Browse Source..._ -and navigate to your home folder, then `dev`, then `fltk-1.5`. Click _Open_. - -The next input field is marked _Where to build the binaries:_. Click _Browse Build..._ -and navigate to your home folder, then `dev`, then `fltk-1.5`, then use _New Folder_ -to create a folder named `build`, and inside that, create a folder named `Xcode`. Click _Open_. - -The top two input fields should read -``` -/Users/your_name/dev/fltk-1.5 -``` -and -``` -/Users/your_name/dev/fltk-1.5/build/Xcode -``` - -Back in the _CMake_ main window, click _Configure_, select _Xcode_ as the generator and -click _Done_. _CMake_ will now analyze your system and find tools and dependencies. When -done, the upper list field in _CMake_ will show CMAKE and FLTK. Open the FLTK field and -adjust options if you like. Note that the bundled image libraries are built by default. -Further options are available under the CMAKE field. - -Finally, click _Generate_ to generate the _Xcode_ IDE file. - -You may be wondering why we chose this rather involved way of creating the IDE files instead -of just including the IDEs in the repo. Well, we did for the longest time, but creating new IDEs -for every possible platform is quite involved. IDE file formats change, platforms change, and -FLTK changes as well, and maintenance of the IDEs had become a nightmare. _CMake_ on the -other hand is very smart, knows about platforms and IDEs that we could never support manually, -and usually needs to be run only once. Even when updating the FLTK source code later, -_CMake_ will be smart enough to update the build files as well. - -<a name="bcx_build"></a> -### Building FLTK (CMake, Xcode) - -Now this is easy if all the previous steps were successful. If you are still in _CMake_, just click -_Open Project_ and _CMake_ will launch _XCode_ for you. If not, just launch _XCode_ and -open `Macintosh HD ▸ Users ▸ your_name ▸ dev ▸ fltk-1.5 ▸ build ▸ Xcode ▸ FLTK.xcodeproj`. - -_XCode_ may or may not ask to Autocreate Schemes. Click _Automatically Create Schemes_. - -In _Xcode_, set the 'active Scheme' to 'hello' or any other test program and press CMD+R -to compile and run that application. - -<a name="bcx_test"></a> -### Testing FLTK (CMake, Xcode) - -After a successful build, you can test FLTK's capabilities by choosing 'ALL_BUILD' as the -'active Scheme' and pressing CMD+B to build, then choosing 'demo' and pressing CMD+R to -run the demo program. - -Note: compiling 'demo' will not compile any of the other demo programs automatically. -This is intentional so you can build the test and demo programs incrementally. - -<a name="bcx_install"></a> -### Installing FLTK (CMake, Xcode) - -TODO: choosing the target 'INSTALL' will not work at this point because it requires root -permission. - -<a name="bcx_new_projects"></a> -### Creating new Projects (CMake, Xcode) - -See README.CMake.txt - -<a name="build_cmake_make"></a> -## How to Build FLTK Using _CMake_ and _make_ - -This option is best for users who like to develop their apps without using -Apple's Xcode IDE. Users should be comfortable with using `bash` or `tcsh` in -a terminal window. - -This option requires neither administrator rights, nor an Apple ID. - -<a name="bcm_prerequisites"></a> -### Prerequisites (CMake, make) - -In order to build FLTK, you need to install _CMake_ and the _Xcode_ command line tools. - -"CMake is used to control the software compilation process using simple platform and -compiler independent configuration files, and generate native makefiles and workspaces -that can be used in the compiler environment of your choice." - -Please download and install the macOS version of _CMake_ from -[www.cmake.org](https://cmake.org/download/). Download the .dmg file, click it, and when -the Finder window opens, drag the _CMake_ icon into the Applications folder. - -We will be using _CMake_ from the command line. Please launch _CMake_ and choose -`Tools > How to Install for Command Line Use` and follow the instructions -in the dialog box. If you have admin right, you can also use - -```bash -sudo ln -s /Applications/CMake.app/Contents/bin/cmake /usr/local/bin/cmake -``` - -Installing the _Xcode_ command line tools is pretty straight forward. Just enter this -in your shell and follow the dialogs: - -```bash -xcode-select --install -``` - -On older versions of macOS, you will have to install _Xcode_ from the -[App Store](https://itunes.apple.com/de/app/xcode/id497799835?l=en&mt=12) -and then install the command line tools from within _Xcode_. - - -<a name="bcm_download"></a> -### Downloading and Unpacking (CMake, make) - -Downloading FLTK is explained [here](#bam_download). - -<a name="bcm_config"></a> -### Configuring FLTK (CMake, make) - -Using your shell in the terminal, make sure that you are in the root directory of your -FLTK source code tree. - -Configure your FLTK installation. CMake will create the required directories for you: - -```bash -cmake -B build/Makefile -G "Unix Makefiles" -D CMAKE_BUILD_TYPE=Debug . -``` - -Replace 'Debug' with 'Release' if you want to build a release version. - -_CMake_ runs a number of tests to find external headers, libraries, and tools. -The configuration summary should not show any errors. You can now continue to build FLTK. - -For the advanced user there are a few more options to the _CMake_ setup. Type -`cmake -L .` to get a complete list of options. These should be pretty -self-explanatory. Some more details can be found in -[online documentation](https://www.fltk.org/doc-1.5/intro.html#intro_cmake). - -<a name="bcm_build"></a> -### Building FLTK (CMake, make) - -Now this is easy if all the previous steps were successful. Stay in the root -directory of your FLTK source code tree and type: - -```bash -cmake --build build/Makefile -``` - -The entire FLTK toolkit including many test programs will be built for you. No -warnings should appear, but "ranlib" may complain about a few modules having no -symbols. This is normal and can safely be ignored. - -To build individual targets, you can use: - -```bash -cmake --build build/Makefile --target hello -``` - -<a name="bcm_test"></a> -### Testing FLTK (CMake, make) - -After a successful build, you can test FLTK's capabilities by running - -```bash -open build/Makefile/bin/test/demo.app -``` - -<a name="bcm_install"></a> -### Installing FLTK (CMake, make) - -If you did not change any of the configuration settings, FLTK will be installed -in `/usr/local/include`, `/usr/local/lib`, and `/usr/local/bin` by typing - -```bash -sudo cmake --build build/Makefile --target install -``` - -It is possible to install FLTK without superuser privileges by changing the -installation path to a location within the user account by adding the -`-D CMAKE_INSTALL_PREFIX=<PREFIX>` parameter to the `cmake` command. - -<a name="bcm_new_projects"></a> -### Creating new Projects (CMake, make) - -FLTK provides a neat script named `fltk-config` that can provide all the flags -needed to build FLTK applications using the same flags that were used to build -the library itself. Running `fltk-config` without arguments will print a list -of options. The easiest call to compile an FLTK application from a single source -file is: - -```bash -fltk-config --compile myProgram.cxx -``` - -`fltk-config` and our user interface designer `fluid` will be installed in -`/usr/local/bin/` by default. I recommend that you add this directory to the shell -`PATH` variable. - - -<a name="dropstart"></a> -## Make an Application Launchable by Dropping Files on its Icon - -- Prepare an Info.plist file for your application derived from file -_test/mac-resources/editor.plist_ which allows any file to be dropped -on the application icon. -You can edit this file in Xcode and change -CFBundleDocumentTypes/Item 0/CFBundleTypeExtensions/Item 0 -from the current "*" to the desired file extension. Use several items to -declare several extensions. - -- Call function <a href=https://www.fltk.org/doc-1.5/group__group__macosx.html#ga0702a54934d10f5b72157137cf291296>fl\_open\_callback()</a> at the beginning of your main() function to set -what function will be called when a file is dropped on the application icon. - -- In Xcode, set the `Info.plist File` build setting of your target application -to the *Info.plist* file you have prepared. Alternatively, use CMake's -`set_target_properties` function and `MACOSX_BUNDLE_INFO_PLIST` property -to have CMake put your *Info.plist* file in the resulting macOS application bundle. - -- Rebuild your application. - -## Links - -[GitHub, git, forking, fetching. and pull requests](https://gist.github.com/Chaser324/ce0505fbed06b947d962) - -<a name="doc_history"></a> -## DOCUMENT HISTORY - -- Oct 29 2010 - matt: removed warnings -- Oct 24 2010 - matt: restructured entire document and verified instructions -- Dec 19 2010 - Manolo: corrected typos -- Dec 29 2010 - Manolo: removed reference to AudioToolbox.framework that's no longer needed -- Feb 24 2011 - Manolo: architecture flags are not propagated to the fltk-config script. -- Apr 17 2012 - matt: added Xcode4 documentation -- Nov 13 2012 - Manolo: added "MAKE AN APPLICATION LAUNCHABLE BY DROPPING FILES ON ITS ICON" -- Mar 18 2015 - Manolo: removed uses of the Xcode3 project -- Apr 01 2016 - Albrecht: corrected typo, formatted most line breaks < 80 columns -- Dec 04 2018 - Albrecht: fix typo (lowercase fluid.app) for case sensitive macOS -- Dec 28 2018 - Matt: complete rework for FLTK 1.4 -- Mar 01 2021 - Albrecht: minor updates, macOS Big Sur and Apple Silicon M1 (ARM) -- Feb 23 2022 - Manolo: install autoconf without brew -- Mar 22 2025 - Matt: update for FLTK 1.5 diff --git a/bin/fluid b/bin/fluid Binary files differnew file mode 100755 index 000000000..63d4d5c6d --- /dev/null +++ b/bin/fluid @@ -1,7 +1,9 @@ -/* @CONFIG_H@. Generated from @CONFIG_H_IN@ by CMake. */ /* - * Configuration file for the Fast Light Tool Kit (FLTK). This file is used - * internally in the FLTK library and is not publicly available (not installed). + * Configuration file for the Fast Light Tool Kit (FLTK). + * This file is used internally in the FLTK library and is not publicly + * available (not installed). + * + * Hardcoded for X11-only build. * * Copyright 1998-2026 by Bill Spitzak and others. * @@ -16,19 +18,8 @@ * https://www.fltk.org/bugs.php */ -/* - * Note: CMake syntax in input file (examples): - * - * For instance in @CONFIG_H_IN@ (remove brackets for real syntax): - * ---------------------------------------------------------------- - * [#]cmakedefine01 HAVE_GL - * [#]cmakedefine HAVE_SNPRINTF 1 - * - * The former defines HAVE_GL either as 0 or 1. - * - * The latter either doesn't define HAVE_SNPRINTF or defines it as 1. - * The value (1 in the example) can be an arbitrary number or string. - */ +#ifndef _FL_config_h_ +#define _FL_config_h_ /* * Always include the public build configuration header @@ -40,8 +31,8 @@ * Where to find files... */ -#define FLTK_DATADIR "@PREFIX_DATA@" -#define FLTK_DOCDIR "@PREFIX_DOC@" +#define FLTK_DATADIR "/usr/local/share/fltk" +#define FLTK_DOCDIR "/usr/local/share/doc/fltk" /* * BORDER_WIDTH: @@ -66,7 +57,7 @@ * OpenGL, and FLTK will be smaller. */ -#cmakedefine01 HAVE_GL +#define HAVE_GL 1 /* * HAVE_GL_GLU_H: @@ -75,7 +66,7 @@ * (many broken Mesa RPMs do not...) */ -#cmakedefine01 HAVE_GL_GLU_H +#define HAVE_GL_GLU_H 1 /* * HAVE_GLXGETPROCADDRESSARB: @@ -83,7 +74,7 @@ * Do you have the OpenGL glXGetProcAddressARB() function? */ -#cmakedefine HAVE_GLXGETPROCADDRESSARB 1 +#define HAVE_GLXGETPROCADDRESSARB 1 /* * USE_COLORMAP: @@ -100,7 +91,7 @@ * Do we have the Xinerama library to support multi-head displays? */ -#cmakedefine01 HAVE_XINERAMA +#define HAVE_XINERAMA 1 /* * USE_XFT @@ -108,7 +99,7 @@ * Use the Xft library to draw anti-aliased text. */ -#cmakedefine01 USE_XFT +#define USE_XFT 1 /* * USE_PANGO @@ -116,7 +107,7 @@ * Use the pango library to draw UTF-8 text. */ -#cmakedefine01 USE_PANGO +#define USE_PANGO 1 /* * HAVE_XFIXES: @@ -124,7 +115,7 @@ * Do we have the X fixes extension? */ -#cmakedefine01 HAVE_XFIXES +#define HAVE_XFIXES 1 /* * HAVE_XCURSOR: @@ -132,7 +123,7 @@ * Do we have the X cursor library? */ -#cmakedefine01 HAVE_XCURSOR +#define HAVE_XCURSOR 1 /* * HAVE_XRENDER: @@ -140,7 +131,7 @@ * Do we have the X render library? */ -#cmakedefine01 HAVE_XRENDER +#define HAVE_XRENDER 1 /* * HAVE_X11_XREGION_H: @@ -148,7 +139,7 @@ * Do we have the X11 Xregion.h header file ? */ -#cmakedefine01 HAVE_X11_XREGION_H +#define HAVE_X11_XREGION_H 1 /* * HAVE_GL_OVERLAY: @@ -165,11 +156,7 @@ * Byte order of your machine: 1 = big-endian, 0 = little-endian. */ -#ifdef __APPLE__ -#include <mac_endianness.h> -#else -#cmakedefine01 WORDS_BIGENDIAN -#endif +#define WORDS_BIGENDIAN 0 /* * U16, U32, U64: @@ -178,9 +165,9 @@ * U16 is optional but FLTK will work better with it! */ -#cmakedefine U16 @U16@ -#cmakedefine U32 @U32@ -#cmakedefine U64 @U64@ +#define U16 unsigned short +#define U32 unsigned int +/* #undef U64 */ /* * HAVE_DIRENT_H, HAVE_SYS_NDIR_H, HAVE_SYS_DIR_H, HAVE_NDIR_H, @@ -189,35 +176,35 @@ * Where is <dirent.h> (used only by fl_file_chooser and scandir). */ -#cmakedefine HAVE_DIRENT_H 1 -#cmakedefine HAVE_SYS_NDIR_H 1 -#cmakedefine HAVE_SYS_DIR_H 1 -#cmakedefine HAVE_NDIR_H 1 -#cmakedefine HAVE_SCANDIR 1 -#cmakedefine HAVE_SCANDIR_POSIX 1 +#define HAVE_DIRENT_H 1 +/* #undef HAVE_SYS_NDIR_H */ +/* #undef HAVE_SYS_DIR_H */ +/* #undef HAVE_NDIR_H */ +#define HAVE_SCANDIR 1 +#define HAVE_SCANDIR_POSIX 1 /* * Possibly missing sprintf-style functions: */ -#cmakedefine HAVE_VSNPRINTF 1 -#cmakedefine HAVE_SNPRINTF 1 +#define HAVE_VSNPRINTF 1 +#define HAVE_SNPRINTF 1 /* * String functions and headers... */ -#cmakedefine HAVE_STRINGS_H 1 -#cmakedefine HAVE_STRCASECMP 1 -#cmakedefine HAVE_STRLCAT 1 -#cmakedefine HAVE_STRLCPY 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRCASECMP 1 +/* #undef HAVE_STRLCAT */ +/* #undef HAVE_STRLCPY */ /* * Do we have POSIX locale support? */ -#cmakedefine HAVE_LOCALE_H 1 -#cmakedefine HAVE_LOCALECONV 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LOCALECONV 1 /* * HAVE_SYS_SELECT_H: @@ -225,7 +212,7 @@ * Whether or not select() call has its own header file. */ -#cmakedefine01 HAVE_SYS_SELECT_H +#define HAVE_SYS_SELECT_H 1 /* * HAVE_SYS_STDTYPES_H: @@ -233,7 +220,7 @@ * Whether or not we have the <sys/stdtypes.h> header file. */ -#cmakedefine HAVE_SYS_STDTYPES_H 1 +/* #undef HAVE_SYS_STDTYPES_H */ /* * USE_POLL: @@ -241,7 +228,7 @@ * Use the poll() call provided on Linux and Irix instead of select() */ -#cmakedefine01 USE_POLL +#define USE_POLL 0 /* * HAVE_SETENV: @@ -249,7 +236,7 @@ * Whether or not POSIX setenv() is available from stdlib.h. */ -#cmakedefine01 HAVE_SETENV +#define HAVE_SETENV 1 /* * HAVE_TRUNC: @@ -257,15 +244,15 @@ * Whether or not POSIX trunc() is available from math.h. */ -#cmakedefine01 HAVE_TRUNC +#define HAVE_TRUNC 1 /* * Do we have various image libraries? */ -#cmakedefine HAVE_LIBPNG 1 -#cmakedefine HAVE_LIBZ 1 -#cmakedefine HAVE_LIBJPEG 1 +#define HAVE_LIBPNG 1 +#define HAVE_LIBZ 1 +#define HAVE_LIBJPEG 1 /* * Which header file do we include for libpng? @@ -274,40 +261,39 @@ * There is no other choice. */ -#cmakedefine HAVE_PNG_H 1 +#define HAVE_PNG_H 1 /* * Do we have the png_xyz() functions? */ -#cmakedefine HAVE_PNG_GET_VALID 1 -#cmakedefine HAVE_PNG_SET_TRNS_TO_ALPHA 1 - +#define HAVE_PNG_GET_VALID 1 +#define HAVE_PNG_SET_TRNS_TO_ALPHA 1 /* * Do we have POSIX threading? */ -#cmakedefine HAVE_PTHREAD 1 -#cmakedefine HAVE_PTHREAD_H 1 +#define HAVE_PTHREAD 1 +#define HAVE_PTHREAD_H 1 /* * Do we have PTHREAD_MUTEX_RECURSIVE? */ -#cmakedefine HAVE_PTHREAD_MUTEX_RECURSIVE 1 +#define HAVE_PTHREAD_MUTEX_RECURSIVE 1 /* * Do we have the ALSA library? */ -#cmakedefine HAVE_ALSA_ASOUNDLIB_H 1 +#define HAVE_ALSA_ASOUNDLIB_H 1 /* * Do we have the long long type? */ -#cmakedefine HAVE_LONG_LONG 1 +#define HAVE_LONG_LONG 1 #ifdef HAVE_LONG_LONG # define FLTK_LLFMT "%lld" @@ -321,53 +307,34 @@ * Do we have the dlsym() function and header? */ -#cmakedefine01 HAVE_DLFCN_H -#cmakedefine01 HAVE_DLSYM +#define HAVE_DLFCN_H 1 +#define HAVE_DLSYM 1 /* * Do we want print support? */ -#cmakedefine FL_NO_PRINT_SUPPORT 1 - -/* - * Do we use GDI+ to get antialiased graphics? - */ - -#ifdef _WIN32 -#cmakedefine01 USE_GDIPLUS -#endif +/* #undef FL_NO_PRINT_SUPPORT */ /* * Do we want filename handling and a filechooser? */ -#cmakedefine FL_CFG_NO_FILESYSTEM_SUPPORT 1 - -/* - * Can we use the "XDG dialog windows" Wayland protocol? - */ - -#cmakedefine01 HAVE_XDG_DIALOG - +/* #undef FL_CFG_NO_FILESYSTEM_SUPPORT */ /* - * Can we use the "Cursor shape" Wayland protocol? + * Wayland-specific options (disabled for X11-only build) */ -#cmakedefine01 HAVE_CURSOR_SHAPE - +#define HAVE_XDG_DIALOG 0 +#define HAVE_CURSOR_SHAPE 0 /* * FLTK_HAVE_PEN_SUPPORT * - * Do we have pen/tablet support for the current platform? - * See CMake option FLTK_OPTION_PEN_SUPPORT, but note that a build test - * (try_compile()) is performed to test if the option is available - * - * Note: this option is "hidden" in 'config.h', i.e. it's not (yet) - * publicly accessibe. Move this to 'fl_config.h' to make it public. - * + * Pen/tablet support is not available for X11-only build. */ -#cmakedefine FLTK_HAVE_PEN_SUPPORT 1 +/* #undef FLTK_HAVE_PEN_SUPPORT */ + +#endif /* _FL_config_h_ */ diff --git a/documentation/CMakeLists.txt b/documentation/CMakeLists.txt deleted file mode 100644 index c4f9c599c..000000000 --- a/documentation/CMakeLists.txt +++ /dev/null @@ -1,296 +0,0 @@ -# -# CMakeLists.txt to build docs for the FLTK project using CMake (www.cmake.org) -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -set(DOCS) -set(GENERATE_DOCS FALSE) -set(YEAR "") -set(CURRENT_DATE "") - -if(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS) - set(GENERATE_DOCS TRUE) -endif() - -if(FLTK_INCLUDE_DRIVER_DOCS) - set(DRIVER_DOCS "DriverDev") -else() - set(DRIVER_DOCS "") -endif() - -#------------------------------------------------ -# generate files used for both HTML and PDF docs -#------------------------------------------------ - -if(GENERATE_DOCS) - - # create required variables - - string(TIMESTAMP YEAR "%Y" UTC) - # note: current locale is used for abbreviated month - string(TIMESTAMP CURRENT_DATE "%b %d, %Y" UTC) - string(TIMESTAMP PDF_DATE "D:%Y%m%d%H%M%SZ" UTC) - string(TIMESTAMP TODAY "%B %d, %Y" UTC) - string(REPLACE " 0" " " TODAY "${TODAY}") - - # Find "short" doxygen version if it was built from Git - # Note: this is still needed in CMake 3.15 but later CMake versions - # (notably 3.25) remove the Git revision in 'DOXYGEN_VERSION'. - # Todo: Find the "first good" CMake version and remove this redundant - # code once we require this as our minimal version and replace the - # variable DOXYGEN_VERSION_SHORT with DOXYGEN_VERSION below. - - if(DOXYGEN_FOUND) - # strip trailing git revision if doxygen was built from source - string(REGEX REPLACE " .*$" "" DOXYGEN_VERSION_SHORT ${DOXYGEN_VERSION}) - endif(DOXYGEN_FOUND) - - # configure version.dox (includes the bare FLTK version number) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/version.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/version.dox - @ONLY - ) - - # configure copyright.dox (includes current year) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/copyright.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/copyright.dox - @ONLY - ) - - # configure generated.dox (includes date and versions) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/generated.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/generated.dox - @ONLY - ) - - if(0) # debug - fl_debug_var(YEAR) - fl_debug_var(CURRENT_DATE) - fl_debug_var(PDF_DATE) - fl_debug_var(TODAY) - fl_debug_var(FLTK_GIT_REVISION) - fl_debug_var(DOXYGEN_FOUND) - fl_debug_var(DOXYGEN_EXECUTABLE) - fl_debug_var(DOXYGEN_VERSION) - fl_debug_var(DOXYGEN_VERSION_SHORT) - endif() - -endif(GENERATE_DOCS) - -#-------------------------- -# build html documentation -#-------------------------- - -if(FLTK_BUILD_HTML_DOCS) - - list(APPEND DOCS html) - - # generate Doxygen file "Doxyfile" - - set(GENERATE_HTML YES) - set(GENERATE_LATEX NO) - set(EXTRA_SECTIONS "HTML_SECTIONS") - set(LATEX_HEADER "") - set(DOXYFILE "Doxyfile") - set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log") - - # configure Doxygen input file for HTML docs (Doxyfile.in) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in - @ONLY - ) - - # convert Doxyfile to used doxygen version - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile - ${DOXYGEN_EXECUTABLE} - ${DOXYFILE}.in - ${DOXYFILE} - ${LOGFILE} - BYPRODUCTS ${LOGFILE} - COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM - ) - - # generate HTML documentation - - add_custom_target(html - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating HTML documentation" VERBATIM - ) - -endif(FLTK_BUILD_HTML_DOCS) - -#-------------------------- -# build pdf documentation -#-------------------------- - -if(FLTK_BUILD_PDF_DOCS) - - list(APPEND DOCS pdf) - - # generate Doxygen input file "Doxybook" - - set(GENERATE_HTML NO) - set(GENERATE_LATEX YES) - set(EXTRA_SECTIONS "LATEX_SECTIONS") - set(LATEX_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fltk-book.tex") - set(DOXYFILE "Doxybook") - set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log") - - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated) - - # configure Doxygen input file for PDF docs (Doxybook.in) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in - @ONLY - ) - - # convert Doxybook to current doxygen version - - # set DOXY_VERSION for compatibility with configure/make, - # to be replaced in fltk-title.tex.in - # FIXME: this can be simplified when configure/make is no longer supported - - set(DOXY_VERSION "${DOXYGEN_VERSION_SHORT}") # - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile - ${DOXYGEN_EXECUTABLE} - ${DOXYFILE}.in - ${DOXYFILE} - ${LOGFILE} - BYPRODUCTS ${LOGFILE} - COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM - ) - - # generate LaTeX title fltk-title.tex and make_pdf script - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/fltk-title.tex.in - ${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex - @ONLY - ) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/make_pdf.in - ${CMAKE_CURRENT_BINARY_DIR}/make_pdf - @ONLY - ) - - # Generate code snapshots (images with international characters). - # Note: File names (even from different folders) must be unique ! - - set(image_output_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") - set(_deps) - set(image_input_sources - ${CMAKE_CURRENT_SOURCE_DIR}/src/unicode.dox - # ${CMAKE_CURRENT_SOURCE_DIR}/src/cmp.dox # more documentation files - # ${FLTK_SOURCE_DIR}/src/Fl.cxx # example source file - ) - - # Generate one custom command and one timestamp per input file - # so dependencies can be used to generate the images only if - # the source file was changes. - # Variable `_deps` is used to make the final PDF generation - # depend on all input files. - - foreach(_infile ${image_input_sources}) - get_filename_component(_name "${_infile}" NAME) - set(_timestamp ${image_output_dir}/${_name}.timestamp) - list(APPEND _deps ${_timestamp}) - # create custom command - add_custom_command( - OUTPUT ${_timestamp} - COMMAND touch ${_timestamp} - COMMAND code_snapshot ${_infile} - DEPENDS ${_infile} - WORKING_DIRECTORY ${image_output_dir} - COMMENT "Generating code snapshots (PNG) from '${_infile}'" - ) - endforeach() - - # Now generate the PDF file (fltk.pdf) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header - ${DOXYGEN_EXECUTABLE} - ${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex - ${CMAKE_CURRENT_BINARY_DIR}/fltk-book.tex - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/make_pdf - COMMAND cp -f latex/refman.pdf fltk.pdf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - ${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex - ${_deps} # source files processed to generate PNG's - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating PDF documentation" VERBATIM - ) - - # add target 'pdf' - - add_custom_target(pdf - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf - ) - add_dependencies(pdf code_snapshot) - -endif(FLTK_BUILD_PDF_DOCS) - -#---------------------------------- -# add target 'docs' for all docs -#---------------------------------- - -if(DOCS) - - add_custom_target(docs - DEPENDS ${DOCS} - ) - -endif(DOCS) - -#---------------------------------- -# install html + pdf documentation -#---------------------------------- - -if(FLTK_INSTALL_HTML_DOCS AND FLTK_BUILD_HTML_DOCS) - - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html - DESTINATION ${FLTK_DATADIR}/doc/fltk - ) - -endif(FLTK_INSTALL_HTML_DOCS AND FLTK_BUILD_HTML_DOCS) - -if(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS) - - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf - DESTINATION ${FLTK_DATADIR}/doc/fltk/ - ) - -endif(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt deleted file mode 100644 index a8dfa970f..000000000 --- a/examples/CMakeLists.txt +++ /dev/null @@ -1,219 +0,0 @@ -# -# CMakeLists.txt used to build example apps by the CMake build system -# -# Copyright 2020-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# -################################################################################ - -include(../CMake/fl_create_example.cmake) -include(../CMake/FLTK-Functions.cmake) - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin/examples) -file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) - -################################################################################ - -# create separate lists of all source (.cxx) files -# depending on the required FLTK and system libraries - -############################################################ -# simple examples w/o extra libs -############################################################ - -set(SIMPLE_SOURCES - browser-simple - callbacks - chart-simple - draggable-group - grid-simple - howto-add_fd-and-popen - howto-browser-with-icons - howto-drag-and-drop - howto-draw-an-x - howto-flex-simple - howto-menu-with-images - howto-parse-args - howto-remap-numpad-keyboard-keys - howto-text-over-image-button - menubar-add - nativefilechooser-simple - nativefilechooser-simple-app - progress-simple - shapedwindow - simple-terminal - table-as-container - table-simple - table-sort - table-spreadsheet - table-spreadsheet-with-keyboard-nav - table-with-keynav - table-with-right-column-stretch-fit - table-with-right-click-menu - tabs-simple - textdisplay-with-colors - texteditor-simple - texteditor-with-dynamic-colors - tree-as-container - tree-custom-draw-items - tree-custom-sort - tree-of-tables - tree-simple - wizard-simple -) - -############################################################ -# simple FLUID examples w/o extra libs -############################################################ - -set(FLUID_SOURCES - fluid-callback -) - -############################################################ -# examples requiring fltk::images -############################################################ - -set(IMAGE_SOURCES - animgifimage - animgifimage-play - animgifimage-resize - animgifimage-simple - howto-simple-svg -) - -############################################################ -# examples requiring cairo -############################################################ - -set(CAIRO_SOURCES - cairo-draw-x -) - -############################################################ -# examples requiring OpenGL3 + GLEW -############################################################ - -set(OPENGL_SOURCES - OpenGL3-glut-test - OpenGL3test -) - -############################################################ -# create simple example programs -############################################################ - -foreach(src ${SIMPLE_SOURCES}) - fl_create_example(${src} ${src}.cxx fltk::fltk) -endforeach(src) - -############################################################ -# create FLUID example programs -############################################################ - -foreach(src ${FLUID_SOURCES}) - fl_create_example(${src} ${src}.fl fltk::fltk) -endforeach(src) - -############################################################ -# create example programs with fltk_images library -############################################################ - -foreach(src ${IMAGE_SOURCES}) - fl_create_example(${src} ${src}.cxx "fltk::images") -endforeach(src) - -############################################################ -# create example programs requiring cairo -############################################################ - -foreach(src ${CAIRO_SOURCES}) - fl_create_example(${src} ${src}.cxx fltk::fltk) -endforeach(src) - -############################################################ -# create example programs with OpenGL3 + GLEW -############################################################ -# -# Note 1: macOS (Quartz) does not need GLEW, it's included in OpenGL -# Note 2: find_package(GLEW) finds either shared or static libs or both. -# Note 3: on Windows we set the variable GLEW_USE_STATIC_LIBS=TRUE because -# we *want* to find static libs but we *can* also use shared libs. -# Note 4: FindGLEW.cmake changed the library suffixes for MinGW in CMake 3.28.0, -# obviously "assuming" that ".lib" is Visual Studio only. There have been -# discussions about finding the "wrong" libraries since CMake 3.25 or so. -# Therefore the static lib "glew32s.lib" is not found if CMake 3.28 or -# higher is used (current version, as of this writing: 3.29.3). However, -# this assumption is probably not true for a pure C library (glew32s). -# This library *is* found and works well with CMake 3.15.0 - 3.27.9. -# Users may need to copy or rename "glew32s.lib" to "glew32s.a" -# if CMake 3.28 or higher is used. -# Albrecht-S, May 13, 2024 - -if(OPENGL_FOUND) - if(WIN32) - set(GLEW_USE_STATIC_LIBS TRUE) - endif() - set(_glew_lib GLEW::glew) - set(_glew_static FALSE) - if(APPLE AND NOT FLTK_BACKEND_X11) # macOS Quartz - set(_glew_lib) - set(GLEW_FOUND TRUE) - else() - # set(GLEW_VERBOSE TRUE) # make `find_package(GLEW)` verbose - set(_CMAKE_PREFIX_PATH_SAVED ${CMAKE_PREFIX_PATH}) - set(CMAKE_PREFIX_PATH ${FLTK_GLEW_DIR} ${CMAKE_PREFIX_PATH}) - find_package(GLEW MODULE) - set(CMAKE_PREFIX_PATH ${_CMAKE_PREFIX_PATH_SAVED}) - unset(_CMAKE_PREFIX_PATH_SAVED) - # Did we find the static lib? If yes, use it - if(TARGET GLEW::glew_s) - set(_glew_lib GLEW::glew_s) - set(_glew_static TRUE) - endif() - endif() - - if(0) # Debug - fl_debug_var(OPENGL_FOUND) - fl_debug_var(GLEW_FOUND) - fl_debug_var(GLEW_DIR) - fl_debug_var(_glew_lib) - fl_debug_target(GLEW::glew) - fl_debug_target(GLEW::glew_s) - fl_debug_target(GLEW::GLEW) - endif() # /Debug - -endif(OPENGL_FOUND) - -if(OPENGL_FOUND AND (TARGET "${_glew_lib}" OR APPLE)) - - # GLEW was found, create the OpenGL3 targets: - - foreach(tgt ${OPENGL_SOURCES}) - fl_create_example(${tgt} ${tgt}.cxx "fltk::gl;${_glew_lib}") - set_property(TARGET ${tgt} PROPERTY CXX_STANDARD 11) - set_property(TARGET ${tgt} PROPERTY CXX_STANDARD_REQUIRED TRUE) - # define preprocessor macro GLEW_STATIC only if we link to the static lib - if(_glew_static) - target_compile_definitions(${tgt} PRIVATE "GLEW_STATIC") - endif() - endforeach(tgt) - -else() - - message(STATUS - "OpenGL or GLEW not present: OpenGL3 example programs will not be built.") - fl_debug_var(OPENGL_FOUND) - fl_debug_var(GLEW_FOUND) - message("") - -endif() # (OPENGL_FOUND AND TARGET "${_glew_lib}") diff --git a/fl_config.h.in b/fl_config.h.in deleted file mode 100644 index cf7168557..000000000 --- a/fl_config.h.in +++ /dev/null @@ -1,162 +0,0 @@ -/* FL/fl_config.h. Generated from fl_config.h.in by CMake. */ -/* - * Build configuration file for the Fast Light Tool Kit (FLTK). This - * configuration file is publicly accessible by user programs (installed). - * - * Copyright 1998-2025 by Bill Spitzak and others. - * - * This library is free software. Distribution and use rights are outlined in - * the file "COPYING" which should have been included with this file. If this - * file is missing or damaged, see the license at: - * - * https://www.fltk.org/COPYING.php - * - * Please see the following page on how to report bugs and issues: - * - * https://www.fltk.org/bugs.php - */ - -#ifndef _FL_fl_config_h_ -#define _FL_fl_config_h_ - -/** \defgroup version_numbers Version Numbers - - FLTK defines some constants to help the programmer to - find out, for which FLTK version a program is compiled. - - The following constants are defined: - @{ -*/ - -/** - The major release version of this FLTK library. - \see FL_VERSION -*/ -#define FL_MAJOR_VERSION @FLTK_VERSION_MAJOR@ - -/** - The minor release version for this library. - - FLTK remains mostly source-code compatible between minor version changes. -*/ -#define FL_MINOR_VERSION @FLTK_VERSION_MINOR@ - -/** - The patch version for this library. - - FLTK remains binary compatible between patch versions. -*/ -#define FL_PATCH_VERSION @FLTK_VERSION_PATCH@ - -/** - The FLTK ABI (Application Binary Interface) version number as an \em int. - - FL_ABI_VERSION is an \em int that describes the major, minor, and patch - ABI version numbers in the same format as FL_API_VERSION. - - The ABI version number \p FL_ABI_VERSION is usually the same as the - API version \p FL_API_VERSION with the last two digits set to '00'. - - FLTK retains the ABI (Application Binary Interface) during patch - releases of the same major and minor versions. Examples: - - \verbatim - FLTK Version FL_API_VERSION FL_ABI_VERSION FL_VERSION (deprecated) - 1.3.0 10300 10300 1.0300 - 1.3.4 10304 10300 1.0304 - \endverbatim - - Version 1.2.3 is actually stored as 10203 to allow for more than 9 minor - and patch releases. - - The FL_MAJOR_VERSION, FL_MINOR_VERSION, and FL_PATCH_VERSION constants - give the integral values for the major, minor, and patch releases - respectively. - - To enable new ABI-breaking features in patch releases you can configure - FLTK to use a higher FL_ABI_VERSION. The highest allowed version is - - FL_ABI_VERSION = FL_API_VERSION + 1 - - to allow for "next version" ABI features when FLTK is built from git or - from a snapshot (pre-release version). - - \see README.abi-version.txt -*/ - -#define FL_ABI_VERSION @FL_ABI_VERSION@ - -/** @} */ - -// End of doxygen group 'version_numbers'. More is added to the group in -// in file FL/Enumerations.H - -/* - * FLTK_HAVE_CAIRO - * - * Do we have Fl_Cairo_Window support? -*/ - -#cmakedefine FLTK_HAVE_CAIRO 1 - - -/* - * FLTK_HAVE_CAIROEXT - * - * Do we have the Cairo library available and want extended Cairo use in FLTK ? - * This implies to link cairo.lib in all FLTK based apps. -*/ - -#cmakedefine FLTK_HAVE_CAIROEXT 1 - - -/* - * FLTK_HAVE_FORMS - * - * Do we have the Forms compatibility library available? -*/ - -#cmakedefine FLTK_HAVE_FORMS 1 - - -/* - * FLTK_USE_X11 - * - * Do we use X11 for the current platform? - * - */ - -#cmakedefine FLTK_USE_X11 1 - - -/* - * FLTK_USE_CAIRO - * - * Do we use Cairo to draw to the display? - * - */ - -#cmakedefine FLTK_USE_CAIRO 1 - - -/* - * FLTK_USE_WAYLAND - * - * Do we use Wayland for the current platform? - * - */ - -#cmakedefine FLTK_USE_WAYLAND 1 - - -/* - * FLTK_USE_SVG - * - * Do we want FLTK to read and write SVG-formatted files ? - * - */ - -#cmakedefine01 FLTK_USE_SVG - - -#endif /* _FL_fl_config_h_ */ diff --git a/fltk-config.in b/fltk-config.in deleted file mode 100644 index c23b79ce6..000000000 --- a/fltk-config.in +++ /dev/null @@ -1,443 +0,0 @@ -#!/bin/sh -# -# FLTK configuration utility. -# -# Copyright 2000-2025 by Bill Spitzak and others. -# Original version Copyright 2000 by James Dean Palmer -# Adapted by Vincent Penne and Michael Sweet -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Variables and constants generated by CMake: - -# version numbers -MAJOR_VERSION=@FLTK_VERSION_MAJOR@ -MINOR_VERSION=@FLTK_VERSION_MINOR@ -PATCH_VERSION=@FLTK_VERSION_PATCH@ - -VERSION="$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION" -APIVERSION="$MAJOR_VERSION.$MINOR_VERSION" - -# compiler names -CC="@CC@" -CXX="@CXX@" - -# flags for C++ compiler: -ARCHFLAGS="@ARCHFLAGS@" -CFLAGS="@CFLAGS@ @LARGEFILE@ @PTHREAD_FLAGS@" -CXXFLAGS="@CXXFLAGS@ @LARGEFILE@ @PTHREAD_FLAGS@" -LDFLAGS="@LDFLAGS@" -LDLIBS="@LIBS@" -OPTIM="@OPTIM@" -CAIROFLAGS="@CAIROFLAGS@" - -# BINARY_DIR: this is only set for CMake builds in the CMake build directory, -# otherwise it is an empty string (for instance in the install directory) -BINARY_DIR=@BINARY_DIR@ - -prefix="@prefix@" -exec_prefix="@exec_prefix@" -exec_prefix_set=no -includedir="@includedir@" -libdir="@libdir@" -srcdir="@srcdir@" - -# BEGIN fltk-config code - -# Check for local invocation (in FLTK source folder), and update paths accordingly... -selfdir=`dirname "$0"` -if test -f "$selfdir/FL/Fl_Window.H"; then - includedir="$selfdir" - libdir="$selfdir/lib" -fi - -# Libraries to link with (must be after 'prefix' stuff and after check for local invocation) -LIBNAME="@LIBNAME@" -DSONAME="@DSONAME@" -DSOLINK="@DSOLINK@" -IMAGELIBS="@IMAGELIBS@" -STATICIMAGELIBS="@STATICIMAGELIBS@" -SHAREDSUFFIX="@SHAREDSUFFIX@" -CAIROLIBS="@CAIROLIBS@" -GLLIBS="@GLLIBS@" - -# Check bundled image libraries in source tree -if test -f "$libdir/libfltk_jpeg.a" -a -d $includedir/jpeg; then - CFLAGS="-I$includedir/jpeg $CFLAGS" - CXXFLAGS="-I$includedir/jpeg $CXXFLAGS" -fi - -if test -f "$libdir/libfltk_z.a" -a -d $includedir/zlib; then - CFLAGS="-I$includedir/zlib $CFLAGS" - CXXFLAGS="-I$includedir/zlib $CXXFLAGS" -fi - -if test -f "$libdir/libfltk_png.a" -a -d $includedir/png; then - CFLAGS="-I$includedir/png $CFLAGS" - CXXFLAGS="-I$includedir/png $CXXFLAGS" -fi - -# Check bundled image libraries in installation folder. -# Note: jpeg, png, and zlib headers are installed in FL/images -if test -d "$includedir/FL/images"; then - CFLAGS="-I$includedir/FL/images $CFLAGS" - CXXFLAGS="-I$includedir/FL/images $CXXFLAGS" -fi - -# Cairo support: *append* CAIROFLAGS -if test -n "$CAIROFLAGS"; then - CFLAGS="$CFLAGS $CAIROFLAGS" - CXXFLAGS="$CXXFLAGS $CAIROFLAGS" -fi - -usage () -{ - echo "Usage: fltk-config [OPTIONS] -Options: - [--version] - [--api-version] - -Options telling what we are doing: - [--use-gl] use GL - [--use-images] use extra image formats (PNG, JPEG) - [--use-glut] use glut compatibility layer - [--use-forms] use forms compatibility layer - [--use-cairo] use cairo graphics lib - -Options telling what information we request: - [--cc] return C compiler used to compile FLTK - [--cxx] return C++ compiler used to compile FLTK - [--optim] return compiler optimization used to compile FLTK - [--cflags] return flags to compile C using FLTK - [--cxxflags] return flags to compile C++ using FLTK - [--ldflags] return flags to link against FLTK - [--ldstaticflags] return flags to link against static FLTK library - even if there are DSOs installed - [--libs] return FLTK libraries full path for dependencies - [--prefix] return FLTK install time --prefix directory - [--includedir] return FLTK install time include directory - -Options to compile and link an application: - [-g] compile the program with debugging information - [-Dname[=value]] compile the program with the given define - [--compile program.cxx ..] compile and link the program with optional - .. compiler flags, source files, and libraries - [--link flags and libs] additional linker flags and libraries - .. for --compile, added after all other libs - [--post program] prepare the program for desktop use (macOS) -" - exit $1 -} - -if test $# -eq 0; then - usage 1 -fi - -# variables for parsing and generation of the commandline -compile= -post= -debug= -flags= -files= -use_link= -link= - -# Parse command line options -while test $# -gt 0 -do - case $1 in - --version) - echo $VERSION - ;; - --api-version) - echo $APIVERSION - ;; - --cc) - echo $CC - ;; - --cxx) - echo $CXX - ;; - --optim) - echo_optim=yes - ;; - --use-gl | --use-glut) - use_gl=yes - ;; - --use-forms) - use_forms=yes - ;; - --use-images) - use_images=yes - ;; - --use-cairo) - use_cairo=yes - ;; - --cflags) - echo_cflags=yes - ;; - --cxxflags) - echo_cxxflags=yes - ;; - --ldflags) - echo_ldflags=yes - ;; - --ldstaticflags) - echo_ldstaticflags=yes - ;; - --libs) - echo_libs=yes - ;; - --prefix) - echo_prefix=yes - ;; - --includedir) - echo_includedir=yes - ;; - -g) - debug=-g - ;; - -D*) - CXXFLAGS="$CXXFLAGS $1" - ;; - --compile) - compile="$2" - shift - ;; - --post) - post="$2" - shift - ;; - --link) - # linker flags and libs, allowed only after "--compile" - if test -n "$compile"; then - use_link=yes - else - echo_help=yes - fi - ;; - -*) - # additional compiler flags, allowed only after "--compile" - if test -n "$compile"; then - if test -n "$use_link"; then - link="$link $1" # flags and libs after "--link" - else - flags="$flags $1" # compiler flags like "-I..." - fi - else - echo_help=yes - fi - ;; - *) - # additional source files or libs, allowed only after "--compile" - if test -n "$compile"; then - if test -n "$use_link"; then - link="$link $1" # linker flag or library - else - files="$files $1" # other (source) files - fi - else - echo_help=yes - fi - ;; - esac - shift -done - -if test "$includedir" != /usr/include; then - includes="-I$includedir" -else - includes= -fi - -# prepend build directory for fltk-config in CMake build folder -if test -n "$BINARY_DIR"; then - includes="-I$BINARY_DIR $includes" -fi - -if test "$libdir" != /usr/lib -a "$libdir" != /usr/lib32; then - libs="-L$libdir" -else - libs= -fi - -# Calculate needed libraries -LDSTATIC="$libdir/libfltk.a $LDLIBS" -LDLIBS="-lfltk$SHAREDSUFFIX $LDLIBS" - -if test x$use_forms = xyes; then - LDLIBS="-lfltk_forms$SHAREDSUFFIX $LDLIBS" - LDSTATIC="$libdir/libfltk_forms.a $LDSTATIC" -fi - -if test x$use_gl = xyes; then - LDLIBS="-lfltk_gl$SHAREDSUFFIX $GLLIBS $LDLIBS" - LDSTATIC="$libdir/libfltk_gl.a $GLLIBS $LDSTATIC" -fi - -if test x$use_images = xyes; then - LDLIBS="-lfltk_images$SHAREDSUFFIX $IMAGELIBS $LDLIBS" - LDSTATIC="$libdir/libfltk_images.a $STATICIMAGELIBS $LDSTATIC" -fi - -if test x$use_cairo = xyes -a -n "$CAIROLIBS"; then - LDLIBS="$CAIROLIBS $LDLIBS" - LDSTATIC="$CAIROLIBS $LDSTATIC" -fi - -LDLIBS="$DSOLINK $LDFLAGS $libs $LDLIBS" -LDSTATIC="$LDFLAGS $LDSTATIC" - -# Answer to user requests -if test -n "$echo_help"; then - usage 1 -fi - -if test -n "$compile"; then - case "$compile" in - *.cxx) - prog="`basename \"$compile\" .cxx`" - ;; - *.cpp) - prog="`basename \"$compile\" .cpp`" - ;; - *.cc) - prog="`basename \"$compile\" .cc`" - ;; - *.C) - prog="`basename \"$compile\" .C`" - ;; - *) - echo "ERROR: Unknown/bad C++ source file extension on \"$compile\"!" - exit 1 - ;; - esac - - post="$prog" - - command="$CXX $ARCHFLAGS $includes $CXXFLAGS $debug -o $prog $flags $compile $files $LDSTATIC $link" - - echo $command - $command || exit 1 -fi - -if test -n "$post"; then - running=`uname` - if test "$running" = "Darwin"; then - # if FLTK targets macOS + X11, apps need not be bundled - if test `echo $LDLIBS | fgrep -c -e " -lX11"` = 1; then - running="" - fi - fi - case $running in - Darwin) - echo Creating "'$post.app'" bundle for desktop... - id=`echo $post | tr ' ' '_'` - - # Make the bundle directory and move the executable there - rm -rf "$post.app/Contents/MacOS" - mkdir -p "$post.app/Contents/MacOS" - mv "$post" "$post.app/Contents/MacOS" - - # Make a shell script that runs the bundled executable - echo "#!/bin/sh" >"$post" - echo 'dir="`dirname \"$0\"`"' >>"$post" - echo 'exec "$dir/'"$post.app/Contents/MacOS/$post"'" "$@"' >>"$post" - chmod +x "$post" - - # Make the simplest Info.plist needed for an application - cat >"$post.app/Contents/Info.plist" <<EOF -<?xml version="1.0" encoding="UTF-8"?> -<plist version="0.9"> - <dict> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleExecutable</key> - <string>$post</string> - <key>CFBundleIdentifier</key> - <string>org.fltk.$id</string> - <key>CFBundleName</key> - <string>$post</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>NSHighResolutionCapable</key> - <true/> - </dict> -</plist> -EOF - ;; - esac -fi - -if test "$echo_cflags" = "yes"; then - echo $includes $CFLAGS -fi - -if test "$echo_cxxflags" = "yes"; then - echo $includes $CXXFLAGS -fi - -if test "$echo_optim" = "yes"; then - echo $OPTIM -fi - -if test "$echo_ldflags" = "yes"; then - my_libs= - libdirs="$libs" - - for i in $LDLIBS ; do - if test $i != "-L$libdir" ; then - if test -z "$my_libs" ; then - my_libs="$i" - else - my_libs="$my_libs $i" - fi - fi - done - echo $libdirs $my_libs -fi - -if test "$echo_ldstaticflags" = "yes"; then - echo $LDSTATIC -fi - -if test "$echo_libs" = "yes"; then - USELIBS="$libdir/libfltk.a" - - if test x$use_forms = xyes; then - USELIBS="$libdir/libfltk_forms.a $USELIBS" - fi - - if test x$use_gl = xyes; then - USELIBS="$libdir/libfltk_gl.a $USELIBS" - fi - - if test x$use_images = xyes; then - USELIBS="$libdir/libfltk_images.a $USELIBS" - - for lib in fltk_jpeg fltk_png fltk_z; do - if test -f "$libdir/lib$lib.a"; then - USELIBS="$libdir/lib$lib.a $USELIBS" - fi - done - fi - - echo $USELIBS -fi - -if test "$echo_prefix" = "yes"; then - echo $prefix -fi - -if test "$echo_includedir" = "yes"; then - echo $includedir -fi diff --git a/fltk-options/CMakeLists.txt b/fltk-options/CMakeLists.txt deleted file mode 100644 index 3f7b1436e..000000000 --- a/fltk-options/CMakeLists.txt +++ /dev/null @@ -1,149 +0,0 @@ -# -# CMakeLists.txt to build fltk-options for the FLTK project using CMake (www.cmake.org) -# -# Copyright 2023-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Targets that will be built: fltk-options and fltk-options-cmd (Windows) -set(TARGETS "") - -if(APPLE AND NOT FLTK_BACKEND_X11) - set(BACKEND_APPLE TRUE) - set(ICON_NAME fltk-options.icns) - set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_NAME}") - list(APPEND SOURCES ${ICON_PATH}) -else() - set(BACKEND_APPLE FALSE) - set(ICON_NAME "") - set(ICON_PATH "") -endif() - -# This macro is used to avoid duplicate code to create executable programs. -# This must be a macro because it changes at least one global variable: TARGETS. -# This macro also uses some (local) variables defined above. -# In the future this might be converted to a function to avoid side effects. - -macro(make_target TARGET GUI SOURCES LIBS EXPORT_NAME) - - if(ICON_PATH) - list(APPEND SOURCES ${ICON_PATH}) # macOS only - endif() - - # message(STATUS "[fltk-options] make_target ${TARGET} ${GUI} ${SOURCES} ${LIBS} ${EXPORT_NAME}") - - # Options WIN32 and MACOSX_BUNDLE build a Windows GUI program or macOS bundle, - # respectively. Both options are ignored on other platforms. - - if(${GUI}) - add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${SOURCES}) - else() - add_executable(${TARGET} ${SOURCES}) - endif(${GUI}) - - list(APPEND TARGETS ${TARGET}) - - if(BACKEND_APPLE) - - # set bundle properties - set_target_properties(${TARGET} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}.plist") - set_target_properties(${TARGET} PROPERTIES MACOSX_BUNDLE_ICON_FILE ${ICON_NAME}) - set_target_properties(${TARGET} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "org.fltk.${TARGET}") - - # install command line tool - install(PROGRAMS $<TARGET_FILE:${TARGET}> - DESTINATION ${FLTK_BINDIR}) - - # create macOS bundle wrapper script - - set(WRAPPER "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/${TARGET}") - add_custom_command( - TARGET ${TARGET} POST_BUILD - COMMAND cp ${FLTK_SOURCE_DIR}/CMake/macOS-bundle-wrapper.in ${WRAPPER} - COMMAND chmod u+x,g+x,o+x ${WRAPPER} - BYPRODUCTS ${WRAPPER} - VERBATIM - ) - unset(WRAPPER) - - endif(BACKEND_APPLE) - - target_link_libraries(${TARGET} PRIVATE ${LIBS}) - set_target_properties(${TARGET} PROPERTIES EXPORT_NAME ${EXPORT_NAME}) - -endmacro(make_target TARGET GUI LIBS EXPORT_NAME) - -set(SOURCES fltk-options.cxx) - -make_target(fltk-options TRUE "${SOURCES}" fltk::fltk options) - -# Add the console app (Windows only) -# This is done for all Windows targets, even if cross-compiling. - -if(WIN32) - make_target(fltk-options-cmd FALSE "${SOURCES}" fltk::fltk options-cmd) -endif() - -# Add the "shared" executable (linked against the shared FLTK libs). -# Note 1: only the GUI version is built as "shared" executable. -# Note 2: For MSVC we need the special object library 'call_main'. - -if(FLTK_BUILD_SHARED_LIBS) - if(MSVC) - set(libs fltk::fltk-shared call_main) - else() - set(libs fltk::fltk-shared) - endif() - make_target(fltk-options-shared TRUE "${SOURCES}" "${libs}" options-shared) -endif() - -# Create aliases for all executables, -# replacing 'fltk-options' with 'fltk::options' - -foreach(tgt ${TARGETS}) - string(REPLACE "fltk-options" "fltk::options" alias ${tgt}) - add_executable(${alias} ALIAS ${tgt}) - unset(alias) -endforeach() - -# Install fltk-options GUI and commandline tool - -# Install the GUI and (on Windows only) the commandline tool 'fltk-options-cmd' -# message(STATUS "fltk-options: INSTALL TARGETS: ${TARGETS}") - -install(TARGETS ${TARGETS} - EXPORT FLTK-Targets - RUNTIME DESTINATION ${FLTK_BINDIR} - LIBRARY DESTINATION ${FLTK_LIBDIR} - ARCHIVE DESTINATION ${FLTK_LIBDIR} - BUNDLE DESTINATION ${FLTK_BINDIR} # macOS: bundles -) - -# Install desktop files - -if(UNIX) - install(FILES fltk-options.desktop - DESTINATION ${FLTK_DATADIR}/applications - ) - # Install mime-type file(x-fltk-options.desktop method is deprecated) - install(FILES fltk-options.xml - DESTINATION ${FLTK_DATADIR}/mime/packages - ) - - # Install desktop icons - foreach(icon 32 48 64 128) - install(FILES icons/fltk-options-${icon}.png - DESTINATION ${FLTK_DATADIR}/icons/hicolor/${icon}x${icon}/apps - RENAME fltk-options.png - ) - endforeach() -endif(UNIX) diff --git a/fluid/CMakeLists.txt b/fluid/CMakeLists.txt deleted file mode 100644 index 9eeec492b..000000000 --- a/fluid/CMakeLists.txt +++ /dev/null @@ -1,306 +0,0 @@ -# -# CMakeLists.txt to build fluid for the FLTK project using CMake (www.cmake.org) -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Targets that will be built: fluid and fluid-cmd (Windows) - -# Targets that will be built: fluid, fluid-shared, and fluid-cmd (Windows only) -set(TARGETS "") - -# Defaults to be used and potentially modified later - -set(BACKEND_APPLE FALSE) # FIXME: should be global, e.g. FLTK_BACKEND_APPLE -set(ICON_NAME "") -set(ICON_PATH "") -set(SUFFIX "UNIX") # suffix for platform specific source files - -# platform specific settings - -if(APPLE AND NOT FLTK_BACKEND_X11) # macOS "native" - set(BACKEND_APPLE TRUE) - set(ICON_NAME fluid.icns) - set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_NAME}") -elseif(WIN32) - set(SUFFIX "WIN32") -endif() - -# This macro is used to avoid duplicate code to create executable programs. -# This must be a macro because it changes at least one global variable: TARGETS. -# This macro also uses some (local) variables defined above. -# In the future this might be converted to a function to avoid side effects. - -macro(make_target TARGET GUI SOURCES LIBS EXPORT_NAME) - - if(ICON_PATH) - list(APPEND SOURCES ${ICON_PATH}) # macOS only - endif() - - # message(STATUS "[fluid] make_target ${TARGET} ${GUI} ${SOURCES} ${LIBS} ${EXPORT_NAME}") - - # Options WIN32 and MACOSX_BUNDLE build a Windows GUI program or macOS bundle, - # respectively. Both options are ignored on other platforms. - - if(${GUI}) - add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${SOURCES}) - else() - add_executable(${TARGET} ${SOURCES}) - endif(${GUI}) - - list(APPEND TARGETS ${TARGET}) - - if(BACKEND_APPLE) - - # set bundle properties - set_target_properties(${TARGET} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}.plist") - set_target_properties(${TARGET} PROPERTIES MACOSX_BUNDLE_ICON_FILE ${ICON_NAME}) - set_target_properties(${TARGET} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "org.fltk.${TARGET}") - - # install command line tool - install(PROGRAMS $<TARGET_FILE:${TARGET}> - DESTINATION ${FLTK_BINDIR}) - - # create macOS bundle wrapper script - - set(WRAPPER "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/${TARGET}") - add_custom_command( - TARGET ${TARGET} POST_BUILD - COMMAND cp ${FLTK_SOURCE_DIR}/CMake/macOS-bundle-wrapper.in ${WRAPPER} - COMMAND chmod u+x,g+x,o+x ${WRAPPER} - BYPRODUCTS ${WRAPPER} - VERBATIM - ) - unset(WRAPPER) - - endif(BACKEND_APPLE) - - target_link_libraries(${TARGET} PRIVATE ${LIBS}) - set_target_properties(${TARGET} PROPERTIES EXPORT_NAME ${EXPORT_NAME}) - -endmacro(make_target TARGET GUI SOURCES LIBS EXPORT_NAME) - - -# Main source and header files used for the executable because macOS (Xcode) -# needs at least one source file (main.cxx) to link the main program properly - -set(MAIN_FILES main.cxx main.h) - -# Source files for 'fluid-lib': all source files except ${MAIN_FILES} - -set(CPPFILES - Fluid.cxx - Project.cxx - app/args.cxx - app/Snap_Action.cxx - app/Image_Asset.cxx - app/history.cxx - app/Menu.cxx - app/shell_command.cxx - app/templates.cxx - io/Code_Writer.cxx - io/Project_Writer.cxx - io/Project_Reader.cxx - io/String_Writer.cxx - nodes/Tree.cxx - nodes/Button_Node.cxx - nodes/Function_Node.cxx - nodes/Grid_Node.cxx - nodes/Group_Node.cxx - nodes/Menu_Node.cxx - nodes/Node.cxx - nodes/Widget_Node.cxx - nodes/Window_Node.cxx - nodes/callbacks.cxx - nodes/factory.cxx - panels/about_panel.cxx - panels/codeview_panel.cxx - panels/function_panel.cxx - panels/settings_panel.cxx - panels/template_panel.cxx - panels/widget_panel.cxx - panels/widget_panel/Grid_Tab.cxx - panels/widget_panel/Grid_Child_Tab.cxx - proj/align_widget.cxx - proj/i18n.cxx - proj/mergeback.cxx - proj/undo.cxx - rsrcs/pixmaps.cxx - tools/ExternalCodeEditor_${SUFFIX}.cxx - tools/autodoc.cxx - tools/filename.cxx - widgets/App_Menu_Bar.cxx - widgets/Code_Editor.cxx - widgets/Code_Viewer.cxx - widgets/Text_Viewer.cxx - widgets/Formula_Input.cxx - widgets/Bin_Button.cxx - widgets/Style_Parser.cxx - widgets/Node_Browser.cxx -) - -# List header files in Apple's Xcode IDE - -set(HEADERFILES - Fluid.h - Project.h - app/args.h - app/Snap_Action.h - app/Image_Asset.h - app/history.h - app/Menu.h - app/shell_command.h - app/templates.h - io/Code_Writer.h - io/Project_Writer.h - io/Project_Reader.h - io/String_Writer.h - nodes/Tree.h - nodes/Button_Node.h - nodes/Function_Node.h - nodes/Grid_Node.h - nodes/Group_Node.h - nodes/Menu_Node.h - nodes/Node.h - nodes/Widget_Node.h - nodes/Window_Node.h - nodes/callbacks.h - nodes/factory.h - panels/about_panel.h - panels/codeview_panel.h - panels/function_panel.h - panels/settings_panel.h - panels/template_panel.h - panels/widget_panel.h - panels/widget_panel/Grid_Tab.h - panels/widget_panel/Grid_Child_Tab.h - proj/align_widget.h - proj/mergeback.h - proj/i18n.h - proj/undo.h - rsrcs/comments.h - rsrcs/pixmaps.h - tools/ExternalCodeEditor_${SUFFIX}.h - tools/autodoc.h - tools/filename.h - widgets/App_Menu_Bar.h - widgets/Code_Editor.h - widgets/Code_Viewer.h - widgets/Text_Viewer.h - widgets/Formula_Input.h - widgets/Bin_Button.h - widgets/Style_Parser.h - widgets/Node_Browser.h -) - -source_group( - TREE - ${CMAKE_CURRENT_SOURCE_DIR} - FILES - ${CPPFILES} - ${HEADERFILES} - ${MAIN_FILES} - CMakeLists.txt -) - -# Build a local object library to avoid compiling all source files -# multiple times for all fluid targets on Windows (fluid + fluid-cmd). - -add_library(fluid-lib OBJECT EXCLUDE_FROM_ALL) -target_sources(fluid-lib PRIVATE ${CPPFILES} ${HEADERFILES}) -target_include_directories(fluid-lib PUBLIC .) -target_link_libraries(fluid-lib PUBLIC fltk::images) - -# Build targets - -make_target(fluid TRUE "${MAIN_FILES}" fluid-lib fluid) - -# Build the console app on Windows -# This is done for all Windows targets, even if cross-compiling. - -if(WIN32) - make_target(fluid-cmd FALSE "${MAIN_FILES}" fluid-lib fluid-cmd) - set(FLTK_FLUID_EXECUTABLE fltk::fluid-cmd) -else() - set(FLTK_FLUID_EXECUTABLE fltk::fluid) -endif() - -# Add the "shared" executable (linked against the shared FLTK libs). -# Note 1: only the GUI version is built as "shared" executable. -# Note 2: For MSVC we need the special object library 'call_main'. - -if(FLTK_BUILD_SHARED_LIBS) - - add_library(fluid-lib-shared OBJECT EXCLUDE_FROM_ALL) - target_sources(fluid-lib-shared PRIVATE ${CPPFILES} ${HEADERFILES}) - target_include_directories(fluid-lib-shared PUBLIC .) - if(MSVC) - target_link_libraries(fluid-lib-shared PUBLIC fltk::fltk-shared) - else() - target_link_libraries(fluid-lib-shared PUBLIC fltk::images-shared) - endif(MSVC) - - if(MSVC) - make_target(fluid-shared TRUE "${MAIN_FILES}" "fluid-lib-shared;call_main" fluid-shared) - else() - make_target(fluid-shared TRUE "${MAIN_FILES}" fluid-lib-shared fluid-shared) - endif() - - # experimental - # if(NOT WIN32) - # set(FLTK_FLUID_EXECUTABLE fltk::fluid-shared) - # message(STATUS "** experimental ** FLTK_FLUID_EXECUTABLE = ${FLTK_FLUID_EXECUTABLE}") - # endif() - -endif(FLTK_BUILD_SHARED_LIBS) - -# export the variable FLTK_FLUID_EXECUTABLE to the parent scope - -set(FLTK_FLUID_EXECUTABLE "${FLTK_FLUID_EXECUTABLE}" PARENT_SCOPE) - -# Create aliases for all targets - -foreach(tgt ${TARGETS}) - add_executable(fltk::${tgt} ALIAS ${tgt}) -endforeach() - -# Install the GUI and (on Windows only) the commandline tool 'fluid-cmd' -# message(STATUS "Fluid: INSTALL TARGETS: ${TARGETS}") - -install(TARGETS ${TARGETS} - EXPORT FLTK-Targets - RUNTIME DESTINATION ${FLTK_BINDIR} - LIBRARY DESTINATION ${FLTK_LIBDIR} - ARCHIVE DESTINATION ${FLTK_LIBDIR} - BUNDLE DESTINATION ${FLTK_BINDIR} # macOS: bundles -) - -# Install desktop files - -if(UNIX) - install(FILES fluid.desktop - DESTINATION ${FLTK_DATADIR}/applications - ) - # Install mime-type file(x-fluid.desktop method is deprecated) - install(FILES fluid.xml - DESTINATION ${FLTK_DATADIR}/mime/packages - ) - - # Install desktop icons - foreach(icon 32 48 64 128) - install(FILES icons/fluid-${icon}.png - DESTINATION ${FLTK_DATADIR}/icons/hicolor/${icon}x${icon}/apps - RENAME fluid.png - ) - endforeach() -endif(UNIX) diff --git a/fluid/documentation/CMakeLists.txt b/fluid/documentation/CMakeLists.txt deleted file mode 100644 index 3bbdcd755..000000000 --- a/fluid/documentation/CMakeLists.txt +++ /dev/null @@ -1,224 +0,0 @@ -# -# CMakeLists.txt to build docs for the FLTK project using CMake (www.cmake.org) -# -# Copyright 1998-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -set(DOCS) -set(GIT_REVISION "") -set(YEAR "") -set(CURRENT_DATE "") - -#------------------------------------------------ -# generate files used for both HTML and PDF docs -#------------------------------------------------ - -if(FLTK_BUILD_FLUID_DOCS OR FLTK_BUILD_PDF_DOCS) - - # create required variables - - string(TIMESTAMP YEAR "%Y" UTC) - - # note: current locale is used for abbreviated month - string(TIMESTAMP CURRENT_DATE "%b %d, %Y" UTC) - string(TIMESTAMP PDF_DATE "D:%Y%m%d%H%M%SZ" UTC) - string(TIMESTAMP TODAY "%B %d, %Y" UTC) - string(REPLACE " 0" " " TODAY "${TODAY}") - - # Find "short" doxygen version if it was built from Git - # Note: this is still needed in CMake 3.15 but later CMake versions - # (notably 3.25) remove the Git revision in 'DOXYGEN_VERSION'. - # Todo: Find the "first good" CMake version and remove this redundant - # code once we require this as our minimal version and replace the - # variable DOXYGEN_VERSION_SHORT with DOXYGEN_VERSION below. - - if(DOXYGEN_FOUND) - # strip trailing git revision if doxygen was built from source - string(REGEX REPLACE " .*$" "" DOXYGEN_VERSION_SHORT ${DOXYGEN_VERSION}) - endif(DOXYGEN_FOUND) - - # configure version.dox (includes the bare FLTK version number) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/version.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/version.dox - @ONLY - ) - - # configure copyright.dox (includes current year) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/copyright.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/copyright.dox - @ONLY - ) - - # configure generated.dox (includes date and versions) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/generated.dox.in - ${CMAKE_CURRENT_BINARY_DIR}/generated.dox - @ONLY - ) - -endif(FLTK_BUILD_FLUID_DOCS OR FLTK_BUILD_PDF_DOCS) - -#------------------------------- -# build FLUID html documentation -#------------------------------- - -if(FLTK_BUILD_FLUID_DOCS) - - #list(APPEND DOCS html) - - # generate Doxygen file "Doxyfile" - - set(GENERATE_FLUID_HTML YES) - set(GENERATE_LATEX NO) - set(LATEX_HEADER "") - set(FL_HTML_INDEX "FL_HTML_INDEX") - set(DOXYFILE "Doxyfile") - set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log") - - # configure Doxygen input file for HTML docs (Doxyfile.in) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in - @ONLY - ) - - # convert Doxyfile to used doxygen version - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile - ${DOXYGEN_EXECUTABLE} - ${DOXYFILE}.in - ${DOXYFILE} - ${LOGFILE} - BYPRODUCTS ${LOGFILE} - COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM - ) - - # generate screen shot using FLUID --autodoc target_dir - # generate HTML documentation - - add_custom_target(fluid_docs - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/src/ - COMMAND fltk::fluid -scheme gtk+ --autodoc ${CMAKE_CURRENT_BINARY_DIR}/src/ - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating HTML documentation" VERBATIM - ) - add_dependencies(fluid_docs fltk::fluid) - -endif(FLTK_BUILD_FLUID_DOCS) - -#-------------------------- -# build pdf documentation -#-------------------------- - -if(FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS) - - # generate Doxygen input file "Doxybook" - - set(GENERATE_FLUID_HTML NO) - set(GENERATE_LATEX YES) - set(LATEX_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fluid-book.tex") - set(FL_HTML_INDEX "FL_NO_HTML_INDEX") - set(DOXYFILE "Doxybook") - set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log") - - # configure Doxygen input file for PDF docs (Doxybook.in) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in - @ONLY - ) - - # convert Doxybook to current doxygen version - - set(DOXY_VERSION "${DOXYGEN_VERSION_SHORT}") # - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile - ${DOXYGEN_EXECUTABLE} - ${DOXYFILE}.in - ${DOXYFILE} - ${LOGFILE} - BYPRODUCTS ${LOGFILE} - COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM - ) - - # generate LaTeX title fluid-title.tex - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/src/fluid-title.tex.in - ${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex - @ONLY - ) - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/make_pdf.in - ${CMAKE_CURRENT_BINARY_DIR}/make_pdf - @ONLY - ) - - # generate fluid.pdf - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header - ${DOXYGEN_EXECUTABLE} - ${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex - ${CMAKE_CURRENT_BINARY_DIR}/fluid-book.tex - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/make_pdf - COMMAND cp -f latex/refman.pdf fluid.pdf - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} - ${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating FLUID PDF documentation" VERBATIM - ) - - # add target 'pdf' - - add_custom_target(fluid_pdf - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf - ) - add_dependencies(fluid_pdf fluid_docs) - -endif(FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS) - -#--------------------------------------- -# install FLUID html + pdf documentation -#--------------------------------------- - -if(FLTK_INSTALL_FLUID_DOCS AND FLTK_BUILD_FLUID_DOCS) - - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html - DESTINATION ${FLTK_DATADIR}/doc/fltk/fluid - ) - -endif(FLTK_INSTALL_FLUID_DOCS AND FLTK_BUILD_FLUID_DOCS) - -if(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS) - - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf - DESTINATION ${FLTK_DATADIR}/doc/fltk/ - ) - -endif(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS) diff --git a/jpeg/CMakeLists.txt b/jpeg/CMakeLists.txt deleted file mode 100644 index c1ec4fae8..000000000 --- a/jpeg/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ -# -# JPEG library CMake configuration for the Fast Light Toolkit (FLTK). -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# memmgr back ends: compile only one of these into a working library -# (For now, let's use the mode that requires the image fit into memory. -# This is the recommended mode for Win32 anyway.) - -set(systemdependent_SRCS jmemnobs.c) - -# library object files common to compression and decompression - -set(common_SRCS - jaricom.c jcomapi.c jutils.c jerror.c jmemmgr.c -) - -# compression library object files - -set(compression_SRCS - jcapimin.c jcapistd.c jcarith.c jctrans.c jcparam.c jdatadst.c jcinit.c - jcmaster.c jcmarker.c jcmainct.c jcprepct.c jccoefct.c jccolor.c - jcsample.c jchuff.c jcdctmgr.c jfdctfst.c jfdctflt.c - jfdctint.c -) - -# decompression library object files - -set(decompression_SRCS - jdapimin.c jdapistd.c jdarith.c jdtrans.c jdatasrc.c jdmaster.c - jdinput.c jdmarker.c jdhuff.c jdmainct.c jdcoefct.c - jdpostct.c jddctmgr.c jidctfst.c jidctflt.c jidctint.c - jdsample.c jdcolor.c jquant1.c jquant2.c jdmerge.c -) - -list(APPEND BUILD_SRCS "${systemdependent_SRCS};${common_SRCS}") -list(APPEND BUILD_SRCS "${compression_SRCS};${decompression_SRCS}") - -####################################################################### -# Set common variables for static and shared builds -####################################################################### - -set(_include_dirs - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> - $<INSTALL_INTERFACE:include> -) - -# Suppress Visual Studio compiler warnings - -set(msvc_warnings /wd4267) - -####################################################################### -# Build the static library -####################################################################### - -fl_add_library(fltk_jpeg STATIC "${BUILD_SRCS}") -set(target fltk_jpeg) - -target_include_directories(${target} PUBLIC ${_include_dirs}) - -if(MSVC) - target_compile_options(${target} PRIVATE ${msvc_warnings}) -endif(MSVC) - -list(APPEND FLTK_IMAGE_LIBRARIES fltk::jpeg) - -# Propagate to parent scope (modified by fl_add_library and here) -set(FLTK_LIBRARIES ${FLTK_LIBRARIES} PARENT_SCOPE) -set(FLTK_IMAGE_LIBRARIES ${FLTK_IMAGE_LIBRARIES} PARENT_SCOPE) - -####################################################################### -# Build the shared library (optional) -####################################################################### - -if(FLTK_BUILD_SHARED_LIBS) - - # ensure to export all symbols for Windows DLL's - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) - - fl_add_library(fltk_jpeg SHARED "${BUILD_SRCS}") - set(target fltk_jpeg-shared) - - target_include_directories(${target} PUBLIC ${_include_dirs}) - - if(MSVC) - target_compile_options(${target} PRIVATE ${msvc_warnings}) - endif(MSVC) - - list(APPEND FLTK_IMAGE_LIBRARIES_SHARED fltk::jpeg-shared) - - # Propagate to parent scope (modified by fl_add_library and here) - set(FLTK_LIBRARIES_SHARED ${FLTK_LIBRARIES_SHARED} PARENT_SCOPE) - set(FLTK_IMAGE_LIBRARIES_SHARED ${FLTK_IMAGE_LIBRARIES_SHARED} PARENT_SCOPE) - -endif(FLTK_BUILD_SHARED_LIBS) - -####################################################################### -# Install the library headers -####################################################################### - -install(FILES - jconfig.h jerror.h jmorecfg.h jpeglib.h fltk_jpeg_prefix.h - DESTINATION - ${FLTK_INCLUDEDIR}/FL/images -) diff --git a/lib/libfltk 3.a b/lib/libfltk 3.a Binary files differnew file mode 100644 index 000000000..8044fca12 --- /dev/null +++ b/lib/libfltk 3.a diff --git a/lib/libfltk.a b/lib/libfltk.a Binary files differnew file mode 100644 index 000000000..9e8158a99 --- /dev/null +++ b/lib/libfltk.a diff --git a/lib/libfltk_forms 3.a b/lib/libfltk_forms 3.a Binary files differnew file mode 100644 index 000000000..2a29f6921 --- /dev/null +++ b/lib/libfltk_forms 3.a diff --git a/lib/libfltk_forms.a b/lib/libfltk_forms.a Binary files differnew file mode 100644 index 000000000..37c34d0d0 --- /dev/null +++ b/lib/libfltk_forms.a diff --git a/lib/libfltk_gl 3.a b/lib/libfltk_gl 3.a Binary files differnew file mode 100644 index 000000000..9b80cb7b4 --- /dev/null +++ b/lib/libfltk_gl 3.a diff --git a/lib/libfltk_gl.a b/lib/libfltk_gl.a Binary files differnew file mode 100644 index 000000000..a9e265e32 --- /dev/null +++ b/lib/libfltk_gl.a diff --git a/lib/libfltk_images 3.a b/lib/libfltk_images 3.a Binary files differnew file mode 100644 index 000000000..346ed5b38 --- /dev/null +++ b/lib/libfltk_images 3.a diff --git a/lib/libfltk_images.a b/lib/libfltk_images.a Binary files differnew file mode 100644 index 000000000..a159c246c --- /dev/null +++ b/lib/libfltk_images.a diff --git a/lib/libfltk_jpeg 3.a b/lib/libfltk_jpeg 3.a Binary files differnew file mode 100644 index 000000000..556409145 --- /dev/null +++ b/lib/libfltk_jpeg 3.a diff --git a/lib/libfltk_jpeg.a b/lib/libfltk_jpeg.a Binary files differnew file mode 100644 index 000000000..81e4e9e2c --- /dev/null +++ b/lib/libfltk_jpeg.a diff --git a/lib/libfltk_png 3.a b/lib/libfltk_png 3.a Binary files differnew file mode 100644 index 000000000..a9d49f8a9 --- /dev/null +++ b/lib/libfltk_png 3.a diff --git a/lib/libfltk_png.a b/lib/libfltk_png.a Binary files differnew file mode 100644 index 000000000..71340d024 --- /dev/null +++ b/lib/libfltk_png.a diff --git a/lib/libfltk_z 3.a b/lib/libfltk_z 3.a Binary files differnew file mode 100644 index 000000000..ace4e51b0 --- /dev/null +++ b/lib/libfltk_z 3.a diff --git a/lib/libfltk_z.a b/lib/libfltk_z.a Binary files differnew file mode 100644 index 000000000..2a73c558e --- /dev/null +++ b/lib/libfltk_z.a diff --git a/libdecor/LICENSE b/libdecor/LICENSE deleted file mode 100644 index 9cf106272..000000000 --- a/libdecor/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/libdecor/README.md b/libdecor/README.md deleted file mode 100644 index 83234c7ee..000000000 --- a/libdecor/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# libdecor - A client-side decorations library for Wayland client - -libdecor is a library that can help Wayland clients draw window -decorations for them. It aims to provide multiple backends that implements the -decoration drawing. - - -## Dependencies - -Required: -- `meson` >= 0.47 -- `ninja` -- `wayland-client` >= 1.18 -- `wayland-protocols` >= 1.15 -- `wayland-cursor` -- `cairo` -- `pangocairo` - -Recommended: -- `dbus-1` (to query current cursor theme) - -Optional -- `egl` (to build EGL example) -- `opengl` -- `xkbcommon` (to build cairo demo) - -Install via apt: -`sudo apt install meson libwayland-dev wayland-protocols libpango1.0-dev libdbus-1-dev libegl-dev libopengl-dev libxkbcommon-dev` - -Install via dnf: -`sudo dnf install meson wayland-devel wayland-protocols-devel pango-devel dbus-devel mesa-libEGL-devel libglvnd-devel libxkbcommon-devel` - -Newer meson versions can be installed via pip: `pip3 install -U meson`. - -## Build & Install - -### Quick Start - -To build and run the example program: -1. `meson build -Dinstall_demo=true && meson compile -C build` -2. `meson devenv -C build libdecor-demo` - -### Release Builds - -The library and default plugins can be built and installed via: -1. `meson build --buildtype release` -2. `meson install -C build` - -where `build` is the build directory that will be created during this process. - -This will install by default to `/usr/local/`. To change this set the `prefix` during built, e.g. `meson build --buildtype release -Dprefix=$HOME/.local/`. - -Plugins will be installed into the same directory and from thereon will be selected automatically depending on their precedence. This behaviour can be overridden at runtime by setting the environment variable `LIBDECOR_PLUGIN_DIR` and pointing it to a directory with a valid plugin. - -### Debug and Development Builds - -During development and when debugging, it is recommended to enable the AddressSanitizer and increase the warning level: -1. `meson build -Dinstall_demo=true -Db_sanitize=address -Dwarning_level=3` -2. `meson compile -C build` - -You may have to install `libasan6` (apt) or `libasan` (dnf). Otherwise linking will fail. - -By default `libdecor` will look for plugins in the target directory of the installation. Therefore, when running the demos directly from the `build` directory, no plugins will be found and the fallback plugin without any decorations will be used. - -On Meson 0.58.0 and above, this can be corrected using `devenv`, i.e., to run the demo: - -`meson devenv -C build libdecor-demo` - -On older Meson versions, the search path for plugins can be overridden by the environment variable `LIBDECOR_PLUGIN_DIR`. To use the `cairo` plugin, point to the plugin directory: - -`export LIBDECOR_PLUGIN_DIR=build/src/plugins/cairo/` - -and run the demo: - -`./build/demo/libdecor-demo`. - - -### Code of Conduct - -libdecor follows the Contributor Covenant, found at: -https://www.freedesktop.org/wiki/CodeOfConduct - -Please conduct yourself in a respectful and civilised manner when interacting -with community members on mailing lists, IRC, or bug trackers. The community -represents the project as a whole, and abusive or bullying behaviour is not -tolerated by the project. diff --git a/libdecor/build/fl_libdecor-plugins.c b/libdecor/build/fl_libdecor-plugins.c deleted file mode 100644 index 4197ea8f0..000000000 --- a/libdecor/build/fl_libdecor-plugins.c +++ /dev/null @@ -1,311 +0,0 @@ -// -// Interface with the libdecor library for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/* Support of interactions between FLTK and libdecor plugins, either dynamically - loaded by dlopen() or built-in FLTK. - - Under USE_SYSTEM_LIBDECOR, the plugin can only be dynamically loaded. - Under ! USE_SYSTEM_LIBDECOR, it can be dynamically loaded from a directory - given in environment variable LIBDECOR_PLUGIN_DIR, or the built-in one is used. - */ - -#include <dlfcn.h> -#include <string.h> -#include "fl_libdecor.h" -#include <pango/pangocairo.h> -#include <dlfcn.h> - -#ifndef HAVE_GTK -# define HAVE_GTK 0 -#endif - -enum plugin_kind { UNKNOWN, SSD, CAIRO, GTK3 }; - -#if USE_SYSTEM_LIBDECOR -# include "../src/libdecor-plugin.h" - -enum component {NONE}; /* details are not necessary*/ -enum decoration_type {DECORATION_TYPE_NONE}; /* details are not necessary*/ - -struct buffer { // identical in libdecor-cairo.c and libdecor-gtk.c - struct wl_buffer *wl_buffer; - bool in_use; - bool is_detached; - - void *data; - size_t data_size; - int width; - int height; - int scale; - int buffer_width; - int buffer_height; -}; - -#else // !USE_SYSTEM_LIBDECOR - -const struct libdecor_plugin_description *fl_libdecor_plugin_description = NULL; - -# if HAVE_GTK -# include "../src/plugins/gtk/libdecor-gtk.c" -# else -# include "../src/plugins/cairo/libdecor-cairo.c" -# endif // HAVE_GTK - -#endif // USE_SYSTEM_LIBDECOR - - -#if USE_SYSTEM_LIBDECOR || HAVE_GTK -/* these definitions derive from libdecor/src/plugins/cairo/libdecor-cairo.c */ - -enum composite_mode {COMPOSITE_SERVER}; /* details are not necessary*/ - -struct border_component_cairo { - enum component type; - - bool is_hidden; - bool opaque; - - enum composite_mode composite_mode; - struct { - struct wl_surface *wl_surface; - struct wl_subsurface *wl_subsurface; - struct buffer *buffer; - struct wl_list output_list; - int scale; - } server; - struct { - cairo_surface_t *image; - struct border_component_cairo *parent_component; - } client; - - struct wl_list child_components; /* border_component::link */ - struct wl_list link; /* border_component::child_components */ -}; - -struct libdecor_frame_cairo { - struct libdecor_frame frame; - - struct libdecor_plugin_cairo *plugin_cairo; - - int content_width; - int content_height; - - enum decoration_type decoration_type; - - enum libdecor_window_state window_state; - - char *title; - - enum libdecor_capabilities capabilities; - - struct border_component_cairo *focus; - struct border_component_cairo *active; - struct border_component_cairo *grab; - - bool shadow_showing; - struct border_component_cairo shadow; - - struct { - bool is_showing; - struct border_component_cairo title; - struct border_component_cairo min; - struct border_component_cairo max; - struct border_component_cairo close; - } title_bar; - - /* store pre-processed shadow tile */ - cairo_surface_t *shadow_blur; - - struct wl_list link; -}; -#endif // USE_SYSTEM_LIBDECOR || HAVE_GTK - - -#if USE_SYSTEM_LIBDECOR || !HAVE_GTK - -/* Definitions derived from libdecor-gtk.c */ - -typedef struct _GtkWidget GtkWidget; -enum header_element { HEADER_NONE }; /* details are not needed */ - -typedef enum { GTK_STATE_FLAG_NORMAL = 0 } GtkStateFlags; - -struct border_component_gtk { - enum component type; - struct wl_surface *wl_surface; - struct wl_subsurface *wl_subsurface; - struct buffer *buffer; - bool opaque; - struct wl_list output_list; - int scale; - struct wl_list child_components; /* border_component::link */ - struct wl_list link; /* border_component::child_components */ -}; - -struct header_element_data { - const char* name; - enum header_element type; - GtkWidget *widget; - GtkStateFlags state; -}; - -struct libdecor_frame_gtk { - struct libdecor_frame frame; - struct libdecor_plugin_gtk *plugin_gtk; - int content_width; - int content_height; - enum libdecor_window_state window_state; - enum decoration_type decoration_type; - char *title; - enum libdecor_capabilities capabilities; - struct border_component_gtk *active; - struct border_component_gtk *touch_active; - struct border_component_gtk *focus; - struct border_component_gtk *grab; - bool shadow_showing; - struct border_component_gtk shadow; - GtkWidget *window; /* offscreen window for rendering */ - GtkWidget *header; /* header bar with widgets */ - struct border_component_gtk headerbar; - struct header_element_data hdr_focus; - cairo_surface_t *shadow_blur; - struct wl_list link; - struct { - enum titlebar_gesture_state {TITLEBAR_GESTURE_STATE_INIT} state; - int button_pressed_count; - uint32_t first_pressed_button; - uint32_t first_pressed_time; - double pressed_x; - double pressed_y; - uint32_t pressed_serial; - } titlebar_gesture; -}; - -#endif // USE_SYSTEM_LIBDECOR || !HAVE_GTK - - -static unsigned char *gtk_titlebar_buffer(struct libdecor_frame *frame, - int *width, int *height, int *stride) -{ - struct libdecor_frame_gtk *lfg = (struct libdecor_frame_gtk *)frame; - struct buffer *buffer = lfg->headerbar.buffer; - *width = buffer->buffer_width; - *height = buffer->buffer_height; - *stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width); - return (unsigned char*)buffer->data; -} - - -static unsigned char *cairo_titlebar_buffer(struct libdecor_frame *frame, - int *width, int *height, int *stride) -{ - struct libdecor_frame_cairo *lfc = (struct libdecor_frame_cairo *)frame; - struct buffer *buffer = lfc->title_bar.title.server.buffer; - *width = buffer->buffer_width; - *height = buffer->buffer_height; - *stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width); - return (unsigned char*)buffer->data; -} - - -/* - Although each plugin declares an exported global variable - LIBDECOR_EXPORT const struct libdecor_plugin_description libdecor_plugin_description; - these plugins are dlopen()'ed in libdecor.c without the RTLD_GLOBAL flag. - Consequently their symbols are not discovered by dlsym(RTLD_DEFAULT, "symbol-name"). - - Under USE_SYSTEM_LIBDECOR, we repeat the dlopen() for the same plugin - then dlsym() will report the address of libdecor_plugin_description. - - Under !USE_SYSTEM_LIBDECOR, we compile fl_libdecor.c which modifies the dlopen() - to call dlsym(ld, "libdecor_plugin_description") just after the dlopen and memorizes - this address. - - A plugin is loaded also if SSD. - KWin has its own size limit, similar to that of GDK plugin - */ -static const char *get_libdecor_plugin_description() { - static const struct libdecor_plugin_description *plugin_description = NULL; - if (!plugin_description) { -#if USE_SYSTEM_LIBDECOR - char fname[PATH_MAX]; - const char *dir = getenv("LIBDECOR_PLUGIN_DIR"); - if (!dir) dir = LIBDECOR_PLUGIN_DIR; - snprintf(fname, PATH_MAX, "%s/libdecor-gtk.so", dir); - void *dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL); - if (!dl) { - snprintf(fname, PATH_MAX, "%s/libdecor-cairo.so", dir); - dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL); - } - if (dl) plugin_description = (const struct libdecor_plugin_description*)dlsym(dl, "libdecor_plugin_description"); -#else - plugin_description = fl_libdecor_plugin_description; - extern const struct libdecor_plugin_description libdecor_plugin_description; - if (!plugin_description) plugin_description = &libdecor_plugin_description; -#endif - //if (plugin_description) puts(plugin_description->description); - } - return plugin_description ? plugin_description->description : NULL; -} - - -static enum plugin_kind get_plugin_kind(struct libdecor_frame *frame) { - static enum plugin_kind kind = UNKNOWN; - if (kind == UNKNOWN) { - if (frame) { - int X, Y = 0; - libdecor_frame_translate_coordinate(frame, 0, 0, &X, &Y); - if (Y == 0) { - return SSD; - } - } - const char *name = get_libdecor_plugin_description(); - if (name && !strcmp(name, "GTK3 plugin")) kind = GTK3; - else if (name && !strcmp(name, "libdecor plugin using Cairo")) kind = CAIRO; - } - return kind; -} - -/* - FLTK-added utility function to give access to the pixel array representing - the titlebar of a window decorated by the cairo plugin of libdecor. - frame: a libdecor-defined pointer given by fl_xid(win)->frame (with Fl_Window *win); - *width, *height: returned assigned to the width and height in pixels of the titlebar; - *stride: returned assigned to the number of bytes per line of the pixel array; - return value: start of the pixel array, which is in BGRA order, or NULL. - */ -unsigned char *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame, - int *width, int *height, int *stride) -{ - enum plugin_kind kind = get_plugin_kind(frame); - if (kind == GTK3) { - return gtk_titlebar_buffer(frame, width, height, stride); - } - else if (kind == CAIRO) { - return cairo_titlebar_buffer(frame, width, height, stride); - } - return NULL; -} - - -/* Returns whether surface is the libdecor-created GTK-titlebar of frame */ -bool fl_is_surface_from_GTK_titlebar (struct wl_surface *surface, struct libdecor_frame *frame, - bool *using_GTK) { - *using_GTK = (get_plugin_kind(NULL) == GTK3); - if (!*using_GTK) return false; - struct libdecor_frame_gtk *frame_gtk = (struct libdecor_frame_gtk*)frame; - return (frame_gtk->headerbar.wl_surface == surface); -} diff --git a/libdecor/build/fl_libdecor.c b/libdecor/build/fl_libdecor.c deleted file mode 100644 index c7105bd85..000000000 --- a/libdecor/build/fl_libdecor.c +++ /dev/null @@ -1,145 +0,0 @@ -// -// Interface with the libdecor library for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/* Improvements to libdecor.c without modifying libdecor.c itself */ -#if ! USE_SYSTEM_LIBDECOR - -#include <dlfcn.h> -#include <stdlib.h> -static void *dlopen_corrected(const char *, int); -#define dlopen(A, B) dlopen_corrected(A, B) -#include "fl_libdecor.h" -#undef libdecor_new -#define libdecor_new libdecor_new_orig -#undef libdecor_frame_set_minimized -#define libdecor_frame_set_minimized libdecor_frame_set_minimized_orig -#include "../src/libdecor.c" -#undef dlopen -#undef libdecor_frame_set_minimized -#undef libdecor_new -#define libdecor_new fl_libdecor_new -#define libdecor_frame_set_minimized fl_libdecor_frame_set_minimized - -extern bool fl_libdecor_using_weston(void); -extern const struct libdecor_plugin_description *fl_libdecor_plugin_description; -//#include <stdio.h> - -// we have a built-in plugin so don't need a fallback one -struct libdecor_plugin *libdecor_fallback_plugin_new(struct libdecor *context) { - return NULL; -} - -// see get_libdecor_plugin_description() explaining why this is useful -static void *dlopen_corrected(const char *filename, int flags) { - static int best_priority = -1; - void *retval = dlopen(filename, flags); - if (retval) { - const struct libdecor_plugin_description *description = - (const struct libdecor_plugin_description*)dlsym(retval, "libdecor_plugin_description"); - if (description && description->priorities->priority > best_priority) { - fl_libdecor_plugin_description = description; - best_priority = description->priorities->priority; - } - } - return retval; -} - - -void fl_libdecor_frame_set_minimized(struct libdecor_frame *frame) -{ - static bool done = false; - static bool using_weston = false; - if (!done) { - typedef bool (*ext_f)(void); - volatile ext_f ext = fl_libdecor_using_weston; - done = true; - if (ext) using_weston = fl_libdecor_using_weston(); -//fprintf(stderr, "fl_libdecor_using_weston=%p using_weston=%d\n", fl_libdecor_using_weston, using_weston); - if (using_weston) { // determine the version of the running Weston compositor - FILE *pipe = popen("weston --version", "r"); - if (pipe) { - char line[50], *p; - int version = 0; - p = fgets(line, sizeof(line), pipe); - pclose(pipe); - if (p) p = strchr(line, ' '); - if (p) { - sscanf(p, "%d", &version); - // Weston version 10 has fixed the bug handled here - if (version >= 10) using_weston = false; - } - } - } - } - if (using_weston) libdecor_frame_set_visibility(frame, false); - libdecor_frame_set_minimized_orig(frame); -} - - -/* - By default, FLTK modifies libdecor's libdecor_new() function to determine the plugin as follows : - 1) the directory pointed by environment variable LIBDECOR_PLUGIN_DIR or, in absence of this variable, - by -DLIBDECOR_PLUGIN_DIR=xxx at build time is searched for a libdecor plugin; - 2) if this directory does not exist or contains no plugin, the built-in plugin is used. - * if FLTK was built with package libgtk-3-dev, the GTK plugin is used - * if FLTK was built without package libgtk-3-dev, the Cairo plugin is used - - If FLTK was built with FLTK_USE_SYSTEM_LIBDECOR turned ON, the present modification - isn't compiled, so the plugin-searching algorithm of libdecor_new() in libdecor-0.so is used. - This corresponds to step 1) above and to use no titlebar is no plugin is found. - - N.B.: only the system package is built with a meaningful value of -DLIBDECOR_PLUGIN_DIR= - so a plugin may be loaded that way only if FLTK was built with FLTK_USE_SYSTEM_LIBDECOR turned ON. - - */ -struct libdecor *fl_libdecor_new(struct wl_display *wl_display, const struct libdecor_interface *iface) -{ - struct libdecor *context; - context = zalloc(sizeof *context); - context->ref_count = 1; - context->iface = iface; - context->wl_display = wl_display; - context->wl_registry = wl_display_get_registry(wl_display); - wl_registry_add_listener(context->wl_registry, ®istry_listener, context); - context->init_callback = wl_display_sync(context->wl_display); - wl_callback_add_listener(context->init_callback, &init_wl_display_callback_listener, context); - wl_list_init(&context->frames); - // attempt to dynamically load a libdecor plugin with dlopen() - if (init_plugins(context) != 0) { // attempt to load plugin by dlopen() - // no plug-in was found by dlopen(), use built-in plugin instead - // defined in the source code of the built-in plugin: libdecor-cairo.c or libdecor-gtk.c - extern const struct libdecor_plugin_description libdecor_plugin_description; -#if HAVE_GTK - bool gdk_caution = false; - if (getenv("GDK_BACKEND") && strcmp(getenv("GDK_BACKEND"), "x11") == 0) { - // Environment variable GDK_BACKEND=x11 makes the .constructor below fail - // for the built-in GTK plugin and then FLTK crashes (#1029). - // Temporarily unset GDK_BACKEND to prevent that. - gdk_caution = true; - unsetenv("GDK_BACKEND"); - } -#endif - context->plugin = libdecor_plugin_description.constructor(context); -#if HAVE_GTK - if (gdk_caution) putenv("GDK_BACKEND=x11"); -#endif - } - - wl_display_flush(wl_display); - return context; -} - -#endif //! USE_SYSTEM_LIBDECOR diff --git a/libdecor/build/fl_libdecor.h b/libdecor/build/fl_libdecor.h deleted file mode 100644 index 97041c885..000000000 --- a/libdecor/build/fl_libdecor.h +++ /dev/null @@ -1,93 +0,0 @@ -// -// Interface with the libdecor library for the Fast Light Tool Kit (FLTK). -// -// Copyright 2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_LIBDECOR_H -#define FL_LIBDECOR_H - -#if ! USE_SYSTEM_LIBDECOR - -// add "fl_" prefix to libdecor.h symbols -#define libdecor_unref fl_libdecor_unref -#define libdecor_new fl_libdecor_new -#define libdecor_new_with_user_data fl_libdecor_new_with_user_data -#define libdecor_get_user_data fl_libdecor_get_user_data -#define libdecor_set_user_data fl_libdecor_set_user_data -#define libdecor_get_fd fl_libdecor_get_fd -#define libdecor_dispatch fl_libdecor_dispatch -#define libdecor_decorate fl_libdecor_decorate -#define libdecor_frame_ref fl_libdecor_frame_ref -#define libdecor_frame_unref fl_libdecor_frame_unref -#define libdecor_frame_get_user_data fl_libdecor_frame_get_user_data -#define libdecor_frame_set_user_data fl_libdecor_frame_set_user_data -#define libdecor_frame_set_visibility fl_libdecor_frame_set_visibility -#define libdecor_frame_is_visible fl_libdecor_frame_is_visible -#define libdecor_frame_set_parent fl_libdecor_frame_set_parent -#define libdecor_frame_set_title fl_libdecor_frame_set_title -#define libdecor_frame_get_title fl_libdecor_frame_get_title -#define libdecor_frame_set_app_id fl_libdecor_frame_set_app_id -#define libdecor_frame_set_capabilities fl_libdecor_frame_set_capabilities -#define libdecor_frame_unset_capabilities fl_libdecor_frame_unset_capabilitiesf -#define libdecor_frame_has_capability fl_libdecor_frame_has_capability -#define libdecor_frame_show_window_menu fl_libdecor_frame_show_window_menu -#define libdecor_frame_popup_grab fl_libdecor_frame_popup_grab -#define libdecor_frame_popup_ungrab fl_libdecor_frame_popup_ungrab -#define libdecor_frame_translate_coordinate fl_libdecor_frame_translate_coordinate -#define libdecor_frame_set_min_content_size fl_libdecor_frame_set_min_content_size -#define libdecor_frame_set_max_content_size fl_libdecor_frame_set_max_content_size -#define libdecor_frame_get_min_content_size fl_libdecor_frame_get_min_content_size -#define libdecor_frame_get_max_content_size fl_libdecor_frame_get_max_content_size -#define libdecor_frame_resize fl_libdecor_frame_resize -#define libdecor_frame_move fl_libdecor_frame_move -#define libdecor_frame_commit fl_libdecor_frame_commit -#define libdecor_frame_set_minimized fl_libdecor_frame_set_minimized -#define libdecor_frame_set_maximized fl_libdecor_frame_set_maximized -#define libdecor_frame_unset_maximized fl_libdecor_frame_unset_maximized -#define libdecor_frame_set_fullscreen fl_libdecor_frame_set_fullscreen -#define libdecor_frame_unset_fullscreen fl_libdecor_frame_unset_fullscreen -#define libdecor_frame_is_floating fl_libdecor_frame_is_floating -#define libdecor_frame_close fl_libdecor_frame_close -#define libdecor_frame_map fl_libdecor_frame_map -#define libdecor_frame_get_xdg_surface fl_libdecor_frame_get_xdg_surface -#define libdecor_frame_get_xdg_toplevel fl_libdecor_frame_get_xdg_toplevel -#define libdecor_frame_get_wm_capabilities fl_libdecor_frame_get_wm_capabilities -#define libdecor_set_handle_application_cursor fl_libdecor_set_handle_application_cursor -#define libdecor_state_new fl_libdecor_state_new -#define libdecor_state_free fl_libdecor_state_free -#define libdecor_configuration_get_content_size fl_libdecor_configuration_get_content_size -#define libdecor_configuration_get_window_state fl_libdecor_configuration_get_window_state - -// add "fl_" prefix to libdecor-plugin.h symbols -#define libdecor_frame_get_wl_surface fl_libdecor_frame_get_wl_surface -#define libdecor_frame_get_content_width fl_libdecor_frame_get_content_width -#define libdecor_frame_get_content_height fl_libdecor_frame_get_content_height -#define libdecor_frame_get_window_state fl_libdecor_frame_get_window_state -#define libdecor_frame_get_capabilities fl_libdecor_frame_get_capabilities -#define libdecor_frame_dismiss_popup fl_libdecor_frame_dismiss_popup -#define libdecor_frame_toplevel_commit fl_libdecor_frame_toplevel_commit -#define libdecor_get_wl_display fl_libdecor_get_wl_display -#define libdecor_notify_plugin_ready fl_libdecor_notify_plugin_ready -#define libdecor_notify_plugin_error fl_libdecor_notify_plugin_error -#define libdecor_state_get_content_width fl_libdecor_state_get_content_width -#define libdecor_state_get_content_height fl_libdecor_state_get_content_height -#define libdecor_state_get_window_state fl_libdecor_state_get_window_state -#define libdecor_plugin_init fl_libdecor_plugin_init -#define libdecor_plugin_release fl_libdecor_plugin_release - -#endif // ! USE_SYSTEM_LIBDECOR - -#include "../src/libdecor.h" - -#endif // ! FL_LIBDECOR_H diff --git a/libdecor/build/gtk-shell.xml b/libdecor/build/gtk-shell.xml deleted file mode 100644 index f00684679..000000000 --- a/libdecor/build/gtk-shell.xml +++ /dev/null @@ -1,109 +0,0 @@ -<!-- found at: https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gdk/wayland/protocol/gtk-shell.xml --> -<protocol name="gtk"> - - <interface name="gtk_shell1" version="5"> - <description summary="gtk specific extensions"> - gtk_shell is a protocol extension providing additional features for - clients implementing it. - </description> - - <enum name="capability"> - <entry name="global_app_menu" value="1"/> - <entry name="global_menu_bar" value="2"/> - <entry name="desktop_icons" value="3"/> - </enum> - - <event name="capabilities"> - <arg name="capabilities" type="uint"/> - </event> - - <request name="get_gtk_surface"> - <arg name="gtk_surface" type="new_id" interface="gtk_surface1"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="set_startup_id"> - <arg name="startup_id" type="string" allow-null="true"/> - </request> - - <request name="system_bell"> - <arg name="surface" type="object" interface="gtk_surface1" allow-null="true"/> - </request> - - <!-- Version 3 additions --> - <request name="notify_launch" since="3"> - <arg name="startup_id" type="string"/> - </request> - </interface> - - <interface name="gtk_surface1" version="5"> - <request name="set_dbus_properties"> - <arg name="application_id" type="string" allow-null="true"/> - <arg name="app_menu_path" type="string" allow-null="true"/> - <arg name="menubar_path" type="string" allow-null="true"/> - <arg name="window_object_path" type="string" allow-null="true"/> - <arg name="application_object_path" type="string" allow-null="true"/> - <arg name="unique_bus_name" type="string" allow-null="true"/> - </request> - - <request name="set_modal"/> - <request name="unset_modal"/> - - <request name="present"> - <arg name="time" type="uint"/> - </request> - - <!-- Version 2 additions --> - - <enum name="state"> - <entry name="tiled" value="1"/> - - <entry name="tiled_top" value="2" since="2" /> - <entry name="tiled_right" value="3" since="2" /> - <entry name="tiled_bottom" value="4" since="2" /> - <entry name="tiled_left" value="5" since="2" /> - </enum> - - <enum name="edge_constraint" since="2"> - <entry name="resizable_top" value="1"/> - <entry name="resizable_right" value="2"/> - <entry name="resizable_bottom" value="3"/> - <entry name="resizable_left" value="4"/> - </enum> - - <event name="configure"> - <arg name="states" type="array"/> - </event> - - <event name="configure_edges" since="2"> - <arg name="constraints" type="array"/> - </event> - - <!-- Version 3 additions --> - <request name="request_focus" since="3"> - <arg name="startup_id" type="string" allow-null="true"/> - </request> - - <!-- Version 4 additions --> - <request name="release" type="destructor" since="4"/> - - <!-- Version 5 additions --> - <enum name="gesture" since="5"> - <entry name="double_click" value="1"/> - <entry name="right_click" value="2"/> - <entry name="middle_click" value="3"/> - </enum> - - <enum name="error" since="5"> - <entry name="invalid_gesture" value="0"/> - </enum> - - <request name="titlebar_gesture" since="5"> - <arg name="serial" type="uint"/> - <arg name="seat" type="object" interface="wl_seat"/> - <arg name="gesture" type="uint" enum="gesture"/> - </request> - </interface> - -</protocol> - diff --git a/libdecor/src/desktop-settings.c b/libdecor/src/desktop-settings.c deleted file mode 100644 index 28067ac3e..000000000 --- a/libdecor/src/desktop-settings.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright © 2019 Christian Rauch - * Copyright © 2024 Colin Kinloch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "desktop-settings.h" -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include <stdint.h> -#include "config.h" - -static bool -get_cursor_settings_from_env(char **theme, int *size) -{ - char *env_xtheme; - char *env_xsize; - - env_xtheme = getenv("XCURSOR_THEME"); - if (env_xtheme != NULL) - *theme = strdup(env_xtheme); - - env_xsize = getenv("XCURSOR_SIZE"); - if (env_xsize != NULL) - *size = atoi(env_xsize); - - return env_xtheme != NULL && env_xsize != NULL; -} - -#ifdef HAS_DBUS -#include <dbus/dbus.h> - -static DBusMessage * -get_setting_sync(DBusConnection *const connection, - const char *key, - const char *value) -{ - DBusError error; - dbus_bool_t success; - DBusMessage *message; - DBusMessage *reply; - - message = dbus_message_new_method_call( - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.Settings", - "Read"); - - success = dbus_message_append_args(message, - DBUS_TYPE_STRING, &key, - DBUS_TYPE_STRING, &value, - DBUS_TYPE_INVALID); - - if (!success) - return NULL; - - dbus_error_init(&error); - - reply = dbus_connection_send_with_reply_and_block( - connection, - message, - DBUS_TIMEOUT_USE_DEFAULT, - &error); - - dbus_message_unref(message); - - if (dbus_error_is_set(&error)) { - dbus_error_free(&error); - return NULL; - } - - dbus_error_free(&error); - return reply; -} - -static bool -parse_type(DBusMessage *const reply, - const int type, - void *value) -{ - DBusMessageIter iter[3]; - - dbus_message_iter_init(reply, &iter[0]); - if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) - return false; - - dbus_message_iter_recurse(&iter[0], &iter[1]); - if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) - return false; - - dbus_message_iter_recurse(&iter[1], &iter[2]); - if (dbus_message_iter_get_arg_type(&iter[2]) != type) - return false; - - dbus_message_iter_get_basic(&iter[2], value); - - return true; -} - -bool -libdecor_get_cursor_settings(char **theme, int *size) -{ - static const char name[] = "org.gnome.desktop.interface"; - static const char key_theme[] = "cursor-theme"; - static const char key_size[] = "cursor-size"; - - DBusError error; - DBusConnection *connection; - DBusMessage *reply; - const char *value_theme = NULL; - - dbus_error_init(&error); - - connection = dbus_bus_get(DBUS_BUS_SESSION, &error); - - if (dbus_error_is_set(&error)) - goto fallback; - - reply = get_setting_sync(connection, name, key_theme); - if (!reply) - goto fallback; - - if (!parse_type(reply, DBUS_TYPE_STRING, &value_theme)) { - dbus_message_unref(reply); - goto fallback; - } - - *theme = strdup(value_theme); - - dbus_message_unref(reply); - - reply = get_setting_sync(connection, name, key_size); - if (!reply) - goto fallback; - - if (!parse_type(reply, DBUS_TYPE_INT32, size)) { - dbus_message_unref(reply); - goto fallback; - } - - dbus_message_unref(reply); - - return true; - -fallback: - return get_cursor_settings_from_env(theme, size); -} - -enum libdecor_color_scheme -libdecor_get_color_scheme() -{ - static const char name[] = "org.freedesktop.appearance"; - static const char key_color_scheme[] = "color-scheme"; - uint32_t color = 0; - - DBusError error; - DBusConnection *connection; - DBusMessage *reply; - - dbus_error_init(&error); - - connection = dbus_bus_get(DBUS_BUS_SESSION, &error); - - if (dbus_error_is_set(&error)) - return 0; - - reply = get_setting_sync(connection, name, key_color_scheme); - if (!reply) - return 0; - - if (!parse_type(reply, DBUS_TYPE_UINT32, &color)) { - dbus_message_unref(reply); - return 0; - } - - dbus_message_unref(reply); - - return color; -} -#else -bool -libdecor_get_cursor_settings(char **theme, int *size) -{ - return get_cursor_settings_from_env(theme, size); -} - -uint32_t -libdecor_get_color_scheme() -{ - return LIBDECOR_COLOR_SCHEME_DEFAULT; -} -#endif diff --git a/libdecor/src/desktop-settings.h b/libdecor/src/desktop-settings.h deleted file mode 100644 index 5747d3168..000000000 --- a/libdecor/src/desktop-settings.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2019 Christian Rauch - * Copyright © 2024 Colin Kinloch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include <stdbool.h> - -enum libdecor_color_scheme { - LIBDECOR_COLOR_SCHEME_DEFAULT, - LIBDECOR_COLOR_SCHEME_PREFER_DARK, - LIBDECOR_COLOR_SCHEME_PREFER_LIGHT, -}; - -bool -libdecor_get_cursor_settings(char **theme, int *size); - -enum libdecor_color_scheme -libdecor_get_color_scheme(); diff --git a/libdecor/src/libdecor-fallback.c b/libdecor/src/libdecor-fallback.c deleted file mode 100644 index ea0d35b03..000000000 --- a/libdecor/src/libdecor-fallback.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright © 2019 Jonas Ådahl - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include "libdecor-fallback.h" - -#include <poll.h> -#include <errno.h> - -#include "utils.h" - -struct libdecor_plugin_fallback { - struct libdecor_plugin plugin; - struct libdecor *context; -}; - -static void -libdecor_plugin_fallback_destroy(struct libdecor_plugin *plugin) -{ - libdecor_plugin_release(plugin); - free(plugin); -} - -static int -libdecor_plugin_fallback_get_fd(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_fallback *plugin_fallback = - (struct libdecor_plugin_fallback *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_fallback->context); - - return wl_display_get_fd(wl_display); -} - -static int -libdecor_plugin_fallback_dispatch(struct libdecor_plugin *plugin, - int timeout) -{ - struct libdecor_plugin_fallback *plugin_fallback = - (struct libdecor_plugin_fallback *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_fallback->context); - struct pollfd fds[1]; - int ret; - int dispatch_count = 0; - - while (wl_display_prepare_read(wl_display) != 0) - dispatch_count += wl_display_dispatch_pending(wl_display); - - if (wl_display_flush(wl_display) < 0 && - errno != EAGAIN) { - wl_display_cancel_read(wl_display); - return -errno; - } - - fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN }; - - ret = poll(fds, ARRAY_SIZE (fds), timeout); - if (ret > 0) { - if (fds[0].revents & POLLIN) { - wl_display_read_events(wl_display); - dispatch_count += wl_display_dispatch_pending(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return dispatch_count; - } - } else if (ret == 0) { - wl_display_cancel_read(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return -errno; - } -} - -static struct libdecor_frame * -libdecor_plugin_fallback_frame_new(struct libdecor_plugin *plugin) -{ - struct libdecor_frame *frame; - - frame = zalloc(sizeof *frame); - - return frame; -} - -static void -libdecor_plugin_fallback_frame_free(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ -} - -static void -libdecor_plugin_fallback_frame_commit(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration) -{ -} - -static void -libdecor_plugin_fallback_frame_property_changed(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ -} - -static void -libdecor_plugin_fallback_frame_popup_grab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ -} - -static void -libdecor_plugin_fallback_frame_popup_ungrab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ -} - -static bool -libdecor_plugin_fallback_frame_get_border_size(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_configuration *configuration, - int *left, - int *right, - int *top, - int *bottom) -{ - if (left) - *left = 0; - if (right) - *right = 0; - if (top) - *top = 0; - if (bottom) - *bottom = 0; - - return true; -} - -static struct libdecor_plugin_interface fallback_plugin_iface = { - .destroy = libdecor_plugin_fallback_destroy, - .get_fd = libdecor_plugin_fallback_get_fd, - .dispatch = libdecor_plugin_fallback_dispatch, - .frame_new = libdecor_plugin_fallback_frame_new, - .frame_free = libdecor_plugin_fallback_frame_free, - .frame_commit = libdecor_plugin_fallback_frame_commit, - .frame_property_changed = libdecor_plugin_fallback_frame_property_changed, - .frame_popup_grab = libdecor_plugin_fallback_frame_popup_grab, - .frame_popup_ungrab = libdecor_plugin_fallback_frame_popup_ungrab, - .frame_get_border_size = libdecor_plugin_fallback_frame_get_border_size, -}; - -struct libdecor_plugin * -libdecor_fallback_plugin_new(struct libdecor *context) -{ - struct libdecor_plugin_fallback *plugin; - - plugin = zalloc(sizeof *plugin); - libdecor_plugin_init(&plugin->plugin, context, &fallback_plugin_iface); - plugin->context = context; - - libdecor_notify_plugin_ready(context); - - return &plugin->plugin; -} diff --git a/libdecor/src/libdecor-fallback.h b/libdecor/src/libdecor-fallback.h deleted file mode 100644 index 40a5c51d2..000000000 --- a/libdecor/src/libdecor-fallback.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright © 2019 Jonas Ådahl - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef LIBDECOR_FALLBACK_H -#define LIBDECOR_FALLBACK_H - -#include "libdecor.h" -#include "libdecor-plugin.h" - -struct libdecor_plugin * -libdecor_fallback_plugin_new(struct libdecor *context); - -#endif /* LIBDECOR_FALLBACK_H */ diff --git a/libdecor/src/libdecor-plugin.h b/libdecor/src/libdecor-plugin.h deleted file mode 100644 index d57430e9c..000000000 --- a/libdecor/src/libdecor-plugin.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright © 2017-2018 Red Hat Inc. - * Copyright © 2018 Jonas Ådahl - * Copyright © 2019 Christian Rauch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef LIBDECOR_PLUGIN_H -#define LIBDECOR_PLUGIN_H - -#include "libdecor.h" - -struct libdecor_frame_private; - -struct libdecor_frame { - struct libdecor_frame_private *priv; - struct wl_list link; -}; - -struct libdecor_plugin_private; - -struct libdecor_plugin { - struct libdecor_plugin_private *priv; -}; - -typedef struct libdecor_plugin * (* libdecor_plugin_constructor)(struct libdecor *context); - -#define LIBDECOR_PLUGIN_PRIORITY_HIGH 1000 -#define LIBDECOR_PLUGIN_PRIORITY_MEDIUM 100 -#define LIBDECOR_PLUGIN_PRIORITY_LOW 0 - -struct libdecor_plugin_priority { - const char *desktop; - int priority; -}; - -enum libdecor_plugin_capabilities { - LIBDECOR_PLUGIN_CAPABILITY_BASE = 1 << 0, -}; - -struct libdecor_plugin_description { - /* API version the plugin is compatible with. */ - int api_version; - - /* Human readable string describing the plugin. */ - char *description; - - /* A plugin has a bitmask of capabilities. The plugin loader can use this - * to load a plugin with the right capabilities. */ - enum libdecor_plugin_capabilities capabilities; - - /* - * The priorities field points to a list of per desktop priorities. - * properties[i].desktop is matched against XDG_CURRENT_DESKTOP when - * determining what plugin to use. The last entry in the list MUST have - * the priorities[i].desktop pointer set to NULL as a default - * priority. - */ - const struct libdecor_plugin_priority *priorities; - - /* Vfunc used for constructing a plugin instance. */ - libdecor_plugin_constructor constructor; - - /* NULL terminated list of incompatible symbols. */ - char *conflicting_symbols[1024]; -}; - -struct libdecor_plugin_interface { - void (* destroy)(struct libdecor_plugin *plugin); - - int (* get_fd)(struct libdecor_plugin *plugin); - int (* dispatch)(struct libdecor_plugin *plugin, - int timeout); - - void (* set_handle_application_cursor)(struct libdecor_plugin *plugin, - bool handle_cursor); - - struct libdecor_frame * (* frame_new)(struct libdecor_plugin *plugin); - void (* frame_free)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame); - void (* frame_commit)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration); - void (*frame_property_changed)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame); - void (* frame_popup_grab)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name); - void (* frame_popup_ungrab)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name); - - bool (* frame_get_border_size)(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_configuration *configuration, - int *left, - int *right, - int *top, - int *bottom); - - /* Reserved */ - void (* reserved0)(void); - void (* reserved1)(void); - void (* reserved2)(void); - void (* reserved3)(void); - void (* reserved4)(void); - void (* reserved5)(void); - void (* reserved6)(void); - void (* reserved7)(void); - void (* reserved8)(void); - void (* reserved9)(void); -}; - -struct wl_surface * -libdecor_frame_get_wl_surface(struct libdecor_frame *frame); - -int -libdecor_frame_get_content_width(struct libdecor_frame *frame); - -int -libdecor_frame_get_content_height(struct libdecor_frame *frame); - -enum libdecor_window_state -libdecor_frame_get_window_state(struct libdecor_frame *frame); - -enum libdecor_capabilities -libdecor_frame_get_capabilities(const struct libdecor_frame *frame); - -void -libdecor_frame_dismiss_popup(struct libdecor_frame *frame, - const char *seat_name); - -void -libdecor_frame_toplevel_commit(struct libdecor_frame *frame); - -struct wl_display * -libdecor_get_wl_display(struct libdecor *context); - -void -libdecor_notify_plugin_ready(struct libdecor *context); - -void -libdecor_notify_plugin_error(struct libdecor *context, - enum libdecor_error error, - const char *__restrict fmt, - ...); - -int -libdecor_state_get_content_width(struct libdecor_state *state); - -int -libdecor_state_get_content_height(struct libdecor_state *state); - -enum libdecor_window_state -libdecor_state_get_window_state(struct libdecor_state *state); - -int -libdecor_plugin_init(struct libdecor_plugin *plugin, - struct libdecor *context, - struct libdecor_plugin_interface *iface); - -void -libdecor_plugin_release(struct libdecor_plugin *plugin); - -#endif /* LIBDECOR_PLUGIN_H */ diff --git a/libdecor/src/libdecor.c b/libdecor/src/libdecor.c deleted file mode 100644 index 39886c80f..000000000 --- a/libdecor/src/libdecor.c +++ /dev/null @@ -1,1871 +0,0 @@ -/* - * Copyright © 2017-2018 Red Hat Inc. - * Copyright © 2018 Jonas Ådahl - * Copyright © 2019 Christian Rauch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include <errno.h> -#include <dirent.h> -#include <dlfcn.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> - -#include "libdecor.h" -#include "libdecor-fallback.h" -#include "libdecor-plugin.h" -#include "utils.h" - -#include "xdg-shell-client-protocol.h" -#include "xdg-decoration-client-protocol.h" - -struct libdecor { - int ref_count; - - const struct libdecor_interface *iface; - void *user_data; - - struct libdecor_plugin *plugin; - bool plugin_ready; - - struct wl_display *wl_display; - struct wl_registry *wl_registry; - struct xdg_wm_base *xdg_wm_base; - struct zxdg_decoration_manager_v1 *decoration_manager; - - struct wl_callback *init_callback; - bool init_done; - bool has_error; - - struct wl_list frames; -}; - -struct libdecor_state { - enum libdecor_window_state window_state; - - int content_width; - int content_height; -}; - -struct libdecor_limits { - int min_width; - int min_height; - int max_width; - int max_height; -}; - -struct libdecor_configuration { - uint32_t serial; - - bool has_window_state; - enum libdecor_window_state window_state; - - bool has_size; - int window_width; - int window_height; -}; - -struct libdecor_frame_private { - int ref_count; - - struct libdecor *context; - - struct wl_surface *wl_surface; - - const struct libdecor_frame_interface *iface; - void *user_data; - - struct xdg_surface *xdg_surface; - struct xdg_toplevel *xdg_toplevel; - struct zxdg_toplevel_decoration_v1 *toplevel_decoration; - - bool pending_map; - - struct { - char *app_id; - char *title; - struct libdecor_limits content_limits; - struct xdg_toplevel *parent; - } state; - - struct libdecor_configuration *pending_configuration; - - int content_width; - int content_height; - - enum libdecor_window_state window_state; - - bool has_decoration_mode; - enum zxdg_toplevel_decoration_v1_mode decoration_mode; - - enum libdecor_capabilities capabilities; - - enum libdecor_wm_capabilities wm_capabilities; - - /* original limits for interactive resize */ - struct libdecor_limits interactive_limits; - - bool visible; -}; - -struct libdecor_plugin_private { - struct libdecor_plugin_interface *iface; -}; - -/* gather all states at which a window is non-floating */ -static const enum libdecor_window_state states_non_floating = - LIBDECOR_WINDOW_STATE_MAXIMIZED | LIBDECOR_WINDOW_STATE_FULLSCREEN | - LIBDECOR_WINDOW_STATE_TILED_LEFT | LIBDECOR_WINDOW_STATE_TILED_RIGHT | - LIBDECOR_WINDOW_STATE_TILED_TOP | LIBDECOR_WINDOW_STATE_TILED_BOTTOM; - -static bool -streql(const char *str1, const char *str2) -{ - return (str1 && str2) && (strcmp(str1, str2) == 0); -} - - -static void -do_map(struct libdecor_frame *frame); - -static bool -state_is_floating(enum libdecor_window_state window_state) -{ - return !(window_state & states_non_floating); -} - -static void -constrain_content_size(const struct libdecor_frame *frame, - int *width, - int *height) -{ - const struct libdecor_limits lim = frame->priv->state.content_limits; - - if (lim.min_width > 0) - *width = MAX(lim.min_width, *width); - if (lim.max_width > 0) - *width = MIN(*width, lim.max_width); - - if (lim.min_height > 0) - *height = MAX(lim.min_height, *height); - if (lim.max_height > 0) - *height = MIN(*height, lim.max_height); -} - -static bool -frame_has_visible_client_side_decoration(struct libdecor_frame *frame) -{ - /* visibility by client configuration */ - const bool vis_client = frame->priv->visible; - /* visibility by compositor configuration */ - const bool vis_server = (frame->priv->decoration_mode == - ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); - - return vis_client && vis_server; -} - -LIBDECOR_EXPORT int -libdecor_state_get_content_width(struct libdecor_state *state) -{ - return state->content_width; -} - -LIBDECOR_EXPORT int -libdecor_state_get_content_height(struct libdecor_state *state) -{ - return state->content_height; -} - -LIBDECOR_EXPORT enum libdecor_window_state -libdecor_state_get_window_state(struct libdecor_state *state) -{ - return state->window_state; -} - -LIBDECOR_EXPORT struct libdecor_state * -libdecor_state_new(int width, - int height) -{ - struct libdecor_state *state; - - state = zalloc(sizeof *state); - state->content_width = width; - state->content_height = height; - - return state; -} - -LIBDECOR_EXPORT void -libdecor_state_free(struct libdecor_state *state) -{ - free(state); -} - -static struct libdecor_configuration * -libdecor_configuration_new(void) -{ - struct libdecor_configuration *configuration; - - configuration = zalloc(sizeof *configuration); - - return configuration; -} - -static void -libdecor_configuration_free(struct libdecor_configuration *configuration) -{ - free(configuration); -} - -static bool -frame_get_window_size_for(struct libdecor_frame *frame, - struct libdecor_state *state, - int *window_width, - int *window_height) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - *window_width = state->content_width; - *window_height = state->content_height; - - if (frame_has_visible_client_side_decoration(frame) && - plugin->priv->iface->frame_get_border_size) { - int left, right, top, bottom; - if (!plugin->priv->iface->frame_get_border_size( - plugin, frame, NULL, &left, &right, &top, &bottom)) - return false; - *window_width += left + right; - *window_height += top + bottom; - } - - return true; -} - -static void -frame_set_window_geometry(struct libdecor_frame *frame, - int32_t content_width, int32_t content_height) -{ - struct libdecor_plugin *plugin = frame->priv->context->plugin; - int x, y, width, height; - int left, right, top, bottom; - - plugin->priv->iface->frame_get_border_size(plugin, frame, NULL, - &left, &right, &top, &bottom); - x = -left; - y = -top; - width = content_width + left + right; - height = content_height + top + bottom; - xdg_surface_set_window_geometry(frame->priv->xdg_surface, x, y, width, height); -} - -LIBDECOR_EXPORT bool -libdecor_configuration_get_content_size(struct libdecor_configuration *configuration, - struct libdecor_frame *frame, - int *width, - int *height) -{ - struct libdecor_plugin *plugin = frame->priv->context->plugin; - - /* get configured toplevel dimensions */ - if (!configuration->has_size) - return false; - - if (configuration->window_width == 0 || configuration->window_height == 0) - return false; - - *width = configuration->window_width; - *height = configuration->window_height; - - /* remove plugin-specific border size */ - if (frame_has_visible_client_side_decoration(frame) && - plugin->priv->iface->frame_get_border_size) { - int left, right, top, bottom; - - /* Update window state for correct border size calculation */ - frame->priv->window_state = configuration->window_state; - if (!plugin->priv->iface->frame_get_border_size( - plugin, frame, configuration, &left, &right, &top, &bottom)) - return false; - - *width -= (left + right); - *height -= (top + bottom); - } - - /* constrain content dimensions manually */ - if (state_is_floating(configuration->window_state)) { - constrain_content_size(frame, width, height); - } - - return true; -} - -LIBDECOR_EXPORT bool -libdecor_configuration_get_window_state(struct libdecor_configuration *configuration, - enum libdecor_window_state *window_state) -{ - if (!configuration->has_window_state) - return false; - - *window_state = configuration->window_state; - return true; -} - -static void -xdg_surface_configure(void *user_data, - struct xdg_surface *xdg_surface, - uint32_t serial) -{ - struct libdecor_frame *frame = user_data; - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor_configuration *configuration; - - configuration = frame_priv->pending_configuration; - frame_priv->pending_configuration = NULL; - - if (!configuration) - configuration = libdecor_configuration_new(); - - configuration->serial = serial; - - frame_priv->iface->configure(frame, - configuration, - frame_priv->user_data); - - libdecor_configuration_free(configuration); -} - -static const struct xdg_surface_listener xdg_surface_listener = { - xdg_surface_configure, -}; - -static enum libdecor_window_state -parse_states(struct wl_array *states) -{ - enum libdecor_window_state pending_state = LIBDECOR_WINDOW_STATE_NONE; - uint32_t *p; - - wl_array_for_each(p, states) { - enum xdg_toplevel_state state = *p; - - switch (state) { - case XDG_TOPLEVEL_STATE_FULLSCREEN: - pending_state |= LIBDECOR_WINDOW_STATE_FULLSCREEN; - break; - case XDG_TOPLEVEL_STATE_MAXIMIZED: - pending_state |= LIBDECOR_WINDOW_STATE_MAXIMIZED; - break; - case XDG_TOPLEVEL_STATE_ACTIVATED: - pending_state |= LIBDECOR_WINDOW_STATE_ACTIVE; - break; - case XDG_TOPLEVEL_STATE_TILED_LEFT: - pending_state |= LIBDECOR_WINDOW_STATE_TILED_LEFT; - break; - case XDG_TOPLEVEL_STATE_TILED_RIGHT: - pending_state |= LIBDECOR_WINDOW_STATE_TILED_RIGHT; - break; - case XDG_TOPLEVEL_STATE_TILED_TOP: - pending_state |= LIBDECOR_WINDOW_STATE_TILED_TOP; - break; - case XDG_TOPLEVEL_STATE_TILED_BOTTOM: - pending_state |= LIBDECOR_WINDOW_STATE_TILED_BOTTOM; - break; - case XDG_TOPLEVEL_STATE_RESIZING: - pending_state |= LIBDECOR_WINDOW_STATE_RESIZING; - break; -#ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION - case XDG_TOPLEVEL_STATE_SUSPENDED: - pending_state |= LIBDECOR_WINDOW_STATE_SUSPENDED; - break; -#endif -#ifdef XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION - case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: - pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_LEFT; - break; - case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: - pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_RIGHT; - break; - case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: - pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_TOP; - break; - case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: - pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_BOTTOM; - break; -#endif - default: - break; - } - } - - return pending_state; -} - -static void -xdg_toplevel_configure(void *user_data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height, - struct wl_array *states) -{ - struct libdecor_frame *frame = user_data; - struct libdecor_frame_private *frame_priv = frame->priv; - enum libdecor_window_state window_state; - - window_state = parse_states(states); - - frame_priv->pending_configuration = libdecor_configuration_new(); - - frame_priv->pending_configuration->has_size = true; - frame_priv->pending_configuration->window_width = width; - frame_priv->pending_configuration->window_height = height; - - frame_priv->pending_configuration->has_window_state = true; - frame_priv->pending_configuration->window_state = window_state; -} - -static void -xdg_toplevel_close(void *user_data, - struct xdg_toplevel *xdg_toplevel) -{ - struct libdecor_frame *frame = user_data; - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->iface->close(frame, frame_priv->user_data); -} - -#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION -static void -xdg_toplevel_configure_bounds(void *user_data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height) -{ - struct libdecor_frame *frame = user_data; - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - int left = 0, top = 0, right = 0, bottom = 0; - - if (frame_has_visible_client_side_decoration(frame) && - plugin->priv->iface->frame_get_border_size) { - plugin->priv->iface->frame_get_border_size(plugin, frame, NULL, - &left, &right, &top, &bottom); - } - - width -= left + right; - height -= top + bottom; - if (frame_priv->iface->bounds) { - frame_priv->iface->bounds(frame, width, height, frame_priv->user_data); - } -} -#endif - -#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION -static void -xdg_toplevel_wm_capabilities(void *user_data, - struct xdg_toplevel *xdg_toplevel, - struct wl_array *capabilities) -{ - struct libdecor_frame *frame = user_data; - struct libdecor_frame_private *frame_priv = frame->priv; - enum xdg_toplevel_wm_capabilities *wm_cap; - - frame_priv->wm_capabilities = 0; - - wl_array_for_each(wm_cap, capabilities) { - switch (*wm_cap) { - case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: - frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_WINDOW_MENU; - break; - case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: - frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MAXIMIZE; - break; - case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: - frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_FULLSCREEN; - break; - case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: - frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MINIMIZE; - break; - default: - break; - } - } -} -#endif - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - xdg_toplevel_configure, - xdg_toplevel_close, -#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION - xdg_toplevel_configure_bounds, -#endif -#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION - xdg_toplevel_wm_capabilities, -#endif -}; - -static void -toplevel_decoration_configure( - void *data, - struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, - uint32_t mode) -{ - struct libdecor_frame_private *frame_priv = (struct libdecor_frame_private *)data; - /* Ignore any _configure calls after the first, they will be - * from our set_mode call. */ - if (!frame_priv->has_decoration_mode) { - frame_priv->has_decoration_mode = true; - frame_priv->decoration_mode = mode; - } -} - -static const struct zxdg_toplevel_decoration_v1_listener - xdg_toplevel_decoration_listener = { - toplevel_decoration_configure, -}; - -void -libdecor_frame_create_xdg_decoration(struct libdecor_frame_private *frame_priv) -{ - if (!frame_priv->context->decoration_manager) - return; - - frame_priv->toplevel_decoration = - zxdg_decoration_manager_v1_get_toplevel_decoration( - frame_priv->context->decoration_manager, - frame_priv->xdg_toplevel); - - zxdg_toplevel_decoration_v1_add_listener( - frame_priv->toplevel_decoration, - &xdg_toplevel_decoration_listener, - frame_priv); -} - -static void -init_shell_surface(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - - if (frame_priv->xdg_surface) - return; - - frame_priv->xdg_surface = - xdg_wm_base_get_xdg_surface(context->xdg_wm_base, - frame_priv->wl_surface); - xdg_surface_add_listener(frame_priv->xdg_surface, - &xdg_surface_listener, - frame); - - frame_priv->xdg_toplevel = - xdg_surface_get_toplevel(frame_priv->xdg_surface); - xdg_toplevel_add_listener(frame_priv->xdg_toplevel, - &xdg_toplevel_listener, - frame); - - frame_priv->decoration_mode = - ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - frame_priv->toplevel_decoration = NULL; - libdecor_frame_create_xdg_decoration(frame_priv); - - if (frame_priv->state.parent) { - xdg_toplevel_set_parent(frame_priv->xdg_toplevel, - frame_priv->state.parent); - } - if (frame_priv->state.title) { - xdg_toplevel_set_title(frame_priv->xdg_toplevel, - frame_priv->state.title); - } - if (frame_priv->state.app_id) { - xdg_toplevel_set_app_id(frame_priv->xdg_toplevel, - frame_priv->state.app_id); - } - - if (frame_priv->pending_map) - do_map(frame); -} - -LIBDECOR_EXPORT struct libdecor_frame * -libdecor_decorate(struct libdecor *context, - struct wl_surface *wl_surface, - const struct libdecor_frame_interface *iface, - void *user_data) -{ - struct libdecor_plugin *plugin = context->plugin; - struct libdecor_frame *frame; - struct libdecor_frame_private *frame_priv; - - if (context->has_error) - return NULL; - - frame = plugin->priv->iface->frame_new(plugin); - if (!frame) - return NULL; - - frame_priv = zalloc(sizeof *frame_priv); - frame->priv = frame_priv; - - frame_priv->ref_count = 1; - frame_priv->context = context; - - frame_priv->wl_surface = wl_surface; - frame_priv->iface = iface; - frame_priv->user_data = user_data; - frame_priv->wm_capabilities = LIBDECOR_WM_CAPABILITIES_WINDOW_MENU | - LIBDECOR_WM_CAPABILITIES_MAXIMIZE | - LIBDECOR_WM_CAPABILITIES_FULLSCREEN | - LIBDECOR_WM_CAPABILITIES_MINIMIZE; - - wl_list_insert(&context->frames, &frame->link); - - libdecor_frame_set_capabilities(frame, - LIBDECOR_ACTION_MOVE | - LIBDECOR_ACTION_RESIZE | - LIBDECOR_ACTION_MINIMIZE | - LIBDECOR_ACTION_FULLSCREEN | - LIBDECOR_ACTION_CLOSE); - - frame_priv->visible = true; - - if (context->init_done) - init_shell_surface(frame); - - return frame; -} - -LIBDECOR_EXPORT void -libdecor_frame_ref(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->ref_count++; -} - -LIBDECOR_EXPORT void -libdecor_frame_unref(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->ref_count--; - if (frame_priv->ref_count == 0) { - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - if (context->decoration_manager && frame_priv->toplevel_decoration) { - zxdg_toplevel_decoration_v1_destroy(frame_priv->toplevel_decoration); - frame_priv->toplevel_decoration = NULL; - } - - wl_list_remove(&frame->link); - - if (frame_priv->xdg_toplevel) - xdg_toplevel_destroy(frame_priv->xdg_toplevel); - if (frame_priv->xdg_surface) - xdg_surface_destroy(frame_priv->xdg_surface); - - plugin->priv->iface->frame_free(plugin, frame); - - free(frame_priv->state.title); - free(frame_priv->state.app_id); - - free(frame_priv); - - free(frame); - } -} - -LIBDECOR_EXPORT void * -libdecor_frame_get_user_data(struct libdecor_frame *frame) -{ - return frame->priv->user_data; -} - -LIBDECOR_EXPORT void -libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data) -{ - frame->priv->user_data = user_data; -} - -LIBDECOR_EXPORT void -libdecor_frame_set_visibility(struct libdecor_frame *frame, - bool visible) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - frame_priv->visible = visible; - - /* enable/disable decorations that are managed by the compositor. - * Note that, as of xdg_decoration v1, this is just a hint and there is - * no reliable way of disabling all decorations. In practice this should - * work but per spec this is not guaranteed. - * - * See also: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/17 - */ - if (context->decoration_manager && - frame_priv->toplevel_decoration && - frame_priv->has_decoration_mode && - frame_priv->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) { - zxdg_toplevel_decoration_v1_set_mode(frame_priv->toplevel_decoration, - frame->priv->visible - ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE - : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); - } - - if (frame_priv->content_width <= 0 || - frame_priv->content_height <= 0) - return; - - /* enable/disable decorations that are managed by a plugin */ - if (frame_has_visible_client_side_decoration(frame)) { - /* show client-side decorations */ - plugin->priv->iface->frame_commit(plugin, frame, NULL, NULL); - } else { - /* destroy client-side decorations */ - plugin->priv->iface->frame_free(plugin, frame); - } - - frame_set_window_geometry(frame, - frame_priv->content_width, - frame_priv->content_height); - - libdecor_frame_toplevel_commit(frame); -} - -LIBDECOR_EXPORT bool -libdecor_frame_is_visible(struct libdecor_frame *frame) -{ - return frame->priv->visible; -} - -LIBDECOR_EXPORT void -libdecor_frame_set_parent(struct libdecor_frame *frame, - struct libdecor_frame *parent) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - if (!frame_priv->xdg_toplevel) - return; - - frame_priv->state.parent = parent ? parent->priv->xdg_toplevel : NULL; - - xdg_toplevel_set_parent(frame_priv->xdg_toplevel, - frame_priv->state.parent); -} - -LIBDECOR_EXPORT void -libdecor_frame_set_title(struct libdecor_frame *frame, - const char *title) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor_plugin *plugin = frame_priv->context->plugin; - - if (!streql(frame_priv->state.title, title)) { - free(frame_priv->state.title); - frame_priv->state.title = strdup(title); - - if (!frame_priv->xdg_toplevel) - return; - - xdg_toplevel_set_title(frame_priv->xdg_toplevel, title); - - plugin->priv->iface->frame_property_changed(plugin, frame); - } -} - -LIBDECOR_EXPORT const char * -libdecor_frame_get_title(struct libdecor_frame *frame) -{ - return frame->priv->state.title; -} - -LIBDECOR_EXPORT void -libdecor_frame_set_app_id(struct libdecor_frame *frame, - const char *app_id) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - free(frame_priv->state.app_id); - frame_priv->state.app_id = strdup(app_id); - - if (!frame_priv->xdg_toplevel) - return; - - xdg_toplevel_set_app_id(frame_priv->xdg_toplevel, app_id); -} - -static void -notify_on_capability_change(struct libdecor_frame *frame, - const enum libdecor_capabilities old_capabilities) -{ - struct libdecor_plugin *plugin = frame->priv->context->plugin; - struct libdecor_state *state; - - if (frame->priv->capabilities == old_capabilities) - return; - - if (frame->priv->content_width == 0 || - frame->priv->content_height == 0) - return; - - plugin->priv->iface->frame_property_changed(plugin, frame); - - if (!libdecor_frame_has_capability(frame, LIBDECOR_ACTION_RESIZE)) { - frame->priv->interactive_limits = frame->priv->state.content_limits; - /* set fixed window size */ - libdecor_frame_set_min_content_size(frame, - frame->priv->content_width, - frame->priv->content_height); - libdecor_frame_set_max_content_size(frame, - frame->priv->content_width, - frame->priv->content_height); - } else { - /* restore old limits */ - frame->priv->state.content_limits = frame->priv->interactive_limits; - } - - state = libdecor_state_new(frame->priv->content_width, - frame->priv->content_height); - libdecor_frame_commit(frame, state, NULL); - libdecor_state_free(state); - - libdecor_frame_toplevel_commit(frame); -} - -LIBDECOR_EXPORT void -libdecor_frame_set_capabilities(struct libdecor_frame *frame, - enum libdecor_capabilities capabilities) -{ - const enum libdecor_capabilities old_capabilities = - frame->priv->capabilities; - - frame->priv->capabilities |= capabilities; - - notify_on_capability_change(frame, old_capabilities); -} - -LIBDECOR_EXPORT void -libdecor_frame_unset_capabilities(struct libdecor_frame *frame, - enum libdecor_capabilities capabilities) -{ - const enum libdecor_capabilities old_capabilities = - frame->priv->capabilities; - - frame->priv->capabilities &= ~capabilities; - - notify_on_capability_change(frame, old_capabilities); -} - -LIBDECOR_EXPORT bool -libdecor_frame_has_capability(struct libdecor_frame *frame, - enum libdecor_capabilities capability) -{ - return frame->priv->capabilities & capability; -} - -LIBDECOR_EXPORT void -libdecor_frame_popup_grab(struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - plugin->priv->iface->frame_popup_grab(plugin, frame, seat_name); -} - -LIBDECOR_EXPORT void -libdecor_frame_popup_ungrab(struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - plugin->priv->iface->frame_popup_ungrab(plugin, frame, seat_name); -} - -LIBDECOR_EXPORT void -libdecor_frame_dismiss_popup(struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->iface->dismiss_popup(frame, seat_name, frame_priv->user_data); -} - -LIBDECOR_EXPORT void -libdecor_frame_show_window_menu(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial, - int x, - int y) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - if (!frame_priv->xdg_toplevel) { - fprintf(stderr, "Can't show window menu before being mapped\n"); - return; - } - - xdg_toplevel_show_window_menu(frame_priv->xdg_toplevel, - wl_seat, serial, - x, y); -} - -LIBDECOR_EXPORT void -libdecor_frame_translate_coordinate(struct libdecor_frame *frame, - int content_x, - int content_y, - int *frame_x, - int *frame_y) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - *frame_x = content_x; - *frame_y = content_y; - - if (frame_has_visible_client_side_decoration(frame) && - plugin->priv->iface->frame_get_border_size) { - int left, top; - plugin->priv->iface->frame_get_border_size(plugin, frame, NULL, - &left, NULL, &top, NULL); - *frame_x += left; - *frame_y += top; - } -} - -LIBDECOR_EXPORT void -libdecor_frame_set_min_content_size(struct libdecor_frame *frame, - int content_width, - int content_height) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->state.content_limits.min_width = content_width; - frame_priv->state.content_limits.min_height = content_height; -} - -LIBDECOR_EXPORT void -libdecor_frame_set_max_content_size(struct libdecor_frame *frame, - int content_width, - int content_height) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->state.content_limits.max_width = content_width; - frame_priv->state.content_limits.max_height = content_height; -} - -LIBDECOR_EXPORT void -libdecor_frame_get_min_content_size(const struct libdecor_frame *frame, - int *content_width, - int *content_height) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - *content_width = frame_priv->state.content_limits.min_width; - *content_height = frame_priv->state.content_limits.min_height; -} - -LIBDECOR_EXPORT void -libdecor_frame_get_max_content_size(const struct libdecor_frame *frame, - int *content_width, - int *content_height) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - *content_width = frame_priv->state.content_limits.max_width; - *content_height = frame_priv->state.content_limits.max_height; -} - -LIBDECOR_EXPORT enum libdecor_capabilities -libdecor_frame_get_capabilities(const struct libdecor_frame *frame) -{ - return frame->priv->capabilities; -} - -enum xdg_toplevel_resize_edge -edge_to_xdg_edge(enum libdecor_resize_edge edge) -{ - switch (edge) { - case LIBDECOR_RESIZE_EDGE_NONE: - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - case LIBDECOR_RESIZE_EDGE_TOP: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP; - case LIBDECOR_RESIZE_EDGE_BOTTOM: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - case LIBDECOR_RESIZE_EDGE_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - case LIBDECOR_RESIZE_EDGE_TOP_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - case LIBDECOR_RESIZE_EDGE_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - case LIBDECOR_RESIZE_EDGE_TOP_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; - } - - abort(); -} - -LIBDECOR_EXPORT void -libdecor_frame_resize(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial, - enum libdecor_resize_edge edge) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - enum xdg_toplevel_resize_edge xdg_edge; - - xdg_edge = edge_to_xdg_edge(edge); - xdg_toplevel_resize(frame_priv->xdg_toplevel, - wl_seat, serial, xdg_edge); -} - -LIBDECOR_EXPORT void -libdecor_frame_move(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - xdg_toplevel_move(frame_priv->xdg_toplevel, wl_seat, serial); -} - -LIBDECOR_EXPORT void -libdecor_frame_set_minimized(struct libdecor_frame *frame) -{ - xdg_toplevel_set_minimized(frame->priv->xdg_toplevel); -} - -LIBDECOR_EXPORT void -libdecor_frame_set_maximized(struct libdecor_frame *frame) -{ - xdg_toplevel_set_maximized(frame->priv->xdg_toplevel); -} - -LIBDECOR_EXPORT void -libdecor_frame_unset_maximized(struct libdecor_frame *frame) -{ - xdg_toplevel_unset_maximized(frame->priv->xdg_toplevel); -} - -LIBDECOR_EXPORT void -libdecor_frame_set_fullscreen(struct libdecor_frame *frame, - struct wl_output *output) -{ - xdg_toplevel_set_fullscreen(frame->priv->xdg_toplevel, output); -} - -LIBDECOR_EXPORT void -libdecor_frame_unset_fullscreen(struct libdecor_frame *frame) -{ - xdg_toplevel_unset_fullscreen(frame->priv->xdg_toplevel); -} - -LIBDECOR_EXPORT bool -libdecor_frame_is_floating(struct libdecor_frame *frame) -{ - return state_is_floating(frame->priv->window_state); -} - -LIBDECOR_EXPORT void -libdecor_frame_close(struct libdecor_frame *frame) -{ - xdg_toplevel_close(frame, frame->priv->xdg_toplevel); -} - -bool -valid_limits(struct libdecor_frame_private *frame_priv) -{ - if (frame_priv->state.content_limits.min_width > 0 && - frame_priv->state.content_limits.max_width > 0 && - frame_priv->state.content_limits.min_width > - frame_priv->state.content_limits.max_width) - return false; - - if (frame_priv->state.content_limits.min_height > 0 && - frame_priv->state.content_limits.max_height > 0 && - frame_priv->state.content_limits.min_height > - frame_priv->state.content_limits.max_height) - return false; - - return true; -} - -static void -libdecor_frame_apply_limits(struct libdecor_frame *frame, - enum libdecor_window_state window_state) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - if (!valid_limits(frame_priv)) { - libdecor_notify_plugin_error( - frame_priv->context, - LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION, - "minimum size (%i,%i) must be smaller than maximum size (%i,%i)", - frame_priv->state.content_limits.min_width, - frame_priv->state.content_limits.min_height, - frame_priv->state.content_limits.max_width, - frame_priv->state.content_limits.max_height); - } - - /* If the frame is configured as non-resizable before the first - * configure event is received, we have to manually set the min/max - * limits with the configured content size afterwards. */ - if (!libdecor_frame_has_capability(frame, LIBDECOR_ACTION_RESIZE)) { - frame_priv->state.content_limits.min_width = - frame_priv->content_width; - frame_priv->state.content_limits.max_width = - frame_priv->content_width; - - frame_priv->state.content_limits.min_height = - frame_priv->content_height; - frame_priv->state.content_limits.max_height = - frame_priv->content_height; - } - - if (frame_priv->state.content_limits.min_width > 0 && - frame_priv->state.content_limits.min_height > 0) { - struct libdecor_state state_min; - int win_min_width, win_min_height; - - state_min.content_width = frame_priv->state.content_limits.min_width; - state_min.content_height = frame_priv->state.content_limits.min_height; - state_min.window_state = window_state; - - frame_get_window_size_for(frame, &state_min, - &win_min_width, &win_min_height); - xdg_toplevel_set_min_size(frame_priv->xdg_toplevel, - win_min_width, win_min_height); - } else { - xdg_toplevel_set_min_size(frame_priv->xdg_toplevel, 0, 0); - } - - if (frame_priv->state.content_limits.max_width > 0 && - frame_priv->state.content_limits.max_height > 0) { - struct libdecor_state state_max; - int win_max_width, win_max_height; - - state_max.content_width = frame_priv->state.content_limits.max_width; - state_max.content_height = frame_priv->state.content_limits.max_height; - state_max.window_state = window_state; - - frame_get_window_size_for(frame, &state_max, - &win_max_width, &win_max_height); - xdg_toplevel_set_max_size(frame_priv->xdg_toplevel, - win_max_width, win_max_height); - } else { - xdg_toplevel_set_max_size(frame_priv->xdg_toplevel, 0, 0); - } -} - -static void -libdecor_frame_apply_state(struct libdecor_frame *frame, - struct libdecor_state *state) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->content_width = state->content_width; - frame_priv->content_height = state->content_height; - - /* do not set limits in non-floating states */ - if (state_is_floating(state->window_state)) { - libdecor_frame_apply_limits(frame, state->window_state); - } -} - -LIBDECOR_EXPORT void -libdecor_frame_toplevel_commit(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->iface->commit(frame, frame_priv->user_data); -} - -LIBDECOR_EXPORT void -libdecor_frame_commit(struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - struct libdecor *context = frame_priv->context; - struct libdecor_plugin *plugin = context->plugin; - - if (configuration && configuration->has_window_state) { - frame_priv->window_state = configuration->window_state; - state->window_state = configuration->window_state; - } else { - state->window_state = frame_priv->window_state; - } - - libdecor_frame_apply_state(frame, state); - - /* switch between decoration modes */ - if (frame_has_visible_client_side_decoration(frame)) { - plugin->priv->iface->frame_commit(plugin, frame, state, - configuration); - } else { - plugin->priv->iface->frame_free(plugin, frame); - } - - frame_set_window_geometry(frame, - frame_priv->content_width, - frame_priv->content_height); - - if (configuration) { - xdg_surface_ack_configure(frame_priv->xdg_surface, - configuration->serial); - } -} - -static void -do_map(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - frame_priv->pending_map = false; - wl_surface_commit(frame_priv->wl_surface); -} - -LIBDECOR_EXPORT void -libdecor_frame_map(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - if (!frame_priv->xdg_surface) { - frame_priv->pending_map = true; - return; - } - - do_map(frame); -} - -LIBDECOR_EXPORT struct wl_surface * -libdecor_frame_get_wl_surface(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->wl_surface; -} - -LIBDECOR_EXPORT struct xdg_surface * -libdecor_frame_get_xdg_surface(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->xdg_surface; -} - -LIBDECOR_EXPORT struct xdg_toplevel * -libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame) -{ - return frame->priv->xdg_toplevel; -} - -LIBDECOR_EXPORT void -libdecor_set_handle_application_cursor(struct libdecor *context, - bool handle_cursor) -{ - struct libdecor_plugin *plugin = context->plugin; - - plugin->priv->iface->set_handle_application_cursor(plugin, - handle_cursor); -} - -LIBDECOR_EXPORT int -libdecor_frame_get_content_width(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->content_width; -} - -LIBDECOR_EXPORT int -libdecor_frame_get_content_height(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->content_height; -} - -LIBDECOR_EXPORT enum libdecor_window_state -libdecor_frame_get_window_state(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->window_state; -} - -LIBDECOR_EXPORT enum libdecor_wm_capabilities -libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame) -{ - struct libdecor_frame_private *frame_priv = frame->priv; - - return frame_priv->wm_capabilities; -} - -LIBDECOR_EXPORT int -libdecor_plugin_init(struct libdecor_plugin *plugin, - struct libdecor *context, - struct libdecor_plugin_interface *iface) -{ - plugin->priv = zalloc(sizeof (struct libdecor_plugin_private)); - if (!plugin->priv) - return -1; - - plugin->priv->iface = iface; - - return 0; -} - -LIBDECOR_EXPORT void -libdecor_plugin_release(struct libdecor_plugin *plugin) -{ - free(plugin->priv); -} - -static void -xdg_wm_base_ping(void *user_data, - struct xdg_wm_base *xdg_wm_base, - uint32_t serial) -{ - xdg_wm_base_pong(xdg_wm_base, serial); -} - -static const struct xdg_wm_base_listener xdg_wm_base_listener = { - xdg_wm_base_ping, -}; - -static void -init_xdg_wm_base(struct libdecor *context, - uint32_t id, - uint32_t version) -{ - uint32_t desired_version = 2; - - /* Find the required version for the available features. */ -#ifdef XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION - desired_version = MAX(desired_version, XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION); -#endif -#ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION - desired_version = MAX(desired_version, XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION); -#endif -#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION - desired_version = MAX(desired_version, XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION); -#endif -#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION - desired_version = MAX(desired_version, XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION); -#endif - - context->xdg_wm_base = wl_registry_bind(context->wl_registry, - id, - &xdg_wm_base_interface, - MIN(version, desired_version)); - xdg_wm_base_add_listener(context->xdg_wm_base, - &xdg_wm_base_listener, - context); -} - -static void -registry_handle_global(void *user_data, - struct wl_registry *wl_registry, - uint32_t id, - const char *interface, - uint32_t version) -{ - struct libdecor *context = user_data; - - if (!strcmp(interface, xdg_wm_base_interface.name)) { - init_xdg_wm_base(context, id, version); - } else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)) { - const char *force_csd = getenv("LIBDECOR_FORCE_CSD"); - - if (force_csd && atoi(force_csd)) { - return; - } - - context->decoration_manager = wl_registry_bind( - context->wl_registry, id, - &zxdg_decoration_manager_v1_interface, - MIN(version,2)); - } -} - -static void -registry_handle_global_remove(void *user_data, - struct wl_registry *wl_registry, - uint32_t name) -{ -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static bool -is_compositor_compatible(struct libdecor *context) -{ - if (!context->xdg_wm_base) - return false; - - return true; -} - -static void -notify_error(struct libdecor *context, - enum libdecor_error error, - const char *message) -{ - context->has_error = true; - context->iface->error(context, error, message); - context->plugin->priv->iface->destroy(context->plugin); -} - -static void -finish_init(struct libdecor *context) -{ - struct libdecor_frame *frame; - - wl_list_for_each(frame, &context->frames, link) - init_shell_surface(frame); -} - -static void -init_wl_display_callback(void *user_data, - struct wl_callback *callback, - uint32_t time) -{ - struct libdecor *context = user_data; - - context->init_done = true; - - wl_callback_destroy(callback); - context->init_callback = NULL; - - if (!is_compositor_compatible(context)) { - notify_error(context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "Compositor is missing required interfaces"); - } - - if (context->plugin_ready) { - finish_init(context); - } -} - -static const struct wl_callback_listener init_wl_display_callback_listener = { - init_wl_display_callback -}; - -struct plugin_loader { - struct wl_list link; - void *lib; - const struct libdecor_plugin_description *description; - int priority; - char *name; -}; - -static int -calculate_priority(const struct libdecor_plugin_description *plugin_description) -{ - const char *current_desktop; - int i; - - if (!plugin_description->priorities) - return -1; - - current_desktop = getenv("XDG_CURRENT_DESKTOP"); - - i = 0; - while (true) { - struct libdecor_plugin_priority priority = - plugin_description->priorities[i]; - - i++; - - if (priority.desktop) { - char *tokens; - char *saveptr; - char *token; - - if (!current_desktop) - continue; - - tokens = strdup(current_desktop); - token = strtok_r(tokens, ":", &saveptr); - while (token) { - if (strcmp(priority.desktop, token) == 0) { - free(tokens); - return priority.priority; - } - token = strtok_r(NULL, ":", &saveptr); - } - free(tokens); - } else { - return priority.priority; - } - } - - return -1; -} - -static bool -check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description, void *lib) -{ - char * const *symbol; - - symbol = plugin_description->conflicting_symbols; - while (*symbol) { - dlerror(); - void *sym = dlsym(RTLD_DEFAULT, *symbol); - if (!dlerror()) { - void *libsym = dlsym(lib, *symbol); - if (!dlerror() && libsym != sym) { - fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n", - plugin_description->description, *symbol); - return false; - } - } - - symbol++; - } - - return true; -} - -static struct plugin_loader * -load_plugin_loader(struct libdecor *context, - const char *path, - const char *name) -{ - char *ext; - char *filename; - void *lib; - const struct libdecor_plugin_description *plugin_description; - int priority; - struct plugin_loader *plugin_loader; - - ext = strrchr(name, '.'); - if (ext == NULL || strcmp(ext, ".so") != 0) - return NULL; - - if (asprintf(&filename, "%s/%s", path, name) == -1) - return NULL; - - lib = dlopen(filename, RTLD_NOW | RTLD_LAZY); - free(filename); - if (!lib) { - fprintf(stderr, "Failed to load plugin: '%s'\n", dlerror()); - return NULL; - } - - plugin_description = dlsym(lib, "libdecor_plugin_description"); - if (!plugin_description) { - fprintf(stderr, - "Failed to load plugin '%s': no plugin description symbol\n", - name); - dlclose(lib); - return NULL; - } - - if (plugin_description->api_version != LIBDECOR_PLUGIN_API_VERSION) { - fprintf(stderr, - "Plugin '%s' found, but it's incompatible " - "(expected API version %d, but got %d)\n", - name, - LIBDECOR_PLUGIN_API_VERSION, - plugin_description->api_version); - dlclose(lib); - return NULL; - } - - if (!(plugin_description->capabilities & LIBDECOR_PLUGIN_CAPABILITY_BASE)) { - dlclose(lib); - return NULL; - } - - if (!check_symbol_conflicts(plugin_description, lib)) { - dlclose(lib); - return NULL; - } - - priority = calculate_priority(plugin_description); - if (priority == -1) { - fprintf(stderr, - "Plugin '%s' found, but has an invalid description\n", - name); - dlclose(lib); - return NULL; - } - - plugin_loader = zalloc(sizeof *plugin_loader); - plugin_loader->description = plugin_description; - plugin_loader->lib = lib; - plugin_loader->priority = priority; - plugin_loader->name = strdup(name); - - return plugin_loader; -} - -static bool -plugin_loader_higher_priority(struct plugin_loader *plugin_loader, - struct plugin_loader *best_plugin_loader) -{ - return plugin_loader->priority > best_plugin_loader->priority; -} - -static int -init_plugins(struct libdecor *context) -{ - const char *plugin_dir_env; - char *all_plugin_dirs; - char *plugin_dir; - char *saveptr; - DIR *dir; - struct wl_list plugin_loaders; - struct plugin_loader *plugin_loader, *tmp; - struct plugin_loader *best_plugin_loader; - struct libdecor_plugin *plugin; - - plugin_dir_env = getenv("LIBDECOR_PLUGIN_DIR"); - if (!plugin_dir_env) { - plugin_dir_env = LIBDECOR_PLUGIN_DIR; - } - all_plugin_dirs = strdup(plugin_dir_env); - - wl_list_init(&plugin_loaders); - plugin_dir = strtok_r(all_plugin_dirs, ":", &saveptr); - while (plugin_dir) { - dir = opendir(plugin_dir); - if (!dir) { - fprintf(stderr, "Couldn't open plugin directory: %s\n", - strerror(errno)); - } else { - - while (true) { - struct dirent *de; - - de = readdir(dir); - if (!de) - break; - - plugin_loader = load_plugin_loader(context, - plugin_dir, - de->d_name); - if (!plugin_loader) - continue; - - wl_list_insert(plugin_loaders.prev, &plugin_loader->link); - } - - closedir(dir); - } - plugin_dir = strtok_r(NULL, ":", &saveptr); - } - free(all_plugin_dirs); - -retry_next: - best_plugin_loader = NULL; - wl_list_for_each(plugin_loader, &plugin_loaders, link) { - if (!best_plugin_loader) { - best_plugin_loader = plugin_loader; - continue; - } - - if (plugin_loader_higher_priority(plugin_loader, - best_plugin_loader)) - best_plugin_loader = plugin_loader; - } - - if (!best_plugin_loader) - return -1; - - plugin_loader = best_plugin_loader; - plugin = plugin_loader->description->constructor(context); - if (!plugin) { - fprintf(stderr, - "Failed to load plugin '%s': failed to init\n", - plugin_loader->name); - dlclose(plugin_loader->lib); - wl_list_remove(&plugin_loader->link); - free(plugin_loader->name); - free(plugin_loader); - goto retry_next; - } - - context->plugin = plugin; - - wl_list_remove(&plugin_loader->link); - free(plugin_loader->name); - free(plugin_loader); - - wl_list_for_each_safe(plugin_loader, tmp, &plugin_loaders, link) { - dlclose(plugin_loader->lib); - free(plugin_loader->name); - free(plugin_loader); - } - - return 0; -} - -LIBDECOR_EXPORT void * -libdecor_get_user_data(struct libdecor *context) -{ - return context->user_data; -} - -LIBDECOR_EXPORT void -libdecor_set_user_data(struct libdecor *context, void *user_data) -{ - context->user_data = user_data; -} - -LIBDECOR_EXPORT int -libdecor_get_fd(struct libdecor *context) -{ - struct libdecor_plugin *plugin = context->plugin; - - return plugin->priv->iface->get_fd(plugin); -} - -LIBDECOR_EXPORT int -libdecor_dispatch(struct libdecor *context, - int timeout) -{ - struct libdecor_plugin *plugin = context->plugin; - - return plugin->priv->iface->dispatch(plugin, timeout); -} - -LIBDECOR_EXPORT struct wl_display * -libdecor_get_wl_display(struct libdecor *context) -{ - return context->wl_display; -} - -LIBDECOR_EXPORT void -libdecor_notify_plugin_ready(struct libdecor *context) -{ - context->plugin_ready = true; - - if (context->init_done) - finish_init(context); -} - -LIBDECOR_EXPORT void -libdecor_notify_plugin_error(struct libdecor *context, - enum libdecor_error error, - const char *__restrict fmt, - ...) -{ - char *msg = NULL; - int nbytes = 0; - va_list argp; - - if (context->has_error) - return; - - va_start(argp, fmt); - nbytes = vasprintf(&msg, fmt, argp); - va_end(argp); - - if (nbytes>0) - notify_error(context, error, msg); - - if (msg) - free(msg); -} - -LIBDECOR_EXPORT void -libdecor_unref(struct libdecor *context) -{ - context->ref_count--; - if (context->ref_count == 0) { - if (context->plugin) - context->plugin->priv->iface->destroy(context->plugin); - if (context->init_callback) - wl_callback_destroy(context->init_callback); - wl_registry_destroy(context->wl_registry); - if (context->xdg_wm_base) - xdg_wm_base_destroy(context->xdg_wm_base); - if (context->decoration_manager) - zxdg_decoration_manager_v1_destroy( - context->decoration_manager); - free(context); - } -} - -LIBDECOR_EXPORT struct libdecor * -libdecor_new(struct wl_display *wl_display, - const struct libdecor_interface *iface) -{ - return libdecor_new_with_user_data(wl_display, iface, NULL); -} - -LIBDECOR_EXPORT struct libdecor * -libdecor_new_with_user_data(struct wl_display *wl_display, - const struct libdecor_interface *iface, - void *user_data) -{ - struct libdecor *context; - - context = zalloc(sizeof *context); - - context->ref_count = 1; - context->iface = iface; - context->user_data = user_data; - context->wl_display = wl_display; - context->wl_registry = wl_display_get_registry(wl_display); - wl_registry_add_listener(context->wl_registry, - ®istry_listener, - context); - context->init_callback = wl_display_sync(context->wl_display); - wl_callback_add_listener(context->init_callback, - &init_wl_display_callback_listener, - context); - - wl_list_init(&context->frames); - - if (init_plugins(context) != 0) { - fprintf(stderr, - "No plugins found, falling back on no decorations\n"); - context->plugin = libdecor_fallback_plugin_new(context); - } - - wl_display_flush(wl_display); - - return context; -} diff --git a/libdecor/src/libdecor.h b/libdecor/src/libdecor.h deleted file mode 100644 index 71c9d7660..000000000 --- a/libdecor/src/libdecor.h +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright © 2017-2018 Red Hat Inc. - * Copyright © 2018 Jonas Ådahl - * Copyright © 2019 Christian Rauch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef LIBDECOR_H -#define LIBDECOR_H - -#include <stdbool.h> -#include <wayland-client.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__GNUC__) && __GNUC__ >= 4 -#define LIBDECOR_EXPORT __attribute__ ((visibility("default"))) -#else -#define LIBDECOR_EXPORT -#endif - -struct xdg_toplevel; - -/** \class libdecor - * - * \brief A libdecor context instance. - */ -struct libdecor; - -/** \class libdecor_frame - * - * \brief A frame used for decorating a Wayland surface. - */ -struct libdecor_frame; - -/** \class libdecor_configuration - * - * \brief An object representing a toplevel window configuration. - */ -struct libdecor_configuration; - -/** \class libdecor_state - * - * \brief An object corresponding to a configured content state. - */ -struct libdecor_state; - -enum libdecor_error { - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION, -}; - -enum libdecor_window_state { - LIBDECOR_WINDOW_STATE_NONE = 0, - LIBDECOR_WINDOW_STATE_ACTIVE = 1 << 0, - LIBDECOR_WINDOW_STATE_MAXIMIZED = 1 << 1, - LIBDECOR_WINDOW_STATE_FULLSCREEN = 1 << 2, - LIBDECOR_WINDOW_STATE_TILED_LEFT = 1 << 3, - LIBDECOR_WINDOW_STATE_TILED_RIGHT = 1 << 4, - LIBDECOR_WINDOW_STATE_TILED_TOP = 1 << 5, - LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 1 << 6, - LIBDECOR_WINDOW_STATE_SUSPENDED = 1 << 7, - LIBDECOR_WINDOW_STATE_RESIZING = 1 << 8, - LIBDECOR_WINDOW_STATE_CONSTRAINED_LEFT = 1 << 9, - LIBDECOR_WINDOW_STATE_CONSTRAINED_RIGHT = 1 << 10, - LIBDECOR_WINDOW_STATE_CONSTRAINED_TOP = 1 << 11, - LIBDECOR_WINDOW_STATE_CONSTRAINED_BOTTOM = 1 << 12, -}; - -enum libdecor_resize_edge { - LIBDECOR_RESIZE_EDGE_NONE, - LIBDECOR_RESIZE_EDGE_TOP, - LIBDECOR_RESIZE_EDGE_BOTTOM, - LIBDECOR_RESIZE_EDGE_LEFT, - LIBDECOR_RESIZE_EDGE_TOP_LEFT, - LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT, - LIBDECOR_RESIZE_EDGE_RIGHT, - LIBDECOR_RESIZE_EDGE_TOP_RIGHT, - LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT, -}; - -enum libdecor_capabilities { - LIBDECOR_ACTION_MOVE = 1 << 0, - LIBDECOR_ACTION_RESIZE = 1 << 1, - LIBDECOR_ACTION_MINIMIZE = 1 << 2, - LIBDECOR_ACTION_FULLSCREEN = 1 << 3, - LIBDECOR_ACTION_CLOSE = 1 << 4, -}; - -enum libdecor_wm_capabilities { - LIBDECOR_WM_CAPABILITIES_WINDOW_MENU = 1 << 0, - LIBDECOR_WM_CAPABILITIES_MAXIMIZE = 1 << 1, - LIBDECOR_WM_CAPABILITIES_FULLSCREEN = 1 << 2, - LIBDECOR_WM_CAPABILITIES_MINIMIZE = 1 << 3 -}; - -struct libdecor_interface { - /** - * An error event - */ - void (* error)(struct libdecor *context, - enum libdecor_error error, - const char *message); - - /* Reserved */ - void (* reserved0)(void); - void (* reserved1)(void); - void (* reserved2)(void); - void (* reserved3)(void); - void (* reserved4)(void); - void (* reserved5)(void); - void (* reserved6)(void); - void (* reserved7)(void); - void (* reserved8)(void); - void (* reserved9)(void); -}; - -/** - * Interface for integrating a Wayland surface with libdecor. - */ -struct libdecor_frame_interface { - /** - * A new configuration was received. An application should respond to - * this by creating a suitable libdecor_state, and apply it using - * libdecor_frame_commit. - */ - void (* configure)(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, - void *user_data); - - /** - * The window was requested to be closed by the compositor. - */ - void (* close)(struct libdecor_frame *frame, - void *user_data); - - /** - * The window decoration asked to have the main surface to be - * committed. This is required when the decoration is implemented using - * synchronous subsurfaces. - */ - void (* commit)(struct libdecor_frame *frame, - void *user_data); - - /** - * Any mapped popup that has a grab on the given seat should be - * dismissed. - */ - void (* dismiss_popup)(struct libdecor_frame *frame, - const char *seat_name, - void *user_data); - - /** - * The recommended client region bounds for the window. - * This will be followed by a configure event. - */ - void (* bounds)(struct libdecor_frame *frame, - int width, - int height, - void *user_data); - - /* Reserved */ - void (* reserved0)(void); - void (* reserved1)(void); - void (* reserved2)(void); - void (* reserved3)(void); - void (* reserved4)(void); - void (* reserved5)(void); - void (* reserved6)(void); - void (* reserved7)(void); - void (* reserved8)(void); -}; - -/** - * Remove a reference to the libdecor instance. When the reference count - * reaches zero, it is freed. - */ -void -libdecor_unref(struct libdecor *context); - -/** - * Create a new libdecor context for the given wl_display. - */ -struct libdecor * -libdecor_new(struct wl_display *display, - const struct libdecor_interface *iface); - -/** - * Create a new libdecor context for the given wl_display and attach user data. - */ -struct libdecor * -libdecor_new_with_user_data(struct wl_display *display, - const struct libdecor_interface *iface, - void *user_data); - -/** - * Get the user data associated with this libdecor context. - */ -void * -libdecor_get_user_data(struct libdecor *context); - -/** - * Set the user data associated with this libdecor context. - */ -void -libdecor_set_user_data(struct libdecor *context, void *user_data); - -/** - * Get the file descriptor used by libdecor. This is similar to - * wl_display_get_fd(), thus should be polled, and when data is available, - * libdecor_dispatch() should be called. - */ -int -libdecor_get_fd(struct libdecor *context); - -/** - * Dispatch events. This function should be called when data is available on - * the file descriptor returned by libdecor_get_fd(). If timeout is zero, this - * function will never block. - */ -int -libdecor_dispatch(struct libdecor *context, - int timeout); - -/** - * Decorate the given content wl_surface. - * - * This will create an xdg_surface and an xdg_toplevel, and integrate it - * properly with the windowing system, including creating appropriate - * decorations when needed, as well as handle windowing integration events such - * as resizing, moving, maximizing, etc. - * - * The passed wl_surface should only contain actual application content, - * without any window decoration. - */ -struct libdecor_frame * -libdecor_decorate(struct libdecor *context, - struct wl_surface *surface, - const struct libdecor_frame_interface *iface, - void *user_data); - -/** - * Add a reference to the frame object. - */ -void -libdecor_frame_ref(struct libdecor_frame *frame); - -/** - * Remove a reference to the frame object. When the reference count reaches - * zero, the frame object is destroyed. - */ -void -libdecor_frame_unref(struct libdecor_frame *frame); - -/** - * Get the user data associated with this libdecor frame. - */ -void * -libdecor_frame_get_user_data(struct libdecor_frame *frame); - -/** - * Set the user data associated with this libdecor frame. - */ -void -libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data); - -/** - * Set the visibility of the frame. - * - * If an application wants to be borderless, it can set the frame visibility to - * false. - */ -void -libdecor_frame_set_visibility(struct libdecor_frame *frame, - bool visible); - -/** - * Get the visibility of the frame. - */ -bool -libdecor_frame_is_visible(struct libdecor_frame *frame); - - -/** - * Set the parent of the window. - * - * This can be used to stack multiple toplevel windows above or under each - * other. - */ -void -libdecor_frame_set_parent(struct libdecor_frame *frame, - struct libdecor_frame *parent); - -/** - * Set the title of the window. - */ -void -libdecor_frame_set_title(struct libdecor_frame *frame, - const char *title); - -/** - * Get the title of the window. - */ -const char * -libdecor_frame_get_title(struct libdecor_frame *frame); - -/** - * Set the application ID of the window. - */ -void -libdecor_frame_set_app_id(struct libdecor_frame *frame, - const char *app_id); - -/** - * Set new capabilities of the window. - * - * This determines whether e.g. a window decoration should show a maximize - * button, etc. - * - * Setting a capability does not implicitly unset any other. - */ -void -libdecor_frame_set_capabilities(struct libdecor_frame *frame, - enum libdecor_capabilities capabilities); - -/** - * Unset capabilities of the window. - * - * The opposite of libdecor_frame_set_capabilities. - */ -void -libdecor_frame_unset_capabilities(struct libdecor_frame *frame, - enum libdecor_capabilities capabilities); - -/** - * Check whether the window has any of the given capabilities. - */ -bool -libdecor_frame_has_capability(struct libdecor_frame *frame, - enum libdecor_capabilities capability); - -/** - * Show the window menu. - */ -void -libdecor_frame_show_window_menu(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial, - int x, - int y); - -/** - * Issue a popup grab on the window. Call this when a xdg_popup is mapped, so - * that it can be properly dismissed by the decorations. - */ -void -libdecor_frame_popup_grab(struct libdecor_frame *frame, - const char *seat_name); - -/** - * Release the popup grab. Call this when you unmap a popup. - */ -void -libdecor_frame_popup_ungrab(struct libdecor_frame *frame, - const char *seat_name); - -/** - * Translate content surface local coordinates to toplevel window local - * coordinates. - * - * This can be used to translate surface coordinates to coordinates useful for - * e.g. showing the window menu, or positioning a popup. - */ -void -libdecor_frame_translate_coordinate(struct libdecor_frame *frame, - int surface_x, - int surface_y, - int *frame_x, - int *frame_y); - -/** - * Set the min content size. - * - * This translates roughly to xdg_toplevel_set_min_size(). - */ -void -libdecor_frame_set_min_content_size(struct libdecor_frame *frame, - int content_width, - int content_height); - -/** - * Set the max content size. - * - * This translates roughly to xdg_toplevel_set_max_size(). - */ -void -libdecor_frame_set_max_content_size(struct libdecor_frame *frame, - int content_width, - int content_height); - -/** - * Get the min content size. - */ -void -libdecor_frame_get_min_content_size(const struct libdecor_frame *frame, - int *content_width, - int *content_height); - -/** - * Get the max content size. - */ -void -libdecor_frame_get_max_content_size(const struct libdecor_frame *frame, - int *content_width, - int *content_height); - -/** - * Initiate an interactive resize. - * - * This roughly translates to xdg_toplevel_resize(). - */ -void -libdecor_frame_resize(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial, - enum libdecor_resize_edge edge); - -/** - * Initiate an interactive move. - * - * This roughly translates to xdg_toplevel_move(). - */ -void -libdecor_frame_move(struct libdecor_frame *frame, - struct wl_seat *wl_seat, - uint32_t serial); - -/** - * Commit a new window state. This can be called on application driven resizes - * when the window is floating, or in response to received configurations, i.e. - * from e.g. interactive resizes or state changes. - */ -void -libdecor_frame_commit(struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration); - -/** - * Minimize the window. - * - * Roughly translates to xdg_toplevel_set_minimized(). - */ -void -libdecor_frame_set_minimized(struct libdecor_frame *frame); - -/** - * Maximize the window. - * - * Roughly translates to xdg_toplevel_set_maximized(). - */ -void -libdecor_frame_set_maximized(struct libdecor_frame *frame); - -/** - * Unmaximize the window. - * - * Roughly translates to xdg_toplevel_unset_maximized(). - */ -void -libdecor_frame_unset_maximized(struct libdecor_frame *frame); - -/** - * Fullscreen the window. - * - * Roughly translates to xdg_toplevel_set_fullscreen(). - */ -void -libdecor_frame_set_fullscreen(struct libdecor_frame *frame, - struct wl_output *output); - -/** - * Unfullscreen the window. - * - * Roughly translates to xdg_toplevel_unset_unfullscreen(). - */ -void -libdecor_frame_unset_fullscreen(struct libdecor_frame *frame); - -/** - * Return true if the window is floating. - * - * A window is floating when it's not maximized, tiled, fullscreen, or in any - * similar way with a fixed size and state. - * Note that this function uses the "applied" configuration. If this function - * is used in the 'configure' callback, the provided configuration has to be - * applied via 'libdecor_frame_commit' first, before it will reflect the current - * window state from the provided configuration. - */ -bool -libdecor_frame_is_floating(struct libdecor_frame *frame); - -/** - * Close the window. - * - * Roughly translates to xdg_toplevel_close(). - */ -void -libdecor_frame_close(struct libdecor_frame *frame); - -/** - * Map the window. - * - * This will eventually result in the initial configure event. - */ -void -libdecor_frame_map(struct libdecor_frame *frame); - -/** - * Get the associated xdg_surface for content wl_surface. - */ -struct xdg_surface * -libdecor_frame_get_xdg_surface(struct libdecor_frame *frame); - -/** - * Get the associated xdg_toplevel for the content wl_surface. - */ -struct xdg_toplevel * -libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame); - -/** - * Get the supported window manager capabilities for the window. - */ -enum libdecor_wm_capabilities -libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame); - -/** - * Tell libdecor to set the default pointer cursor when the pointer is over an - * application surface. The default false. - */ -void -libdecor_set_handle_application_cursor(struct libdecor *context, - bool handle_cursor); - -/** - * Create a new content surface state. - */ -struct libdecor_state * -libdecor_state_new(int width, - int height); - -/** - * Free a content surface state. - */ -void -libdecor_state_free(struct libdecor_state *state); - -/** - * Get the expected size of the content for this configuration. - * - * If the configuration doesn't contain a size, false is returned. - */ -bool -libdecor_configuration_get_content_size(struct libdecor_configuration *configuration, - struct libdecor_frame *frame, - int *width, - int *height); - -/** - * Get the window state for this configuration. - * - * If the configuration doesn't contain any associated window state, false is - * returned, and the application should assume the window state remains - * unchanged. - */ -bool -libdecor_configuration_get_window_state(struct libdecor_configuration *configuration, - enum libdecor_window_state *window_state); - -#ifdef __cplusplus -} -#endif - -#endif /* LIBDECOR_H */ diff --git a/libdecor/src/os-compatibility.c b/libdecor/src/os-compatibility.c deleted file mode 100644 index 23766473d..000000000 --- a/libdecor/src/os-compatibility.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright © 2012 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include <sys/types.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> - -#ifdef HAVE_MEMFD_CREATE -#include <sys/mman.h> -#endif - -#include "os-compatibility.h" - -#ifndef HAVE_MKOSTEMP -static int -set_cloexec_or_close(int fd) -{ - long flags; - - if (fd == -1) - return -1; - - flags = fcntl(fd, F_GETFD); - if (flags == -1) - goto err; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - goto err; - - return fd; - -err: - close(fd); - return -1; -} -#endif - -static int -create_tmpfile_cloexec(char *tmpname) -{ - int fd; - -#ifdef HAVE_MKOSTEMP - fd = mkostemp(tmpname, O_CLOEXEC); - if (fd >= 0) - unlink(tmpname); -#else - fd = mkstemp(tmpname); - if (fd >= 0) { - fd = set_cloexec_or_close(fd); - unlink(tmpname); - } -#endif - - return fd; -} - -static int -os_resize_anonymous_file(int fd, off_t size) -{ -#ifdef HAVE_POSIX_FALLOCATE - sigset_t mask; - sigset_t old_mask; - - /* posix_fallocate() might be interrupted, so we need to check - * for EINTR and retry in that case. - * However, in the presence of an alarm, the interrupt may trigger - * repeatedly and prevent a large posix_fallocate() to ever complete - * successfully, so we need to first block SIGALRM to prevent - * this. - */ - sigemptyset(&mask); - sigaddset(&mask, SIGALRM); - sigprocmask(SIG_BLOCK, &mask, &old_mask); - /* - * Filesystems that do not support fallocate will return EINVAL or - * EOPNOTSUPP. In this case we need to fall back to ftruncate - */ - do { - errno = posix_fallocate(fd, 0, size); - } while (errno == EINTR); - sigprocmask(SIG_SETMASK, &old_mask, NULL); - if (errno == 0) - return 0; - else if (errno != EINVAL && errno != EOPNOTSUPP) - return -1; -#endif - if (ftruncate(fd, size) < 0) - return -1; - - return 0; -} - -/* - * Create a new, unique, anonymous file of the given size, and - * return the file descriptor for it. The file descriptor is set - * CLOEXEC. The file is immediately suitable for mmap()'ing - * the given size at offset zero. - * - * The file should not have a permanent backing store like a disk, - * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. - * - * The file name is deleted from the file system. - * - * The file is suitable for buffer sharing between processes by - * transmitting the file descriptor over Unix sockets using the - * SCM_RIGHTS methods. - * - * If the C library implements posix_fallocate(), it is used to - * guarantee that disk space is available for the file at the - * given size. If disk space is insufficient, errno is set to ENOSPC. - * If posix_fallocate() is not supported, program may receive - * SIGBUS on accessing mmap()'ed file contents instead. - * - * If the C library implements memfd_create(), it is used to create the - * file purely in memory, without any backing file name on the file - * system, and then sealing off the possibility of shrinking it. This - * can then be checked before accessing mmap()'ed file contents, to - * make sure SIGBUS can't happen. It also avoids requiring - * XDG_RUNTIME_DIR. - */ -int -libdecor_os_create_anonymous_file(off_t size) -{ - static const char template[] = "/libdecor-shared-XXXXXX"; - const char *path; - char *name; - int fd; - -#ifdef HAVE_MEMFD_CREATE - fd = memfd_create("libdecor", MFD_CLOEXEC | MFD_ALLOW_SEALING); - if (fd >= 0) { - /* We can add this seal before calling posix_fallocate(), as - * the file is currently zero-sized anyway. - * - * There is also no need to check for the return value, we - * couldn't do anything with it anyway. - */ - fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); - } else -#endif - { - path = getenv("XDG_RUNTIME_DIR"); - if (!path) { - errno = ENOENT; - return -1; - } - - name = malloc(strlen(path) + sizeof(template)); - if (!name) - return -1; - - strcpy(name, path); - strcat(name, template); - - fd = create_tmpfile_cloexec(name); - - free(name); - - if (fd < 0) - return -1; - } - - if (os_resize_anonymous_file(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} diff --git a/libdecor/src/os-compatibility.h b/libdecor/src/os-compatibility.h deleted file mode 100644 index 6ce49d01c..000000000 --- a/libdecor/src/os-compatibility.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright © 2012 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef OS_COMPATIBILITY_H -#define OS_COMPATIBILITY_H - -#include <sys/types.h> - -int -libdecor_os_create_anonymous_file(off_t size); - -#endif /* OS_COMPATIBILITY_H */ diff --git a/libdecor/src/plugins/cairo/libdecor-cairo.c b/libdecor/src/plugins/cairo/libdecor-cairo.c deleted file mode 100644 index d8854bc8e..000000000 --- a/libdecor/src/plugins/cairo/libdecor-cairo.c +++ /dev/null @@ -1,2796 +0,0 @@ -/* - * Copyright © 2018 Jonas Ådahl - * Copyright © 2019 Christian Rauch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include <linux/input.h> -#include <fcntl.h> -#include <poll.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> -#include <limits.h> -#include <wayland-cursor.h> - -#include "libdecor-plugin.h" -#include "utils.h" -#include "desktop-settings.h" -#include "os-compatibility.h" - -#include <cairo/cairo.h> -#include <pango/pangocairo.h> - -#include "common/libdecor-cairo-blur.h" - -static const size_t SHADOW_MARGIN = 24; /* graspable part of the border */ -static const size_t TITLE_HEIGHT = 24; -static const size_t BUTTON_WIDTH = 32; -static const size_t SYM_DIM = 14; - -static const uint32_t COL_TITLE = 0xFF080706; -static const uint32_t COL_TITLE_INACT = 0xFF303030; -static const uint32_t COL_BUTTON_MIN = 0xFFFFBB00; -static const uint32_t COL_BUTTON_MAX = 0xFF238823; -static const uint32_t COL_BUTTON_CLOSE = 0xFFFB6542; -static const uint32_t COL_BUTTON_INACT = 0xFF404040; -static const uint32_t COL_SYM = 0xFFF4F4EF; -static const uint32_t COL_SYM_ACT = 0xFF20322A; -static const uint32_t COL_SYM_INACT = 0xFF909090; - -static const uint32_t DOUBLE_CLICK_TIME_MS = 400; - -static const char *cursor_names[] = { - "top_side", - "bottom_side", - "left_side", - "top_left_corner", - "bottom_left_corner", - "right_side", - "top_right_corner", - "bottom_right_corner" -}; - - -/* color conversion function from 32bit integer to double components */ - -double -red(const uint32_t *const col) { - return ((const uint8_t*)(col))[2] / (double)(255); -} - -double -green(const uint32_t *const col) { - return ((const uint8_t*)(col))[1] / (double)(255); -} - -double -blue(const uint32_t *const col) { - return ((const uint8_t*)(col))[0] / (double)(255); -} - -double -alpha(const uint32_t *const col) { - return ((const uint8_t*)(col))[3] / (double)(255); -} - -void -cairo_set_rgba32(cairo_t *cr, const uint32_t *const c) { - cairo_set_source_rgba(cr, red(c), green(c), blue(c), alpha(c)); -} - -static bool -streql(const char *str1, const char *str2) -{ - return (str1 && str2) && (strcmp(str1, str2) == 0); -} - -enum decoration_type { - DECORATION_TYPE_NONE, - DECORATION_TYPE_ALL, - DECORATION_TYPE_MAXIMIZED, - DECORATION_TYPE_TILED -}; - -enum component { - NONE = 0, - SHADOW, - TITLE, - BUTTON_MIN, - BUTTON_MAX, - BUTTON_CLOSE, -}; - -enum composite_mode { - COMPOSITE_SERVER, - COMPOSITE_CLIENT, -}; - -struct seat { - struct libdecor_plugin_cairo *plugin_cairo; - - char *name; - - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - - struct wl_surface *cursor_surface; - struct wl_cursor *current_cursor; - int cursor_scale; - struct wl_list cursor_outputs; - - struct wl_cursor_theme *cursor_theme; - /* cursors for resize edges and corners */ - struct wl_cursor *cursors[ARRAY_LENGTH(cursor_names)]; - struct wl_cursor *cursor_left_ptr; - - struct wl_surface *pointer_focus; - struct libdecor_frame_cairo *pointer_focus_frame; - - int pointer_x, pointer_y; - - uint32_t pointer_button_time_stamp; - - uint32_t serial; - - bool grabbed; - - struct wl_list link; -}; - -struct output { - struct libdecor_plugin_cairo *plugin_cairo; - - struct wl_output *wl_output; - uint32_t id; - int scale; - - struct wl_list link; -}; - -struct buffer { - struct wl_buffer *wl_buffer; - bool in_use; - bool is_detached; - - void *data; - size_t data_size; - int width; - int height; - int scale; - int buffer_width; - int buffer_height; -}; - -struct border_component { - enum component type; - - bool is_hidden; - bool opaque; - - enum composite_mode composite_mode; - struct { - struct wl_surface *wl_surface; - struct wl_subsurface *wl_subsurface; - struct buffer *buffer; - struct wl_list output_list; - int scale; - } server; - struct { - cairo_surface_t *image; - struct border_component *parent_component; - } client; - - struct wl_list child_components; /* border_component::link */ - struct wl_list link; /* border_component::child_components */ -}; - -struct surface_output { - struct output *output; - struct wl_list link; -}; - -struct cursor_output { - struct output *output; - struct wl_list link; -}; - -struct libdecor_frame_cairo { - struct libdecor_frame frame; - - struct libdecor_plugin_cairo *plugin_cairo; - - int content_width; - int content_height; - - enum decoration_type decoration_type; - - enum libdecor_window_state window_state; - - char *title; - - enum libdecor_capabilities capabilities; - - struct border_component *focus; - struct border_component *active; - struct border_component *grab; - - bool shadow_showing; - struct border_component shadow; - - struct { - bool is_showing; - struct border_component title; - struct border_component min; - struct border_component max; - struct border_component close; - } title_bar; - - /* store pre-processed shadow tile */ - cairo_surface_t *shadow_blur; - - struct wl_list link; -}; - -struct libdecor_plugin_cairo { - struct libdecor_plugin plugin; - - struct wl_callback *globals_callback; - struct wl_callback *globals_callback_shm; - - struct libdecor *context; - - struct wl_registry *wl_registry; - struct wl_subcompositor *wl_subcompositor; - struct wl_compositor *wl_compositor; - - struct wl_shm *wl_shm; - struct wl_callback *shm_callback; - bool has_argb; - - struct wl_list visible_frame_list; - struct wl_list seat_list; - struct wl_list output_list; - - char *cursor_theme_name; - int cursor_size; - - PangoFontDescription *font; - - bool handle_cursor; -}; - -static const char *libdecor_cairo_proxy_tag = "libdecor-cairo"; - -static void -sync_active_component(struct libdecor_frame_cairo *frame_cairo, - struct seat *seat); - -static void -synthesize_pointer_enter(struct seat *seat); - -static void -synthesize_pointer_leave(struct seat *seat); - -static bool -own_proxy(struct wl_proxy *proxy) -{ - if (!proxy) - return false; - - return (wl_proxy_get_tag(proxy) == &libdecor_cairo_proxy_tag); -} - -static bool -own_surface(struct wl_surface *surface) -{ - return own_proxy((struct wl_proxy *) surface); -} - -static bool -own_output(struct wl_output *output) -{ - return own_proxy((struct wl_proxy *) output); -} - -static bool -moveable(struct libdecor_frame_cairo *frame_cairo) { - return libdecor_frame_has_capability(&frame_cairo->frame, - LIBDECOR_ACTION_MOVE); -} - -static bool -resizable(struct libdecor_frame_cairo *frame_cairo) { - return libdecor_frame_has_capability(&frame_cairo->frame, - LIBDECOR_ACTION_RESIZE); -} - -static bool -minimizable(struct libdecor_frame_cairo *frame_cairo) { - return libdecor_frame_has_capability(&frame_cairo->frame, - LIBDECOR_ACTION_MINIMIZE); -} - -static bool -closeable(struct libdecor_frame_cairo *frame_cairo) { - return libdecor_frame_has_capability(&frame_cairo->frame, - LIBDECOR_ACTION_CLOSE); -} - -static void -buffer_free(struct buffer *buffer); - -static void -draw_border_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component); - -static void -send_cursor(struct seat *seat); - -static bool -update_local_cursor(struct seat *seat); - -static void -libdecor_plugin_cairo_destroy(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - struct seat *seat, *seat_tmp; - struct output *output, *output_tmp; - struct libdecor_frame_cairo *frame, *frame_tmp; - - if (plugin_cairo->globals_callback) - wl_callback_destroy(plugin_cairo->globals_callback); - if (plugin_cairo->globals_callback_shm) - wl_callback_destroy(plugin_cairo->globals_callback_shm); - if (plugin_cairo->shm_callback) - wl_callback_destroy(plugin_cairo->shm_callback); - wl_registry_destroy(plugin_cairo->wl_registry); - - wl_list_for_each_safe(seat, seat_tmp, &plugin_cairo->seat_list, link) { - struct cursor_output *cursor_output, *tmp; - - if (seat->wl_pointer) - wl_pointer_destroy(seat->wl_pointer); - if (seat->cursor_surface) - wl_surface_destroy(seat->cursor_surface); - wl_seat_destroy(seat->wl_seat); - if (seat->cursor_theme) - wl_cursor_theme_destroy(seat->cursor_theme); - - wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - free(seat->name); - - free(seat); - } - - wl_list_for_each_safe(output, output_tmp, - &plugin_cairo->output_list, link) { - if (wl_output_get_version (output->wl_output) >= - WL_OUTPUT_RELEASE_SINCE_VERSION) - wl_output_release(output->wl_output); - else - wl_output_destroy(output->wl_output); - free(output); - } - - wl_list_for_each_safe(frame, frame_tmp, - &plugin_cairo->visible_frame_list, link) { - wl_list_remove(&frame->link); - } - - free(plugin_cairo->cursor_theme_name); - - if (plugin_cairo->wl_shm) - wl_shm_destroy(plugin_cairo->wl_shm); - - pango_font_description_free(plugin_cairo->font); - - if (plugin_cairo->wl_compositor) - wl_compositor_destroy(plugin_cairo->wl_compositor); - if (plugin_cairo->wl_subcompositor) - wl_subcompositor_destroy(plugin_cairo->wl_subcompositor); - - libdecor_plugin_release(&plugin_cairo->plugin); - free(plugin_cairo); -} - -static void -init_server_component(struct border_component *border_component, - enum component type) -{ - border_component->composite_mode = COMPOSITE_SERVER; - wl_list_init(&border_component->child_components); - border_component->type = type; -} - -static void -init_client_component(struct border_component *border_component, - struct border_component *parent, - enum component type) -{ - border_component->composite_mode = COMPOSITE_CLIENT; - wl_list_init(&border_component->child_components); - wl_list_insert(parent->child_components.prev, &border_component->link); - border_component->client.parent_component = parent; - border_component->type = type; -} - -static void -init_components(struct libdecor_frame_cairo *frame_cairo) -{ - init_server_component(&frame_cairo->title_bar.title, - TITLE); - init_client_component(&frame_cairo->title_bar.min, - &frame_cairo->title_bar.title, - BUTTON_MIN); - init_client_component(&frame_cairo->title_bar.max, - &frame_cairo->title_bar.title, - BUTTON_MAX); - init_client_component(&frame_cairo->title_bar.close, - &frame_cairo->title_bar.title, - BUTTON_CLOSE); - init_server_component(&frame_cairo->shadow, - SHADOW); -} - -static struct libdecor_frame_cairo * -libdecor_frame_cairo_new(struct libdecor_plugin_cairo *plugin_cairo) -{ - struct libdecor_frame_cairo *frame_cairo = zalloc(sizeof *frame_cairo); - cairo_t *cr; - - static const int size = 128; - static const int boundary = 32; - - frame_cairo->plugin_cairo = plugin_cairo; - frame_cairo->shadow_blur = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, size, size); - wl_list_insert(&plugin_cairo->visible_frame_list, &frame_cairo->link); - - init_components(frame_cairo); - - cr = cairo_create(frame_cairo->shadow_blur); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr, 0, 0, 0, 1); - cairo_rectangle(cr, boundary, boundary, size-2*boundary, size-2*boundary); - cairo_fill(cr); - cairo_destroy(cr); - blur_surface(frame_cairo->shadow_blur, 64); - - return frame_cairo; -} - -static int -libdecor_plugin_cairo_get_fd(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_cairo->context); - - return wl_display_get_fd(wl_display); -} - -static int -libdecor_plugin_cairo_dispatch(struct libdecor_plugin *plugin, - int timeout) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_cairo->context); - struct pollfd fds[1]; - int ret; - int dispatch_count = 0; - - while (wl_display_prepare_read(wl_display) != 0) - dispatch_count += wl_display_dispatch_pending(wl_display); - - if (wl_display_flush(wl_display) < 0 && - errno != EAGAIN) { - wl_display_cancel_read(wl_display); - return -errno; - } - - fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN }; - - ret = poll(fds, ARRAY_SIZE (fds), timeout); - if (ret > 0) { - if (fds[0].revents & POLLIN) { - wl_display_read_events(wl_display); - dispatch_count += wl_display_dispatch_pending(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return dispatch_count; - } - } else if (ret == 0) { - wl_display_cancel_read(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return -errno; - } -} - -static void -libdecor_plugin_cairo_set_handle_application_cursor(struct libdecor_plugin *plugin, - bool handle_cursor) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - - plugin_cairo->handle_cursor = handle_cursor; -} - -static struct libdecor_frame * -libdecor_plugin_cairo_frame_new(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - struct libdecor_frame_cairo *frame_cairo; - - frame_cairo = libdecor_frame_cairo_new(plugin_cairo); - - return &frame_cairo->frame; -} - -static void -toggle_maximized(struct libdecor_frame *const frame) -{ - if (!resizable((struct libdecor_frame_cairo *)frame)) - return; - - if (!(libdecor_frame_get_window_state(frame) & - LIBDECOR_WINDOW_STATE_MAXIMIZED)) - libdecor_frame_set_maximized(frame); - else - libdecor_frame_unset_maximized(frame); -} - -static void -buffer_release(void *user_data, - struct wl_buffer *wl_buffer) -{ - struct buffer *buffer = user_data; - - if (buffer->is_detached) - buffer_free(buffer); - else - buffer->in_use = false; -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release -}; - -static struct buffer * -create_shm_buffer(struct libdecor_plugin_cairo *plugin_cairo, - int width, - int height, - bool opaque, - int scale) -{ - struct wl_shm_pool *pool; - int fd, size, buffer_width, buffer_height, stride; - void *data; - struct buffer *buffer; - enum wl_shm_format buf_fmt; - - buffer_width = width * scale; - buffer_height = height * scale; - stride = buffer_width * 4; - size = stride * buffer_height; - - fd = libdecor_os_create_anonymous_file(size); - if (fd < 0) { - fprintf(stderr, "creating a buffer file for %d B failed: %s\n", - size, strerror(errno)); - return NULL; - } - - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %s\n", strerror(errno)); - close(fd); - return NULL; - } - - buf_fmt = opaque ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888; - - pool = wl_shm_create_pool(plugin_cairo->wl_shm, fd, size); - buffer = zalloc(sizeof *buffer); - buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0, - buffer_width, buffer_height, - stride, - buf_fmt); - wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); - wl_shm_pool_destroy(pool); - close(fd); - - buffer->data = data; - buffer->data_size = size; - buffer->width = width; - buffer->height = height; - buffer->scale = scale; - buffer->buffer_width = buffer_width; - buffer->buffer_height = buffer_height; - - return buffer; -} - -static void -buffer_free(struct buffer *buffer) -{ - if (buffer->wl_buffer) { - wl_buffer_destroy(buffer->wl_buffer); - munmap(buffer->data, buffer->data_size); - buffer->wl_buffer = NULL; - buffer->in_use = false; - } - free(buffer); -} - -static void -free_border_component(struct border_component *border_component) -{ - struct surface_output *surface_output, *surface_output_tmp; - - if (border_component->server.wl_surface) { - wl_subsurface_destroy(border_component->server.wl_subsurface); - border_component->server.wl_subsurface = NULL; - wl_surface_destroy(border_component->server.wl_surface); - border_component->server.wl_surface = NULL; - } - if (border_component->server.buffer) { - buffer_free(border_component->server.buffer); - border_component->server.buffer = NULL; - } - if (border_component->client.image) { - cairo_surface_destroy(border_component->client.image); - border_component->client.image = NULL; - } - if (border_component->server.output_list.next != NULL) { - wl_list_for_each_safe(surface_output, surface_output_tmp, - &border_component->server.output_list, link) { - wl_list_remove(&surface_output->link); - free(surface_output); - } - } -} - -static void -libdecor_plugin_cairo_frame_free(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ - struct libdecor_plugin_cairo *plugin_cairo = - (struct libdecor_plugin_cairo *) plugin; - struct libdecor_frame_cairo *frame_cairo = - (struct libdecor_frame_cairo *) frame; - struct seat *seat; - - wl_list_for_each(seat, &plugin_cairo->seat_list, link) { - if (seat->pointer_focus) { - if (wl_surface_get_user_data(seat->pointer_focus) == frame_cairo) - seat->pointer_focus = NULL; - if (seat->pointer_focus_frame == frame_cairo) - seat->pointer_focus_frame = NULL; - } - } - - free_border_component(&frame_cairo->title_bar.title); - free_border_component(&frame_cairo->title_bar.min); - free_border_component(&frame_cairo->title_bar.max); - free_border_component(&frame_cairo->title_bar.close); - frame_cairo->title_bar.is_showing = false; - free_border_component(&frame_cairo->shadow); - frame_cairo->shadow_showing = false; - if (frame_cairo->shadow_blur != NULL) { - cairo_surface_destroy(frame_cairo->shadow_blur); - frame_cairo->shadow_blur = NULL; - } - - free(frame_cairo->title); - frame_cairo->title = NULL; - - frame_cairo->decoration_type = DECORATION_TYPE_NONE; - - if (frame_cairo->link.next != NULL) - wl_list_remove(&frame_cairo->link); -} - -static bool -is_border_surfaces_showing(struct libdecor_frame_cairo *frame_cairo) -{ - return frame_cairo->shadow_showing; -} - -static bool -is_title_bar_surfaces_showing(struct libdecor_frame_cairo *frame_cairo) -{ - return frame_cairo->title_bar.is_showing; -} - -static struct border_component * -get_server_component(struct border_component *border_component) -{ - switch (border_component->composite_mode) { - case COMPOSITE_SERVER: - return border_component; - case COMPOSITE_CLIENT: - return get_server_component(border_component->client.parent_component); - } - return NULL; -} - -static void -redraw_border_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component) -{ - struct border_component *server_component; - - server_component = get_server_component(border_component); - draw_border_component(frame_cairo, server_component); -} - -static void -hide_border_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component) -{ - border_component->is_hidden = true; - - switch (border_component->composite_mode) { - case COMPOSITE_SERVER: - if (!border_component->server.wl_surface) - return; - - wl_surface_attach(border_component->server.wl_surface, - NULL, 0, 0); - wl_surface_commit(border_component->server.wl_surface); - break; - case COMPOSITE_CLIENT: - redraw_border_component(frame_cairo, border_component); - break; - } -} - -static void -hide_border_surfaces(struct libdecor_frame_cairo *frame_cairo) -{ - hide_border_component(frame_cairo, &frame_cairo->shadow); - frame_cairo->shadow_showing = false; -} - -static void -hide_title_bar_surfaces(struct libdecor_frame_cairo *frame_cairo) -{ - hide_border_component(frame_cairo, &frame_cairo->title_bar.title); - hide_border_component(frame_cairo, &frame_cairo->title_bar.min); - hide_border_component(frame_cairo, &frame_cairo->title_bar.max); - hide_border_component(frame_cairo, &frame_cairo->title_bar.close); - frame_cairo->title_bar.is_showing = false; -} - -static struct border_component * -get_component_for_surface(struct libdecor_frame_cairo *frame_cairo, - struct wl_surface *surface) -{ - if (frame_cairo->shadow.server.wl_surface == surface) - return &frame_cairo->shadow; - if (frame_cairo->title_bar.title.server.wl_surface == surface) - return &frame_cairo->title_bar.title; - return NULL; -} - -static void -calculate_component_size(struct libdecor_frame_cairo *frame_cairo, - enum component component, - int *component_x, - int *component_y, - int *component_width, - int *component_height); - -static void -update_component_focus(struct libdecor_frame_cairo *frame_cairo, - struct wl_surface *surface, - struct seat *seat) -{ - static struct border_component *border_component; - static struct border_component *child_component; - static struct border_component *focus_component; - - border_component = get_component_for_surface(frame_cairo, surface); - if (!border_component) { - focus_component = NULL; - goto out; - } - - focus_component = border_component; - wl_list_for_each(child_component, &border_component->child_components, link) { - int component_x = 0, component_y = 0; - int component_width = 0, component_height = 0; - - calculate_component_size(frame_cairo, child_component->type, - &component_x, &component_y, - &component_width, &component_height); - if (seat->pointer_x >= component_x && - seat->pointer_x < component_x + component_width && - seat->pointer_y >= component_y && - seat->pointer_y < component_y + component_height) { - focus_component = child_component; - break; - } - } - -out: - if (frame_cairo->grab) - frame_cairo->active = frame_cairo->grab; - else - frame_cairo->active = focus_component; - frame_cairo->focus = focus_component; - -} - -static void -ensure_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *cmpnt); - -static bool -redraw_scale(struct libdecor_frame_cairo *frame_cairo, - struct border_component *cmpnt) -{ - struct surface_output *surface_output; - int scale = 1; - - if (cmpnt->is_hidden) - return false; - - ensure_component(frame_cairo, cmpnt); - - wl_list_for_each(surface_output, &cmpnt->server.output_list, link) { - scale = MAX(scale, surface_output->output->scale); - } - if (scale != cmpnt->server.scale) { - cmpnt->server.scale = scale; - if ((cmpnt->type != SHADOW) || is_border_surfaces_showing(frame_cairo)) { - draw_border_component(frame_cairo, cmpnt); - return true; - } - } - return false; -} - -static bool -add_surface_output(struct libdecor_plugin_cairo *plugin_cairo, - struct wl_output *wl_output, - struct wl_list *list) -{ - struct output *output; - struct surface_output *surface_output; - - if (!own_output(wl_output)) - return false; - - output = wl_output_get_user_data(wl_output); - - if (output == NULL) - return false; - - surface_output = zalloc(sizeof *surface_output); - surface_output->output = output; - wl_list_insert(list, &surface_output->link); - return true; -} - -static void -surface_enter(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct libdecor_frame_cairo *frame_cairo = data; - struct border_component *cmpnt; - - if (!(own_surface(wl_surface) && own_output(wl_output))) - return; - - cmpnt = get_component_for_surface(frame_cairo, wl_surface); - if (cmpnt == NULL) - return; - - if (!add_surface_output(frame_cairo->plugin_cairo, wl_output, - &cmpnt->server.output_list)) - return; - - if (redraw_scale(frame_cairo, cmpnt)) - libdecor_frame_toplevel_commit(&frame_cairo->frame); -} - -static bool -remove_surface_output(struct wl_list *list, struct wl_output *wl_output) -{ - struct surface_output *surface_output; - wl_list_for_each(surface_output, list, link) { - if (surface_output->output->wl_output == wl_output) { - wl_list_remove(&surface_output->link); - free(surface_output); - return true; - } - } - return false; -} - -static void -surface_leave(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct libdecor_frame_cairo *frame_cairo = data; - struct border_component *cmpnt; - - if (!(own_surface(wl_surface) && own_output(wl_output))) - return; - - cmpnt = get_component_for_surface(frame_cairo, wl_surface); - if (cmpnt == NULL) - return; - - if (!remove_surface_output(&cmpnt->server.output_list, wl_output)) - return; - - if (redraw_scale(frame_cairo, cmpnt)) - libdecor_frame_toplevel_commit(&frame_cairo->frame); -} - -static struct wl_surface_listener surface_listener = { - surface_enter, - surface_leave, -}; - -static void -create_surface_subsurface_pair(struct libdecor_frame_cairo *frame_cairo, - struct wl_surface **out_wl_surface, - struct wl_subsurface **out_wl_subsurface) -{ - struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo; - struct libdecor_frame *frame = &frame_cairo->frame; - struct wl_compositor *wl_compositor = plugin_cairo->wl_compositor; - struct wl_subcompositor *wl_subcompositor = plugin_cairo->wl_subcompositor; - struct wl_surface *wl_surface; - struct wl_surface *parent; - struct wl_subsurface *wl_subsurface; - - wl_surface = wl_compositor_create_surface(wl_compositor); - wl_proxy_set_tag((struct wl_proxy *) wl_surface, - &libdecor_cairo_proxy_tag); - - parent = libdecor_frame_get_wl_surface(frame); - wl_subsurface = wl_subcompositor_get_subsurface(wl_subcompositor, - wl_surface, - parent); - - *out_wl_surface = wl_surface; - *out_wl_subsurface = wl_subsurface; -} - -static void -ensure_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *cmpnt) -{ - switch (cmpnt->composite_mode) { - case COMPOSITE_SERVER: - if (!cmpnt->server.wl_surface) { - wl_list_init(&cmpnt->server.output_list); - cmpnt->server.scale = 1; - create_surface_subsurface_pair(frame_cairo, - &cmpnt->server.wl_surface, - &cmpnt->server.wl_subsurface); - wl_surface_add_listener(cmpnt->server.wl_surface, - &surface_listener, - frame_cairo); - } - break; - case COMPOSITE_CLIENT: - wl_list_init(&cmpnt->server.output_list); - break; - } - - cmpnt->is_hidden = false; -} - -static void -ensure_border_surfaces(struct libdecor_frame_cairo *frame_cairo) -{ - int min_width, min_height, current_max_w, current_max_h; - - frame_cairo->shadow.opaque = false; - ensure_component(frame_cairo, &frame_cairo->shadow); - - libdecor_frame_get_min_content_size(&frame_cairo->frame, - &min_width, &min_height); - min_width = MAX(min_width, (int)MAX(56, 4 * BUTTON_WIDTH)); - min_height = MAX(min_height, (int)MAX(56, TITLE_HEIGHT + 1)); - libdecor_frame_set_min_content_size(&frame_cairo->frame, min_width, min_height); - libdecor_frame_get_max_content_size(&frame_cairo->frame, ¤t_max_w, - ¤t_max_h); - if (current_max_w && current_max_w < min_width) current_max_w = min_width; - if (current_max_h && current_max_h < min_height) current_max_h = min_height; - libdecor_frame_set_max_content_size(&frame_cairo->frame, current_max_w, - current_max_h); -} - - -static void -ensure_title_bar_surfaces(struct libdecor_frame_cairo *frame_cairo) -{ - frame_cairo->title_bar.title.opaque = true; - ensure_component(frame_cairo, &frame_cairo->title_bar.title); - - frame_cairo->title_bar.min.opaque = true; - ensure_component(frame_cairo, &frame_cairo->title_bar.min); - - frame_cairo->title_bar.max.opaque = true; - ensure_component(frame_cairo, &frame_cairo->title_bar.max); - - frame_cairo->title_bar.close.opaque = true; - ensure_component(frame_cairo, &frame_cairo->title_bar.close); -} - -static void -calculate_component_size(struct libdecor_frame_cairo *frame_cairo, - enum component component, - int *component_x, - int *component_y, - int *component_width, - int *component_height) -{ - struct libdecor_frame *frame = &frame_cairo->frame; - int content_width, content_height; - - content_width = libdecor_frame_get_content_width(frame); - content_height = libdecor_frame_get_content_height(frame); - - switch (component) { - case NONE: - *component_width = 0; - *component_height = 0; - return; - case SHADOW: - *component_x = -(int)SHADOW_MARGIN; - *component_y = -(int)(SHADOW_MARGIN+TITLE_HEIGHT); - *component_width = content_width + 2 * SHADOW_MARGIN; - *component_height = content_height - + 2 * SHADOW_MARGIN - + TITLE_HEIGHT; - return; - case TITLE: - *component_x = 0; - *component_y = -(int)TITLE_HEIGHT; - *component_width = content_width; - *component_height = TITLE_HEIGHT; - return; - case BUTTON_MIN: - *component_x = content_width - 3 * BUTTON_WIDTH; - *component_y = 0; - *component_width = BUTTON_WIDTH; - *component_height = TITLE_HEIGHT; - return; - case BUTTON_MAX: - *component_x = content_width - 2 * BUTTON_WIDTH; - *component_y = 0; - *component_width = BUTTON_WIDTH; - *component_height = TITLE_HEIGHT; - return; - case BUTTON_CLOSE: - *component_x = content_width - BUTTON_WIDTH; - *component_y = 0; - *component_width = BUTTON_WIDTH; - *component_height = TITLE_HEIGHT; - return; - } - - abort(); -} - -static int -border_component_get_scale(struct border_component *border_component) -{ - switch (border_component->composite_mode) { - case COMPOSITE_SERVER: - return border_component->server.scale; - case COMPOSITE_CLIENT: - return border_component_get_scale( - border_component->client.parent_component); - } - return 0; -} - -static void -draw_title_text(struct libdecor_frame_cairo *frame_cairo, - cairo_t *cr, - const int *title_width, - bool active) -{ - const uint32_t col_title = active ? COL_TITLE : COL_TITLE_INACT; - const uint32_t col_title_text = active ? COL_SYM : COL_SYM_INACT; - - PangoLayout *layout; - - /* title fade out at buttons */ - const int fade_width = 5 * BUTTON_WIDTH; - int fade_start; - cairo_pattern_t *fade; - - /* text position and dimensions */ - int text_extents_width, text_extents_height; - double text_x, text_y; - double text_width, text_height; - - const char *title; - - title = libdecor_frame_get_title((struct libdecor_frame*) frame_cairo); - if (!title) - return; - - layout = pango_cairo_create_layout(cr); - - pango_layout_set_text(layout, - title, - -1); - pango_layout_set_font_description(layout, frame_cairo->plugin_cairo->font); - pango_layout_get_size(layout, &text_extents_width, &text_extents_height); - - /* set text position and dimensions */ - text_width = text_extents_width / PANGO_SCALE; - text_height = text_extents_height / PANGO_SCALE; - text_x = *title_width / 2.0 - text_width / 2.0; - text_x += MIN(0.0, ((*title_width - fade_width) - (text_x + text_width))); - text_x = MAX(text_x, BUTTON_WIDTH); - text_y = TITLE_HEIGHT / 2.0 - text_height / 2.0; - - /* draw title text */ - cairo_move_to(cr, text_x, text_y); - cairo_set_rgba32(cr, &col_title_text); - pango_cairo_show_layout(cr, layout); - - /* draw fade-out from title text to buttons */ - fade_start = *title_width - fade_width; - fade = cairo_pattern_create_linear(fade_start, 0, - fade_start + 2 * BUTTON_WIDTH, 0); - cairo_pattern_add_color_stop_rgba(fade, 0, - red(&col_title), - green(&col_title), - blue(&col_title), - 0); - cairo_pattern_add_color_stop_rgb(fade, 1, - red(&col_title), - green(&col_title), - blue(&col_title)); - cairo_rectangle(cr, fade_start, 0, fade_width, TITLE_HEIGHT); - cairo_set_source(cr, fade); - cairo_fill(cr); - - cairo_pattern_destroy(fade); - g_object_unref(layout); -} - -static void -draw_component_content(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component, - int component_width, - int component_height, - enum component component) -{ - struct buffer *buffer; - cairo_surface_t *surface = NULL; - int width = 0, height = 0; - int scale; - cairo_t *cr; - - /* button symbol origin */ - const double x = BUTTON_WIDTH / 2 - SYM_DIM / 2 + 0.5; - const double y = TITLE_HEIGHT / 2 - SYM_DIM / 2 + 0.5; - - enum libdecor_window_state state; - - bool active; - - uint32_t col_title; - - bool cap_min, cap_max, cap_close; - - /* capabilities of decorations */ - cap_min = minimizable(frame_cairo); - cap_max = resizable(frame_cairo); - cap_close = closeable(frame_cairo); - - scale = border_component_get_scale(border_component); - - state = libdecor_frame_get_window_state((struct libdecor_frame *) frame_cairo); - - active = state & LIBDECOR_WINDOW_STATE_ACTIVE; - - col_title = active ? COL_TITLE : COL_TITLE_INACT; - - /* clear buffer */ - switch (border_component->composite_mode) { - case COMPOSITE_SERVER: - buffer = border_component->server.buffer; - - surface = cairo_image_surface_create_for_data( - buffer->data, CAIRO_FORMAT_ARGB32, - buffer->buffer_width, buffer->buffer_height, - cairo_format_stride_for_width( - CAIRO_FORMAT_ARGB32, - buffer->buffer_width) - ); - cairo_surface_set_device_scale(surface, scale, scale); - width = buffer->width; - height = buffer->height; - break; - case COMPOSITE_CLIENT: - surface = cairo_surface_reference(border_component->client.image); - width = cairo_image_surface_get_width(surface); - height = cairo_image_surface_get_height(surface); - break; - } - - cr = cairo_create(surface); - cairo_save(cr); - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_restore(cr); - - /* background */ - switch (component) { - case NONE: - break; - case SHADOW: - if (frame_cairo->decoration_type != DECORATION_TYPE_TILED) - render_shadow(cr, - frame_cairo->shadow_blur, - -(int)SHADOW_MARGIN/2, - -(int)SHADOW_MARGIN/2, - width + SHADOW_MARGIN, - height + SHADOW_MARGIN, - 64, - 64); - break; - case TITLE: - cairo_set_rgba32(cr, &col_title); - cairo_paint(cr); - break; - case BUTTON_MIN: - if (cap_min && frame_cairo->active == &frame_cairo->title_bar.min) - cairo_set_rgba32(cr, active ? &COL_BUTTON_MIN : &COL_BUTTON_INACT); - else - cairo_set_rgba32(cr, &col_title); - cairo_paint(cr); - break; - case BUTTON_MAX: - if (cap_max && frame_cairo->active == &frame_cairo->title_bar.max) - cairo_set_rgba32(cr, active ? &COL_BUTTON_MAX : &COL_BUTTON_INACT); - else - cairo_set_rgba32(cr, &col_title); - cairo_paint(cr); - break; - case BUTTON_CLOSE: - if (cap_close && frame_cairo->active == &frame_cairo->title_bar.close) - cairo_set_rgba32(cr, active ? &COL_BUTTON_CLOSE : &COL_BUTTON_INACT); - else - cairo_set_rgba32(cr, &col_title); - cairo_paint(cr); - break; - } - - /* button symbols */ - /* https://www.cairographics.org/FAQ/#sharp_lines */ - cairo_set_line_width(cr, 1); - - switch (component) { - case TITLE: - draw_title_text(frame_cairo,cr, &component_width, active); - break; - case BUTTON_MIN: - if (!active) { - /* inactive: use single desaturated color */ - cairo_set_rgba32(cr, &COL_SYM_INACT); - } else { - if (!cap_min || - frame_cairo->active == &frame_cairo->title_bar.min) { - /* active (a.k.a. prelight) */ - cairo_set_rgba32(cr, &COL_SYM_ACT); - } else { - /* normal */ - cairo_set_rgba32(cr, &COL_SYM); - } - } - cairo_move_to(cr, x, y + SYM_DIM - 1); - cairo_rel_line_to(cr, SYM_DIM - 1, 0); - cairo_stroke(cr); - break; - case BUTTON_MAX: - if (!active) { - /* inactive: use single desaturated color */ - cairo_set_rgba32(cr, &COL_SYM_INACT); - } else { - if (!cap_max || - frame_cairo->active == &frame_cairo->title_bar.max) { - /* active (a.k.a. prelight) */ - cairo_set_rgba32(cr, &COL_SYM_ACT); - } else { - /* normal */ - cairo_set_rgba32(cr, &COL_SYM); - } - } - - if (state & LIBDECOR_WINDOW_STATE_MAXIMIZED) { - const size_t small = 12; - cairo_rectangle(cr, - x, - y + SYM_DIM - small, - small - 1, - small - 1); - cairo_move_to(cr, - x + SYM_DIM - small, - y + SYM_DIM - small); - cairo_line_to(cr, x + SYM_DIM - small, y); - cairo_rel_line_to(cr, small - 1, 0); - cairo_rel_line_to(cr, 0, small - 1); - cairo_line_to(cr, x + small - 1, y + small - 1); - } else { - cairo_rectangle(cr, x, y, SYM_DIM - 1, SYM_DIM - 1); - } - cairo_stroke(cr); - break; - case BUTTON_CLOSE: - if (!active) { - /* inactive: use single desaturated color */ - cairo_set_rgba32(cr, &COL_SYM_INACT); - } else { - if (!cap_close || - frame_cairo->active == &frame_cairo->title_bar.close) { - /* active (a.k.a. prelight) */ - cairo_set_rgba32(cr, &COL_SYM_ACT); - } else { - /* normal */ - cairo_set_rgba32(cr, &COL_SYM); - } - } - cairo_move_to(cr, x, y); - cairo_rel_line_to(cr, SYM_DIM - 1, SYM_DIM - 1); - cairo_move_to(cr, x + SYM_DIM - 1, y); - cairo_line_to(cr, x, y + SYM_DIM - 1); - cairo_stroke(cr); - break; - default: - break; - } - - /* mask the toplevel surface */ - if (component == SHADOW) { - int component_x, component_y, component_width, component_height; - calculate_component_size(frame_cairo, component, - &component_x, &component_y, - &component_width, &component_height); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_rectangle(cr, -component_x, -component_y, - libdecor_frame_get_content_width( - &frame_cairo->frame), - libdecor_frame_get_content_height( - &frame_cairo->frame)); - cairo_fill(cr); - } - - cairo_destroy(cr); - cairo_surface_destroy(surface); -} - -static void -set_component_input_region(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component) -{ - if (border_component->type == SHADOW && frame_cairo->shadow_showing) { - struct wl_region *input_region; - int component_x; - int component_y; - int component_width; - int component_height; - - calculate_component_size(frame_cairo, border_component->type, - &component_x, &component_y, - &component_width, &component_height); - - /* - * the input region is the outer surface size minus the inner - * content size - */ - input_region = wl_compositor_create_region( - frame_cairo->plugin_cairo->wl_compositor); - wl_region_add(input_region, 0, 0, - component_width, component_height); - wl_region_subtract(input_region, -component_x, -component_y, - libdecor_frame_get_content_width(&frame_cairo->frame), - libdecor_frame_get_content_height(&frame_cairo->frame)); - wl_surface_set_input_region(border_component->server.wl_surface, - input_region); - wl_region_destroy(input_region); - } -} - -static void -ensure_component_realized_server(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component, - int component_width, - int component_height, - int scale) -{ - struct buffer *old_buffer; - struct buffer *buffer = NULL; - - old_buffer = border_component->server.buffer; - if (old_buffer) { - if (!old_buffer->in_use && - old_buffer->buffer_width == component_width * scale && - old_buffer->buffer_height == component_height * scale) { - buffer = old_buffer; - } else { - buffer_free(old_buffer); - border_component->server.buffer = NULL; - } - } - - if (!buffer) - buffer = create_shm_buffer(frame_cairo->plugin_cairo, - component_width, - component_height, - border_component->opaque, - border_component->server.scale); - - border_component->server.buffer = buffer; -} - -static void -ensure_component_realized_client(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component, - int component_width, - int component_height, - int scale) -{ - cairo_surface_t *old_image; - - old_image = border_component->client.image; - if (old_image) { - int cairo_buffer_width; - int cairo_buffer_height; - double x_scale; - double y_scale; - - cairo_surface_get_device_scale(old_image, &x_scale, &y_scale); - cairo_buffer_width = - (int) round(cairo_image_surface_get_width(old_image) * - x_scale); - cairo_buffer_height = - (int) round(cairo_image_surface_get_height(old_image) * - y_scale); - - if (cairo_buffer_width != component_width * scale || - cairo_buffer_height != component_height * scale) { - cairo_surface_destroy(old_image); - border_component->client.image = NULL; - } - } - - if (!border_component->client.image) { - cairo_surface_t *new_image; - - new_image = - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - component_width * scale, - component_height * scale); - cairo_surface_set_device_scale(new_image, scale, scale); - border_component->client.image = new_image; - } - -} - -static void -ensure_component_realized(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component, - int component_width, - int component_height, - int scale) -{ - switch (border_component->composite_mode) { - case COMPOSITE_SERVER: - ensure_component_realized_server(frame_cairo, border_component, - component_width, - component_height, - scale); - break; - case COMPOSITE_CLIENT: - ensure_component_realized_client(frame_cairo, border_component, - component_width, - component_height, - scale); - break; - } -} - -static cairo_t * -create_cairo_for_parent(struct border_component *border_component) -{ - struct border_component *parent = - border_component->client.parent_component; - struct buffer *buffer; - struct border_component *server_component; - cairo_surface_t *parent_surface; - cairo_t *cr; - - switch (parent->composite_mode) { - case COMPOSITE_SERVER: - buffer = parent->server.buffer; - parent_surface = cairo_image_surface_create_for_data( - buffer->data, CAIRO_FORMAT_ARGB32, - buffer->buffer_width, buffer->buffer_height, - cairo_format_stride_for_width( - CAIRO_FORMAT_ARGB32, - buffer->buffer_width) - ); - cr = cairo_create(parent_surface); - cairo_surface_destroy(parent_surface); - cairo_scale(cr, buffer->scale, buffer->scale); - return cr; - case COMPOSITE_CLIENT: - cr = cairo_create(parent->client.image); - server_component = get_server_component(border_component); - cairo_scale(cr, - server_component->server.scale, - server_component->server.scale); - return cr; - } - return NULL; -} - -static void -draw_border_component(struct libdecor_frame_cairo *frame_cairo, - struct border_component *border_component) -{ - enum component component = border_component->type; - struct buffer *buffer; - cairo_t *cr; - int component_x; - int component_y; - int component_width; - int component_height; - int scale; - struct border_component *child_component; - - if (border_component->is_hidden) - return; - - calculate_component_size(frame_cairo, component, - &component_x, &component_y, - &component_width, &component_height); - - set_component_input_region(frame_cairo, border_component); - - scale = border_component_get_scale(border_component); - ensure_component_realized(frame_cairo, border_component, - component_width, - component_height, - scale); - - draw_component_content(frame_cairo, - border_component, - component_width, component_height, - component); - - switch(border_component->composite_mode) { - case COMPOSITE_SERVER: - buffer = border_component->server.buffer; - wl_surface_attach(border_component->server.wl_surface, - buffer->wl_buffer, - 0, 0); - wl_surface_set_buffer_scale(border_component->server.wl_surface, - buffer->scale); - buffer->in_use = true; - wl_surface_commit(border_component->server.wl_surface); - wl_surface_damage_buffer(border_component->server.wl_surface, 0, 0, - component_width * scale, - component_height * scale); - wl_subsurface_set_position(border_component->server.wl_subsurface, - component_x, component_y); - break; - case COMPOSITE_CLIENT: - cr = create_cairo_for_parent(border_component); - cairo_set_source_surface(cr, - border_component->client.image, - component_x, component_y); - cairo_paint(cr); - cairo_destroy(cr); - break; - } - - wl_list_for_each(child_component, &border_component->child_components, link) - draw_border_component(frame_cairo, child_component); -} - -static void -draw_border(struct libdecor_frame_cairo *frame_cairo) -{ - draw_border_component(frame_cairo, &frame_cairo->shadow); - frame_cairo->shadow_showing = true; -} - -static void -draw_title_bar(struct libdecor_frame_cairo *frame_cairo) -{ - draw_border_component(frame_cairo, &frame_cairo->title_bar.title); - frame_cairo->title_bar.is_showing = true; -} - -static void -draw_decoration(struct libdecor_frame_cairo *frame_cairo) -{ - switch (frame_cairo->decoration_type) { - case DECORATION_TYPE_NONE: - if (frame_cairo->link.next != NULL) - wl_list_remove(&frame_cairo->link); - if (is_border_surfaces_showing(frame_cairo)) - hide_border_surfaces(frame_cairo); - if (is_title_bar_surfaces_showing(frame_cairo)) - hide_title_bar_surfaces(frame_cairo); - break; - case DECORATION_TYPE_TILED: - case DECORATION_TYPE_ALL: - /* show borders */ - ensure_border_surfaces(frame_cairo); - draw_border(frame_cairo); - /* show title bar */ - ensure_title_bar_surfaces(frame_cairo); - draw_title_bar(frame_cairo); - /* link frame */ - if (frame_cairo->link.next == NULL) - wl_list_insert( - &frame_cairo->plugin_cairo->visible_frame_list, - &frame_cairo->link); - break; - case DECORATION_TYPE_MAXIMIZED: - /* hide borders */ - if (is_border_surfaces_showing(frame_cairo)) - hide_border_surfaces(frame_cairo); - /* show title bar */ - ensure_title_bar_surfaces(frame_cairo); - draw_title_bar(frame_cairo); - /* link frame */ - if (frame_cairo->link.next == NULL) - wl_list_insert( - &frame_cairo->plugin_cairo->visible_frame_list, - &frame_cairo->link); - break; - } -} - -static enum decoration_type -window_state_to_decoration_type(enum libdecor_window_state window_state) -{ - if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) - return DECORATION_TYPE_NONE; - else if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) - /* title bar, no shadows */ - return DECORATION_TYPE_MAXIMIZED; - else if (window_state & LIBDECOR_WINDOW_STATE_TILED_LEFT || - window_state & LIBDECOR_WINDOW_STATE_TILED_RIGHT || - window_state & LIBDECOR_WINDOW_STATE_TILED_TOP || - window_state & LIBDECOR_WINDOW_STATE_TILED_BOTTOM) - /* title bar, invisible shadows */ - return DECORATION_TYPE_TILED; - else - /* title bar, shadows */ - return DECORATION_TYPE_ALL; -} - -static void -libdecor_plugin_cairo_frame_commit(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration) -{ - struct libdecor_frame_cairo *frame_cairo = - (struct libdecor_frame_cairo *) frame; - enum libdecor_window_state old_window_state; - enum libdecor_window_state new_window_state; - int old_content_width, old_content_height; - int new_content_width, new_content_height; - enum decoration_type old_decoration_type; - enum decoration_type new_decoration_type; - - old_window_state = frame_cairo->window_state; - new_window_state = libdecor_frame_get_window_state(frame); - - old_content_width = frame_cairo->content_width; - old_content_height = frame_cairo->content_height; - new_content_width = libdecor_frame_get_content_width(frame); - new_content_height = libdecor_frame_get_content_height(frame); - - old_decoration_type = frame_cairo->decoration_type; - new_decoration_type = window_state_to_decoration_type(new_window_state); - - if (old_decoration_type == new_decoration_type && - old_content_width == new_content_width && - old_content_height == new_content_height && - old_window_state == new_window_state) - return; - - frame_cairo->content_width = new_content_width; - frame_cairo->content_height = new_content_height; - frame_cairo->decoration_type = new_decoration_type; - frame_cairo->window_state = new_window_state; - - draw_decoration(frame_cairo); -} - -static void -libdecor_plugin_cairo_frame_property_changed(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ - struct libdecor_frame_cairo *frame_cairo = - (struct libdecor_frame_cairo *) frame; - bool redraw_needed = false; - const char *new_title; - - new_title = libdecor_frame_get_title(frame); - if (frame_cairo->title_bar.is_showing) { - if (!streql(frame_cairo->title, new_title)) - redraw_needed = true; - } - - if (frame_cairo->title) { - free(frame_cairo->title); - frame_cairo->title = NULL; - } - - if (new_title) { - frame_cairo->title = strdup(new_title); - } - - if (frame_cairo->capabilities != libdecor_frame_get_capabilities(frame)) { - frame_cairo->capabilities = libdecor_frame_get_capabilities(frame); - redraw_needed = true; - } - - if (redraw_needed) { - draw_decoration(frame_cairo); - libdecor_frame_toplevel_commit(frame); - } -} - -static bool -streq(const char *str1, - const char *str2) -{ - if (!str1 && !str2) - return true; - - if (str1 && str2) - return strcmp(str1, str2) == 0; - - return false; -} - -static void -libdecor_plugin_cairo_frame_popup_grab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_cairo *frame_cairo = - (struct libdecor_frame_cairo *) frame; - struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo; - struct seat *seat; - - wl_list_for_each(seat, &plugin_cairo->seat_list, link) { - if (streq(seat->name, seat_name)) { - if (seat->grabbed) { - fprintf(stderr, "libdecor-WARNING: Application " - "tried to grab seat twice\n"); - } - synthesize_pointer_leave(seat); - seat->grabbed = true; - return; - } - } - - fprintf(stderr, - "libdecor-WARNING: Application tried to grab unknown seat\n"); -} - -static void -libdecor_plugin_cairo_frame_popup_ungrab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_cairo *frame_cairo = - (struct libdecor_frame_cairo *) frame; - struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo; - struct seat *seat; - - wl_list_for_each(seat, &plugin_cairo->seat_list, link) { - if (streq(seat->name, seat_name)) { - if (!seat->grabbed) { - fprintf(stderr, "libdecor-WARNING: Application " - "tried to ungrab seat twice\n"); - } - seat->grabbed = false; - synthesize_pointer_enter(seat); - sync_active_component(frame_cairo, seat); - return; - } - } - - fprintf(stderr, - "libdecor-WARNING: Application tried to ungrab unknown seat\n"); -} - -static bool -libdecor_plugin_cairo_frame_get_border_size(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_configuration *configuration, - int *left, - int *right, - int *top, - int *bottom) -{ - enum libdecor_window_state window_state; - - if (configuration) { - if (!libdecor_configuration_get_window_state( - configuration, &window_state)) - return false; - } else { - window_state = libdecor_frame_get_window_state(frame); - } - - if (left) - *left = 0; - if (right) - *right = 0; - if (bottom) - *bottom = 0; - if (top) { - enum decoration_type type = window_state_to_decoration_type(window_state); - - if (((struct libdecor_frame_cairo *)frame)->title_bar.is_showing && - (type != DECORATION_TYPE_NONE)) - *top = TITLE_HEIGHT; - else - *top = 0; - } - - return true; -} - -static struct libdecor_plugin_interface cairo_plugin_iface = { - .destroy = libdecor_plugin_cairo_destroy, - .get_fd = libdecor_plugin_cairo_get_fd, - .dispatch = libdecor_plugin_cairo_dispatch, - - .set_handle_application_cursor = libdecor_plugin_cairo_set_handle_application_cursor, - - .frame_new = libdecor_plugin_cairo_frame_new, - .frame_free = libdecor_plugin_cairo_frame_free, - .frame_commit = libdecor_plugin_cairo_frame_commit, - .frame_property_changed = libdecor_plugin_cairo_frame_property_changed, - .frame_popup_grab = libdecor_plugin_cairo_frame_popup_grab, - .frame_popup_ungrab = libdecor_plugin_cairo_frame_popup_ungrab, - .frame_get_border_size = libdecor_plugin_cairo_frame_get_border_size, -}; - -static void -init_wl_compositor(struct libdecor_plugin_cairo *plugin_cairo, - uint32_t id, - uint32_t version) -{ - plugin_cairo->wl_compositor = - wl_registry_bind(plugin_cairo->wl_registry, - id, &wl_compositor_interface, - MIN(version, 4)); -} - -static void -init_wl_subcompositor(struct libdecor_plugin_cairo *plugin_cairo, - uint32_t id, - uint32_t version) -{ - plugin_cairo->wl_subcompositor = - wl_registry_bind(plugin_cairo->wl_registry, - id, &wl_subcompositor_interface, 1); -} - -static void -shm_format(void *user_data, - struct wl_shm *wl_shm, - uint32_t format) -{ - struct libdecor_plugin_cairo *plugin_cairo = user_data; - - if (format == WL_SHM_FORMAT_ARGB8888) - plugin_cairo->has_argb = true; -} - -struct wl_shm_listener shm_listener = { - shm_format -}; - -static void -shm_callback(void *user_data, - struct wl_callback *callback, - uint32_t time) -{ - struct libdecor_plugin_cairo *plugin_cairo = user_data; - struct libdecor *context = plugin_cairo->context; - - wl_callback_destroy(callback); - plugin_cairo->globals_callback_shm = NULL; - - if (!plugin_cairo->has_argb) { - libdecor_notify_plugin_error( - context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "Compositor is missing required shm format"); - return; - } - - libdecor_notify_plugin_ready(context); -} - -static const struct wl_callback_listener shm_callback_listener = { - shm_callback -}; - -static void -init_wl_shm(struct libdecor_plugin_cairo *plugin_cairo, - uint32_t id, - uint32_t version) -{ - struct libdecor *context = plugin_cairo->context; - struct wl_display *wl_display = libdecor_get_wl_display(context); - - plugin_cairo->wl_shm = - wl_registry_bind(plugin_cairo->wl_registry, - id, &wl_shm_interface, 1); - wl_shm_add_listener(plugin_cairo->wl_shm, &shm_listener, plugin_cairo); - - plugin_cairo->globals_callback_shm = wl_display_sync(wl_display); - wl_callback_add_listener(plugin_cairo->globals_callback_shm, - &shm_callback_listener, - plugin_cairo); -} - -static void -cursor_surface_enter(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct seat *seat = data; - - if(own_output(wl_output)) { - struct cursor_output *cursor_output; - cursor_output = zalloc(sizeof *cursor_output); - cursor_output->output = wl_output_get_user_data(wl_output); - wl_list_insert(&seat->cursor_outputs, &cursor_output->link); - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static void -cursor_surface_leave(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct seat *seat = data; - - if(own_output(wl_output)) { - struct cursor_output *cursor_output, *tmp; - wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) { - if (cursor_output->output->wl_output == wl_output) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - } - - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static struct wl_surface_listener cursor_surface_listener = { - cursor_surface_enter, - cursor_surface_leave, -}; - -static void -ensure_cursor_surface(struct seat *seat) -{ - struct wl_compositor *wl_compositor = seat->plugin_cairo->wl_compositor; - - if (seat->cursor_surface) - return; - - seat->cursor_surface = wl_compositor_create_surface(wl_compositor); - wl_surface_add_listener(seat->cursor_surface, - &cursor_surface_listener, seat); -} - -static bool -ensure_cursor_theme(struct seat *seat) -{ - struct libdecor_plugin_cairo *plugin_cairo = seat->plugin_cairo; - int scale = 1; - struct wl_cursor_theme *theme; - struct cursor_output *cursor_output; - - wl_list_for_each(cursor_output, &seat->cursor_outputs, link) { - scale = MAX(scale, cursor_output->output->scale); - } - - if (seat->cursor_theme && seat->cursor_scale == scale) - return false; - - seat->cursor_scale = scale; - theme = wl_cursor_theme_load(plugin_cairo->cursor_theme_name, - plugin_cairo->cursor_size * scale, - plugin_cairo->wl_shm); - if (theme == NULL) - return false; - - if (seat->cursor_theme) - wl_cursor_theme_destroy(seat->cursor_theme); - - seat->cursor_theme = theme; - - for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) { - seat->cursors[i] = wl_cursor_theme_get_cursor( - seat->cursor_theme, - cursor_names[i]); - } - - seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, - "left_ptr"); - seat->current_cursor = seat->cursor_left_ptr; - - return true; -} - -enum libdecor_resize_edge -component_edge(const struct border_component *cmpnt, - const int pointer_x, - const int pointer_y, - const int margin) -{ - const bool top = pointer_y < margin * 2; - const bool bottom = pointer_y > (cmpnt->server.buffer->height - margin * 2); - const bool left = pointer_x < margin * 2; - const bool right = pointer_x > (cmpnt->server.buffer->width - margin * 2); - - if (top) - if (left) - return LIBDECOR_RESIZE_EDGE_TOP_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_TOP_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_TOP; - else if (bottom) - if (left) - return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_BOTTOM; - else if (left) - return LIBDECOR_RESIZE_EDGE_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_NONE; -} - -static bool -update_local_cursor(struct seat *seat) -{ - if (!seat->pointer_focus) { - seat->current_cursor = seat->cursor_left_ptr; - return false; - } - - if (!own_surface(seat->pointer_focus)) { - if (seat->plugin_cairo->handle_cursor) { - seat->current_cursor = seat->cursor_left_ptr; - return true; - } else { - return false; - } - } - - struct libdecor_frame_cairo *frame_cairo = - wl_surface_get_user_data(seat->pointer_focus); - struct wl_cursor *wl_cursor = NULL; - - if (!frame_cairo || !frame_cairo->active) { - seat->current_cursor = seat->cursor_left_ptr; - return false; - } - - bool theme_updated = ensure_cursor_theme(seat); - - if (frame_cairo->active->type == SHADOW && - is_border_surfaces_showing(frame_cairo) && - resizable(frame_cairo)) { - enum libdecor_resize_edge edge; - edge = component_edge(frame_cairo->active, - seat->pointer_x, - seat->pointer_y, SHADOW_MARGIN); - - if (edge != LIBDECOR_RESIZE_EDGE_NONE) - wl_cursor = seat->cursors[edge - 1]; - } else { - wl_cursor = seat->cursor_left_ptr; - } - - if (seat->current_cursor != wl_cursor) { - seat->current_cursor = wl_cursor; - return true; - } - - return theme_updated; -} - -static void -send_cursor(struct seat *seat) -{ - struct wl_cursor_image *image; - struct wl_buffer *buffer; - - if (seat->pointer_focus == NULL || seat->current_cursor == NULL) - return; - - image = seat->current_cursor->images[0]; - buffer = wl_cursor_image_get_buffer(image); - wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width * seat->cursor_scale, - image->height * seat->cursor_scale); - wl_surface_commit(seat->cursor_surface); - wl_pointer_set_cursor(seat->wl_pointer, seat->serial, - seat->cursor_surface, - image->hotspot_x / seat->cursor_scale, - image->hotspot_y / seat->cursor_scale); -} - -static void -sync_active_component(struct libdecor_frame_cairo *frame_cairo, - struct seat *seat) -{ - struct border_component *old_active; - - if (!seat->pointer_focus) - return; - - old_active = frame_cairo->active; - update_component_focus(frame_cairo, seat->pointer_focus, seat); - if (old_active != frame_cairo->active) { - draw_decoration(frame_cairo); - libdecor_frame_toplevel_commit(&frame_cairo->frame); - } - - if (update_local_cursor(seat)) - send_cursor(seat); -} - -static void -synthesize_pointer_enter(struct seat *seat) -{ - struct wl_surface *surface; - struct libdecor_frame_cairo *frame_cairo; - - surface = seat->pointer_focus; - if (!surface || !own_surface(surface)) - return; - - frame_cairo = wl_surface_get_user_data(surface); - if (!frame_cairo) - return; - - update_component_focus(frame_cairo, seat->pointer_focus, seat); - frame_cairo->grab = NULL; - - /* update decorations */ - if (frame_cairo->active) { - draw_decoration(frame_cairo); - libdecor_frame_toplevel_commit(&frame_cairo->frame); - } - - update_local_cursor(seat); - send_cursor(seat); -} - -static void -synthesize_pointer_leave(struct seat *seat) -{ - struct wl_surface *surface; - struct libdecor_frame_cairo *frame_cairo; - - surface = seat->pointer_focus; - if (!surface || !own_surface(surface)) - return; - - frame_cairo = wl_surface_get_user_data(surface); - if (!frame_cairo) - return; - - if (!frame_cairo->active) - return; - - frame_cairo->active = NULL; - draw_decoration(frame_cairo); - libdecor_frame_toplevel_commit(&frame_cairo->frame); - update_local_cursor(seat); -} - -static void -pointer_enter(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - struct seat *seat = data; - struct libdecor_frame_cairo *frame_cairo = NULL; - - if (!surface) - return; - - if (!own_surface(surface)) { - struct seat *seat = wl_pointer_get_user_data(wl_pointer); - struct libdecor_plugin_cairo *plugin_cairo = seat->plugin_cairo; - - if (!plugin_cairo->handle_cursor) - return; - } else { - frame_cairo = wl_surface_get_user_data(surface); - } - - ensure_cursor_surface(seat); - - seat->pointer_x = wl_fixed_to_int(surface_x); - seat->pointer_y = wl_fixed_to_int(surface_y); - seat->serial = serial; - seat->pointer_focus = surface; - seat->pointer_focus_frame = frame_cairo; - - if (seat->grabbed) - return; - - synthesize_pointer_enter(seat); -} - -static void -pointer_leave(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface) -{ - struct seat *seat = data; - - if (!surface) - return; - - if (!own_surface(surface)) - return; - - synthesize_pointer_leave(seat); - seat->pointer_focus = NULL; - seat->pointer_focus_frame = NULL; -} - -static void -pointer_motion(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - struct seat *seat = data; - - seat->pointer_x = wl_fixed_to_int(surface_x); - seat->pointer_y = wl_fixed_to_int(surface_y); - - if (seat->grabbed) - return; - - if (!seat->pointer_focus_frame) - return; - - sync_active_component(seat->pointer_focus_frame, seat); -} - -static void -pointer_button(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - struct seat *seat = data; - struct libdecor_frame_cairo *frame_cairo; - - if (!seat->pointer_focus || !own_surface(seat->pointer_focus)) - return; - - frame_cairo = wl_surface_get_user_data(seat->pointer_focus); - if (!frame_cairo) - return; - - if (seat->grabbed) { - libdecor_frame_dismiss_popup(&frame_cairo->frame, seat->name); - return; - } - - if (!frame_cairo->active) - return; - - if (button == BTN_LEFT) { - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - enum libdecor_resize_edge edge = - LIBDECOR_RESIZE_EDGE_NONE; - - frame_cairo->grab = NULL; - - switch (frame_cairo->active->type) { - case SHADOW: - edge = component_edge(frame_cairo->active, - seat->pointer_x, - seat->pointer_y, - SHADOW_MARGIN); - break; - case TITLE: - if (time-seat->pointer_button_time_stamp < - DOUBLE_CLICK_TIME_MS) { - toggle_maximized(&frame_cairo->frame); - } - else if (moveable(frame_cairo)) { - seat->pointer_button_time_stamp = time; - libdecor_frame_move(&frame_cairo->frame, - seat->wl_seat, - serial); - } - break; - case BUTTON_MIN: - case BUTTON_MAX: - case BUTTON_CLOSE: - frame_cairo->grab = frame_cairo->active; - break; - default: - break; - } - - if (edge != LIBDECOR_RESIZE_EDGE_NONE && - resizable(frame_cairo)) { - libdecor_frame_resize( - &frame_cairo->frame, - seat->wl_seat, - serial, - edge); - } - } - else if (state == WL_POINTER_BUTTON_STATE_RELEASED && - frame_cairo->grab) { - libdecor_frame_ref(&frame_cairo->frame); - if (frame_cairo->grab == frame_cairo->focus) { - switch (frame_cairo->active->type) { - case BUTTON_MIN: - if (minimizable(frame_cairo)) - libdecor_frame_set_minimized( - &frame_cairo->frame); - break; - case BUTTON_MAX: - toggle_maximized(&frame_cairo->frame); - break; - case BUTTON_CLOSE: - if (closeable(frame_cairo)) - libdecor_frame_close(&frame_cairo->frame); - break; - default: - break; - } - } - frame_cairo->grab = NULL; - sync_active_component(frame_cairo, seat); - libdecor_frame_unref(&frame_cairo->frame); - } - } - else if (button == BTN_RIGHT && - state == WL_POINTER_BUTTON_STATE_PRESSED && - seat->pointer_focus == frame_cairo->title_bar.title.server.wl_surface) { - libdecor_frame_show_window_menu(&frame_cairo->frame, - seat->wl_seat, - serial, - seat->pointer_x, - seat->pointer_y - TITLE_HEIGHT); - } -} - -static void -pointer_axis(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ -} - -static struct wl_pointer_listener pointer_listener = { - pointer_enter, - pointer_leave, - pointer_motion, - pointer_button, - pointer_axis -}; - -static void -seat_capabilities(void *data, - struct wl_seat *wl_seat, - uint32_t capabilities) -{ - struct seat *seat = data; - - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && - !seat->wl_pointer) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(seat->wl_pointer, - &pointer_listener, seat); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && - seat->wl_pointer) { - wl_pointer_release(seat->wl_pointer); - seat->wl_pointer = NULL; - } -} - -static void -seat_name(void *data, - struct wl_seat *wl_seat, - const char *name) -{ - struct seat *seat = data; - - seat->name = strdup(name); -} - -static struct wl_seat_listener seat_listener = { - seat_capabilities, - seat_name -}; - -static void -init_wl_seat(struct libdecor_plugin_cairo *plugin_cairo, - uint32_t id, - uint32_t version) -{ - struct seat *seat; - - if (version < 3) { - libdecor_notify_plugin_error( - plugin_cairo->context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "%s version 3 required but only version %i is available\n", - wl_seat_interface.name, version); - } - - seat = zalloc(sizeof *seat); - seat->cursor_scale = 1; - seat->plugin_cairo = plugin_cairo; - wl_list_init(&seat->cursor_outputs); - wl_list_insert(&plugin_cairo->seat_list, &seat->link); - seat->wl_seat = - wl_registry_bind(plugin_cairo->wl_registry, - id, &wl_seat_interface, 3); - wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); -} - -static void -output_geometry(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform) -{ -} - -static void -output_mode(void *data, - struct wl_output *wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) -{ -} - -static void -output_done(void *data, - struct wl_output *wl_output) -{ - struct output *output = data; - struct libdecor_frame_cairo *frame_cairo; - struct seat *seat; - - wl_list_for_each(frame_cairo, - &output->plugin_cairo->visible_frame_list, link) { - bool updated = false; - updated |= redraw_scale(frame_cairo, &frame_cairo->shadow); - updated |= redraw_scale(frame_cairo, &frame_cairo->title_bar.title); - if (updated) - libdecor_frame_toplevel_commit(&frame_cairo->frame); - } - wl_list_for_each(seat, &output->plugin_cairo->seat_list, link) { - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static void -output_scale(void *data, - struct wl_output *wl_output, - int32_t factor) -{ - struct output *output = data; - - output->scale = factor; -} - -static struct wl_output_listener output_listener = { - output_geometry, - output_mode, - output_done, - output_scale -}; - -static void -init_wl_output(struct libdecor_plugin_cairo *plugin_cairo, - uint32_t id, - uint32_t version) -{ - struct output *output; - - if (version < 2) { - libdecor_notify_plugin_error( - plugin_cairo->context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "%s version 2 required but only version %i is available\n", - wl_output_interface.name, version); - } - - output = zalloc(sizeof *output); - output->plugin_cairo = plugin_cairo; - wl_list_insert(&plugin_cairo->output_list, &output->link); - output->id = id; - output->wl_output = - wl_registry_bind(plugin_cairo->wl_registry, - id, &wl_output_interface, - MIN (version, 3)); - wl_proxy_set_tag((struct wl_proxy *) output->wl_output, - &libdecor_cairo_proxy_tag); - wl_output_add_listener(output->wl_output, &output_listener, output); -} - -static void -registry_handle_global(void *user_data, - struct wl_registry *wl_registry, - uint32_t id, - const char *interface, - uint32_t version) -{ - struct libdecor_plugin_cairo *plugin_cairo = user_data; - - if (strcmp(interface, "wl_compositor") == 0) - init_wl_compositor(plugin_cairo, id, version); - else if (strcmp(interface, "wl_subcompositor") == 0) - init_wl_subcompositor(plugin_cairo, id, version); - else if (strcmp(interface, "wl_shm") == 0) - init_wl_shm(plugin_cairo, id, version); - else if (strcmp(interface, "wl_seat") == 0) - init_wl_seat(plugin_cairo, id, version); - else if (strcmp(interface, "wl_output") == 0) - init_wl_output(plugin_cairo, id, version); -} - -static void -remove_surface_outputs(struct border_component *cmpnt, struct output *output) -{ - struct surface_output *surface_output; - wl_list_for_each(surface_output, &cmpnt->server.output_list, link) { - if (surface_output->output == output) { - wl_list_remove(&surface_output->link); - free(surface_output); - break; - } - } -} - -static void -output_removed(struct libdecor_plugin_cairo *plugin_cairo, - struct output *output) -{ - struct libdecor_frame_cairo *frame_cairo; - struct seat *seat; - - wl_list_for_each(frame_cairo, &plugin_cairo->visible_frame_list, link) { - remove_surface_outputs(&frame_cairo->shadow, output); - remove_surface_outputs(&frame_cairo->title_bar.title, output); - remove_surface_outputs(&frame_cairo->title_bar.min, output); - remove_surface_outputs(&frame_cairo->title_bar.max, output); - remove_surface_outputs(&frame_cairo->title_bar.close, output); - } - wl_list_for_each(seat, &plugin_cairo->seat_list, link) { - struct cursor_output *cursor_output, *tmp; - wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) { - if (cursor_output->output == output) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - } - } - - wl_list_remove(&output->link); - wl_output_destroy(output->wl_output); - free(output); -} - -static void -registry_handle_global_remove(void *user_data, - struct wl_registry *wl_registry, - uint32_t name) -{ - struct libdecor_plugin_cairo *plugin_cairo = user_data; - struct output *output; - - wl_list_for_each(output, &plugin_cairo->output_list, link) { - if (output->id == name) { - output_removed(plugin_cairo, output); - break; - } - } -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static bool -has_required_globals(struct libdecor_plugin_cairo *plugin_cairo) -{ - if (!plugin_cairo->wl_compositor) - return false; - if (!plugin_cairo->wl_subcompositor) - return false; - if (!plugin_cairo->wl_shm) - return false; - - return true; -} - -static void -globals_callback(void *user_data, - struct wl_callback *callback, - uint32_t time) -{ - struct libdecor_plugin_cairo *plugin_cairo = user_data; - - wl_callback_destroy(callback); - plugin_cairo->globals_callback = NULL; -} - -static const struct wl_callback_listener globals_callback_listener = { - globals_callback -}; - -static struct libdecor_plugin * -libdecor_plugin_new(struct libdecor *context) -{ - struct libdecor_plugin_cairo *plugin_cairo; - struct wl_display *wl_display; - - plugin_cairo = zalloc(sizeof *plugin_cairo); - libdecor_plugin_init(&plugin_cairo->plugin, - context, - &cairo_plugin_iface); - plugin_cairo->context = context; - - wl_list_init(&plugin_cairo->visible_frame_list); - wl_list_init(&plugin_cairo->seat_list); - wl_list_init(&plugin_cairo->output_list); - - /* fetch cursor theme and size*/ - if (!libdecor_get_cursor_settings(&plugin_cairo->cursor_theme_name, - &plugin_cairo->cursor_size)) { - plugin_cairo->cursor_theme_name = NULL; - plugin_cairo->cursor_size = 24; - } - - /* define a sens-serif bold font at symbol size */ - plugin_cairo->font = pango_font_description_new(); - pango_font_description_set_family(plugin_cairo->font, "sans"); - pango_font_description_set_weight(plugin_cairo->font, PANGO_WEIGHT_BOLD); - pango_font_description_set_absolute_size(plugin_cairo->font, SYM_DIM * PANGO_SCALE); - - wl_display = libdecor_get_wl_display(context); - plugin_cairo->wl_registry = wl_display_get_registry(wl_display); - wl_registry_add_listener(plugin_cairo->wl_registry, - ®istry_listener, - plugin_cairo); - - plugin_cairo->globals_callback = wl_display_sync(wl_display); - wl_callback_add_listener(plugin_cairo->globals_callback, - &globals_callback_listener, - plugin_cairo); - wl_display_roundtrip(wl_display); - - if (!has_required_globals(plugin_cairo)) { - fprintf(stderr, "libdecor-cairo-WARNING: Could not get required globals\n"); - libdecor_plugin_cairo_destroy(&plugin_cairo->plugin); - return NULL; - } - - return &plugin_cairo->plugin; -} - -static struct libdecor_plugin_priority priorities[] = { - { NULL, LIBDECOR_PLUGIN_PRIORITY_MEDIUM } -}; - -LIBDECOR_EXPORT const struct libdecor_plugin_description -libdecor_plugin_description = { - .api_version = LIBDECOR_PLUGIN_API_VERSION, - .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE, - .description = "libdecor plugin using Cairo", - .priorities = priorities, - .constructor = libdecor_plugin_new, -}; diff --git a/libdecor/src/plugins/common/libdecor-cairo-blur.c b/libdecor/src/plugins/common/libdecor-cairo-blur.c deleted file mode 100644 index 2cddc7a23..000000000 --- a/libdecor/src/plugins/common/libdecor-cairo-blur.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright © 2008 Kristian Høgsberg - * Copyright © 2012 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * functions 'blur_surface' and 'render_shadow' from weston project: - * https://gitlab.freedesktop.org/wayland/weston/raw/master/shared/cairo-util.c - */ - -#include "libdecor-cairo-blur.h" -#include <stdint.h> -#include <stdlib.h> -#include <math.h> - -/** - * Compile-time computation of number of items in a hardcoded array. - * - * @param a the array being measured. - * @return the number of items hardcoded into the array. - */ -#ifndef ARRAY_LENGTH -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) -#endif - -int -blur_surface(cairo_surface_t *surface, int margin) -{ - int32_t width, height, stride, x, y, z, w; - uint8_t *src, *dst; - uint32_t *s, *d, a, p; - int i, j, k, size, half; - uint32_t kernel[71]; - double f; - - size = ARRAY_LENGTH(kernel); - width = cairo_image_surface_get_width(surface); - height = cairo_image_surface_get_height(surface); - stride = cairo_image_surface_get_stride(surface); - src = cairo_image_surface_get_data(surface); - - dst = malloc(height * stride); - if (dst == NULL) - return -1; - - half = size / 2; - a = 0; - for (i = 0; i < size; i++) { - f = (i - half); - kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000; - a += kernel[i]; - } - - for (i = 0; i < height; i++) { - s = (uint32_t *) (src + i * stride); - d = (uint32_t *) (dst + i * stride); - for (j = 0; j < width; j++) { - if (margin < j && j < width - margin) { - d[j] = s[j]; - continue; - } - - x = 0; - y = 0; - z = 0; - w = 0; - for (k = 0; k < size; k++) { - if (j - half + k < 0 || j - half + k >= width) - continue; - p = s[j - half + k]; - - x += (p >> 24) * kernel[k]; - y += ((p >> 16) & 0xff) * kernel[k]; - z += ((p >> 8) & 0xff) * kernel[k]; - w += (p & 0xff) * kernel[k]; - } - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } - - for (i = 0; i < height; i++) { - s = (uint32_t *) (dst + i * stride); - d = (uint32_t *) (src + i * stride); - for (j = 0; j < width; j++) { - if (margin <= i && i < height - margin) { - d[j] = s[j]; - continue; - } - - x = 0; - y = 0; - z = 0; - w = 0; - for (k = 0; k < size; k++) { - if (i - half + k < 0 || i - half + k >= height) - continue; - s = (uint32_t *) (dst + (i - half + k) * stride); - p = s[j]; - - x += (p >> 24) * kernel[k]; - y += ((p >> 16) & 0xff) * kernel[k]; - z += ((p >> 8) & 0xff) * kernel[k]; - w += (p & 0xff) * kernel[k]; - } - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } - - free(dst); - cairo_surface_mark_dirty(surface); - - return 0; -} - -void -render_shadow(cairo_t *cr, cairo_surface_t *surface, - int x, int y, int width, int height, int margin, int top_margin) -{ - cairo_pattern_t *pattern; - cairo_matrix_t matrix; - int i, fx, fy, shadow_height, shadow_width; - - cairo_set_source_rgba(cr, 0, 0, 0, 0.45); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - pattern = cairo_pattern_create_for_surface (surface); - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); - - for (i = 0; i < 4; i++) { - /* when fy is set, then we are working with lower corners, - * when fx is set, then we are working with right corners - * - * 00 ------- 01 - * | | - * | | - * 10 ------- 11 - */ - fx = i & 1; - fy = i >> 1; - - cairo_matrix_init_translate(&matrix, - -x + fx * (128 - width), - -y + fy * (128 - height)); - cairo_pattern_set_matrix(pattern, &matrix); - - shadow_width = margin; - shadow_height = fy ? margin : top_margin; - - /* if the shadows together are greater than the surface, we need - * to fix it - set the shadow size to the half of - * the size of surface. Also handle the case when the size is - * not divisible by 2. In that case we need one part of the - * shadow to be one pixel greater. !fy or !fx, respectively, - * will do the work. - */ - if (height < 2 * shadow_height) - shadow_height = (height + !fy) / 2; - - if (width < 2 * shadow_width) - shadow_width = (width + !fx) / 2; - - cairo_reset_clip(cr); - cairo_rectangle(cr, - x + fx * (width - shadow_width), - y + fy * (height - shadow_height), - shadow_width, shadow_height); - cairo_clip (cr); - cairo_mask(cr, pattern); - } - - - shadow_width = width - 2 * margin; - shadow_height = top_margin; - if (height < 2 * shadow_height) - shadow_height = height / 2; - - if (shadow_width > 0 && shadow_height) { - /* Top stretch */ - cairo_matrix_init_translate(&matrix, 60, 0); - cairo_matrix_scale(&matrix, 8.0 / width, 1); - cairo_matrix_translate(&matrix, -x - width / 2, -y); - cairo_pattern_set_matrix(pattern, &matrix); - cairo_rectangle(cr, x + margin, y, shadow_width, shadow_height); - - cairo_reset_clip(cr); - cairo_rectangle(cr, - x + margin, y, - shadow_width, shadow_height); - cairo_clip (cr); - cairo_mask(cr, pattern); - - /* Bottom stretch */ - cairo_matrix_translate(&matrix, 0, -height + 128); - cairo_pattern_set_matrix(pattern, &matrix); - - cairo_reset_clip(cr); - cairo_rectangle(cr, x + margin, y + height - margin, - shadow_width, margin); - cairo_clip (cr); - cairo_mask(cr, pattern); - } - - shadow_width = margin; - if (width < 2 * shadow_width) - shadow_width = width / 2; - - shadow_height = height - margin - top_margin; - - /* if height is smaller than sum of margins, - * then the shadow is already done by the corners */ - if (shadow_height > 0 && shadow_width) { - /* Left stretch */ - cairo_matrix_init_translate(&matrix, 0, 60); - cairo_matrix_scale(&matrix, 1, 8.0 / height); - cairo_matrix_translate(&matrix, -x, -y - height / 2); - cairo_pattern_set_matrix(pattern, &matrix); - cairo_reset_clip(cr); - cairo_rectangle(cr, x, y + top_margin, - shadow_width, shadow_height); - cairo_clip (cr); - cairo_mask(cr, pattern); - - /* Right stretch */ - cairo_matrix_translate(&matrix, -width + 128, 0); - cairo_pattern_set_matrix(pattern, &matrix); - cairo_rectangle(cr, x + width - shadow_width, y + top_margin, - shadow_width, shadow_height); - cairo_reset_clip(cr); - cairo_clip (cr); - cairo_mask(cr, pattern); - } - - cairo_pattern_destroy(pattern); - cairo_reset_clip(cr); -} diff --git a/libdecor/src/plugins/common/libdecor-cairo-blur.h b/libdecor/src/plugins/common/libdecor-cairo-blur.h deleted file mode 100644 index d48e9dd3d..000000000 --- a/libdecor/src/plugins/common/libdecor-cairo-blur.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include <cairo/cairo.h> - -int -blur_surface(cairo_surface_t *surface, int margin); - -void -render_shadow(cairo_t *cr, cairo_surface_t *surface, - int x, int y, int width, int height, int margin, int top_margin); diff --git a/libdecor/src/plugins/dummy/libdecor-dummy.c b/libdecor/src/plugins/dummy/libdecor-dummy.c deleted file mode 100644 index 621dd027f..000000000 --- a/libdecor/src/plugins/dummy/libdecor-dummy.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright © 2021 Jonas Ådahl - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include "libdecor-plugin.h" - -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdlib.h> -#include <wayland-cursor.h> - -#include "utils.h" - -struct libdecor_plugin_dummy { - struct libdecor_plugin plugin; - struct libdecor *context; -}; - -static void -libdecor_plugin_dummy_destroy(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_dummy *plugin_dummy = - (struct libdecor_plugin_dummy *) plugin; - - libdecor_plugin_release(plugin); - free(plugin_dummy); -} - -static struct libdecor_frame * -libdecor_plugin_dummy_frame_new(struct libdecor_plugin *plugin) -{ - struct libdecor_frame *frame; - - frame = zalloc(sizeof *frame); - - return frame; -} - -static void -libdecor_plugin_dummy_set_handle_application_cursor(struct libdecor_plugin *plugin, - bool handle_cursor) -{ -} - -static void -libdecor_plugin_dummy_frame_free(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ -} - -static void -libdecor_plugin_dummy_frame_commit(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration) -{ -} - -static void -libdecor_plugin_dummy_frame_property_changed(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ -} - -static void -libdecor_plugin_dummy_frame_popup_grab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ -} - -static void -libdecor_plugin_dummy_frame_popup_ungrab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ -} - -static struct libdecor_plugin_interface dummy_plugin_iface = { - .destroy = libdecor_plugin_dummy_destroy, - - .set_handle_application_cursor = libdecor_plugin_dummy_set_handle_application_cursor, - - .frame_new = libdecor_plugin_dummy_frame_new, - .frame_free = libdecor_plugin_dummy_frame_free, - .frame_commit = libdecor_plugin_dummy_frame_commit, - .frame_property_changed = libdecor_plugin_dummy_frame_property_changed, - .frame_popup_grab = libdecor_plugin_dummy_frame_popup_grab, - .frame_popup_ungrab = libdecor_plugin_dummy_frame_popup_ungrab, -}; - -static struct libdecor_plugin * -libdecor_plugin_new(struct libdecor *context) -{ - struct libdecor_plugin_dummy *plugin_dummy; - - plugin_dummy = zalloc(sizeof *plugin_dummy); - libdecor_plugin_init(&plugin_dummy->plugin, context, &dummy_plugin_iface); - plugin_dummy->context = context; - - libdecor_notify_plugin_ready(context); - - return &plugin_dummy->plugin; -} - -static struct libdecor_plugin_priority priorities[] = { - { NULL, LIBDECOR_PLUGIN_PRIORITY_LOW } -}; - -LIBDECOR_EXPORT const struct libdecor_plugin_description -libdecor_plugin_description = { - .api_version = LIBDECOR_PLUGIN_API_VERSION, - .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE, - .description = "dummy libdecor plugin", - .priorities = priorities, - .constructor = libdecor_plugin_new, -}; diff --git a/libdecor/src/plugins/gtk/libdecor-gtk.c b/libdecor/src/plugins/gtk/libdecor-gtk.c deleted file mode 100644 index bc5b0fa61..000000000 --- a/libdecor/src/plugins/gtk/libdecor-gtk.c +++ /dev/null @@ -1,3028 +0,0 @@ -/* - * Copyright © 2018 Jonas Ådahl - * Copyright © 2021 Christian Rauch - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include <linux/input.h> -#include <fcntl.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> -#include <wayland-client-core.h> -#include <wayland-cursor.h> - -#include "libdecor-plugin.h" -#include "utils.h" -#include "desktop-settings.h" -#include "os-compatibility.h" - -#include <cairo/cairo.h> - -#include "common/libdecor-cairo-blur.h" -#include <poll.h> - -#include <gtk/gtk.h> - -static const size_t SHADOW_MARGIN = 24; /* grabbable part of the border */ - -static const char *cursor_names[] = { - "top_side", - "bottom_side", - "left_side", - "top_left_corner", - "bottom_left_corner", - "right_side", - "top_right_corner", - "bottom_right_corner" -}; - -enum header_element { - HEADER_NONE, - HEADER_FULL, /* entire header bar */ - HEADER_TITLE, /* label */ - HEADER_MIN, - HEADER_MAX, - HEADER_CLOSE, -}; - -enum titlebar_gesture_state { - TITLEBAR_GESTURE_STATE_INIT, - TITLEBAR_GESTURE_STATE_BUTTON_PRESSED, - TITLEBAR_GESTURE_STATE_CONSUMED, - TITLEBAR_GESTURE_STATE_DISCARDED, -}; - -struct header_element_data { - const char *name; - enum header_element type; - /* pointer to button or NULL if not found*/ - GtkWidget *widget; - GtkStateFlags state; -}; - -static void -find_widget_by_name(GtkWidget *widget, void *data) -{ - if (GTK_IS_WIDGET(widget)) { - char *style_ctx = gtk_style_context_to_string( - gtk_widget_get_style_context(widget), - GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE); - if (strstr(style_ctx, ((struct header_element_data *)data)->name)) { - ((struct header_element_data *)data)->widget = widget; - free(style_ctx); - return; - } - free(style_ctx); - } - - if (GTK_IS_CONTAINER(widget)) { - /* recursively traverse container */ - gtk_container_forall(GTK_CONTAINER(widget), &find_widget_by_name, data); - } -} - -static struct header_element_data -find_widget_by_type(GtkWidget *widget, enum header_element type) -{ - char* name = NULL; - switch (type) { - case HEADER_FULL: - name = "headerbar.titlebar:"; - break; - case HEADER_TITLE: - name = "label.title:"; - break; - case HEADER_MIN: - name = ".minimize"; - break; - case HEADER_MAX: - name = ".maximize"; - break; - case HEADER_CLOSE: - name = ".close"; - break; - default: - break; - } - - struct header_element_data data = {.name = name, .type = type, .widget = NULL}; - find_widget_by_name(widget, &data); - return data; -} - -static bool -in_region(const cairo_rectangle_int_t *rect, const int *x, const int *y) -{ - return (*x>=rect->x) & (*y>=rect->y) & - (*x<(rect->x+rect->width)) & (*y<(rect->y+rect->height)); -} - -static struct header_element_data -get_header_focus(const GtkHeaderBar *header_bar, const int x, const int y) -{ - /* we have to check child widgets (buttons, title) before the 'HDR_HDR' root widget */ - static const enum header_element elems[] = - {HEADER_TITLE, HEADER_MIN, HEADER_MAX, HEADER_CLOSE}; - - for (size_t i = 0; i < ARRAY_SIZE(elems); i++) { - struct header_element_data elem = - find_widget_by_type(GTK_WIDGET(header_bar), elems[i]); - if (elem.widget) { - GtkAllocation allocation; - gtk_widget_get_allocation(GTK_WIDGET(elem.widget), &allocation); - if (in_region(&allocation, &x, &y)) - return elem; - } - } - - struct header_element_data elem_none = { .widget=NULL}; - return elem_none; -} - -static bool -streq(const char *str1, - const char *str2) -{ - if (!str1 && !str2) - return true; - - if (str1 && str2) - return strcmp(str1, str2) == 0; - - return false; -} - -enum decoration_type { - DECORATION_TYPE_NONE, - DECORATION_TYPE_ALL, - DECORATION_TYPE_TITLE_ONLY -}; - -enum component { - NONE = 0, - SHADOW, - HEADER, -}; - -struct seat { - struct libdecor_plugin_gtk *plugin_gtk; - - char *name; - - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - struct wl_touch *wl_touch; - - struct wl_surface *cursor_surface; - struct wl_cursor *current_cursor; - int cursor_scale; - struct wl_list cursor_outputs; - - struct wl_cursor_theme *cursor_theme; - /* cursors for resize edges and corners */ - struct wl_cursor *cursors[ARRAY_LENGTH(cursor_names)]; - struct wl_cursor *cursor_left_ptr; - - struct wl_surface *pointer_focus; - struct wl_surface *touch_focus; - - int pointer_x, pointer_y; - - uint32_t touch_down_time_stamp; - - uint32_t serial; - - bool grabbed; - - struct wl_list link; -}; - -struct output { - struct libdecor_plugin_gtk *plugin_gtk; - - struct wl_output *wl_output; - uint32_t id; - int scale; - - struct wl_list link; -}; - -struct buffer { - struct wl_buffer *wl_buffer; - bool in_use; - bool is_detached; - - void *data; - size_t data_size; - int width; - int height; - int scale; - int buffer_width; - int buffer_height; -}; - -struct border_component { - enum component type; - struct wl_surface *wl_surface; - struct wl_subsurface *wl_subsurface; - struct buffer *buffer; - bool opaque; - struct wl_list output_list; - int scale; - - struct wl_list child_components; /* border_component::link */ - struct wl_list link; /* border_component::child_components */ -}; - -struct surface_output { - struct output *output; - struct wl_list link; -}; - -struct cursor_output { - struct output *output; - struct wl_list link; -}; - -struct libdecor_frame_gtk { - struct libdecor_frame frame; - - struct libdecor_plugin_gtk *plugin_gtk; - - int content_width; - int content_height; - - enum libdecor_window_state window_state; - - enum decoration_type decoration_type; - - char *title; - - enum libdecor_capabilities capabilities; - - struct border_component *active; - struct border_component *touch_active; - - struct border_component *focus; - struct border_component *grab; - - bool shadow_showing; - struct border_component shadow; - - GtkWidget *window; /* offscreen window for rendering */ - GtkWidget *header; /* header bar with widgets */ - struct border_component headerbar; - struct header_element_data hdr_focus; - - /* store pre-processed shadow tile */ - cairo_surface_t *shadow_blur; - - struct wl_list link; - - struct { - enum titlebar_gesture_state state; - int button_pressed_count; - uint32_t first_pressed_button; - uint32_t first_pressed_time; - double pressed_x; - double pressed_y; - uint32_t pressed_serial; - } titlebar_gesture; -}; - -struct libdecor_plugin_gtk { - struct libdecor_plugin plugin; - - struct wl_callback *globals_callback; - struct wl_callback *globals_callback_shm; - - struct libdecor *context; - - struct wl_registry *wl_registry; - struct wl_subcompositor *wl_subcompositor; - struct wl_compositor *wl_compositor; - - struct wl_shm *wl_shm; - struct wl_callback *shm_callback; - bool has_argb; - - struct wl_list visible_frame_list; - struct wl_list seat_list; - struct wl_list output_list; - - char *cursor_theme_name; - int cursor_size; - - uint32_t color_scheme_setting; - - int double_click_time_ms; - int drag_threshold; - - bool handle_cursor; -}; - -static const char *libdecor_gtk_proxy_tag = "libdecor-gtk"; - -static bool -own_proxy(struct wl_proxy *proxy) -{ - if (!proxy) - return false; - - return (wl_proxy_get_tag(proxy) == &libdecor_gtk_proxy_tag); -} - -static bool -own_surface(struct wl_surface *surface) -{ - return own_proxy((struct wl_proxy *) surface); -} - -static bool -own_output(struct wl_output *output) -{ - return own_proxy((struct wl_proxy *) output); -} - -static bool -moveable(struct libdecor_frame_gtk *frame_gtk) { - return libdecor_frame_has_capability(&frame_gtk->frame, - LIBDECOR_ACTION_MOVE); -} - -static bool -resizable(struct libdecor_frame_gtk *frame_gtk) { - return libdecor_frame_has_capability(&frame_gtk->frame, - LIBDECOR_ACTION_RESIZE); -} - -static bool -minimizable(struct libdecor_frame_gtk *frame_gtk) { - return libdecor_frame_has_capability(&frame_gtk->frame, - LIBDECOR_ACTION_MINIMIZE); -} - -static bool -closeable(struct libdecor_frame_gtk *frame_gtk) { - return libdecor_frame_has_capability(&frame_gtk->frame, - LIBDECOR_ACTION_CLOSE); -} - -static void -buffer_free(struct buffer *buffer); - -static void -draw_border_component(struct libdecor_frame_gtk *frame_gtk, - struct border_component *border_component, - enum component component); - -static void -send_cursor(struct seat *seat); - -static bool -update_local_cursor(struct seat *seat); - -static void -libdecor_plugin_gtk_destroy(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_gtk *plugin_gtk = - (struct libdecor_plugin_gtk *) plugin; - struct seat *seat, *seat_tmp; - struct output *output, *output_tmp; - struct libdecor_frame_gtk *frame, *frame_tmp; - - if (plugin_gtk->globals_callback) - wl_callback_destroy(plugin_gtk->globals_callback); - if (plugin_gtk->globals_callback_shm) - wl_callback_destroy(plugin_gtk->globals_callback_shm); - if (plugin_gtk->shm_callback) - wl_callback_destroy(plugin_gtk->shm_callback); - wl_registry_destroy(plugin_gtk->wl_registry); - - wl_list_for_each_safe(seat, seat_tmp, &plugin_gtk->seat_list, link) { - struct cursor_output *cursor_output, *tmp; - - if (seat->wl_pointer) - wl_pointer_destroy(seat->wl_pointer); - if (seat->wl_touch) - wl_touch_destroy(seat->wl_touch); - if (seat->cursor_surface) - wl_surface_destroy(seat->cursor_surface); - wl_seat_destroy(seat->wl_seat); - if (seat->cursor_theme) - wl_cursor_theme_destroy(seat->cursor_theme); - - wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - - free(seat->name); - free(seat); - } - - wl_list_for_each_safe(output, output_tmp, - &plugin_gtk->output_list, link) { - if (wl_output_get_version (output->wl_output) >= - WL_OUTPUT_RELEASE_SINCE_VERSION) - wl_output_release(output->wl_output); - else - wl_output_destroy(output->wl_output); - free(output); - } - - wl_list_for_each_safe(frame, frame_tmp, - &plugin_gtk->visible_frame_list, link) { - wl_list_remove(&frame->link); - } - - free(plugin_gtk->cursor_theme_name); - - if (plugin_gtk->wl_shm) - wl_shm_destroy(plugin_gtk->wl_shm); - - if (plugin_gtk->wl_compositor) - wl_compositor_destroy(plugin_gtk->wl_compositor); - if (plugin_gtk->wl_subcompositor) - wl_subcompositor_destroy(plugin_gtk->wl_subcompositor); - - libdecor_plugin_release(&plugin_gtk->plugin); - free(plugin_gtk); -} - -static struct libdecor_frame_gtk * -libdecor_frame_gtk_new(struct libdecor_plugin_gtk *plugin_gtk) -{ - struct libdecor_frame_gtk *frame_gtk = zalloc(sizeof *frame_gtk); - cairo_t *cr; - - static const int size = 128; - static const int boundary = 32; - - frame_gtk->plugin_gtk = plugin_gtk; - frame_gtk->shadow_blur = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, size, size); - wl_list_insert(&plugin_gtk->visible_frame_list, &frame_gtk->link); - - cr = cairo_create(frame_gtk->shadow_blur); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr, 0, 0, 0, 1); - cairo_rectangle(cr, boundary, boundary, - size - 2 * boundary, - size - 2 * boundary); - cairo_fill(cr); - cairo_destroy(cr); - blur_surface(frame_gtk->shadow_blur, 64); - - return frame_gtk; -} - -static int -libdecor_plugin_gtk_get_fd(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_gtk *plugin_gtk = - (struct libdecor_plugin_gtk *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_gtk->context); - - return wl_display_get_fd(wl_display); -} - -static int -libdecor_plugin_gtk_dispatch(struct libdecor_plugin *plugin, - int timeout) -{ - struct libdecor_plugin_gtk *plugin_gtk = - (struct libdecor_plugin_gtk *) plugin; - struct wl_display *wl_display = - libdecor_get_wl_display(plugin_gtk->context); - struct pollfd fds[1]; - int ret; - int dispatch_count = 0; - - while (g_main_context_iteration(NULL, FALSE)); - - while (wl_display_prepare_read(wl_display) != 0) - dispatch_count += wl_display_dispatch_pending(wl_display); - - if (wl_display_flush(wl_display) < 0 && - errno != EAGAIN) { - wl_display_cancel_read(wl_display); - return -errno; - } - - fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN }; - - ret = poll(fds, ARRAY_SIZE (fds), timeout); - if (ret > 0) { - if (fds[0].revents & POLLIN) { - wl_display_read_events(wl_display); - dispatch_count += wl_display_dispatch_pending(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return dispatch_count; - } - } else if (ret == 0) { - wl_display_cancel_read(wl_display); - return dispatch_count; - } else { - wl_display_cancel_read(wl_display); - return -errno; - } -} - -static void -libdecor_plugin_gtk_set_handle_application_cursor(struct libdecor_plugin *plugin, - bool handle_cursor) -{ - struct libdecor_plugin_gtk *plugin_gtk = - (struct libdecor_plugin_gtk *) plugin; - - plugin_gtk->handle_cursor = handle_cursor; -} - -static struct libdecor_frame * -libdecor_plugin_gtk_frame_new(struct libdecor_plugin *plugin) -{ - struct libdecor_plugin_gtk *plugin_gtk = - (struct libdecor_plugin_gtk *) plugin; - struct libdecor_frame_gtk *frame_gtk; - - frame_gtk = libdecor_frame_gtk_new(plugin_gtk); - - return &frame_gtk->frame; -} - -static void -toggle_maximized(struct libdecor_frame *const frame) -{ - if (!resizable((struct libdecor_frame_gtk *)frame)) - return; - - if (!(libdecor_frame_get_window_state(frame) & - LIBDECOR_WINDOW_STATE_MAXIMIZED)) - libdecor_frame_set_maximized(frame); - else - libdecor_frame_unset_maximized(frame); -} - -static void -buffer_release(void *user_data, - struct wl_buffer *wl_buffer) -{ - struct buffer *buffer = user_data; - - if (buffer->is_detached) - buffer_free(buffer); - else - buffer->in_use = false; -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release -}; - -static struct buffer * -create_shm_buffer(struct libdecor_plugin_gtk *plugin_gtk, - int width, - int height, - bool opaque, - int scale) -{ - struct wl_shm_pool *pool; - int fd, size, buffer_width, buffer_height, stride; - void *data; - struct buffer *buffer; - enum wl_shm_format buf_fmt; - - buffer_width = width * scale; - buffer_height = height * scale; - stride = buffer_width * 4; - size = stride * buffer_height; - - fd = libdecor_os_create_anonymous_file(size); - if (fd < 0) { - fprintf(stderr, "creating a buffer file for %d B failed: %s\n", - size, strerror(errno)); - return NULL; - } - - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %s\n", strerror(errno)); - close(fd); - return NULL; - } - - buf_fmt = opaque ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888; - - pool = wl_shm_create_pool(plugin_gtk->wl_shm, fd, size); - buffer = zalloc(sizeof *buffer); - buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0, - buffer_width, buffer_height, - stride, - buf_fmt); - wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); - wl_shm_pool_destroy(pool); - close(fd); - - buffer->data = data; - buffer->data_size = size; - buffer->width = width; - buffer->height = height; - buffer->scale = scale; - buffer->buffer_width = buffer_width; - buffer->buffer_height = buffer_height; - - return buffer; -} - -static void -buffer_free(struct buffer *buffer) -{ - if (buffer->wl_buffer) { - wl_buffer_destroy(buffer->wl_buffer); - munmap(buffer->data, buffer->data_size); - buffer->wl_buffer = NULL; - buffer->in_use = false; - } - free(buffer); -} - -static void -free_border_component(struct border_component *border_component) -{ - if (border_component->wl_surface) { - wl_subsurface_destroy(border_component->wl_subsurface); - border_component->wl_subsurface = NULL; - wl_surface_destroy(border_component->wl_surface); - border_component->wl_surface = NULL; - } - if (border_component->buffer) { - buffer_free(border_component->buffer); - border_component->buffer = NULL; - } - if (border_component->output_list.next != NULL) { - struct surface_output *surface_output, *surface_output_tmp; - wl_list_for_each_safe(surface_output, surface_output_tmp, - &border_component->output_list, link) { - wl_list_remove(&surface_output->link); - free(surface_output); - } - } -} - -static void -libdecor_plugin_gtk_frame_free(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - - g_clear_pointer (&frame_gtk->header, gtk_widget_destroy); - g_clear_pointer (&frame_gtk->window, gtk_widget_destroy); - - free_border_component(&frame_gtk->headerbar); - free_border_component(&frame_gtk->shadow); - frame_gtk->shadow_showing = false; - - g_clear_pointer (&frame_gtk->shadow_blur, cairo_surface_destroy); - - g_clear_pointer (&frame_gtk->title, free); - - frame_gtk->decoration_type = DECORATION_TYPE_NONE; - - if (frame_gtk->link.next != NULL) - wl_list_remove(&frame_gtk->link); -} - -static bool -is_border_surfaces_showing(struct libdecor_frame_gtk *frame_gtk) -{ - return frame_gtk->shadow_showing; -} - -static void -hide_border_component(struct border_component *border_component) -{ - if (!border_component->wl_surface) - return; - - wl_surface_attach(border_component->wl_surface, NULL, 0, 0); - wl_surface_commit(border_component->wl_surface); -} - -static void -hide_border_surfaces(struct libdecor_frame_gtk *frame_gtk) -{ - hide_border_component(&frame_gtk->shadow); - frame_gtk->shadow_showing = false; -} - -static struct border_component * -get_component_for_surface(struct libdecor_frame_gtk *frame_gtk, - const struct wl_surface *surface) -{ - if (frame_gtk->shadow.wl_surface == surface) - return &frame_gtk->shadow; - if (frame_gtk->headerbar.wl_surface == surface) - return &frame_gtk->headerbar; - return NULL; -} - -static bool -redraw_scale(struct libdecor_frame_gtk *frame_gtk, - struct border_component *cmpnt) -{ - struct surface_output *surface_output; - int scale = 1; - - if (cmpnt->wl_surface == NULL) - return false; - - wl_list_for_each(surface_output, &cmpnt->output_list, link) { - scale = MAX(scale, surface_output->output->scale); - } - if (scale != cmpnt->scale) { - cmpnt->scale = scale; - if ((frame_gtk->decoration_type != DECORATION_TYPE_NONE) && - ((cmpnt->type != SHADOW) || is_border_surfaces_showing(frame_gtk))) { - draw_border_component(frame_gtk, cmpnt, cmpnt->type); - return true; - } - } - return false; -} - -static bool -add_surface_output(struct libdecor_plugin_gtk *plugin_gtk, - struct wl_output *wl_output, - struct wl_list *list) -{ - struct output *output; - struct surface_output *surface_output; - - if (!own_output(wl_output)) - return false; - - output = wl_output_get_user_data(wl_output); - - if (output == NULL) - return false; - - surface_output = zalloc(sizeof *surface_output); - surface_output->output = output; - wl_list_insert(list, &surface_output->link); - return true; -} - -static void -surface_enter(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct libdecor_frame_gtk *frame_gtk = data; - struct border_component *cmpnt; - - if (!(own_surface(wl_surface) && own_output(wl_output))) - return; - - cmpnt = get_component_for_surface(frame_gtk, wl_surface); - if (cmpnt == NULL) - return; - - if (!add_surface_output(frame_gtk->plugin_gtk, wl_output, - &cmpnt->output_list)) - return; - - if (redraw_scale(frame_gtk, cmpnt)) - libdecor_frame_toplevel_commit(&frame_gtk->frame); -} - -static bool -remove_surface_output(struct wl_list *list, const struct wl_output *wl_output) -{ - struct surface_output *surface_output; - wl_list_for_each(surface_output, list, link) { - if (surface_output->output->wl_output == wl_output) { - wl_list_remove(&surface_output->link); - free(surface_output); - return true; - } - } - return false; -} - -static void -surface_leave(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct libdecor_frame_gtk *frame_gtk = data; - struct border_component *cmpnt; - - if (!(own_surface(wl_surface) && own_output(wl_output))) - return; - - cmpnt = get_component_for_surface(frame_gtk, wl_surface); - if (cmpnt == NULL) - return; - - if (!remove_surface_output(&cmpnt->output_list, wl_output)) - return; - - if (redraw_scale(frame_gtk, cmpnt)) - libdecor_frame_toplevel_commit(&frame_gtk->frame); -} - -static struct wl_surface_listener surface_listener = { - surface_enter, - surface_leave, -}; - -static void -create_surface_subsurface_pair(struct libdecor_frame_gtk *frame_gtk, - struct wl_surface **out_wl_surface, - struct wl_subsurface **out_wl_subsurface) -{ - struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk; - struct libdecor_frame *frame = &frame_gtk->frame; - struct wl_compositor *wl_compositor = plugin_gtk->wl_compositor; - struct wl_subcompositor *wl_subcompositor = plugin_gtk->wl_subcompositor; - struct wl_surface *wl_surface; - struct wl_surface *parent; - struct wl_subsurface *wl_subsurface; - - wl_surface = wl_compositor_create_surface(wl_compositor); - wl_proxy_set_tag((struct wl_proxy *) wl_surface, - &libdecor_gtk_proxy_tag); - - parent = libdecor_frame_get_wl_surface(frame); - wl_subsurface = wl_subcompositor_get_subsurface(wl_subcompositor, - wl_surface, - parent); - - *out_wl_surface = wl_surface; - *out_wl_subsurface = wl_subsurface; -} - -static void -ensure_component(struct libdecor_frame_gtk *frame_gtk, - struct border_component *cmpnt) -{ - if (!cmpnt->wl_surface) { - wl_list_init(&cmpnt->output_list); - cmpnt->scale = 1; - create_surface_subsurface_pair(frame_gtk, - &cmpnt->wl_surface, - &cmpnt->wl_subsurface); - wl_surface_add_listener(cmpnt->wl_surface, &surface_listener, - frame_gtk); - } -} - -static void -ensure_border_surfaces(struct libdecor_frame_gtk *frame_gtk) -{ - frame_gtk->shadow.type = SHADOW; - frame_gtk->shadow.opaque = false; - ensure_component(frame_gtk, &frame_gtk->shadow); -} - -static void -ensure_title_bar_surfaces(struct libdecor_frame_gtk *frame_gtk) -{ - GtkStyleContext *context_hdr; - - frame_gtk->headerbar.type = HEADER; - frame_gtk->headerbar.opaque = false; - ensure_component(frame_gtk, &frame_gtk->headerbar); - - if (frame_gtk->shadow.wl_surface) { - wl_subsurface_place_above(frame_gtk->headerbar.wl_subsurface, - frame_gtk->shadow.wl_surface); - } - - /* create an offscreen window with a header bar */ - /* TODO: This should only be done once at frame consutrction, but then - * the window and headerbar would not change style (e.g. backdrop) - * after construction. So we just destroy and re-create them. - */ - /* avoid warning when restoring previously turned off decoration */ - if (GTK_IS_WIDGET(frame_gtk->header)) { - gtk_widget_destroy(frame_gtk->header); - frame_gtk->header = NULL; - } - /* avoid warning when restoring previously turned off decoration */ - if (GTK_IS_WIDGET(frame_gtk->window)) { - gtk_widget_destroy(frame_gtk->window); - frame_gtk->window = NULL; - } - frame_gtk->window = gtk_offscreen_window_new(); - frame_gtk->header = gtk_header_bar_new(); - - g_object_get(gtk_widget_get_settings(frame_gtk->window), - "gtk-double-click-time", - &frame_gtk->plugin_gtk->double_click_time_ms, - "gtk-dnd-drag-threshold", - &frame_gtk->plugin_gtk->drag_threshold, - NULL); - /* set as "default" decoration */ - g_object_set(frame_gtk->header, - "title", libdecor_frame_get_title(&frame_gtk->frame), - "has-subtitle", FALSE, - "show-close-button", TRUE, - NULL); - - context_hdr = gtk_widget_get_style_context(frame_gtk->header); - gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR); - gtk_style_context_add_class(context_hdr, "default-decoration"); - - gtk_window_set_titlebar(GTK_WINDOW(frame_gtk->window), frame_gtk->header); - gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(frame_gtk->header), TRUE); - - gtk_window_set_resizable(GTK_WINDOW(frame_gtk->window), resizable(frame_gtk)); -} - -static void -calculate_component_size(struct libdecor_frame_gtk *frame_gtk, - enum component component, - int *component_x, - int *component_y, - int *component_width, - int *component_height) -{ - struct libdecor_frame *frame = &frame_gtk->frame; - int content_width, content_height; - - content_width = libdecor_frame_get_content_width(frame); - content_height = libdecor_frame_get_content_height(frame); - - /* avoid warning when restoring previously turned off decoration */ - const int title_height = - GTK_IS_WIDGET(frame_gtk->header) - ? gtk_widget_get_allocated_height(frame_gtk->header) : 0; - - switch (component) { - case NONE: - *component_width = 0; - *component_height = 0; - return; - case SHADOW: - *component_x = -(int)SHADOW_MARGIN; - *component_y = -(int)(SHADOW_MARGIN+title_height); - *component_width = content_width + 2 * SHADOW_MARGIN; - *component_height = content_height - + 2 * SHADOW_MARGIN - + title_height; - return; - case HEADER: - *component_x = 0; - /* reuse product of function call above */ - *component_y = - title_height; - *component_width = gtk_widget_get_allocated_width(frame_gtk->header); - /* reuse product of function call above */ - *component_height = title_height; - return; - } - - abort(); -} - -static void -array_append(enum header_element **array, size_t *n, enum header_element item) -{ - (*n)++; - *array = realloc(*array, (*n) * sizeof (enum header_element)); - (*array)[(*n)-1] = item; -} - -static void -draw_header_background(struct libdecor_frame_gtk *frame_gtk, - cairo_t *cr) -{ - /* background */ - GtkAllocation allocation; - GtkStyleContext* style; - - gtk_widget_get_allocation(GTK_WIDGET(frame_gtk->header), &allocation); - style = gtk_widget_get_style_context(frame_gtk->header); - gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height); -} - -static void -draw_header_title(struct libdecor_frame_gtk *frame_gtk, - cairo_surface_t *surface) -{ - /* title */ - GtkWidget *label; - GtkAllocation allocation; - cairo_surface_t *label_surface = NULL; - cairo_t *cr; - - label = find_widget_by_type(frame_gtk->header, HEADER_TITLE).widget; - gtk_widget_get_allocation(label, &allocation); - - /* create subsection in which to draw label */ - label_surface = cairo_surface_create_for_rectangle( - surface, - allocation.x, allocation.y, - allocation.width, allocation.height); - cr = cairo_create(label_surface); - gtk_widget_size_allocate(label, &allocation); - gtk_widget_draw(label, cr); - cairo_destroy(cr); - cairo_surface_destroy(label_surface); -} - -static void -draw_header_button(struct libdecor_frame_gtk *frame_gtk, - cairo_t *cr, - cairo_surface_t *surface, - enum header_element button_type, - enum libdecor_window_state window_state) -{ - struct header_element_data elem; - GtkWidget *button; - GtkStyleContext* button_style; - GtkStateFlags style_state; - - GtkAllocation allocation; - - gchar *icon_name; - int scale; - GtkWidget *icon_widget; - GtkAllocation allocation_icon; - GtkIconInfo* icon_info; - - double sx, sy; - - gint icon_width, icon_height; - - GdkPixbuf* icon_pixbuf; - cairo_surface_t* icon_surface; - - gint width = 0, height = 0; - - gint left = 0, top = 0, right = 0, bottom = 0; - GtkBorder border; - - GtkBorder padding; - - elem = find_widget_by_type(frame_gtk->header, button_type); - button = elem.widget; - if (!button) - return; - button_style = gtk_widget_get_style_context(button); - style_state = elem.state; - - /* change style based on window state and focus */ - if (!(window_state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - style_state |= GTK_STATE_FLAG_BACKDROP; - } - if (frame_gtk->hdr_focus.widget == button) { - style_state |= GTK_STATE_FLAG_PRELIGHT; - if (frame_gtk->hdr_focus.state & GTK_STATE_FLAG_ACTIVE) { - style_state |= GTK_STATE_FLAG_ACTIVE; - } - } - - /* background */ - gtk_widget_get_clip(button, &allocation); - - gtk_style_context_save(button_style); - gtk_style_context_set_state(button_style, style_state); - gtk_render_background(button_style, cr, - allocation.x, allocation.y, - allocation.width, allocation.height); - gtk_render_frame(button_style, cr, - allocation.x, allocation.y, - allocation.width, allocation.height); - gtk_style_context_restore(button_style); - - /* symbol */ - switch (button_type) { - case HEADER_MIN: - icon_name = "window-minimize-symbolic"; - break; - case HEADER_MAX: - icon_name = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) ? - "window-restore-symbolic" : - "window-maximize-symbolic"; - break; - case HEADER_CLOSE: - icon_name = "window-close-symbolic"; - break; - default: - icon_name = NULL; - break; - } - - /* get scale */ - cairo_surface_get_device_scale(surface, &sx, &sy); - scale = (sx+sy) / 2.0; - - /* get original icon dimensions */ - icon_widget = gtk_bin_get_child(GTK_BIN(button)); - gtk_widget_get_allocation(icon_widget, &allocation_icon); - - /* icon info */ - if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &icon_width, &icon_height)) { - icon_width = 16; - icon_height = 16; - } - icon_info = gtk_icon_theme_lookup_icon_for_scale( - gtk_icon_theme_get_default(), icon_name, - icon_width, scale, (GtkIconLookupFlags)0); - - /* icon pixel buffer*/ - gtk_style_context_save(button_style); - gtk_style_context_set_state(button_style, style_state); - icon_pixbuf = gtk_icon_info_load_symbolic_for_context( - icon_info, button_style, NULL, NULL); - icon_surface = gdk_cairo_surface_create_from_pixbuf(icon_pixbuf, scale, NULL); - gtk_style_context_restore(button_style); - - /* dimensions and position */ - gtk_style_context_get(button_style, gtk_style_context_get_state(button_style), - "min-width", &width, "min-height", &height, NULL); - - if (width < icon_width) - width = icon_width; - if (height < icon_height) - height = icon_height; - - gtk_style_context_get_border(button_style, gtk_style_context_get_state(button_style), &border); - left += border.left; - right += border.right; - top += border.top; - bottom += border.bottom; - - gtk_style_context_get_padding(button_style, gtk_style_context_get_state(button_style), &padding); - left += padding.left; - right += padding.right; - top += padding.top; - bottom += padding.bottom; - - width += left + right; - height += top + bottom; - - gtk_render_icon_surface(gtk_widget_get_style_context(icon_widget), - cr, icon_surface, - allocation.x + ((width - icon_width) / 2), - allocation.y + ((height - icon_height) / 2)); - cairo_paint(cr); - cairo_surface_destroy(icon_surface); - g_object_unref(icon_pixbuf); -} - -static void -draw_header_buttons(struct libdecor_frame_gtk *frame_gtk, - cairo_t *cr, - cairo_surface_t *surface) -{ - /* buttons */ - enum libdecor_window_state window_state; - enum header_element *buttons = NULL; - size_t nbuttons = 0; - - window_state = libdecor_frame_get_window_state( - (struct libdecor_frame*)frame_gtk); - - /* set buttons by capability */ - if (minimizable(frame_gtk)) - array_append(&buttons, &nbuttons, HEADER_MIN); - if (resizable(frame_gtk)) - array_append(&buttons, &nbuttons, HEADER_MAX); - if (closeable(frame_gtk)) - array_append(&buttons, &nbuttons, HEADER_CLOSE); - - for (size_t i = 0; i < nbuttons; i++) { - draw_header_button(frame_gtk, cr, surface, buttons[i], window_state); - } /* loop buttons */ - free(buttons); -} - -static void -draw_header(struct libdecor_frame_gtk *frame_gtk, - cairo_t *cr, - cairo_surface_t *surface) -{ - draw_header_background(frame_gtk, cr); - draw_header_title(frame_gtk, surface); - draw_header_buttons(frame_gtk, cr, surface); -} - -static void -draw_component_content(struct libdecor_frame_gtk *frame_gtk, - struct buffer *buffer, - int component_width, - int component_height, - enum component component) -{ - cairo_surface_t *surface; - cairo_t *cr; - - /* clear buffer */ - memset(buffer->data, 0, buffer->data_size); - - surface = cairo_image_surface_create_for_data( - buffer->data, CAIRO_FORMAT_ARGB32, - buffer->buffer_width, buffer->buffer_height, - cairo_format_stride_for_width( - CAIRO_FORMAT_ARGB32, - buffer->buffer_width) - ); - - cr = cairo_create(surface); - - cairo_surface_set_device_scale(surface, buffer->scale, buffer->scale); - - /* background */ - switch (component) { - case NONE: - break; - case SHADOW: - render_shadow(cr, - frame_gtk->shadow_blur, - -(int)SHADOW_MARGIN/2, - -(int)SHADOW_MARGIN/2, - buffer->width + SHADOW_MARGIN, - buffer->height + SHADOW_MARGIN, - 64, - 64); - break; - case HEADER: - draw_header(frame_gtk, cr, surface); - break; - } - - /* mask the toplevel surface */ - if (component == SHADOW) { - int component_x, component_y, component_width, component_height; - calculate_component_size(frame_gtk, component, - &component_x, &component_y, - &component_width, &component_height); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_rectangle(cr, -component_x, -component_y, - libdecor_frame_get_content_width( - &frame_gtk->frame), - libdecor_frame_get_content_height( - &frame_gtk->frame)); - cairo_fill(cr); - } - - cairo_destroy(cr); - cairo_surface_destroy(surface); -} - -static void -set_component_input_region(struct libdecor_frame_gtk *frame_gtk, - struct border_component *border_component) -{ - if (border_component->type == SHADOW && frame_gtk->shadow_showing) { - struct wl_region *input_region; - int component_x; - int component_y; - int component_width; - int component_height; - - calculate_component_size(frame_gtk, border_component->type, - &component_x, &component_y, - &component_width, &component_height); - - /* - * the input region is the outer surface size minus the inner - * content size - */ - input_region = wl_compositor_create_region( - frame_gtk->plugin_gtk->wl_compositor); - wl_region_add(input_region, 0, 0, - component_width, component_height); - wl_region_subtract(input_region, -component_x, -component_y, - libdecor_frame_get_content_width(&frame_gtk->frame), - libdecor_frame_get_content_height(&frame_gtk->frame)); - wl_surface_set_input_region(border_component->wl_surface, - input_region); - wl_region_destroy(input_region); - } -} - -static void -draw_border_component(struct libdecor_frame_gtk *frame_gtk, - struct border_component *border_component, - enum component component) -{ - struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk; - struct buffer *old_buffer; - struct buffer *buffer = NULL; - int component_x; - int component_y; - int component_width; - int component_height; - int scale = border_component->scale; - - if (border_component->wl_surface == NULL) - return; - - calculate_component_size(frame_gtk, component, - &component_x, &component_y, - &component_width, &component_height); - - set_component_input_region(frame_gtk, border_component); - - old_buffer = border_component->buffer; - if (old_buffer) { - if (!old_buffer->in_use && - old_buffer->buffer_width == component_width * scale && - old_buffer->buffer_height == component_height * scale) { - buffer = old_buffer; - } else { - buffer_free(old_buffer); - border_component->buffer = NULL; - } - } - - if (!buffer) - buffer = create_shm_buffer(plugin_gtk, - component_width, - component_height, - border_component->opaque, - border_component->scale); - - draw_component_content(frame_gtk, buffer, - component_width, component_height, - component); - - wl_surface_attach(border_component->wl_surface, buffer->wl_buffer, 0, 0); - wl_surface_set_buffer_scale(border_component->wl_surface, buffer->scale); - buffer->in_use = true; - wl_surface_commit(border_component->wl_surface); - wl_surface_damage_buffer(border_component->wl_surface, 0, 0, - component_width * scale, - component_height * scale); - wl_subsurface_set_position(border_component->wl_subsurface, - component_x, component_y); - - border_component->buffer = buffer; -} - -static void -draw_border(struct libdecor_frame_gtk *frame_gtk) -{ - draw_border_component(frame_gtk, &frame_gtk->shadow, SHADOW); - frame_gtk->shadow_showing = true; -} - -static void -draw_title_bar(struct libdecor_frame_gtk *frame_gtk) -{ - GtkAllocation allocation = {0, 0, frame_gtk->content_width, 0}; - enum libdecor_window_state state; - GtkStyleContext *style; - int pref_width; - int current_min_w, current_min_h, current_max_w, current_max_h, W, H; - - state = libdecor_frame_get_window_state((struct libdecor_frame*)frame_gtk); - style = gtk_widget_get_style_context(frame_gtk->window); - - if (!(state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - gtk_widget_set_state_flags(frame_gtk->window, GTK_STATE_FLAG_BACKDROP, true); - } else { - gtk_widget_unset_state_flags(frame_gtk->window, GTK_STATE_FLAG_BACKDROP); - } - - if (libdecor_frame_is_floating(&frame_gtk->frame)) { - gtk_style_context_remove_class(style, "maximized"); - } else { - gtk_style_context_add_class(style, "maximized"); - } - - gtk_widget_show_all(frame_gtk->window); - - /* set default width, using an empty title to estimate its smallest admissible value */ - gtk_header_bar_set_title(GTK_HEADER_BAR(frame_gtk->header), ""); - gtk_widget_get_preferred_width(frame_gtk->header, NULL, &pref_width); - gtk_header_bar_set_title(GTK_HEADER_BAR(frame_gtk->header), - libdecor_frame_get_title(&frame_gtk->frame)); - libdecor_frame_get_min_content_size(&frame_gtk->frame, ¤t_min_w, ¤t_min_h); - if (current_min_w < pref_width) { - current_min_w = pref_width; - libdecor_frame_set_min_content_size(&frame_gtk->frame, current_min_w, current_min_h); - } - libdecor_frame_get_max_content_size(&frame_gtk->frame, ¤t_max_w, ¤t_max_h); - if (current_max_w && current_max_w < current_min_w) { - libdecor_frame_set_max_content_size(&frame_gtk->frame, current_min_w, current_max_h); - } - W = libdecor_frame_get_content_width(&frame_gtk->frame); - H = libdecor_frame_get_content_height(&frame_gtk->frame); - if (W < current_min_w) { - W = current_min_w; - struct libdecor_state *libdecor_state = libdecor_state_new(W, H); - libdecor_frame_commit(&frame_gtk->frame, libdecor_state, NULL); - libdecor_state_free(libdecor_state); - return; - } - /* set default height */ - gtk_widget_get_preferred_height(frame_gtk->header, NULL, &allocation.height); - - gtk_widget_size_allocate(frame_gtk->header, &allocation); - - draw_border_component(frame_gtk, &frame_gtk->headerbar, HEADER); -} - -static void -draw_decoration(struct libdecor_frame_gtk *frame_gtk) -{ - switch (frame_gtk->decoration_type) { - case DECORATION_TYPE_NONE: - if (frame_gtk->link.next != NULL) - wl_list_remove(&frame_gtk->link); - if (is_border_surfaces_showing(frame_gtk)) - hide_border_surfaces(frame_gtk); - hide_border_component(&frame_gtk->headerbar); - break; - case DECORATION_TYPE_ALL: - /* show borders */ - ensure_border_surfaces(frame_gtk); - draw_border(frame_gtk); - /* show title bar */ - ensure_title_bar_surfaces(frame_gtk); - draw_title_bar(frame_gtk); - /* link frame */ - if (frame_gtk->link.next == NULL) - wl_list_insert( - &frame_gtk->plugin_gtk->visible_frame_list, - &frame_gtk->link); - break; - case DECORATION_TYPE_TITLE_ONLY: - /* hide borders */ - if (is_border_surfaces_showing(frame_gtk)) - hide_border_surfaces(frame_gtk); - /* show title bar */ - ensure_title_bar_surfaces(frame_gtk); - draw_title_bar(frame_gtk); - /* link frame */ - if (frame_gtk->link.next == NULL) - wl_list_insert( - &frame_gtk->plugin_gtk->visible_frame_list, - &frame_gtk->link); - break; - } -} - -static enum decoration_type -window_state_to_decoration_type(enum libdecor_window_state window_state) -{ - if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) - return DECORATION_TYPE_NONE; - else if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED || - window_state & LIBDECOR_WINDOW_STATE_TILED_LEFT || - window_state & LIBDECOR_WINDOW_STATE_TILED_RIGHT || - window_state & LIBDECOR_WINDOW_STATE_TILED_TOP || - window_state & LIBDECOR_WINDOW_STATE_TILED_BOTTOM) - /* title bar, no shadows */ - return DECORATION_TYPE_TITLE_ONLY; - else - /* title bar, shadows */ - return DECORATION_TYPE_ALL; -} - -static void -libdecor_plugin_gtk_frame_commit(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_state *state, - struct libdecor_configuration *configuration) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - enum libdecor_window_state old_window_state; - enum libdecor_window_state new_window_state; - int old_content_width, old_content_height; - int new_content_width, new_content_height; - enum decoration_type old_decoration_type; - enum decoration_type new_decoration_type; - - old_window_state = frame_gtk->window_state; - new_window_state = libdecor_frame_get_window_state(frame); - - old_content_width = frame_gtk->content_width; - old_content_height = frame_gtk->content_height; - new_content_width = libdecor_frame_get_content_width(frame); - new_content_height = libdecor_frame_get_content_height(frame); - - old_decoration_type = frame_gtk->decoration_type; - new_decoration_type = window_state_to_decoration_type(new_window_state); - - if (old_decoration_type == new_decoration_type && - old_content_width == new_content_width && - old_content_height == new_content_height && - old_window_state == new_window_state) - return; - - frame_gtk->content_width = new_content_width; - frame_gtk->content_height = new_content_height; - frame_gtk->window_state = new_window_state; - frame_gtk->decoration_type = new_decoration_type; - - draw_decoration(frame_gtk); - - /* set fixed window size */ - if (!resizable(frame_gtk)) { - libdecor_frame_set_min_content_size(frame, - frame_gtk->content_width, - frame_gtk->content_height); - libdecor_frame_set_max_content_size(frame, - frame_gtk->content_width, - frame_gtk->content_height); - } -} - -static void -libdecor_plugin_gtk_frame_property_changed(struct libdecor_plugin *plugin, - struct libdecor_frame *frame) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - bool redraw_needed = false; - const char *new_title; - - /* - * when in SSD mode, the window title is not to be managed by GTK; - * this is detected by frame_gtk->header not being a proper GTK widget - */ - if (!GTK_IS_WIDGET(frame_gtk->header)) return; - - new_title = libdecor_frame_get_title(frame); - if (!streq(frame_gtk->title, new_title)) - redraw_needed = true; - free(frame_gtk->title); - frame_gtk->title = NULL; - if (new_title) - frame_gtk->title = strdup(new_title); - - if (frame_gtk->capabilities != libdecor_frame_get_capabilities(frame)) { - frame_gtk->capabilities = libdecor_frame_get_capabilities(frame); - redraw_needed = true; - } - - if (redraw_needed) { - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(frame); - } -} - -static void -update_component_focus(struct libdecor_frame_gtk *frame_gtk, - struct wl_surface *surface, - struct seat *seat) -{ - static struct border_component *border_component; - static struct border_component *child_component; - static struct border_component *focus_component; - - border_component = get_component_for_surface(frame_gtk, surface); - - focus_component = border_component; - wl_list_for_each(child_component, &border_component->child_components, link) { - int component_x = 0, component_y = 0; - int component_width = 0, component_height = 0; - - calculate_component_size(frame_gtk, child_component->type, - &component_x, &component_y, - &component_width, &component_height); - if (seat->pointer_x >= component_x && - seat->pointer_x < component_x + component_width && - seat->pointer_y >= component_y && - seat->pointer_y < component_y + component_height) { - focus_component = child_component; - break; - } - } - - if (frame_gtk->grab) - frame_gtk->active = frame_gtk->grab; - else - frame_gtk->active = focus_component; - frame_gtk->focus = focus_component; - -} - -static void -sync_active_component(struct libdecor_frame_gtk *frame_gtk, - struct seat *seat) -{ - struct border_component *old_active; - - if (!seat->pointer_focus) - return; - - old_active = frame_gtk->active; - update_component_focus(frame_gtk, seat->pointer_focus, seat); - if (old_active != frame_gtk->active) { - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - - if (update_local_cursor(seat)) - send_cursor(seat); -} - -static void -synthesize_pointer_enter(struct seat *seat) -{ - struct wl_surface *surface; - struct libdecor_frame_gtk *frame_gtk; - - surface = seat->pointer_focus; - if (!surface || !own_surface(surface)) - return; - - frame_gtk = wl_surface_get_user_data(surface); - if (!frame_gtk) - return; - - update_component_focus(frame_gtk, seat->pointer_focus, seat); - frame_gtk->grab = NULL; - - /* update decorations */ - if (frame_gtk->active) { - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - - update_local_cursor(seat); - send_cursor(seat); -} - -static void -synthesize_pointer_leave(struct seat *seat) -{ - struct wl_surface *surface; - struct libdecor_frame_gtk *frame_gtk; - - surface = seat->pointer_focus; - if (!surface || !own_surface(surface)) - return; - - frame_gtk = wl_surface_get_user_data(surface); - if (!frame_gtk) - return; - - if (!frame_gtk->active) - return; - - frame_gtk->active = NULL; - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - update_local_cursor(seat); -} - -static void -libdecor_plugin_gtk_frame_popup_grab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk; - struct seat *seat; - - wl_list_for_each(seat, &plugin_gtk->seat_list, link) { - if (streq(seat->name, seat_name)) { - if (seat->grabbed) { - fprintf(stderr, "libdecor-WARNING: Application " - "tried to grab seat twice\n"); - } - synthesize_pointer_leave(seat); - seat->grabbed = true; - return; - } - } - - fprintf(stderr, - "libdecor-WARNING: Application tried to grab unknown seat\n"); -} - -static void -libdecor_plugin_gtk_frame_popup_ungrab(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - const char *seat_name) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk; - struct seat *seat; - - wl_list_for_each(seat, &plugin_gtk->seat_list, link) { - if (streq(seat->name, seat_name)) { - if (!seat->grabbed) { - fprintf(stderr, "libdecor-WARNING: Application " - "tried to ungrab seat twice\n"); - } - seat->grabbed = false; - synthesize_pointer_enter(seat); - sync_active_component(frame_gtk, seat); - return; - } - } - - fprintf(stderr, - "libdecor-WARNING: Application tried to ungrab unknown seat\n"); -} - -static bool -libdecor_plugin_gtk_frame_get_border_size(struct libdecor_plugin *plugin, - struct libdecor_frame *frame, - struct libdecor_configuration *configuration, - int *left, - int *right, - int *top, - int *bottom) -{ - struct libdecor_frame_gtk *frame_gtk = - (struct libdecor_frame_gtk *) frame; - enum libdecor_window_state window_state; - - if (configuration) { - if (!libdecor_configuration_get_window_state( - configuration, &window_state)) - return false; - } else { - window_state = libdecor_frame_get_window_state(frame); - } - - if (left) - *left = 0; - if (right) - *right = 0; - if (bottom) - *bottom = 0; - if (top) { - enum decoration_type type = window_state_to_decoration_type(window_state); - - switch (type) { - case DECORATION_TYPE_NONE: - *top = 0; - break; - case DECORATION_TYPE_ALL: - ensure_border_surfaces(frame_gtk); - //draw_border(frame_gtk); - G_GNUC_FALLTHROUGH; - case DECORATION_TYPE_TITLE_ONLY: - if (!frame_gtk->header) - ensure_title_bar_surfaces(frame_gtk); - gtk_widget_show_all(frame_gtk->window); - gtk_widget_get_preferred_height(frame_gtk->header, NULL, top); - break; - } - } - - return true; -} - -static struct libdecor_plugin_interface gtk_plugin_iface = { - .destroy = libdecor_plugin_gtk_destroy, - .get_fd = libdecor_plugin_gtk_get_fd, - .dispatch = libdecor_plugin_gtk_dispatch, - - .set_handle_application_cursor = libdecor_plugin_gtk_set_handle_application_cursor, - - .frame_new = libdecor_plugin_gtk_frame_new, - .frame_free = libdecor_plugin_gtk_frame_free, - .frame_commit = libdecor_plugin_gtk_frame_commit, - .frame_property_changed = libdecor_plugin_gtk_frame_property_changed, - - .frame_popup_grab = libdecor_plugin_gtk_frame_popup_grab, - .frame_popup_ungrab = libdecor_plugin_gtk_frame_popup_ungrab, - - .frame_get_border_size = libdecor_plugin_gtk_frame_get_border_size, -}; - -static void -init_wl_compositor(struct libdecor_plugin_gtk *plugin_gtk, - uint32_t id, - uint32_t version) -{ - plugin_gtk->wl_compositor = - wl_registry_bind(plugin_gtk->wl_registry, - id, &wl_compositor_interface, - MIN(version, 4)); -} - -static void -init_wl_subcompositor(struct libdecor_plugin_gtk *plugin_gtk, - uint32_t id, - uint32_t version) -{ - plugin_gtk->wl_subcompositor = - wl_registry_bind(plugin_gtk->wl_registry, - id, &wl_subcompositor_interface, 1); -} - -static void -shm_format(void *user_data, - struct wl_shm *wl_shm, - uint32_t format) -{ - struct libdecor_plugin_gtk *plugin_gtk = user_data; - - if (format == WL_SHM_FORMAT_ARGB8888) - plugin_gtk->has_argb = true; -} - -struct wl_shm_listener shm_listener = { - shm_format -}; - -static void -shm_callback(void *user_data, - struct wl_callback *callback, - uint32_t time) -{ - struct libdecor_plugin_gtk *plugin_gtk = user_data; - struct libdecor *context = plugin_gtk->context; - - wl_callback_destroy(callback); - plugin_gtk->globals_callback_shm = NULL; - - if (!plugin_gtk->has_argb) { - libdecor_notify_plugin_error( - context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "Compositor is missing required shm format"); - return; - } - - libdecor_notify_plugin_ready(context); -} - -static const struct wl_callback_listener shm_callback_listener = { - shm_callback -}; - -static void -init_wl_shm(struct libdecor_plugin_gtk *plugin_gtk, - uint32_t id, - uint32_t version) -{ - struct libdecor *context = plugin_gtk->context; - struct wl_display *wl_display = libdecor_get_wl_display(context); - - plugin_gtk->wl_shm = - wl_registry_bind(plugin_gtk->wl_registry, - id, &wl_shm_interface, 1); - wl_shm_add_listener(plugin_gtk->wl_shm, &shm_listener, plugin_gtk); - - plugin_gtk->globals_callback_shm = wl_display_sync(wl_display); - wl_callback_add_listener(plugin_gtk->globals_callback_shm, - &shm_callback_listener, - plugin_gtk); -} - -static void -cursor_surface_enter(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct seat *seat = data; - - if (own_output(wl_output)) { - struct cursor_output *cursor_output; - cursor_output = zalloc(sizeof *cursor_output); - cursor_output->output = wl_output_get_user_data(wl_output); - wl_list_insert(&seat->cursor_outputs, &cursor_output->link); - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static void -cursor_surface_leave(void *data, - struct wl_surface *wl_surface, - struct wl_output *wl_output) -{ - struct seat *seat = data; - - if (own_output(wl_output)) { - struct cursor_output *cursor_output, *tmp; - wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) { - if (cursor_output->output->wl_output == wl_output) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - } - - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static struct wl_surface_listener cursor_surface_listener = { - cursor_surface_enter, - cursor_surface_leave, -}; - -static void -ensure_cursor_surface(struct seat *seat) -{ - struct wl_compositor *wl_compositor = seat->plugin_gtk->wl_compositor; - - if (seat->cursor_surface) - return; - - seat->cursor_surface = wl_compositor_create_surface(wl_compositor); - wl_surface_add_listener(seat->cursor_surface, - &cursor_surface_listener, seat); -} - -static bool -ensure_cursor_theme(struct seat *seat) -{ - struct libdecor_plugin_gtk *plugin_gtk = seat->plugin_gtk; - int scale = 1; - struct wl_cursor_theme *theme; - struct cursor_output *cursor_output; - - wl_list_for_each(cursor_output, &seat->cursor_outputs, link) { - scale = MAX(scale, cursor_output->output->scale); - } - - if (seat->cursor_theme && seat->cursor_scale == scale) - return false; - - seat->cursor_scale = scale; - theme = wl_cursor_theme_load(plugin_gtk->cursor_theme_name, - plugin_gtk->cursor_size * scale, - plugin_gtk->wl_shm); - if (theme == NULL) - return false; - - if (seat->cursor_theme) - wl_cursor_theme_destroy(seat->cursor_theme); - - seat->cursor_theme = theme; - - for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) { - seat->cursors[i] = wl_cursor_theme_get_cursor( - seat->cursor_theme, - cursor_names[i]); - } - - seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, - "left_ptr"); - seat->current_cursor = seat->cursor_left_ptr; - - return true; -} - -enum libdecor_resize_edge -component_edge(const struct border_component *cmpnt, - const int pointer_x, - const int pointer_y, - const int margin) -{ - const bool top = pointer_y < margin * 2; - const bool bottom = pointer_y > (cmpnt->buffer->height - margin * 2); - const bool left = pointer_x < margin * 2; - const bool right = pointer_x > (cmpnt->buffer->width - margin * 2); - - if (top) { - if (left) - return LIBDECOR_RESIZE_EDGE_TOP_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_TOP_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_TOP; - } else if (bottom) { - if (left) - return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_BOTTOM; - } else if (left) { - return LIBDECOR_RESIZE_EDGE_LEFT; - } else if (right) { - return LIBDECOR_RESIZE_EDGE_RIGHT; - } else { - return LIBDECOR_RESIZE_EDGE_NONE; - } -} - -static bool -update_local_cursor(struct seat *seat) -{ - if (!seat->pointer_focus) { - seat->current_cursor = seat->cursor_left_ptr; - return false; - } - - if (!own_surface(seat->pointer_focus)) - return false; - - struct libdecor_frame_gtk *frame_gtk = - wl_surface_get_user_data(seat->pointer_focus); - struct wl_cursor *wl_cursor = NULL; - - if (!frame_gtk || !frame_gtk->active) { - seat->current_cursor = seat->cursor_left_ptr; - return false; - } - - bool theme_updated = ensure_cursor_theme(seat); - - if (frame_gtk->active->type == SHADOW && - is_border_surfaces_showing(frame_gtk) && - resizable(frame_gtk)) { - enum libdecor_resize_edge edge; - edge = component_edge(frame_gtk->active, - seat->pointer_x, - seat->pointer_y, SHADOW_MARGIN); - - if (edge != LIBDECOR_RESIZE_EDGE_NONE) - wl_cursor = seat->cursors[edge - 1]; - } else { - wl_cursor = seat->cursor_left_ptr; - } - - if (seat->current_cursor != wl_cursor) { - seat->current_cursor = wl_cursor; - return true; - } - - return theme_updated; -} - -static void -send_cursor(struct seat *seat) -{ - struct wl_cursor_image *image; - struct wl_buffer *buffer; - - if (seat->pointer_focus == NULL || seat->current_cursor == NULL) - return; - - image = seat->current_cursor->images[0]; - buffer = wl_cursor_image_get_buffer(image); - wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width * seat->cursor_scale, - image->height * seat->cursor_scale); - wl_surface_commit(seat->cursor_surface); - wl_pointer_set_cursor(seat->wl_pointer, seat->serial, - seat->cursor_surface, - image->hotspot_x / seat->cursor_scale, - image->hotspot_y / seat->cursor_scale); -} - -static void -pointer_enter(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - if (!surface) - return; - - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk = NULL; - - if (!own_surface(surface)) { - struct seat *seat = wl_pointer_get_user_data(wl_pointer); - struct libdecor_plugin_gtk *plugin_gtk = seat->plugin_gtk; - - if (!plugin_gtk->handle_cursor) - return; - } else { - frame_gtk = wl_surface_get_user_data(surface); - } - - ensure_cursor_surface(seat); - - seat->pointer_x = wl_fixed_to_int(surface_x); - seat->pointer_y = wl_fixed_to_int(surface_y); - seat->serial = serial; - seat->pointer_focus = surface; - - if (!frame_gtk) - return; - - frame_gtk->active = get_component_for_surface(frame_gtk, surface); - - /* update decorations */ - if (frame_gtk->active) { - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - - update_local_cursor(seat); - send_cursor(seat); -} - -static void -pointer_leave(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - - seat->pointer_focus = NULL; - - if (!surface) - return; - - if (!own_surface(surface)) - return; - - frame_gtk = wl_surface_get_user_data(surface); - - if (frame_gtk) { - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_INIT; - frame_gtk->titlebar_gesture.first_pressed_button = 0; - - frame_gtk->active = NULL; - frame_gtk->hdr_focus.widget = NULL; - frame_gtk->hdr_focus.type = HEADER_NONE; - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - update_local_cursor(seat); - } -} - -static void -pointer_motion(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - struct header_element_data new_focus; - - if (!seat->pointer_focus || !own_surface(seat->pointer_focus)) - return; - - seat->pointer_x = wl_fixed_to_int(surface_x); - seat->pointer_y = wl_fixed_to_int(surface_y); - if (update_local_cursor(seat)) - send_cursor(seat); - - frame_gtk = wl_surface_get_user_data(seat->pointer_focus); - /* avoid warnings after decoration has been turned off */ - if (!GTK_IS_WIDGET(frame_gtk->header) || frame_gtk->active->type != HEADER) { - frame_gtk->hdr_focus.type = HEADER_NONE; - } - - new_focus = get_header_focus(GTK_HEADER_BAR(frame_gtk->header), - seat->pointer_x, seat->pointer_y); - - /* only update if widget change so that we keep the state */ - if (frame_gtk->hdr_focus.widget != new_focus.widget) { - frame_gtk->hdr_focus = new_focus; - } - frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT; - /* redraw with updated button visuals */ - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - - switch (frame_gtk->titlebar_gesture.state) { - case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED: - if (frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT) { - if (ABS ((double) seat->pointer_x - - (double) frame_gtk->titlebar_gesture.pressed_x) > - frame_gtk->plugin_gtk->drag_threshold || - ABS ((double) seat->pointer_y - - (double) frame_gtk->titlebar_gesture.pressed_y) > - frame_gtk->plugin_gtk->drag_threshold) { - libdecor_frame_move(&frame_gtk->frame, - seat->wl_seat, - frame_gtk->titlebar_gesture.pressed_serial); - } - } - case TITLEBAR_GESTURE_STATE_INIT: - case TITLEBAR_GESTURE_STATE_CONSUMED: - case TITLEBAR_GESTURE_STATE_DISCARDED: - break; - } -} - -static void -handle_button_on_shadow(struct libdecor_frame_gtk *frame_gtk, - struct seat *seat, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - enum libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE; - - edge = component_edge(frame_gtk->active, - seat->pointer_x, - seat->pointer_y, - SHADOW_MARGIN); - - if (edge != LIBDECOR_RESIZE_EDGE_NONE && resizable(frame_gtk)) { - libdecor_frame_resize(&frame_gtk->frame, - seat->wl_seat, - serial, - edge); - } -} - -enum titlebar_gesture { - TITLEBAR_GESTURE_DOUBLE_CLICK, - TITLEBAR_GESTURE_MIDDLE_CLICK, - TITLEBAR_GESTURE_RIGHT_CLICK, -}; - -static void -handle_titlebar_gesture(struct libdecor_frame_gtk *frame_gtk, - struct seat *seat, - uint32_t serial, - enum titlebar_gesture gesture) -{ - switch (gesture) { - case TITLEBAR_GESTURE_DOUBLE_CLICK: - toggle_maximized(&frame_gtk->frame); - break; - case TITLEBAR_GESTURE_MIDDLE_CLICK: - break; - case TITLEBAR_GESTURE_RIGHT_CLICK: - { - const int title_height = gtk_widget_get_allocated_height(frame_gtk->header); - libdecor_frame_show_window_menu(&frame_gtk->frame, - seat->wl_seat, - serial, - seat->pointer_x, - seat->pointer_y - -title_height); - } - break; - } -} - -static void -handle_button_on_header(struct libdecor_frame_gtk *frame_gtk, - struct seat *seat, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - switch (frame_gtk->titlebar_gesture.state) { - case TITLEBAR_GESTURE_STATE_INIT: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - return; - - if (button == BTN_RIGHT) { - handle_titlebar_gesture(frame_gtk, - seat, - serial, - TITLEBAR_GESTURE_RIGHT_CLICK); - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_CONSUMED; - } else { - if (button == BTN_LEFT && - frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT && - time - frame_gtk->titlebar_gesture.first_pressed_time < - (uint32_t) frame_gtk->plugin_gtk->double_click_time_ms) { - handle_titlebar_gesture(frame_gtk, - seat, - serial, - TITLEBAR_GESTURE_DOUBLE_CLICK); - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_CONSUMED; - } else { - frame_gtk->titlebar_gesture.first_pressed_button = button; - frame_gtk->titlebar_gesture.first_pressed_time = time; - frame_gtk->titlebar_gesture.pressed_x = seat->pointer_x; - frame_gtk->titlebar_gesture.pressed_y = seat->pointer_y; - frame_gtk->titlebar_gesture.pressed_serial = serial; - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_BUTTON_PRESSED; - } - } - - frame_gtk->titlebar_gesture.button_pressed_count = 1; - - switch (frame_gtk->hdr_focus.type) { - case HEADER_MIN: - case HEADER_MAX: - case HEADER_CLOSE: - frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE; - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - break; - default: - break; - } - - break; - case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED: - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_DISCARDED; - frame_gtk->titlebar_gesture.button_pressed_count++; - } else { - frame_gtk->titlebar_gesture.button_pressed_count--; - - if (frame_gtk->titlebar_gesture.button_pressed_count == 0) { - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_INIT; - if (frame_gtk->titlebar_gesture.first_pressed_button == button && - button == BTN_LEFT) { - libdecor_frame_ref(&frame_gtk->frame); - switch (frame_gtk->hdr_focus.type) { - case HEADER_MIN: - if (minimizable(frame_gtk)) - libdecor_frame_set_minimized( - &frame_gtk->frame); - break; - case HEADER_MAX: - toggle_maximized(&frame_gtk->frame); - break; - case HEADER_CLOSE: - if (closeable(frame_gtk)) { - libdecor_frame_close( - &frame_gtk->frame); - seat->pointer_focus = NULL; - } - break; - default: - break; - } - - frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE; - if (GTK_IS_WIDGET(frame_gtk->header)) { - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - libdecor_frame_unref(&frame_gtk->frame); - } - } else { - frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE; - if (GTK_IS_WIDGET(frame_gtk->header)) { - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - } - - } - break; - case TITLEBAR_GESTURE_STATE_CONSUMED: - case TITLEBAR_GESTURE_STATE_DISCARDED: - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - frame_gtk->titlebar_gesture.button_pressed_count++; - } else { - frame_gtk->titlebar_gesture.button_pressed_count--; - if (frame_gtk->titlebar_gesture.button_pressed_count == 0) { - frame_gtk->titlebar_gesture.state = - TITLEBAR_GESTURE_STATE_INIT; - frame_gtk->titlebar_gesture.first_pressed_button = 0; - } - } - break; - } -} - -static void -pointer_button(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - - if (!seat->pointer_focus || !own_surface(seat->pointer_focus)) - return; - - frame_gtk = wl_surface_get_user_data(seat->pointer_focus); - if (!frame_gtk) - return; - - switch (frame_gtk->active->type) { - case SHADOW: - handle_button_on_shadow (frame_gtk, seat, serial, time, button, state); - break; - case HEADER: - handle_button_on_header (frame_gtk, seat, serial, time, button, state); - break; - default: - break; - } -} - -static void -pointer_axis(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ -} - -static struct wl_pointer_listener pointer_listener = { - pointer_enter, - pointer_leave, - pointer_motion, - pointer_button, - pointer_axis -}; - -static void -update_touch_focus(struct seat *seat, - struct libdecor_frame_gtk *frame_gtk, - wl_fixed_t x, - wl_fixed_t y) -{ - /* avoid warnings after decoration has been turned off */ - if (GTK_IS_WIDGET(frame_gtk->header) && frame_gtk->touch_active->type == HEADER) { - struct header_element_data new_focus = get_header_focus( - GTK_HEADER_BAR(frame_gtk->header), - wl_fixed_to_int(x), wl_fixed_to_int(y)); - /* only update if widget change so that we keep the state */ - if (frame_gtk->hdr_focus.widget != new_focus.widget) { - frame_gtk->hdr_focus = new_focus; - } - frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT; - /* redraw with updated button visuals */ - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } else { - frame_gtk->hdr_focus.type = HEADER_NONE; - } -} - -static void -touch_down(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - int32_t id, - wl_fixed_t x, - wl_fixed_t y) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - - if (!surface || !own_surface(surface)) - return; - - frame_gtk = wl_surface_get_user_data(surface); - if (!frame_gtk) - return; - - seat->touch_focus = surface; - frame_gtk->touch_active = get_component_for_surface(frame_gtk, surface); - - if (!frame_gtk->touch_active) - return; - - update_touch_focus(seat, frame_gtk, x, y); - - /* update decorations */ - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - - enum libdecor_resize_edge edge = - LIBDECOR_RESIZE_EDGE_NONE; - switch (frame_gtk->touch_active->type) { - case SHADOW: - edge = component_edge(frame_gtk->touch_active, - wl_fixed_to_int(x), - wl_fixed_to_int(y), - SHADOW_MARGIN); - break; - case HEADER: - switch (frame_gtk->hdr_focus.type) { - case HEADER_MIN: - case HEADER_MAX: - case HEADER_CLOSE: - frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE; - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - break; - default: - if (time - seat->touch_down_time_stamp < - (uint32_t)frame_gtk->plugin_gtk->double_click_time_ms) { - toggle_maximized(&frame_gtk->frame); - } - else if (moveable(frame_gtk)) { - seat->touch_down_time_stamp = time; - libdecor_frame_move(&frame_gtk->frame, - seat->wl_seat, - serial); - } - break; - } - break; - default: - break; - } - if (edge != LIBDECOR_RESIZE_EDGE_NONE && - resizable(frame_gtk)) { - libdecor_frame_resize( - &frame_gtk->frame, - seat->wl_seat, - serial, - edge); - } -} - -static void -touch_up(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - int32_t id) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - - if (!seat->touch_focus || !own_surface(seat->touch_focus)) - return; - - frame_gtk = wl_surface_get_user_data(seat->touch_focus); - if (!frame_gtk) - return; - - if (!frame_gtk->touch_active) - return; - - switch (frame_gtk->touch_active->type) { - case HEADER: - libdecor_frame_ref(&frame_gtk->frame); - switch (frame_gtk->hdr_focus.type) { - case HEADER_MIN: - if (minimizable(frame_gtk)) { - libdecor_frame_set_minimized( - &frame_gtk->frame); - } - break; - case HEADER_MAX: - toggle_maximized(&frame_gtk->frame); - break; - case HEADER_CLOSE: - if (closeable(frame_gtk)) { - libdecor_frame_close( - &frame_gtk->frame); - seat->touch_focus = NULL; - } - break; - default: - break; - } - /* unset active/clicked state once released */ - frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE; - if (GTK_IS_WIDGET(frame_gtk->header)) { - draw_title_bar(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - libdecor_frame_unref(&frame_gtk->frame); - break; - default: - break; - } - - seat->touch_focus = NULL; - frame_gtk->touch_active = NULL; - frame_gtk->hdr_focus.widget = NULL; - frame_gtk->hdr_focus.type = HEADER_NONE; - draw_decoration(frame_gtk); - libdecor_frame_toplevel_commit(&frame_gtk->frame); -} - -static void -touch_motion(void *data, - struct wl_touch *wl_touch, - uint32_t time, - int32_t id, - wl_fixed_t x, - wl_fixed_t y) -{ - struct seat *seat = data; - struct libdecor_frame_gtk *frame_gtk; - - if (!seat->touch_focus || !own_surface(seat->touch_focus)) - return; - - frame_gtk = wl_surface_get_user_data(seat->touch_focus); - if (!frame_gtk) - return; - - update_touch_focus(seat, frame_gtk, x, y); -} - -static void -touch_frame(void *data, - struct wl_touch *wl_touch) -{ -} - -static void -touch_cancel(void *data, - struct wl_touch *wl_touch) -{ -} - -static struct wl_touch_listener touch_listener = { - touch_down, - touch_up, - touch_motion, - touch_frame, - touch_cancel -}; - -static void -seat_capabilities(void *data, - struct wl_seat *wl_seat, - uint32_t capabilities) -{ - struct seat *seat = data; - - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && - !seat->wl_pointer) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(seat->wl_pointer, - &pointer_listener, seat); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && - seat->wl_pointer) { - wl_pointer_release(seat->wl_pointer); - seat->wl_pointer = NULL; - } - - if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) && - !seat->wl_touch) { - seat->wl_touch = wl_seat_get_touch(wl_seat); - wl_touch_add_listener(seat->wl_touch, - &touch_listener, seat); - } else if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH) && - seat->wl_touch) { - wl_touch_release(seat->wl_touch); - seat->wl_touch = NULL; - } -} - -static void -seat_name(void *data, - struct wl_seat *wl_seat, - const char *name) -{ - /* avoid warning messages when opening/closing popup window */ - struct seat *seat = (struct seat*)data; - seat->name = strdup(name); -} - -static struct wl_seat_listener seat_listener = { - seat_capabilities, - seat_name -}; - -static void -init_wl_seat(struct libdecor_plugin_gtk *plugin_gtk, - uint32_t id, - uint32_t version) -{ - struct seat *seat; - - if (version < 3) { - libdecor_notify_plugin_error( - plugin_gtk->context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "%s version 3 required but only version %i is available\n", - wl_seat_interface.name, - version); - } - - seat = zalloc(sizeof *seat); - seat->cursor_scale = 1; - seat->plugin_gtk = plugin_gtk; - wl_list_init(&seat->cursor_outputs); - wl_list_insert(&plugin_gtk->seat_list, &seat->link); - seat->wl_seat = - wl_registry_bind(plugin_gtk->wl_registry, - id, &wl_seat_interface, 3); - wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); -} - -static void -output_geometry(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform) -{ -} - -static void -output_mode(void *data, - struct wl_output *wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) -{ -} - -static void -output_done(void *data, - struct wl_output *wl_output) -{ - struct output *output = data; - struct libdecor_frame_gtk *frame_gtk; - struct seat *seat; - - wl_list_for_each(frame_gtk, - &output->plugin_gtk->visible_frame_list, link) { - bool updated = false; - updated |= redraw_scale(frame_gtk, &frame_gtk->shadow); - if (updated) - libdecor_frame_toplevel_commit(&frame_gtk->frame); - } - wl_list_for_each(seat, &output->plugin_gtk->seat_list, link) { - if (update_local_cursor(seat)) - send_cursor(seat); - } -} - -static void -output_scale(void *data, - struct wl_output *wl_output, - int32_t factor) -{ - struct output *output = data; - - output->scale = factor; -} - -static struct wl_output_listener output_listener = { - output_geometry, - output_mode, - output_done, - output_scale -}; - -static void -init_wl_output(struct libdecor_plugin_gtk *plugin_gtk, - uint32_t id, - uint32_t version) -{ - struct output *output; - - if (version < 2) { - libdecor_notify_plugin_error( - plugin_gtk->context, - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - "%s version 2 required but only version %i is available\n", - wl_output_interface.name, - version); - } - - output = zalloc(sizeof *output); - output->plugin_gtk = plugin_gtk; - wl_list_insert(&plugin_gtk->output_list, &output->link); - output->id = id; - output->wl_output = - wl_registry_bind(plugin_gtk->wl_registry, - id, &wl_output_interface, - MIN (version, 3)); - wl_proxy_set_tag((struct wl_proxy *) output->wl_output, - &libdecor_gtk_proxy_tag); - wl_output_add_listener(output->wl_output, &output_listener, output); -} - -static void -registry_handle_global(void *user_data, - struct wl_registry *wl_registry, - uint32_t id, - const char *interface, - uint32_t version) -{ - struct libdecor_plugin_gtk *plugin_gtk = user_data; - - if (strcmp(interface, "wl_compositor") == 0) - init_wl_compositor(plugin_gtk, id, version); - else if (strcmp(interface, "wl_subcompositor") == 0) - init_wl_subcompositor(plugin_gtk, id, version); - else if (strcmp(interface, "wl_shm") == 0) - init_wl_shm(plugin_gtk, id, version); - else if (strcmp(interface, "wl_seat") == 0) - init_wl_seat(plugin_gtk, id, version); - else if (strcmp(interface, "wl_output") == 0) - init_wl_output(plugin_gtk, id, version); -} - -static void -remove_surface_outputs(struct border_component *cmpnt, const struct output *output) -{ - struct surface_output *surface_output; - wl_list_for_each(surface_output, &cmpnt->output_list, link) { - if (surface_output->output == output) { - wl_list_remove(&surface_output->link); - free(surface_output); - break; - } - } -} - -static void -output_removed(struct libdecor_plugin_gtk *plugin_gtk, - struct output *output) -{ - struct libdecor_frame_gtk *frame_gtk; - struct seat *seat; - - wl_list_for_each(frame_gtk, &plugin_gtk->visible_frame_list, link) { - remove_surface_outputs(&frame_gtk->shadow, output); - } - wl_list_for_each(seat, &plugin_gtk->seat_list, link) { - struct cursor_output *cursor_output; - wl_list_for_each(cursor_output, &seat->cursor_outputs, link) { - if (cursor_output->output == output) { - wl_list_remove(&cursor_output->link); - free(cursor_output); - } - } - } - - wl_list_remove(&output->link); - wl_output_destroy(output->wl_output); - free(output); -} - -static void -registry_handle_global_remove(void *user_data, - struct wl_registry *wl_registry, - uint32_t name) -{ - struct libdecor_plugin_gtk *plugin_gtk = user_data; - struct output *output; - - wl_list_for_each(output, &plugin_gtk->output_list, link) { - if (output->id == name) { - output_removed(plugin_gtk, output); - break; - } - } -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static bool -has_required_globals(struct libdecor_plugin_gtk *plugin_gtk) -{ - if (!plugin_gtk->wl_compositor) - return false; - if (!plugin_gtk->wl_subcompositor) - return false; - if (!plugin_gtk->wl_shm) - return false; - - return true; -} - -static void -globals_callback(void *user_data, - struct wl_callback *callback, - uint32_t time) -{ - struct libdecor_plugin_gtk *plugin_gtk = user_data; - - wl_callback_destroy(callback); - plugin_gtk->globals_callback = NULL; -} - -static const struct wl_callback_listener globals_callback_listener = { - globals_callback -}; - -static struct libdecor_plugin * -libdecor_plugin_new(struct libdecor *context) -{ - struct libdecor_plugin_gtk *plugin_gtk; - struct wl_display *wl_display; - -#ifdef HAVE_GETTID - /* Only support running on the main thread. */ - if (getpid () != gettid ()) - return NULL; -#endif - - plugin_gtk = zalloc(sizeof *plugin_gtk); - libdecor_plugin_init(&plugin_gtk->plugin, - context, - >k_plugin_iface); - plugin_gtk->context = context; - - wl_list_init(&plugin_gtk->visible_frame_list); - wl_list_init(&plugin_gtk->seat_list); - wl_list_init(&plugin_gtk->output_list); - - /* fetch cursor theme and size*/ - if (!libdecor_get_cursor_settings(&plugin_gtk->cursor_theme_name, - &plugin_gtk->cursor_size)) { - plugin_gtk->cursor_theme_name = NULL; - plugin_gtk->cursor_size = 24; - } - - plugin_gtk->color_scheme_setting = libdecor_get_color_scheme(); - - wl_display = libdecor_get_wl_display(context); - plugin_gtk->wl_registry = wl_display_get_registry(wl_display); - wl_registry_add_listener(plugin_gtk->wl_registry, - ®istry_listener, - plugin_gtk); - - plugin_gtk->globals_callback = wl_display_sync(wl_display); - wl_callback_add_listener(plugin_gtk->globals_callback, - &globals_callback_listener, - plugin_gtk); - wl_display_roundtrip(wl_display); - - if (!has_required_globals(plugin_gtk)) { - fprintf(stderr, "libdecor-gtk-WARNING: Could not get required globals\n"); - libdecor_plugin_gtk_destroy(&plugin_gtk->plugin); - return NULL; - } - - /* setup GTK context */ - gdk_set_allowed_backends("wayland"); - gtk_disable_setlocale(); - - if (!gtk_init_check(NULL, NULL)) { - fprintf(stderr, "libdecor-gtk-WARNING: Failed to initialize GTK\n"); - libdecor_plugin_gtk_destroy(&plugin_gtk->plugin); - return NULL; - } - - g_object_set(gtk_settings_get_default(), - "gtk-application-prefer-dark-theme", - plugin_gtk->color_scheme_setting == LIBDECOR_COLOR_SCHEME_PREFER_DARK, - NULL); - - return &plugin_gtk->plugin; -} - -static struct libdecor_plugin_priority priorities[] = { - { NULL, LIBDECOR_PLUGIN_PRIORITY_HIGH } -}; - -LIBDECOR_EXPORT const struct libdecor_plugin_description -libdecor_plugin_description = { - .api_version = LIBDECOR_PLUGIN_API_VERSION, - .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE, - .description = "GTK3 plugin", - .priorities = priorities, - .constructor = libdecor_plugin_new, - .conflicting_symbols = { - "png_free", - "gdk_get_use_xshm", - NULL, - }, -}; diff --git a/libdecor/src/utils.h b/libdecor/src/utils.h deleted file mode 100644 index 7892793b6..000000000 --- a/libdecor/src/utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright © 2017 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef UTILS_H -#define UTILS_H - -#include <stdlib.h> - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -#ifndef ARRAY_LENGTH -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -static inline void * -zalloc(size_t size) -{ - return calloc(1, size); -} - -#endif /* UTILS_H */ diff --git a/package/CMakeLists.txt b/package/CMakeLists.txt deleted file mode 100644 index e47f546ce..000000000 --- a/package/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -# -# CMakeLists.txt to enable CPack for the FLTK project -# -# Copyright 2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Note: this file is included by add_subdirectory() only if it really -# is to be used (top level project, maybe an option, etc.). -# Therefore the code below is executed unconditionally... - -####################################################################### -# Configure CPack parameters -####################################################################### - -set(CPACK_PACKAGE_NAME "FLTK") -set(CPACK_PACKAGE_VENDOR "The FLTK TEAM (fltk.org)") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cross-platform GUI development library") -set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") -set(CPACK_PACKAGE_VERSION_MAJOR "${FLTK_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${FLTK_VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${FLTK_VERSION_PATCH}") - -set(CPACK_VERBATIM_VARIABLES TRUE) - -# The following files are used by *some* installers (not yet supported by FLTK). -# These files would be located in the same directory as this file. -# CMake uses default values if these variables are not defined. - -# set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_LIST_DIR}/Description.txt) -# set(CPACK_RESOURCE_FILE_WELCOME ${CMAKE_CURRENT_LIST_DIR}/Welcome.txt) -# set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/License.txt) -# set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_LIST_DIR}/Readme.txt) - -####################################################################### -# Include the CPack module -####################################################################### - -include(CPack) diff --git a/png/CMakeLists.txt b/png/CMakeLists.txt deleted file mode 100644 index e873e9be0..000000000 --- a/png/CMakeLists.txt +++ /dev/null @@ -1,141 +0,0 @@ -# -# PNG library CMake configuration for the Fast Light Toolkit (FLTK). -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# source files for png -set(PNG_SRCS - png.c - pngerror.c - pngget.c - pngmem.c - pngpread.c - pngread.c - pngrio.c - pngrtran.c - pngrutil.c - pngset.c - pngtrans.c - pngwio.c - pngwrite.c - pngwtran.c - pngwutil.c -) - -####################################################################### -# Note: This file is used only if we build the bundled PNG library, -# and if we do this we MUST also build and use the *bundled* ZLIB, -# hence we also link against the bundled ZLIB. Therefore there's -# no need to check which ZLIB version to use in this context. -####################################################################### - -####################################################################### -# Build some files on ARM (e.g. Apple M1 systems) -####################################################################### - -# We can only determine the target architecture if it is set -# in CMAKE_OSX_ARCHITECTURES, otherwise we *assume* it is true and -# compile these files even if this results in some warnings. -# This includes all non-macOS platforms. - -if(CMAKE_OSX_ARCHITECTURES) - string(REGEX MATCH "arm64" is_arm "${CMAKE_OSX_ARCHITECTURES}") -else() - set(is_arm TRUE) -endif() - -if(is_arm) - list(APPEND PNG_SRCS - arm/arm_init.c - arm/filter_neon_intrinsics.c - arm/palette_neon_intrinsics.c - ) -endif() - -unset(is_arm) - -####################################################################### -# Build some files on ppc64. -# We compile these files whatever the architecture resulting in -# void code on non-ppc64 architectures. -####################################################################### - -list(APPEND PNG_SRCS - powerpc/powerpc_init.c - powerpc/filter_vsx_intrinsics.c -) - -####################################################################### -# Set common variables for static and shared builds -####################################################################### - -set(compile_defs - HAVE_PNG_H=1 - HAVE_PNG_GET_VALID=1 - HAVE_PNG_SET_TRNS_TO_ALPHA=1 -) - -set(include_dirs - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> - $<INSTALL_INTERFACE:include> -) - -####################################################################### -# Build the static library -####################################################################### - -fl_add_library(fltk_png STATIC "${PNG_SRCS}") -set(target fltk_png) - -target_link_libraries (${target} PUBLIC fltk::z) -target_compile_definitions(${target} PUBLIC ${compile_defs}) -target_include_directories(${target} PUBLIC ${include_dirs}) - -list(APPEND FLTK_IMAGE_LIBRARIES fltk::png) - -# Propagate to parent scope (modified by fl_add_library and here) -set(FLTK_LIBRARIES ${FLTK_LIBRARIES} PARENT_SCOPE) -set(FLTK_IMAGE_LIBRARIES ${FLTK_IMAGE_LIBRARIES} PARENT_SCOPE) - -####################################################################### -# Build the shared library (optional) -####################################################################### - -if(FLTK_BUILD_SHARED_LIBS) - - # ensure to export all symbols for Windows DLL's - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) - - fl_add_library(fltk_png SHARED "${PNG_SRCS}") - set(target fltk_png-shared) - - target_link_libraries (${target} PUBLIC fltk::z-shared) - target_compile_definitions(${target} PUBLIC ${compile_defs}) - target_include_directories(${target} PUBLIC ${include_dirs}) - - list(APPEND FLTK_IMAGE_LIBRARIES_SHARED fltk::png-shared) - - # Propagate to parent scope (modified by fl_add_library and here) - set(FLTK_LIBRARIES_SHARED ${FLTK_LIBRARIES_SHARED} PARENT_SCOPE) - set(FLTK_IMAGE_LIBRARIES_SHARED ${FLTK_IMAGE_LIBRARIES_SHARED} PARENT_SCOPE) - -endif() - -####################################################################### -# Install the library headers -####################################################################### - -install(FILES png.h pngconf.h pnglibconf.h pngprefix.h - DESTINATION ${FLTK_INCLUDEDIR}/FL/images -) diff --git a/screenshots/CMakeLists.txt b/screenshots/CMakeLists.txt deleted file mode 100644 index f7cc10e30..000000000 --- a/screenshots/CMakeLists.txt +++ /dev/null @@ -1,67 +0,0 @@ -# -# CMakeLists.txt to create screenshot programs for FLTK documentation -# -# Copyright 2026 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -######################################################################## -# Screenshot programs for FLTK documentation -######################################################################## - -# The programs in this subdirectory are intended to be used by FLTK -# developers to create screenshots for our Doxygen documentation. -# See README.txt for more info. - -# These programs are not "installed" on target systems, they are only -# built in the FLTK build tree (if FLTK_BUILD_SCREENSHOTS=ON). - -######################################################################## -# Define a list of programs that will be built w/o extension. -# All programs must use the 'scr_' prefix and the '.cxx' extension. -# Define the names in the list below w/o prefix and extension. -######################################################################## - -set(NAMES - unicode # Unicode text example - # add more programs here ... -) - -######################################################################## -# Build a special CMake "object library" for common (screenshot) code -######################################################################## - -# not yet implemented - -######################################################################## -# Build all programs with common options -######################################################################## - -set(EXECUTABLE_OUTPUT_PATH - ${CMAKE_CURRENT_BINARY_DIR}/../bin/screenshots) - -set(PREFIX scr_) # will be prepended to target names - -foreach(_prog ${NAMES}) - - set(_target ${PREFIX}${_prog}) # enforce the target prefix ! - - add_executable(${_target} WIN32 MACOSX_BUNDLE ${_prog}.cxx) - - target_link_libraries(${_target} PRIVATE fltk::images) - - set_target_properties(${_target} PROPERTIES - OUTPUT_NAME ${_target} - EXCLUDE_FROM_ALL FALSE - ) - -endforeach() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index cf4196185..000000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,1071 +0,0 @@ -# -# CMakeLists.txt to build the FLTK library using CMake (www.cmake.org) -# -# Copyright 1998-2026 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Local macro to check existence of a required file with warning message -# -# In: FILENAME (string): File to search -# Out: WARN (string): *Name* of a variable that is set to true if NOT found -# -# Set variable ${WARN} to FALSE before calling this macro - -macro(fl_check_required_file WARN FILENAME) - if(NOT EXISTS ${FILENAME}) - message("*** Required file not found: ${FILENAME} ***") - set(${WARN} TRUE) - endif() -endmacro(fl_check_required_file WARN FILENAME) - -set(CPPFILES - Fl.cxx - Fl_Adjuster.cxx - Fl_Bitmap.cxx - Fl_Browser.cxx - Fl_Browser_.cxx - Fl_Browser_load.cxx - Fl_Box.cxx - Fl_Button.cxx - Fl_Chart.cxx - Fl_Check_Browser.cxx - Fl_Check_Button.cxx - Fl_Choice.cxx - Fl_Clock.cxx - Fl_Color_Chooser.cxx - Fl_Copy_Surface.cxx - Fl_Counter.cxx - Fl_Device.cxx - Fl_Dial.cxx - Fl_Double_Window.cxx - Fl_File_Browser.cxx - Fl_File_Chooser.cxx - Fl_File_Chooser2.cxx - Fl_File_Icon.cxx - Fl_File_Input.cxx - Fl_Flex.cxx - Fl_Graphics_Driver.cxx - Fl_Grid.cxx - Fl_Group.cxx - Fl_Help_View.cxx - Fl_Image.cxx - Fl_Image_Surface.cxx - Fl_Input.cxx - Fl_Input_.cxx - Fl_Input_Choice.cxx - Fl_Light_Button.cxx - Fl_Menu.cxx - Fl_Menu_.cxx - Fl_Menu_Bar.cxx - Fl_Menu_Button.cxx - Fl_Menu_Window.cxx - Fl_Menu_add.cxx - Fl_Menu_global.cxx - Fl_Message.cxx - Fl_Multi_Label.cxx - Fl_Native_File_Chooser.cxx - Fl_Overlay_Window.cxx - Fl_Pack.cxx - Fl_Paged_Device.cxx - Fl_Pixmap.cxx - Fl_Positioner.cxx - Fl_Preferences.cxx - Fl_Printer.cxx - Fl_Progress.cxx - Fl_Repeat_Button.cxx - Fl_Return_Button.cxx - Fl_Roller.cxx - Fl_Round_Button.cxx - Fl_Scheme.cxx - Fl_Scheme_Choice.cxx - Fl_Screen_Driver.cxx - Fl_Scroll.cxx - Fl_Scrollbar.cxx - Fl_Shared_Image.cxx - Fl_Shortcut_Button.cxx - Fl_Single_Window.cxx - Fl_Slider.cxx - Fl_Spinner.cxx - Fl_Sys_Menu_Bar.cxx - Fl_System_Driver.cxx - Fl_Table.cxx - Fl_Table_Row.cxx - Fl_Tabs.cxx - Fl_Terminal.cxx - Fl_Text_Buffer.cxx - Fl_Text_Display.cxx - Fl_Text_Editor.cxx - Fl_Tile.cxx - Fl_Tiled_Image.cxx - Fl_Timeout.cxx - Fl_Tooltip.cxx - Fl_Tree.cxx - Fl_Tree_Item_Array.cxx - Fl_Tree_Item.cxx - Fl_Tree_Prefs.cxx - Fl_Valuator.cxx - Fl_Value_Input.cxx - Fl_Value_Output.cxx - Fl_Value_Slider.cxx - Fl_Widget.cxx - Fl_Widget_Surface.cxx - Fl_Window.cxx - Fl_Window_Driver.cxx - Fl_Window_fullscreen.cxx - Fl_Window_hotspot.cxx - Fl_Window_iconize.cxx - Fl_Wizard.cxx - Fl_XBM_Image.cxx - Fl_XPM_Image.cxx - Fl_abort.cxx - Fl_add_idle.cxx - Fl_arg.cxx - Fl_compose.cxx - Fl_display.cxx - Fl_get_system_colors.cxx - Fl_grab.cxx - Fl_lock.cxx - Fl_own_colormap.cxx - Fl_visual.cxx - filename_absolute.cxx - filename_expand.cxx - filename_ext.cxx - filename_isdir.cxx - filename_list.cxx - filename_match.cxx - filename_setext.cxx - fl_arc.cxx - fl_ask.cxx - fl_boxtype.cxx - fl_color.cxx - fl_contrast.cxx - fl_cursor.cxx - fl_curve.cxx - fl_diamond_box.cxx - fl_draw.cxx - fl_draw_arrow.cxx - fl_draw_pixmap.cxx - fl_encoding_latin1.cxx - fl_encoding_mac_roman.cxx - fl_engraved_label.cxx - fl_file_dir.cxx - fl_font.cxx - fl_gleam.cxx - fl_gtk.cxx - fl_labeltype.cxx - fl_open_uri.cxx - fl_oval_box.cxx - fl_overlay.cxx - fl_oxy.cxx - fl_plastic.cxx - fl_read_image.cxx - fl_rect.cxx - fl_round_box.cxx - fl_rounded_box.cxx - fl_set_font.cxx - fl_scroll_area.cxx - fl_shadow_box.cxx - fl_shortcut.cxx - fl_show_colormap.cxx - fl_string_functions.cxx - fl_symbols.cxx - fl_utf8.cxx - fl_vertex.cxx - print_button.cxx - screen_xywh.cxx -) - -if(FLTK_HAVE_CAIRO) # FLTK_OPTION_CAIRO_WINDOW or FLTK_OPTION_CAIRO_EXT - list(APPEND CPPFILES Fl_Cairo.cxx) -endif() - -# find all header files in includes directory <FL/...> -file(GLOB - HEADER_FILES - "../FL/*.[hH]" - "../FL/core/*.[hH]" -) - -# find all private header files in source directory "src/..." -file(GLOB - PRIVATE_HEADER_FILES - "*.[hH]" -) - -# find all private header files in source directory "src/..." -file(GLOB - PRIVATE_HEADER_FILES - "*.[hH]" -) - -# add generated header files in build directory -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_BINARY_DIR}/../FL/fl_config.h - ${CMAKE_CURRENT_BINARY_DIR}/../config.h -) - -set(GL_HEADER_FILES) # FIXME: not (yet?) defined - -if(FLTK_USE_X11 AND NOT FLTK_OPTION_PRINT_SUPPORT) - set(PSFILES) -else() - set(PSFILES - drivers/PostScript/Fl_PostScript.cxx - drivers/PostScript/Fl_PostScript_image.cxx - ) -endif(FLTK_USE_X11 AND NOT FLTK_OPTION_PRINT_SUPPORT) - -set(DRIVER_FILES) - -if(FLTK_USE_X11 AND NOT FLTK_USE_WAYLAND) - - # X11 (including APPLE with X11) - - set(DRIVER_FILES - drivers/Posix/Fl_Posix_Printer_Driver.cxx - drivers/X11/Fl_X11_Screen_Driver.cxx - drivers/X11/Fl_X11_Window_Driver.cxx - drivers/Posix/Fl_Posix_System_Driver.cxx - drivers/Unix/Fl_Unix_System_Driver.cxx - drivers/Unix/Fl_Unix_Screen_Driver.cxx - drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx - drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx - drivers/X11/fl_X11_platform_init.cxx - Fl_x.cxx - fl_dnd_x.cxx - Fl_Native_File_Chooser_FLTK.cxx - Fl_Native_File_Chooser_GTK.cxx - Fl_get_key.cxx - ) - - list(APPEND DRIVER_FILES - Fl_Native_File_Chooser_Kdialog.cxx - Fl_Native_File_Chooser_Zenity.cxx) - - if(FLTK_USE_CAIRO) - list(APPEND DRIVER_FILES - drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx - drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx - ) - else() - if(USE_XFT) - list(APPEND DRIVER_FILES - drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx - ) - if(USE_PANGO) - list(APPEND DRIVER_FILES drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx) - endif(USE_PANGO) - else() - list(APPEND DRIVER_FILES - drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx - ) - endif(USE_XFT) - list(APPEND DRIVER_FILES - drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx - drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx - ) - endif(FLTK_USE_CAIRO) - - set(DRIVER_HEADER_FILES - drivers/Posix/Fl_Posix_System_Driver.H - drivers/X11/Fl_X11_Screen_Driver.H - drivers/X11/Fl_X11_Window_Driver.H - drivers/Xlib/Fl_Xlib_Graphics_Driver.H - drivers/Xlib/Fl_Font.H - drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H - drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H - drivers/Unix/Fl_Unix_System_Driver.H - ) - if(FLTK_USE_CAIRO) - set(DRIVER_HEADER_FILES ${DRIVER_HEADER_FILES} - drivers/Cairo/Fl_Cairo_Graphics_Driver.H - drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.H - ) - elseif(USE_PANGO) - set(DRIVER_HEADER_FILES ${DRIVER_HEADER_FILES} - drivers/Cairo/Fl_Cairo_Graphics_Driver.H - ) - endif(FLTK_USE_CAIRO) - -elseif(FLTK_USE_WAYLAND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_BINARY_DIR}") - set(DRIVER_FILES - drivers/Posix/Fl_Posix_System_Driver.cxx - drivers/Posix/Fl_Posix_Printer_Driver.cxx - drivers/Unix/Fl_Unix_Screen_Driver.cxx - drivers/Wayland/Fl_Wayland_Screen_Driver.cxx - drivers/Wayland/Fl_Wayland_Window_Driver.cxx - drivers/Unix/Fl_Unix_System_Driver.cxx - drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx - drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx - drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx - drivers/Wayland/fl_wayland_clipboard_dnd.cxx - drivers/Wayland/fl_wayland_platform_init.cxx - drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx - Fl_Native_File_Chooser_FLTK.cxx - Fl_Native_File_Chooser_GTK.cxx - ) - - list(APPEND DRIVER_FILES - Fl_Native_File_Chooser_Kdialog.cxx - Fl_Native_File_Chooser_Zenity.cxx) - - if(FLTK_USE_X11) - list(APPEND DRIVER_FILES - drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx - drivers/X11/Fl_X11_Screen_Driver.cxx - drivers/X11/Fl_X11_Window_Driver.cxx - drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx - drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx - Fl_x.cxx - fl_dnd_x.cxx - Fl_get_key.cxx - ) - endif(FLTK_USE_X11) - - set(DRIVER_HEADER_FILES - drivers/Posix/Fl_Posix_System_Driver.H - drivers/Wayland/Fl_Wayland_Screen_Driver.H - drivers/Wayland/Fl_Wayland_Window_Driver.H - drivers/Wayland/Fl_Wayland_Graphics_Driver.H - drivers/Cairo/Fl_Cairo_Graphics_Driver.H - drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.H - drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H - drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H - drivers/Unix/Fl_Unix_System_Driver.H - ) - -elseif(APPLE) - - # Apple Quartz - - set(DRIVER_FILES - drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx - drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx - drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx - drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx - drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx - drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx - drivers/Posix/Fl_Posix_System_Driver.cxx - drivers/Darwin/Fl_Darwin_System_Driver.cxx - Fl_get_key_mac.cxx - drivers/Darwin/fl_macOS_platform_init.cxx - ) - set(DRIVER_HEADER_FILES - drivers/Posix/Fl_Posix_System_Driver.H - drivers/Darwin/Fl_Darwin_System_Driver.H - drivers/Cocoa/Fl_Cocoa_Screen_Driver.H - drivers/Cocoa/Fl_Cocoa_Window_Driver.H - drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H - drivers/Quartz/Fl_Quartz_Graphics_Driver.H - drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H - drivers/Quartz/Fl_Font.H - drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H - ) - -else() - - # Windows (GDI) - - set(DRIVER_FILES - drivers/WinAPI/Fl_WinAPI_System_Driver.cxx - drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx - drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx - drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx - drivers/GDI/Fl_GDI_Graphics_Driver.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx - drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx - drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx - drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx - Fl_win32.cxx - fl_dnd_win32.cxx - Fl_Native_File_Chooser_WIN32.cxx - Fl_get_key_win32.cxx - drivers/WinAPI/fl_WinAPI_platform_init.cxx - ) - set(DRIVER_HEADER_FILES - drivers/WinAPI/Fl_WinAPI_System_Driver.H - drivers/WinAPI/Fl_WinAPI_Screen_Driver.H - drivers/WinAPI/Fl_WinAPI_Window_Driver.H - drivers/GDI/Fl_GDI_Graphics_Driver.H - drivers/GDI/Fl_Font.H - drivers/GDI/Fl_GDI_Copy_Surface_Driver.H - drivers/GDI/Fl_GDI_Image_Surface_Driver.H - ) - - # Optional Pen/Tablet Support - - if(FLTK_HAVE_PEN_SUPPORT) - list(APPEND DRIVER_FILES - drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx - ) - endif(FLTK_HAVE_PEN_SUPPORT) - -endif(FLTK_USE_X11 AND NOT FLTK_USE_WAYLAND) - -# Common Pen/Tablet Support Files - -if(FLTK_HAVE_PEN_SUPPORT) - list(APPEND DRIVER_FILES - drivers/Base/Fl_Base_Pen_Events.cxx - ) - list(APPEND DRIVER_HEADER_FILES - drivers/Base/Fl_Base_Pen_Events.H - ) -endif(FLTK_HAVE_PEN_SUPPORT) - -source_group("Header Files" FILES ${HEADER_FILES}) -source_group("Private Header Files" FILES ${PRIVATE_HEADER_FILES}) -source_group("Driver Source Files" FILES ${DRIVER_FILES}) -source_group("Driver Header Files" FILES ${DRIVER_HEADER_FILES}) - -set(CPPFILES - ${CPPFILES} - ${DRIVER_FILES} -) - -if(FLTK_BUILD_FORMS) - set(FORMS_FILES - forms_compatibility.cxx - forms_bitmap.cxx - forms_free.cxx - forms_fselect.cxx - forms_pixmap.cxx - forms_timer.cxx - ) -else() - set(FORMS_FILES "") -endif() - -set(GLCPPFILES - Fl_Gl_Choice.cxx - Fl_Gl_Device_Plugin.cxx - Fl_Gl_Overlay.cxx - Fl_Gl_Window.cxx - freeglut_geometry.cxx - freeglut_stroke_mono_roman.cxx - freeglut_stroke_roman.cxx - freeglut_teapot.cxx - gl_draw.cxx - gl_start.cxx - glut_compatibility.cxx - glut_font.cxx -) - -set(GL_DRIVER_FILES - drivers/OpenGL/Fl_OpenGL_Display_Device.cxx - # the following file doesn't contribute any code: - # drivers/OpenGL/Fl_OpenGL_Graphics_Driver.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx - drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx -) -if(FLTK_USE_WAYLAND) - set(GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx) - set(GL_DRIVER_HEADER_FILES drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H) - if(FLTK_USE_X11) - list(APPEND GL_DRIVER_FILES drivers/X11/Fl_X11_Gl_Window_Driver.cxx) - list(APPEND GL_DRIVER_HEADER_FILES drivers/X11/Fl_X11_Gl_Window_Driver.H) - endif(FLTK_USE_X11) -elseif(FLTK_USE_X11) - set(GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/X11/Fl_X11_Gl_Window_Driver.cxx) - set(GL_DRIVER_HEADER_FILES drivers/X11/Fl_X11_Gl_Window_Driver.H) -elseif(APPLE) - set(GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm) - set(GL_DRIVER_HEADER_FILES drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H) -elseif(WIN32) - set(GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx) - set(GL_DRIVER_HEADER_FILES drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H) -endif(FLTK_USE_WAYLAND) - -set(GL_DRIVER_HEADER_FILES ${GL_DRIVER_FILES} - drivers/OpenGL/Fl_OpenGL_Display_Device.H - drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H -) - -source_group("Driver Header Files" FILES ${GL_DRIVER_HEADER_FILES}) -source_group("Driver Source Files" FILES ${GL_DRIVER_FILES}) - -set(GLCPPFILES - ${GLCPPFILES} - ${GL_DRIVER_FILES} -) - -set(IMGCPPFILES - fl_images_core.cxx - fl_write_png.cxx - Fl_BMP_Image.cxx - Fl_File_Icon2.cxx - Fl_GIF_Image.cxx - Fl_Anim_GIF_Image.cxx - Fl_Help_Dialog.cxx - Fl_ICO_Image.cxx - Fl_JPEG_Image.cxx - Fl_PNG_Image.cxx - Fl_PNM_Image.cxx - Fl_Image_Reader.cxx - Fl_SVG_Image.cxx - nanosvg.cxx - drivers/SVG/Fl_SVG_File_Surface.cxx -) - -set(CFILES - flstring.c - numericsort.c - vsnprintf.c - xutf8/is_right2left.c - xutf8/is_spacing.c - xutf8/case.c -) - -if(FLTK_USE_X11) - list(APPEND CFILES - xutf8/keysym2Ucs.c - scandir_posix.c - ) - if(NOT USE_XFT) - list(APPEND CFILES - xutf8/utf8Utils.c - xutf8/utf8Input.c - ) - if(NOT APPLE) - list(APPEND CFILES xutf8/utf8Wrap.c) - endif(NOT APPLE) - endif(NOT USE_XFT) -endif(FLTK_USE_X11) - -if(FLTK_USE_WAYLAND) - set(IDIRS "${CMAKE_CURRENT_BINARY_DIR}") - set(CDEFS "_GNU_SOURCE;HAVE_MKOSTEMP") - if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_HOST_SYSTEM_NAME} STREQUAL "FreeBSD") - set(CDEFS "${CDEFS};HAVE_MEMFD_CREATE;HAVE_POSIX_FALLOCATE") - endif() - set(COPTS "-fPIC") - if(FLTK_USE_DBUS) - pkg_check_modules(DBUS IMPORTED_TARGET dbus-1) - if(DBUS_FOUND) - set(CDEFS "${CDEFS};HAS_DBUS") - set(IDIRS "${IDIRS};${DBUS_INCLUDE_DIRS}") - endif(DBUS_FOUND) - endif(FLTK_USE_DBUS) - if(USE_SYSTEM_LIBDECOR) - set(CDEFS "${CDEFS};USE_SYSTEM_LIBDECOR;LIBDECOR_PLUGIN_DIR=${LIBDECOR_PLUGIN_DIR}") - if(GTK_FOUND) - set(CDEFS "${CDEFS};HAVE_GTK") - endif(GTK_FOUND) - set_source_files_properties( - ${FLTK_SOURCE_DIR}/libdecor/build/fl_libdecor-plugins.c - ${FLTK_SOURCE_DIR}/libdecor/src/os-compatibility.c - ${FLTK_SOURCE_DIR}/libdecor/src/desktop-settings.c - PROPERTIES COMPILE_DEFINITIONS "${CDEFS}" - INCLUDE_DIRECTORIES "${IDIRS}" - COMPILE_OPTIONS "${COPTS}" - ) - else() - set(IDIRS "${IDIRS};${FLTK_SOURCE_DIR}/libdecor/src" - "${FLTK_SOURCE_DIR}/libdecor/src/plugins") - set(CDEFS "${CDEFS};USE_SYSTEM_LIBDECOR=0;LIBDECOR_PLUGIN_API_VERSION=1" - "LIBDECOR_PLUGIN_DIR=\"\"") - if(GTK_FOUND AND FLTK_USE_LIBDECOR_GTK) - set(CDEFS "${CDEFS};HAVE_GTK") - endif(GTK_FOUND AND FLTK_USE_LIBDECOR_GTK) - set_source_files_properties( - ${FLTK_SOURCE_DIR}/libdecor/build/fl_libdecor.c - ${FLTK_SOURCE_DIR}/libdecor/build/fl_libdecor-plugins.c - ${FLTK_SOURCE_DIR}/libdecor/src/os-compatibility.c - ${FLTK_SOURCE_DIR}/libdecor/src/desktop-settings.c - PROPERTIES - COMPILE_DEFINITIONS "${CDEFS}" - INCLUDE_DIRECTORIES "${IDIRS}" - COMPILE_OPTIONS "${COPTS}" - ) - endif(USE_SYSTEM_LIBDECOR) - set_source_files_properties( - ${FLTK_SOURCE_DIR}/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx - ${FLTK_SOURCE_DIR}/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx - PROPERTIES COMPILE_DEFINITIONS "USE_SYSTEM_LIBDECOR=${USE_SYSTEM_LIBDECOR}" - ) - - list(APPEND CFILES - scandir_posix.c - ../libdecor/src/desktop-settings.c - ../libdecor/src/os-compatibility.c - ../libdecor/build/fl_libdecor-plugins.c - ) - if(FLTK_USE_X11) - list(APPEND CFILES xutf8/keysym2Ucs.c) - endif(FLTK_USE_X11) - if(NOT USE_SYSTEM_LIBDECOR) - list(APPEND CFILES - ../libdecor/build/fl_libdecor.c - ../libdecor/src/plugins/common/libdecor-cairo-blur.c - ) - endif(NOT USE_SYSTEM_LIBDECOR) -endif(FLTK_USE_WAYLAND) - -if(WIN32) - list(APPEND CFILES - scandir_win32.c - ) -endif(WIN32) - -if(APPLE AND NOT FLTK_BACKEND_X11) - set(MMFILES - Fl_cocoa.mm - drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm - Fl_Native_File_Chooser_MAC.mm - Fl_MacOS_Sys_Menu_Bar.mm - ) - if(FLTK_HAVE_PEN_SUPPORT) - list(APPEND MMFILES - drivers/Cocoa/Fl_Cocoa_Pen_Events.mm - ) - endif() - source_group("ObjC Source Files" FILES ${MMFILES}) -else() - set(MMFILES) -endif() - - -####################################################################### - -# prepare source files for shared and static FLTK libraries - -set(SHARED_FILES ${CPPFILES} ${MMFILES} ${CFILES} ${PSFILES}) -list(APPEND SHARED_FILES ${HEADER_FILES} ${PRIVATE_HEADER_FILES} ${DRIVER_HEADER_FILES}) - -set(STATIC_FILES ${SHARED_FILES}) - -# Visual Studio (MSVC) is known to need WinMain() and maybe BORLAND -# needs it as well, hence we include it on all Windows platforms. -# The GNU compilers (MinGW, MSYS2, Cygwin) disable compilation inside -# the source file which is what we finally want and need. - -if(WIN32) - list(APPEND STATIC_FILES fl_call_main.c) -endif() - -####################################################################### -# -# Prepare optional libs for shared and static FLTK libraries. -# -# Notes: -# - 'OPTIONAL_LIBS' is a CMake 'list' but must not contain arbitrary -# CMake targets because these targets would be propagated to -# consumer projects. The macro below simplifies adding link -# libraries of such targets to 'OPTIONAL_LIBS'. -# - 'OPTIONAL_INCLUDES' is a similar CMake list that defines additional -# include directories. -# -# This macro appends link libraries to 'OPTIONAL_LIBS' and include -# directories to 'OPTIONAL_INCLUDES'. -# -# Input: -# 'targets' may be a CMake list of targets or a single target. -# It must be quoted if multiple targets are to be added in -# one call (see examples below). -# -####################################################################### - -set(OPTIONAL_LIBS) -set(OPTIONAL_INCLUDES) - -macro(append_optional_libs targets) - foreach(_target ${targets}) - get_target_property(_link_libraries ${_target} INTERFACE_LINK_LIBRARIES) - if(_link_libraries) - list(APPEND OPTIONAL_LIBS ${_link_libraries}) - endif() - get_target_property(_include_dirs ${_target} INTERFACE_INCLUDE_DIRECTORIES) - if(_include_dirs) - list(APPEND OPTIONAL_INCLUDES ${_include_dirs}) - endif() - endforeach() - unset(_target) - unset(_link_libraries) - unset(_include_dirs) -endmacro() - -# Add the required properties for ${OPTIONAL_LIBS} to the given target. -# Note: we must use 'PUBLIC', see GitHub Issue #1173 - -macro(add_optional_libs target) - target_link_libraries (${target} PUBLIC ${OPTIONAL_LIBS}) - target_include_directories(${target} PUBLIC ${OPTIONAL_INCLUDES}) -endmacro() - -# Build the list of optional libs - -if(LIB_dl) - list(APPEND OPTIONAL_LIBS ${LIB_dl}) -endif(LIB_dl) - -if(USE_THREADS) - list(APPEND OPTIONAL_LIBS ${CMAKE_THREAD_LIBS_INIT}) -endif(USE_THREADS) - -if(FLTK_USE_X11) - list(APPEND OPTIONAL_LIBS ${X11_LIBRARIES}) - list(APPEND OPTIONAL_INCLUDES ${X11_INCLUDE_DIR}) -endif(FLTK_USE_X11) - -if(WIN32) - list(APPEND OPTIONAL_LIBS comctl32 ws2_32) - if(USE_GDIPLUS) - list(APPEND OPTIONAL_LIBS gdiplus) - endif() -endif(WIN32) - -if(HAVE_XINERAMA) - list(APPEND OPTIONAL_LIBS ${X11_Xinerama_LIB}) -endif(HAVE_XINERAMA) - -if(HAVE_XFIXES) - list(APPEND OPTIONAL_LIBS ${X11_Xfixes_LIB}) -endif(HAVE_XFIXES) - -if(HAVE_XCURSOR) - list(APPEND OPTIONAL_LIBS ${X11_Xcursor_LIB}) -endif(HAVE_XCURSOR) - -if(HAVE_XRENDER) - list(APPEND OPTIONAL_LIBS ${X11_Xrender_LIB}) -endif(HAVE_XRENDER) - -if(USE_PANGO) - list(APPEND OPTIONAL_LIBS ${HAVE_LIB_PANGO}) - append_optional_libs(PkgConfig::PANGOCAIRO) - list(APPEND OPTIONAL_LIBS ${HAVE_LIB_GOBJECT}) - if(USE_PANGOXFT) - append_optional_libs(PkgConfig::PANGOXFT) - endif(USE_PANGOXFT) -endif(USE_PANGO) - -if(USE_XFT) - list(APPEND OPTIONAL_LIBS ${X11_Xft_LIB}) - if(LIB_fontconfig) - list(APPEND OPTIONAL_LIBS ${LIB_fontconfig}) - endif(LIB_fontconfig) -endif(USE_XFT) - -if(UNIX AND FLTK_USE_WAYLAND) - pkg_get_variable(PROTOCOLS wayland-protocols pkgdatadir) - # replace "//" with "/" - string(REPLACE "//" "/" PROTOCOLS ${PROTOCOLS}) - - # The following variable is used for finding required files and to terminate - # the build if one or more files are not found. For user convenience - # the build is terminated after *all* files have been checked. - set(STOP_REQUIRED FALSE) - - set(INFILE ${PROTOCOLS}/stable/xdg-shell/xdg-shell.xml) - fl_check_required_file(STOP_REQUIRED ${INFILE}) - add_custom_command( - OUTPUT xdg-shell-protocol.c xdg-shell-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} xdg-shell-protocol.c - COMMAND wayland-scanner client-header ${INFILE} xdg-shell-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "xdg-shell-protocol.c") - list(APPEND SHARED_FILES "xdg-shell-protocol.c") - - if(NOT USE_SYSTEM_LIBDECOR) - set(INFILE ${PROTOCOLS}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml) - fl_check_required_file(STOP_REQUIRED ${INFILE}) - add_custom_command( - OUTPUT xdg-decoration-protocol.c xdg-decoration-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} xdg-decoration-protocol.c - COMMAND wayland-scanner client-header ${INFILE} xdg-decoration-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "xdg-decoration-protocol.c") - list(APPEND SHARED_FILES "xdg-decoration-protocol.c") - endif(NOT USE_SYSTEM_LIBDECOR) - - set(INFILE ${FLTK_SOURCE_DIR}/libdecor/build/gtk-shell.xml) - add_custom_command( - OUTPUT gtk-shell-protocol.c gtk-shell-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} gtk-shell-protocol.c - COMMAND wayland-scanner client-header ${INFILE} gtk-shell-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "gtk-shell-protocol.c") - list(APPEND SHARED_FILES "gtk-shell-protocol.c") - - set(INFILE ${PROTOCOLS}/unstable/text-input/text-input-unstable-v3.xml) - fl_check_required_file(STOP_REQUIRED ${INFILE}) - add_custom_command( - OUTPUT text-input-protocol.c text-input-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} text-input-protocol.c - COMMAND wayland-scanner client-header ${INFILE} text-input-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "text-input-protocol.c") - list(APPEND SHARED_FILES "text-input-protocol.c") - - if(HAVE_XDG_DIALOG) - set(INFILE ${PROTOCOLS}/staging/xdg-dialog/xdg-dialog-v1.xml) - add_custom_command( - OUTPUT xdg-dialog-protocol.c xdg-dialog-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} xdg-dialog-protocol.c - COMMAND wayland-scanner client-header ${INFILE} xdg-dialog-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "xdg-dialog-protocol.c") - list(APPEND SHARED_FILES "xdg-dialog-protocol.c") - endif() - - if(HAVE_CURSOR_SHAPE) - set(INFILE ${PROTOCOLS}/staging/cursor-shape/cursor-shape-v1.xml) - add_custom_command( - OUTPUT cursor-shape-protocol.c cursor-shape-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} cursor-shape-protocol.c - COMMAND wayland-scanner client-header ${INFILE} cursor-shape-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "cursor-shape-protocol.c") - list(APPEND SHARED_FILES "cursor-shape-protocol.c") -# File cursor-shape-protocol.c requires memory data allocated by the "Tablet" protocol -# but that protocol's header file is not necessary for the "cursor shape" protocol itself. - set(INFILE ${PROTOCOLS}/stable/tablet/tablet-v2.xml) - add_custom_command( - OUTPUT tablet-protocol.c # tablet-client-protocol.h - COMMAND wayland-scanner private-code ${INFILE} tablet-protocol.c -# COMMAND wayland-scanner client-header ${INFILE} tablet-client-protocol.h - DEPENDS ${INFILE} - VERBATIM - ) - list(APPEND STATIC_FILES "tablet-protocol.c") - list(APPEND SHARED_FILES "tablet-protocol.c") - endif() - - if(STOP_REQUIRED) - message(FATAL_ERROR "*** Terminating: one or more required file(s) were not found. ***") - endif() - - if(FLTK_USE_GL) - append_optional_libs("PkgConfig::WLD_EGL;PkgConfig::PKG_EGL") - endif(FLTK_USE_GL) - - if(USE_SYSTEM_LIBDECOR) - append_optional_libs(PkgConfig::SYSTEM_LIBDECOR) - elseif(GTK_FOUND AND FLTK_USE_LIBDECOR_GTK) - append_optional_libs(PkgConfig::GTK) - endif() - - append_optional_libs("PkgConfig::WLDCURSOR;PkgConfig::WLDCLIENT;PkgConfig::XKBCOMMON") - - if(FLTK_USE_DBUS AND DBUS_FOUND) - append_optional_libs(PkgConfig::DBUS) - endif() - -endif(UNIX AND FLTK_USE_WAYLAND) - -list(REMOVE_DUPLICATES OPTIONAL_LIBS) -list(REMOVE_DUPLICATES OPTIONAL_INCLUDES) - -####################################################################### - -fl_add_library(fltk STATIC "${STATIC_FILES}") -add_optional_libs(fltk) - -####################################################################### - -if(FLTK_BUILD_FORMS) - fl_add_library(fltk_forms STATIC "${FORMS_FILES}") - target_link_libraries(fltk_forms PUBLIC fltk::fltk) -endif() - -####################################################################### - -if(0) - message(STATUS "---------------------- fltk_images -----------------------") - fl_debug_var(FLTK_JPEG_LIBRARIES) - fl_debug_var(FLTK_PNG_LIBRARIES) - fl_debug_var(FLTK_ZLIB_LIBRARIES) - fl_debug_var(FLTK_IMAGE_LIBRARIES) - message(STATUS "---------------------- fltk_images -----------------------") -endif() - -fl_add_library(fltk_images STATIC "${IMGCPPFILES}") -target_link_libraries(fltk_images PUBLIC fltk::fltk) -target_link_libraries(fltk_images PRIVATE ${FLTK_IMAGE_LIBRARIES}) - -if(FLTK_USE_BUNDLED_JPEG) - target_include_directories(fltk_images PUBLIC - $<BUILD_INTERFACE:${FLTK_SOURCE_DIR}/jpeg> - $<INSTALL_INTERFACE:include/FL/images>) -endif() - -if(FLTK_USE_BUNDLED_PNG) - target_include_directories(fltk_images PUBLIC - $<BUILD_INTERFACE:${FLTK_SOURCE_DIR}/png> - $<INSTALL_INTERFACE:include/FL/images>) -endif() - -if(FLTK_USE_BUNDLED_ZLIB) - target_include_directories(fltk_images PUBLIC - $<BUILD_INTERFACE:${FLTK_SOURCE_DIR}/zlib> - $<INSTALL_INTERFACE:include/FL/images>) -endif() - -####################################################################### - -if(FLTK_USE_GL) - fl_add_library(fltk_gl STATIC "${GLCPPFILES};${GL_HEADER_FILES};${GL_DRIVER_HEADER_FILES}") - target_link_libraries(fltk_gl PUBLIC ${OPENGL_LIBRARIES} fltk::fltk) - target_include_directories(fltk_gl PUBLIC ${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIRS}) - - # Add "optional libs" (FIXME: this can be optimized, we don't need *all* these libs here) - add_optional_libs(fltk_gl) - - if(FLTK_OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk_gl PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) - endif() -endif(FLTK_USE_GL) - -####################################################################### -# Build shared libraries (optional) -####################################################################### -# Shared libraries, part 1: everything except Visual Studio (MSVC) -####################################################################### - -if(FLTK_BUILD_SHARED_LIBS AND NOT MSVC) - - fl_add_library(fltk SHARED "${SHARED_FILES}") - add_optional_libs(fltk-shared) - - ################################################################### - - if(FLTK_BUILD_FORMS) - fl_add_library(fltk_forms SHARED "${FORMS_FILES}") - target_link_libraries(fltk_forms-shared PUBLIC fltk::fltk-shared) - endif() - - ################################################################### - - fl_add_library(fltk_images SHARED "${IMGCPPFILES}") - target_link_libraries(fltk_images-shared PUBLIC fltk::fltk-shared) - - target_link_libraries(fltk_images PUBLIC ${FLTK_JPEG_LIBRARIES}) - target_link_libraries(fltk_images PUBLIC ${FLTK_PNG_LIBRARIES}) - target_link_libraries(fltk_images PUBLIC ${FLTK_IMAGE_LIBRARIES}) - - if(FLTK_USE_BUNDLED_JPEG) - target_include_directories(fltk_images-shared PUBLIC - $<BUILD_INTERFACE:${FLTK_SOURCE_DIR}/jpeg> - # $<INSTALL_INTERFACE:include> - ) - endif() - - if(FLTK_USE_BUNDLED_JPEG) - target_link_libraries(fltk_images-shared PUBLIC fltk::jpeg-shared) - else() - target_link_libraries(fltk_images-shared PUBLIC ${JPEG_LIBRARIES}) - endif() - - if(FLTK_USE_BUNDLED_PNG) - target_link_libraries(fltk_images-shared PUBLIC fltk::png-shared) - else() - target_link_libraries(fltk_images-shared PUBLIC ${PNG_LIBRARIES}) - endif() - - ################################################################### - - if(FLTK_USE_GL) - fl_add_library(fltk_gl SHARED "${GLCPPFILES};${GL_HEADER_FILES};${GL_DRIVER_HEADER_FILES}") - target_link_libraries(fltk_gl-shared PUBLIC ${OPENGL_LIBRARIES} fltk::fltk-shared) - target_include_directories(fltk_gl-shared PUBLIC ${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIRS}) - - # Add "optional libs" (FIXME: this can be optimized, we don't need *all* these libs here) - add_optional_libs(fltk_gl-shared) - - if(FLTK_OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk_gl-shared PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) - endif() - endif(FLTK_USE_GL) - -endif(FLTK_BUILD_SHARED_LIBS AND NOT MSVC) - -####################################################################### -# Shared libraries, part 2: Visual Studio (MSVC) -####################################################################### - -# Note to devs: As of June 2020 we can't build separate shared libs -# (DLL's) under Windows with Visual Studio (MSVC) but we can build one -# big DLL that comprises all FLTK and optional PNG, JPEG, and ZLIB libs. -# The reason is the common DLL linkage (FL_EXPORT) for all libs. This -# might be changed in the future but it would require a lot of work. -# AlbrechtS - -if(FLTK_BUILD_SHARED_LIBS AND MSVC) - - set(SOURCES ${SHARED_FILES} ${FORMS_FILES} ${IMGCPPFILES}) - if(OPENGL_FOUND) - list(APPEND SOURCES ${GLCPPFILES} ${GL_HEADER_FILES} ${GL_DRIVER_HEADER_FILES}) - endif(OPENGL_FOUND) - - fl_add_library(fltk SHARED "${SOURCES}") - add_optional_libs(fltk-shared) - - if(FLTK_USE_BUNDLED_JPEG) - target_link_libraries(fltk-shared PUBLIC fltk::jpeg-shared) - else() - target_link_libraries(fltk-shared PUBLIC ${FLTK_JPEG_LIBRARIES}) - endif() - - if(FLTK_USE_BUNDLED_PNG) - target_link_libraries(fltk-shared PUBLIC fltk::png-shared) - else() - target_link_libraries(fltk-shared PUBLIC ${FLTK_PNG_LIBRARIES}) - endif() - - if(OPENGL_FOUND) - target_link_libraries(fltk-shared PUBLIC ${OPENGL_LIBRARIES}) - target_include_directories(fltk-shared PUBLIC ${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIRS}) - if(FLTK_OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk-shared PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) - endif() - endif(OPENGL_FOUND) - -endif(FLTK_BUILD_SHARED_LIBS AND MSVC) - -####################################################################### - -set(FLTK_LIBRARIES ${FLTK_LIBRARIES} PARENT_SCOPE) -set(FLTK_LIBRARIES_SHARED ${FLTK_LIBRARIES_SHARED} PARENT_SCOPE) diff --git a/src/Fl.cxx b/src/Fl.cxx index 399d8249b..07e107b1d 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -2572,73 +2572,16 @@ FL_EXPORT const char* fl_local_alt = Fl::system_driver()->alt_name(); FL_EXPORT const char* fl_local_ctrl = Fl::system_driver()->control_name(); /** - Convert Windows commandline arguments to UTF-8. - - \note This function does nothing on other (non-Windows) platforms, hence - you may call it on all platforms or only on Windows by using platform - specific code like <tt>'\#ifdef _WIN32'</tt> etc. - it's your choice. - Calling it on other platforms returns quickly w/o wasting much CPU time. - - This function <i>must be called <b>on Windows platforms</b></i> in \c main() - before the array \c argv is used if your program uses any commandline - argument strings (these should be UTF-8 encoded). - This applies also to standard FLTK commandline arguments like - "-name" (class name) and "-title" (window title in the title bar). - - Unfortunately Windows \b neither provides commandline arguments in UTF-8 - encoding \b nor as Windows "Wide Character" strings in the standard - \c main() and/or the Windows specific \c WinMain() function. - - On Windows platforms (no matter which build system) this function calls - a Windows specific function to retrieve commandline arguments as Windows - "Wide Character" strings, converts these strings to an internally allocated - buffer (or multiple buffers) and returns the result in \c argv. - For implementation details please refer to the source code; however these - details may be changed in the future. - - Note that \c argv is provided by reference so it can be overwritten. - - In the recommended simple form the function overwrites the variable - \c argv and allocates a new array of strings pointed to by \c argv. - You may use this form on all platforms and it is as simple as adding - one line to old programs to make them work with international (UTF-8) - commandline arguments. + Ensure commandline arguments are UTF-8 encoded. - \code - int main(int argc, char **argv) { - Fl::args_to_utf8(argc, argv); // add this line - // ... use argc and argv, e.g. for commandline parsing - window->show(argc, argv); - return Fl::run(); - } - \endcode - - For an example see 'examples/howto-parse-args.cxx' in the FLTK sources. - - If you want to retain the original \c argc and \c argv variables the - following slightly longer and more complicated code works as well on - all platforms. + On X11 this is a no-op since arguments are already in the locale encoding + which is typically UTF-8 on modern systems. - \code - int main(int argc, char **argv) { - char **argvn = argv; // must copy argv to work on all platforms - int argcn = Fl::args_to_utf8(argc, argvn); - // ... use argcn and argvn, e.g. for commandline parsing - window->show(argcn, argvn); - return Fl::run(); - } - \endcode - - \param[in] argc used only on non-Windows platforms - \param[out] argv modified only on Windows platforms + \param[in] argc argument count + \param[out] argv argument array \returns argument count (always the same as argc) \since 1.4.0 - - \internal This function must not open the display, otherwise - commandline processing (e.g. by fluid) would open the display. - OTOH calling it when the display is opened wouldn't work either - for the same reasons ('fluid -c' doesn't open the display). */ int Fl::args_to_utf8(int argc, char ** &argv) { return Fl::system_driver()->args_to_utf8(argc, argv); diff --git a/src/Fl_Cairo.cxx b/src/Fl_Cairo.cxx index 1b830c045..20cb08b56 100644 --- a/src/Fl_Cairo.cxx +++ b/src/Fl_Cairo.cxx @@ -27,37 +27,9 @@ #ifdef FLTK_HAVE_CAIRO -// Define USE_MAC_OS for convenience (below). We use macOS specific features -// if USE_MAC_OS is defined, otherwise we're using X11 (XQuartz) on macOS - -#if defined __APPLE__ && !defined(FLTK_USE_X11) -#define USE_MAC_OS -#include <ApplicationServices/ApplicationServices.h> -#endif - #include <FL/platform.H> #include <FL/Fl_Window.H> - -// Cairo is currently supported for the following platforms: -// Windows, macOS (Apple Quartz), X11, Wayland - -#if defined(_WIN32) // Windows -# include <cairo-win32.h> -#elif defined(FLTK_USE_WAYLAND) // Wayland or hybrid -# include "../src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H" -# include "../src/drivers/Wayland/Fl_Wayland_Window_Driver.H" -# if defined(FLTK_USE_X11) -# include <cairo-xlib.h> -# else - static void *fl_gc = NULL; -# endif -#elif defined(FLTK_USE_X11) // X11 -# include <cairo-xlib.h> -#elif defined(__APPLE__) // macOS -# include <cairo-quartz.h> -#else -# error Cairo is not supported on this platform. -#endif +#include <cairo-xlib.h> // static initialization @@ -140,24 +112,13 @@ void Fl_Cairo_State::autolink(bool b) { \note Only available when CMake option '-D FLTK_OPTION_CAIRO_WINDOW' is set. \return The valid cairo_t *cairo context associated to this window. - \retval NULL if \a wi is NULL or maybe with GL windows under Wayland + \retval NULL if \a wi is NULL */ cairo_t *Fl::cairo_make_current(Fl_Window *wi) { if (!wi) return NULL; cairo_t *cairo_ctxt; -#if defined(FLTK_USE_WAYLAND) - if (fl_wl_display()) { // true means using wayland backend - struct wld_window *xid = fl_wl_xid(wi); - if (!xid || !xid->buffer) - return NULL; // this may happen with GL windows or if window is not shown - cairo_ctxt = xid->buffer->draw_buffer.cairo_; - Fl::Private::cairo_state_.cc(cairo_ctxt, false); - return cairo_ctxt; - } -#endif - if (fl_gc == 0) { // means remove current cc Fl::cairo_cc(0); // destroy any previous cc Fl::Private::cairo_state_.window(0); @@ -168,93 +129,23 @@ cairo_t *Fl::cairo_make_current(Fl_Window *wi) { if (fl_gc == Fl::Private::cairo_state_.gc() && fl_xid(wi) == (Window)Fl::Private::cairo_state_.window()) return Fl::cairo_cc(); - // Scale the Cairo context appropriately. This is platform dependent - -#if !defined(USE_MAC_OS) - float scale = Fl::screen_scale(wi->screen_num()); // get the screen scaling factor -#endif - -#if defined(FLTK_USE_X11) + // Scale the Cairo context appropriately + float scale = Fl::screen_scale(wi->screen_num()); cairo_ctxt = Fl::Private::cairo_make_current(0, wi->w() * scale, wi->h() * scale); -#else - // on macOS, scaling is done before by Fl_Window::make_current(), on Windows, the size is not used - cairo_ctxt = Fl::Private::cairo_make_current(fl_gc, wi->w(), wi->h()); -#endif - Fl::Private::cairo_state_.window((void *)fl_xid(wi)); - -#if !defined(USE_MAC_OS) cairo_scale(cairo_ctxt, scale, scale); -#endif return cairo_ctxt; } /* - Creates transparently a cairo_surface_t object. - gc is an HDC context in Windows, a CGContext* in Quartz, and - a display on X11 (not used on this platform) + Creates a cairo_surface_t object using X11/Xlib. */ static cairo_surface_t *cairo_create_surface(void *gc, int W, int H) { -#if defined(FLTK_USE_X11) return cairo_xlib_surface_create(fl_display, fl_window, fl_visual->visual, W, H); -#elif defined(FLTK_USE_WAYLAND) - return NULL; -#elif defined(_WIN32) - return cairo_win32_surface_create((HDC)gc); -#elif defined(__APPLE__) - return cairo_quartz_surface_create_for_cg_context((CGContextRef)gc, W, H); -#else -#error Cairo is not supported on this platform. -#endif } -#if 0 // this non-public function appears not to be used anywhere in FLTK -/** - Creates a Cairo context from a \a gc only, gets its window size or - offscreen size if fl_window is null. - - \note Only available if CMake FLTK_OPTION_CAIRO_WINDOW is enabled. -*/ -cairo_t *Fl::Private::cairo_make_current(void *gc) { - int W = 0, H = 0; -#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) - // FIXME X11 get W,H - // gc will be the window handle here - // # warning FIXME get W,H for cairo_make_current(void*) -#elif defined(__APPLE__) - if (fl_window) { - W = Fl_Window::current()->w(); - H = Fl_Window::current()->h(); - } else { - W = CGBitmapContextGetWidth(fl_gc); - H = CGBitmapContextGetHeight(fl_gc); - } -#elif defined(_WIN32) - // we don't need any W,H for Windows -#else -#error Cairo is not supported on this platform. -#endif - - if (!gc) { - Fl::cairo_cc(0); - cairo_state_.gc(0); // keep track for next time - return 0; - } - if (gc == Fl::Private::cairo_state_.gc() && - fl_window == (Window)Fl::Private::cairo_state_.window() && - cairo_state_.cc() != 0) - return Fl::cairo_cc(); - cairo_state_.gc(fl_gc); // keep track for next time - cairo_surface_t *s = cairo_create_surface(gc, W, H); - cairo_t *c = cairo_create(s); - cairo_surface_destroy(s); - cairo_state_.cc(c); - return c; -} -#endif - /** Creates a Cairo context from a \p gc and the given size. @@ -269,29 +160,14 @@ cairo_t *Fl::Private::cairo_make_current(void *gc, int W, int H) { // we need to (re-)create a fresh cc ... cairo_state_.gc(gc); // keep track for next time cairo_surface_t *s = cairo_create_surface(gc, W, H); - -#if defined(USE_MAC_OS) && defined(FLTK_HAVE_CAIROEXT) - CGAffineTransform at = CGContextGetCTM((CGContextRef)gc); - CGContextSaveGState((CGContextRef)gc); - CGContextConcatCTM((CGContextRef)gc, CGAffineTransformInvert(at)); -#endif - cairo_t *c = cairo_create(s); - -#if defined(USE_MAC_OS) && defined(FLTK_HAVE_CAIROEXT) - CGContextRestoreGState((CGContextRef)gc); -#endif - cairo_state_.cc(c); // and purge any previously owned context cairo_surface_destroy(s); return c; } /** Flush Cairo drawings on Cairo context \p c. - This is \b required on Windows if you use the Cairo context provided - by the "Cairo autolink" option. Call this when all your drawings on - the Cairo context are finished. This is maybe not necessary on other - platforms than Windows but it does no harm if you call it always. + Call this when all your drawings on the Cairo context are finished. You don't need to use this if you use an Fl_Cairo_Window which does this automatically after the draw callback returns. @@ -321,7 +197,7 @@ cairo_t *Fl::Private::cairo_make_current(void *gc, int W, int H) { \see Fl::cairo_make_current(Fl_Window*); */ FL_EXPORT extern void Fl::cairo_flush(cairo_t *c) { - // flush Cairo drawings: necessary at least for Windows + // flush Cairo drawings cairo_surface_t *s = cairo_get_target(c); cairo_surface_flush(s); } diff --git a/src/Fl_MacOS_Sys_Menu_Bar.mm b/src/Fl_MacOS_Sys_Menu_Bar.mm deleted file mode 100644 index f41db31b4..000000000 --- a/src/Fl_MacOS_Sys_Menu_Bar.mm +++ /dev/null @@ -1,785 +0,0 @@ -// -// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#if defined(__APPLE__) - -#include <FL/platform.H> -#include <FL/fl_string_functions.h> -#include "drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H" -#include "flstring.h" -#include <stdio.h> -#include <ctype.h> -#include <stdarg.h> -#include "Fl_System_Driver.H" - -#import <Cocoa/Cocoa.h> // keep this after include of Fl_MacOS_Sys_Menu_Bar_Driver.H because of check() conflict - -typedef const Fl_Menu_Item *pFl_Menu_Item; - -static Fl_Menu_Bar *custom_menu; -static NSString *localized_Window = nil; - -static char *remove_ampersand(const char *s); -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 -static void previous_tab_cb(Fl_Widget *, void *data); -static void next_tab_cb(Fl_Widget *, void *data); -static void move_tab_cb(Fl_Widget *, void *data); -static void merge_all_windows_cb(Fl_Widget *, void *data); -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 -const NSInteger NSControlStateValueOn = NSOnState; -const NSInteger NSControlStateValueOff = NSOffState; -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -const NSUInteger NSEventModifierFlagCommand = NSCommandKeyMask; -const NSUInteger NSEventModifierFlagOption = NSAlternateKeyMask; -const NSUInteger NSEventModifierFlagControl = NSControlKeyMask; -const NSUInteger NSEventModifierFlagShift = NSShiftKeyMask; -#endif - -void Fl_MacOS_Sys_Menu_Bar_Driver::draw() { - bar->deactivate(); // prevent Fl_Sys_Menu_Bar object from receiving events -} - -Fl_MacOS_Sys_Menu_Bar_Driver* Fl_MacOS_Sys_Menu_Bar_Driver::driver() { - static Fl_MacOS_Sys_Menu_Bar_Driver *once = new Fl_MacOS_Sys_Menu_Bar_Driver(); - if (driver_ != once) { - if (driver_) { - once->bar = driver_->bar; - delete driver_; - } - driver_ = once; - if (driver_->bar) driver_->update(); - } - return once; -} - -/* Class FLMenuItem, derived from NSMenuItem, associates any item of the macOS system menu - with a corresponding Fl_Menu_Item as follows: - - if the system item's tag is >= 0, fl_sys_menu_bar->menu() + tag is the address - of the relevant Fl_Menu_Item; - - otherwise, the system item's representedObject is the Fl_Menu_Item's address. - This allows the MacOS system menu to use the same Fl_Menu_Item's as those used by FLTK menus, - the address of which can be relocated by the FLTK menu logic. - The "representedObject" is used for non-relocatable Fl_Menu_Item's associated to FL_SUBMENU_POINTER. - Sending the getFlItem message to a macOS system menu item (of class FLMenuItem) returns the address - of the relevant Fl_Menu_Item. -*/ - -// Apple App Menu -const char *Fl_Mac_App_Menu::about = "About %@"; -const char *Fl_Mac_App_Menu::print = "Print Front Window & Titlebar"; -const char *Fl_Mac_App_Menu::print_no_titlebar = "Print Front Window"; -const char *Fl_Mac_App_Menu::toggle_print_titlebar = "Toggle printing of titlebar"; -const char *Fl_Mac_App_Menu::services = "Services"; -const char *Fl_Mac_App_Menu::hide = "Hide %@"; -const char *Fl_Mac_App_Menu::hide_others = "Hide Others"; -const char *Fl_Mac_App_Menu::show = "Show All"; -const char *Fl_Mac_App_Menu::quit = "Quit %@"; - - -@interface FLMenuItem : NSMenuItem { -} -- (const Fl_Menu_Item*) getFlItem; -- (void) itemCallback:(Fl_Menu_*)menu; -- (void) doCallback; -- (void) customCallback; -- (void) directCallback; -- (void) setKeyEquivalentModifierMask:(int)value; -- (void) setFltkShortcut:(int)key; -+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu action:(SEL)selector; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 -- (BOOL)validateMenuItem:(NSMenuItem *)item; -#endif -@end - -@implementation FLMenuItem -- (const Fl_Menu_Item*) getFlItem -// returns the Fl_Menu_Item corresponding to this system menu item -{ - NSInteger tag = [self tag]; - if (tag >= 0) return fl_sys_menu_bar->menu() + tag; - return *(const Fl_Menu_Item**)[(NSData*)[self representedObject] bytes]; -} -- (void) itemCallback:(Fl_Menu_*)menu -{ - const Fl_Menu_Item *item = [self getFlItem]; - menu->picked(item); - Fl::flush(); - if ( item->flags & FL_MENU_TOGGLE ) { // update the menu toggle symbol - [self setState:(item->value() ? NSControlStateValueOn : NSControlStateValueOff)]; - } - else if ( item->flags & FL_MENU_RADIO ) { // update the menu radio symbols - NSMenu* this_menu = [self menu]; - NSInteger flRank = [this_menu indexOfItem:self]; - NSInteger last = [this_menu numberOfItems] - 1; - int from = (int)flRank; - while(from > 0) { - if ([[this_menu itemAtIndex:from-1] isSeparatorItem]) break; - item = [(FLMenuItem*)[this_menu itemAtIndex:from-1] getFlItem]; - if ( !(item->flags & FL_MENU_RADIO) ) break; - from--; - } - int to = (int)flRank; - while (to < last) { - if ([[this_menu itemAtIndex:to+1] isSeparatorItem]) break; - item = [(FLMenuItem*)[this_menu itemAtIndex:to+1] getFlItem]; - if (!(item->flags & FL_MENU_RADIO)) break; - to++; - } - for(int i = from; i <= to; i++) { - NSMenuItem *nsitem = [this_menu itemAtIndex:i]; - [nsitem setState:(nsitem != self ? NSControlStateValueOff : NSControlStateValueOn)]; - } - } -} -- (void) doCallback -{ - fl_lock_function(); - [self itemCallback:fl_sys_menu_bar]; - fl_unlock_function(); -} -- (void) customCallback -{ - fl_lock_function(); - [self itemCallback:custom_menu]; - fl_unlock_function(); -} -- (void) directCallback -{ - fl_lock_function(); - Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes]; - if ( item && item->callback() ) item->do_callback(NULL, FL_REASON_SELECTED); - fl_unlock_function(); -} -- (void) setKeyEquivalentModifierMask:(int)value -{ - NSUInteger macMod = 0; - if ( value & FL_META ) macMod = NSEventModifierFlagCommand; - if ( value & FL_SHIFT || (value > 0 && value < 127 && isupper(value)) ) macMod |= NSEventModifierFlagShift; - if ( value & FL_ALT ) macMod |= NSEventModifierFlagOption; - if ( value & FL_CTRL ) macMod |= NSEventModifierFlagControl; - [super setKeyEquivalentModifierMask:macMod]; -} -- (void) setFltkShortcut:(int)key -{ - // Separate key and modifier - int mod = key; - mod &= ~FL_KEY_MASK; // modifier(s) - key &= FL_KEY_MASK; // key - unichar mac_key = (unichar)key; - if ( (key >= (FL_F+1)) && (key <= FL_F_Last) ) { // Handle function keys - int fkey_num = (key - FL_F); // 1,2.. - mac_key = NSF1FunctionKey + fkey_num - 1; - } else if (key == FL_Escape) { - mac_key = 27; - } else if (key == FL_Tab) { - mac_key = NSTabCharacter; - } else if (key == FL_Enter) { - mac_key = 0x0d; - } else if (key == FL_BackSpace) { - mac_key = NSBackspaceCharacter; - } else if (key == FL_Delete) { - mac_key = NSDeleteCharacter; - } else if (key == FL_Up) { - mac_key = NSUpArrowFunctionKey; - } else if (key == FL_Down) { - mac_key = NSDownArrowFunctionKey; - } else if (key == FL_Left) { - mac_key = NSLeftArrowFunctionKey; - } else if (key == FL_Right) { - mac_key = NSRightArrowFunctionKey; - } else if (key == FL_Page_Up) { - mac_key = NSPageUpFunctionKey; - } else if (key == FL_Page_Down) { - mac_key = NSPageDownFunctionKey; - } else if (key == FL_KP_Enter) { - mac_key = 0x2324; // "⌤" U+2324 - } else if (key == FL_Home) { - mac_key = NSHomeFunctionKey; - } else if (key == FL_End) { - mac_key = NSEndFunctionKey; - } - [self setKeyEquivalent:[NSString stringWithCharacters:&mac_key length:1]]; - [self setKeyEquivalentModifierMask:mod]; -} -+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu action:(SEL)selector -{ - char *name = remove_ampersand(mitem->label()); - NSString *title = NSLocalizedString([NSString stringWithUTF8String:name], nil); - free(name); - FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:title - action:selector - keyEquivalent:@""]; - if (mitem->labelfont() & FL_BOLD) { - NSFont *boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]; - NSAttributedString *attributed = - [ [ [NSAttributedString alloc] initWithString:title - attributes:@{ NSFontAttributeName: boldFont }] - autorelease]; - item.attributedTitle = attributed; - } - // >= 0 if mitem is in the menu items of fl_sys_menu_bar, -1 if not - NSInteger index = (fl_sys_menu_bar ? fl_sys_menu_bar->find_index(mitem) : -1); - [item setTag:index]; - if (index < 0) { - NSData *pointer = [[NSData alloc] initWithBytes:&mitem length:sizeof(Fl_Menu_Item*)]; - [item setRepresentedObject:pointer]; - [pointer release];//pointer will dealloc each time item dealloc's - } - [menu addItem:item]; - [item setTarget:item]; - int retval = (int)[menu indexOfItem:item]; - [item release]; - return retval; -} - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 -- (BOOL)validateMenuItem:(NSMenuItem *)item { - // return YES for all but items of the Window menu - if (fl_mac_os_version < 101200 || - Fl_Sys_Menu_Bar::window_menu_style() <= Fl_Sys_Menu_Bar::tabbing_mode_none || - [item hasSubmenu]) return YES; - NSString *title = [[item parentItem] title]; // 10.6 - if (!title || !localized_Window || [title compare:localized_Window] != NSOrderedSame) return YES; - const Fl_Menu_Item *flitem = [(FLMenuItem*)item getFlItem]; - Fl_Callback *item_cb = flitem->callback(); - if (item_cb == previous_tab_cb || item_cb == next_tab_cb || item_cb == move_tab_cb) { - // is the current window tabbed? - Fl_Window *win = Fl::first_window(); - NSWindow *main = win ? (NSWindow*)fl_xid(win) : nil; - return (main && [main tabbedWindows] != nil); - } else if (item_cb == merge_all_windows_cb) { - // is there any untabbed, tabbable window? - int total = 0, untabbed = 0; - while ((++flitem)->label()) { - total++; - NSWindow *nsw = (NSWindow*)fl_xid( (Fl_Window*)flitem->user_data() ); - if (![nsw tabbedWindows] && [nsw tabbingMode] != NSWindowTabbingModeDisallowed) { - untabbed++; - } - } - return (untabbed > 0 && total >= 2); - } - return YES; -} -#endif -@end - - -void Fl_MacOS_Sys_Menu_Bar_Driver::about( Fl_Callback *cb, void *user_data) -{ - Fl_Menu_Item aboutItem; - memset(&aboutItem, 0, sizeof(Fl_Menu_Item)); - aboutItem.callback(cb); - aboutItem.user_data(user_data); - NSMenu *appleMenu = [[[NSApp mainMenu] itemAtIndex:0] submenu]; - CFStringRef cfname = CFStringCreateCopy(NULL, (CFStringRef)[[appleMenu itemAtIndex:0] title]); - [appleMenu removeItemAtIndex:0]; - FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname - action:@selector(directCallback) - keyEquivalent:@""] autorelease]; - NSData *pointer = [NSData dataWithBytes:&aboutItem length:sizeof(Fl_Menu_Item)]; - [item setRepresentedObject:pointer]; - [appleMenu insertItem:item atIndex:0]; - CFRelease(cfname); - [item setTarget:item]; -} - -/* - * Set a shortcut for an Apple menu item using the FLTK shortcut descriptor. - */ -static void setMenuShortcut( NSMenu* mh, int miCnt, const Fl_Menu_Item *m ) -{ - if ( !m->shortcut_ ) - return; - if ( m->flags & FL_SUBMENU ) - return; - if ( m->flags & FL_SUBMENU_POINTER ) - return; - FLMenuItem* menuItem = (FLMenuItem*)[mh itemAtIndex:miCnt]; - [menuItem setFltkShortcut:(m->shortcut_)]; -} - - -/* - * Set the Toggle and Radio flag based on FLTK flags - */ -static void setMenuFlags( NSMenu* mh, int miCnt, const Fl_Menu_Item *m ) -{ - if ( m->flags & FL_MENU_TOGGLE ) - { - NSMenuItem *menuItem = [mh itemAtIndex:miCnt]; - [menuItem setState:(m->flags & FL_MENU_VALUE ? NSControlStateValueOn : NSControlStateValueOff)]; - } - else if ( m->flags & FL_MENU_RADIO ) { - NSMenuItem *menuItem = [mh itemAtIndex:miCnt]; - [menuItem setState:(m->flags & FL_MENU_VALUE ? NSControlStateValueOn : NSControlStateValueOff)]; - } -} - -static char *remove_ampersand(const char *s) -{ - char *ret = fl_strdup(s); - const char *p = s; - char *q = ret; - while(*p != 0) { - if (p[0]=='&') { - if (p[1]=='&') { - *q++ = '&'; p+=2; - } else { - p++; - } - } else { - *q++ = *p++; - } - } - *q = 0; - return ret; -} - - -/* - * create a sub menu for a specific menu handle - */ -static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *mitem, SEL selector) -{ - NSMenu *submenu; - int miCnt, flags; - - if (mitem) { - NSMenuItem *menuItem; - char *ts = remove_ampersand(mitem->text); - NSString *title = NSLocalizedString([NSString stringWithUTF8String:ts], nil); - free(ts); - submenu = [[NSMenu alloc] initWithTitle:(NSString*)title]; - [submenu setAutoenablesItems:NO]; - - int cnt; - cnt = (int)[mh numberOfItems]; - cnt--; - menuItem = [mh itemAtIndex:cnt]; - if (mitem->labelfont() & FL_BOLD) { - NSFont *boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]; - NSAttributedString *attributed = - [ [ [NSAttributedString alloc] initWithString:title - attributes:@{ NSFontAttributeName: boldFont }] - autorelease]; - menuItem.attributedTitle = attributed; - } - [menuItem setSubmenu:submenu]; - [submenu release]; - } else submenu = mh; - - while ( mm->text ) { - if (!mm->visible() ) { // skip invisible items and submenus - mm = mm->next(0); - continue; - } - miCnt = [FLMenuItem addNewItem:mm menu:submenu - action:( (mm->flags & (FL_SUBMENU+FL_SUBMENU_POINTER) && !mm->callback()) ? nil : selector) - ]; - setMenuFlags( submenu, miCnt, mm ); - setMenuShortcut( submenu, miCnt, mm ); - if (mitem && (mm->flags & FL_MENU_INACTIVE || mitem->flags & FL_MENU_INACTIVE)) { - NSMenuItem *item = [submenu itemAtIndex:miCnt]; - [item setEnabled:NO]; - } - flags = mm->flags; - if ( mm->flags & FL_SUBMENU ) - { - mm++; - createSubMenu( submenu, mm, mm - 1, selector); - } - else if ( mm->flags & FL_SUBMENU_POINTER ) - { - const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_; - createSubMenu( submenu, smm, mm, selector); - } - if ( flags & FL_MENU_DIVIDER ) { - [submenu addItem:[NSMenuItem separatorItem]]; - } - mm++; - } -} - - -/* - * convert a complete Fl_Menu_Item array into a series of menus in the top menu bar - * ALL PREVIOUS SYSTEM MENUS, EXCEPT THE APPLICATION MENU, ARE REPLACED BY THE NEW DATA - */ -static void convertToMenuBar(const Fl_Menu_Item *mm) -{ - NSMenu *fl_system_menu = [NSApp mainMenu]; - int count;//first, delete all existing system menus - count = (int)[fl_system_menu numberOfItems]; - for(int i = count - 1; i > 0; i--) { - [fl_system_menu removeItem:[fl_system_menu itemAtIndex:i]]; - } - if (mm) createSubMenu(fl_system_menu, mm, NULL, @selector(doCallback)); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (localized_Window) { - NSMenuItem *item = [fl_system_menu itemWithTitle:localized_Window]; - if (item) [[item submenu] setAutoenablesItems:YES]; - } -#endif -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::update() -{ - convertToMenuBar(bar->Fl_Menu_::menu()); -} - - -static int process_sys_menu_shortcuts(int event) -{ - if (event != FL_SHORTCUT || !fl_sys_menu_bar || Fl::modal()) return 0; - // is the last event the shortcut of an item of the fl_sys_menu_bar menu ? - const Fl_Menu_Item *item = fl_sys_menu_bar->menu()->test_shortcut(); - if (!item) return 0; - if (item->visible()) // have the system menu process the shortcut, highlighting the corresponding menu - [[NSApp mainMenu] performKeyEquivalent:[NSApp currentEvent]]; - else // have FLTK process the shortcut associated to an invisible Fl_Menu_Item - fl_sys_menu_bar->picked(item); - return 1; -} - -Fl_MacOS_Sys_Menu_Bar_Driver::Fl_MacOS_Sys_Menu_Bar_Driver() : Fl_Sys_Menu_Bar_Driver() -{ - window_menu_items = NULL; - first_window_menu_item = 0; - Fl::add_handler(process_sys_menu_shortcuts); -} - -Fl_MacOS_Sys_Menu_Bar_Driver::~Fl_MacOS_Sys_Menu_Bar_Driver() -{ - Fl::remove_handler(process_sys_menu_shortcuts); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::menu(const Fl_Menu_Item *m) -{ - fl_open_display(); - bar->Fl_Menu_Bar::menu( m ); - convertToMenuBar(m); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::clear() -{ - bar->Fl_Menu_::clear(); - convertToMenuBar(NULL); -} - -int Fl_MacOS_Sys_Menu_Bar_Driver::clear_submenu(int index) -{ - int retval = bar->Fl_Menu_::clear_submenu(index); - if (retval != -1) update(); - return retval; -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::remove(int index) -{ - bar->Fl_Menu_::remove(index); - update(); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::replace(int index, const char *name) -{ - bar->Fl_Menu_::replace(index, name); - update(); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::mode(int i, int fl) { - bar->Fl_Menu_::mode(i, fl); - update(); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::shortcut (int i, int s) { - bar->Fl_Menu_Bar::shortcut(i, s); - update(); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::setonly (Fl_Menu_Item *item) { - bar->Fl_Menu_::setonly(item); - update(); -} - -int Fl_MacOS_Sys_Menu_Bar_Driver::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) -{ - fl_open_display(); - int index = bar->Fl_Menu_::add(label, shortcut, cb, user_data, flags); - update(); - return index; -} - -int Fl_MacOS_Sys_Menu_Bar_Driver::add(const char* str) -{ - fl_open_display(); - int index = bar->Fl_Menu_::add(str); - update(); - return index; -} - -int Fl_MacOS_Sys_Menu_Bar_Driver::insert(int index, const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) -{ - fl_open_display(); - int menu_index = bar->Fl_Menu_::insert(index, label, shortcut, cb, user_data, flags); - update(); - return menu_index; -} - -/** \class Fl_Mac_App_Menu - Mac OS-specific class allowing to customize and localize the application menu. - - The public class attributes are used to build the application menu. They can be localized - at run time to any UTF-8 text by placing instructions such as this before fl_open_display() - gets called: - \verbatim - Fl_Mac_App_Menu::print = "Imprimer la fenêtre"; - \endverbatim - \see \ref osissues_macos for another way to localization. - */ - -void Fl_Mac_App_Menu::custom_application_menu_items(const Fl_Menu_Item *m) -{ - fl_open_display(); // create the system menu, if needed - custom_menu = new Fl_Menu_Bar(0,0,0,0); - custom_menu->menu(m); - NSMenu *menu = [[[NSApp mainMenu] itemAtIndex:0] submenu]; // the application menu - NSInteger to_index; - if ([[menu itemAtIndex:2] action] != @selector(printPanel)) { // the 'Print' item was removed - [menu insertItem:[NSMenuItem separatorItem] atIndex:1]; - to_index = 2; - } else to_index = 5; // after the "Print Front Window/Toggle" items and the separator - NSInteger count = [menu numberOfItems]; - createSubMenu(menu, m, NULL, @selector(customCallback)); // add new items at end of application menu - NSInteger count2 = [menu numberOfItems]; - for (NSInteger i = count; i < count2; i++) { // move new items to their desired position in application menu - NSMenuItem *item = [menu itemAtIndex:i]; - [item retain]; - [menu removeItemAtIndex:i]; - [menu insertItem:item atIndex:to_index++]; - [item release]; - } -} - -static void minimize_win_cb(Fl_Widget *, void *data) -{ - [[NSApp mainWindow] miniaturize:nil]; -} - -static void window_menu_cb(Fl_Widget *, void *data) -{ - if (data) ((Fl_Window*)data)->show(); -} - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - -static void previous_tab_cb(Fl_Widget *, void *data) -{ - [[NSApp mainWindow] selectPreviousTab:nil]; -} - -static void next_tab_cb(Fl_Widget *, void *data) -{ - [[NSApp mainWindow] selectNextTab:nil]; -} - -static void move_tab_cb(Fl_Widget *, void *data) -{ - [[NSApp mainWindow] moveTabToNewWindow:nil]; -} - -static void merge_all_windows_cb(Fl_Widget *, void *) -{ - Fl_Window *first = Fl::first_window(); - while (first && (first->parent() || !first->border())) - first = Fl::next_window(first); - if (first) { - [(NSWindow*)fl_xid(first) mergeAllWindows:nil]; - } -} - -#endif - - -static bool window_menu_installed = false; -static int window_menu_items_count = 0; - -void Fl_MacOS_Sys_Menu_Bar_Driver::create_window_menu(void) -{ - if (window_menu_style() == Fl_Sys_Menu_Bar::no_window_menu) return; - if (window_menu_installed) return; - window_menu_installed = true; - int rank = 0; - if (fl_sys_menu_bar && fl_sys_menu_bar->menu()) { - if (fl_sys_menu_bar->find_index("Window") >= 0) { // there's already a "Window" menu -> don't create another - window_menu_style_ = Fl_Sys_Menu_Bar::no_window_menu; - return; - } - // put the Window menu last in menu bar or before Help if it's present - const Fl_Menu_Item *item = fl_sys_menu_bar->menu(); - while (item->label() && strcmp(item->label(), "Help") != 0) { - item = item->next(); - } - rank = fl_sys_menu_bar->find_index(item); - } else if (!fl_sys_menu_bar) { - fl_open_display(); - new Fl_Sys_Menu_Bar(0,0,0,0); - } - if (!window_menu_items_count) { - window_menu_items_count = 6; - window_menu_items = (Fl_Menu_Item*)calloc(window_menu_items_count, sizeof(Fl_Menu_Item)); - } - rank = fl_sys_menu_bar->Fl_Menu_::insert(rank, "Window", 0, NULL, window_menu_items, FL_SUBMENU_POINTER); - localized_Window = NSLocalizedString(@"Window", nil); - window_menu_items[0].label("Minimize"); - window_menu_items[0].callback(minimize_win_cb); - window_menu_items[0].shortcut(FL_COMMAND+'m'); - window_menu_items[0].flags = FL_MENU_DIVIDER; - first_window_menu_item = 1; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (fl_mac_os_version >= 101200 && window_menu_style() != Fl_Sys_Menu_Bar::tabbing_mode_none) { - window_menu_items[1].label("Show Previous Tab"); - window_menu_items[1].callback(previous_tab_cb); - window_menu_items[1].shortcut(FL_SHIFT+FL_CTRL+0x9); - window_menu_items[2].label("Show Next Tab"); - window_menu_items[2].callback(next_tab_cb); - window_menu_items[2].shortcut(FL_CTRL+0x9); - window_menu_items[3].label("Move Tab To New Window"); - window_menu_items[3].callback(move_tab_cb); - window_menu_items[4].label("Merge All Windows"); - window_menu_items[4].callback(merge_all_windows_cb); - window_menu_items[4].flags = FL_MENU_DIVIDER; - first_window_menu_item = 5; - } -#endif - fl_sys_menu_bar->menu_end(); - fl_sys_menu_bar->update(); -} - - -void Fl_MacOS_Sys_Menu_Bar_Driver::new_window(Fl_Window *win) -{ - if (!window_menu_style() || !win->label()) return; - int index = window_menu_items->size() - 1; - if (index >= window_menu_items_count - 1) { - window_menu_items_count += 5; - window_menu_items = (Fl_Menu_Item*)realloc(window_menu_items, - window_menu_items_count * sizeof(Fl_Menu_Item)); - Fl_Menu_Item *item = (Fl_Menu_Item*)fl_sys_menu_bar->find_item("Window"); - item->user_data(window_menu_items); - } - const char *p = win->iconlabel() ? win->iconlabel() : win->label(); - window_menu_items[index].label(p); - window_menu_items[index].callback(window_menu_cb); - window_menu_items[index].user_data(win); - window_menu_items[index].flags = FL_MENU_RADIO; - window_menu_items[index+1].label(NULL); - window_menu_items[index].setonly(); - fl_sys_menu_bar->update(); -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::remove_window(Fl_Window *win) -{ - if (!window_menu_style()) return; - int index = first_window_menu_item; - if (index < 1) return; - while (true) { - Fl_Menu_Item *item = window_menu_items + index; - if (!item->label()) return; - if (item->user_data() == win) { - bool doit = item->value(); - int count = window_menu_items->size(); - if (count - index - 1 > 0) memmove(item, item + 1, (count - index - 1)*sizeof(Fl_Menu_Item)); - memset(window_menu_items + count - 2, 0, sizeof(Fl_Menu_Item)); - if (doit) { // select Fl::first_window() in Window menu - item = window_menu_items + first_window_menu_item; - while (item->label() && item->user_data() != Fl::first_window()) item++; - if (item->label()) { - ((Fl_Window*)item->user_data())->show(); - item->setonly(); - } - } - bar->update(); - break; - } - index++; - } -} - -void Fl_MacOS_Sys_Menu_Bar_Driver::rename_window(Fl_Window *win) -{ - if (!window_menu_style()) return; - int index = first_window_menu_item; - if (index < 1) return; - while (true) { - Fl_Menu_Item *item = window_menu_items + index; - if (!item->label()) return; - if (item->user_data() == win) { - item->label(win->iconlabel() ? win->iconlabel() : win->label()); - bar->update(); - return; - } - index++; - } -} - -void fl_mac_set_about(Fl_Callback *cb, void *user_data, int shortcut) { - Fl_Sys_Menu_Bar::about(cb, user_data); -} - - -void Fl_MacOS_Sys_Menu_Bar_Driver::play_menu(const Fl_Menu_Item *item) { - // Use the accessibility interface to programmatically open a menu of the system menubar - CFArrayRef children = NULL; - CFIndex count = 0; - AXUIElementRef element; - char *label = remove_ampersand(item->label()); - NSString *mac_name = NSLocalizedString([NSString stringWithUTF8String:label], nil); - free(label); - AXUIElementRef appElement = AXUIElementCreateApplication(getpid()); - AXUIElementRef menu_bar = NULL; - AXError error = AXUIElementCopyAttributeValue(appElement, kAXMenuBarAttribute, - (CFTypeRef *)&menu_bar); - if (!error) error = AXUIElementGetAttributeValueCount(menu_bar, kAXChildrenAttribute, &count); - if (!error) error = AXUIElementCopyAttributeValues(menu_bar, kAXChildrenAttribute, 0, count, - &children); - if (!error) { - NSEnumerator *enumerator = [(NSArray*)children objectEnumerator]; - [enumerator nextObject]; // skip Apple menu - [enumerator nextObject]; // skip application menu - bool need_more = true; - while (need_more && (element = (AXUIElementRef)[enumerator nextObject]) != nil) { - CFTypeRef title = NULL; - need_more = ( AXUIElementCopyAttributeValue(element, kAXTitleAttribute, &title) == 0 ); - if (need_more && [(NSString*)title isEqualToString:mac_name]) { - AXUIElementPerformAction(element, kAXPressAction); - need_more = false; - } - if (title) CFRelease(title); - } - } - if (menu_bar) CFRelease(menu_bar); - if (children) CFRelease(children); - CFRelease(appElement); -} - -#endif /* __APPLE__ */ diff --git a/src/Fl_Native_File_Chooser_MAC.mm b/src/Fl_Native_File_Chooser_MAC.mm deleted file mode 100644 index b3dd9ae8f..000000000 --- a/src/Fl_Native_File_Chooser_MAC.mm +++ /dev/null @@ -1,825 +0,0 @@ -// -// FLTK native OS file chooser widget for macOS -// -// Copyright 2004 Greg Ercolano. -// Copyright 1998-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// TODO: -// o When doing 'open file', only dir is preset, not filename. -// Possibly 'preset_file' could be used to select the filename. -// - -#include <FL/Fl.H> -#include <FL/platform.H> // for fl_mac_os_version -#include <FL/Fl_Native_File_Chooser.H> -#include <FL/Fl_File_Chooser.H> -#include <FL/filename.H> -#include <FL/fl_string_functions.h> -#define MAXFILTERS 80 -#import <Cocoa/Cocoa.h> -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 -# import <UniformTypeIdentifiers/UniformTypeIdentifiers.h> -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 -const NSInteger NSModalResponseOK = NSFileHandlingPanelOKButton; -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -const NSUInteger NSControlSizeRegular = NSRegularControlSize; -#endif - -class Fl_Quartz_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_Driver { -private: - int _btype; // kind-of browser to show() - int _options; // general options - NSSavePanel *_panel; - char **_pathnames; // array of pathnames - int _tpathnames; // total pathnames - char *_directory; // default pathname to use - char *_title; // title for window - char *_preset_file; // the 'save as' filename - - char *_filter; // user-side search filter, eg: - // C Files\t*.[ch]\nText Files\t*.txt" - - char *_filt_names; // filter names (tab delimited) - // eg. "C Files\tText Files" - - char *_filt_patt[MAXFILTERS]; - // array of filter patterns, eg: - // _filt_patt[0]="*.{cxx,h}" - // _filt_patt[1]="*.txt" - - int _filt_total; // parse_filter() # of filters loaded - int _filt_value; // index of the selected filter - char *_errmsg; // error message - - // Private methods - void errmsg(const char *msg); - void clear_pathnames(); - void set_single_pathname(const char *s); - int get_saveas_basename(void); - void clear_filters(); - void parse_filter(const char *from); - int post(); - int runmodal(); -public: - Fl_Quartz_Native_File_Chooser_Driver(int val); - ~Fl_Quartz_Native_File_Chooser_Driver(); - void type(int t) FL_OVERRIDE; - int type() const FL_OVERRIDE; - void options(int o) FL_OVERRIDE; - int options() const FL_OVERRIDE; - int count() const FL_OVERRIDE; - const char *filename() const FL_OVERRIDE; - const char *filename(int i) const FL_OVERRIDE; - void directory(const char *val) FL_OVERRIDE; - const char *directory() const FL_OVERRIDE; - void title(const char *t) FL_OVERRIDE; - const char* title() const FL_OVERRIDE; - const char *filter() const FL_OVERRIDE; - void filter(const char *f) FL_OVERRIDE; - int filters() const FL_OVERRIDE; - void filter_value(int i) FL_OVERRIDE; - int filter_value() const FL_OVERRIDE; - void preset_file(const char*f) FL_OVERRIDE; - const char* preset_file() const FL_OVERRIDE; - const char *errmsg() const FL_OVERRIDE; - int show() FL_OVERRIDE; -}; - -Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { - platform_fnfc = new Fl_Quartz_Native_File_Chooser_Driver(val); -} - -// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS -void Fl_Quartz_Native_File_Chooser_Driver::clear_pathnames() { - if ( _pathnames ) { - while ( --_tpathnames >= 0 ) { - _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); - } - delete [] _pathnames; - _pathnames = NULL; - } - _tpathnames = 0; -} - -// SET A SINGLE PATHNAME -void Fl_Quartz_Native_File_Chooser_Driver::set_single_pathname(const char *s) { - clear_pathnames(); - _pathnames = new char*[1]; - _pathnames[0] = strnew(s); - _tpathnames = 1; -} - -// CONSTRUCTOR -Fl_Quartz_Native_File_Chooser_Driver::Fl_Quartz_Native_File_Chooser_Driver(int val) : - Fl_Native_File_Chooser_Driver(val) { - _btype = val; - _panel = NULL; - _options = Fl_Native_File_Chooser::NO_OPTIONS; - _pathnames = NULL; - _tpathnames = 0; - _title = NULL; - _filter = NULL; - _filt_names = NULL; - memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS); - _filt_total = 0; - _filt_value = 0; - _directory = NULL; - _preset_file = NULL; - _errmsg = NULL; -} - -// DESTRUCTOR -Fl_Quartz_Native_File_Chooser_Driver::~Fl_Quartz_Native_File_Chooser_Driver() { - // _opts // nothing to manage - // _options // nothing to manage - // _keepstate // nothing to manage - // _tempitem // nothing to manage - clear_pathnames(); - _directory = strfree(_directory); - _title = strfree(_title); - _preset_file = strfree(_preset_file); - _filter = strfree(_filter); - //_filt_names // managed by clear_filters() - //_filt_patt[i] // managed by clear_filters() - //_filt_total // managed by clear_filters() - clear_filters(); - //_filt_value // nothing to manage - _errmsg = strfree(_errmsg); -} - -// GET TYPE OF BROWSER -int Fl_Quartz_Native_File_Chooser_Driver::type() const { - return(_btype); -} - -// SET OPTIONS -void Fl_Quartz_Native_File_Chooser_Driver::options(int val) { - _options = val; -} - -// GET OPTIONS -int Fl_Quartz_Native_File_Chooser_Driver::options() const { - return(_options); -} - -// SHOW THE BROWSER WINDOW -// Returns: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_Quartz_Native_File_Chooser_Driver::show() { - - // Make sure fltk interface updates before posting our dialog - Fl::flush(); - - // POST BROWSER - int err = post(); - - return(err); -} - -// SET ERROR MESSAGE -// Internal use only. -// -void Fl_Quartz_Native_File_Chooser_Driver::errmsg(const char *msg) { - _errmsg = strfree(_errmsg); - _errmsg = strnew(msg); -} - -// RETURN ERROR MESSAGE -const char *Fl_Quartz_Native_File_Chooser_Driver::errmsg() const { - return(_errmsg ? _errmsg : "No error"); -} - -// GET FILENAME -const char* Fl_Quartz_Native_File_Chooser_Driver::filename() const { - if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); - return(""); -} - -// GET FILENAME FROM LIST OF FILENAMES -const char* Fl_Quartz_Native_File_Chooser_Driver::filename(int i) const { - if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); - return(""); -} - -// GET TOTAL FILENAMES CHOSEN -int Fl_Quartz_Native_File_Chooser_Driver::count() const { - return(_tpathnames); -} - -// PRESET PATHNAME -// Value can be NULL for none. -// -void Fl_Quartz_Native_File_Chooser_Driver::directory(const char *val) { - _directory = strfree(_directory); - _directory = strnew(val); -} - -// GET PRESET PATHNAME -// Returned value can be NULL if none set. -// -const char* Fl_Quartz_Native_File_Chooser_Driver::directory() const { - return(_directory); -} - -// SET TITLE -// Value can be NULL if no title desired. -// -void Fl_Quartz_Native_File_Chooser_Driver::title(const char *val) { - _title = strfree(_title); - _title = strnew(val); -} - -// GET TITLE -// Returned value can be NULL if none set. -// -const char *Fl_Quartz_Native_File_Chooser_Driver::title() const { - return(_title); -} - -// SET FILTER -// Can be NULL if no filter needed -// -void Fl_Quartz_Native_File_Chooser_Driver::filter(const char *val) { - _filter = strfree(_filter); - _filter = strnew(val); - - // Parse filter user specified - // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt" - // OUT: _filt_names = "C Files\tText Files" - // _filt_patt[0] = "*.{cxx,h}" - // _filt_patt[1] = "*.txt" - // _filt_total = 2 - // - parse_filter(_filter); -} - -// GET FILTER -// Returned value can be NULL if none set. -// -const char *Fl_Quartz_Native_File_Chooser_Driver::filter() const { - return(_filter); -} - -// CLEAR ALL FILTERS -// Internal use only. -// -void Fl_Quartz_Native_File_Chooser_Driver::clear_filters() { - _filt_names = strfree(_filt_names); - for (int i=0; i<_filt_total; i++) { - _filt_patt[i] = strfree(_filt_patt[i]); - } - _filt_total = 0; -} - -// PARSE USER'S FILTER SPEC -// Parses user specified filter ('in'), -// breaks out into _filt_patt[], _filt_names, and _filt_total. -// -// Handles: -// IN: OUT:_filt_names OUT: _filt_patt -// ------------------------------------ ------------------ --------------- -// "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}" -// "*.[abc]" "*.[abc] Files" "*.[abc]" -// "*.txt" "*.txt Files" "*.c" -// "C Files\t*.[ch]" "C Files" "*.[ch]" -// "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]" -// -// Parsing Mode: -// IN:"C Files\t*.{cxx,h}" -// ||||||| ||||||||| -// mode: nnnnnnn wwwwwwwww -// \_____/ \_______/ -// Name Wildcard -// -void Fl_Quartz_Native_File_Chooser_Driver::parse_filter(const char *in) { - clear_filters(); - if ( ! in ) return; - int has_name = strchr(in, '\t') ? 1 : 0; - - char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard - char wildcard[1024] = ""; // parsed wildcard - char name[1024] = ""; - - // Parse filter user specified - for ( ; 1; in++ ) { - - //// DEBUG - //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n", - //// *in, mode, name, wildcard); - - switch (*in) { - // FINISHED PARSING NAME? - case '\t': - if ( mode != 'n' ) goto regchar; - mode = 'w'; - break; - - // ESCAPE NEXT CHAR - case '\\': - ++in; - goto regchar; - - // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? - case '\r': - case '\n': - case '\0': - // TITLE - // If user didn't specify a name, make one - // - if ( name[0] == '\0' ) { - snprintf(name, sizeof(name), "%.*s Files", (int)sizeof(name)-10, wildcard); - } - // APPEND NEW FILTER TO LIST - if ( wildcard[0] ) { - // Add to filtername list - // Tab delimit if more than one. We later break - // tab delimited string into CFArray with - // CFStringCreateArrayBySeparatingStrings() - // - if ( _filt_total ) { - _filt_names = strapp(_filt_names, "\t"); - } - _filt_names = strapp(_filt_names, name); - - // Add filter to the pattern array - _filt_patt[_filt_total++] = strnew(wildcard); - } - // RESET - wildcard[0] = name[0] = '\0'; - mode = strchr(in, '\t') ? 'n' : 'w'; - // DONE? - if ( *in == '\0' ) return; // done - else continue; // not done yet, more filters - - // Parse all other chars - default: // handle all non-special chars - regchar: // handle regular char - switch ( mode ) { - case 'n': chrcat(name, *in); continue; - case 'w': chrcat(wildcard, *in); continue; - } - break; - } - } - //NOTREACHED -} - -// SET PRESET FILE -// Value can be NULL for none. -// -void Fl_Quartz_Native_File_Chooser_Driver::preset_file(const char* val) { - _preset_file = strfree(_preset_file); - _preset_file = strnew(val); -} - -// PRESET FILE -// Returned value can be NULL if none set. -// -const char* Fl_Quartz_Native_File_Chooser_Driver::preset_file() const { - return(_preset_file); -} - -void Fl_Quartz_Native_File_Chooser_Driver::filter_value(int val) { - _filt_value = val; -} - -int Fl_Quartz_Native_File_Chooser_Driver::filter_value() const { - return(_filt_value); -} - -int Fl_Quartz_Native_File_Chooser_Driver::filters() const { - return(_filt_total); -} - -#define UNLIKELYPREFIX "___fl_very_unlikely_prefix_" - -int Fl_Quartz_Native_File_Chooser_Driver::get_saveas_basename(void) { - char *q = fl_strdup( [[[_panel URL] path] UTF8String] ); - if ( !(_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM) ) { - const char *d = [[[[_panel URL] path] stringByDeletingLastPathComponent] UTF8String]; - int l = (int)strlen(d) + 1; - if (strcmp(d, "/") == 0) l = 1; - int lu = (int)strlen(UNLIKELYPREFIX); - int ln = (int)strlen(q+l); - if (ln >= lu) { - // Remove UNLIKELYPREFIX between directory and filename parts - if (memcmp(q+l, UNLIKELYPREFIX, lu) == 0) memmove(q + l, q + l + lu, strlen(q + l + lu) + 1); - } - } - set_single_pathname( q ); - free(q); - return 0; -} - -// SET THE TYPE OF BROWSER -void Fl_Quartz_Native_File_Chooser_Driver::type(int val) { - _btype = val; -} - -/* Input - filter= "C files\t*.{c,h}\nText files\t*.txt\n" - patterns[0] = "*.{c,h}" - patterns[1] = "*.txt" - count = 2 - Return: - "C files (*.{c,h})\nText files (*.txt)\n" - */ -static char *prepareMacFilter(int count, const char *filter, char **patterns) { - int rank = 0, l = 0; - for (int i = 0; i < count; i++) { - l += strlen(patterns[i]) + 3; - } - const char *p = filter; - const int t_size = (int)strlen(p) + l + 1; - char *q; q = new char[t_size]; - const char *r, *s; - char *t; - t = q; - do { // copy to t what is in filter removing what is between \t and \n, if any - r = strchr(p, '\n'); - if (!r) r = p + strlen(p); - s = strchr(p, '\t'); - if (s && s < r) { - memcpy(q, p, s - p); - q += s - p; - if (rank < count) { - snprintf(q, t_size-(q-t), " (%s)", patterns[rank]); q += strlen(q); - } - } - else { - memcpy(q, p, r - p); - q += r - p; - } - rank++; - *(q++) = '\n'; - if (*r) p = r + 1; else p = r; - } while(*p); - *q = 0; - return t; -} - -@interface FLopenDelegate : NSObject <NSOpenSavePanelDelegate> -{ - NSPopUpButton *nspopup; - char **filter_pattern; -} -- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern; -- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename; -- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url; -@end -@implementation FLopenDelegate -- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern -{ - nspopup = popup; - filter_pattern = pattern; - return self; -} -- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename -{ - if ( [nspopup indexOfSelectedItem] == [nspopup numberOfItems] - 1) return YES; - BOOL isdir = NO; - [[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isdir]; - if (isdir) return YES; - if ( fl_filename_match([filename fileSystemRepresentation], filter_pattern[([nspopup indexOfSelectedItem])]) ) return YES; - return NO; -} -- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url -{ - return [self panel:sender shouldShowFilename:[url path]]; -} -@end - -@interface FLsaveDelegate : NSObject <NSOpenSavePanelDelegate> -{ - NSSavePanel *dialog; - BOOL saveas_confirm; -} -- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag; -- (void)control_allowed_types:(const char *)p; -- (void)changedPopup:(id)sender; -- (void)panel:(NSSavePanel*)p; -- (void)option:(BOOL)o; -@end -@implementation FLsaveDelegate -- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag -{ - if ( !okFlag || saveas_confirm ) return filename; - // User has clicked save, and no overwrite confirmation should occur. - // To get the latter, we need to change the name we return (hence the prefix): - return [@ UNLIKELYPREFIX stringByAppendingString:filename]; -} -- (void)control_allowed_types:(const char *)p -{ - NSString *ext = [NSString stringWithUTF8String:p]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 - if (@available(macOS 11.0, *)) { - UTType *type = [UTType typeWithFilenameExtension:ext]; // 11.0 + framework UniformTypeIdentifiers - [dialog setAllowedContentTypes:[NSArray arrayWithObject:type]]; // 11.0 - } - else -#endif - if (fl_mac_os_version >= 100900) { - [dialog performSelector:@selector(setAllowedFileTypes:) - withObject:[NSArray arrayWithObject:ext]]; - } -} -- (void)changedPopup:(id)sender -// runs when the save panel popup menu changes output file type -// correspondingly changes the extension of the output file name -{ - char *s = fl_strdup([[(NSPopUpButton*)sender titleOfSelectedItem] UTF8String]); - if (!s) return; - char *p = strchr(s, '('); - if (!p) p = s; - p = strchr(p, '.'); - if (!p) {free(s); return;} - p++; - while (*p == ' ') p++; - if (!p || *p == '{') {free(s); return;} - char *q = p+1; - while (*q != ' ' && *q != ')' && *q != 0) q++; - *q = 0; - NSString *ns = [NSString stringWithFormat:@"%@.%@", - [[dialog performSelector:@selector(nameFieldStringValue)] stringByDeletingPathExtension], - [NSString stringWithUTF8String:p]]; - [self control_allowed_types:p]; - free(s); - [dialog performSelector:@selector(setNameFieldStringValue:) withObject:ns]; -} -- (void)panel:(NSSavePanel*)p -{ - dialog = p; -} -- (void) option:(BOOL)o -{ - saveas_confirm = o; -} -@end - - -@interface FLHiddenFilesAction : NSObject -{ -@public - NSSavePanel *panel; - NSButton *button; -} -- (void)action; -@end -@implementation FLHiddenFilesAction -- (void)action { - [panel setShowsHiddenFiles:[button intValue]]; // 10.6 -} -@end - - -static NSPopUpButton *createPopupAccessory(NSSavePanel *panel, const char *filter, const char *title, int rank) -{ - NSPopUpButton *popup = nil; - NSRect rectview = NSMakeRect(5, 5, 350, filter ? 60 : 30); - NSView *view = [[[NSView alloc] initWithFrame:rectview] autorelease]; - NSRect rectbox = NSMakeRect(0, 3, 140, 20 ); - // the "Show hidden files" button - NSRect hidden_files_rect = {{150, 0}, {80, 30}}; - if (filter) hidden_files_rect.origin.y = 35; - NSButton *hidden_files = [[[NSButton alloc] initWithFrame:hidden_files_rect] autorelease]; - [hidden_files setButtonType: -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - NSButtonTypeSwitch -#else - NSSwitchButton -#endif - ]; - [hidden_files setTitle:[NSString stringWithUTF8String:Fl_File_Chooser::hidden_label]]; - [hidden_files sizeToFit]; - [hidden_files setIntValue:0]; - [view addSubview:hidden_files]; - static FLHiddenFilesAction *target = [[FLHiddenFilesAction alloc] init]; // never released - target->panel = panel; - target->button = hidden_files; - [hidden_files setAction:@selector(action)]; - [hidden_files setTarget:target]; - if (filter) { - NSBox *box = [[[NSBox alloc] initWithFrame:rectbox] autorelease]; - NSRect rectpop = NSMakeRect(105, 0, 246, 30 ); - popup = [[[NSPopUpButton alloc ] initWithFrame:rectpop pullsDown:NO] autorelease]; - [view addSubview:box]; - [view addSubview:popup]; - NSString *nstitle = [[NSString alloc] initWithUTF8String:title]; - [box setTitle:nstitle]; - [box setTitlePosition:NSBelowTop]; - [nstitle release]; - NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; - [box setTitleFont:font]; - [box sizeToFit]; - // horizontally move box to fit the locale-dependent width of its title - NSRect r=[box frame]; - r.origin.x = rectpop.origin.x - r.size.width; - r.origin.y = rectpop.origin.y + (rectpop.size.height - r.size.height) / 2; - [box setFrame:r]; - CFStringRef tab = CFSTR("\n"); - CFStringRef tmp_cfs; - tmp_cfs = CFStringCreateWithCString(NULL, filter, kCFStringEncodingUTF8); - CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, tmp_cfs, tab); - CFRelease(tmp_cfs); - CFRelease(tab); - [popup addItemsWithTitles:(NSArray*)array]; - NSMenuItem *item = [popup itemWithTitle:@""]; - if (item) [popup removeItemWithTitle:@""]; - CFRelease(array); - [popup selectItemAtIndex:rank]; - } - [panel setAccessoryView:view]; - return popup; -} - -int Fl_Quartz_Native_File_Chooser_Driver::runmodal() -{ - NSString *dir = nil; - NSString *fname = nil; - NSString *preset = nil; - NSInteger retval; - if (_preset_file) { - preset = [[NSString alloc] initWithUTF8String:_preset_file]; - if (strchr(_preset_file, '/') != NULL) { - dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]]; - } - fname = [preset lastPathComponent]; - } - if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory]; -#if defined(__BLOCKS__) - { - bool usepath = false; - NSString *path = nil; - if (dir && fname && [_panel isKindOfClass:[NSOpenPanel class]]) { - // STR #3406: If both dir + fname specified, combine and pass to setDirectoryURL - path = [[NSString alloc] initWithFormat:@"%@/%@", dir, fname]; // dir+fname -> path - // See if full path to file exists - // If dir exists but fname doesn't, avoid using setDirectoryURL, - // otherwise NSSavePanel falls back to showing user's Documents dir. - // - if ( [[NSFileManager defaultManager] fileExistsAtPath:path] ) usepath = true; - } - if (usepath) { - // Set only if full path exists - [_panel setDirectoryURL:[NSURL fileURLWithPath:path]]; // 10.6 - } else { // didn't setDirectoryURL to full path? Set dir + fname separately.. - if (dir) [_panel setDirectoryURL:[NSURL fileURLWithPath:dir]]; // 10.6 - if (fname) [_panel setNameFieldStringValue:fname]; // 10.6 - } - [path release]; - if ([NSApp mainWindow]) { - __block NSInteger complete = -1; - [_panel beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSInteger returnCode) { - complete = returnCode; // this block runs after OK or Cancel was triggered in file dialog - }]; // 10.6 this message returns immediately and begins the file dialog as a sheet - while (complete == -1) Fl::wait(100); // loop until end of file dialog - retval = complete; - } else { - retval = [_panel runModal]; - } - } -#else // !__BLOCKS__ - // the deprecation warning runs only without blocks -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - retval = [_panel runModalForDirectory:dir file:fname]; // deprecated in 10.6 -#pragma clang diagnostic pop -#endif // __BLOCKS__ - [dir release]; - [preset release]; - return (retval == NSModalResponseOK ? 1 : 0); -} - -// POST BROWSER -// Internal use only. -// Assumes '_opts' has been initialized. -// -// Returns: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_Quartz_Native_File_Chooser_Driver::post() { - // INITIALIZE BROWSER - if ( _filt_total == 0 ) { // Make sure they match - _filt_value = 0; // TBD: move to someplace more logical? - } - fl_open_display(); - NSAutoreleasePool *localPool; - localPool = [[NSAutoreleasePool alloc] init]; - switch (_btype) { - case Fl_Native_File_Chooser::BROWSE_FILE: - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - _panel = [NSOpenPanel openPanel]; - break; - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_SAVE_FILE: - _panel = [NSSavePanel savePanel]; - break; - } - BOOL is_open_panel = [_panel isKindOfClass:[NSOpenPanel class]]; - if (_title) { - SEL title_or_message = (is_open_panel && fl_mac_os_version >= 101200) ? - @selector(setMessage:) : @selector(setTitle:); - [_panel performSelector:title_or_message withObject:[NSString stringWithUTF8String:_title]]; - } - switch (_btype) { - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: - [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; - break; - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; - /* FALLTHROUGH */ - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - [(NSOpenPanel*)_panel setCanChooseDirectories:YES]; - break; - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - [_panel setCanCreateDirectories:YES]; - break; - } - - // SHOW THE DIALOG - NSWindow *key = [NSApp keyWindow]; - NSPopUpButton *popup = nil; - if ( is_open_panel ) { - if (_filt_total) { - char *t = prepareMacFilter(_filt_total, _filter, _filt_patt); - popup = createPopupAccessory(_panel, t, Fl_File_Chooser::show_label, 0); - delete[] t; - [[popup menu] addItem:[NSMenuItem separatorItem]]; - [popup addItemWithTitle:[NSString stringWithUTF8String:Fl_File_Chooser::all_files_label]]; - [popup setAction:@selector(validateVisibleColumns)]; - [popup setTarget:(NSObject*)_panel]; - FLopenDelegate *openDelegate = [[[FLopenDelegate alloc] init] autorelease]; - [openDelegate setPopup:popup filter_pattern:_filt_patt]; - [_panel setDelegate:openDelegate]; - } else createPopupAccessory(_panel, NULL, Fl_File_Chooser::show_label, 0); - } - else { - FLsaveDelegate *saveDelegate = [[[FLsaveDelegate alloc] init] autorelease]; - [_panel setAllowsOtherFileTypes:YES]; - [_panel setDelegate:saveDelegate]; - [saveDelegate option:(_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM)]; - if (_filt_total) { - if (_filt_value >= _filt_total) _filt_value = _filt_total - 1; - char *t = prepareMacFilter(_filt_total, _filter, _filt_patt); - popup = createPopupAccessory(_panel, t, [[_panel nameFieldLabel] UTF8String], _filt_value); - delete[] t; - if (_options & Fl_Native_File_Chooser::USE_FILTER_EXT) { - [popup setAction:@selector(changedPopup:)]; - [popup setTarget:saveDelegate]; - [saveDelegate panel:(NSSavePanel*)_panel]; - if (fl_mac_os_version >= 100900) { - char *p = _filt_patt[_filt_value]; - char *q = strchr(p, '.'); if(!q) q = p-1; - do q++; while (*q==' ' || *q=='{'); - p = fl_strdup(q); - q = strchr(p, ','); if (q) *q = 0; - [saveDelegate control_allowed_types:p]; - free(p); - } - } - [_panel setCanSelectHiddenExtension:YES]; - [_panel setExtensionHidden:NO]; - } else createPopupAccessory(_panel, NULL, Fl_File_Chooser::show_label, 0); - } - int retval = runmodal(); - if (_filt_total) { - _filt_value = (int)[popup indexOfSelectedItem]; - } - if ( retval == 1 ) { - if (is_open_panel) { - clear_pathnames(); - NSArray *array = [(NSOpenPanel*)_panel URLs]; - _tpathnames = (int)[array count]; - _pathnames = new char*[_tpathnames]; - for(int i = 0; i < _tpathnames; i++) { - _pathnames[i] = strnew([[(NSURL*)[array objectAtIndex:i] path] UTF8String]); - } - } - else get_saveas_basename(); - } - [key makeKeyWindow]; - [localPool release]; - return (retval == 1 ? 0 : 1); -} diff --git a/src/Fl_Native_File_Chooser_WIN32.cxx b/src/Fl_Native_File_Chooser_WIN32.cxx deleted file mode 100644 index f33af11c8..000000000 --- a/src/Fl_Native_File_Chooser_WIN32.cxx +++ /dev/null @@ -1,1061 +0,0 @@ -// -// FLTK native OS file chooser widget -// -// Copyright 1998-2021 by Bill Spitzak and others. -// Copyright 2004 Greg Ercolano. -// API changes + filter improvements by Nathan Vander Wilt 2005 -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Any application to multi-folder implementation: -// http://www.codeproject.com/dialog/selectfolder.asp -// - -#ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE -#include <FL/Enumerations.H> - -#include <stdlib.h> // malloc -#include <stdio.h> // snprintf -#include <wchar.h> - -#define FNFC_MAX_PATH 32768 // XXX: MAX_PATH under win32 is 260, too small for modern use - -#include <FL/fl_string_functions.h> // fl_strdup() -#include "flstring.h" // fl_strlcpy()/cat() -#include <FL/Fl_Native_File_Chooser.H> -# include <windows.h> -# include <commdlg.h> // OPENFILENAMEW, GetOpenFileName() -# include <shlobj.h> // BROWSEINFOW, SHBrowseForFolder() -# include <FL/filename.H> // FL_EXPORT -#include <FL/platform.H> // fl_open_display - - -class Fl_WinAPI_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_Driver { -private: - int _btype; // kind-of browser to show() - int _options; // general options - OPENFILENAMEW *_ofn_ptr; // GetOpenFileName() & GetSaveFileName() struct - BROWSEINFOW *_binf_ptr; // SHBrowseForFolder() struct - WCHAR *_wpattern; // pattern buffer for filter - char **_pathnames; // array of pathnames - int _tpathnames; // total pathnames - char *_directory; // default pathname to use - char *_title; // title for window - char *_filter; // user-side search filter - char *_parsedfilt; // filter parsed for Windows dialog - int _nfilters; // number of filters parse_filter counted - char *_preset_file; // the file to preselect - char *_errmsg; // error message - - // Private methods - void errmsg(const char *msg); - - void clear_pathnames(); - void set_single_pathname(const char *s); - void add_pathname(const char *s); - - void ClearOFN(); - void ClearBINF(); - void Win2Unix(char *s); - void Unix2Win(char *s); - bool IsUnixPath(const char *s); - int showfile(); - int showdir(); - - void parse_filter(const char *); - void clear_filters(); - void add_filter(const char *, const char *); -public: - Fl_WinAPI_Native_File_Chooser_Driver(int val); - ~Fl_WinAPI_Native_File_Chooser_Driver(); - void type(int t) FL_OVERRIDE; - int type() const FL_OVERRIDE; - void options(int o) FL_OVERRIDE; - int options() const FL_OVERRIDE; - int count() const FL_OVERRIDE; - const char *filename() const FL_OVERRIDE; - const char *filename(int i) const FL_OVERRIDE; - void directory(const char *val) FL_OVERRIDE; - const char *directory() const FL_OVERRIDE; - void title(const char *t) FL_OVERRIDE; - const char* title() const FL_OVERRIDE; - const char *filter() const FL_OVERRIDE; - void filter(const char *f) FL_OVERRIDE; - int filters() const FL_OVERRIDE; - void filter_value(int i) FL_OVERRIDE; - int filter_value() const FL_OVERRIDE; - void preset_file(const char*f) FL_OVERRIDE; - const char* preset_file() const FL_OVERRIDE; - const char *errmsg() const FL_OVERRIDE; - int show() FL_OVERRIDE; -}; - - -Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { - platform_fnfc = new Fl_WinAPI_Native_File_Chooser_Driver(val); -} - - -static LPCWSTR utf8towchar(const char *in); -static char *wchartoutf8(LPCWSTR in); - - -#define LCURLY_CHR '{' -#define RCURLY_CHR '}' -#define LBRACKET_CHR '[' -#define RBRACKET_CHR ']' - -// STATIC: Print Windows 'double-null' string (debug) -#ifdef DEBUG -#include <stdio.h> -static void dnullprint(char *wp) { - if ( ! wp ) return; - for ( int t=0; true; t++ ) { - if ( wp[t] == '\0' && wp[t+1] == '\0' ) { - printf("\\0\\0"); - fflush(stdout); - return; - } else if ( wp[t] == '\0' ) { - printf("\\0"); - } else { - printf("%c",wp[t]); - } - } -} -#endif - -// Return length of double-null string -// Includes single nulls in count, excludes trailing double-null. -// -// 1234 567 -// |||/\||| -// IN: "one\0two\0\0" -// OUT: 7 -// -static int dnulllen(const char *wp) { - int len = 0; - while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) ) { - ++wp; - ++len; - } - return(len); -} - -// STATIC: Append a string to another, leaving terminated with DOUBLE NULL. -// Automatically handles extending length of string. -// wp can be NULL (a new wp will be allocated and initialized). -// string must be NULL terminated. -// The pointer wp may be modified on return. -// -static void dnullcat(char*&wp, const char *string, int n = -1 ) { - //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n"); - size_t inlen = ( n < 0 ) ? strlen(string) : n; - char *wp2 = 0; // used to point at end of last string - if ( ! wp ) { - wp = new char[inlen + 4]; - *(wp+0) = '\0'; - *(wp+1) = '\0'; - wp2 = wp; // no "last string", point at begin of buffer - } else { - int wplen = dnulllen(wp); - // Make copy of wp into larger buffer - char *tmp = new char[wplen + inlen + 4]; - memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull - delete[] wp; // delete old wp - wp = tmp; // use new copy - wp2 = wp + wplen + 1; // point at second null - //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen); - } - - // *wp2 points at second null; the buffer is large enough to copy the string! - strcpy(wp2, string); - *(wp2+inlen+1) = '\0'; // Leave string double-null terminated - //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n"); -} - -// CTOR -Fl_WinAPI_Native_File_Chooser_Driver::Fl_WinAPI_Native_File_Chooser_Driver(int val) : - Fl_Native_File_Chooser_Driver(val) { - _btype = val; - _options = Fl_Native_File_Chooser::NO_OPTIONS; - _ofn_ptr = new OPENFILENAMEW; - _binf_ptr = new BROWSEINFOW; - _wpattern = 0; - memset((void*)_ofn_ptr, 0, sizeof(OPENFILENAMEW)); - _ofn_ptr->lStructSize = sizeof(OPENFILENAMEW); - _ofn_ptr->hwndOwner = 0L; - memset((void*)_binf_ptr, 0, sizeof(BROWSEINFOW)); - _pathnames = NULL; - _tpathnames = 0; - _directory = NULL; - _title = NULL; - _filter = NULL; - _parsedfilt = NULL; - _nfilters = 0; - _preset_file = NULL; - _errmsg = NULL; -} - -// DTOR -Fl_WinAPI_Native_File_Chooser_Driver::~Fl_WinAPI_Native_File_Chooser_Driver() { - //_pathnames // managed by clear_pathnames() - //_tpathnames // managed by clear_pathnames() - _directory = strfree(_directory); - _title = strfree(_title); - _filter = strfree(_filter); - //_parsedfilt // managed by clear_filters() - //_nfilters // managed by clear_filters() - _preset_file = strfree(_preset_file); - _errmsg = strfree(_errmsg); - clear_filters(); - clear_pathnames(); - ClearOFN(); - ClearBINF(); - delete _binf_ptr; - delete _ofn_ptr; - if ( _wpattern ) delete[] _wpattern; -} - -// SET TYPE OF BROWSER -void Fl_WinAPI_Native_File_Chooser_Driver::type(int val) { - _btype = val; -} - -// GET TYPE OF BROWSER -int Fl_WinAPI_Native_File_Chooser_Driver::type() const { - return( _btype ); -} - -// SET OPTIONS -void Fl_WinAPI_Native_File_Chooser_Driver::options(int val) { - _options = val; -} - -// GET OPTIONS -int Fl_WinAPI_Native_File_Chooser_Driver::options() const { - return(_options); -} - -// PRIVATE: SET ERROR MESSAGE -void Fl_WinAPI_Native_File_Chooser_Driver::errmsg(const char *val) { - _errmsg = strfree(_errmsg); - _errmsg = strnew(val); -} - -// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS -void Fl_WinAPI_Native_File_Chooser_Driver::clear_pathnames() { - if ( _pathnames ) { - while ( --_tpathnames >= 0 ) { - _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); - } - delete[] _pathnames; - _pathnames = NULL; - } - _tpathnames = 0; -} - -// SET A SINGLE PATHNAME -void Fl_WinAPI_Native_File_Chooser_Driver::set_single_pathname(const char *s) { - clear_pathnames(); - _pathnames = new char*[1]; - _pathnames[0] = strnew(s); - _tpathnames = 1; -} - -// ADD PATHNAME TO EXISTING ARRAY -void Fl_WinAPI_Native_File_Chooser_Driver::add_pathname(const char *s) { - if ( ! _pathnames ) { - // Create first element in array - ++_tpathnames; - _pathnames = new char*[_tpathnames]; - } else { - // Grow array by 1 - char **tmp = new char*[_tpathnames+1]; // create new buffer - memcpy((void*)tmp, (void*)_pathnames, - sizeof(char*)*_tpathnames); // copy old - delete[] _pathnames; // delete old - _pathnames = tmp; // use new - ++_tpathnames; - } - _pathnames[_tpathnames-1] = strnew(s); -} - -// FREE A PIDL (Pointer to IDentity List) -static void FreePIDL(LPITEMIDLIST pidl) { - IMalloc *imalloc = NULL; - if ( SUCCEEDED(SHGetMalloc(&imalloc)) ) { - imalloc->Free(pidl); - imalloc->Release(); - imalloc = NULL; - } -} - -// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS -void Fl_WinAPI_Native_File_Chooser_Driver::ClearOFN() { - // Free any previously allocated lpstrFile before zeroing out _ofn_ptr - if ( _ofn_ptr->lpstrFile ) { - delete[] _ofn_ptr->lpstrFile; - _ofn_ptr->lpstrFile = NULL; - } - if ( _ofn_ptr->lpstrInitialDir ) { - delete[] (TCHAR*) _ofn_ptr->lpstrInitialDir; //msvc6 compilation fix - _ofn_ptr->lpstrInitialDir = NULL; - } - _ofn_ptr->lpstrFilter = NULL; // (deleted elsewhere) - int temp = _ofn_ptr->nFilterIndex; // keep the filter_value - memset((void*)_ofn_ptr, 0, sizeof(OPENFILENAMEW)); - _ofn_ptr->lStructSize = sizeof(OPENFILENAMEW); - _ofn_ptr->nFilterIndex = temp; -} - -// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS -void Fl_WinAPI_Native_File_Chooser_Driver::ClearBINF() { - if ( _binf_ptr->pidlRoot ) { - FreePIDL((ITEMIDLIST*)_binf_ptr->pidlRoot); - _binf_ptr->pidlRoot = NULL; - } - memset((void*)_binf_ptr, 0, sizeof(BROWSEINFOW)); -} - -// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES -void Fl_WinAPI_Native_File_Chooser_Driver::Win2Unix(char *s) { - while ( (s=strchr(s,'\\')) ) *s = '/'; -} - -// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES -void Fl_WinAPI_Native_File_Chooser_Driver::Unix2Win(char *s) { - while ( (s=strchr(s,'/')) ) *s = '\\'; -} - -// SEE IF PATH IS FRONT SLASH OR BACKSLASH STYLE -// Use this to preserve path style after windows dialog appears. -// If no slashes are specified, windows is assumed. -// If a mix of both path styles is used, windows is assumed. -// -bool Fl_WinAPI_Native_File_Chooser_Driver::IsUnixPath(const char *s) { - if ( !s ) return false; // NULL? - if ( strchr(s, '\\') ) return false; // windows style? - if ( strchr(s, '/') ) return true; // unix style? - return false; // no slashes? assume native windows -} - -// SAVE THE CURRENT WORKING DIRECTORY -// Returns a malloc()ed copy of the cwd that can -// later be freed with RestoreCWD(). May return 0 on error. -// -static char *SaveCWD() { - char *thecwd = 0; - DWORD thecwdsz = GetCurrentDirectory(0,0); - if ( thecwdsz > 0 ) { - thecwd = (char*)malloc(thecwdsz); - if (GetCurrentDirectory(thecwdsz, thecwd) == 0 ) { - free(thecwd); thecwd = 0; - } - } - return thecwd; -} - -// RESTORES THE CWD SAVED BY SaveCWD(), FREES STRING -// Always returns NULL (string was freed). -// -static void RestoreCWD(char *thecwd) { - if ( !thecwd ) return; - SetCurrentDirectory(thecwd); - free(thecwd); -} - -// SHOW FILE BROWSER -int Fl_WinAPI_Native_File_Chooser_Driver::showfile() { - bool unixpath = IsUnixPath(_directory) || IsUnixPath(_preset_file); // caller uses unix paths? - ClearOFN(); - clear_pathnames(); - size_t fsize = FNFC_MAX_PATH; - _ofn_ptr->Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes - _ofn_ptr->Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag - // USE NEW BROWSER - _ofn_ptr->Flags |= OFN_EXPLORER; // use newer explorer windows - _ofn_ptr->Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?) - _ofn_ptr->Flags |= OFN_NOCHANGEDIR; // XXX: docs say ineffective on XP/2K/NT, but set it anyway.. - - switch ( _btype ) { - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - abort(); // never happens: handled by showdir() - case Fl_Native_File_Chooser::BROWSE_FILE: - break; - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: - _ofn_ptr->Flags |= OFN_ALLOWMULTISELECT; - break; - case Fl_Native_File_Chooser::BROWSE_SAVE_FILE: - if ( options() & Fl_Native_File_Chooser::SAVEAS_CONFIRM && type() == Fl_Native_File_Chooser::BROWSE_SAVE_FILE ) { - _ofn_ptr->Flags |= OFN_OVERWRITEPROMPT; - } - break; - } - // SPACE FOR RETURNED FILENAME - _ofn_ptr->lpstrFile = new WCHAR[fsize]; - _ofn_ptr->nMaxFile = (DWORD)(fsize-1); - _ofn_ptr->lpstrFile[0] = 0; - _ofn_ptr->lpstrFile[1] = 0; // dnull - // PARENT WINDOW - _ofn_ptr->hwndOwner = GetForegroundWindow(); - // DIALOG TITLE - if (_title) { - static WCHAR wtitle[200]; - wcsncpy(wtitle, utf8towchar(_title), 200); - wtitle[200-1] = 0; - _ofn_ptr->lpstrTitle = wtitle; - } else { - _ofn_ptr->lpstrTitle = NULL; - } - // FILTER - if (_parsedfilt != NULL) { // to convert a null-containing char string into a widechar string - // NEW - if ( !_wpattern ) _wpattern = new WCHAR[FNFC_MAX_PATH]; - const char *p = _parsedfilt; - while(*(p + strlen(p) + 1) != 0) p += strlen(p) + 1; - p += strlen(p) + 2; - MultiByteToWideChar(CP_UTF8, 0, _parsedfilt, (int) (p - _parsedfilt), _wpattern, FNFC_MAX_PATH); - _ofn_ptr->lpstrFilter = _wpattern; - } else { - _ofn_ptr->lpstrFilter = NULL; - } - // PRESET FILE - // If set, supercedes _directory. See KB Q86920 for details - // XXX: this doesn't preselect the item in the listview.. why? - // - if ( _preset_file ) { - // Temp copy of _dirname we can convert to windows path if needed - char *winpath = fl_strdup(_preset_file); - if ( unixpath ) Unix2Win(winpath); - size_t len = strlen(winpath); - if ( len >= _ofn_ptr->nMaxFile ) { - char msg[80]; - snprintf(msg, 80, "preset_file() filename is too long: %ld is >=%ld", (long)len, (long)fsize); - errmsg(msg); - return(-1); - } - wcscpy(_ofn_ptr->lpstrFile, utf8towchar(winpath)); - len = wcslen(_ofn_ptr->lpstrFile); - _ofn_ptr->lpstrFile[len+0] = 0; // multiselect needs dnull - _ofn_ptr->lpstrFile[len+1] = 0; - free(winpath); // free temp copy now that we have a new wchar - //wprintf(L"lpstrFile is '%ls'\n", (WCHAR*)(_ofn_ptr->lpstrFile)); - } - // PRESET DIR - // XXX: See KB Q86920 for doc bug: - // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920 - // - if ( _directory ) { - // Temp copy of _dirname we can convert to windows path if needed - char *winpath = fl_strdup(_directory); - // Caller specified unix front slash path? - // If so, convert to backslashes; windows native browser mishandles unix style paths. - // We'll convert back to unix style when dialog completes. - // - if ( unixpath ) Unix2Win(winpath); - // Make a wide char version of potentially utf8 string - _ofn_ptr->lpstrInitialDir = new WCHAR[FNFC_MAX_PATH]; - wcscpy((WCHAR *)_ofn_ptr->lpstrInitialDir, utf8towchar(winpath)); - free(winpath); // free temp copy now that we have a new wchar - //wprintf(L"lpstrInitialDir is '%ls'\n", (WCHAR*)(_ofn_ptr->lpstrInitialDir)); - } - // SAVE THE CURRENT DIRECTORY - // See above warning (XXX) for OFN_NOCHANGEDIR - // - char *save_cwd = SaveCWD(); // must be freed with RestoreCWD() - // OPEN THE DIALOG WINDOW - int err; - if ( _btype == Fl_Native_File_Chooser::BROWSE_SAVE_FILE ) { - err = GetSaveFileNameW(_ofn_ptr); - } else { - err = GetOpenFileNameW(_ofn_ptr); - } - // GET EXTENDED ERROR - int exterr = CommDlgExtendedError(); - // RESTORE CURRENT DIRECTORY - RestoreCWD(save_cwd); save_cwd = 0; // also frees save_cwd - // ERROR OR CANCEL? - if ( err == 0 ) { - if ( exterr == 0 ) return(1); // user hit cancel - // Otherwise, an error occurred.. - char msg[80]; - snprintf(msg, 80, "CommDlgExtendedError() code=%d", exterr); - errmsg(msg); - return(-1); - } - // PREPARE PATHNAMES FOR RETURN - switch ( _btype ) { - case Fl_Native_File_Chooser::BROWSE_FILE: - case Fl_Native_File_Chooser::BROWSE_SAVE_FILE: - set_single_pathname(wchartoutf8(_ofn_ptr->lpstrFile)); - if ( unixpath ) Win2Unix(_pathnames[_tpathnames-1]); // preserve unix style path - break; - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: { - // EXTRACT MULTIPLE FILENAMES - const WCHAR *dirname = _ofn_ptr->lpstrFile; - size_t dirlen = wcslen(dirname); - if ( dirlen > 0 ) { - // WALK STRING SEARCHING FOR 'DOUBLE-NULL' - // eg. "/dir/name\0foo1\0foo2\0foo3\0\0" - // - char pathname[FNFC_MAX_PATH]; - for ( const WCHAR *s = dirname + dirlen + 1; *s; s += (wcslen(s)+1)) { - // ISSUE #206: replace strncpy/cat with fl_strlcpy/cat - fl_strlcpy(pathname, wchartoutf8(dirname), FNFC_MAX_PATH); - fl_strlcat(pathname, "\\", FNFC_MAX_PATH); - fl_strlcat(pathname, wchartoutf8(s), FNFC_MAX_PATH); - add_pathname(pathname); - } - } - // XXX - // Work around problem where pasted forward-slash pathname - // into the file browser causes new "Explorer" interface - // not to grok forward slashes, passing back as a 'filename'..! - // - if ( _tpathnames == 0 ) { - add_pathname(wchartoutf8(dirname)); - } - // Caller specified unix path? Return unix paths - if ( unixpath ) { - for ( int t=0; t<_tpathnames; t++ ) { - Win2Unix(_pathnames[t]); - } - } - break; - } - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - abort(); // never happens: handled by showdir() - } - return(0); -} - -// Used by SHBrowseForFolder(), sets initial selected dir. -// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes -// Subject: How to specify to select an initial folder .." -// -static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) { - switch (msg) { - case BFFM_INITIALIZED: - if (data) ::SendMessageW(win, BFFM_SETSELECTIONW, TRUE, data); - break; - case BFFM_SELCHANGED: - TCHAR path[FNFC_MAX_PATH]; - if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) { - ::SendMessage(win, BFFM_ENABLEOK, 0, 1); - } else { - // disable ok button if not a path - ::SendMessage(win, BFFM_ENABLEOK, 0, 0); - } - break; - case BFFM_VALIDATEFAILED: - // we could pop up an annoying message here. - // also needs set ulFlags |= BIF_VALIDATE - break; - default: - break; - } - return(0); -} - -// SHOW DIRECTORY BROWSER -int Fl_WinAPI_Native_File_Chooser_Driver::showdir() { - bool unixpath = IsUnixPath(_directory); // caller uses unix paths? - // initialize OLE only once - fl_open_display(); // init needed by BIF_USENEWUI - ClearBINF(); - clear_pathnames(); - // PARENT WINDOW - _binf_ptr->hwndOwner = GetForegroundWindow(); - // DIALOG TITLE - //_binf_ptr->lpszTitle = _title ? _title : NULL; - if (_title) { - static WCHAR wtitle[256]; - wcsncpy(wtitle, utf8towchar(_title), 256); - wtitle[255] = 0; - _binf_ptr->lpszTitle = wtitle; - } else { - _binf_ptr->lpszTitle = NULL; - } - - // FLAGS - _binf_ptr->ulFlags = 0; // initialize - - // TBD: make sure matches to runtime system, if need be. - //(what if _WIN32_IE doesn't match system? does the program not run?) - // - // TBD: match all 3 types of directories - // - // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares - // from being visible in BROWSE_DIRECTORY mode. Walter Garm's comments: - // - // --- Garms, Walter (GE EntSol, Security) wrote: - // With your help I was able to solve the problem of the network drives. - // For Version 6.0, at least, the BIF_SHAREABLE flag seems to have the - // opposite sense: With BIF_SHAREABLE not set I see the mapped network - // drives, and with BIF_SHAREABLE set I do not. - // --- - -#if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0 - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_NONEWFOLDERBUTTON; - _binf_ptr->ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS; -#elif defined(BIF_USENEWUI) // Version 5.0 - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_EDITBOX; - else if ( _btype == Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_USENEWUI; - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS; -#elif defined(BIF_EDITBOX) // Version 4.71 - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX; -#else // Version Old - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS; -#endif - - // BUFFER - //char displayname[FNFC_MAX_PATH]; - WCHAR displayname[FNFC_MAX_PATH]; - _binf_ptr->pszDisplayName = displayname; - - // PRESET DIR - WCHAR presetname[FNFC_MAX_PATH]; - if ( _directory ) { - // Temp copy of _dirname we can convert to windows path if needed - char *winpath = fl_strdup(_directory); - // Caller specified unix front slash path? - // If so, convert to backslashes; windows native browser mishandles unix style paths. - // We'll convert back to unix style when dialog completes. - // - if ( unixpath ) Unix2Win(winpath); - // Wide char version of potentially utf8 string - wcsncpy(presetname, utf8towchar(winpath), FNFC_MAX_PATH); - free(winpath); // free temp copy now that we have a new wchar - presetname[FNFC_MAX_PATH-1] = 0; // dnull - presetname[FNFC_MAX_PATH-2] = 0; - _binf_ptr->lParam = (LPARAM)presetname; - //wprintf(L"presetname is '%ls'\n", (WCHAR*)(presetname)); - } - else _binf_ptr->lParam = 0; - _binf_ptr->lpfn = Dir_CB; - // OPEN BROWSER - LPITEMIDLIST pidl = SHBrowseForFolderW(_binf_ptr); - // CANCEL? - if ( pidl == NULL ) return(1); - - // GET THE PATHNAME(S) THE USER SELECTED - // TBD: expand NetHood shortcuts from this PIDL?? - // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp - - WCHAR path[FNFC_MAX_PATH]; - if ( SHGetPathFromIDListW(pidl, path) ) { - add_pathname(wchartoutf8(path)); - if ( unixpath ) Win2Unix(_pathnames[_tpathnames-1]); // preserve unix style path - } - FreePIDL(pidl); - if ( !wcslen(path) ) return(1); // don't return empty pathnames - return(0); -} - -// RETURNS: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_WinAPI_Native_File_Chooser_Driver::show() { - int retval; - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY || - _btype == Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY || - _btype == Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY ) { - retval = showdir(); - } else { - retval = showfile(); - } - // restore the correct state of mouse buttons and keyboard modifier keys (STR #3221) - HWND h = GetForegroundWindow(); - if (h) { - WNDPROC windproc = (WNDPROC)GetWindowLongPtrW(h, GWLP_WNDPROC); - CallWindowProc(windproc, h, WM_ACTIVATEAPP, 1, 0); - } - return retval; -} - -// RETURN ERROR MESSAGE -const char *Fl_WinAPI_Native_File_Chooser_Driver::errmsg() const { - return(_errmsg ? _errmsg : "No error"); -} - -// GET FILENAME -const char* Fl_WinAPI_Native_File_Chooser_Driver::filename() const { - if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); - return(""); -} - -// GET FILENAME FROM LIST OF FILENAMES -const char* Fl_WinAPI_Native_File_Chooser_Driver::filename(int i) const { - if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); - return(""); -} - -// GET TOTAL FILENAMES CHOSEN -int Fl_WinAPI_Native_File_Chooser_Driver::count() const { - return(_tpathnames); -} - -// PRESET PATHNAME -// Can be NULL if no preset is desired. -// -void Fl_WinAPI_Native_File_Chooser_Driver::directory(const char *val) { - _directory = strfree(_directory); - _directory = strnew(val); -} - -// GET PRESET PATHNAME -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::directory() const { - return(_directory); -} - -// SET TITLE -// Can be NULL if no title desired. -// -void Fl_WinAPI_Native_File_Chooser_Driver::title(const char *val) { - _title = strfree(_title); - _title = strnew(val); -} - -// GET TITLE -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::title() const { - return(_title); -} - -// SET FILTER -// Can be NULL if no filter needed -// -void Fl_WinAPI_Native_File_Chooser_Driver::filter(const char *val) { - _filter = strfree(_filter); - clear_filters(); - if ( val ) { - _filter = strnew(val); - parse_filter(_filter); - } - add_filter("All Files", "*.*"); // always include 'all files' option - -#ifdef DEBUG - dnullprint(_parsedfilt); -#endif /*DEBUG*/ -} - -// GET FILTER -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::filter() const { - return(_filter); -} - -// CLEAR FILTERS -void Fl_WinAPI_Native_File_Chooser_Driver::clear_filters() { - _nfilters = 0; - _parsedfilt = strfree(_parsedfilt); -} - -// ADD A FILTER -void Fl_WinAPI_Native_File_Chooser_Driver::add_filter(const char *name_in, // name of filter (optional: can be null) - const char *winfilter) { // windows style filter (eg. "*.cxx;*.h") - // No name? Make one.. - char name[1024]; - if ( !name_in || name_in[0] == '\0' ) { - snprintf(name, sizeof(name), "%.*s Files", int(sizeof(name)-10), winfilter); - } else { - if ((strlen(name_in)+strlen(winfilter)+3) < sizeof(name)) { - snprintf(name, sizeof(name), "%s (%s)", name_in, winfilter); - } else { - snprintf(name, sizeof(name), "%.*s", int(sizeof(name))-1, name_in); - } - } - dnullcat(_parsedfilt, name); - dnullcat(_parsedfilt, winfilter); - _nfilters++; - //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter); -} - -// RETURN HOW MANY DIFFERENT FILTERS WERE SPECIFIED -// In: "foo.[CH]" or "foo.{C,H}" -// Out: 2 -// -static int count_filters(const char *filter) { - int count = 0; - char mode = 0; - const char *in = filter; - while (*in) { - switch(*in) { - case '\\': // escape next character - ++in; if ( *in == 0 ) continue; // skip escape. EOL? done - ++in; // skip escaped char - continue; - case LCURLY_CHR: // start "{aaa,bbb}" - mode = *in; // set mode, parse over curly - ++count; // at least +1 wildcard - break; - case RCURLY_CHR: // end "{aaa,bbb}" - if ( mode == LCURLY_CHR ) // disable curly mode (if on) - mode = 0; - break; - case LBRACKET_CHR: // start "[xyz]" - mode = *in; // set mode, parse over bracket - break; - case RBRACKET_CHR: // end "[xyz]" - if ( mode == LBRACKET_CHR ) // disable bracket mode (if on) - mode = 0; - break; - default: // any other char - switch (mode) { // handle {} or [] modes - case LCURLY_CHR: // handle "{aaa,bbb}" - if (*in==',' || *in=='|') // ',' and '|' adds filters - ++count; - break; - case LBRACKET_CHR: // handle "[xyz]" - ++count; // all chars in []'s add new filter - break; - } - break; - } - ++in; // parse past char - } - return count > 0 ? count : 1; // return at least 1 -} - -// Convert FLTK style pattern matches to windows 'double-null' pattern -// Returns with the parsed double-null result in '_parsedfilt'. -// -// Handles: -// IN OUT -// ----------- ----------------------------- -// *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0" -// *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0" -// *.txt "*.txt Files\0*.txt\0\0" -// C Files\t*.[ch] "C Files\0*.c;*.h\0\0" -// -// Example: -// IN: "*.{ma,mb}" -// OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0" -// --------------- --------- --------- --- -// | | | | -// Title Wildcards Title Wildcards -// -// Parsing Mode: -// IN:"C Files\t*.{cxx,h}" -// ||||||| ||||||||| -// mode: nnnnnnn ww{{{{{{{ -// \_____/ \_______/ -// Name Wildcard -// -void Fl_WinAPI_Native_File_Chooser_Driver::parse_filter(const char *in) { - clear_filters(); - if ( ! in || in[0] == '\0' ) return; - - int has_name = strchr(in, '\t') ? 1 : 0; - char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard - - // whatever input string is, our output won't be much longer in length.. - // use double length just for safety. - size_t slen = strlen(in); - char *wildprefix = new char[(slen+1)*2]; wildprefix[0] = 0; - char *comp = new char[(slen+1)*2]; comp[0] = 0; - char *name = new char[(slen+1)*2]; name[0] = 0; - - // Init - int nwildcards = 0; - int maxfilters = count_filters(in) + 1; // count wildcard seps - char **wildcards = new char*[maxfilters]; // parsed wildcards (can be several) - int t; - for ( t=0; t<maxfilters; t++ ) { - wildcards[t] = new char[slen+1]; - wildcards[t][0] = '\0'; - } - - // Parse - for ( ; 1; in++ ) { - - // DEBUG - // printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n", - // *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]); - - switch (*in) { - case ',': - case '|': - if ( mode == LCURLY_CHR ) { - // create new wildcard, copy in prefix - strcat(wildcards[nwildcards++], wildprefix); - continue; - } else { - goto regchar; - } - continue; - - // FINISHED PARSING A NAME? - case '\t': - if ( mode != 'n' ) goto regchar; - // finish parsing name? switch to wildcard mode - mode = 'w'; - break; - - // ESCAPE NEXT CHAR - case '\\': - ++in; - goto regchar; - - // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? - case '\r': - case '\n': - case '\0': - { - if ( mode == 'w' ) { // finished parsing wildcard? - if ( nwildcards == 0 ) { - strcpy(wildcards[nwildcards++], wildprefix); - } - // Append wildcards in Microsoft's "*.one;*.two" format - comp[0] = 0; - for ( t=0; t<nwildcards; t++ ) { - if ( t != 0 ) strcat(comp, ";"); - strcat(comp, wildcards[t]); - } - // Add if not empty - if ( comp[0] ) { - add_filter(name, comp); - } - } - // RESET - for ( t=0; t<maxfilters; t++ ) { - wildcards[t][0] = '\0'; - } - nwildcards = 0; - wildprefix[0] = name[0] = '\0'; - mode = strchr(in,'\t') ? 'n' : 'w'; - // DONE? - if ( *in == '\0' ) { // done - // Free everything - delete[] wildprefix; - delete[] comp; - delete[] name; - for ( t=0; t<maxfilters; t++ ) delete[] wildcards[t]; - delete[] wildcards; - return; - } - continue; // not done yet, more filters - } - - // STARTING A WILDCARD? - case LBRACKET_CHR: - case LCURLY_CHR: - mode = *in; - if ( *in == LCURLY_CHR ) { - // create new wildcard - strcat(wildcards[nwildcards++], wildprefix); - } - continue; - - // ENDING A WILDCARD? - case RBRACKET_CHR: - case RCURLY_CHR: - mode = 'w'; // back to wildcard mode - continue; - - // ALL OTHER NON-SPECIAL CHARACTERS - default: - regchar: // handle regular char - switch ( mode ) { - case LBRACKET_CHR: - // create new wildcard - ++nwildcards; - // copy in prefix - strcpy(wildcards[nwildcards-1], wildprefix); - // append search char - chrcat(wildcards[nwildcards-1], *in); - continue; - - case LCURLY_CHR: - if ( nwildcards > 0 ) { - chrcat(wildcards[nwildcards-1], *in); - } - continue; - - case 'n': - chrcat(name, *in); - continue; - - case 'w': - chrcat(wildprefix, *in); - for ( t=0; t<nwildcards; t++ ) { - chrcat(wildcards[t], *in); - } - continue; - } - break; - } - } -} - -// SET 'CURRENTLY SELECTED FILTER' -void Fl_WinAPI_Native_File_Chooser_Driver::filter_value(int i) { - _ofn_ptr->nFilterIndex = i + 1; -} - -// RETURN VALUE OF 'CURRENTLY SELECTED FILTER' -int Fl_WinAPI_Native_File_Chooser_Driver::filter_value() const { - return(_ofn_ptr->nFilterIndex ? _ofn_ptr->nFilterIndex-1 : _nfilters+1); -} - -// PRESET FILENAME FOR 'SAVE AS' CHOOSER -void Fl_WinAPI_Native_File_Chooser_Driver::preset_file(const char* val) { - _preset_file = strfree(_preset_file); - _preset_file = strnew(val); -} - -// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER -const char* Fl_WinAPI_Native_File_Chooser_Driver::preset_file() const { - return(_preset_file); -} - -int Fl_WinAPI_Native_File_Chooser_Driver::filters() const { - return(_nfilters); -} - -static char *wchartoutf8(LPCWSTR in) { - static char *out = NULL; - static int lchar = 0; - if (in == NULL)return NULL; - int utf8len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); - if (utf8len > lchar) { - lchar = utf8len; - out = (char *)realloc(out, lchar * sizeof(char)); - } - WideCharToMultiByte(CP_UTF8, 0, in, -1, out, utf8len, NULL, NULL); - return out; -} - -static LPCWSTR utf8towchar(const char *in) { - static WCHAR *wout = NULL; - static int lwout = 0; - if (in == NULL)return NULL; - int wlen = MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0); - if (wlen > lwout) { - lwout = wlen; - wout = (WCHAR *)realloc(wout, lwout * sizeof(WCHAR)); - } - MultiByteToWideChar(CP_UTF8, 0, in, -1, wout, wlen); - return wout; -} - -#endif /* !FL_DOXYGEN */ diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm deleted file mode 100644 index 02e66ed43..000000000 --- a/src/Fl_cocoa.mm +++ /dev/null @@ -1,4793 +0,0 @@ -// -// macOS-Cocoa specific code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -extern "C" { -#include <pthread.h> -} - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include "Fl_Window_Driver.H" -#include "Fl_Screen_Driver.H" -#include "Fl_Timeout.h" -#include <FL/Fl_Window.H> -#include <FL/Fl_Tooltip.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/fl_draw.H> -#include <FL/Fl_Rect.H> -#include <FL/fl_string_functions.h> -#include "drivers/Quartz/Fl_Quartz_Graphics_Driver.H" -#include "drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H" -#include "drivers/Cocoa/Fl_Cocoa_Screen_Driver.H" -#include "drivers/Cocoa/Fl_Cocoa_Window_Driver.H" -#include "drivers/Darwin/Fl_Darwin_System_Driver.H" -#include "drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H" -#include "print_button.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdarg.h> -#include <math.h> -#include <limits.h> -#include <dlfcn.h> -#include <string.h> -#include <pwd.h> - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 -# error macOS SDK and deployment target version 10.7 or higher is required. -// Note: change also the warning in Fl_Darwin_System_Driver::calc_mac_os_version() below -#endif - -#import <Cocoa/Cocoa.h> -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 -# import <ScreenCaptureKit/ScreenCaptureKit.h> -#endif - -// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING -#ifdef DEBUG_SELECT -#include <stdio.h> // testing -#define DEBUGMSG(msg) if ( msg ) fprintf(stderr, msg); -#define DEBUGPERRORMSG(msg) if ( msg ) perror(msg) -#define DEBUGTEXT(txt) txt -#else -#define DEBUGMSG(msg) -#define DEBUGPERRORMSG(msg) -#define DEBUGTEXT(txt) NULL -#endif /*DEBUG_SELECT*/ - -// external functions -extern void fl_fix_focus(); -extern int fl_send_system_handlers(void *e); - -// forward definition of functions in this file -// converting cr lf converter function -static void createAppleMenu(void); -static void cocoaMouseHandler(NSEvent *theEvent); -#if defined(FLTK_HAVE_PEN_SUPPORT) -static bool cocoaTabletHandler(NSEvent *theEvent, bool lock); -extern bool fl_cocoa_tablet_handler(NSEvent*, Fl_Window*); -#endif -static void clipboard_check(void); -static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, int w, int h); -static NSBitmapImageRep* rect_to_NSBitmapImageRep_subwins(Fl_Window *win, int x, int y, int w, int h, bool capture_subwins); -static void drain_dropped_files_list(void); -static NSPoint FLTKtoCocoa(Fl_Window *win, int x, int y, int H); -static int get_window_frame_sizes(Fl_Window *win, int *pbx = NULL, int *pby = NULL); - -int fl_mac_os_version = Fl_Darwin_System_Driver::calc_mac_os_version(); // the version number of the running Mac OS X (e.g., 100604 for 10.6.4) - -// public variables -void *fl_capture = 0; // (NSWindow*) we need this to compensate for a missing(?) mouse capture -FLWindow *fl_window; - -// forward declarations of variables in this file -static int main_screen_height; // height of menubar-containing screen used to convert between Cocoa and FLTK global screen coordinates -// through_drawRect = YES means the drawRect: message was sent to the view, -// thus the graphics context was prepared by the system -static BOOL through_drawRect = NO; -// through_Fl_X_flush = YES means Fl_Cocoa_Window_Driver::flush() was called -static BOOL through_Fl_X_flush = NO; -static BOOL views_use_CA = NO; // YES means views are layer-backed, as on macOS 10.14 when linked with SDK 10.14 -static int im_enabled = -1; - -// OS version-dependent pasteboard type names. -// the next 5 deprecation/availability warnings can be legitimately ignored -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wunguarded-availability" -static NSString *TIFF_pasteboard_type = NSPasteboardTypeTIFF; -static NSString *PDF_pasteboard_type = NSPasteboardTypePDF; -static NSString *PICT_pasteboard_type = @"com.apple.pict"; -static NSString *UTF8_pasteboard_type = NSPasteboardTypeString; -static NSString *fl_filenames_pboard_type = -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 - (fl_mac_os_version >= 101300 ? NSPasteboardTypeFileURL : NSFilenamesPboardType); -#else - NSFilenamesPboardType; -#endif -#pragma clang diagnostic pop - -static bool in_nsapp_run = false; // true during execution of [NSApp run] -static NSMutableArray *dropped_files_list = nil; // list of files dropped at app launch -typedef void (*open_cb_f_type)(const char *); -static Fl_Window *starting_moved_window = NULL; // the moved window which brings its subwins with it - -enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; - -// Carbon functions and definitions - -typedef void *TSMDocumentID; - -extern "C" enum { - kTSMDocumentEnabledInputSourcesPropertyTag = 'enis' // from Carbon/TextServices.h -}; - -// Undocumented voodoo. Taken from Mozilla. -static const int smEnableRomanKybdsOnly = -23; - -typedef TSMDocumentID (*TSMGetActiveDocument_type)(void); -static TSMGetActiveDocument_type TSMGetActiveDocument; -typedef OSStatus (*TSMSetDocumentProperty_type)(TSMDocumentID, OSType, UInt32, void*); -static TSMSetDocumentProperty_type TSMSetDocumentProperty; -typedef OSStatus (*TSMRemoveDocumentProperty_type)(TSMDocumentID, OSType); -static TSMRemoveDocumentProperty_type TSMRemoveDocumentProperty; -typedef CFArrayRef (*TISCreateInputSourceList_type)(CFDictionaryRef, Boolean); -static TISCreateInputSourceList_type TISCreateInputSourceList; -static CFStringRef kTISTypeKeyboardLayout; -static CFStringRef kTISPropertyInputSourceType; - -typedef void (*KeyScript_type)(short); -static KeyScript_type KeyScript; - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 -const NSInteger NSControlStateValueOn = NSOnState; -const NSInteger NSControlStateValueOff = NSOffState; -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -const NSUInteger NSEventModifierFlagCommand = NSCommandKeyMask; -const NSUInteger NSEventModifierFlagOption = NSAlternateKeyMask; -const NSUInteger NSEventModifierFlagControl = NSControlKeyMask; -const NSUInteger NSEventModifierFlagShift = NSShiftKeyMask; -const NSUInteger NSEventModifierFlagCapsLock = NSAlphaShiftKeyMask; - -const NSEventType NSEventTypeLeftMouseDown = NSLeftMouseDown; -const NSEventType NSEventTypeRightMouseDown = NSRightMouseDown; -const NSEventType NSEventTypeOtherMouseDown = NSOtherMouseDown; -const NSEventType NSEventTypeLeftMouseUp = NSLeftMouseUp; -const NSEventType NSEventTypeRightMouseUp = NSRightMouseUp; -const NSEventType NSEventTypeOtherMouseUp = NSOtherMouseUp; -const NSEventType NSEventTypeLeftMouseDragged = NSLeftMouseDragged; -const NSEventType NSEventTypeRightMouseDragged = NSRightMouseDragged; -const NSEventType NSEventTypeOtherMouseDragged = NSOtherMouseDragged; -const NSEventType NSEventTypeMouseMoved = NSMouseMoved; -const NSEventType NSEventTypeMouseEntered = NSMouseEntered; -const NSEventType NSEventTypeMouseExited = NSMouseExited; -const NSEventType NSEventTypeKeyUp = NSKeyUp; -const NSEventType NSEventTypeApplicationDefined = NSApplicationDefined; - -const NSUInteger NSWindowStyleMaskResizable = NSResizableWindowMask; -const NSUInteger NSWindowStyleMaskBorderless = NSBorderlessWindowMask; -const NSUInteger NSWindowStyleMaskMiniaturizable = NSMiniaturizableWindowMask; -const NSUInteger NSWindowStyleMaskClosable = NSClosableWindowMask; -const NSUInteger NSWindowStyleMaskTitled = NSTitledWindowMask; -const NSUInteger NSWindowStyleMaskFullScreen = NSFullScreenWindowMask; - -const NSUInteger NSEventMaskAny = NSAnyEventMask; -const NSUInteger NSEventMaskSystemDefined = NSSystemDefinedMask; - -const NSUInteger NSBitmapFormatAlphaFirst = NSAlphaFirstBitmapFormat; -const NSUInteger NSBitmapFormatAlphaNonpremultiplied = NSAlphaNonpremultipliedBitmapFormat; -const short NSEventSubtypeTabletProximity = NSTabletProximityEventSubtype; -const short NSEventSubtypeTabletPoint = NSTabletPointEventSubtype; -const NSUInteger NSEventModifierFlagFunction = NSFunctionKeyMask; -#endif - -/* - * Mac keyboard lookup table - */ -static unsigned short* macKeyLookUp = NULL; - -/* - * convert the current mouse chord into the FLTK modifier state - */ -static unsigned int mods_to_e_state( NSUInteger mods ) -{ - unsigned int state = 0; - if ( mods & NSEventModifierFlagCommand ) state |= FL_META; - if ( mods & NSEventModifierFlagOption ) state |= FL_ALT; - if ( mods & NSEventModifierFlagControl ) state |= FL_CTRL; - if ( mods & NSEventModifierFlagShift ) state |= FL_SHIFT; - if ( mods & NSEventModifierFlagCapsLock ) state |= FL_CAPS_LOCK; - unsigned int ret = ( Fl::e_state & 0xff000000 ) | state; - Fl::e_state = ret; - //printf( "State 0x%08x (%04x)\n", Fl::e_state, mods ); - return ret; -} - -// these pointers are set by the Fl::lock() function: -static void nothing() {} -void (*fl_lock_function)() = nothing; -void (*fl_unlock_function)() = nothing; - -// -// Select interface -- how it's implemented: -// When the user app configures one or more file descriptors to monitor -// with Fl::add_fd(), we start a separate thread to select() the data, -// sending a custom OSX 'FLTK data ready event' to the parent thread's -// RunApplicationLoop(), so that it triggers the data ready callbacks -// in the parent thread. -erco 04/04/04 -// -#define POLLIN 1 -#define POLLOUT 4 -#define POLLERR 8 - -// Class to handle select() 'data ready' -class DataReady -{ - struct FD - { - int fd; - short events; - void (*cb)(int, void*); - void* arg; - }; - int nfds, fd_array_size; - FD *fds; - pthread_t tid; // select()'s thread id - - // Data that needs to be locked (all start with '_') - pthread_mutex_t _datalock; // data lock - fd_set _fdsets[3]; // r/w/x sets user wants to monitor - int _maxfd; // max fd count to monitor - int _cancelpipe[2]; // pipe used to help cancel thread - -public: - DataReady() - { - nfds = 0; - fd_array_size = 0; - fds = 0; - tid = 0; - - pthread_mutex_init(&_datalock, NULL); - FD_ZERO(&_fdsets[0]); FD_ZERO(&_fdsets[1]); FD_ZERO(&_fdsets[2]); - _cancelpipe[0] = _cancelpipe[1] = 0; - _maxfd = -1; - } - - ~DataReady() - { - CancelThread(DEBUGTEXT("DESTRUCTOR\n")); - if (fds) { free(fds); fds = 0; } - nfds = 0; - } - - // Locks - // The convention for locks: volatile vars start with '_', - // and must be locked before use. Locked code is prefixed - // with /*LOCK*/ to make painfully obvious esp. in debuggers. -erco - // - void DataLock() { pthread_mutex_lock(&_datalock); } - void DataUnlock() { pthread_mutex_unlock(&_datalock); } - - // Accessors - int IsThreadRunning() { return(tid ? 1 : 0); } - int GetNfds() { return(nfds); } - int GetCancelPipe(int ix) { return(_cancelpipe[ix]); } - fd_set GetFdset(int ix) { return(_fdsets[ix]); } - - // Methods - void AddFD(int n, int events, void (*cb)(int, void*), void *v); - void RemoveFD(int n, int events); - int CheckData(fd_set& r, fd_set& w, fd_set& x); - void HandleData(fd_set& r, fd_set& w, fd_set& x); - static void* DataReadyThread(void *self); - void StartThread(void); - void CancelThread(const char *reason); -}; - -static DataReady dataready; - -void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v) -{ - RemoveFD(n, events); - int i = nfds++; - if (i >= fd_array_size) - { - fl_open_display(); // necessary for NSApp to be defined and the event loop to work - FD *temp; - fd_array_size = 2*fd_array_size+1; - if (!fds) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); } - else { temp = (FD*)realloc(fds, fd_array_size*sizeof(FD)); } - if (!temp) return; - fds = temp; - } - fds[i].cb = cb; - fds[i].arg = v; - fds[i].fd = n; - fds[i].events = events; - DataLock(); - /*LOCK*/ if (events & POLLIN) FD_SET(n, &_fdsets[0]); - /*LOCK*/ if (events & POLLOUT) FD_SET(n, &_fdsets[1]); - /*LOCK*/ if (events & POLLERR) FD_SET(n, &_fdsets[2]); - /*LOCK*/ if (n > _maxfd) _maxfd = n; - DataUnlock(); -} - -// Remove an FD from the array -void DataReady::RemoveFD(int n, int events) -{ - int i,j; - _maxfd = -1; // recalculate maxfd on the fly - for (i=j=0; i<nfds; i++) { - if (fds[i].fd == n) { - int e = fds[i].events & ~events; - if (!e) continue; // if no events left, delete this fd - fds[i].events = e; - } - if (fds[i].fd > _maxfd) _maxfd = fds[i].fd; - // move it down in the array if necessary: - if (j<i) { - fds[j] = fds[i]; - } - j++; - } - nfds = j; - DataLock(); - /*LOCK*/ if (events & POLLIN) FD_CLR(n, &_fdsets[0]); - /*LOCK*/ if (events & POLLOUT) FD_CLR(n, &_fdsets[1]); - /*LOCK*/ if (events & POLLERR) FD_CLR(n, &_fdsets[2]); - DataUnlock(); -} - -// CHECK IF USER DATA READY, RETURNS r/w/x INDICATING WHICH IF ANY -int DataReady::CheckData(fd_set& r, fd_set& w, fd_set& x) -{ - int ret; - DataLock(); - /*LOCK*/ timeval t = { 0, 1 }; // quick check - /*LOCK*/ r = _fdsets[0], w = _fdsets[1], x = _fdsets[2]; - /*LOCK*/ ret = ::select(_maxfd+1, &r, &w, &x, &t); - DataUnlock(); - if ( ret == -1 ) { - DEBUGPERRORMSG("CheckData(): select()"); - } - return(ret); -} - -// HANDLE DATA READY CALLBACKS -void DataReady::HandleData(fd_set& r, fd_set& w, fd_set& x) -{ - for (int i=0; i<nfds; i++) { - int f = fds[i].fd; - short revents = 0; - if (FD_ISSET(f, &r)) revents |= POLLIN; - if (FD_ISSET(f, &w)) revents |= POLLOUT; - if (FD_ISSET(f, &x)) revents |= POLLERR; - if (fds[i].events & revents) { - DEBUGMSG("DOING CALLBACK: "); - fds[i].cb(f, fds[i].arg); - DEBUGMSG("DONE\n"); - } - } -} - -// DATA READY THREAD -// This thread watches for changes in user's file descriptors. -// Sends a 'data ready event' to the main thread if any change. -// -void* DataReady::DataReadyThread(void *o) -{ - DataReady *self = (DataReady*)o; - while ( 1 ) { // loop until thread cancel or error - // Thread safe local copies of data before each select() - self->DataLock(); - /*LOCK*/ int maxfd = self->_maxfd; - /*LOCK*/ fd_set r = self->GetFdset(0); - /*LOCK*/ fd_set w = self->GetFdset(1); - /*LOCK*/ fd_set x = self->GetFdset(2); - /*LOCK*/ int cancelpipe = self->GetCancelPipe(0); - /*LOCK*/ if ( cancelpipe > maxfd ) maxfd = cancelpipe; - /*LOCK*/ FD_SET(cancelpipe, &r); // add cancelpipe to fd's to watch - /*LOCK*/ FD_SET(cancelpipe, &x); - self->DataUnlock(); - // timeval t = { 1000, 0 }; // 1000 seconds; - timeval t = { 2, 0 }; // HACK: 2 secs prevents 'hanging' problem - int ret = ::select(maxfd+1, &r, &w, &x, &t); - pthread_testcancel(); // OSX 10.0.4 and older: needed for parent to cancel - switch ( ret ) { - case 0: // NO DATA - continue; - case -1: // ERROR - { - DEBUGPERRORMSG("CHILD THREAD: select() failed"); - return(NULL); // error? exit thread - } - default: // DATA READY - { - if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel? - { return(NULL); } // just exit - DEBUGMSG("CHILD THREAD: DATA IS READY\n"); - NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined - location:NSMakePoint(0,0) - modifierFlags:0 - timestamp:0 - windowNumber:0 context:NULL subtype:FLTKDataReadyEvent data1:0 data2:0]; - [NSApp postEvent:event atStart:NO]; - [localPool release]; - return(NULL); // done with thread - } - } - } -} - -// START 'DATA READY' THREAD RUNNING, CREATE INTER-THREAD PIPE -void DataReady::StartThread(void) -{ - CancelThread(DEBUGTEXT("STARTING NEW THREAD\n")); - DataLock(); - /*LOCK*/ pipe(_cancelpipe); // pipe for sending cancel msg to thread - DataUnlock(); - DEBUGMSG("*** START THREAD\n"); - pthread_create(&tid, NULL, DataReadyThread, (void*)this); -} - -// CANCEL 'DATA READY' THREAD, CLOSE PIPE -void DataReady::CancelThread(const char *reason) -{ - if ( tid ) { - DEBUGMSG("*** CANCEL THREAD: "); - DEBUGMSG(reason); - if ( pthread_cancel(tid) == 0 ) { // cancel first - DataLock(); - /*LOCK*/ write(_cancelpipe[1], "x", 1); // wake thread from select - DataUnlock(); - pthread_join(tid, NULL); // wait for thread to finish - } - tid = 0; - DEBUGMSG("(JOINED) OK\n"); - } - // Close pipe if open - DataLock(); - /*LOCK*/ if ( _cancelpipe[0] ) { close(_cancelpipe[0]); _cancelpipe[0] = 0; } - /*LOCK*/ if ( _cancelpipe[1] ) { close(_cancelpipe[1]); _cancelpipe[1] = 0; } - DataUnlock(); -} - -void Fl_Darwin_System_Driver::add_fd( int n, int events, void (*cb)(int, void*), void *v ) -{ - dataready.AddFD(n, events, cb, v); -} - -void Fl_Darwin_System_Driver::add_fd(int fd, void (*cb)(int, void*), void* v) -{ - dataready.AddFD(fd, POLLIN, cb, v); -} - -void Fl_Darwin_System_Driver::remove_fd(int n, int events) -{ - dataready.RemoveFD(n, events); -} - -void Fl_Darwin_System_Driver::remove_fd(int n) -{ - dataready.RemoveFD(n, -1); -} - -/* - * Check if there is actually a message pending - */ -int Fl_Darwin_System_Driver::ready() - -{ - NSEvent *retval = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:[NSDate dateWithTimeIntervalSinceNow:0] - inMode:NSDefaultRunLoopMode - dequeue:NO]; - return retval != nil; -} - - -static void processFLTKEvent(void) { - fl_lock_function(); - dataready.CancelThread(DEBUGTEXT("DATA READY EVENT\n")); - - // CHILD THREAD TELLS US DATA READY - // Check to see what's ready, and invoke user's cb's - // - fd_set r,w,x; - switch(dataready.CheckData(r,w,x)) { - case 0: // NO DATA - break; - case -1: // ERROR - break; - default: // DATA READY - dataready.HandleData(r,w,x); - break; - } - fl_unlock_function(); - return; -} - - -/* - * break the current event loop - */ -void Fl_Cocoa_Screen_Driver::breakMacEventLoop() -{ - NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined - location:NSMakePoint(0,0) - modifierFlags:0 timestamp:0 - windowNumber:0 context:NULL - subtype:FLTKTimerEvent - data1:0 - data2:0]; - [NSApp postEvent:event atStart:NO]; -} - - -@interface FLWindow : NSWindow { - Fl_Window *w; -} -- (FLWindow*)initWithFl_W:(Fl_Window *)flw - contentRect:(NSRect)rect - styleMask:(NSUInteger)windowStyle; -- (Fl_Window *)getFl_Window; -- (void)recursivelySendToSubwindows:(SEL)sel applyToSelf:(BOOL)b; -- (void)setSubwindowFrame; -- (void)checkSubwindowFrame; -- (void)waitForExpose; -- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen; -- (NSPoint)convertBaseToScreen:(NSPoint)aPoint; -- (NSBitmapImageRep*)rect_to_NSBitmapImageRep:(Fl_Rect*)r; -- (void)makeKeyWindow; -@end - - -@interface FLView : NSView <NSTextInput, NSTextInputClient, NSDraggingSource> { - BOOL in_key_event; // YES means keypress is being processed by handleEvent - BOOL need_handle; // YES means Fl::handle(FL_KEYBOARD,) is needed after handleEvent processing - NSInteger identifier; - NSRange selectedRange; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -@public - CGContextRef aux_bitmap; // all drawing to view goes there and is finally copied to the CALayer -#endif -} -+ (void)prepareEtext:(NSString*)aString; -+ (void)concatEtext:(NSString*)aString; -- (BOOL)process_keydown:(NSEvent*)theEvent; -- (id)initWithFrame:(NSRect)frameRect; -- (void)drawRect:(NSRect)rect; -- (BOOL)acceptsFirstResponder; -- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; -- (void)resetCursorRects; -- (BOOL)performKeyEquivalent:(NSEvent*)theEvent; -- (void)mouseUp:(NSEvent *)theEvent; -- (void)rightMouseUp:(NSEvent *)theEvent; -- (void)otherMouseUp:(NSEvent *)theEvent; -- (void)mouseDown:(NSEvent *)theEvent; -- (void)rightMouseDown:(NSEvent *)theEvent; -- (void)otherMouseDown:(NSEvent *)theEvent; -- (void)mouseMoved:(NSEvent *)theEvent; -- (void)mouseEntered:(NSEvent *)theEvent; -- (void)mouseExited:(NSEvent *)theEvent; -- (void)mouseDragged:(NSEvent *)theEvent; -- (void)rightMouseDragged:(NSEvent *)theEvent; -- (void)otherMouseDragged:(NSEvent *)theEvent; -- (void)scrollWheel:(NSEvent *)theEvent; -- (void)magnifyWithEvent:(NSEvent *)theEvent; -- (void)keyDown:(NSEvent *)theEvent; -- (void)keyUp:(NSEvent *)theEvent; -- (void)flagsChanged:(NSEvent *)theEvent; -- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender; -- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender; -- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; -- (void)draggingExited:(id < NSDraggingInfo >)sender; -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal; -- (void)updateTrackingAreas; -- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context; -- (void)draggingSession:(NSDraggingSession *)session - endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation; -- (BOOL)did_view_resolution_change; -#if defined(FLTK_HAVE_PEN_SUPPORT) -- (void)tabletProximity:(NSEvent *)theEvent; -- (void)tabletPoint:(NSEvent *)theEvent; -#endif -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -- (void)create_aux_bitmap:(CGContextRef)gc retina:(BOOL)r; -- (void)reset_aux_bitmap; -#endif -@end - - -@implementation FLWindow -- (void)close -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA) [(FLView*)[self contentView] reset_aux_bitmap]; -#endif - [[self standardWindowButton:NSWindowDocumentIconButton] setImage:nil]; - [super close]; - while (true) { - NSArray *a = [[self contentView] trackingAreas]; - if ([a count] == 0) break; - NSTrackingArea *ta = (NSTrackingArea*)[a objectAtIndex:0]; - [[self contentView] removeTrackingArea:ta]; - } - // when a fullscreen window is closed, windowDidResize may be sent after the close message was sent - // and before the FLWindow receives the final dealloc message - w = NULL; -} -- (NSPoint)convertBaseToScreen:(NSPoint)aPoint -{ - NSRect r = [self convertRectToScreen:NSMakeRect(aPoint.x, aPoint.y, 0, 0)]; - return r.origin; -} -- (FLWindow*)initWithFl_W:(Fl_Window *)flw - contentRect:(NSRect)rect - styleMask:(NSUInteger)windowStyle -{ - self = [super initWithContentRect:rect styleMask:windowStyle backing:NSBackingStoreBuffered defer:NO]; - if (self) { - w = flw; - [self setRestorable:NO]; - } - return self; -} -- (Fl_Window *)getFl_Window -{ - return w; -} - -- (BOOL)canBecomeKeyWindow -{ - if (Fl::modal_ && (Fl::modal_ != w)) - return NO; // prevent the caption to be redrawn as active on click - // when another modal window is currently the key win - return !(!w || w->output() || w->tooltip_window() || w->menu_window() || w->parent()); -} - -- (BOOL)canBecomeMainWindow -{ - if (Fl::modal_ && (Fl::modal_ != w)) - return NO; // prevent the caption to be redrawn as active on click - // when another modal window is currently the key win - - return !(!w || w->tooltip_window() || w->menu_window() || w->parent()); -} - -- (void)recursivelySendToSubwindows:(SEL)sel applyToSelf:(BOOL)b -{ - if (b) [self performSelector:sel]; - NSEnumerator *enumerator = [[self childWindows] objectEnumerator]; - id child; - while ((child = [enumerator nextObject]) != nil) { - if ([child isKindOfClass:[FLWindow class]]) [child recursivelySendToSubwindows:sel applyToSelf:YES]; - } -} - -- (void)setSubwindowFrame { // have the cocoa position and size of a (sub)window follow its FLTK data - Fl_Window *parent = w->window(); - if (!w->visible_r()) return; - NSPoint pt = FLTKtoCocoa(w, w->x(), w->y(), w->h()); - float s = Fl::screen_driver()->scale(0); - int bt = parent ? 0 : get_window_frame_sizes(w); - NSRect rp = NSMakeRect(round(pt.x), round(pt.y), round(s * w->w()), round(s * w->h()) + bt); - if (!NSEqualRects(rp, [self frame])) { - [self setFrame:rp display:(views_use_CA ? NO : YES)]; - } - if (parent && ![self parentWindow]) { // useful when subwin is first shown, not when moved - FLWindow *pxid = fl_xid(parent); - [pxid addChildWindow:self ordered:NSWindowAbove]; // needs OS X 10.2 - [self orderWindow:NSWindowAbove relativeTo:[pxid windowNumber]]; // necessary under 10.3 - } -} - -- (void)checkSubwindowFrame { - if (!w->parent()) return; - // make sure this subwindow doesn't leak out of its parent window - Fl_Window *from = w, *parent; - CGRect full = CGRectMake(0, 0, w->w(), w->h()); // full subwindow area - CGRect srect = full; // will become new subwindow clip - int fromx = 0, fromy = 0; - while ((parent = from->window()) != NULL) { // loop over all parent windows - fromx -= from->x(); // parent origin in subwindow's coordinates - fromy -= from->y(); - CGRect prect = CGRectMake(fromx, fromy, parent->w(), parent->h()); - srect = CGRectIntersection(prect, srect); // area of subwindow inside its parent - from = parent; - } - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(w); - CGRect *r = d->subRect(); - CGRect current_clip = (r ? *r : full); // current subwindow clip - if (!CGRectEqualToRect(srect, current_clip)) { // if new clip differs from current clip - delete r; - FLWindow *xid = fl_xid(w); - FLView *view = (FLView*)[xid contentView]; - if (CGRectEqualToRect(srect, full)) { - r = NULL; - } else { - r = new CGRect(srect); - if (r->size.width == 0 && r->size.height == 0) r->origin.x = r->origin.y = 0; - } - d->subRect(r); - w->redraw(); - if (fl_mac_os_version < 100900) { - NSInteger parent_num = [fl_xid(w->window()) windowNumber]; - [xid orderWindow:NSWindowBelow relativeTo:parent_num]; - [xid orderWindow:NSWindowAbove relativeTo:parent_num]; - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (!views_use_CA || view->aux_bitmap) -#endif - [view display]; // subwindow needs redrawn - } -} - --(void)waitForExpose -{ - if ([self getFl_Window]->shown()) { - // this makes freshly created windows appear on the screen, if they are not there already - NSModalSession session = [NSApp beginModalSessionForWindow:self]; - [NSApp runModalSession:session]; - [NSApp endModalSession:session]; - } -} - -/* With Mac OS 10.11 the green window button makes window fullscreen (covers system menu bar and dock). - When there are subwindows, they are by default constrained not to cover the menu bar - (this is arguably a Mac OS bug). - Overriding the constrainFrameRect:toScreen: method removes this constraint. - */ -- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen -{ - if ([self parentWindow]) return frameRect; // do not constrain subwindows - return [super constrainFrameRect:frameRect toScreen:screen]; // will prevent a window from going above the menu bar -} -- (NSBitmapImageRep*)rect_to_NSBitmapImageRep:(Fl_Rect*)r { - return rect_to_NSBitmapImageRep(w, r->x(), r->y(), r->w(), r->h()); -} -- (void)makeKeyWindow { - // Necessary in this scenario at least: - // transition of a subwindow-containing window from multiscreen-fullscreen mode to normal mode. - if ([self canBecomeKeyWindow]) [super makeKeyWindow]; -} -@end - -@interface FLApplication : NSObject -{ -} -+ (void)sendEvent:(NSEvent *)theEvent; -@end - -/* - * This function is the central event handler. - * It reads events from the event queue using the given maximum time - */ -static int do_queued_events( double time = 0.0 ) -{ - static int got_events; // not sure the static is necessary here - got_events = 0; - - // Check for re-entrant condition - if ( dataready.IsThreadRunning() ) { - dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n")); - } - - // Start thread to watch for data ready - if ( dataready.GetNfds() ) { - dataready.StartThread(); - } - - // Elapse timeouts and calculate waiting time - Fl_Timeout::elapse_timeouts(); - time = Fl_Timeout::time_to_wait(time); - - fl_unlock_function(); - NSEvent *event; - while ( (event = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:[NSDate dateWithTimeIntervalSinceNow:time] - inMode:NSDefaultRunLoopMode - dequeue:YES]) != nil ) { - got_events = 1; - [FLApplication sendEvent:event]; // will then call [NSApplication sendevent:] - time = 0; - } - fl_lock_function(); - - return got_events; -} - -double Fl_Darwin_System_Driver::wait(double time_to_wait) -{ - if (dropped_files_list) { // when the list of dropped files is not empty, open one and remove it from list - drain_dropped_files_list(); - } - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - time_to_wait = Fl_System_Driver::wait(time_to_wait); - // the deprecation warnings can be ignored because they run only for macOS < 10.11 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - if (fl_mac_os_version < 101100) NSDisableScreenUpdates(); // deprecated 10.11 - Fl::flush(); - if (fl_mac_os_version < 101100) NSEnableScreenUpdates(); // deprecated 10.11 -#pragma clang diagnostic pop - if (Fl::idle()) // 'idle' may have been set within flush() - time_to_wait = 0.0; - int retval = do_queued_events(time_to_wait); - - Fl_Cocoa_Window_Driver::q_release_context(); - [pool release]; - return retval; -} - -static NSInteger max_normal_window_level(void) -{ - Fl_X *x; - NSInteger max_level; - - max_level = 0; - - for (x = Fl_X::first;x;x = x->next) { - NSInteger level; - FLWindow *cw = (FLWindow*)x->xid; - Fl_Window *win = x->w; - if (!win || !cw || ![cw isVisible]) - continue; - if (win->modal() || win->non_modal()) - continue; - level = [cw level]; - if (level >= max_level) - max_level = level; - } - - return max_level; -} - -// appropriate window level for modal windows -static NSInteger modal_window_level(void) -{ - NSInteger level; - - level = max_normal_window_level(); - if (level < NSStatusWindowLevel) - return NSStatusWindowLevel; - - // Need some room for non-modal windows - level += 2; - - // We cannot exceed this - if (level > CGShieldingWindowLevel()) - return CGShieldingWindowLevel(); - - return level; -} - -// appropriate window level for non-modal windows -static NSInteger non_modal_window_level(void) -{ - NSInteger level; - - level = max_normal_window_level(); - if (level < NSFloatingWindowLevel) - return NSFloatingWindowLevel; - - level += 1; - - if (level > CGShieldingWindowLevel()) - return CGShieldingWindowLevel(); - - return level; -} - -// makes sure modal and non-modal windows stay on top -static void fixup_window_levels(void) -{ - NSInteger modal_level, non_modal_level; - - Fl_X *x; - FLWindow *prev_modal, *prev_non_modal; - - modal_level = modal_window_level(); - non_modal_level = non_modal_window_level(); - - prev_modal = NULL; - prev_non_modal = NULL; - - for (x = Fl_X::first;x;x = x->next) { - FLWindow *cw = (FLWindow*)x->xid; - Fl_Window *win = x->w; - if (!win || !cw || ![cw isVisible]) - continue; - if (win->modal()) { - if ([cw level] != modal_level) { - [cw setLevel:modal_level]; - // changing level puts then in front, so make sure the - // stacking isn't messed up - if (prev_modal != NULL) - [cw orderWindow:NSWindowBelow - relativeTo:[prev_modal windowNumber]]; - } - prev_modal = cw; - } else if (win->non_modal()) { - if ([cw level] != non_modal_level) { - [cw setLevel:non_modal_level]; - if (prev_non_modal != NULL) - [cw orderWindow:NSWindowBelow - relativeTo:[prev_non_modal windowNumber]]; - } - prev_non_modal = cw; - } - } -} - - -// updates Fl::e_x, Fl::e_y, Fl::e_x_root, and Fl::e_y_root -static void update_e_xy_and_e_xy_root(NSWindow *nsw) -{ - NSPoint pt; - pt = [nsw mouseLocationOutsideOfEventStream]; - float s = Fl::screen_driver()->scale(0); - Fl::e_x = int(pt.x / s); - Fl::e_y = int(([[nsw contentView] frame].size.height - pt.y)/s); - pt = [NSEvent mouseLocation]; - Fl::e_x_root = int(pt.x/s); - Fl::e_y_root = int((main_screen_height - pt.y)/s); -} - - -/* - * Cocoa Mousewheel handler - */ -static void cocoaMouseWheelHandler(NSEvent *theEvent) -{ - // Handle the new "MightyMouse" mouse wheel events. Please, someone explain - // to me why Apple changed the API on this even though the current API - // supports two wheels just fine. Matthias, - fl_lock_function(); - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - Fl::first_window(window); - // Under OSX, mousewheel deltas are floats, but fltk only supports ints. - float s = Fl::screen_driver()->scale(0); - float edx = [theEvent deltaX]; - float edy = [theEvent deltaY]; - int dx = roundf(edx / s); - int dy = roundf(edy / s); - // make sure that even small wheel movements count at least as one unit - if (edx>0.0f) dx++; else if (edx<0.0f) dx--; - if (edy>0.0f) dy++; else if (edy<0.0f) dy--; - // allow both horizontal and vertical movements to be processed by the widget - if (dx) { - Fl::e_dx = -dx; - Fl::e_dy = 0; - Fl::handle( FL_MOUSEWHEEL, window ); - } - if (dy) { - Fl::e_dx = 0; - Fl::e_dy = -dy; - Fl::handle( FL_MOUSEWHEEL, window ); - } - fl_unlock_function(); -} - -/* - * Cocoa Magnify Gesture Handler - */ -static void cocoaMagnifyHandler(NSEvent *theEvent) -{ - fl_lock_function(); - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - if ( !window->shown() ) { - fl_unlock_function(); - return; - } - Fl::first_window(window); - Fl::e_dy = [theEvent magnification]*1000; // 10.5.2 - if ( Fl::e_dy) { - NSPoint pos = [theEvent locationInWindow]; - pos.y = window->h() - pos.y; - NSUInteger mods = [theEvent modifierFlags]; - mods_to_e_state( mods ); - update_e_xy_and_e_xy_root([theEvent window]); - Fl::handle( FL_ZOOM_GESTURE, window ); - } - fl_unlock_function(); -} - -#if defined(FLTK_HAVE_PEN_SUPPORT) - -static bool cocoaTabletHandler(NSEvent *theEvent, bool lock) -{ - if (lock) fl_lock_function(); - auto theWindow = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - auto ret = fl_cocoa_tablet_handler(theEvent, theWindow); - if (lock) fl_unlock_function(); - return ret; -} - -#endif // FLTK_HAVE_PEN_SUPPORT - -namespace Fl { -namespace Private { -// Global mouse position at mouse down event -int e_x_down { 0 }; -int e_y_down { 0 }; -}; // namespace Private -}; // namespace Fl - -/* - * Cocoa Mouse Button Handler - */ -static void cocoaMouseHandler(NSEvent *theEvent) -{ - static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2, FL_Button+4, FL_Button+5 }; - - fl_lock_function(); - -#if defined(FLTK_HAVE_PEN_SUPPORT) - // Handle tablet proximity and point subevents - if ( ([theEvent type] != NSEventTypeMouseEntered) // does not have a subtype - && ([theEvent type] != NSEventTypeMouseExited) ) // does not have a subtype - { - if ( ([theEvent subtype] == NSEventSubtypeTabletPoint) - || ([theEvent subtype] == NSEventSubtypeTabletProximity) ) - { - if (cocoaTabletHandler(theEvent, false)) { - fl_unlock_function(); - return; - } - // else fall through into mouse event handling - } - } -#endif // FLTK_HAVE_PEN_SUPPORT - - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - if (!window || !window->shown() ) { - fl_unlock_function(); - return; - } - - NSPoint pos = [theEvent locationInWindow]; - float s = Fl::screen_driver()->scale(0); - pos.x /= s; pos.y /= s; - pos.y = window->h() - pos.y; - NSInteger btn = [theEvent buttonNumber] + 1; - NSUInteger mods = [theEvent modifierFlags]; - int sendEvent = 0; - - NSEventType etype = [theEvent type]; - if (etype == NSEventTypeLeftMouseDown || etype == NSEventTypeRightMouseDown || - etype == NSEventTypeOtherMouseDown) { - if (btn == 1) Fl::e_state |= FL_BUTTON1; - else if (btn == 3) Fl::e_state |= FL_BUTTON2; - else if (btn == 2) Fl::e_state |= FL_BUTTON3; - else if (btn == 4) Fl::e_state |= FL_BUTTON4; - else if (btn == 5) Fl::e_state |= FL_BUTTON5; - } - else if (etype == NSEventTypeLeftMouseUp || etype == NSEventTypeRightMouseUp || - etype == NSEventTypeOtherMouseUp) { - if (btn == 1) Fl::e_state &= ~FL_BUTTON1; - else if (btn == 3) Fl::e_state &= ~FL_BUTTON2; - else if (btn == 2) Fl::e_state &= ~FL_BUTTON3; - else if (btn == 4) Fl::e_state &= ~FL_BUTTON4; - else if (btn == 5) Fl::e_state &= ~FL_BUTTON5; - } - - switch ( etype ) { - case NSEventTypeLeftMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeOtherMouseDown: - sendEvent = FL_PUSH; - Fl::e_is_click = 1; - Fl::Private::e_x_down = (int)pos.x; - Fl::Private::e_y_down = (int)pos.y; - if ([theEvent clickCount] > 1) - Fl::e_clicks++; - else - Fl::e_clicks = 0; - // fall through - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseUp: - if ( !window ) break; - if ( !sendEvent ) { - sendEvent = FL_RELEASE; - } - Fl::e_keysym = keysym[ btn ]; - // fall through - case NSEventTypeMouseMoved: - if ( !sendEvent ) { - sendEvent = FL_MOVE; - } - // fall through - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: { - if ( !sendEvent ) { - sendEvent = FL_MOVE; // Fl::handle will convert into FL_DRAG - if ( (fabs(pos.x - Fl::Private::e_x_down) > 5) || - (fabs(pos.y - Fl::Private::e_y_down) > 5)) - Fl::e_is_click = 0; - } - mods_to_e_state( mods ); - update_e_xy_and_e_xy_root([theEvent window]); - Fl::handle( sendEvent, window ); - } - break; - case NSEventTypeMouseEntered : - if ([theEvent window]) update_e_xy_and_e_xy_root([theEvent window]); - Fl::handle(FL_ENTER, window); - break; - case NSEventTypeMouseExited : - Fl::handle(FL_LEAVE, window); - break; - default: - break; - } - - fl_unlock_function(); - - return; -} - - -@interface FLTextView : NSTextView // this subclass is only needed under OS X < 10.6 -{ - BOOL isActive; -} -+ (void)initialize; -+ (FLTextView*)singleInstance; -- (void)insertText:(id)aString; -- (void)doCommandBySelector:(SEL)aSelector; -- (void)setActive:(BOOL)a; -@end -static FLTextView *fltextview_instance = nil; -@implementation FLTextView -+ (void)initialize { - NSRect rect={{0,0},{20,20}}; - fltextview_instance = [[FLTextView alloc] initWithFrame:rect]; -} -+ (FLTextView*)singleInstance { - return fltextview_instance; -} -- (void)insertText:(id)aString -{ - if (isActive) [[[NSApp keyWindow] contentView] insertText:aString]; -} -- (void)doCommandBySelector:(SEL)aSelector -{ - [[[NSApp keyWindow] contentView] doCommandBySelector:aSelector]; -} -- (void)setActive:(BOOL)a -{ - isActive = a; -} -@end - - -@interface FLWindowDelegate : NSObject <NSWindowDelegate> -+ (void)initialize; -+ (FLWindowDelegate*)singleInstance; -- (void)windowDidMove:(NSNotification *)notif; -- (void)view_did_resize:(NSNotification *)notif; -- (void)windowDidResignKey:(NSNotification *)notif; -- (void)windowDidBecomeKey:(NSNotification *)notif; -- (void)windowDidBecomeMain:(NSNotification *)notif; -- (void)windowDidDeminiaturize:(NSNotification *)notif; -- (void)fl_windowMiniaturize:(NSNotification *)notif; -- (void)windowDidMiniaturize:(NSNotification *)notif; -- (void)windowWillEnterFullScreen:(NSNotification *)notif; -- (void)windowWillExitFullScreen:(NSNotification *)notif; -- (BOOL)windowShouldClose:(id)fl; -- (void)anyWindowWillClose:(NSNotification *)notif; -- (void)doNothing:(id)unused; -- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; -@end - - -/* make subwindows re-appear after appl unhide or window deminiaturize - (not necessary with 10.5 and above) - */ -static void orderfront_subwindows(FLWindow *xid) -{ - NSArray *children = [xid childWindows]; // 10.2 - NSEnumerator *enumerator = [children objectEnumerator]; - id child; - while ((child = [enumerator nextObject]) != nil) { // this undo-redo seems necessary under 10.3 - [xid removeChildWindow:child]; - [xid addChildWindow:child ordered:NSWindowAbove]; - [child orderWindow:NSWindowAbove relativeTo:[xid windowNumber]]; - orderfront_subwindows(child); - } -} - - -// compute coordinates of the win top left in FLTK units -static void CocoatoFLTK(Fl_Window *win, int &x, int &y) { - NSPoint ori; - FLWindow *nsw = fl_xid(win); - ori = [nsw convertBaseToScreen:NSMakePoint(0, [[nsw contentView] frame].size.height)]; - float s = Fl::screen_driver()->scale(0); - x = (int)lround(ori.x / s); - y = (int)lround((main_screen_height - ori.y) / s); - while (win->parent()) {win = win->window(); x -= win->x(); y -= win->y();} -} - -// return Cocoa coordinates of the point in window win at (x,y) FLTK units -static NSPoint FLTKtoCocoa(Fl_Window *win, int x, int y, int H) { - float s = Fl::screen_driver()->scale(0); - while (win->parent()) {win = win->window(); x += win->x(); y += win->y();} - return NSMakePoint(round(x * s), main_screen_height - round((y + H)*s)); -} - -static FLWindowDelegate *flwindowdelegate_instance = nil; -@implementation FLWindowDelegate -+ (void)initialize -{ - if (self == [FLWindowDelegate self]) { - flwindowdelegate_instance = [FLWindowDelegate alloc]; - flwindowdelegate_instance = [flwindowdelegate_instance init]; - } -} -+ (FLWindowDelegate*)singleInstance { - return flwindowdelegate_instance; -} -- (void)windowDidMove:(NSNotification *)notif -{ - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - if (!window->parent()) starting_moved_window = window; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - FLView *view = (FLView*)[nsw contentView]; - if (views_use_CA && [view did_view_resolution_change]) { - if (window->as_gl_window() && Fl::use_high_res_GL()) [view setNeedsDisplay:YES]; // necessary with macOS ≥ 10.14.2; harmless before - } -#endif - if (window == starting_moved_window) { - // we update 'main_screen_height' here because it's wrong just after screen config changes - main_screen_height = CGDisplayBounds(CGMainDisplayID()).size.height; - int X, Y; - CocoatoFLTK(window, X, Y); - if (window->x() != X || window->y() != Y) { - if (!Fl_Cocoa_Window_Driver::driver(window)->through_resize()) - window->position(X, Y); - else - window->Fl_Widget::resize(X,Y,window->w(),window->h()); - } - update_e_xy_and_e_xy_root(nsw); - // at least since MacOS 10.9: OS moves subwindows contained in a moved window - // setSubwindowFrame is no longer necessary. - if (fl_mac_os_version < 100900) [nsw recursivelySendToSubwindows:@selector(setSubwindowFrame) applyToSelf:NO]; - if (window->parent()) [nsw recursivelySendToSubwindows:@selector(checkSubwindowFrame) applyToSelf:YES]; - starting_moved_window = NULL; - } - if (!window->parent()) { - int nscreen = Fl::screen_num(window->x(), window->y(), window->w(), window->h()); - Fl_Window_Driver::driver(window)->screen_num(nscreen); - } - fl_unlock_function(); -} - -/* - This method is called whenever the view of an Fl_Window changes size. - - This can happen for various reasons: - - - the user resizes a desktop window (NSViewFrameDidChangeNotification) - Fl_Cocoa_Window_Driver::driver(window)->through_resize() == 0 for the top level window - Fl_Window::is_a_rescale() == 0 - - the app scale is changed (the Cocoa size changes, but the FLTK size remains) - Fl_Cocoa_Window_Driver::driver(window)->through_resize() == 1 - Fl_Window::is_a_rescale() == 1 - - a window is resized by application code: Fl_Window:resize() - Fl_Cocoa_Window_Driver::driver(window)->through_resize() == 1 - Fl_Window::is_a_rescale() == 0 - - Note that a top level window must be treated differently than a subwindow - (an Fl_Window that is the child of another window). - - Also note, it's important to keep the logical FLTK coordinate system intact. - Converting Cocoa coordinates into FLTK coordinates is not reliable because - it loses precision if the screen scale is set to anything but 1:1. - - See also: - Fl_Cocoa_Window_Driver::driver(window)->view_resized() avoid recursion - Fl_Cocoa_Window_Driver::driver(window)->through_resize(); avoid recursion - Fl_Cocoa_Window_Driver::driver(window)->changed_resolution(); tested OK - */ -- (void)view_did_resize:(NSNotification *)notif -{ - if (![[notif object] isKindOfClass:[FLView class]]) return; - FLView *view = (FLView*)[notif object]; - FLWindow *nsw = (FLWindow*)[view window]; - if (!nsw || ![nsw getFl_Window]) return; - fl_lock_function(); - Fl_Window *window = [nsw getFl_Window]; - - int X, Y, W, H; - float s = Fl::screen_driver()->scale(window->screen_num()); - if (Fl_Window::is_a_rescale()) { - if (window->parent()) { - X = window->x(); - Y = window->y(); - } else { - // Recalculate the FLTK position from the current Cocoa position applying - // the new scale, so the window stays at its current position after scaling. - CocoatoFLTK(window, X, Y); - } - W = window->w(); - H = window->h(); - } else if (Fl_Cocoa_Window_Driver::driver(window)->through_resize()) { - if (window->parent()) { - X = window->x(); - Y = window->y(); - } else { - // Recalculate the FLTK position from the current Cocoa position - CocoatoFLTK(window, X, Y); - } - W = window->w(); - H = window->h(); - } else { - CocoatoFLTK(window, X, Y); - NSRect r = [view frame]; - W = (int)lround(r.size.width/s); - H = (int)lround(r.size.height/s); - } - - Fl_Cocoa_Window_Driver::driver(window)->view_resized(1); - if (Fl_Cocoa_Window_Driver::driver(window)->through_resize()) { - if (window->as_gl_window()) { - static Fl_Cocoa_Plugin *plugin = NULL; - if (!plugin) { - Fl_Plugin_Manager pm("fltk:cocoa"); - plugin = (Fl_Cocoa_Plugin*)pm.plugin("gl.cocoa.fltk.org"); - } - // calls Fl_Gl_Window::resize() without including Fl_Gl_Window.H - plugin->resize(window->as_gl_window(), X, Y, W, H); - } else { - Fl_Cocoa_Window_Driver::driver(window)->resize(X, Y, W, H); - } - } else - window->resize(X, Y, W, H); - Fl_Cocoa_Window_Driver::driver(window)->view_resized(0); - update_e_xy_and_e_xy_root(nsw); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA && !window->as_gl_window()) { - [view reset_aux_bitmap]; - window->redraw(); - } -#endif - if (!window->parent() && window->border() && Fl_Window_Driver::driver(window)->is_resizable()) { - Fl_Cocoa_Window_Driver::driver(window)->is_maximized([nsw isZoomed] && - !window->fullscreen_active()); - } - fl_unlock_function(); -} -- (void)windowDidResignKey:(NSNotification *)notif -{ - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - /* Fullscreen windows obscure all other windows so we need to return - to a "normal" level when the user switches to another window or another app */ - if (window->fullscreen_active()) { - [nsw setLevel:NSNormalWindowLevel]; - fixup_window_levels(); - } - // Situations such as opening a character palette produce windowDidResignKey but - // [NSApp keyWindow] remains set to the resigning window. In that case, don't send FL_UNFOCUS - if ([NSApp keyWindow] != nsw) Fl::handle(FL_UNFOCUS, window); - fl_unlock_function(); -} -- (void)windowDidBecomeKey:(NSNotification *)notif -{ - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *w = [nsw getFl_Window]; - /* Restore previous fullscreen level */ - if (w->fullscreen_active() && !(nsw.styleMask & NSWindowStyleMaskFullScreen)) { - [nsw setLevel:NSStatusWindowLevel]; - fixup_window_levels(); - } - Fl::handle( FL_FOCUS, w); - fl_unlock_function(); -} -- (void)windowDidBecomeMain:(NSNotification *)notif -{ - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - Fl::first_window(window); - if (!window->parent()) [nsw orderFront:nil]; - if (fl_sys_menu_bar && Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style()) { - // select the corresponding Window menu item - int index = Fl_MacOS_Sys_Menu_Bar_Driver::driver()->first_window_menu_item; - while (index > 0) { - Fl_Menu_Item *item = Fl_MacOS_Sys_Menu_Bar_Driver::driver()->window_menu_items + index; - if (!item->label()) break; - if (item->user_data() == window) { - if (!item->value()) { - Fl_MacOS_Sys_Menu_Bar_Driver::driver()->setonly(item); - } - break; - } - index++; - } - } - fl_unlock_function(); -} -- (void)windowDidDeminiaturize:(NSNotification *)notif -{ - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - if ([nsw miniwindowImage]) { [nsw setMiniwindowImage:nil]; } - Fl_Window *window = [nsw getFl_Window]; - Fl::handle(FL_SHOW, window); - // necessary when resolutions before miniaturization and after deminiaturization differ - // or if GUI was resized while window was minimized - [nsw recursivelySendToSubwindows:@selector(setSubwindowFrame) applyToSelf:YES]; - update_e_xy_and_e_xy_root(nsw); - Fl::flush(); // Process redraws set by FL_SHOW. - fl_unlock_function(); -} -- (void)fl_windowMiniaturize:(NSNotification *)notif -{ - // subwindows are not captured in system-built miniature window image - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - if ([[nsw childWindows] count]) { - Fl_Window *window = [nsw getFl_Window]; - // capture the window and its subwindows and use as miniature window image - NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep_subwins(window, 0, 0, window->w(), window->h(), true); - if (bitmap) { - NSImage *img = [[[NSImage alloc] initWithSize:NSMakeSize([bitmap pixelsWide], [bitmap pixelsHigh])] autorelease]; - [img addRepresentation:bitmap]; - [bitmap release]; - [nsw setMiniwindowImage:img]; - } - } - fl_unlock_function(); -} -- (void)windowDidMiniaturize:(NSNotification *)notif -{ - [self fl_windowMiniaturize:notif]; - fl_lock_function(); - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - Fl::handle(FL_HIDE, window); - fl_unlock_function(); -} -- (void)windowWillEnterFullScreen:(NSNotification *)notif -{ - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - window->_set_fullscreen(); -} -- (void)windowWillExitFullScreen:(NSNotification *)notif -{ - FLWindow *nsw = (FLWindow*)[notif object]; - Fl_Window *window = [nsw getFl_Window]; - window->_clear_fullscreen(); -} -- (BOOL)windowShouldClose:(id)fl -{ - fl_lock_function(); - Fl_Window *win = [(FLWindow *)fl getFl_Window]; - if (win) Fl::handle(FL_CLOSE, win); // this might or might not close the window - fl_unlock_function(); - // the system doesn't need to send [fl close] because FLTK does it when needed - return NO; -} -- (void)anyWindowWillClose:(NSNotification *)notif -{ - fl_lock_function(); - if ([[notif object] isKeyWindow]) { - // If the closing window is the key window, - // find a bordered top-level window to become the new key window - Fl_Window *w = Fl::first_window(); - while (w && (w->parent() || !w->border() || !w->visible())) { - w = Fl::next_window(w); - } - if (w) { - [fl_mac_xid(w) makeKeyWindow]; - } - } - fl_unlock_function(); -} -- (void)doNothing:(id)unused -{ - return; -} -- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { - return NO; -} -@end - -@interface FLAppDelegate : NSObject <NSApplicationDelegate> -{ - @public - open_cb_f_type open_cb; - TSMDocumentID currentDoc; -} -- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app; -- (void)applicationDidFinishLaunching:(NSNotification *)notification; -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; -- (void)applicationDidBecomeActive:(NSNotification *)notify; -- (void)applicationDidChangeScreenParameters:(NSNotification *)aNotification; -- (void)applicationDidUpdate:(NSNotification *)aNotification; -- (void)applicationWillResignActive:(NSNotification *)notify; -- (void)applicationWillHide:(NSNotification *)notify; -- (void)applicationWillUnhide:(NSNotification *)notify; -- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; -@end - -@implementation FLAppDelegate -- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app { - // Avoids macOS 14 warning message when app is launched from command line: - // "WARNING: Secure coding is automatically enabled for restorable state! - // However, not on all supported macOS versions of this application. - // Opt-in to secure coding explicitly by implementing - // NSApplicationDelegate.applicationSupportsSecureRestorableState:." - return (fl_mac_os_version >= 140000); -} -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - if (fl_mac_os_version >= 101300 && [NSApp isRunning]) [NSApp stop:nil]; -} -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender -{ - fl_lock_function(); - while ( Fl_X::first ) { - Fl_Window *win = Fl::first_window(); - if (win->parent()) win = win->top_window(); - Fl_Widget_Tracker wt(win); // track the window object - Fl::handle(FL_CLOSE, win); - if (wt.exists() && win->shown()) { // the user didn't close win - break; - } - } - fl_unlock_function(); - if ( ! Fl::first_window() ) { - Fl::program_should_quit(1); - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); // necessary when called through menu and in Fl::wait() - } - return NSTerminateCancel; -} -- (void)applicationDidBecomeActive:(NSNotification *)notify -{ - fl_lock_function(); - - // update clipboard status - clipboard_check(); - - /** - * Cocoa organizes the Z depth of windows on a global priority. FLTK however - * expects the window manager to organize Z level by application. The trickery - * below will change Z order during activation and deactivation. - */ - fixup_window_levels(); - - Fl::handle(FL_APP_ACTIVATE, nullptr); - fl_unlock_function(); -} -- (void)applicationDidChangeScreenParameters:(NSNotification *)unused -{ // react to changes in screen numbers and positions - fl_lock_function(); - main_screen_height = CGDisplayBounds(CGMainDisplayID()).size.height; - Fl::call_screen_init(); - Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); - fl_unlock_function(); -} -- (void)applicationDidUpdate:(NSNotification *)aNotification -{ - if (im_enabled != -1) { - TSMDocumentID newDoc; - // It is extremely unclear when Cocoa decides to create/update - // the input context, but debugging reveals that it is done - // by NSApplication:updateWindows. So check if the input context - // has shifted after each such run so that we can update our - // input methods status. - newDoc = TSMGetActiveDocument(); - if (newDoc != currentDoc) { - TSMDocumentID doc; - - doc = TSMGetActiveDocument(); - - if (im_enabled) - TSMRemoveDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag); - else { - CFArrayRef inputSources; - CFDictionaryRef filter; - // FLΤΚ previously used TISCreateASCIICapableInputSourceList(), - // which mostly hits the mark. But it excludes things like Greek - // and Cyrillic keyboards. So let's be more explicit. - filter = CFDictionaryCreate(NULL, (const void **)kTISPropertyInputSourceType, - (const void **)kTISTypeKeyboardLayout, - 1, NULL, NULL); - inputSources = TISCreateInputSourceList(filter, false); - CFRelease(filter); - TSMSetDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag, - sizeof(CFArrayRef), &inputSources); - CFRelease(inputSources); - } - currentDoc = newDoc; - } - } -} -- (void)applicationWillResignActive:(NSNotification *)notify -{ - fl_lock_function(); - Fl_X *x; - FLWindow *top = 0; - // sort in all regular windows - for (x = Fl_X::first;x;x = x->next) { - FLWindow *cw = (FLWindow*)x->xid; - Fl_Window *win = x->w; - if (win && cw) { - if (win->modal()) { - } else if (win->non_modal()) { - } else { - if (!top) top = cw; - } - } - } - // now sort in all modals - for (x = Fl_X::first;x;x = x->next) { - FLWindow *cw = (FLWindow*)x->xid; - Fl_Window *win = x->w; - if (win && cw && [cw isVisible]) { - if (win->modal()) { - [cw setLevel:NSNormalWindowLevel]; - if (top) [cw orderWindow:NSWindowAbove relativeTo:[top windowNumber]]; - } - } - } - // finally all non-modals - for (x = Fl_X::first;x;x = x->next) { - FLWindow *cw = (FLWindow*)x->xid; - Fl_Window *win = x->w; - if (win && cw && [cw isVisible]) { - if (win->non_modal()) { - [cw setLevel:NSNormalWindowLevel]; - if (top) [cw orderWindow:NSWindowAbove relativeTo:[top windowNumber]]; - } - } - } - Fl::handle(FL_APP_DEACTIVATE, nullptr); - fl_unlock_function(); -} -- (void)applicationWillHide:(NSNotification *)notify -{ - fl_lock_function(); - Fl_X *x; - for (x = Fl_X::first;x;x = x->next) { - Fl_Window *window = x->w; - if ( !window->parent() ) Fl::handle( FL_HIDE, window); - } - fl_unlock_function(); -} -- (void)applicationWillUnhide:(NSNotification *)notify -{ - fl_lock_function(); - for (Fl_X *x = Fl_X::first;x;x = x->next) { - Fl_Window *w = x->w; - if ( !w->parent() && ![(FLWindow*)x->xid isMiniaturized]) { - Fl::handle(FL_SHOW, w); - } - } - fl_unlock_function(); -} -- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename -{ - if (fl_mac_os_version < 101300) { - // without the next two statements, the opening of the 1st window is delayed by several seconds - // under 10.8 ≤ Mac OS < 10.13 when a file is dragged on the application icon - Fl_Window *firstw = Fl::first_window(); - if (firstw) firstw->wait_for_expose(); - } else if (in_nsapp_run) { // memorize all dropped filenames - if (!dropped_files_list) dropped_files_list = [[NSMutableArray alloc] initWithCapacity:1]; - [dropped_files_list addObject:filename]; - return YES; - } - if (open_cb) { - fl_lock_function(); - (*open_cb)([filename UTF8String]); - Fl::flush(); // useful for AppleScript that does not break the event loop - fl_unlock_function(); - return YES; - } - return NO; -} -@end - - -static void drain_dropped_files_list() { - open_cb_f_type open_cb = ((FLAppDelegate*)[NSApp delegate])->open_cb; - if (!open_cb) { - [dropped_files_list removeAllObjects]; - [dropped_files_list release]; - dropped_files_list = nil; - return; - } - NSString *s = (NSString*)[dropped_files_list objectAtIndex:0]; - char *fname = fl_strdup([s UTF8String]); - [dropped_files_list removeObjectAtIndex:0]; - if ([dropped_files_list count] == 0) { - [dropped_files_list release]; - dropped_files_list = nil; - } - open_cb(fname); - free(fname); -} - -/* - * Install an open documents event handler... - */ -void Fl_Darwin_System_Driver::open_callback(void (*cb)(const char *)) { - fl_open_display(); - ((FLAppDelegate*)[NSApp delegate])->open_cb = cb; -} - -@implementation FLApplication -+ (void)sendEvent:(NSEvent *)theEvent -{ - if (fl_send_system_handlers(theEvent)) - return; - - NSEventType type = [theEvent type]; - if (type == NSEventTypeLeftMouseDown) { - fl_lock_function(); - Fl_Window *grab = Fl::grab(); - if (grab) { - FLWindow *win = (FLWindow *)[theEvent window]; - if ( [win isKindOfClass:[FLWindow class]] && grab != [win getFl_Window]) { - // a click event out of a menu window, so we should close this menu - // done here to catch also clicks on window title bar/resize box - cocoaMouseHandler(theEvent); - } - } - fl_unlock_function(); - } else if (type == NSEventTypeApplicationDefined) { - if ([theEvent subtype] == FLTKDataReadyEvent) { - processFLTKEvent(); - } - return; - } else if (type == NSEventTypeKeyUp) { - // The default sendEvent turns key downs into performKeyEquivalent when - // modifiers are down, but swallows the key up if the modifiers include - // command. This one makes all modifiers consistent by always sending key ups. - // FLView treats performKeyEquivalent to keyDown, but performKeyEquivalent is - // still needed for the system menu. - [[NSApp keyWindow] sendEvent:theEvent]; - return; - } - [NSApp sendEvent:theEvent]; -} -@end - -/* Prototype of undocumented function needed to support Mac OS 10.2 or earlier - extern "C" { - OSErr CPSEnableForegroundOperation(ProcessSerialNumber*, UInt32, UInt32, UInt32, UInt32); -} -*/ - -static BOOL is_bundled() { - static int value = 2; - if (value == 2) { - value = 1; - NSBundle *bundle = [NSBundle mainBundle]; - if (bundle) { - NSString *exe = [[bundle executablePath] stringByStandardizingPath]; - NSString *bpath = [[bundle bundlePath] stringByStandardizingPath]; - NSString *exe_dir = [exe stringByDeletingLastPathComponent]; -//NSLog(@"exe=%@ bpath=%@ exe_dir=%@",exe, bpath, exe_dir); - if ([bpath isEqualToString:exe] || [bpath isEqualToString:exe_dir]) value = 0; - } else value = 0; - } - return value == 1; -} - - -static void foreground_and_activate() { - if ( !is_bundled() ) { // only transform the application type for unbundled apps - ProcessSerialNumber cur_psn = { 0, kCurrentProcess }; - TransformProcessType(&cur_psn, kProcessTransformToForegroundApplication); // needs Mac OS 10.3 - /* support of Mac OS 10.2 or earlier used this undocumented call instead - err = CPSEnableForegroundOperation(&cur_psn, 0x03, 0x3C, 0x2C, 0x1103); - */ - } - [NSApp activateIgnoringOtherApps:YES]; -} - -// simpler way to activate application tested OK on MacOS 10.3 10.6 10.9 10.13 and 10.14 public beta - -void Fl_Cocoa_Screen_Driver::open_display_platform() { - static char beenHereDoneThat = 0; - if ( !beenHereDoneThat ) { - beenHereDoneThat = 1; - - BOOL need_new_nsapp = (NSApp == nil); - if (need_new_nsapp) [NSApplication sharedApplication]; - NSAutoreleasePool *localPool; - localPool = [[NSAutoreleasePool alloc] init]; // never released - FLAppDelegate *delegate = [FLAppDelegate alloc]; - [(NSApplication*)NSApp setDelegate:[delegate init]]; - if (need_new_nsapp) { - if (fl_mac_os_version >= 101300 && fl_mac_os_version < 140000 && is_bundled()) { - [NSApp activateIgnoringOtherApps:YES]; - in_nsapp_run = true; - [NSApp run]; - in_nsapp_run = false; - } - else { - [NSApp finishLaunching]; - // Unbundled app may require this so delegate receives applicationDidFinishLaunching: - // even if doc states this is sent at the end of finishLaunching. - if (!is_bundled()) [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:NO]; - } - } - if (fl_mac_os_version < 140000) { - // empty the event queue but keep system events for drag&drop of files at launch - NSEvent *ign_event; - do ign_event = [NSApp nextEventMatchingMask:(NSEventMaskAny & ~NSEventMaskSystemDefined) - untilDate:[NSDate dateWithTimeIntervalSinceNow:0] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - while (ign_event); - } - if (![NSApp isActive]) foreground_and_activate(); - if (![NSApp servicesMenu]) createAppleMenu(); - else Fl_Sys_Menu_Bar::window_menu_style(Fl_Sys_Menu_Bar::no_window_menu); - main_screen_height = CGDisplayBounds(CGMainDisplayID()).size.height; - [[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate singleInstance] - selector:@selector(anyWindowWillClose:) - name:NSWindowWillCloseNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate singleInstance] - selector:@selector(view_did_resize:) - name:NSViewFrameDidChangeNotification - object:nil]; - if (![NSThread isMultiThreaded]) { - // With old OS X versions, it is necessary to create one thread for secondary pthreads to be - // allowed to use cocoa, especially to create an NSAutoreleasePool. - // We create a thread that does nothing so it completes very fast: - [NSThread detachNewThreadSelector:@selector(doNothing:) toTarget:[FLWindowDelegate singleInstance] withObject:nil]; - } - (void)localPool; // silence warning - } -} - - -// Force a "Roman" or "ASCII" keyboard, which both the Mozilla and -// Safari people seem to think implies turning off advanced IME stuff -// (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput -// in Safari/Webcore). Should be good enough for us then... - -static int input_method_startup() -{ - static int retval = -1; // -1: not initialized, 0: not usable, 1: ready for use - if (retval == -1) { - fl_open_display(); - // These symbols require 10.5. They are no longer visible in Apple doc. - // They do exist in Carbon.framework --> HIToolbox.framework --> TextServices.h - TSMGetActiveDocument = (TSMGetActiveDocument_type)Fl_Darwin_System_Driver::get_carbon_function("TSMGetActiveDocument"); - TSMSetDocumentProperty = (TSMSetDocumentProperty_type)Fl_Darwin_System_Driver::get_carbon_function("TSMSetDocumentProperty"); - TSMRemoveDocumentProperty = (TSMRemoveDocumentProperty_type)Fl_Darwin_System_Driver::get_carbon_function("TSMRemoveDocumentProperty"); - // These symbols are no longer visible in Apple doc. - // They do exist in Carbon.framework --> HIToolbox.framework --> TextInputSources.h - TISCreateInputSourceList = (TISCreateInputSourceList_type)Fl_Darwin_System_Driver::get_carbon_function("TISCreateInputSourceList"); - kTISTypeKeyboardLayout = (CFStringRef)Fl_Darwin_System_Driver::get_carbon_function("kTISTypeKeyboardLayout"); - kTISPropertyInputSourceType = (CFStringRef)Fl_Darwin_System_Driver::get_carbon_function("kTISPropertyInputSourceType"); - retval = (TSMGetActiveDocument && TSMSetDocumentProperty && TSMRemoveDocumentProperty && TISCreateInputSourceList && kTISTypeKeyboardLayout && kTISPropertyInputSourceType ? 1 : 0); - } - return retval; -} - -void Fl_Cocoa_Screen_Driver::enable_im() { - if (!input_method_startup()) return; - - im_enabled = 1; - - ((FLAppDelegate*)[NSApp delegate])->currentDoc = NULL; - [NSApp updateWindows]; // triggers [FLAppDelegate applicationDidUpdate] -} - -void Fl_Cocoa_Screen_Driver::disable_im() { - if (!input_method_startup()) return; - - im_enabled = 0; - - ((FLAppDelegate*)[NSApp delegate])->currentDoc = NULL; - [NSApp updateWindows]; // triggers [FLAppDelegate applicationDidUpdate] -} - - -// Gets the border sizes and the titlebar height -static int get_window_frame_sizes(Fl_Window *win, int *pbx, int *pby) { - if (pbx) *pbx = 0; if (pby) *pby = 0; - if (win && !win->border()) return 0; - FLWindow *flw = fl_xid(win); - if (flw) { - return [flw frame].size.height - [[flw contentView] frame].size.height; - } - static int top = 0, left, bottom; - if (!top) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSRect inside = { {20,20}, {100,100} }; - NSRect outside = [NSWindow frameRectForContentRect:inside - styleMask:NSWindowStyleMaskTitled]; - left = int(outside.origin.x - inside.origin.x); - bottom = int(outside.origin.y - inside.origin.y); - top = int(outside.size.height - inside.size.height) - bottom; - [pool release]; - } - if (pbx) *pbx = left; - if (pby) *pby = bottom; - return top; -} - -void Fl_Cocoa_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) { - *top = get_window_frame_sizes(pWindow, left, bottom); - *right = *left; -} - -/* - * smallest x coordinate in screen space of work area of menubar-containing display - */ -int Fl_Cocoa_Screen_Driver::x() { - open_display(); - return int([[[NSScreen screens] objectAtIndex:0] visibleFrame].origin.x) / scale(0); -} - - -/* - * smallest y coordinate in screen space of work area of menubar-containing display - */ -int Fl_Cocoa_Screen_Driver::y() { - open_display(); - NSRect visible = [[[NSScreen screens] objectAtIndex:0] visibleFrame]; - return int(main_screen_height - (visible.origin.y + visible.size.height)) / scale(0); -} - - -/* - * width of work area of menubar-containing display - */ -int Fl_Cocoa_Screen_Driver::w() { - open_display(); - return int([[[NSScreen screens] objectAtIndex:0] visibleFrame].size.width) / scale(0); -} - - -/* - * height of work area of menubar-containing display - */ -int Fl_Cocoa_Screen_Driver::h() { - open_display(); - return int([[[NSScreen screens] objectAtIndex:0] visibleFrame].size.height) / scale(0); -} - -// computes the work area of the nth screen (screen #0 has the menubar) -void Fl_Cocoa_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - open_display(); - NSRect r = [[[NSScreen screens] objectAtIndex:n] visibleFrame]; - X = int(r.origin.x) / scale(0); - Y = (main_screen_height - int(r.origin.y + r.size.height)) / scale(0); - W = int(r.size.width) / scale(0); - H = int(r.size.height) / scale(0); -} - -/* - * get the current mouse pointer world coordinates - */ -int Fl_Cocoa_Screen_Driver::get_mouse(int &x, int &y) -{ - open_display(); - NSPoint pt = [NSEvent mouseLocation]; - x = int(pt.x); - y = int(main_screen_height - pt.y); - return screen_num(x/scale(0), y/scale(0)); -} - - -static int fake_X_wm(Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) { - int W, H, xoff, yoff, dx, dy; - int ret = bx = by = bt = 0; - if (w->border() && !w->parent()) { - int minw, minh, maxw, maxh; - w->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (maxw != minw || maxh != minh) { - ret = 2; - } else { - ret = 1; - } - bt = get_window_frame_sizes(w, &bx, &by); - } - if (w->parent()) return 0; - // The coordinates of the whole window, including non-client area - xoff = bx; - yoff = by + bt; - dx = 2*bx; - dy = 2*by + bt; - float s = Fl::screen_driver()->scale(0); - X = round(w->x()*s)-xoff; - Y = round(w->y()*s)-yoff; - W = w->w()*s+dx; - H = w->h()*s+dy; - - // Proceed to positioning the window fully inside the screen, if possible - - // let's get a little elaborate here. Mac OS X puts a lot of stuff on the desk - // that we want to avoid when positioning our window, namely the Dock and the - // top menu bar (and even more stuff in 10.4 Tiger). So we will go through the - // list of all available screens and find the one that this window is most - // likely to go to, and then reposition it to fit withing the 'good' area. - // Rect r; - // find the screen, that the center of this window will fall into - int R = X+W, B = Y+H; // right and bottom - int cx = (X+R)/2, cy = (Y+B)/2; // center of window; - NSScreen *gd = NULL; - NSArray *a = [NSScreen screens]; int count = (int)[a count]; NSRect r; int i; - for( i = 0; i < count; i++) { - r = [[a objectAtIndex:i] frame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( cx >= r.origin.x && cx <= r.origin.x + r.size.width - && cy >= r.origin.y && cy <= r.origin.y + r.size.height) - break; - } - if (i < count) gd = [a objectAtIndex:i]; - - // if the center doesn't fall on a screen, try the top left - if (!gd) { - for( i = 0; i < count; i++) { - r = [[a objectAtIndex:i] frame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( X >= r.origin.x && X <= r.origin.x + r.size.width - && Y >= r.origin.y && Y <= r.origin.y + r.size.height) - break; - } - if (i < count) gd = [a objectAtIndex:i]; - } - // if that doesn't fall on a screen, try the top right - if (!gd) { - for( i = 0; i < count; i++) { - r = [[a objectAtIndex:i] frame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( R >= r.origin.x && R <= r.origin.x + r.size.width - && Y >= r.origin.y && Y <= r.origin.y + r.size.height) - break; - } - if (i < count) gd = [a objectAtIndex:i]; - } - // if that doesn't fall on a screen, try the bottom left - if (!gd) { - for( i = 0; i < count; i++) { - r = [[a objectAtIndex:i] frame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( X >= r.origin.x && X <= r.origin.x + r.size.width - && Y+H >= r.origin.y && Y+H <= r.origin.y + r.size.height) - break; - } - if (i < count) gd = [a objectAtIndex:i]; - } - // last resort, try the bottom right - if (!gd) { - for( i = 0; i < count; i++) { - r = [[a objectAtIndex:i] frame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( R >= r.origin.x && R <= r.origin.x + r.size.width - && Y+H >= r.origin.y && Y+H <= r.origin.y + r.size.height) - break; - } - if (i < count) gd = [a objectAtIndex:i]; - } - // if we still have not found a screen, we will use the main - // screen, the one that has the application menu bar. - if (!gd) gd = [a objectAtIndex:0]; - if (gd) { - r = [gd visibleFrame]; - r.origin.y = main_screen_height - (r.origin.y + r.size.height); // use FLTK's multiscreen coordinates - if ( R > r.origin.x + r.size.width ) X -= int(R - (r.origin.x + r.size.width)); - if ( B > r.size.height + r.origin.y ) Y -= int(B - (r.size.height + r.origin.y)); - if ( X < r.origin.x ) X = int(r.origin.x); - if ( Y < r.origin.y ) Y = int(r.origin.y); - } - - // Return the client area's top left corner in (X,Y) - X+=xoff; - Y+=yoff; - X /= s; - Y /= s; - - return ret; -} - - -Fl_Window *fl_dnd_target_window = 0; - -static void q_set_window_title(NSWindow *nsw, const char * name, const char *mininame) { - CFStringRef title = CFStringCreateWithCString(NULL, (name ? name : ""), kCFStringEncodingUTF8); - if(!title) { // fallback when name contains malformed UTF-8 - int l = (int)strlen(name); - unsigned short* utf16 = new unsigned short[l + 1]; - l = fl_utf8toUtf16(name, l, utf16, l + 1); - title = CFStringCreateWithCharacters(NULL, utf16, l); - delete[] utf16; - } - [nsw setTitle:(NSString*)title]; - CFRelease(title); - if (mininame && strlen(mininame)) { - CFStringRef minititle = CFStringCreateWithCString(NULL, mininame, kCFStringEncodingUTF8); - if (minititle) { - [nsw setMiniwindowTitle:(NSString*)minititle]; - CFRelease(minititle); - } - } -} - -/** How FLTK handles Mac OS text input - - Let myview be the instance of the FLView class that has the keyboard focus. FLView is an FLTK-defined NSView subclass - that implements the NSTextInputClient protocol to properly handle text input. It also implements the old NSTextInput - protocol to run with OS <= 10.4. The few NSTextInput protocol methods that differ in signature from the NSTextInputClient - protocol transmit the received message to the corresponding NSTextInputClient method. - - Keyboard input sends keyDown: and performKeyEquivalent: messages to myview. The latter occurs for keys such as - ForwardDelete, arrows and F1, and when the Ctrl or Cmd modifiers are used. Other key presses send keyDown: messages. - The keyDown: method calls [myview process_keydown:theEvent] that is equivalent to - [[myview inputContext] handleEvent:theEvent], and triggers system processing of keyboard events. - The performKeyEquivalent: method directly calls Fl::handle(FL_KEYBOARD, focus-window) - when the Ctrl or Cmd modifiers are used. If not, it also calls [[myview inputContext] handleEvent:theEvent]. - The performKeyEquivalent: method returns YES when the keystroke has been handled and NO otherwise, which allows - shortcuts of the system menu to be processed. Three sorts of messages are then sent back by the system to myview: - doCommandBySelector:, setMarkedText: and insertText:. All 3 messages eventually produce Fl::handle(FL_KEYBOARD, win) calls. - The doCommandBySelector: message allows to process events such as new-line, forward and backward delete, arrows, - escape, tab, F1. The message setMarkedText: is sent when marked text, that is, temporary text that gets replaced later - by some other text, is inserted. This happens when a dead key is pressed, and also - when entering complex scripts (e.g., Chinese). Fl_Cocoa_Screen_Driver::next_marked_length gives the byte - length of marked text before the FL_KEYBOARD event is processed. Fl::compose_state gives this length after this processing. - Message insertText: is sent to enter text in the focused widget. If there's marked text, Fl::compose_state is > 0, and this - marked text gets replaced by the inserted text. If there's no marked text, the new text is inserted at the insertion point. - When the character palette is used to enter text, the system sends an insertText: message to myview. - The in_key_event field of the FLView class allows to differentiate keyboard from palette inputs. - - During processing of the handleEvent message, inserted and marked strings are concatenated in a single string - inserted in a single FL_KEYBOARD event after return from handleEvent. The need_handle member variable of FLView allows - to determine when setMarkedText or insertText strings have been sent during handleEvent processing and must trigger - an FL_KEYBOARD event. Concatenating two insertText operations or an insertText followed by a setMarkedText is possible. - In contrast, setMarkedText followed by insertText or by another setMarkedText isn't correct if concatenated in a single - string. Thus, in such case, the setMarkedText and the next operation produce each an FL_KEYBOARD event. - - OS >= 10.7 contains a feature where pressing and holding certain keys opens a menu window that shows a list - of possible accented variants of this key. The selectedRange field of the FLView class and the selectedRange, insertText: - and setMarkedText: methods of the NSTextInputClient protocol are used to support this feature. - The notion of selected text (!= marked text) is monitored by the selectedRange field. - The -(NSRange)[FLView selectedRange] method is used to control whether an FLTK widget opens accented character windows - by returning .location = NSNotFound to disable that, or returning the value of the selectedRange field to enable the feature. - When selectedRange.location >= 0, the value of selectedRange.length is meaningful. 0 means no text is currently selected, - > 0 means this number of characters before the insertion point are selected. The insertText: method does - selectedRange = NSMakeRange(100, 0); to indicate no text is selected. The setMarkedText: method does - selectedRange = NSMakeRange(100, newSelection.length); to indicate that this length of text is selected. - - With OS <= 10.5, the NSView class does not implement the inputContext message. [myview process_keydown:theEvent] is - equivalent to [[FLTextInputContext singleInstance] handleEvent:theEvent]. - Method +[FLTextInputContext singleInstance] returns an instance of class FLTextInputContext that possesses - a handleEvent: method. The class FLTextView implements the so-called view's "field editor". This editor is an instance - of the FLTextView class allocated by the -(id)[FLWindowDelegate windowWillReturnFieldEditor: toObject:] method. - The -(BOOL)[FLTextInputContext handleEvent:] method emulates the missing 10.6 -(BOOL)[NSTextInputContext handleEvent:] - by sending the interpretKeyEvents: message to the FLTextView object. The system sends back doCommandBySelector: and - insertText: messages to the FLTextView object that are transmitted unchanged to myview to be processed as with OS >= 10.6. - The system also sends setMarkedText: messages directly to myview. - - There is furthermore an oddity of dead key processing with OS <= 10.5. It occurs when a dead key followed by a non-accented - key are pressed. Say, for example, that keys '^' followed by 'p' are pressed on a French or German keyboard. Resulting - messages are: [myview setMarkedText:@"^"], [myview insertText:@"^"], [myview insertText:@"p"], [FLTextView insertText:@"^p"]. - The 2nd '^' replaces the marked 1st one, followed by p^p. The resulting text in the widget is "^p^p" instead of the - desired "^p". To avoid that, the FLTextView object is deactivated by the insertText: message and reactivated after - the handleEvent: message has been processed. - - NSEvent's during a character composition sequence: - - keyDown with deadkey -> [[theEvent characters] length] is 0 - - keyUp -> [theEvent characters] contains the deadkey - - keyDown with next key -> [theEvent characters] contains the composed character - - keyUp -> [theEvent characters] contains the standard character - */ - -static void cocoaKeyboardHandler(NSEvent *theEvent) -{ - NSUInteger mods; - // get the modifiers - mods = [theEvent modifierFlags]; - // get the key code - UInt32 keyCode = 0, maskedKeyCode = 0; - unsigned short sym = 0; - keyCode = [theEvent keyCode]; - // extended keyboards can also send sequences on key-up to generate Kanji etc. codes. - // Some observed prefixes are 0x81 to 0x83, followed by an 8 bit keycode. - // In this mode, there seem to be no key-down codes - // printf("%08x %08x %08x\n", keyCode, mods, key); - maskedKeyCode = keyCode & 0x7f; - mods_to_e_state( mods ); // process modifier keys - if (!macKeyLookUp) macKeyLookUp = Fl_Darwin_System_Driver::compute_macKeyLookUp(); - sym = macKeyLookUp[maskedKeyCode]; - if (sym < 0xff00) { // a "simple" key - // find the result of this key without modifier - NSString *sim = [theEvent charactersIgnoringModifiers]; - UniChar one; - CFStringGetCharacters((CFStringRef)sim, CFRangeMake(0, 1), &one); - // charactersIgnoringModifiers doesn't ignore shift, remove it when it's on - if(one >= 'A' && one <= 'Z') one += 32; - if (one > 0 && one <= 0x7f && (sym<'0' || sym>'9') ) sym = one; - } - Fl::e_keysym = Fl::e_original_keysym = sym; - /*NSLog(@"cocoaKeyboardHandler: keycode=%08x keysym=%08x mods=%08x symbol=%@ (%@)", - keyCode, sym, mods, [theEvent characters], [theEvent charactersIgnoringModifiers]);*/ - // If there is text associated with this key, it will be filled in later. - Fl::e_length = 0; - Fl::e_text = (char*)""; -} - -@interface FLTextInputContext : NSObject // "emulates" NSTextInputContext before OS 10.6 -+ (void)initialize; -+ (FLTextInputContext*)singleInstance; --(BOOL)handleEvent:(NSEvent*)theEvent; -@end -static FLTextInputContext* fltextinputcontext_instance = nil; -@implementation FLTextInputContext -+ (void)initialize { - fltextinputcontext_instance = [[FLTextInputContext alloc] init]; -} -+ (FLTextInputContext*)singleInstance { - return fltextinputcontext_instance; -} --(BOOL)handleEvent:(NSEvent*)theEvent { - FLTextView *edit = [FLTextView singleInstance]; - [edit setActive:YES]; - [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; - [edit setActive:YES]; - return YES; -} -@end - -/* Implementation note for the support of layer-backed views. - MacOS 10.14 Mojave changes the way all drawing to displays is performed: - all NSView objects become layer-backed, that is, drawing is done by - Core Animation to a CALayer object whose content is then displayed by the NSView. - The global variable views_use_CA is set to YES when such change applies, - that is, for apps running under 10.14 and linked to SDK 10.14. - When views_use_CA is NO, views are not supposed to be layer-backed. - - Most drawing is done by [FLView drawRect:] which the system calls - when a window is created or resized and when Fl_Window_Driver::flush() runs which sends the display - message to the view. Within drawRect:, [[NSGraphicsContext currentContext] CGContext] - gives a graphics context whose product ultimately appears on screen. But the - full content of the view must be redrawn each time drawRect: runs, in contrast - to pre-10.14 where drawings were added to the previous window content. - That is why FLView maintains a bitmap (view->aux_bitmap) to which all drawing is directed. - At the end of drawRect:, the content of view->aux_bitmap is copied to the window's graphics context. - - A problem arises to support drawing done outside Fl_Window_Driver::flush(), that is, - after the app calls Fl_Window::make_current() at any time it wants. - That situation is identified by the condition (views_use_CA && !through_drawRect). - Fl_Window::make_current() thus calls [view setNeedsDisplay:YES] which instructs the system to - run drawRect: at the next event loop. Later, when drawRect: runs, the content of - aux_bitmap is copied to drawRect's graphics context. - - OpenGL windows remain processed under 10.14 as before. - */ - -@implementation FLView -- (BOOL)did_view_resolution_change { - // determine whether window is mapped to a retina display - Fl_Window *window = [(FLWindow*)[self window] getFl_Window]; - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - bool previous = d->mapped_to_retina(); - NSView *view = (!views_use_CA && window->parent() && !window->as_gl_window()) ? - [fl_xid(window->top_window()) contentView] : self; - if (view) { - NSSize s = [view convertSizeToBacking:NSMakeSize(10, 10)]; // 10.7 - d->mapped_to_retina( int(s.width + 0.5) > 10 ); - } - BOOL retval = (d->wait_for_expose_value == 0 && previous != d->mapped_to_retina()); - if (retval) { - d->changed_resolution(true); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA && !window->as_gl_window() ) { - [self reset_aux_bitmap]; - window->redraw(); - } -#endif - } - return retval; -} -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -- (void)create_aux_bitmap:(CGContextRef)gc retina:(BOOL)r { - if (!gc || fl_mac_os_version >= 101600) { - // bitmap context-related functions (e.g., CGBitmapContextGetBytesPerRow) can't be used here with macOS 11.0 "Big Sur" - static CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - int W = [self frame].size.width, H = [self frame].size.height; - if (r) { W *= 2; H *= 2; } - aux_bitmap = CGBitmapContextCreate(NULL, W, H, 8, 0, cspace, kCGImageAlphaPremultipliedFirst|kCGBitmapByteOrder32Host); - } else { - aux_bitmap = CGBitmapContextCreate(NULL, CGBitmapContextGetWidth(gc), CGBitmapContextGetHeight(gc), - CGBitmapContextGetBitsPerComponent(gc), CGBitmapContextGetBytesPerRow(gc), - CGBitmapContextGetColorSpace(gc), CGBitmapContextGetBitmapInfo(gc)); - } - CGContextClearRect(aux_bitmap, CGRectMake(0, 0, - CGBitmapContextGetWidth(aux_bitmap), CGBitmapContextGetHeight(aux_bitmap))); - if (r) CGContextScaleCTM(aux_bitmap, 2, 2); -} -- (void)reset_aux_bitmap { - CGContextRelease(aux_bitmap); - aux_bitmap = NULL; -} -#endif -- (BOOL)process_keydown:(NSEvent*)theEvent -{ - return [[self inputContext] handleEvent:theEvent]; -} -- (id)initWithFrame:(NSRect)frameRect -{ - static NSInteger counter = 0; - self = [super initWithFrame:frameRect]; - if (self) { - in_key_event = NO; - identifier = ++counter; - } - return self; -} - -/* Used by all GL or non-GL windows. - * Gets called when a window is created, resized, or moved between retina and non-retina displays. - * For non-GL windows, also called by Fl_Window_Driver::flush() because of the display message sent to the view. - */ -- (void)drawRect:(NSRect)rect -{ - FLWindow *cw = (FLWindow*)[self window]; - Fl_Window *window = [cw getFl_Window]; - if (!window) return; // may happen after closing full-screen window - if (!Fl_X::flx(window)) return; // reported to happen with Gmsh (issue #434) - fl_lock_function(); - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - if (!through_Fl_X_flush -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - && (!views_use_CA || !aux_bitmap) -#endif - ) { - [self did_view_resolution_change]; - if (d->wait_for_expose_value) { - d->wait_for_expose_value = 0; - if (window->as_gl_window() && views_use_CA && fl_mac_os_version < 101401) { // 1st drawing of layer-backed GL window - window->size(window->w(), window->h()); // sends message [GLcontext update] - } - } - Fl_X *i = Fl_X::flx(window); - if ( i->region ) { - Fl_Graphics_Driver::default_driver().XDestroyRegion(i->region); - i->region = 0; - } - window->clear_damage(FL_DAMAGE_ALL); - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - CGContextRef destination = NULL; - if (views_use_CA) { - destination = [[NSGraphicsContext currentContext] CGContext]; - if (!aux_bitmap && !window->as_gl_window()) [self create_aux_bitmap:destination retina:d->mapped_to_retina()]; - } -#endif - through_drawRect = YES; - if (window->damage()) d->Fl_Window_Driver::flush(); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (destination) { // can be NULL with gl_start/gl_finish - if (fl_mac_os_version < 101600 && CGBitmapContextGetBytesPerRow(aux_bitmap) == CGBitmapContextGetBytesPerRow(destination)) { - memcpy(CGBitmapContextGetData(destination), CGBitmapContextGetData(aux_bitmap), - CGBitmapContextGetHeight(aux_bitmap) * CGBitmapContextGetBytesPerRow(aux_bitmap)); - } else { - CGImageRef img = CGBitmapContextCreateImage(aux_bitmap); - CGContextDrawImage(destination, [self frame], img); - CGImageRelease(img); - } - } -#endif - Fl_Cocoa_Window_Driver::q_release_context(); - if (!through_Fl_X_flush) window->clear_damage(); - through_drawRect = NO; - fl_unlock_function(); -} - -- (BOOL)acceptsFirstResponder -{ - return [[self window] parentWindow] ? NO : YES; // 10.2 -} -- (BOOL)performKeyEquivalent:(NSEvent*)theEvent -{ - //NSLog(@"performKeyEquivalent:"); - /* The condition below is always false (and therefore the return statement doesn't run) - for the FLTK library unless it contains class Fl_Native_Input with which FLTK windows - may contain subviews inside their contentView. When such subview has focus, the condition - below becomes true. - */ - if ([[self window] firstResponder] != self) { - return NO; - } - NSUInteger mods = [theEvent modifierFlags]; - NSString *pure = [theEvent charactersIgnoringModifiers]; - // detect Function+e to open character palette - if ((mods & NSEventModifierFlagFunction) && [pure isEqualToString:@"e"] ) { - [NSApp orderFrontCharacterPalette:self]; - return YES; - } - fl_lock_function(); - cocoaKeyboardHandler(theEvent); - BOOL handled; - Fl_Window *w = [(FLWindow*)[theEvent window] getFl_Window]; - if ( (mods & NSEventModifierFlagControl) || (mods & NSEventModifierFlagCommand) ) { - NSString *s = [theEvent characters]; - if ( (mods & NSEventModifierFlagShift) && (mods & NSEventModifierFlagCommand) ) { - s = [s uppercaseString]; // US keyboards return lowercase letter in s if cmd-shift-key is hit - } - [FLView prepareEtext:s]; - Fl::compose_state = 0; - handled = Fl::handle(FL_KEYBOARD, w); - if (!handled) { - // detect Ctrl+Command+Space to open character palette, if not used before as shortcut - if ( (mods & NSEventModifierFlagControl) && (mods & NSEventModifierFlagCommand) && - !(mods & (NSEventModifierFlagShift|NSEventModifierFlagOption)) && [pure isEqualToString:@" "] ) { - [NSApp orderFrontCharacterPalette:self]; - } - } - } - else { - in_key_event = YES; - need_handle = NO; - handled = [self process_keydown:theEvent]; - if (need_handle) handled = Fl::handle(FL_KEYBOARD, w); - in_key_event = NO; - } - fl_unlock_function(); - return handled; -} -- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent -{ - Fl_Window *w = [(FLWindow*)[theEvent window] getFl_Window]; - Fl_Window *first = Fl::first_window(); - return (first == w || !first->modal()); -} -- (void)resetCursorRects { - Fl_Window *w = [(FLWindow*)[self window] getFl_Window]; - Fl_X *i = (w ? Fl_X::flx(w) : NULL); - if (!i) return; // fix for STR #3128 - // We have to have at least one cursor rect for invalidateCursorRectsForView - // to work, hence the "else" clause. - if (Fl_Cocoa_Window_Driver::driver(w)->cursor) - [self addCursorRect:[self frame] cursor:Fl_Cocoa_Window_Driver::driver(w)->cursor]; - else - [self addCursorRect:[self frame] cursor:[NSCursor arrowCursor]]; -} -- (void)mouseUp:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)rightMouseUp:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)otherMouseUp:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)mouseDown:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)rightMouseDown:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)otherMouseDown:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)mouseMoved:(NSEvent *)theEvent { - if (Fl::belowmouse()) cocoaMouseHandler(theEvent); -} -- (void)mouseEntered:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)mouseExited:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -#if defined(FLTK_HAVE_PEN_SUPPORT) -- (void)tabletProximity:(NSEvent *)theEvent { - cocoaTabletHandler(theEvent, true); -} -- (void)tabletPoint:(NSEvent *)theEvent { - cocoaTabletHandler(theEvent, true); -} -#endif -- (void)updateTrackingAreas { - if (![[self window] parentWindow]) { - while (true) { - NSArray *a = [self trackingAreas]; // 10.5 - if ([a count] == 0) break; - NSTrackingArea *ta = (NSTrackingArea*)[a objectAtIndex:0]; - [self removeTrackingArea:ta]; // 10.5 - } - NSTrackingArea *tracking = [[[NSTrackingArea alloc] // 10.5 - initWithRect:[self frame] - options:NSTrackingActiveAlways | - NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved - owner:self - userInfo:nil] autorelease]; - if (tracking) { - [self addTrackingArea:tracking]; // 10.5 - } - } - [super updateTrackingAreas]; -} -- (void)mouseDragged:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)rightMouseDragged:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)otherMouseDragged:(NSEvent *)theEvent { - cocoaMouseHandler(theEvent); -} -- (void)scrollWheel:(NSEvent *)theEvent { - cocoaMouseWheelHandler(theEvent); -} -- (void)magnifyWithEvent:(NSEvent *)theEvent { - cocoaMagnifyHandler(theEvent); -} -- (void)keyDown:(NSEvent *)theEvent { - //NSLog(@"keyDown:%@",[theEvent characters]); - fl_lock_function(); - Fl_Window *window = [(FLWindow*)[theEvent window] getFl_Window]; - Fl::first_window(window); - cocoaKeyboardHandler(theEvent); - in_key_event = YES; - Fl_Widget *f = Fl::focus(); - if (f && f->as_gl_window()) { // ignore text input methods for GL windows - need_handle = YES; - [FLView prepareEtext:[theEvent characters]]; - } else { - need_handle = NO; - [self process_keydown:theEvent]; - } - if (need_handle) Fl::handle(FL_KEYBOARD, window); - in_key_event = NO; - fl_unlock_function(); -} -- (void)keyUp:(NSEvent *)theEvent { - //NSLog(@"keyUp:%@",[theEvent characters]); - if (![[theEvent window] isKindOfClass:[FLWindow class]]) // issue #1170 - return [super keyUp:theEvent]; - fl_lock_function(); - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - Fl::first_window(window); - cocoaKeyboardHandler(theEvent); - NSString *s = [theEvent characters]; - if ([s length] >= 1) [FLView prepareEtext:[s substringToIndex:1]]; - Fl::handle(FL_KEYUP,window); - fl_unlock_function(); -} -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10 - typedef NSUInteger NSEventModifierFlags; -#endif -- (void)flagsChanged:(NSEvent *)theEvent { - //NSLog(@"flagsChanged: "); - fl_lock_function(); - static NSEventModifierFlags prevMods = 0; - NSEventModifierFlags mods = [theEvent modifierFlags]; - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - NSEventModifierFlags tMods = prevMods ^ mods; - int sendEvent = 0; - if ( tMods ) - { - unsigned short keycode = [theEvent keyCode]; - if (!macKeyLookUp) macKeyLookUp = Fl_Darwin_System_Driver::compute_macKeyLookUp(); - Fl::e_keysym = Fl::e_original_keysym = macKeyLookUp[keycode & 0x7f]; - if ( Fl::e_keysym ) - sendEvent = ( prevMods<mods ) ? FL_KEYBOARD : FL_KEYUP; - Fl::e_length = 0; - Fl::e_text = (char*)""; - prevMods = mods; - } - mods_to_e_state( mods ); - if (sendEvent) Fl::handle(sendEvent,window); - fl_unlock_function(); -} -- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender -{ - fl_lock_function(); - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - update_e_xy_and_e_xy_root([self window]); - fl_dnd_target_window = target; - int ret = Fl::handle( FL_DND_ENTER, target ); - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); - Fl::flush(); - return ret ? NSDragOperationCopy : NSDragOperationNone; -} -- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender -{ - fl_lock_function(); - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - update_e_xy_and_e_xy_root([self window]); - fl_dnd_target_window = target; - int ret = Fl::handle( FL_DND_DRAG, target ); - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); - // if the DND started in the same application, Fl::dnd() will not return until - // the DND operation is finished. The call below causes the drop indicator - // to be drawn correctly (a full event handling would be better...) - Fl::flush(); - return ret ? NSDragOperationCopy : NSDragOperationNone; -} -- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender -{ - static char *DragData = NULL; - fl_lock_function(); - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - if ( !Fl::handle( FL_DND_RELEASE, target ) ) { - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); - return NO; - } - NSPasteboard *pboard; - // NSDragOperation sourceDragMask; - // sourceDragMask = [sender draggingSourceOperationMask]; - pboard = [sender draggingPasteboard]; - update_e_xy_and_e_xy_root([self window]); - if (DragData) { free(DragData); DragData = NULL; } - if ([[pboard types] containsObject:fl_filenames_pboard_type]) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 - if (fl_mac_os_version >= 101300) { - NSArray *a = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] - options:nil]; // 10.6 - NSEnumerator *enumerator = [a objectEnumerator]; - NSURL *url; - while ((url = (NSURL*)[enumerator nextObject]) != nil) { - const char *p = [url fileSystemRepresentation]; // 10.9 - if (!DragData) { - DragData = strdup(p); - } else { - int l = (int)strlen(DragData) + (int)strlen(p) + 2; - char *drag2 = (char*)malloc(l); - snprintf(drag2, l, "%s\n%s", DragData, p); - free(DragData); - DragData = drag2; - } - } - } else -#endif - { - CFArrayRef files = (CFArrayRef)[pboard - propertyListForType:fl_filenames_pboard_type]; - CFStringRef all = CFStringCreateByCombiningStrings(NULL, files, CFSTR("\n")); - int l = (int)CFStringGetMaximumSizeForEncoding(CFStringGetLength(all), - kCFStringEncodingUTF8); - DragData = (char *)malloc(l + 1); - CFStringGetCString(all, DragData, l + 1, kCFStringEncodingUTF8); - CFRelease(all); - } - } else if ([[pboard types] containsObject:UTF8_pasteboard_type]) { - NSData *data = [pboard dataForType:UTF8_pasteboard_type]; - DragData = (char *)malloc([data length] + 1); - [data getBytes:DragData length:[data length]]; - DragData[([data length])] = 0; - Fl_Screen_Driver::convert_crlf(DragData, strlen(DragData)); - } - else { - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); - return NO; - } - Fl::e_text = DragData; - Fl::e_length = (int)strlen(DragData); - int old_event = Fl::e_number; - Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); - Fl::e_number = old_event; - if (DragData) { free(DragData); DragData = NULL; } - Fl::e_text = NULL; - Fl::e_length = 0; - fl_dnd_target_window = NULL; - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); - return YES; -} -- (void)draggingExited:(id < NSDraggingInfo >)sender -{ - fl_lock_function(); - if ( fl_dnd_target_window ) { - Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); - fl_dnd_target_window = 0; - } - fl_unlock_function(); -} -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal -{ - return NSDragOperationGeneric; -} - -+ (void)prepareEtext:(NSString*)aString { - // fills Fl::e_text with UTF-8 encoded aString using an adequate memory allocation - static char *received_utf8 = NULL; - static int lreceived = 0; - char *p = (char*)[aString UTF8String]; - int l = (int)strlen(p); - if (l > 0) { - if (lreceived == 0) { - received_utf8 = (char*)malloc(l + 1); - lreceived = l; - } - else if (l > lreceived) { - received_utf8 = (char*)realloc(received_utf8, l + 1); - lreceived = l; - } - strcpy(received_utf8, p); - Fl::e_text = received_utf8; - } - Fl::e_length = l; -} - -+ (void)concatEtext:(NSString*)aString { - // extends Fl::e_text with aString - NSString *newstring = [[NSString stringWithUTF8String:Fl::e_text] stringByAppendingString:aString]; - [FLView prepareEtext:newstring]; -} - -- (void)doCommandBySelector:(SEL)aSelector { - NSString *s = [[NSApp currentEvent] characters]; - //NSLog(@"doCommandBySelector:%s text='%@'",sel_getName(aSelector), s); - s = [s substringFromIndex:[s length] - 1]; - [FLView prepareEtext:s]; // use the last character of the event; necessary for deadkey + Tab - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - Fl::handle(FL_KEYBOARD, target); -} - -- (void)insertText:(id)aString { - [self insertText:aString replacementRange:NSMakeRange(NSNotFound, 0)]; -} - -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { - NSString *received; - if ([aString isKindOfClass:[NSAttributedString class]]) { - received = [(NSAttributedString*)aString string]; - } else { - received = (NSString*)aString; - } - /*NSLog(@"insertText='%@' l=%d Fl::compose_state=%d range=%d,%d", - received,strlen([received UTF8String]),Fl::compose_state,replacementRange.location,replacementRange.length);*/ - fl_lock_function(); - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - if (fl_mac_os_version >= 101400 && replacementRange.length > 0) { - // occurs after a key was pressed and maintained and an auxiliary window appeared - // prevents marking dead key from deactivation - [[self inputContext] discardMarkedText]; - } - while (replacementRange.length--) { // delete replacementRange.length characters before insertion point - int saved_keysym = Fl::e_keysym; - Fl::e_keysym = FL_BackSpace; - Fl::handle(FL_KEYBOARD, target); - Fl::e_keysym = saved_keysym; - } - if (in_key_event && Fl_Cocoa_Screen_Driver::next_marked_length && Fl::e_length) { - // if setMarkedText + insertText is sent during handleEvent, text cannot be concatenated in single FL_KEYBOARD event - Fl::handle(FL_KEYBOARD, target); - Fl::e_length = 0; - } - if (in_key_event && Fl::e_length) [FLView concatEtext:received]; - else [FLView prepareEtext:received]; - Fl_Cocoa_Screen_Driver::next_marked_length = 0; - // We can get called outside of key events (e.g., from the character palette, from CJK text input). - BOOL palette = !(in_key_event || Fl::compose_state); - if (palette) Fl::e_keysym = 0; - // YES if key has text attached - BOOL has_text_key = Fl::e_keysym <= '~' || Fl::e_keysym == FL_Iso_Key || - (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last && Fl::e_keysym != FL_KP_Enter); - // insertText sent during handleEvent of a key without text cannot be processed in a single FL_KEYBOARD event. - // Occurs with deadkey followed by non-text key. Occurs also with emoji palette. - if (!in_key_event || !has_text_key) { - Fl::handle(FL_KEYBOARD, target); - Fl::e_length = 0; - } - else need_handle = YES; - selectedRange = NSMakeRange(100, 0); // 100 is an arbitrary value - // for some reason, with the palette, the window does not redraw until the next mouse move or button push - // sending a 'redraw()' or 'awake()' does not solve the issue! - if (palette) Fl::flush(); - fl_unlock_function(); -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { - [self setMarkedText:aString selectedRange:newSelection replacementRange:NSMakeRange(NSNotFound, 0)]; -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection replacementRange:(NSRange)replacementRange { - NSString *received; - if ([aString isKindOfClass:[NSAttributedString class]]) { - received = [(NSAttributedString*)aString string]; - } else { - received = (NSString*)aString; - } - fl_lock_function(); - /*NSLog(@"setMarkedText:%@ l=%d newSelection=%d,%d Fl::compose_state=%d replacement=%d,%d", - received, strlen([received UTF8String]), newSelection.location, newSelection.length, Fl::compose_state, - replacementRange.location, replacementRange.length);*/ - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; - while (replacementRange.length--) { // delete replacementRange.length characters before insertion point - Fl::e_keysym = FL_BackSpace; - Fl::compose_state = 0; - Fl_Cocoa_Screen_Driver::next_marked_length = 0; - Fl::handle(FL_KEYBOARD, target); - Fl::e_keysym = 'a'; // pretend a letter key was hit - } - if (in_key_event && Fl_Cocoa_Screen_Driver::next_marked_length && Fl::e_length) { - // if setMarkedText + setMarkedText is sent during handleEvent, text cannot be concatenated in single FL_KEYBOARD event - Fl::handle(FL_KEYBOARD, target); - Fl::e_length = 0; - } - if (in_key_event && Fl::e_length) [FLView concatEtext:received]; - else [FLView prepareEtext:received]; - Fl_Cocoa_Screen_Driver::next_marked_length = (int)strlen([received UTF8String]); - if (!in_key_event) Fl::handle( FL_KEYBOARD, target); - else need_handle = YES; - selectedRange = NSMakeRange(100, newSelection.length); - fl_unlock_function(); -} - -- (void)unmarkText { - fl_lock_function(); - Fl_Cocoa_Screen_Driver::reset_marked_text(); - fl_unlock_function(); - //NSLog(@"unmarkText"); -} - -- (NSRange)selectedRange { - Fl_Widget *w = Fl::focus(); - if (w && w->use_accents_menu()) return selectedRange; - return NSMakeRange(NSNotFound, 0); -} - -- (NSRange)markedRange { - //NSLog(@"markedRange=%d %d", Fl::compose_state > 0?0:NSNotFound, Fl::compose_state); - return NSMakeRange(Fl::compose_state > 0?0:NSNotFound, Fl::compose_state); -} - -- (BOOL)hasMarkedText { - //NSLog(@"hasMarkedText %s", Fl::compose_state > 0?"YES":"NO"); - return (Fl::compose_state > 0); -} - -- (NSAttributedString *)attributedSubstringFromRange:(NSRange)aRange { - return [self attributedSubstringForProposedRange:aRange actualRange:NULL]; -} -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { - //NSLog(@"attributedSubstringFromRange: %d %d",aRange.location,aRange.length); - return nil; -} - -- (NSArray *)validAttributesForMarkedText { - return nil; -} - -- (NSRect)firstRectForCharacterRange:(NSRange)aRange { - return [self firstRectForCharacterRange:aRange actualRange:NULL]; -} -- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { - //NSLog(@"firstRectForCharacterRange %d %d actualRange=%p",aRange.location, aRange.length,actualRange); - NSRect glyphRect; - fl_lock_function(); - Fl_Widget *focus = Fl::focus(); - Fl_Window *wfocus = [(FLWindow*)[self window] getFl_Window]; - if (!focus) focus = wfocus; - glyphRect.size.width = 0; - - int x, y, height; - if (Fl_Cocoa_Screen_Driver::insertion_point_location(&x, &y, &height)) { - glyphRect.origin.x = (CGFloat)x; - glyphRect.origin.y = (CGFloat)y; - } else { - if (focus->as_window()) { - glyphRect.origin.x = 0; - glyphRect.origin.y = focus->h(); - } - else { - glyphRect.origin.x = focus->x(); - glyphRect.origin.y = focus->y() + focus->h(); - } - height = 12; - } - glyphRect.size.height = height; - Fl_Window *win = focus->as_window(); - if (!win) win = focus->window(); - while (win != NULL && win != wfocus) { - glyphRect.origin.x += win->x(); - glyphRect.origin.y += win->y(); - win = win->window(); - } - // Convert the rect to screen coordinates - float s = Fl_Graphics_Driver::default_driver().scale(); - glyphRect.origin.x *= s; - glyphRect.origin.y *= s; - glyphRect.origin.y = wfocus->h()*s - glyphRect.origin.y; - glyphRect.origin = [(FLWindow*)[self window] convertBaseToScreen:glyphRect.origin]; - glyphRect.size.height *= s; - if (actualRange) *actualRange = aRange; - fl_unlock_function(); - return glyphRect; -} - -- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint { - return 0; -} - -- (NSInteger)windowLevel { - return [[self window] level]; -} - -- (NSInteger)conversationIdentifier { - return identifier; -} - -- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context -{ - return NSDragOperationCopy; -} -- (void)draggingSession:(NSDraggingSession *)session - endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation -{ - Fl_Widget *w = Fl::pushed(); - if ( w ) { - int old_event = Fl::e_number; - w->handle(Fl::e_number = FL_RELEASE); - Fl::e_number = old_event; - Fl::pushed( 0 ); - } -} - -@end - - -/* - * Initialize the given port for redraw and call the window's flush() to actually draw the content - */ -void Fl_Cocoa_Window_Driver::flush() -{ - if (pWindow->as_gl_window()) { - Fl_Window_Driver::flush(); - } else { - through_Fl_X_flush = YES; - NSView *view = [fl_xid(pWindow) contentView]; - if (views_use_CA) [view display]; - else { - [view setNeedsDisplay:YES]; - [view displayIfNeededIgnoringOpacity]; - } - through_Fl_X_flush = NO; - } -} - -/* - * go ahead, create that (sub)window - */ -void Fl_Cocoa_Window_Driver::makeWindow() -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Fl_Group::current(0); - fl_open_display(); - NSInteger winlevel = NSNormalWindowLevel; - NSUInteger winstyle; - Fl_Sys_Menu_Bar::create_window_menu(); // effective once at most - Fl_Window* w = pWindow; - if (w->parent()) { - w->border(0); - show_iconic(0); - } - if (w->border()) { - winstyle = (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable); - if (is_resizable()) - winstyle |= NSWindowStyleMaskResizable; - } else { - winstyle = NSWindowStyleMaskBorderless; - } - if (show_iconic() && !w->parent()) { // prevent window from being out of work area when created iconized - int sx, sy, sw, sh; - Fl::screen_work_area (sx, sy, sw, sh, w->x(), w->y()); - if (w->x() < sx) x(sx); - if (w->y() < sy) y(sy); - } - int xp = w->x(); - int yp = w->y(); - - int xwm = xp, ywm = yp, bt, bx, by; - - if (!fake_X_wm(w, xwm, ywm, bt, bx, by)) { - // menu windows and tooltips - if (w->modal()||w->tooltip_window()) { - winlevel = modal_window_level(); - } - } - if (w->modal()) { - winstyle &= ~NSWindowStyleMaskMiniaturizable; - winlevel = modal_window_level(); - } - else if (w->non_modal()) { - winlevel = non_modal_window_level(); - } - - if (force_position()) { - if (!Fl::grab()) { - xp = xwm; yp = ywm; - x(xp);y(yp); - } - xp -= bx; - yp -= by+bt; - } - - Fl_X *x = new Fl_X; - other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows - x->region = 0; - subRect(0); - gc = 0; - mapped_to_retina(false); - changed_resolution(false); - - NSRect crect; - float s = Fl::screen_driver()->scale(0); - crect.origin.x = round(s * w->x()); // correct origin set later for subwindows - crect.origin.y = main_screen_height - round(s * (w->y() + w->h())); - crect.size.width = int(s * w->w()); - crect.size.height = int(s * w->h()); - FLWindow *cw = [[FLWindow alloc] initWithFl_W:w - contentRect:crect - styleMask:winstyle]; - [cw setFrameOrigin:crect.origin]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (fl_mac_os_version >= 101200) { - if (!w->parent() && (winstyle & NSWindowStyleMaskTitled) && - (winstyle & NSWindowStyleMaskResizable) && !w->modal() && !w->non_modal() && - (Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() > Fl_Sys_Menu_Bar::tabbing_mode_none)) { - if (Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() == Fl_Sys_Menu_Bar::tabbing_mode_preferred) - [cw setTabbingMode:NSWindowTabbingModePreferred]; - else [cw setTabbingMode:NSWindowTabbingModeAutomatic]; - } else { - [cw setTabbingMode:NSWindowTabbingModeDisallowed]; - } - } -#endif - if (!w->parent()) { - [cw setHasShadow:YES]; - [cw setAcceptsMouseMovedEvents:YES]; - } - if (w->shape()) { - [cw setOpaque:NO]; // shaped windows must be non opaque - [cw setBackgroundColor:[NSColor clearColor]]; // and with transparent background color - } - x->xid = (fl_uintptr_t)cw; - x->w = w; - flx(x); - wait_for_expose_value = 1; - if (!w->parent()) { - x->next = Fl_X::first; - Fl_X::first = x; - } else if (Fl_X::first) { - x->next = Fl_X::first->next; - Fl_X::first->next = x; - } - else { - x->next = NULL; - Fl_X::first = x; - } - FLView *myview = [[FLView alloc] initWithFrame:crect]; - [cw setContentView:myview]; - [myview release]; - [cw setLevel:winlevel]; - - q_set_window_title(cw, w->label(), w->iconlabel()); - NSImage *icon = icon_image; // is a window or default icon present? - if (!icon) icon = ((Fl_Cocoa_Screen_Driver*)Fl::screen_driver())->default_icon; - if (icon && (winstyle & NSWindowStyleMaskTitled) && w->label() && strlen(w->label()) > 0) { - [cw setRepresentedFilename:[NSString stringWithFormat:@"/%@", [cw title]]]; - NSButton *icon_button = [cw standardWindowButton:NSWindowDocumentIconButton]; - if (icon_button) { - [icon setSize:[icon_button frame].size]; - [icon_button setImage:icon]; - } - } - if (!force_position()) { - if (w->modal()) { - [cw center]; - } else if (w->non_modal()) { - [cw center]; - } else if (!w->fullscreen_active()) { - static NSPoint delta = NSZeroPoint; - delta = [cw cascadeTopLeftFromPoint:delta]; - } - crect = [cw frame]; // synchronize FLTK's and the system's window coordinates - this->x(round(crect.origin.x/s)); - this->y( round((main_screen_height - crect.origin.y)/s) - w->h() ); - } - if(w->menu_window()) { // make menu windows slightly transparent - [cw setAlphaValue:0.97]; - } - // Install DnD handlers - [myview registerForDraggedTypes:[NSArray arrayWithObjects:UTF8_pasteboard_type, - fl_filenames_pboard_type, nil]]; - - if (pWindow->get_size_range(NULL, NULL, NULL, NULL, NULL, NULL, NULL)) size_range(); - - if ( w->border() || (!w->modal() && !w->tooltip_window()) ) { - Fl_Tooltip::enter(0); - } - - if (w->modal()) Fl::modal_ = w; - - w->set_visible(); - if ( w->border() || (!w->modal() && !w->tooltip_window() && - w->user_data() != (void*)&Fl_Screen_Driver::transient_scale_display) ) Fl::handle(FL_FOCUS, w); - [cw setDelegate:[FLWindowDelegate singleInstance]]; - if (show_iconic()) { - show_iconic(0); - w->handle(FL_SHOW); // create subwindows if any - if (fl_mac_os_version < 101300) { // TODO: threshold may be smaller - // draw the window and its subwindows before its icon is computed - [cw recursivelySendToSubwindows:@selector(display) applyToSelf:YES]; - } - [cw miniaturize:nil]; - } else if (w->parent()) { // a subwindow - [cw setIgnoresMouseEvents:YES]; // needs OS X 10.2 - // next 2 statements so a subwindow doesn't leak out of its parent window - [cw setOpaque:NO]; - [cw setBackgroundColor:[NSColor clearColor]]; // transparent background color - starting_moved_window = w; - [cw setSubwindowFrame]; - starting_moved_window = NULL; - // needed if top window was first displayed miniaturized - FLWindow *pxid = fl_xid(w->top_window()); - [pxid makeFirstResponder:[pxid contentView]]; - } else { // a top-level window - if ([cw canBecomeKeyWindow]) [cw makeKeyAndOrderFront:nil]; - else [cw orderFront:nil]; - if (w->fullscreen_active()) { - if (fullscreen_screen_top() >= 0) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (fl_mac_os_version >= 101200) - cw.collectionBehavior |= NSWindowCollectionBehaviorFullScreenNone; -#endif - *no_fullscreen_x() = pWindow->x(); - *no_fullscreen_y() = pWindow->y(); - } - fullscreen_on(); - } - } - if (fl_sys_menu_bar && Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() && !w->parent() && w->border() && - !w->modal() && !w->non_modal()) { - Fl_MacOS_Sys_Menu_Bar_Driver::driver()->new_window(w); - } - int old_event = Fl::e_number; - w->handle(Fl::e_number = FL_SHOW); - Fl::e_number = old_event; - - // if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); } - if (!w->parent()) [myview did_view_resolution_change]; // to set mapped_to_retina to its current state - [pool release]; -} - - -static BOOL fullscreen_screen_border = NO; // YES means the multi-screened window had a border before - - -static NSUInteger calc_win_style(Fl_Window *win); - - -void Fl_Cocoa_Window_Driver::fullscreen_on() { - pWindow->_set_fullscreen(); - bool has_border = pWindow->border(); - if (fullscreen_screen_top() >= 0 && has_border) { - fullscreen_screen_border = YES; - has_border = false; - } - if (has_border) { - NSWindow *nswin = fl_xid(pWindow); -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 - if (fl_mac_os_version >= 101300) { - NSWindow *active_tab = [[nswin tabGroup] selectedWindow]; - if (active_tab) nswin = active_tab; - } -# endif - if (fullscreen_screen_border) { // from "All Screens" fullscreen to single-screen fullscreen - pWindow->_clear_fullscreen(); - [nswin setLevel:NSNormalWindowLevel]; - [nswin setStyleMask:calc_win_style(pWindow)]; //10.6 - pWindow->_set_fullscreen(); - } - [nswin toggleFullScreen:nil]; - } else { - FLWindow *nswin = fl_xid(pWindow); - if (nswin.styleMask & NSWindowStyleMaskFullScreen) { - // from single-screen fullscreen to "All Screens" fullscreen, with border -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (fl_mac_os_version >= 101200) { - bool allscreens_on = (nswin.collectionBehavior & NSWindowCollectionBehaviorFullScreenNone); - if (allscreens_on) nswin.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenNone; - [nswin toggleFullScreen:nil]; - if (allscreens_on) nswin.collectionBehavior |= NSWindowCollectionBehaviorFullScreenNone; - } else -#endif - [nswin toggleFullScreen:nil]; - if (*no_fullscreen_w() == 0) { - *no_fullscreen_x() = x(); - *no_fullscreen_y() = y(); - *no_fullscreen_w() = w(); - *no_fullscreen_h() = h(); - } - pWindow->_set_fullscreen(); - } - [nswin setStyleMask:NSWindowStyleMaskBorderless]; // 10.6 - if ([nswin isKeyWindow]) { - if ([nswin level] != NSStatusWindowLevel) { - [nswin setLevel:NSStatusWindowLevel]; - fixup_window_levels(); - } - } else if([nswin level] != NSNormalWindowLevel) { - [nswin setLevel:NSNormalWindowLevel]; - fixup_window_levels(); - } - int sx, sy, sw, sh, X, Y, W, H; - int top = fullscreen_screen_top(); - int bottom = fullscreen_screen_bottom(); - int left = fullscreen_screen_left(); - int right = fullscreen_screen_right(); - if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { - top = Fl::screen_num(x(), y(), w(), h()); - bottom = top; - left = top; - right = top; - } - Fl::screen_xywh(sx, sy, sw, sh, top); - Y = sy; - Fl::screen_xywh(sx, sy, sw, sh, bottom); - H = sy + sh - Y; - Fl::screen_xywh(sx, sy, sw, sh, left); - X = sx; - Fl::screen_xywh(sx, sy, sw, sh, right); - W = sx + sw - X; - pWindow->resize(X, Y, W, H); - } - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_Cocoa_Window_Driver::maximize() { - if (border()) [fl_xid(pWindow) performZoom:nil]; - else Fl_Window_Driver::maximize(); -} - - -void Fl_Cocoa_Window_Driver::un_maximize() { - if (border()) [fl_xid(pWindow) performZoom:nil]; - else Fl_Window_Driver::un_maximize(); -} - - -static NSUInteger calc_win_style(Fl_Window *win) { - NSUInteger winstyle; - if (win->border() && !win->fullscreen_active()) { - winstyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; - if (Fl_Window_Driver::driver(win)->is_resizable()) winstyle |= NSWindowStyleMaskResizable; - if (!win->modal()) winstyle |= NSWindowStyleMaskMiniaturizable; - } else winstyle = NSWindowStyleMaskBorderless; - return winstyle; -} - -static void restore_window_title_and_icon(Fl_Window *pWindow, NSImage *icon) { - FLWindow *nswin = fl_xid(pWindow); - q_set_window_title(nswin, pWindow->label(), pWindow->iconlabel()); - if (!icon) icon = ((Fl_Cocoa_Screen_Driver*)Fl::screen_driver())->default_icon; - if (icon && ([nswin styleMask] & NSWindowStyleMaskTitled) && pWindow->label() && - (strlen(pWindow->label()) > 0)) { - NSButton *icon_button = [nswin standardWindowButton:NSWindowDocumentIconButton]; - if (icon_button) { - [icon setSize:[icon_button frame].size]; - [icon_button setImage:icon]; - } - } -} - - -void Fl_Cocoa_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { - NSWindow *nswin = fl_xid(pWindow); - pWindow->_clear_fullscreen(); - if ([nswin styleMask] & NSWindowStyleMaskFullScreen) { -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 - if (fl_mac_os_version >= 101300) { - NSWindow *active_tab = [[nswin tabGroup] selectedWindow]; - if (active_tab) nswin = active_tab; - } -# endif - [nswin toggleFullScreen:nil]; - pWindow->resize(*no_fullscreen_x(), *no_fullscreen_y(), *no_fullscreen_w(), *no_fullscreen_h()); - } else { - // Transition from multi-screen fullscreen mode to normal mode - NSInteger level = NSNormalWindowLevel; - if (pWindow->modal()) level = modal_window_level(); - else if (pWindow->non_modal()) level = non_modal_window_level(); - /* Hide (orderOut) and later show (orderFront) the window to avoid a crash that - occurs in a very specific situation: the dock is at bottom and - H is larger than the maximum value for the display. - See "Crashing regression in MacOS code" in fltk.coredev. - */ - BOOL has_focus = [nswin isKeyWindow]; - [nswin orderOut:nil]; - [nswin setLevel:level]; - [nswin setStyleMask:calc_win_style(pWindow)]; //10.6 - restore_window_title_and_icon(pWindow, icon_image); - pWindow->resize(X, Y, W, H); - if (pWindow->maximize_active()) Fl_Window_Driver::maximize(); - if (has_focus) [nswin makeKeyAndOrderFront:nil]; - else [nswin orderFront:nil]; - } - Fl::handle(FL_FULLSCREEN, pWindow); - fullscreen_screen_border = NO; -} - - -void Fl_Cocoa_Window_Driver::fullscreen_screens(bool on_off) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (fl_mac_os_version >= 101200) { - FLWindow *xid = fl_mac_xid(pWindow); - if (on_off) xid.collectionBehavior |= NSWindowCollectionBehaviorFullScreenNone; - else xid.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenNone; - } -#endif -} - - -void Fl_Cocoa_Window_Driver::use_border() { - if (!shown() || pWindow->parent()) return; - if (pWindow->fullscreen_active() || pWindow->maximize_active()) { - // prevent changing border while window is fullscreen or maximized - static bool active = false; - if (!active) { - active = true; - bool b = !border(); - pWindow->border(b); - active = false; - } - return; - } - [fl_xid(pWindow) setStyleMask:calc_win_style(pWindow)]; // 10.6 - if (border()) restore_window_title_and_icon(pWindow, icon_image); - pWindow->redraw(); -} - -/* - * Tell the OS what window sizes we want to allow - */ -void Fl_Cocoa_Window_Driver::size_range() { - Fl_X *i = Fl_X::flx(pWindow); - if (i && i->xid) { - float s = Fl::screen_driver()->scale(0); - int bt = get_window_frame_sizes(pWindow); - int minw, minh, maxw, maxh; - pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - NSSize minSize = NSMakeSize(int(minw * s +.5) , int(minh * s +.5) + bt); - NSSize maxSize = NSMakeSize(maxw ? int(maxw * s + .5):32000, maxh ? int(maxh * s +.5) + bt:32000); - [(FLWindow*)i->xid setMinSize:minSize]; - [(FLWindow*)i->xid setMaxSize:maxSize]; - } -} - -void Fl_Cocoa_Window_Driver::wait_for_expose() -{ - if (fl_mac_os_version < 101300) { - [fl_xid(pWindow) recursivelySendToSubwindows:@selector(waitForExpose) applyToSelf:YES]; - } else { - Fl_Window_Driver::wait_for_expose(); - } -} - -/* - * set the window title bar name - */ -void Fl_Cocoa_Window_Driver::label(const char *name, const char *mininame) { - if (shown() || Fl_X::flx(pWindow)) { - q_set_window_title(fl_xid(pWindow), name, mininame); - if (fl_sys_menu_bar && Fl_Sys_Menu_Bar_Driver::window_menu_style()) - Fl_MacOS_Sys_Menu_Bar_Driver::driver()->rename_window(pWindow); - } -} - - -/* - * make a window visible - */ -void Fl_Cocoa_Window_Driver::show() { - Fl_X *top = NULL; - if (parent()) top = Fl_X::flx(pWindow->top_window()); - if (!shown() && (!parent() || (top && ![(FLWindow*)top->xid isMiniaturized]))) { - makeWindow(); - } else { - if ( !parent() ) { - Fl_X *i = Fl_X::flx(pWindow); - if ([(FLWindow*)i->xid isMiniaturized]) { - i->w->redraw(); - [(FLWindow*)i->xid deminiaturize:nil]; - } - if (!fl_capture) { - [(FLWindow*)i->xid makeKeyAndOrderFront:nil]; - } - } - else pWindow->set_visible(); - } -} - -/* - * resize a window - */ -void Fl_Cocoa_Window_Driver::resize(int X, int Y, int W, int H) { - if (!pWindow->shown() && (X != x() || Y != y())) force_position(1); - if (view_resized() || !visible_r()) { - pWindow->Fl_Group::resize(X, Y, W, H); - if (!pWindow->shown()) pWindow->init_sizes(); - } else if (!through_resize()) { - NSPoint pt = FLTKtoCocoa(pWindow, X, Y, H); - FLWindow *xid = fl_xid(pWindow); - through_resize(1); - if (W != w() || H != h() || Fl_Window::is_a_rescale()) { - NSRect r; - float s = Fl::screen_driver()->scale(screen_num()); - int bt = get_window_frame_sizes(pWindow); - r.origin = pt; - r.size.width = round(W*s); - r.size.height = round(H*s) + bt; - if (NSEqualRects(r, [xid frame])) { - pWindow->Fl_Group::resize(X, Y, W, H); // runs rarely, e.g. with scaled down test/tabs - pWindow->redraw(); - } else { - // First resize the logical FLTK coordinates for this and all children - if (!Fl_Window::is_a_rescale()) - pWindow->Fl_Group::resize(X, Y, W, H); - // Next update the physical Cocoa view - [xid setFrame:r display:YES]; - [[xid contentView] displayIfNeededIgnoringOpacity]; - // Finally tell the the group to render its contents if the code above - // didn't already - pWindow->redraw(); - } - } - else { - if (pWindow->parent()) starting_moved_window = pWindow; - if (!NSEqualPoints([xid frame].origin, pt)) - [xid setFrameOrigin:pt]; // set cocoa coords to FLTK position - else { - x(X); y(Y); - } - if (pWindow->parent()) starting_moved_window = NULL; - } - through_resize(0); - } - - // make sure subwindow doesn't leak outside parent - if (pWindow->parent()) [fl_xid(pWindow) checkSubwindowFrame]; -} - - -/* - * make all drawing go into this window (called by subclass flush() impl.) - - This can be called in 3 different situations: - - 1) When a window is created, resized or moved between low/high resolution displays. - macOS sends the drawRect: message to the window view after having prepared the - current graphics context to draw to this view. The drawRect: method sets through_drawRect - to YES and calls Fl_Window_Driver::flush(). Fl_Window_Driver::flush() calls - Fl_Window::flush() that calls Fl_Window::make_current() that uses the graphics - context of the window or the layer. The window's draw() function is then executed. - - 2) At each round of the FLTK event loop. - Fl::flush() is called, that calls Fl_Cocoa_Window_Driver::flush() on each window that needs drawing. - Fl_Cocoa_Window_Driver::flush() sets through_Fl_X_Flush to YES and marks the view as - needing display. The view is sent the displayIfNeededIgnoringOpacity or display message which makes - the OS send the view the drawRect: message. The program proceeds next as in 1) above. - - 3) An FLTK application can call Fl_Window::make_current() at any time before it draws to a window. - This occurs for instance in the idle callback function of the mandelbrot test program. Variables - through_Fl_X_flush and through_drawRect equal NO. - Before 10.14: The window graphics context is obtained. Subsequent drawing requests go to the window. - After 10.14: The layered view is marked as needing display. It will be sent the drawRect: message - at the next event loop. Subsequent drawing operations, until drawRect: runs, are sent to view->aux_bitmap. - - CAUTION: it's not possible to call Fl::wait(), Fl::check() nor Fl::ready() while in the draw() - function of a widget. Use an idle callback instead. - */ -void Fl_Cocoa_Window_Driver::make_current() -{ - q_release_context(); - Fl_X *i = Fl_X::flx(pWindow); - //NSLog(@"region-count=%d damage=%u",i->region?i->region->count:0, pWindow->damage()); - fl_window = (FLWindow*)i->xid; - ((Fl_Quartz_Graphics_Driver&)Fl_Graphics_Driver::default_driver()).high_resolution( mapped_to_retina() ); - - if (pWindow->as_overlay_window() && other_xid && changed_resolution()) { - destroy_double_buffer(); - changed_resolution(false); - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - FLView *view = (FLView*)[fl_window contentView]; - if (views_use_CA && !through_drawRect) { // detect direct calls from the app - [view setNeedsDisplay:YES]; - } - if (views_use_CA && view->aux_bitmap) { - gc = view->aux_bitmap; - } else -#endif - { -// ignore deprecation warning of "graphicsContextWithWindow" because used only with 10.13 or before -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSGraphicsContext *nsgc = (through_drawRect ? [NSGraphicsContext currentContext] : - [NSGraphicsContext graphicsContextWithWindow:fl_window]); -#pragma clang diagnostic pop - static SEL gc_sel = fl_mac_os_version >= 101000 ? @selector(CGContext) : @selector(graphicsPort); - gc = (CGContextRef)[nsgc performSelector:gc_sel]; - } - Fl_Graphics_Driver::default_driver().gc(gc); -#if defined(FLTK_HAVE_CAIROEXT) - CGContextSaveGState(gc); // one extra level -#endif - CGContextSaveGState(gc); // native context - // antialiasing must be deactivated because it applies to rectangles too - // and escapes even clipping!!! - // it gets activated when needed (e.g., draw text) - CGContextSetShouldAntialias(gc, false); - CGFloat hgt = [[fl_window contentView] frame].size.height; - float s = Fl::screen_driver()->scale(0); - CGContextTranslateCTM(gc, 0.5f*s, hgt-0.5f*s); - CGContextScaleCTM(gc, 1.0f, -1.0f); // now 0,0 is top-left point of the window - CGContextScaleCTM(gc, s, s); // apply current scaling factor - // for subwindows, limit drawing to inside of parent window - // half pixel offset is necessary for clipping as done by fl_cgrectmake_cocoa() - if (subRect()) { - CGContextClipToRect(gc, CGRectOffset(*(subRect()), -0.5, -0.5)); - } -// this is the context with origin at top left of (sub)window - CGContextSaveGState(gc); - fl_clip_region( 0 ); -#ifdef FLTK_HAVE_CAIROEXT - // update the cairo_t context - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -#endif -} - -// Give the Quartz context back to the system -void Fl_Cocoa_Window_Driver::q_release_context(Fl_Cocoa_Window_Driver *x) { - CGContextRef gc = (CGContextRef)Fl_Graphics_Driver::default_driver().gc(); - if (x && x->shown() && x->gc != gc) return; - if (!gc) return; - CGContextRestoreGState(gc); // match the CGContextSaveGState's of make_current - CGContextRestoreGState(gc); - CGContextFlush(gc); - Fl_Graphics_Driver::default_driver().gc(0); -#if defined(FLTK_HAVE_CAIROEXT) - CGContextRestoreGState(gc); -#endif -} - - -static NSBitmapImageRep *pdf_to_nsbitmapimagerep(NSData *pdfdata) { - NSImage *image = [[NSImage alloc] initWithData:pdfdata]; - NSInteger width = [image size].width * 2; - NSInteger height = [image size].height * 2; - NSBitmapImageRep *bitmap = [NSBitmapImageRep alloc]; - NSRect dest_r = NSMakeRect(0, 0, width, height); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 - if (fl_mac_os_version >= 100900) { - // This procedure is necessary because initWithFocusedViewRect is deprecated in macOS 10.14 - // and because it produces a bitmap with floating point pixel values with macOS 11.x - bitmap = [bitmap initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:0 - bitsPerPixel:0]; - NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]];// 10.4 - [[NSColor clearColor] set]; - NSRect r = NSMakeRect(0, 0, width, height); - NSRectFill(r); - [image drawInRect:dest_r]; // 10.9 - [NSGraphicsContext restoreGraphicsState]; - [localPool release]; - } else -#endif - { - [image lockFocus]; - // the deprecation warning at 10.14 can be ignored because runs only for macOS < 10.9 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - bitmap = [bitmap initWithFocusedViewRect:dest_r]; -#pragma clang diagnostic pop - [image unlockFocus]; - } - [bitmap setSize:[image size]]; - [image release]; - return bitmap; -} - - -Fl_Quartz_Copy_Surface_Driver::~Fl_Quartz_Copy_Surface_Driver() -{ - CGContextRestoreGState(gc); - CGContextEndPage(gc); - CGPDFContextClose(gc); // needs 10.5, necessary with macOS 10.15 - CGContextRelease(gc); - NSPasteboard *clip = [NSPasteboard generalPasteboard]; - [clip declareTypes:[NSArray arrayWithObjects:PDF_pasteboard_type, TIFF_pasteboard_type, nil] owner:nil]; - [clip setData:(NSData*)pdfdata forType:PDF_pasteboard_type]; - - //second, transform this PDF to a bitmap image and put it as tiff in clipboard with retina resolution - NSBitmapImageRep *bitmap = pdf_to_nsbitmapimagerep((NSData*)pdfdata); - CFRelease(pdfdata); - [clip setData:[bitmap TIFFRepresentation] forType:TIFF_pasteboard_type]; - [bitmap release]; - delete driver(); -} - -//////////////////////////////////////////////////////////////// -// Copy & Paste fltk implementation. -//////////////////////////////////////////////////////////////// - -// clipboard variables definitions : -char *fl_selection_buffer[2] = {NULL, NULL}; -int fl_selection_length[2] = {0, 0}; -static int fl_selection_buffer_length[2]; - -extern void fl_trigger_clipboard_notify(int source); - -static void clipboard_check(void) -{ - static NSInteger oldcount = -1; - NSInteger newcount = [[NSPasteboard generalPasteboard] changeCount]; - if (newcount == oldcount) return; - oldcount = newcount; - fl_trigger_clipboard_notify(1); -} - -static void resize_selection_buffer(int len, int clipboard) { - if (len <= fl_selection_buffer_length[clipboard]) - return; - delete[] fl_selection_buffer[clipboard]; - fl_selection_buffer[clipboard] = new char[len+100]; - fl_selection_buffer_length[clipboard] = len+100; -} - -/* - * create a selection - * stuff: pointer to selected data - * len: size of selected data - * type: always "plain/text" for now - */ -void Fl_Cocoa_Screen_Driver::copy(const char *stuff, int len, int clipboard, const char *type) { - if (!stuff || len<0) return; - if (clipboard >= 2) - clipboard = 1; // Only on X11 do multiple clipboards make sense. - - resize_selection_buffer(len+1, clipboard); - memcpy(fl_selection_buffer[clipboard], stuff, len); - fl_selection_buffer[clipboard][len] = 0; // needed for direct paste - fl_selection_length[clipboard] = len; - if (clipboard) { - CFDataRef text = CFDataCreate(kCFAllocatorDefault, (UInt8*)fl_selection_buffer[1], len); - if (text==NULL) return; // there was a pb creating the object, abort. - NSPasteboard *clip = [NSPasteboard generalPasteboard]; - [clip declareTypes:[NSArray arrayWithObject:UTF8_pasteboard_type] owner:nil]; - [clip setData:(NSData*)text forType:UTF8_pasteboard_type]; - CFRelease(text); - } -} - -static int get_plain_text_from_clipboard(int clipboard) -{ - NSInteger length = 0; - NSPasteboard *clip = [NSPasteboard generalPasteboard]; - NSString *found = [clip availableTypeFromArray:[NSArray arrayWithObjects:UTF8_pasteboard_type, @"public.utf16-plain-text", @"com.apple.traditional-mac-plain-text", nil]]; - if (found) { - NSData *data = [clip dataForType:found]; - if (data) { - NSInteger len; - char *aux_c = NULL; - if (![found isEqualToString:UTF8_pasteboard_type]) { - NSString *auxstring; - auxstring = (NSString *)CFStringCreateWithBytes(NULL, (const UInt8*)[data bytes], - [data length], - ([found isEqualToString:@"public.utf16-plain-text"] ? - kCFStringEncodingUnicode : kCFStringEncodingMacRoman), false); - aux_c = fl_strdup([auxstring UTF8String]); - [auxstring release]; - len = strlen(aux_c) + 1; - } - else len = [data length] + 1; - resize_selection_buffer((int)len, clipboard); - if (![found isEqualToString:UTF8_pasteboard_type]) { - strcpy(fl_selection_buffer[clipboard], aux_c); - free(aux_c); - } - else { - [data getBytes:fl_selection_buffer[clipboard] length:[data length]]; - } - fl_selection_buffer[clipboard][len - 1] = 0; - length = Fl_Screen_Driver::convert_crlf(fl_selection_buffer[clipboard], len - 1); // turn all \r characters into \n: - Fl::e_clipboard_type = Fl::clipboard_plain_text; - } - } - return (int)length; -} - -static Fl_RGB_Image* get_image_from_clipboard(Fl_Widget *receiver) -{ - NSPasteboard *clip = [NSPasteboard generalPasteboard]; - NSArray *present = [clip types]; // types in pasteboard in order of decreasing preference - NSArray *possible = [NSArray arrayWithObjects:PDF_pasteboard_type, TIFF_pasteboard_type, PICT_pasteboard_type, nil]; - NSString *found = nil; - NSUInteger rank; - for (NSUInteger i = 0; (!found) && i < [possible count]; i++) { - for (rank = 0; rank < [present count]; rank++) { // find first of possible types present in pasteboard - if ([[present objectAtIndex:rank] isEqualToString:[possible objectAtIndex:i]]) { - found = [present objectAtIndex:rank]; - break; - } - } - } - if (!found) return NULL; - NSData *data = [clip dataForType:found]; - if (!data) return NULL; - NSBitmapImageRep *bitmap = nil; - if ([found isEqualToString:TIFF_pasteboard_type]) { - bitmap = [[NSBitmapImageRep alloc] initWithData:data]; - } - else if ([found isEqualToString:PDF_pasteboard_type] || [found isEqualToString:PICT_pasteboard_type]) { - bitmap = pdf_to_nsbitmapimagerep(data); - } - if (!bitmap) return NULL; - int bytesPerPixel((int)[bitmap bitsPerPixel]/8); - int bpr((int)[bitmap bytesPerRow]); - int hh((int)[bitmap pixelsHigh]); - int ww((int)[bitmap pixelsWide]); - uchar *imagedata = new uchar[bpr * hh]; - memcpy(imagedata, [bitmap bitmapData], bpr * hh); - Fl_RGB_Image *image = new Fl_RGB_Image(imagedata, ww, hh, bytesPerPixel, (bpr == ww * bytesPerPixel ? 0 : bpr) ); - image->scale([bitmap size].width, [bitmap size].height); - image->alloc_array = 1; - [bitmap release]; - Fl::e_clipboard_type = Fl::clipboard_image; - return image; -} - -// Call this when a "paste" operation happens: -void Fl_Cocoa_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) { - if (type[0] == 0) type = Fl::clipboard_plain_text; - if (clipboard) { - Fl::e_clipboard_type = ""; - if (strcmp(type, Fl::clipboard_plain_text) == 0) { - fl_selection_length[1] = get_plain_text_from_clipboard(1); - } - else if (strcmp(type, Fl::clipboard_image) == 0) { - Fl::e_clipboard_data = get_image_from_clipboard(&receiver); - if (Fl::e_clipboard_data) { - int done = receiver.handle(FL_PASTE); - Fl::e_clipboard_type = ""; - if (done == 0) { - delete (Fl_Image*)Fl::e_clipboard_data; - Fl::e_clipboard_data = NULL; - } - } - return; - } - else - fl_selection_length[1] = 0; - } - Fl::e_text = fl_selection_buffer[clipboard]; - Fl::e_length = fl_selection_length[clipboard]; - if (!Fl::e_length) Fl::e_text = (char *)""; - receiver.handle(FL_PASTE); -} - -int Fl_Cocoa_Screen_Driver::clipboard_contains(const char *type) { - NSString *found = nil; - if (strcmp(type, Fl::clipboard_plain_text) == 0) { - found = [[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:UTF8_pasteboard_type, @"public.utf16-plain-text", @"com.apple.traditional-mac-plain-text", nil]]; - } - else if (strcmp(type, Fl::clipboard_image) == 0) { - found = [[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:TIFF_pasteboard_type, PDF_pasteboard_type, PICT_pasteboard_type, nil]]; - } - return found != nil; -} - -void Fl_Cocoa_Window_Driver::destroy(FLWindow *xid) { - [[xid parentWindow] removeChildWindow:xid]; // necessary until 10.6 at least - if (fl_sys_menu_bar && Fl_Sys_Menu_Bar_Driver::window_menu_style()) - Fl_MacOS_Sys_Menu_Bar_Driver::driver()->remove_window([xid getFl_Window]); - [xid close]; -} - - -void Fl_Cocoa_Window_Driver::map() { - FLWindow *xid = fl_xid(pWindow); - if (pWindow && xid && ![xid parentWindow]) { // 10.2 - // after a subwindow has been unmapped, it has lost its parent window and its frame may be wrong - [xid setSubwindowFrame]; - } - if (cursor) { - [cursor release]; - cursor = NULL; - } -} - - -void Fl_Cocoa_Window_Driver::unmap() { - FLWindow *xid = fl_xid(pWindow); - if (pWindow && xid) { - if (parent()) [[xid parentWindow] removeChildWindow:xid]; // necessary with at least 10.5 - [xid orderOut:nil]; - } -} - - -void Fl_Cocoa_Window_Driver::iconize() { - [fl_xid(pWindow) miniaturize:nil]; -} - -static NSImage *CGBitmapContextToNSImage(CGContextRef c) -// the returned NSImage is autoreleased -{ - CGImageRef cgimg = CGBitmapContextCreateImage(c); // requires 10.4 - NSImage* image = [[NSImage alloc] initWithCGImage:cgimg size:NSZeroSize]; // requires 10.6 - CFRelease(cgimg); - return [image autorelease]; -} - -int Fl_Cocoa_Window_Driver::set_cursor(Fl_Cursor c) -{ - if (cursor) { - [(NSCursor*)cursor release]; - cursor = NULL; - } - - switch (c) { - case FL_CURSOR_ARROW: cursor = [NSCursor arrowCursor]; break; - case FL_CURSOR_CROSS: cursor = [NSCursor crosshairCursor]; break; - case FL_CURSOR_INSERT: cursor = [NSCursor IBeamCursor]; break; - case FL_CURSOR_HAND: cursor = [NSCursor pointingHandCursor]; break; - case FL_CURSOR_MOVE: cursor = [NSCursor openHandCursor]; break; - case FL_CURSOR_NS: cursor = [NSCursor resizeUpDownCursor]; break; - case FL_CURSOR_WE: cursor = [NSCursor resizeLeftRightCursor]; break; - case FL_CURSOR_N: cursor = [NSCursor resizeUpCursor]; break; - case FL_CURSOR_E: cursor = [NSCursor resizeRightCursor]; break; - case FL_CURSOR_W: cursor = [NSCursor resizeLeftCursor]; break; - case FL_CURSOR_S: cursor = [NSCursor resizeDownCursor]; break; - default: - return 0; - } - - [(NSCursor*)cursor retain]; - - [fl_xid(pWindow) invalidateCursorRectsForView:[fl_xid(pWindow) contentView]]; - - return 1; -} - -int Fl_Cocoa_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { - if (cursor) { - [(NSCursor*)cursor release]; - cursor = NULL; - } - - if ((hotx < 0) || (hotx >= image->w())) - return 0; - if ((hoty < 0) || (hoty >= image->h())) - return 0; - - if (image->as_svg_image()) { - Fl_RGB_Image *image2 = (Fl_RGB_Image*)image->copy(); - image2->normalize(); - image = image2; - } - // OS X >= 10.6 can create a NSImage from a CGImage, but we need to - // support older versions, hence this pesky handling. - - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:NULL - pixelsWide:image->data_w() - pixelsHigh:image->data_h() - bitsPerSample:8 - samplesPerPixel:image->d() - hasAlpha:!(image->d() & 1) - isPlanar:NO - colorSpaceName:(image->d() <= 2 ? - NSDeviceWhiteColorSpace : NSDeviceRGBColorSpace) - bytesPerRow:(image->data_w() * image->d()) - bitsPerPixel:(image->d()*8)]; - - // Alpha needs to be premultiplied for this format - - const uchar *i = (const uchar*)*image->data(); - const int extra_data = image->ld() ? (image->ld() - image->data_w() * image->d()) : 0; - unsigned char *o = [bitmap bitmapData]; - for (int y = 0;y < image->data_h();y++) { - if (!(image->d() & 1)) { - for (int x = 0;x < image->data_w();x++) { - unsigned int alpha; - if (image->d() == 4) { - alpha = i[3]; - *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); - *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); - } - - alpha = i[1]; - *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); - *o++ = alpha; - i++; - } - } else { - // No alpha, so we can just copy everything directly. - int len = image->data_w() * image->d(); - memcpy(o, i, len); - o += len; - i += len; - } - i += extra_data; - } - - NSImage *nsimage = [[NSImage alloc] - initWithSize:NSMakeSize(image->w(), image->h())]; - - [nsimage addRepresentation:bitmap]; - - cursor = [[NSCursor alloc] - initWithImage:nsimage - hotSpot:NSMakePoint(hotx, hoty)]; - - [fl_xid(pWindow) invalidateCursorRectsForView:[fl_xid(pWindow) contentView]]; - - [bitmap release]; - [nsimage release]; - if (image->as_svg_image()) delete image; - - return 1; -} - -@interface PrintWithTitlebarItem : NSMenuItem { -} -- (void) toggleCallback; -@end - -@implementation PrintWithTitlebarItem -- (void) toggleCallback { - NSMenuItem *item = [self representedObject]; - const char *title; - if ([self state] == NSControlStateValueOn) { - [self setState:NSControlStateValueOff]; - title = Fl_Mac_App_Menu::print_no_titlebar; - } else { - [self setState:NSControlStateValueOn]; - title = Fl_Mac_App_Menu::print; - } - [item setTitle:NSLocalizedString([NSString stringWithUTF8String:title], nil)]; -} -@end - -static PrintWithTitlebarItem *print_with_titlebar_item = NULL; - -@interface FLaboutItemTarget : NSObject -{ -} -- (BOOL)validateMenuItem:(NSMenuItem *)item; -- (void)showPanel; -- (void)printPanel; -- (void)terminate:(id)sender; -@end -@implementation FLaboutItemTarget -- (BOOL)validateMenuItem:(NSMenuItem *)item -{ // invalidate the Quit item of the application menu when running modal or when in native file chooser - if ([[NSApp keyWindow] isKindOfClass:[NSSavePanel class]]) return NO; - if (!Fl::modal() || [item action] != @selector(terminate:)) return YES; - return NO; -} -- (void)showPanel -{ - NSDictionary *options; - options = [NSDictionary dictionaryWithObjectsAndKeys: - [[[NSAttributedString alloc] - initWithString:[NSString stringWithFormat:@" GUI with FLTK %d.%d", - FL_MAJOR_VERSION, FL_MINOR_VERSION ]] autorelease], @"Credits", - nil]; - [NSApp orderFrontStandardAboutPanelWithOptions:options]; -} -- (void)printPanel -{ - bool grab_decoration = ([print_with_titlebar_item state] == NSControlStateValueOn); - fl_lock_function(); - fl_print_or_copy_window(Fl::first_window(), grab_decoration, 1); - fl_unlock_function(); -} -- (void)terminate:(id)sender -{ - [NSApp terminate:sender]; -} -@end - -static void createAppleMenu(void) -{ - static BOOL donethat = NO; - if (donethat) return; - donethat = YES; - NSMenu *mainmenu, *services = nil, *appleMenu; - NSMenuItem *menuItem; - NSString *title; - - SEL infodictSEL = (fl_mac_os_version >= 100200 ? @selector(localizedInfoDictionary) : @selector(infoDictionary)); - NSString *nsappname = [[[NSBundle mainBundle] performSelector:infodictSEL] objectForKey:@"CFBundleName"]; - if (nsappname == nil) - nsappname = [[NSProcessInfo processInfo] processName]; - appleMenu = [[NSMenu alloc] initWithTitle:@""]; - /* Add menu items */ - title = [NSString stringWithFormat:NSLocalizedString([NSString stringWithUTF8String:Fl_Mac_App_Menu::about],nil), nsappname]; - menuItem = [appleMenu addItemWithTitle:title action:@selector(showPanel) keyEquivalent:@""]; - FLaboutItemTarget *about = [[FLaboutItemTarget alloc] init]; - [menuItem setTarget:about]; - [appleMenu addItem:[NSMenuItem separatorItem]]; - // Print front window - title = NSLocalizedString([NSString stringWithUTF8String:Fl_Mac_App_Menu::print], nil); - if ([title length] > 0) { - menuItem = [appleMenu - addItemWithTitle:title - action:@selector(printPanel) - keyEquivalent:@""]; - [menuItem setTarget:about]; - [menuItem setEnabled:YES]; - // Toggle "Print Window with titlebar" / "Print Window" - title = NSLocalizedString([NSString stringWithUTF8String:Fl_Mac_App_Menu::toggle_print_titlebar], nil); - print_with_titlebar_item = [[PrintWithTitlebarItem alloc] initWithTitle:title - action:@selector(toggleCallback) - keyEquivalent:@""]; - [appleMenu addItem:print_with_titlebar_item]; - [print_with_titlebar_item setTarget:print_with_titlebar_item]; - [print_with_titlebar_item setRepresentedObject:menuItem]; - [print_with_titlebar_item setState:NSControlStateValueOn]; - [print_with_titlebar_item setEnabled:YES]; - [appleMenu addItem:[NSMenuItem separatorItem]]; - } - // Services Menu - services = [[NSMenu alloc] initWithTitle:@""]; - menuItem = [appleMenu - addItemWithTitle:NSLocalizedString([NSString stringWithUTF8String:Fl_Mac_App_Menu::services], nil) - action:nil - keyEquivalent:@""]; - [appleMenu setSubmenu:services forItem:menuItem]; - [appleMenu addItem:[NSMenuItem separatorItem]]; - // Hide AppName - title = [NSString stringWithFormat:NSLocalizedString([NSString stringWithUTF8String:Fl_Mac_App_Menu::hide],nil), nsappname]; - [appleMenu addItemWithTitle:title - action:@selector(hide:) - keyEquivalent:@"h"]; - // Hide Others - menuItem = [appleMenu - addItemWithTitle:NSLocalizedString( - [NSString stringWithUTF8String:Fl_Mac_App_Menu::hide_others] , nil) - action:@selector(hideOtherApplications:) - keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)]; - // Show All - [appleMenu addItemWithTitle:NSLocalizedString( - [NSString stringWithUTF8String:Fl_Mac_App_Menu::show], nil) - action:@selector(unhideAllApplications:) - keyEquivalent:@""]; - [appleMenu addItem:[NSMenuItem separatorItem]]; - // Quit AppName - title = [NSString stringWithFormat:NSLocalizedString( - [NSString stringWithUTF8String:Fl_Mac_App_Menu::quit], nil), - nsappname]; - menuItem = [appleMenu addItemWithTitle:title - action:@selector(terminate:) - keyEquivalent:@"q"]; - [menuItem setTarget:about]; - - /* Put menu into the menubar */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:appleMenu]; - mainmenu = [[NSMenu alloc] initWithTitle:@""]; - [mainmenu addItem:menuItem]; - [NSApp setMainMenu:mainmenu]; - if (services) { - [NSApp setServicesMenu:services]; - [services release]; - } - [mainmenu release]; - [appleMenu release]; - [menuItem release]; - Fl_MacOS_Sys_Menu_Bar_Driver::driver(); -} - - -void Fl_Cocoa_Window_Driver::set_key_window() -{ - [fl_xid(pWindow) makeKeyWindow]; -} - -static NSImage *imageFromText(const char *text, int *pwidth, int *pheight) -{ - const char *p, *q; - int width = 0, height, w2, ltext = (int)strlen(text); - fl_font(FL_HELVETICA, 10); - p = text; - int nl = 0; - while(nl < 100 && (q=strchr(p, '\n')) != NULL) { - nl++; - w2 = (int)fl_width(p, (int)(q - p)); - if (w2 > width) width = w2; - p = q + 1; - } - if (text[ ltext - 1] != '\n') { - nl++; - w2 = int(fl_width(p)); - if (w2 > width) width = w2; - } - height = nl * fl_height() + 3; - width += 6; - Fl_Image_Surface *off = new Fl_Image_Surface(width, height, 1); - Fl_Surface_Device::push_current(off); - CGContextSetRGBFillColor( (CGContextRef)off->offscreen(), 0,0,0,0); - fl_rectf(0,0,width,height); - fl_color(FL_BLACK); - p = text; - fl_font(FL_HELVETICA, 10); - int y = fl_height(); - while(TRUE) { - q = strchr(p, '\n'); - if (q) { - fl_draw(p, (int)(q - p), 3, y); - } else { - fl_draw(p, 3, y); - break; - } - y += fl_height(); - p = q + 1; - } - Fl_Surface_Device::pop_current(); - NSImage* image = CGBitmapContextToNSImage( (CGContextRef)off->offscreen() ); - delete off; - *pwidth = width; - *pheight = height; - return image; -} - -static NSImage *defaultDragImage(int *pwidth, int *pheight) -{ - const int width = 50, height = 40; - Fl_Image_Surface *off = new Fl_Image_Surface(width, height, 1); - Fl_Surface_Device::push_current(off); - fl_font(FL_HELVETICA, 20); - fl_color(FL_BLACK); - char str[4]; - // the "Delivery truck" Unicode character from "Apple Color Emoji" font - int l = fl_utf8encode(0x1F69A, str); - fl_draw(str, l, 1, 16); - Fl_Surface_Device::pop_current(); - NSImage* image = CGBitmapContextToNSImage( (CGContextRef)off->offscreen() ); - delete off; - *pwidth = width; - *pheight = height; - return image; -} - - -int Fl_Cocoa_Screen_Driver::dnd(int use_selection) -{ - CFDataRef text = CFDataCreate(kCFAllocatorDefault, (UInt8*)fl_selection_buffer[0], fl_selection_length[0]); - if (text==NULL) return false; - NSAutoreleasePool *localPool; - localPool = [[NSAutoreleasePool alloc] init]; - Fl_Widget *w = Fl::pushed(); - Fl_Window *win = w->top_window(); - FLView *myview = (FLView*)[fl_mac_xid(win) contentView]; - NSEvent *theEvent = [NSApp currentEvent]; - - int width, height; - NSImage *image; - if (use_selection) { - fl_selection_buffer[0][ fl_selection_length[0] ] = 0; - image = imageFromText(fl_selection_buffer[0], &width, &height); - } else { - image = defaultDragImage(&width, &height); - } - - NSPoint pt = [theEvent locationInWindow]; - pt.x -= width/2; - pt.y -= height/2; - NSPasteboardItem *pbItem = [[[NSPasteboardItem alloc] init] autorelease]; - [pbItem setData:(NSData*)text forType:UTF8_pasteboard_type]; - NSDraggingItem *dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease]; - NSRect r = {pt, {CGFloat(width), CGFloat(height)}}; - [dragItem setDraggingFrame:r contents:image]; - [myview beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem] event:theEvent source:myview]; - CFRelease(text); - [localPool release]; - return true; -} - -// rescales an NSBitmapImageRep (and also rewrites it with integer pixels) -static NSBitmapImageRep *scale_nsbitmapimagerep(NSBitmapImageRep *img, float scale) -{ - int w = (int)[img pixelsWide]; - int h = (int)[img pixelsHigh]; - long int scaled_w = lround(scale * w); - long int scaled_h = lround(scale * h); - NSBitmapImageRep *scaled = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:scaled_w - pixelsHigh:scaled_h - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:scaled_w*4 - bitsPerPixel:32]; - NSDictionary *dict = - [NSDictionary dictionaryWithObject:scaled - forKey:NSGraphicsContextDestinationAttributeName]; - NSGraphicsContext *oldgc = [NSGraphicsContext currentContext]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithAttributes:dict]]; - [[NSColor clearColor] set]; - NSRect r = NSMakeRect(0, 0, scaled_w, scaled_h); - NSRectFill(r); - [img drawInRect:r]; - [NSGraphicsContext setCurrentContext:oldgc]; - [img release]; - return scaled; -} - -static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImageRep *from, - int to_x, int to_y) - /* Copies in bitmap "to" the bitmap "from" with its top-left angle at coordinates to_x, to_y - On retina displays both bitmaps have double width and height - to_width is the width in screen units of "to". On retina, its pixel width is twice that. - */ -{ - const uchar *from_data = [from bitmapData]; - // 10.4 required by the bitmapFormat message - if (([to bitmapFormat] & NSBitmapFormatAlphaFirst) && - !([from bitmapFormat] & NSBitmapFormatAlphaFirst) ) { - // "to" is ARGB and "from" is RGBA --> convert "from" to ARGB - // it is enough to read "from" starting one byte earlier, because A is always 0xFF: - // RGBARGBA becomes (A)RGBARGB - from_data--; - } else if ( !([to bitmapFormat] & NSBitmapFormatAlphaFirst) && ([from bitmapFormat] & NSBitmapFormatAlphaFirst) ) { - // "from" is ARGB and "to" is RGBA --> convert "from" to RGBA - // it is enough to offset reading by one byte because A is always 0xFF - // so ARGBARGB becomes RGBARGB(A) as needed - from_data++; - } - int to_w = (int)[to pixelsWide]; // pixel width of "to" - int from_w = (int)[from pixelsWide]; // pixel width of "from" - int from_h = (int)[from pixelsHigh]; // pixel height of "from" - int to_depth = (int)[to samplesPerPixel]; - int from_depth = (int)[from samplesPerPixel]; - int depth = 0; - if (to_depth > from_depth) depth = from_depth; - else if (from_depth > to_depth) depth = to_depth; - float factor = to_w / (float)to_width; // scaling factor is 1 for classic displays and 2 for retina - to_x = factor*to_x; // transform offset from screen unit to pixels - to_y = factor*to_y; - // perform the copy - uchar *tobytes = [to bitmapData] + to_y * to_w * to_depth + to_x * to_depth; - const uchar *frombytes = from_data; - for (int i = 0; i < from_h; i++) { - if (depth == 0) { // depth is always 0 in case of RGBA <-> ARGB conversion - if (i == 0 && from_data < [from bitmapData]) { - memcpy(tobytes+1, frombytes+1, from_w * from_depth-1); // avoid reading before [from bitmapData] - *tobytes = 0xFF; // set the very first A byte - } else if (i == from_h - 1 && from_data > [from bitmapData]) { - memcpy(tobytes, frombytes, from_w * from_depth - 1); // avoid reading after end of [from bitmapData] - *(tobytes + from_w * from_depth - 1) = 0xFF; // set the very last A byte - } else { - memcpy(tobytes, frombytes, from_w * from_depth); - } - } else { - for (int j = 0; j < from_w; j++) { - memcpy(tobytes + j * to_depth, frombytes + j * from_depth, depth); - } - } - tobytes += to_w * to_depth; - frombytes += from_w * from_depth; - } -} - - -static NSBitmapImageRep* GL_rect_to_nsbitmap(Fl_Window *win, int x, int y, int w, int h) -// captures a rectangle from a GL window and returns it as an allocated NSBitmapImageRep -// the capture has high res on retina -{ - Fl_Device_Plugin *plugin = Fl_Device_Plugin::opengl_plugin(); - if (!plugin) return nil; - Fl_RGB_Image *img = plugin->rectangle_capture(win, x, y, w, h); - NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:img->w() pixelsHigh:img->h() bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:4*img->w() bitsPerPixel:32]; - if (img->d() == 4) memcpy([bitmap bitmapData], img->array, 4*img->data_w()*img->data_h()); - else { - memset([bitmap bitmapData], 0xFF, [bitmap bytesPerPlane]); - const uchar *from = img->array; - for (int r = 0; r < img->h(); r++) { - uchar *to = [bitmap bitmapData] + r * [bitmap bytesPerRow]; - for (int c = 0; c < img->w(); c++) { - memcpy(to, from, 3); - from += 3; - to += 4; - } - } - } - delete img; - return bitmap; -} - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -static NSBitmapImageRep* rect_to_NSBitmapImage_layer(Fl_Window *win, int x, int y, int w, int h) -{ // capture window data for layer-based views because initWithFocusedViewRect: does not work for them - FLView *view = (FLView*)[fl_xid(win) contentView]; - if (!view->aux_bitmap) return nil; - CGImageRef cgimg = CGBitmapContextCreateImage(view->aux_bitmap); - if (x || y || w != win->w() || h != win->h()) { - float s = Fl::screen_driver()->scale(0); - if (Fl_Cocoa_Window_Driver::driver(win)->mapped_to_retina()) s *= 2; - CGRect rect = CGRectMake(x * s, y * s, w * s, h * s); - CGImageRef cgimg2 = CGImageCreateWithImageInRect(cgimg, rect); - CGImageRelease(cgimg); - cgimg = cgimg2; - } - NSBitmapImageRep *bitmap = (cgimg ? [[NSBitmapImageRep alloc] initWithCGImage:cgimg/*10.5*/] : nil); - CGImageRelease(cgimg); - return bitmap; -} -#endif - -static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, int w, int h) { - NSBitmapImageRep *bitmap = nil; - NSRect rect; - float s = Fl_Graphics_Driver::default_driver().scale(); - if (win->as_gl_window() && y >= 0) { - bitmap = GL_rect_to_nsbitmap(win, x, y, w, h); - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - else if (views_use_CA) { - bitmap = rect_to_NSBitmapImage_layer(win, x, y, w, h); - } -#endif - else { - NSView *winview = nil; - if ( through_Fl_X_flush && Fl_Window::current() == win ) { - rect = NSMakeRect(x - 0.5, y - 0.5, w, h); - } - else { - winview = [fl_xid(win) contentView]; - int view_h = [winview frame].size.height; - rect = NSMakeRect(int(x*s), int(view_h-y*s-int(h*s)), int(w*s), int(h*s)); - // lock focus to win's view - if (fl_mac_os_version >= 101100) { - NSGraphicsContext *ctxt = [fl_xid(win) - performSelector:@selector(graphicsContext)]; - [ctxt saveGraphicsState]; // necessary under 10.11 - } - [winview performSelector:@selector(lockFocus)]; - } - // The image depth is 3 until macOS 10.5 and 4 with 10.6 and above - // the deprecation warning at 10.14 can be ignored because runs only for macOS < 10.14 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect]; -#pragma clang diagnostic pop - if ( !( through_Fl_X_flush && Fl_Window::current() == win) ) { - [winview performSelector:@selector(unlockFocus)]; - if (fl_mac_os_version >= 101100) { - NSGraphicsContext *ctxt = [fl_xid(win) - performSelector:@selector(graphicsContext)]; - [ctxt restoreGraphicsState]; - } - } - } - return bitmap; -} - -static NSBitmapImageRep* rect_to_NSBitmapImageRep_subwins(Fl_Window *win, int x, int y, int w, int h, bool capture_subwins) -/* Captures a rectangle from a mapped window. - On retina displays, the resulting bitmap has 2 pixels per screen unit. - The returned value is to be released after use - */ -{ - Fl_Rect r(x, y, w, h); - NSBitmapImageRep *bitmap = [fl_xid(win) rect_to_NSBitmapImageRep:&r]; - if (!capture_subwins || !bitmap) return bitmap; - - // capture also subwindows - NSArray *children = [fl_xid(win) childWindows]; // 10.2 - NSEnumerator *enumerator = [children objectEnumerator]; - id child; - while ((child = [enumerator nextObject]) != nil) { - if (![child isKindOfClass:[FLWindow class]]) continue; - Fl_Window *sub = [(FLWindow*)child getFl_Window]; - CGRect rsub = CGRectMake(sub->x(), win->h() -(sub->y()+sub->h()), sub->w(), sub->h()); - CGRect clip = CGRectMake(x, win->h()-(y+h), w, h); - clip = CGRectIntersection(rsub, clip); - if (CGRectIsNull(clip)) continue; - NSBitmapImageRep *childbitmap = rect_to_NSBitmapImageRep_subwins(sub, clip.origin.x - sub->x(), - win->h() - clip.origin.y - sub->y() - clip.size.height, clip.size.width, clip.size.height, true); - if (childbitmap) { - // if bitmap is high res and childbitmap is not, childbitmap must be rescaled - if (!win->as_gl_window() && Fl_Cocoa_Window_Driver::driver(win)->mapped_to_retina() && - sub->as_gl_window() && !Fl::use_high_res_GL()) { - childbitmap = scale_nsbitmapimagerep(childbitmap, 2); - } - float s = Fl_Graphics_Driver::default_driver().scale(); - write_bitmap_inside(bitmap, w * s, childbitmap, - (clip.origin.x - x) * s, - (win->h() - clip.origin.y - clip.size.height - y) * s ); - } - [childbitmap release]; - } - return bitmap; -} - -static void nsbitmapProviderReleaseData (void *info, const void *data, size_t size) -{ - [(NSBitmapImageRep*)info release]; -} - -CGImageRef Fl_Cocoa_Window_Driver::CGImage_from_window_rect(int x, int y, int w, int h, bool capture_subwins) -{ - /* Returns a capture of a rectangle of a mapped window as a CGImage. - With retina displays, the returned image has twice the width and height. - CFRelease the returned CGImageRef after use - */ - CGImageRef img; - NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep_subwins(pWindow, x, y, w, h, capture_subwins); - img = (CGImageRef)[bitmap performSelector:@selector(CGImage)]; // requires Mac OS 10.5 - CGImageRetain(img); - [bitmap release]; - return img; -} - -int Fl_Cocoa_Window_Driver::decorated_w() -{ - if (!shown() || parent() || !border() || !visible()) - return w(); - int bx=0; - get_window_frame_sizes(pWindow, &bx); - return w() + 2 * bx; -} - -int Fl_Cocoa_Window_Driver::decorated_h() -{ - if (!shown() || parent() || !border() || !visible()) - return h(); - int bx = 0, by = 0; - int bt = get_window_frame_sizes(pWindow, &bx, &by); - float s = Fl::screen_driver()->scale(0); - return h() + bt/s; -} - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 && defined(__BLOCKS__) - -// Requires -weak_framework ScreenCaptureKit and used by FLTK for macOS ≥ 15.0 -static CGImageRef capture_decorated_window_SCK(NSWindow *nswin) { - if (@available(macOS 15.0, *)) { - __block CGImageRef capture = NULL; - __block BOOL capture_err = NO; - void (^block_to_stop_main_loop)(void) = ^{ CFRunLoopStop(CFRunLoopGetMain()); }; - // Fix for bug in ScreenCaptureKit that modifies a window's styleMask the first time - // it captures a non-resizable window. We memorize each non-resizable window's styleMask, - // and we restore modified styleMasks later, after the screen capture. - NSMutableArray *xid_array = [NSMutableArray arrayWithCapacity:2]; - NSMutableArray *mask_array = [NSMutableArray arrayWithCapacity:2]; - Fl_Window *win = Fl::first_window(); - while (win) { - if (!win->parent() && win->border()) { - FLWindow *xid = fl_mac_xid(win); - if (xid && !([xid styleMask] & NSWindowStyleMaskResizable)) { - [xid_array addObject:xid]; - NSUInteger mask = [xid styleMask]; - [mask_array addObject:[NSData dataWithBytes:&mask length:sizeof(NSUInteger)]]; - } - } - win = Fl::next_window(win); - } - CGWindowID target_id = (CGWindowID)[nswin windowNumber]; - NSRect r = [nswin frame]; - int W = r.size.width, H = r.size.height; - [SCShareableContent getCurrentProcessShareableContentWithCompletionHandler: // macOS 14.4 - ^(SCShareableContent *shareableContent, NSError *error) { - SCWindow *scwin = nil; - if (!error) { - NSEnumerator *enumerator = [[shareableContent windows] objectEnumerator]; - while ((scwin = (SCWindow*)[enumerator nextObject]) != nil) { - if ([scwin windowID] == target_id) { - break; - } - } - } - if (!scwin) { - capture_err = YES; - dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); - return; - } - SCContentFilter *filter = [[[SCContentFilter alloc] initWithDesktopIndependentWindow:scwin] autorelease]; - int s = (int)[filter pointPixelScale]; - SCStreamConfiguration *config = [[[SCStreamConfiguration alloc] init] autorelease]; - [config setIgnoreShadowsSingleWindow:YES]; - [config setIgnoreShadowsDisplay:YES]; // necessary with macOS 26 Tahoe - [config setShowsCursor:NO]; - [config setWidth:W*s]; - [config setHeight:H*s]; - [config setIncludeChildWindows:NO]; // macOS 14.2 - [SCScreenshotManager captureImageWithFilter:filter - configuration:config - completionHandler:^(CGImageRef sampleBuffer, NSError *error) { - if (error) capture_err = YES; - else { - capture = sampleBuffer; - CGImageRetain(capture); - } - dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); - } - ]; - } - ]; - // run the main loop until the 1 or 2 blocks above have completed and have stopped the loop - while (!capture_err && !capture) CFRunLoopRun(); - if (capture_err) return NULL; - // ScreenCaptureKit bug cont'd: restore modified styleMasks. - for (int i = 0, count = (int)[xid_array count]; i < count; i++) { - NSUInteger mask; - [(NSData*)[mask_array objectAtIndex:i] getBytes:&mask length:sizeof(NSUInteger)]; - NSWindow *xid = (NSWindow*)[xid_array objectAtIndex:i]; - if (mask != [xid styleMask]) [xid setStyleMask:mask]; - } - return capture; - } else return NULL; -} -#endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 - - -CGImageRef Fl_Cocoa_Window_Driver::capture_decorated_window_10_5(NSWindow *nswin) { - // usable with 10.5 and above - CGImageRef img = NULL; -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 && defined(__BLOCKS__) - if (fl_mac_os_version >= 150000) - img = capture_decorated_window_SCK(nswin); - else -#endif - { -# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_15_0 - NSInteger win_id = [nswin windowNumber]; - CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL); - img = CGWindowListCreateImageFromArray(CGRectNull, array, kCGWindowImageBoundsIgnoreFraming); // 10.5 - CFRelease(array); -# endif - } - return img; -} - - -static CGImageRef capture_window_titlebar(Fl_Window *win, Fl_Cocoa_Window_Driver *cocoa_dr) { - CGImageRef img; - // verified OK from 10.6 - FLWindow *nswin = fl_xid(win); - CGImageRef img_full = Fl_Cocoa_Window_Driver::capture_decorated_window_10_5(nswin); - int bt = [nswin frame].size.height - [[nswin contentView] frame].size.height; - int s = CGImageGetWidth(img_full) / [nswin frame].size.width; - CGRect cgr = CGRectMake(0, 0, CGImageGetWidth(img_full), bt * s); - img = CGImageCreateWithImageInRect(img_full, cgr); // 10.4 - CGImageRelease(img_full); - return img; -} - - -void Fl_Cocoa_Window_Driver::draw_titlebar_to_context(CGContextRef gc, int w, int h) -{ - FLWindow *nswin = fl_xid(pWindow); - if ([nswin canBecomeMainWindow]) [nswin makeMainWindow]; - [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO]; - CGImageRef img = capture_window_titlebar(pWindow, this); - if (img) { - CGContextSaveGState(gc); - CGContextDrawImage(gc, CGRectMake(0, 0, w, h), img); - CGImageRelease(img); - CGContextRestoreGState(gc); - } -} - - -/* Returns the version of the running Mac OS as an int such as 100802 for 10.8.2, - and also assigns that value to global fl_mac_os_version. - N.B.: macOS "Big Sur" 11.0 can produce 2 different values for fl_mac_os_version: - - when SDK 11.0 is used, fl_mac_os_version is set to 110000 (or bigger) - - when SDK 10.15 or earlier is used, fl_mac_os_version is set to 101600 - That is reported to facilitate life of apps that assumed majorVersion would remain equal to 10 - and used only minorVersion to determine what is the running version of macOS. - */ -int Fl_Darwin_System_Driver::calc_mac_os_version() { - if (fl_mac_os_version) return fl_mac_os_version; - int M = 0, m = 0, b = 0; - NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 - if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { - NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; - M = (int)version.majorVersion; - m = (int)version.minorVersion; - b = (int)version.patchVersion; - } - else -#endif - { - NSDictionary * sv = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; - const char *s = [[sv objectForKey:@"ProductVersion"] UTF8String]; - sscanf(s, "%d.%d.%d", &M, &m, &b); - } - [localPool release]; - fl_mac_os_version = M*10000 + m*100 + b; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (fl_mac_os_version >= 101400) views_use_CA = YES; -#endif - if (fl_mac_os_version < 100700) - fprintf(stderr, "Warning: FLTK expects macOS version 10.7 or higher"); - return fl_mac_os_version; -} - -/* - Note: `prefs` can be NULL! - */ -char *Fl_Darwin_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, - const char *vendor, const char *application) -{ - static char *filename = 0L; - - // Allocate this only when we need it, but then keep it allocated. - if (!filename) filename = (char*)::calloc(1, FL_PATH_MAX); - - switch (root&Fl_Preferences::ROOT_MASK) { - case Fl_Preferences::SYSTEM: - // This is safe, even on machines that use different languages - strcpy(filename, "/Library/Preferences"); - break; - case Fl_Preferences::USER: - { // Find the home directory, but return NULL if components were not found. - // If we ever port this to iOS: NSHomeDirectory returns tha location of the app! - const char *e = ::getenv("HOME"); - // if $HOME does not exist, try NSHomeDirectory, the Mac way. - NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; - if ( (e==0L) || (e[0]==0) || (::access(e, F_OK)==-1) ) { - NSString *nsHome = NSHomeDirectory(); - if (nsHome) - e = [nsHome UTF8String]; - } - // if NSHomeDirectory does not work, try getpwuid(), the Unix way. - if ( (e==0L) || (e[0]==0) || (::access(e, F_OK)==-1) ) { - struct passwd *pw = getpwuid(getuid()); - e = pw->pw_dir; - } - snprintf(filename, FL_PATH_MAX, "%s/Library/Preferences", e); - [localPool release]; - break; } - } - - // Make sure that the parameters are not NULL - if ( (vendor==0L) || (vendor[0]==0) ) - vendor = "unknown"; - if ( (application==0L) || (application[0]==0) ) - application = "unknown"; - - // Our C path names for preferences will be: - // SYSTEM: "/Library/Preferences/$vendor/$application.prefs" - // USER: "/Users/$user/Library/Preferences/$vendor/$application.prefs" - snprintf(filename + strlen(filename), FL_PATH_MAX - strlen(filename), - "/%s/%s.prefs", vendor, application); - - return filename; -} - -Fl_Cocoa_Window_Driver::~Fl_Cocoa_Window_Driver() -{ - if (shape_data_) { - if (shape_data_->mask) { - CGImageRelease(shape_data_->mask); - } - delete shape_data_; - } - [icon_image release]; -} - -static NSImage* rgb_to_nsimage(const Fl_RGB_Image *rgb) { - if (!rgb) return nil; - int ld = rgb->ld(); - if (!ld) ld = rgb->data_w() * rgb->d(); - NSImage *win_icon = nil; - if (fl_mac_os_version >= 101000) { - NSBitmapImageRep *bitmap = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:rgb->data_w() - pixelsHigh:rgb->data_h() - bitsPerSample:8 - samplesPerPixel:rgb->d() - hasAlpha:!(rgb->d() & 1) - isPlanar:NO - colorSpaceName:(rgb->d() <= 2 ? NSDeviceWhiteColorSpace : - NSDeviceRGBColorSpace) - bitmapFormat:NSBitmapFormatAlphaNonpremultiplied - bytesPerRow:ld - bitsPerPixel:rgb->d() * 8]; // 10.4 - memcpy([bitmap bitmapData], rgb->array, rgb->data_h() * ld); - win_icon = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; - [win_icon addRepresentation:bitmap]; - [bitmap release]; - } - return win_icon; -} - -void Fl_Cocoa_Window_Driver::icons(const Fl_RGB_Image *icons[], int count) { - [icon_image release]; - icon_image = nil; - if (count >= 1 && pWindow->border() && pWindow->label() && strlen(pWindow->label())) { - ((Fl_RGB_Image*)icons[0])->normalize(); - icon_image = rgb_to_nsimage(icons[0]); - } -} - -void Fl_Cocoa_Screen_Driver::default_icons(const Fl_RGB_Image *icons[], int count) { - [default_icon release]; - default_icon = nil; - if (count >= 1) { - default_icon = rgb_to_nsimage(icons[0]); - } -} - - -fl_uintptr_t Fl_Cocoa_Window_Driver::os_id() { - return [fl_xid(pWindow) windowNumber]; -} - - -// Deprecated in 1.4 - only for backward compatibility with 1.3 -void Fl::insertion_point_location(int x, int y, int height) { - Fl_Cocoa_Screen_Driver::insertion_point_location(x, y, height); -} -// Deprecated in 1.4 - only for backward compatibility with 1.3 -void Fl::reset_marked_text() { - Fl_Cocoa_Screen_Driver::reset_marked_text(); -} diff --git a/src/Fl_get_key_mac.cxx b/src/Fl_get_key_mac.cxx deleted file mode 100644 index b9ad86dd1..000000000 --- a/src/Fl_get_key_mac.cxx +++ /dev/null @@ -1,102 +0,0 @@ -// -// MacOS keyboard state routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: this file contains platform specific code and will therefore -// not be processed by doxygen (see Doxyfile.in). - -// Return the current state of a key. Keys are named by fltk symbols, -// which are actually X keysyms. So this has to translate to macOS -// symbols. - -#include <FL/Fl.H> -#include <FL/platform.H> -#include "drivers/Darwin/Fl_Darwin_System_Driver.H" -#include "drivers/Cocoa/Fl_Cocoa_Screen_Driver.H" - -// The list of Mac OS virtual keycodes appears with OS 10.5 in -// ...../Carbon.framework/Frameworks/HIToolbox.framework/Headers/Events.h -#include <Carbon/Carbon.h> - -// convert an FLTK (X) keysym to a MacOS symbol: -// This table is in numeric order by FLTK symbol order for binary search. -static const struct {unsigned short vk, fltk;} vktab[] = { - { kVK_Space, ' ' }, { kVK_ANSI_Quote, '\'' }, { kVK_ANSI_Comma, ',' }, { kVK_ANSI_Minus, '-' }, { kVK_ANSI_Period, '.' }, { kVK_ANSI_Slash, '/' }, - { kVK_ANSI_0, '0' }, { kVK_ANSI_1, '1' }, { kVK_ANSI_2, '2' }, { kVK_ANSI_3, '3' }, - { kVK_ANSI_4, '4' }, { kVK_ANSI_5, '5' }, { kVK_ANSI_6, '6' }, { kVK_ANSI_7, '7' }, - { kVK_ANSI_8, '8' }, { kVK_ANSI_9, '9' }, { kVK_ANSI_Semicolon, ';' }, { kVK_ANSI_Equal, '=' }, - { kVK_ANSI_A, 'A' }, { kVK_ANSI_B, 'B' }, { kVK_ANSI_C, 'C' }, { kVK_ANSI_D, 'D' }, - { kVK_ANSI_E, 'E' }, { kVK_ANSI_F, 'F' }, { kVK_ANSI_G, 'G' }, { kVK_ANSI_H, 'H' }, - { kVK_ANSI_I, 'I' }, { kVK_ANSI_J, 'J' }, { kVK_ANSI_K, 'K' }, { kVK_ANSI_L, 'L' }, - { kVK_ANSI_M, 'M' }, { kVK_ANSI_N, 'N' }, { kVK_ANSI_O, 'O' }, { kVK_ANSI_P, 'P' }, - { kVK_ANSI_Q, 'Q' }, { kVK_ANSI_R, 'R' }, { kVK_ANSI_S, 'S' }, { kVK_ANSI_T, 'T' }, - { kVK_ANSI_U, 'U' }, { kVK_ANSI_V, 'V' }, { kVK_ANSI_W, 'W' }, { kVK_ANSI_X, 'X' }, - { kVK_ANSI_Y, 'Y' }, { kVK_ANSI_Z, 'Z' }, - { kVK_ANSI_LeftBracket, '[' }, { kVK_ANSI_Backslash, '\\' }, { kVK_ANSI_RightBracket, ']' }, { kVK_ANSI_Grave, '`' }, - { kVK_VolumeDown, FL_Volume_Down}, { kVK_Mute, FL_Volume_Mute}, { kVK_VolumeUp, FL_Volume_Up}, - { kVK_Delete, FL_BackSpace }, { kVK_Tab, FL_Tab }, { kVK_ISO_Section, FL_Iso_Key }, { kVK_Return, FL_Enter }, /*{ 0x7F, FL_Pause }, - { 0x7F, FL_Scroll_Lock },*/ { kVK_Escape, FL_Escape }, - { kVK_JIS_Kana, FL_Kana}, { kVK_JIS_Eisu, FL_Eisu}, { kVK_JIS_Yen, FL_Yen}, { kVK_JIS_Underscore, FL_JIS_Underscore}, - { kVK_Home, FL_Home }, { kVK_LeftArrow, FL_Left }, - { kVK_UpArrow, FL_Up }, { kVK_RightArrow, FL_Right }, { kVK_DownArrow, FL_Down }, { kVK_PageUp, FL_Page_Up }, - { kVK_PageDown, FL_Page_Down }, { kVK_End, FL_End }, /*{ 0x7F, FL_Print }, { 0x7F, FL_Insert },*/ - { 0x6e, FL_Menu }, { kVK_Help, FL_Help }, { kVK_ANSI_KeypadClear, FL_Num_Lock }, - { kVK_ANSI_KeypadEnter, FL_KP_Enter }, { kVK_ANSI_KeypadMultiply, FL_KP+'*' }, { kVK_ANSI_KeypadPlus, FL_KP+'+'}, - { kVK_JIS_KeypadComma, FL_KP+',' }, - { kVK_ANSI_KeypadMinus, FL_KP+'-' }, { kVK_ANSI_KeypadDecimal, FL_KP+'.' }, { kVK_ANSI_KeypadDivide, FL_KP+'/' }, - { kVK_ANSI_Keypad0, FL_KP+'0' }, { kVK_ANSI_Keypad1, FL_KP+'1' }, { kVK_ANSI_Keypad2, FL_KP+'2' }, { kVK_ANSI_Keypad3, FL_KP+'3' }, - { kVK_ANSI_Keypad4, FL_KP+'4' }, { kVK_ANSI_Keypad5, FL_KP+'5' }, { kVK_ANSI_Keypad6, FL_KP+'6' }, { kVK_ANSI_Keypad7, FL_KP+'7' }, - { kVK_ANSI_Keypad8, FL_KP+'8' }, { kVK_ANSI_Keypad9, FL_KP+'9' }, { kVK_ANSI_KeypadEquals, FL_KP+'=' }, - { kVK_F1, FL_F+1 }, { kVK_F2, FL_F+2 }, { kVK_F3, FL_F+3 }, { kVK_F4, FL_F+4 }, - { kVK_F5, FL_F+5 }, { kVK_F6, FL_F+6 }, { kVK_F7, FL_F+7 }, { kVK_F8, FL_F+8 }, - { kVK_F9, FL_F+9 }, { kVK_F10, FL_F+10 }, { kVK_F11, FL_F+11 }, { kVK_F12, FL_F+12 }, - { kVK_F13, FL_F+13 }, { kVK_F14, FL_F+14 }, { kVK_F15, FL_F+15 }, { kVK_F16, FL_F+16 }, - { kVK_F17, FL_F+17 }, { kVK_F18, FL_F+18 }, { kVK_F19, FL_F+19 }, { kVK_F20, FL_F+20 }, - { kVK_Shift, FL_Shift_L }, { kVK_RightShift, FL_Shift_R }, { kVK_Control, FL_Control_L }, { kVK_RightControl, FL_Control_R }, - { kVK_CapsLock, FL_Caps_Lock }, { kVK_Command, FL_Meta_L }, { 0x36, FL_Meta_R }, - { kVK_Option, FL_Alt_L }, { kVK_RightOption, FL_Alt_R }, { kVK_ForwardDelete, FL_Delete } -}; - -// Computes the macKeyLookUp table that transforms a Mac OS virtual keycode into an FLTK keysym -unsigned short *Fl_Darwin_System_Driver::compute_macKeyLookUp() -{ - static unsigned short macKeyLookUp[128]; - memset(macKeyLookUp, 0, sizeof(macKeyLookUp)); - for (unsigned i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) { - macKeyLookUp[vktab[i].vk] = vktab[i].fltk; - } - return macKeyLookUp; -} - -static int fltk2mac(int fltk) { - int a = 0; - int b = sizeof(vktab)/sizeof(*vktab); - while (a < b) { - int c = (a+b)/2; - if (vktab[c].fltk == fltk) return vktab[c].vk; - if (vktab[c].fltk < fltk) a = c+1; else b = c; - } - return vktab[a].vk; -} - -//: returns true, if that key was pressed during the last event -int Fl_Cocoa_Screen_Driver::event_key(int k) { - return get_key(k); -} - -//: returns true, if that key is pressed right now -int Fl_Cocoa_Screen_Driver::get_key(int k) { - return (int)CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, fltk2mac(k) ); // 10.4 -} diff --git a/src/Fl_get_key_win32.cxx b/src/Fl_get_key_win32.cxx deleted file mode 100644 index cb844722d..000000000 --- a/src/Fl_get_key_win32.cxx +++ /dev/null @@ -1,127 +0,0 @@ -// -// Windows keyboard state routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: this file contains platform specific code and will therefore -// not be processed by doxygen (see Doxyfile.in). - -// Return the current state of a key. Keys are named by fltk symbols, -// which are actually X keysyms. So this has to translate to Windows -// VK_x symbols. - -#include "drivers/WinAPI/Fl_WinAPI_Screen_Driver.H" -#include <FL/platform.H> - -// Convert an FLTK (X) keysym to a Windows VK symbol: -// See also the inverse converter in Fl_win32.cxx -// This table is in numeric order by FLTK symbol order for binary search: - -static const struct {unsigned short vk, fltk;} vktab[] = { - {VK_SPACE, ' '}, - {'1', '!'}, - {0xde, '\"'}, - {'3', '#'}, - {'4', '$'}, - {'5', '%'}, - {'7', '&'}, - {0xde, '\''}, - {'9', '('}, - {'0', ')'}, - {'8', '*'}, - {0xbb, '+'}, - {0xbc, ','}, - {0xbd, '-'}, - {0xbe, '.'}, - {0xbf, '/'}, - {0xba, ':'}, - {0xba, ';'}, - {0xbc, '<'}, - {0xbb, '='}, - {0xbe, '>'}, - {0xbf, '?'}, - {'2', '@'}, - {0xdb, '['}, - {0xdc, '\\'}, - {0xdd, ']'}, - {'6', '^'}, - {0xbd, '_'}, - {0xc0, '`'}, - {0xdb, '{'}, - {0xdc, '|'}, - {0xdd, '}'}, - {0xc0, '~'}, - {VK_BACK, FL_BackSpace}, - {VK_TAB, FL_Tab}, - {VK_CLEAR, 0xff0b/*XK_Clear*/}, - {0xe2 /*VK_OEM_102*/, FL_Iso_Key}, - {VK_RETURN, FL_Enter}, - {VK_PAUSE, FL_Pause}, - {VK_SCROLL, FL_Scroll_Lock}, - {VK_ESCAPE, FL_Escape}, - {VK_HOME, FL_Home}, - {VK_LEFT, FL_Left}, - {VK_UP, FL_Up}, - {VK_RIGHT, FL_Right}, - {VK_DOWN, FL_Down}, - {VK_PRIOR, FL_Page_Up}, - {VK_NEXT, FL_Page_Down}, - {VK_END, FL_End}, - {VK_SNAPSHOT, FL_Print}, - {VK_INSERT, FL_Insert}, - {VK_APPS, FL_Menu}, - {VK_NUMLOCK, FL_Num_Lock}, -//{VK_???, FL_KP_Enter}, - {VK_MULTIPLY, FL_KP+'*'}, - {VK_ADD, FL_KP+'+'}, - {VK_SUBTRACT, FL_KP+'-'}, - {VK_DECIMAL, FL_KP+'.'}, - {VK_DIVIDE, FL_KP+'/'}, - {VK_LSHIFT, FL_Shift_L}, - {VK_RSHIFT, FL_Shift_R}, - {VK_LCONTROL, FL_Control_L}, - {VK_RCONTROL, FL_Control_R}, - {VK_CAPITAL, FL_Caps_Lock}, - {VK_LWIN, FL_Meta_L}, - {VK_RWIN, FL_Meta_R}, - {VK_LMENU, FL_Alt_L}, - {VK_RMENU, FL_Alt_R}, - {VK_DELETE, FL_Delete} -}; - -static int fltk2ms(int fltk) { - if (fltk >= '0' && fltk <= '9') return fltk; - if (fltk >= 'A' && fltk <= 'Z') return fltk; - if (fltk >= 'a' && fltk <= 'z') return fltk-('a'-'A'); - if (fltk > FL_F && fltk <= FL_F+16) return fltk-(FL_F-(VK_F1-1)); - if (fltk >= FL_KP+'0' && fltk<=FL_KP+'9') return fltk-(FL_KP+'0'-VK_NUMPAD0); - int a = 0; - int b = sizeof(vktab)/sizeof(*vktab); - while (a < b) { - int c = (a+b)/2; - if (vktab[c].fltk == fltk) return vktab[c].vk; - if (vktab[c].fltk < fltk) a = c+1; else b = c; - } - return 0; -} - -int Fl_WinAPI_Screen_Driver::event_key(int k) { - return GetKeyState(fltk2ms(k))&~1; -} - -int Fl_WinAPI_Screen_Driver::get_key(int k) { - uchar foo[256]; - GetKeyboardState(foo); - return foo[fltk2ms(k)]&~1; -} diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx deleted file mode 100644 index b5aca1c78..000000000 --- a/src/Fl_win32.cxx +++ /dev/null @@ -1,2976 +0,0 @@ -// -// Windows-specific code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: this file contains platform specific code and will therefore -// not be processed by doxygen (see Doxyfile.in). - -// This file contains Windows-specific code for FLTK which is always linked -// in. Search other files for "_WIN32" or filenames ending in _win32.cxx -// for other system-specific code. - -/* We require Windows 2000 features (e.g. VK definitions) */ -# if !defined(WINVER) || (WINVER < 0x0500) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0500 -# endif -# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0500 -# endif - -// recent versions of MinGW warn: "Please include winsock2.h before windows.h" -#if !defined(__CYGWIN__) -# include <winsock2.h> -#endif -#include <windows.h> -#include <ole2.h> -#include <shellapi.h> -// Some versions of MinGW now require us to explicitly include winerror to get S_OK defined -#include <winerror.h> -#include <math.h> // for ceil() and round() -#include <algorithm> // for min and max (clamp is C++17) - -void fl_free_fonts(void); -void fl_release_dc(HWND, HDC); -void fl_cleanup_dc_list(void); - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include "Fl_Window_Driver.H" -#include "Fl_Screen_Driver.H" -#include "Fl_Timeout.h" -#include "print_button.h" -#include <FL/Fl_Graphics_Driver.H> // for fl_graphics_driver -#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H" -#include "drivers/WinAPI/Fl_WinAPI_System_Driver.H" -#include "drivers/WinAPI/Fl_WinAPI_Screen_Driver.H" -#include "drivers/GDI/Fl_GDI_Graphics_Driver.H" -#include <FL/fl_utf8.h> -#include <FL/fl_string_functions.h> -#include <FL/Fl_Window.H> -#include <FL/fl_draw.H> -#include <FL/Enumerations.H> -#include <FL/Fl_Tooltip.H> -#include <FL/Fl_Paged_Device.H> -#include <FL/Fl_Image_Surface.H> -#include "flstring.h" -#include "drivers/GDI/Fl_Font.H" -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <time.h> -#include <signal.h> -#ifdef __CYGWIN__ -# include <sys/time.h> -# include <unistd.h> -#endif - -#if !defined(NO_TRACK_MOUSE) -# include <commctrl.h> // TrackMouseEvent -#endif - -#if defined(__GNUC__) -# include <wchar.h> -#endif - -// old versions of MinGW lack definition of GET_XBUTTON_WPARAM: - -#ifndef GET_XBUTTON_WPARAM -#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) -#endif - -static bool is_dpi_aware = false; - -extern bool fl_clipboard_notify_empty(void); -extern void fl_trigger_clipboard_notify(int source); -extern HBRUSH fl_brush_action(int action); -extern void fl_cleanup_pens(void); - -// MSVC 2010 can't find round() although <math.h> is included above, -// which is surprising because ceil() works fine. -// We could (should?) probably add CMake feature tests for round() -// and ceil() rather than depending on MSVC version numbers. -// AlbrechtS, 02/2010 - Note: we don't know about MSVC 2012 - 2015, see -// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros - -#if defined(_MSC_VER) && _MSC_VER <= 1600 -#define round(A) int((A) + 0.5) -#endif // _MSC_VER <= 1600 - -// Internal functions -static void fl_clipboard_notify_target(HWND wnd); -static void fl_clipboard_notify_untarget(HWND wnd); -static int clamp(int v, int a, int b) { - if (v < a) return a; - if (v > b) return b; - return v; -} - -// Internal variables -static HWND clipboard_wnd = 0; -static HWND next_clipboard_wnd = 0; - -static bool initial_clipboard = true; - -// dynamic wsock dll handling api: -#if defined(__CYGWIN__) && !defined(SOCKET) -# define SOCKET int -#endif - -/* - Dynamic linking of imm32.dll - This library is only needed for a hand full (four ATM) functions relating to - international text rendering and locales. Dynamically loading reduces initial - size and link dependencies. -*/ -static HMODULE s_imm_module = 0; -typedef BOOL(WINAPI *flTypeImmAssociateContextEx)(HWND, HIMC, DWORD); -static flTypeImmAssociateContextEx flImmAssociateContextEx = 0; -typedef HIMC(WINAPI *flTypeImmGetContext)(HWND); -static flTypeImmGetContext flImmGetContext = 0; -typedef BOOL(WINAPI *flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); -static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0; -typedef BOOL(WINAPI *flTypeImmReleaseContext)(HWND, HIMC); -static flTypeImmReleaseContext flImmReleaseContext = 0; - -static void get_imm_module() { - s_imm_module = LoadLibrary("IMM32.DLL"); - if (!s_imm_module) - Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" - "Please check your input method manager library accessibility."); - flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx"); - flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); - flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); - flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); -} - -// USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have -// TrackMouseEvent()... -// -// Now (Dec. 2008) we can assume that current Cygwin/MinGW versions -// support the TrackMouseEvent() function, but WinCE obviously doesn't -// support it (STR 2095). Therefore, USE_TRACK_MOUSE is enabled by -// default, but you can disable it by defining NO_TRACK_MOUSE. -// -// TrackMouseEvent is only used to support window leave notifications -// under Windows. It can be used to get FL_LEAVE events, when the -// mouse leaves the _main_ application window (FLTK detects subwindow -// leave events by using normal move events). -// -// Implementation note: If the mouse cursor leaves one subwindow and -// enters another window, then Windows sends a WM_MOUSEMOVE message to -// the new window before it sends a WM_MOUSELEAVE message to the old -// (just left) window. We save the current mouse window in a static variable, -// and if we get a WM_MOUSELEAVE event for the current mouse window, this -// means that the top level window has been left (otherwise we would have -// got another WM_MOUSEMOVE message before). - -// #define NO_TRACK_MOUSE - -#if !defined(NO_TRACK_MOUSE) -# define USE_TRACK_MOUSE -#endif // NO_TRACK_MOUSE - -static Fl_Window *track_mouse_win = 0; // current TrackMouseEvent() window - -// USE_CAPTURE_MOUSE_WIN - this must be defined for TrackMouseEvent to work -// correctly with subwindows - otherwise a single mouse click and release -// (without a move) would generate phantom leave events. -// This defines, if the current mouse window (maybe a subwindow) or the -// main window should get mouse events after pushing (and holding) a mouse -// button, i.e. when dragging the mouse. This is done by calling SetCapture -// (see below). - -#ifdef USE_TRACK_MOUSE -#define USE_CAPTURE_MOUSE_WIN -#endif // USE_TRACK_MOUSE - -// -// WM_SYNCPAINT is an "undocumented" message, which is finally defined in -// VC++ 6.0. -// - -#ifndef WM_SYNCPAINT -# define WM_SYNCPAINT 0x0088 -#endif - -#ifndef WM_MOUSELEAVE -# define WM_MOUSELEAVE 0x02a3 -#endif - -#ifndef WM_MOUSEWHEEL -# define WM_MOUSEWHEEL 0x020a -#endif - -#ifndef WHEEL_DELTA -# define WHEEL_DELTA 120 // according to MSDN. -#endif - -// This is only defined on Vista and upwards... -#ifndef WM_MOUSEHWHEEL -# define WM_MOUSEHWHEEL 0x020E -#endif - -#ifndef SM_CXPADDEDBORDER -# define SM_CXPADDEDBORDER (92) // STR #3061 -#endif - -// https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083(v=vs.85).aspx -#ifndef WM_DPICHANGED -# define WM_DPICHANGED 0x02E0 -#endif - -// -// WM_FLSELECT is the user-defined message that we get when one of -// the sockets has pending data, etc. -// - -#define WM_FLSELECT (WM_APP + 1) // WM_APP is used for hide-window - - -//////////////////////////////////////////////////////////////// -// interface to poll/select call: - -// fd's are only implemented for sockets. Microsoft Windows does not -// have a unified IO system, so it doesn't support select() on files, -// devices, or pipes... -// -// Microsoft provides the Berkeley select() call and an asynchronous -// select function that sends a Windows message when the select condition -// exists. However, we don't try to use the asynchronous WSAAsyncSelect() -// any more for good reasons (see above). -// -// A.S. Dec 2009: We got reports that current winsock2.h files define -// POLLIN, POLLOUT, and POLLERR with conflicting values WRT what we -// used before (STR #2301). Therefore we must not use these values -// for our internal purposes, but use FL_READ, FL_WRITE, and -// FL_EXCEPT, as defined for use in Fl::add_fd(). -// -static int maxfd = 0; -static fd_set fdsets[3]; - -extern IDropTarget *flIDropTarget; - -static int nfds = 0; -static int fd_array_size = 0; -static struct FD { - int fd; - short events; - void (*cb)(FL_SOCKET, void *); // keep socket api opaque at this level to reduce multiplatform deps headaches - void *arg; -} *fd = 0; - -extern unsigned int fl_codepage; - -void Fl_WinAPI_System_Driver::add_fd(int n, int events, void (*cb)(FL_SOCKET, void *), void *v) { - remove_fd(n, events); - int i = nfds++; - if (i >= fd_array_size) { - fd_array_size = 2 * fd_array_size + 1; - fd = (FD *)realloc(fd, fd_array_size * sizeof(FD)); - } - fd[i].fd = n; - fd[i].events = (short)events; - fd[i].cb = cb; - fd[i].arg = v; - - if (events & FL_READ) - FD_SET((unsigned)n, &fdsets[0]); - if (events & FL_WRITE) - FD_SET((unsigned)n, &fdsets[1]); - if (events & FL_EXCEPT) - FD_SET((unsigned)n, &fdsets[2]); - if (n > maxfd) - maxfd = n; -} - -void Fl_WinAPI_System_Driver::add_fd(int fd, void (*cb)(FL_SOCKET, void *), void *v) { - add_fd(fd, FL_READ, cb, v); -} - -void Fl_WinAPI_System_Driver::remove_fd(int n, int events) { - int i, j; - for (i = j = 0; i < nfds; i++) { - if (fd[i].fd == n) { - short e = fd[i].events & ~events; - if (!e) - continue; // if no events left, delete this fd - fd[i].events = e; - } - // move it down in the array if necessary: - if (j < i) { - fd[j] = fd[i]; - } - j++; - } - nfds = j; - - if (events & FL_READ) - FD_CLR(unsigned(n), &fdsets[0]); - if (events & FL_WRITE) - FD_CLR(unsigned(n), &fdsets[1]); - if (events & FL_EXCEPT) - FD_CLR(unsigned(n), &fdsets[2]); -} - -void Fl_WinAPI_System_Driver::remove_fd(int n) { - remove_fd(n, -1); -} - -// these pointers are set by the Fl::lock() function: -static void nothing() {} -void (*fl_lock_function)() = nothing; -void (*fl_unlock_function)() = nothing; - -static void *thread_message_; -void *Fl_WinAPI_System_Driver::thread_message() { - void *r = thread_message_; - thread_message_ = 0; - return r; -} - -extern int fl_send_system_handlers(void *e); - -MSG fl_msg; - -// A local helper function to flush any pending callback requests -// from the awake ring-buffer -static void process_awake_handler_requests(void) { - Fl_Awake_Handler func; - void *data; - while (Fl_WinAPI_System_Driver::pop_awake_handler(func, data) == 0) { - func(data); - } -} - -// This is never called with time_to_wait < 0.0. -// It *should* return negative on error, 0 if nothing happens before -// timeout, and >0 if any callbacks were done. This version -// always returns 1. -double Fl_WinAPI_System_Driver::wait(double time_to_wait) { - - time_to_wait = Fl_System_Driver::wait(time_to_wait); - - int have_message = 0; - - if (nfds) { - // For Windows we need to poll for socket input FIRST, since - // the event queue is not something we can select() on... - timeval t; - t.tv_sec = 0; - t.tv_usec = 0; - - fd_set fdt[3]; - memcpy(fdt, fdsets, sizeof fdt); // one shot faster fdt init - if (select(maxfd + 1, &fdt[0], &fdt[1], &fdt[2], &t)) { - // We got something - do the callback! - for (int i = 0; i < nfds; i++) { - SOCKET f = fd[i].fd; - short revents = 0; - if (FD_ISSET(f, &fdt[0])) - revents |= FL_READ; - if (FD_ISSET(f, &fdt[1])) - revents |= FL_WRITE; - if (FD_ISSET(f, &fdt[2])) - revents |= FL_EXCEPT; - if (fd[i].events & revents) - fd[i].cb(f, fd[i].arg); - } - time_to_wait = 0.0; // just peek for any messages - } else { - // we need to check them periodically, so set a short timeout: - if (time_to_wait > .001) - time_to_wait = .001; - } - } - - if (Fl::idle() || Fl::damage()) - time_to_wait = 0.0; - - // if there are no more windows and this timer is set - // to FOREVER, continue through or look up indefinitely - if (!Fl::first_window() && time_to_wait == 1e20) - time_to_wait = 0.0; - - fl_unlock_function(); - - time_to_wait = (time_to_wait > 10000 ? 10000 : time_to_wait); - - time_to_wait = Fl_Timeout::time_to_wait(time_to_wait); - - int t_msec = (int)(time_to_wait * 1000.0 + 0.5); - MsgWaitForMultipleObjects(0, NULL, FALSE, t_msec, QS_ALLINPUT); - - fl_lock_function(); - - // Execute the message we got, and all other pending messages: - // have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) { - if (fl_send_system_handlers(&fl_msg)) - continue; - - // Let applications treat WM_QUIT identical to SIGTERM on *nix - if (fl_msg.message == WM_QUIT) - raise(SIGTERM); - - if (fl_msg.message == fl_wake_msg) { - // Used for awaking wait() from another thread - thread_message_ = (void *)fl_msg.wParam; - process_awake_handler_requests(); - } - - TranslateMessage(&fl_msg); - DispatchMessageW(&fl_msg); - } - - // The following conditional test: !Fl_System_Driver::awake_ring_empty() - // equivalent to: - // (Fl::awake_ring_head_ != Fl::awake_ring_tail_) - // is a workaround / fix for STR #3143. This works, but a better solution - // would be to understand why the PostThreadMessage() messages are not - // seen by the main window if it is being dragged/ resized at the time. - // If a worker thread posts an awake callback to the ring buffer - // whilst the main window is unresponsive (if a drag or resize operation - // is in progress) we may miss the PostThreadMessage(). So here, we check if - // there is anything pending in the awake ring buffer and if so process - // it. This is not strictly thread safe (for speed it compares the head - // and tail indices without first locking the ring buffer) but is intended - // only as a fall-back recovery mechanism if the awake processing stalls. - // If the test erroneously returns true (may happen if we test the indices - // whilst they are being modified) we will call process_awake_handler_requests() - // unnecessarily, but this has no harmful consequences so is safe to do. - // Note also that if we miss the PostThreadMessage(), then thread_message_ - // will not be updated, so this is not a perfect solution, but it does - // recover and process any pending awake callbacks. - // Normally the ring buffer head and tail indices will match and this - // comparison will do nothing. Addresses STR #3143 - if (!Fl_System_Driver::awake_ring_empty()) { - process_awake_handler_requests(); - } - - Fl::flush(); - - // This should return 0 if only timer events were handled: - return 1; -} - -// just like Fl_WinAPI_System_Driver::wait(0.0) except no callbacks are done: -int Fl_WinAPI_System_Driver::ready() { - if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) - return 1; - if (!nfds) - return 0; - timeval t; - t.tv_sec = 0; - t.tv_usec = 0; - fd_set fdt[3]; - memcpy(fdt, fdsets, sizeof fdt); - return select(0, &fdt[0], &fdt[1], &fdt[2], &t); -} - -static void delayed_create_print_window(void *) { - Fl::remove_check(delayed_create_print_window); - fl_create_print_window(); -} - -void Fl_WinAPI_Screen_Driver::open_display_platform() { - static char beenHereDoneThat = 0; - - if (beenHereDoneThat) - return; - - beenHereDoneThat = 1; - // test whether DpiAwareness has been set before via a manifest - /*enum PROCESS_DPI_AWARENESS { // in shellscalingapi.h from Window 8.1 - PROCESS_DPI_UNAWARE, - PROCESS_SYSTEM_DPI_AWARE, - PROCESS_PER_MONITOR_DPI_AWARE - };*/ - typedef HRESULT(WINAPI * GetProcessDpiAwareness_type)(HANDLE, int *); - GetProcessDpiAwareness_type fl_GetProcessDpiAwareness = - (GetProcessDpiAwareness_type)GetProcAddress(LoadLibrary("Shcore.DLL"), "GetProcessDpiAwareness"); - int awareness; - if (!fl_GetProcessDpiAwareness || fl_GetProcessDpiAwareness(NULL, &awareness) != S_OK) { - awareness = 0; //corresponds to PROCESS_DPI_UNAWARE; - } - if (awareness == 2 /*PROCESS_PER_MONITOR_DPI_AWARE*/) is_dpi_aware = true; - if (awareness == 0 /*PROCESS_DPI_UNAWARE*/) { // DpiAwareness has not been set via a manifest - typedef void *fl_DPI_AWARENESS_CONTEXT; - typedef BOOL(WINAPI * SetProcessDpiAwarenessContext_type)(fl_DPI_AWARENESS_CONTEXT); - SetProcessDpiAwarenessContext_type fl_SetProcessDpiAwarenessContext = - (SetProcessDpiAwarenessContext_type)GetProcAddress(LoadLibrary("User32.DLL"), "SetProcessDpiAwarenessContext"); - if (fl_SetProcessDpiAwarenessContext) { - const fl_DPI_AWARENESS_CONTEXT fl_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = (fl_DPI_AWARENESS_CONTEXT)(-4); - is_dpi_aware = fl_SetProcessDpiAwarenessContext(fl_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - } - if (!is_dpi_aware) { - typedef HRESULT(WINAPI * SetProcessDpiAwareness_type)(int); - SetProcessDpiAwareness_type fl_SetProcessDpiAwareness = - (SetProcessDpiAwareness_type)GetProcAddress(LoadLibrary("Shcore.DLL"), "SetProcessDpiAwareness"); - if (fl_SetProcessDpiAwareness) { - const int fl_PROCESS_PER_MONITOR_DPI_AWARE = 2; - if (fl_SetProcessDpiAwareness(fl_PROCESS_PER_MONITOR_DPI_AWARE) == S_OK) is_dpi_aware = true; - } - } - } - OleInitialize(0L); - get_imm_module(); - Fl::add_check(delayed_create_print_window); -} - - -void Fl_WinAPI_Screen_Driver::update_scaling_capability() { - scaling_capability = SYSTEMWIDE_APP_SCALING; - for (int ns = 1; ns < screen_count(); ns++) { - if (scale(ns) != scale(0)) { - scaling_capability = PER_SCREEN_APP_SCALING; - break; - } - } -} - -void Fl_WinAPI_Screen_Driver::desktop_scale_factor() { - typedef HRESULT(WINAPI * GetDpiForMonitor_type)(HMONITOR, int, UINT *, UINT *); - typedef HMONITOR(WINAPI * MonitorFromRect_type)(LPCRECT, DWORD); - GetDpiForMonitor_type fl_GetDpiForMonitor = NULL; - MonitorFromRect_type fl_MonitorFromRect = NULL; - if (is_dpi_aware) { - fl_GetDpiForMonitor = (GetDpiForMonitor_type)GetProcAddress(LoadLibrary("Shcore.DLL"), "GetDpiForMonitor"); - if (fl_GetDpiForMonitor) - fl_MonitorFromRect = (MonitorFromRect_type)GetProcAddress(LoadLibrary("User32.DLL"), "MonitorFromRect"); - } - for (int ns = 0; ns < screen_count(); ns++) { - UINT dpiX, dpiY; - HRESULT r = E_INVALIDARG; - if (fl_GetDpiForMonitor && fl_MonitorFromRect) { - HMONITOR hm = fl_MonitorFromRect(&screens[ns], MONITOR_DEFAULTTONEAREST); - r = fl_GetDpiForMonitor(hm, 0, &dpiX, &dpiY); - } - if (r != S_OK) { dpiX = dpiY = 96; } - dpi[ns][0] = float(dpiX); - dpi[ns][1] = float(dpiY); - scale(ns, dpiX / 96.f); - // fprintf(LOG, "desktop_scale_factor ns=%d factor=%.2f dpi=%.1f\n", ns, scale(ns), dpi[ns][0]); - } - update_scaling_capability(); -} - - -class Fl_Win32_At_Exit { -public: - Fl_Win32_At_Exit() {} - ~Fl_Win32_At_Exit() { - fl_free_fonts(); // do some Windows cleanup - fl_cleanup_pens(); - OleUninitialize(); - if (fl_graphics_driver) fl_brush_action(1); - fl_cleanup_dc_list(); - // This is actually too late in the cleanup process to remove the - // clipboard notifications, but we have no earlier hook so we try - // to work around it anyway. - if (clipboard_wnd != NULL) - fl_clipboard_notify_untarget(clipboard_wnd); -#if USE_GDIPLUS - Fl_GDIplus_Graphics_Driver::shutdown(); -#endif - } -}; -static Fl_Win32_At_Exit win32_at_exit; - -static char im_enabled = 1; - -void Fl_WinAPI_Screen_Driver::enable_im() { - open_display(); - - Fl_X *i = Fl_X::first; - while (i) { - flImmAssociateContextEx((HWND)i->xid, 0, IACE_DEFAULT); - i = i->next; - } - - im_enabled = 1; -} - -void Fl_WinAPI_Screen_Driver::disable_im() { - open_display(); - - Fl_X *i = Fl_X::first; - while (i) { - flImmAssociateContextEx((HWND)i->xid, 0, 0); - i = i->next; - } - - im_enabled = 0; -} - -void Fl_WinAPI_Screen_Driver::set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) -{ - if (!win) return; - Fl_Window* tw = win->top_window(); - - if (!tw->shown()) - return; - - HIMC himc = flImmGetContext(fl_xid(tw)); - - if (himc) { - COMPOSITIONFORM cfs; - float s = Fl_Graphics_Driver::default_driver().scale(); - cfs.dwStyle = CFS_POINT; - cfs.ptCurrentPos.x = int(X * s); - cfs.ptCurrentPos.y = int(Y * s) - int(tw->labelsize() * s); - // Attempt to have temporary text entered by input method use scaled font. - // Does good, but still not always effective. - Fl_GDI_Font_Descriptor *desc = (Fl_GDI_Font_Descriptor*)Fl_Graphics_Driver::default_driver().font_descriptor(); - if (desc) SelectObject((HDC)Fl_Graphics_Driver::default_driver().gc(), desc->fid); - MapWindowPoints(fl_xid(win), fl_xid(tw), &cfs.ptCurrentPos, 1); - flImmSetCompositionWindow(himc, &cfs); - flImmReleaseContext(fl_xid(tw), himc); - } -} - - -//////////////////////////////////////////////////////////////// - -int Fl_WinAPI_Screen_Driver::get_mouse_unscaled(int &mx, int &my) { - POINT p; - GetCursorPos(&p); - mx = p.x; - my = p.y; - int screen = screen_num_unscaled(mx, my); - return screen >= 0 ? screen : 0; -} - -int Fl_WinAPI_Screen_Driver::get_mouse(int &x, int &y) { - int n = get_mouse_unscaled(x, y); - float s = scale(n); - x = int(x / s); - y = int(y / s); - return n; -} - -//////////////////////////////////////////////////////////////// -// code used for selections: - -char *fl_selection_buffer[2]; -int fl_selection_length[2]; -int fl_selection_buffer_length[2]; -char fl_i_own_selection[2]; - -UINT fl_get_lcid_codepage(LCID id) { - char buf[8]; - buf[GetLocaleInfo(id, LOCALE_IDEFAULTANSICODEPAGE, buf, 8)] = 0; - return atol(buf); -} - -// Convert \n -> \r\n -class Lf2CrlfConvert { - char *out; - int outlen; - -public: - Lf2CrlfConvert(const char *in, int inlen) { - outlen = 0; - const char *i; - char *o; - int lencount; - // Predict size of \r\n conversion buffer - for (i = in, lencount = inlen; lencount > 0; lencount--) { - if (*i == '\r' && *(i + 1) == '\n' && lencount >= 2) { // leave \r\n untranslated - i += 2; - outlen += 2; - lencount--; - } else if (*i == '\n') { // \n by itself? leave room to insert \r - i++; - outlen += 2; - } else { - ++i; - ++outlen; - } - } - // Alloc conversion buffer + NULL - out = new char[outlen + 1]; - // Handle \n -> \r\n conversion - for (i = in, o = out, lencount = inlen; lencount > 0; lencount--) { - if (*i == '\r' && *(i + 1) == '\n' && lencount >= 2) { // leave \r\n untranslated - *o++ = *i++; - *o++ = *i++; - lencount--; - } else if (*i == '\n') { // \n by itself? insert \r - *o++ = '\r'; - *o++ = *i++; - } else { - *o++ = *i++; - } - } - *o++ = 0; - } - ~Lf2CrlfConvert() { - delete[] out; - } - int GetLength() const { return (outlen); } - const char *GetValue() const { return (out); } -}; - -void fl_update_clipboard(void) { - Fl_Window *w1 = Fl::first_window(); - if (!w1) - return; - - HWND hwnd = fl_xid(w1); - - if (!OpenClipboard(hwnd)) - return; - - EmptyClipboard(); - - int utf16_len = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], 0, 0); - - HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc. - LPVOID memLock = GlobalLock(hMem); - - fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], (unsigned short *)memLock, utf16_len + 1); - - GlobalUnlock(hMem); - SetClipboardData(CF_UNICODETEXT, hMem); - - CloseClipboard(); - - // In case Windows managed to lob of a WM_DESTROYCLIPBOARD during - // the above. - fl_i_own_selection[1] = 1; -} - -// call this when you create a selection: -void Fl_WinAPI_Screen_Driver::copy(const char *stuff, int len, int clipboard, const char *type) { - if (!stuff || len < 0) - return; - if (clipboard >= 2) - clipboard = 1; // Only on X11 do multiple clipboards make sense. - - // Convert \n -> \r\n (for old apps like Notepad, DOS) - Lf2CrlfConvert buf(stuff, len); - len = buf.GetLength(); - stuff = buf.GetValue(); - - if (len + 1 > fl_selection_buffer_length[clipboard]) { - delete[] fl_selection_buffer[clipboard]; - fl_selection_buffer[clipboard] = new char[len + 100]; - fl_selection_buffer_length[clipboard] = len + 100; - } - memcpy(fl_selection_buffer[clipboard], stuff, len); - fl_selection_buffer[clipboard][len] = 0; // needed for direct paste - fl_selection_length[clipboard] = len; - fl_i_own_selection[clipboard] = 1; - if (clipboard) - fl_update_clipboard(); -} - -// Call this when a "paste" operation happens: -void Fl_WinAPI_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) { - if (!clipboard || (fl_i_own_selection[clipboard] && strcmp(type, Fl::clipboard_plain_text) == 0)) { - // We already have it, do it quickly without window server. - // Notice that the text is clobbered if set_selection is - // called in response to FL_PASTE! - char *i = fl_selection_buffer[clipboard]; - if (i == 0L) { - Fl::e_text = 0; - return; - } - char *clip_text = new char[fl_selection_length[clipboard] + 1]; - char *o = clip_text; - while (*i) { // Convert \r\n -> \n - if (*i == '\r' && *(i + 1) == '\n') - i++; - else - *o++ = *i++; - } - *o = 0; - Fl::e_text = clip_text; - Fl::e_length = (int)(o - Fl::e_text); - Fl::e_clipboard_type = Fl::clipboard_plain_text; - receiver.handle(FL_PASTE); // this may change Fl::e_text - delete[] clip_text; - Fl::e_text = 0; - } else if (clipboard) { - HANDLE h; - if (!OpenClipboard(NULL)) - return; - if (strcmp(type, Fl::clipboard_plain_text) == 0) { // we want plain text from clipboard - if ((h = GetClipboardData(CF_UNICODETEXT))) { // there's text in the clipboard - wchar_t *memLock = (wchar_t *)GlobalLock(h); - size_t utf16_len = wcslen(memLock); - char *clip_text = new char[utf16_len * 4 + 1]; - unsigned utf8_len = fl_utf8fromwc(clip_text, (unsigned)(utf16_len * 4), memLock, (unsigned)utf16_len); - *(clip_text + utf8_len) = 0; - GlobalUnlock(h); - LPSTR a, b; - a = b = clip_text; - while (*a) { // strip the CRLF pairs ($%$#@^) - if (*a == '\r' && a[1] == '\n') - a++; - else - *b++ = *a++; - } - *b = 0; - Fl::e_text = clip_text; - Fl::e_length = (int)(b - Fl::e_text); - Fl::e_clipboard_type = Fl::clipboard_plain_text; // indicates that the paste event is for plain UTF8 text - receiver.handle(FL_PASTE); // send the FL_PASTE event to the widget. May change Fl::e_text - delete[] clip_text; - Fl::e_text = 0; - } - } else if (strcmp(type, Fl::clipboard_image) == 0) { // we want an image from clipboard - uchar *rgb = NULL; - Fl_RGB_Image *image = NULL; - int width = 0, height = 0, depth = 0; - if ((h = GetClipboardData(CF_DIB))) { // if there's a DIB in clipboard - LPBITMAPINFO lpBI = (LPBITMAPINFO)GlobalLock(h); - width = lpBI->bmiHeader.biWidth; // bitmap width & height - height = lpBI->bmiHeader.biHeight; // is < 0 for top-down DIB - if ((lpBI->bmiHeader.biBitCount == 24 || lpBI->bmiHeader.biBitCount == 32) && - lpBI->bmiHeader.biCompression == BI_RGB && - lpBI->bmiHeader.biClrUsed == 0) { // direct use of the DIB data if it's RGB or RGBA - int linewidth; // row length - depth = lpBI->bmiHeader.biBitCount / 8; // 3 or 4 - if (depth == 3) - linewidth = 4 * ((3 * width + 3) / 4); // row length: series of groups of 3 bytes, rounded to multiple of 4 bytes - else - linewidth = 4 * width; - rgb = new uchar[width * abs(height) * depth]; // will hold the image data - uchar *p = rgb, *r, rr, gg, bb; - int step = (height > 0 ? -1 : +1); - int from = (height > 0 ? height-1 : 0); - int to = (height > 0 ? 0 : -height-1); - for (int i = from; (height > 0 ? i>=to : i <=to); i += step) {// for each row, from last to first - r = (uchar *)(lpBI->bmiColors) + i * linewidth; // beginning of pixel data for the ith row - for (int j = 0; j < width; j++) { // for each pixel in a row - bb = *r++; // BGR is in DIB - gg = *r++; - rr = *r++; - *p++ = rr; // we want RGB - *p++ = gg; - *p++ = bb; - if (depth == 4) - *p++ = *r++; // copy alpha if present - } - } - } else { // the system will decode a complex DIB - void *pDIBBits = (void *)(lpBI->bmiColors + 256); - if (lpBI->bmiHeader.biCompression == BI_BITFIELDS) - pDIBBits = (void *)(lpBI->bmiColors + 3); - else if (lpBI->bmiHeader.biClrUsed > 0) - pDIBBits = (void *)(lpBI->bmiColors + lpBI->bmiHeader.biClrUsed); - Fl_Image_Surface *surf = new Fl_Image_Surface(width, abs(height)); - Fl_Surface_Device::push_current(surf); - SetDIBitsToDevice((HDC)fl_graphics_driver->gc(), 0, 0, width, abs(height), 0, 0, 0, abs(height), pDIBBits, lpBI, DIB_RGB_COLORS); - rgb = fl_read_image(NULL, 0, 0, width, abs(height)); - depth = 3; - Fl_Surface_Device::pop_current(); - delete surf; - } - GlobalUnlock(h); - } else if ((h = GetClipboardData(CF_ENHMETAFILE))) { // if there's an enhanced metafile in clipboard - ENHMETAHEADER header; - GetEnhMetaFileHeader((HENHMETAFILE)h, sizeof(header), &header); // get structure containing metafile dimensions - width = (header.rclFrame.right - header.rclFrame.left + 1); // in .01 mm units - height = (header.rclFrame.bottom - header.rclFrame.top + 1); - HDC hdc = GetDC(NULL); // get unit correspondance between .01 mm and screen pixels - int hmm = GetDeviceCaps(hdc, HORZSIZE); - int hdots = GetDeviceCaps(hdc, HORZRES); - ReleaseDC(NULL, hdc); - float factor = (100.f * hmm) / hdots; - float scaling = Fl::screen_driver()->scale(Fl_Window_Driver::driver(receiver.top_window())->screen_num()); - if (!Fl_Window::current()) { - Fl_GDI_Graphics_Driver *d = (Fl_GDI_Graphics_Driver*)&Fl_Graphics_Driver::default_driver(); - d->scale(scaling);// may run early at app startup before Fl_Window::make_current() scales d - } - width = int(width / (scaling * factor)); // convert to screen pixel unit - height = int(height / (scaling * factor)); - RECT rect = {0, 0, width, height}; - Fl_Image_Surface *surf = new Fl_Image_Surface(width, height, 1); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); // draw white background - fl_rectf(0, 0, width, height); - rect.right = LONG(rect.right * scaling); // apply scaling to the metafile draw operation - rect.bottom = LONG(rect.bottom * scaling); - PlayEnhMetaFile((HDC)fl_graphics_driver->gc(), (HENHMETAFILE)h, &rect); // draw metafile to offscreen buffer - image = surf->image(); - Fl_Surface_Device::pop_current(); - delete surf; - } - if (rgb || image) { - if (!image) { - image = new Fl_RGB_Image(rgb, width, abs(height), depth); // create new image from pixel data - image->alloc_array = 1; - } - Fl::e_clipboard_data = image; - Fl::e_clipboard_type = Fl::clipboard_image; // indicates that the paste event is for image data - int done = receiver.handle(FL_PASTE); // send FL_PASTE event to widget - Fl::e_clipboard_type = ""; - if (done == 0) { // if widget did not handle the event, delete the image - Fl::e_clipboard_data = NULL; - delete image; - } - } - } - CloseClipboard(); - } -} - -int Fl_WinAPI_Screen_Driver::clipboard_contains(const char *type) { - int retval = 0; - if (!OpenClipboard(NULL)) - return 0; - if (strcmp(type, Fl::clipboard_plain_text) == 0 || type[0] == 0) { - retval = IsClipboardFormatAvailable(CF_UNICODETEXT); - } else if (strcmp(type, Fl::clipboard_image) == 0) { - retval = IsClipboardFormatAvailable(CF_DIB) || IsClipboardFormatAvailable(CF_ENHMETAFILE); - } - CloseClipboard(); - return retval; -} - -static void fl_clipboard_notify_target(HWND wnd) { - if (clipboard_wnd) - return; - - // We get one fake WM_DRAWCLIPBOARD immediately, which we therefore - // need to ignore. - initial_clipboard = true; - - clipboard_wnd = wnd; - next_clipboard_wnd = SetClipboardViewer(wnd); -} - -static void fl_clipboard_notify_untarget(HWND wnd) { - if (wnd != clipboard_wnd) - return; - - // We might be called late in the cleanup where Windows has already - // implicitly destroyed our clipboard window. At that point we need - // to do some extra work to manually repair the clipboard chain. - if (IsWindow(wnd)) - ChangeClipboardChain(wnd, next_clipboard_wnd); - else { - HWND tmp, head; - - tmp = CreateWindow("STATIC", "Temporary FLTK Clipboard Window", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); - if (tmp == NULL) - return; - - head = SetClipboardViewer(tmp); - if (head == NULL) - ChangeClipboardChain(tmp, next_clipboard_wnd); - else { - SendMessage(head, WM_CHANGECBCHAIN, (WPARAM)wnd, (LPARAM)next_clipboard_wnd); - ChangeClipboardChain(tmp, head); - } - - DestroyWindow(tmp); - } - - clipboard_wnd = next_clipboard_wnd = 0; -} - -void fl_clipboard_notify_retarget(HWND wnd) { - // The given window is getting destroyed. If it's part of the - // clipboard chain then we need to unregister it and find a - // replacement window. - if (wnd != clipboard_wnd) - return; - - fl_clipboard_notify_untarget(wnd); - - if (Fl::first_window()) - fl_clipboard_notify_target(fl_xid(Fl::first_window())); -} - -void Fl_WinAPI_Screen_Driver::clipboard_notify_change() { - // untarget clipboard monitor if no handlers are registered - if (clipboard_wnd != NULL && fl_clipboard_notify_empty()) { - fl_clipboard_notify_untarget(clipboard_wnd); - return; - } - - // if there are clipboard notify handlers but no window targeted - // target first window if available - if (clipboard_wnd == NULL && Fl::first_window()) - fl_clipboard_notify_target(fl_xid(Fl::first_window())); -} - -//////////////////////////////////////////////////////////////// -void fl_get_codepage() { - HKL hkl = GetKeyboardLayout(0); - TCHAR ld[8]; - - GetLocaleInfo(LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6); - DWORD ccp = atol(ld); - fl_codepage = ccp; -} - -HWND fl_capture; - -// \param[in] window The FLTK window that generated the event -// \param[in] what 0 = down, 1 = double down, 2 = up, 3 = move -// \param[in] button 1 = left, 2 = middle, 3 = right, 4 = XBUTTON1, 5 = any other XBUTTON -// \param[in] wParam depends on event, for example MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_XBUTTON1, MK_XBUTTON2 -// \param[in] lParam 32 bit value, top 16 bit are the signed y coordinate, bottom 16 bits is x in window space -// WM_KILLFOCUS calls this with (Fl::grab(), 0, 1, MK_LBUTTON, MAKELPARAM(32767, 0)) -static int mouse_event(Fl_Window *window, int what, int button, - WPARAM wParam, LPARAM lParam) { - static int px, py, pmx, pmy; - POINT pt; - float scale = Fl::screen_driver()->scale(window->screen_num()); - Fl::e_x = pt.x = (signed short)LOWORD(lParam); - Fl::e_y = pt.y = (signed short)HIWORD(lParam); - Fl::e_x = int(Fl::e_x / scale); - Fl::e_y = int(Fl::e_y / scale); - ClientToScreen(fl_xid(window), &pt); - Fl::e_x_root = int(pt.x / scale); - Fl::e_y_root = int(pt.y / scale); -#ifdef USE_CAPTURE_MOUSE_WIN - Fl_Window *mouse_window = window; // save "mouse window" -#endif - while (window->parent()) { - Fl::e_x += window->x(); - Fl::e_y += window->y(); - window = window->window(); - } - - ulong state = Fl::e_state & 0xff0000; // keep shift key states -#if 0 - // mouse event reports some shift flags, perhaps save them? - if (wParam & MK_SHIFT) state |= FL_SHIFT; - if (wParam & MK_CONTROL) state |= FL_CTRL; -#endif - if (wParam & MK_LBUTTON) state |= FL_BUTTON1; // left - if (wParam & MK_MBUTTON) state |= FL_BUTTON2; // right - if (wParam & MK_RBUTTON) state |= FL_BUTTON3; // middle - if (wParam & MK_XBUTTON1) state |= FL_BUTTON4; // side button 1 (back) - if (wParam & MK_XBUTTON2) state |= FL_BUTTON5; // side button 2 (forward) - - Fl::e_state = state; - - switch (what) { - case 1: // double-click - if (Fl::e_is_click) { - Fl::e_clicks++; - goto J1; - } - case 0: // single-click - Fl::e_clicks = 0; - J1: -#ifdef USE_CAPTURE_MOUSE_WIN - if (!fl_capture) - SetCapture(fl_xid(mouse_window)); // use mouse window -#else - if (!fl_capture) - SetCapture(fl_xid(window)); // use main window -#endif - Fl::e_keysym = FL_Button + button; - Fl::e_is_click = 1; - px = pmx = Fl::e_x_root; - py = pmy = Fl::e_y_root; - return Fl::handle(FL_PUSH, window); - - case 2: // release: - if (!fl_capture) - ReleaseCapture(); - Fl::e_keysym = FL_Button + button; - return Fl::handle(FL_RELEASE, window); - - case 3: // move: - default: // avoid compiler warning - // Windows produces extra events even if the mouse does not move, ignore em: - if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) - return 1; - pmx = Fl::e_x_root; - pmy = Fl::e_y_root; - if (abs(Fl::e_x_root - px) > 5 || abs(Fl::e_y_root - py) > 5) - Fl::e_is_click = 0; - return Fl::handle(FL_MOVE, window); - } -} - -// Convert a Windows VK_x to an FLTK (X) Keysym: -// See also the inverse converter in Fl_get_key_win32.cxx -// This table is in numeric order by VK: -static const struct { - unsigned short vk, fltk, extended; -} vktab[] = { - {VK_BACK, FL_BackSpace}, - {VK_TAB, FL_Tab}, - {VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/}, - {VK_RETURN, FL_Enter, FL_KP_Enter}, - {VK_SHIFT, FL_Shift_L, FL_Shift_R}, - {VK_CONTROL, FL_Control_L, FL_Control_R}, - {VK_MENU, FL_Alt_L, FL_Alt_R}, - {VK_PAUSE, FL_Pause}, - {VK_CAPITAL, FL_Caps_Lock}, - {VK_ESCAPE, FL_Escape}, - {VK_SPACE, ' '}, - {VK_PRIOR, FL_KP+'9', FL_Page_Up}, - {VK_NEXT, FL_KP+'3', FL_Page_Down}, - {VK_END, FL_KP+'1', FL_End}, - {VK_HOME, FL_KP+'7', FL_Home}, - {VK_LEFT, FL_KP+'4', FL_Left}, - {VK_UP, FL_KP+'8', FL_Up}, - {VK_RIGHT, FL_KP+'6', FL_Right}, - {VK_DOWN, FL_KP+'2', FL_Down}, - {VK_SNAPSHOT, FL_Print}, // does not work on NT - {VK_INSERT, FL_KP+'0', FL_Insert}, - {VK_DELETE, FL_KP+'.', FL_Delete}, - {VK_LWIN, FL_Meta_L}, - {VK_RWIN, FL_Meta_R}, - {VK_APPS, FL_Menu}, - {VK_SLEEP, FL_Sleep}, - {VK_MULTIPLY, FL_KP+'*'}, - {VK_ADD, FL_KP+'+'}, - {VK_SUBTRACT, FL_KP+'-'}, - {VK_DECIMAL, FL_KP+'.'}, - {VK_DIVIDE, FL_KP+'/'}, - {VK_NUMLOCK, FL_Num_Lock}, - {VK_SCROLL, FL_Scroll_Lock}, -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) - {VK_BROWSER_BACK, FL_Back}, - {VK_BROWSER_FORWARD, FL_Forward}, - {VK_BROWSER_REFRESH, FL_Refresh}, - {VK_BROWSER_STOP, FL_Stop}, - {VK_BROWSER_SEARCH, FL_Search}, - {VK_BROWSER_FAVORITES, FL_Favorites}, - {VK_BROWSER_HOME, FL_Home_Page}, - {VK_VOLUME_MUTE, FL_Volume_Mute}, - {VK_VOLUME_DOWN, FL_Volume_Down}, - {VK_VOLUME_UP, FL_Volume_Up}, - {VK_MEDIA_NEXT_TRACK, FL_Media_Next}, - {VK_MEDIA_PREV_TRACK, FL_Media_Prev}, - {VK_MEDIA_STOP, FL_Media_Stop}, - {VK_MEDIA_PLAY_PAUSE, FL_Media_Play}, - {VK_LAUNCH_MAIL, FL_Mail}, -#endif - {0xba, ';'}, - {0xbb, '='}, // 0xbb == VK_OEM_PLUS (see #1086) - {0xbc, ','}, - {0xbd, '-'}, - {0xbe, '.'}, - {0xbf, '/'}, - {0xc0, '`'}, - {0xdb, '['}, - {0xdc, '\\'}, - {0xdd, ']'}, - {0xde, '\''}, - {VK_OEM_102, FL_Iso_Key} -}; -static int ms2fltk(WPARAM vk, int extended) { - static unsigned short vklut[256]; - static unsigned short extendedlut[256]; - if (!vklut[1]) { // init the table - unsigned int i; - for (i = 0; i < 256; i++) - vklut[i] = tolower(i); - for (i = VK_F1; i <= VK_F16; i++) - vklut[i] = i + (FL_F - (VK_F1 - 1)); - for (i = VK_NUMPAD0; i <= VK_NUMPAD9; i++) - vklut[i] = i + (FL_KP + '0' - VK_NUMPAD0); - for (i = 0; i < sizeof(vktab) / sizeof(*vktab); i++) { - vklut[vktab[i].vk] = vktab[i].fltk; - extendedlut[vktab[i].vk] = vktab[i].extended; - } - for (i = 0; i < 256; i++) - if (!extendedlut[i]) - extendedlut[i] = vklut[i]; - } - return extended ? extendedlut[vk] : vklut[vk]; -} - -#if USE_COLORMAP -extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx -#endif - - -static Fl_Window *resize_bug_fix; -static bool moving_window = false; // true when dragging a window with the mouse on the titlebar - -extern void fl_save_pen(void); -extern void fl_restore_pen(void); -extern LRESULT fl_win32_tablet_handler(MSG& msg); - - -static void invalidate_gl_win(Fl_Window *glwin) { - static Fl_WinAPI_Plugin *plugin = NULL; - if (!plugin) { - Fl_Plugin_Manager pm("winapi.fltk.org"); - plugin = (Fl_WinAPI_Plugin*)pm.plugin("gl.winapi.fltk.org"); - } - plugin->invalidate(glwin); -} - - -static BOOL CALLBACK child_window_cb(HWND child_xid, LPARAM data) { - Fl_Window *child = fl_find(child_xid); - if (data) { - float s = *(float*)data; - SetWindowPos(child_xid, 0, int(round(child->x() * s)), int(round(child->y() * s)), - int(round(child->w() * s)), int(round(child->h() * s)), 0); - } - if (child->as_gl_window()) invalidate_gl_win(child); - return TRUE; -} - - -static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - // Copy the message to fl_msg so add_handler code can see it. - // It is already there if this is called by DispatchMessage, - // but not if Windows calls this directly. - - fl_msg.hwnd = hWnd; - fl_msg.message = uMsg; - fl_msg.wParam = wParam; - fl_msg.lParam = lParam; - // fl_msg.time = ??? - // fl_msg.pt = ??? - // fl_msg.lPrivate = ??? - - Fl_Window *window = fl_find(hWnd); - float scale = (window ? Fl::screen_driver()->scale(Fl_Window_Driver::driver(window)->screen_num()) : 1); - - if (window) { - switch (uMsg) { - - case WM_DPICHANGED: { // 0x02E0, after display re-scaling and followed by WM_DISPLAYCHANGE - if (is_dpi_aware) { - RECT r, *lParam_rect = (RECT*)lParam; - Fl_WinAPI_Screen_Driver *sd = (Fl_WinAPI_Screen_Driver*)Fl::screen_driver(); - int centerX = (lParam_rect->left + lParam_rect->right)/2; - int centerY = (lParam_rect->top + lParam_rect->bottom)/2; - int ns = sd->screen_num_unscaled(centerX, centerY); - int old_ns = Fl_Window_Driver::driver(window)->screen_num(); - if (sd->dpi[ns][0] != HIWORD(wParam) && ns == old_ns) { // change DPI of a screen - sd->dpi[ns][0] = sd->dpi[ns][1] = HIWORD(wParam); - float f = HIWORD(wParam) / 96.f; - GetClientRect(hWnd, &r); - float old_f = float(r.right) / window->w(); - Fl::screen_driver()->scale(ns, f); - Fl_Window_Driver::driver(window)->resize_after_scale_change(ns, old_f, f); - sd->update_scaling_capability(); - } else if (ns != old_ns) { - // jump window with Windows+Shift+L|R-arrow to other screen with other DPI - if (ns >= 0) Fl_Window_Driver::driver(window)->screen_num(ns); - UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOCOPYBITS; - SetWindowPos(hWnd, NULL, lParam_rect->left, lParam_rect->top, - lParam_rect->right - lParam_rect->left, - lParam_rect->bottom - lParam_rect->top, flags); - if (ns >= 0) { - scale = Fl::screen_driver()->scale(ns); - EnumChildWindows(hWnd, child_window_cb, (LPARAM)&scale); - } - } - } - return 0; - } - - case WM_QUIT: // this should not happen? - Fl::fatal("WM_QUIT message"); - - case WM_CLOSE: // user clicked close box - Fl::handle(FL_CLOSE, window); - return 0; - - case WM_SYNCPAINT: - case WM_NCPAINT: - case WM_ERASEBKGND: - // Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc - // so that Windows can generate the proper paint messages... - // Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too... - break; - - case WM_PAINT: { - HRGN R, R2; - Fl_X *i = Fl_X::flx(window); - Fl_Window_Driver::driver(window)->wait_for_expose_value = 0; - char redraw_whole_window = false; - if (!i->region && window->damage()) { - // Redraw the whole window... - i->region = CreateRectRgn(0, 0, window->w(), window->h()); - redraw_whole_window = true; - } - - // We need to merge Windows' damage into FLTK's damage. - R = CreateRectRgn(0, 0, 0, 0); - int r = GetUpdateRgn(hWnd, R, 0); - if (r == NULLREGION && !redraw_whole_window) { - DeleteObject(R); - break; - } - - // convert i->region in FLTK units to R2 in drawing units - R2 = Fl_GDI_Graphics_Driver::scale_region((HRGN)i->region, scale, NULL); - - RECT r_box; - if (scale != 1 && GetRgnBox(R, &r_box) != NULLREGION) { - // add de-scaled update region to i->region in FLTK units - r_box.left = LONG(r_box.left / scale); - r_box.right = LONG(r_box.right / scale); - r_box.top = LONG(r_box.top / scale); - r_box.bottom = LONG(r_box.bottom / scale); - HRGN R3 = CreateRectRgn(r_box.left, r_box.top, r_box.right + 1, r_box.bottom + 1); - if (!i->region) i->region = R3; - else { - CombineRgn((HRGN)i->region, (HRGN)i->region, R3, RGN_OR); - DeleteObject(R3); - } - } - if (R2) { - // Also tell Windows that we are drawing someplace else as well... - CombineRgn(R2, R2, R, RGN_OR); - DeleteObject(R); - } else { - R2 = R; - } - if (window->type() == FL_DOUBLE_WINDOW) - ValidateRgn(hWnd, 0); - else { - ValidateRgn(hWnd, R2); - } - - if (scale != 1) DeleteObject(R2); - - window->clear_damage((uchar)(window->damage() | FL_DAMAGE_EXPOSE)); - // These next two statements should not be here, so that all update - // is deferred until Fl::flush() is called during idle. However Windows - // apparently is very unhappy if we don't obey it and draw right now. - // Very annoying! - fl_GetDC(hWnd); // Make sure we have a DC for this window... - fl_save_pen(); - Fl_Window_Driver::driver(window)->flush(); - fl_restore_pen(); - window->clear_damage(); - return 0; - } // case WM_PAINT - - case WM_LBUTTONDOWN: - mouse_event(window, 0, 1, wParam, lParam); - return 0; - case WM_LBUTTONDBLCLK: - mouse_event(window, 1, 1, wParam, lParam); - return 0; - case WM_LBUTTONUP: - mouse_event(window, 2, 1, wParam, lParam); - return 0; - case WM_MBUTTONDOWN: - mouse_event(window, 0, 2, wParam, lParam); - return 0; - case WM_MBUTTONDBLCLK: - mouse_event(window, 1, 2, wParam, lParam); - return 0; - case WM_MBUTTONUP: - mouse_event(window, 2, 2, wParam, lParam); - return 0; - case WM_RBUTTONDOWN: - mouse_event(window, 0, 3, wParam, lParam); - return 0; - case WM_RBUTTONDBLCLK: - mouse_event(window, 1, 3, wParam, lParam); - return 0; - case WM_RBUTTONUP: - mouse_event(window, 2, 3, wParam, lParam); - return 0; - case WM_XBUTTONDOWN: { - int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; - mouse_event(window, 0, xbutton, wParam, lParam); - return 0; - } - case WM_XBUTTONDBLCLK: { - int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; - mouse_event(window, 1, xbutton, wParam, lParam); - return 0; - } - case WM_XBUTTONUP: { - int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; - mouse_event(window, 2, xbutton, wParam, lParam); - return 0; - } - - case WM_MOUSEMOVE: -#ifdef USE_TRACK_MOUSE - if (track_mouse_win != window) { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hWnd; - _TrackMouseEvent(&tme); - track_mouse_win = window; - } -#endif // USE_TRACK_MOUSE - mouse_event(window, 3, 0, wParam, lParam); - return 0; - - case WM_MOUSELEAVE: - if (track_mouse_win == window) { // we left the top level window ! - Fl_Window *tw = window; - while (tw->parent()) // find top level window - tw = tw->window(); - // Get a better mouse position for FL_LEAVE event (#87) - POINT pt; - if (GetCursorPos(&pt)) { - float scale = Fl::screen_driver()->scale(tw->screen_num()); - Fl::e_x_root = int(pt.x / scale); - Fl::e_y_root = int(pt.y / scale); - ScreenToClient(fl_xid(tw), &pt); - Fl::e_x = clamp(int(pt.x / scale), 0, window->w() - 1); - Fl::e_y = clamp(int(pt.y / scale), 0, window->h() - 1); - } - Fl::belowmouse(0); - Fl::handle(FL_LEAVE, tw); - } - track_mouse_win = 0; // force TrackMouseEvent() restart - break; - - case WM_SETFOCUS: - if ((Fl::modal_) && (Fl::modal_ != window)) { - SetFocus(fl_xid(Fl::modal_)); - return 0; - } - Fl::handle(FL_FOCUS, window); - break; - - case WM_KILLFOCUS: - if (Fl::grab() && (Fl::grab() != window) && Fl::grab()->menu_window()) { - // simulate click at remote location (see issue #1166), coordinates are signed 16 bit values - mouse_event(Fl::grab(), 0, 1, MK_LBUTTON, MAKELPARAM(32767, 0)); - } - Fl::handle(FL_UNFOCUS, window); - Fl::flush(); // it never returns to main loop when deactivated... - break; - - case WM_SHOWWINDOW: - if (!window->parent()) { - Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); - } - break; - - case WM_ACTIVATEAPP: - // From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP - // messages to restore the correct state of the shift/ctrl/alt/lock - // keys... Added control, shift, alt, and meta keys, and changed - // to use GetAsyncKeyState and do it when wParam is 1 - // (that means we have focus...) - if (wParam) { - ulong state = 0; - if (GetAsyncKeyState(VK_CAPITAL)) - state |= FL_CAPS_LOCK; - if (GetAsyncKeyState(VK_NUMLOCK)) - state |= FL_NUM_LOCK; - if (GetAsyncKeyState(VK_SCROLL)) - state |= FL_SCROLL_LOCK; - if (GetAsyncKeyState(VK_CONTROL) & ~1) - state |= FL_CTRL; - if (GetAsyncKeyState(VK_SHIFT) & ~1) - state |= FL_SHIFT; - if (GetAsyncKeyState(VK_MENU)) - state |= FL_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & ~1) - state |= FL_META; - Fl::e_state = state; - Fl::handle(FL_APP_ACTIVATE, nullptr); - } else { - Fl::handle(FL_APP_DEACTIVATE, nullptr); - } - break; - - case WM_INPUTLANGCHANGE: - fl_get_codepage(); - break; - case WM_IME_COMPOSITION: - // if (!fl_is_nt4() && lParam & GCS_RESULTCLAUSE) { - // HIMC himc = ImmGetContext(hWnd); - // wlen = ImmGetCompositionStringW(himc, GCS_RESULTSTR, - // wbuf, sizeof(wbuf)) / sizeof(short); - // if (wlen < 0) wlen = 0; - // wbuf[wlen] = 0; - // ImmReleaseContext(hWnd, himc); - // } - break; - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_SYSKEYUP: - // save the keysym until we figure out the characters: - Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam, lParam & (1 << 24)); - // Kludge to allow recognizing ctrl+'-' on keyboards with digits in uppercase positions (e.g. French) - if (Fl::e_keysym == '6' && (VkKeyScanA('-') & 0xff) == '6') { - Fl::e_keysym = '-'; - } - // See if TranslateMessage turned it into a WM_*CHAR message: - if (PeekMessageW(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { - uMsg = fl_msg.message; - wParam = fl_msg.wParam; - lParam = fl_msg.lParam; - } - // FALLTHROUGH ... - - case WM_DEADCHAR: - case WM_SYSDEADCHAR: - case WM_CHAR: - case WM_SYSCHAR: { - ulong state = Fl::e_state & 0xff000000; // keep the mouse button state - // if GetKeyState is expensive we might want to comment some of these out: - if (GetKeyState(VK_SHIFT) & ~1) - state |= FL_SHIFT; - if (GetKeyState(VK_CAPITAL)) - state |= FL_CAPS_LOCK; - if (GetKeyState(VK_CONTROL) & ~1) - state |= FL_CTRL; - // Alt gets reported for the Alt-GR switch on non-English keyboards. - // so we need to check the event as well to get it right: - if ((lParam & (1 << 29)) // same as GetKeyState(VK_MENU) - && uMsg != WM_CHAR) - state |= FL_ALT; - if (GetKeyState(VK_NUMLOCK)) - state |= FL_NUM_LOCK; - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & ~1) { - // Windows bug? GetKeyState returns garbage if the user hit the - // meta key to pop up start menu. Sigh. - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & ~1) - state |= FL_META; - } - if (GetKeyState(VK_SCROLL)) - state |= FL_SCROLL_LOCK; - Fl::e_state = state; - static char buffer[1024]; - if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - wchar_t u = (wchar_t)wParam; - // Windows emoji palette triggered with Windows + dot sends 2 or more WM_CHAR messages: - // the 2 components of a surrogate pair, or variation selectors, or zero-width joiner, - // or emoji modifiers FITZPATRICK or extra Unicode points. - if (u >= 0xD800 && u <= 0xDFFF) { // handle the 2 components of a surrogate pair - static wchar_t surrogate_pair[2]; - if (IS_HIGH_SURROGATE(u)) { - surrogate_pair[0] = u; // memorize the 1st member of the pair - Fl::e_length = 0; - return 0; // and wait for next WM_CHAR message that will give the 2nd member - } else { - surrogate_pair[1] = u; // memorize the 2nd member of the pair - Fl::e_length = fl_utf8fromwc(buffer, 1024, surrogate_pair, 2); // transform to UTF-8 - } - } else { - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); // process regular Unicode point - } - buffer[Fl::e_length] = 0; - } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { - if (state & FL_NUM_LOCK) { - // Convert to regular keypress... - buffer[0] = Fl::e_keysym - FL_KP; - Fl::e_length = 1; - } else { - // Convert to special keypress... - buffer[0] = 0; - Fl::e_length = 0; - switch (Fl::e_keysym) { - case FL_KP + '0': - Fl::e_keysym = FL_Insert; - break; - case FL_KP + '1': - Fl::e_keysym = FL_End; - break; - case FL_KP + '2': - Fl::e_keysym = FL_Down; - break; - case FL_KP + '3': - Fl::e_keysym = FL_Page_Down; - break; - case FL_KP + '4': - Fl::e_keysym = FL_Left; - break; - case FL_KP + '6': - Fl::e_keysym = FL_Right; - break; - case FL_KP + '7': - Fl::e_keysym = FL_Home; - break; - case FL_KP + '8': - Fl::e_keysym = FL_Up; - break; - case FL_KP + '9': - Fl::e_keysym = FL_Page_Up; - break; - case FL_KP + '.': - Fl::e_keysym = FL_Delete; - break; - case FL_KP + '/': - case FL_KP + '*': - case FL_KP + '-': - case FL_KP + '+': - buffer[0] = Fl::e_keysym - FL_KP; - Fl::e_length = 1; - break; - } - } - } else if ((lParam & (1 << 31)) == 0) { -#ifdef FLTK_PREVIEW_DEAD_KEYS - if ((lParam & (1 << 24)) == 0) { // clear if dead key (always?) - wchar_t u = (wchar_t)wParam; - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); - buffer[Fl::e_length] = 0; - } else { // set if "extended key" (never printable?) - buffer[0] = 0; - Fl::e_length = 0; - } -#else - buffer[0] = 0; - Fl::e_length = 0; -#endif - } - Fl::e_text = buffer; - - // Kludge to process the +-containing key in cross-platform way when used with Ctrl -/* Table of how Windows processes the '+'-containing key by keyboard layout - key virtual -content key keyboard layout - =|+ 0xbb US/UK/Fr/Arabic/Chinese/Hebrew/Brazil/Russian/Vietnam/Japan/Korean/Persian - +|* 0xbb German/Spanish/Italy/Greek/Portugal - +|? 0xbb Swedish/Finish/Norway - +|± 0xbb Dutch - 1|+ '1' Swiss/Luxemburg - 3|+ '3' Hungarian - 4|+ '4' Turkish -*/ - if ((Fl::e_state & FL_CTRL) && !(GetAsyncKeyState(VK_MENU) >> 15)) { - // extra processing necessary only when Ctrl is down and Alt is up - int vk_plus_key = (VkKeyScanA('+') & 0xff); // virtual key of '+'-containing key - bool plus_shift_pos = ((VkKeyScanA('+') & 0x100) != 0); // true means '+' in shifted position - int plus_other_char; // the other char on same key as '+' - if (plus_shift_pos) plus_other_char = ms2fltk(vk_plus_key, 0); - else if ((VkKeyScanA('*') & 0xff) == vk_plus_key) plus_other_char = '*'; // German - else if ((VkKeyScanA('?') & 0xff) == vk_plus_key) plus_other_char = '?'; // Swedish - else if ((VkKeyScanW(L'±') & 0xff) == vk_plus_key) plus_other_char = L'±'; // Dutch - else plus_other_char = '='; // fallback -//fprintf(stderr, "plus_shift_pos=%d plus_other_char='%c' vk+=0x%x\n", plus_shift_pos, -// plus_other_char, vk_plus_key); - if ( (vk_plus_key == 0xbb && Fl::e_keysym == '=') || // the '+'-containing key is down - (plus_shift_pos && Fl::e_keysym == plus_other_char) ) { - Fl::e_keysym = (plus_shift_pos ? plus_other_char : '+'); - static char plus_other_char_utf8[4]; - int lutf8 = fl_utf8encode(plus_other_char, plus_other_char_utf8); - plus_other_char_utf8[lutf8] = 0; - if (plus_shift_pos) { - Fl::e_text = ( (Fl::e_state & FL_SHIFT) ? (char*)"+" : plus_other_char_utf8 ); - } else { - Fl::e_text = ( (Fl::e_state & FL_SHIFT) ? plus_other_char_utf8 : (char*)"+" ); - } - Fl::e_length = (int)strlen(Fl::e_text); - } - } - // end of processing of the +-containing key - - if (lParam & (1 << 31)) { // key up events. - if (Fl::handle(FL_KEYUP, window)) - return 0; - break; - } - while (window->parent()) - window = window->window(); - if (Fl::handle(FL_KEYBOARD, window)) { - if (uMsg == WM_DEADCHAR || uMsg == WM_SYSDEADCHAR) - Fl::compose_state = 1; - return 0; - } - break; // WM_KEYDOWN ... WM_SYSKEYUP, WM_DEADCHAR ... WM_SYSCHAR - } // case WM_DEADCHAR ... WM_SYSCHAR - - case WM_MOUSEWHEEL: { - static int delta = 0; // running total of all vertical mousewheel motion - delta += (SHORT)(HIWORD(wParam)); - int dy = -delta / WHEEL_DELTA; - delta += dy * WHEEL_DELTA; - if (dy == 0) // nothing to do - return 0; - if (Fl::event_shift()) { // shift key pressed: send horizontal mousewheel event - Fl::e_dx = dy; - Fl::e_dy = 0; - } else { // shift key not pressed (normal behavior): send vertical mousewheel event - Fl::e_dx = 0; - Fl::e_dy = dy; - } - Fl::handle(FL_MOUSEWHEEL, window); - return 0; - } - - case WM_MOUSEHWHEEL: { - static int delta = 0; // running total of all horizontal mousewheel motion - delta += (SHORT)(HIWORD(wParam)); - int dx = delta / WHEEL_DELTA; - delta -= dx * WHEEL_DELTA; - if (dx == 0) // nothing to do - return 0; - if (Fl::event_shift()) { // shift key pressed: send *vertical* mousewheel event - Fl::e_dx = 0; - Fl::e_dy = dx; - } else { // shift key not pressed (normal behavior): send horizontal mousewheel event - Fl::e_dx = dx; - Fl::e_dy = 0; - } - Fl::handle(FL_MOUSEWHEEL, window); - return 0; - } - - case WM_GETMINMAXINFO: - Fl_WinAPI_Window_Driver::driver(window)->set_minmax((LPMINMAXINFO)lParam); - break; - - case WM_SIZE: - if (!window->parent()) { - Fl_Window_Driver::driver(window)->is_maximized(wParam == SIZE_MAXIMIZED); - if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { - Fl::handle(FL_HIDE, window); - } else { - if (!moving_window) { - Fl::handle(FL_SHOW, window); - resize_bug_fix = window; - window->size(int(ceil(LOWORD(lParam) / scale)), int(ceil(HIWORD(lParam) / scale))); - } else { - window->size(int(ceil(LOWORD(lParam) / scale)), int(ceil(HIWORD(lParam) / scale))); - EnumChildWindows(hWnd, child_window_cb, (LPARAM)&scale); - window->redraw(); - } - } - } - return 0; - - case WM_MOVING: - moving_window = true; - return 1; - - case WM_CAPTURECHANGED: - moving_window = false; - resize_bug_fix = 0; - return 0; - - case WM_MOVE: { - if (IsIconic(hWnd) || window->parent()) { - break; - } - if (moving_window) resize_bug_fix = window; - POINTS pts = MAKEPOINTS(lParam); - int nx = pts.x, ny = pts.y; - // detect when window centre changes screen - Fl_WinAPI_Screen_Driver *sd = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver(); - Fl_WinAPI_Window_Driver *wd = Fl_WinAPI_Window_Driver::driver(window); - int olds = wd->screen_num(); - // Issue #1097: when a fullscreen window is restored to its size, it receives first a WM_MOVE - // and then a WM_SIZE, so it still has its fullscreen size at the WM_MOVE event, which defeats - // using window->w()|h() to compute the center of the (small) window. We detect this situation - // with condition: !window->fullscreen_active() && *wd->no_fullscreen_w() - // and use *wd->no_fullscreen_w()|h() instead of window->w()|h(). - int trueW = window->w(), trueH = window->h(); - if (!window->fullscreen_active() && *wd->no_fullscreen_w()) { - trueW = *wd->no_fullscreen_w(); trueH = *wd->no_fullscreen_h(); - } - int news = sd->screen_num_unscaled(nx + int(trueW * scale / 2), ny + int(trueH * scale / 2)); - if (news == -1) - news = olds; - scale = sd->scale(news); - wd->x(int(round(nx/scale))); - wd->y(int(round(ny/scale))); - } - return 0; - - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - while (window->parent()) - window = window->window(); - SetCursor(Fl_WinAPI_Window_Driver::driver(window)->cursor); - return 0; - } - break; - -#if USE_COLORMAP - case WM_QUERYNEWPALETTE: - fl_GetDC(hWnd); - if (fl_select_palette()) - InvalidateRect(hWnd, NULL, FALSE); - break; - - case WM_PALETTECHANGED: - if ((HWND)wParam != hWnd && fl_select_palette()) - UpdateColors(fl_GetDC(hWnd)); - break; - - case WM_CREATE: - fl_GetDC(hWnd); - fl_select_palette(); - break; -#endif - - case WM_DESTROYCLIPBOARD: - fl_i_own_selection[1] = 0; - return 1; - - case WM_DISPLAYCHANGE: {// when screen configuration (number, size, position) changes - Fl::call_screen_init(); - Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); - return 0; - } - case WM_CHANGECBCHAIN: - if ((hWnd == clipboard_wnd) && (next_clipboard_wnd == (HWND)wParam)) - next_clipboard_wnd = (HWND)lParam; - else - SendMessage(next_clipboard_wnd, WM_CHANGECBCHAIN, wParam, lParam); - return 0; - - case WM_DRAWCLIPBOARD: - // When the clipboard moves between two FLTK windows, - // fl_i_own_selection will temporarily be false as we are - // processing this message. Hence the need to use fl_find(). - if (!initial_clipboard && !fl_find(GetClipboardOwner())) - fl_trigger_clipboard_notify(1); - initial_clipboard = false; - - if (next_clipboard_wnd) - SendMessage(next_clipboard_wnd, WM_DRAWCLIPBOARD, wParam, lParam); - - return 0; - - default: { -#if defined(FLTK_HAVE_PEN_SUPPORT) - LRESULT ret = fl_win32_tablet_handler(fl_msg); - if (ret != -1) - return ret; -#endif - if (Fl::handle(0, 0)) - return 0; - break; } - } // switch (uMsg) - } // if (window) - return DefWindowProcW(hWnd, uMsg, wParam, lParam); -} - -/* Implementation note about the API to get the dimensions of the top/left borders and the title bar - - Function fake_X_wm() below is used before calling CreateWindowExW() to create - a window and before calling SetWindowPos(). Both of these Windows functions need the window size - including borders and title bar. Function fake_X_wm() uses AdjustWindowRectExForDpi() or - AdjustWindowRectEx() to get the sizes of borders and title bar. The gotten values don't always match - what is seen on the display, but they are the **required** values so the subsequent calls to - CreateWindowExW() or SetWindowPos() correctly size the window. - The Windows doc of AdjustWindowRectExForDpi/AdjustWindowRectEx makes this very clear: - Calculates the required size of the window rectangle, based on the desired size of the client - rectangle [and the provided DPI]. This window rectangle can then be passed to the CreateWindowEx - function to create a window with a client area of the desired size. - - Conversely, Fl_WinAPI_Window_Driver::border_width_title_bar_height() is used to get - the true sizes of borders and title bar of a mapped window. The correct API for that is - DwmGetWindowAttribute(). - */ - -// ///////////////////////////////////////////////////////////////// -// This function gets the dimensions of the top/left borders and -// the title bar, if there is one, based on the FL_BORDER, FL_MODAL -// and FL_NONMODAL flags, and on the window's size range. -// It returns the following values: -// -// value | border | title bar -// 0 | none | no -// 1 | fix | yes -// 2 | size | yes - -int Fl_WinAPI_Window_Driver::fake_X_wm(int &X, int &Y, int &bt, int &bx, int &by, DWORD style, DWORD styleEx) { - - const Fl_Window *w = pWindow; - - int W = 0, H = 0, xoff = 0, yoff = 0, dx = 0, dy = 0; - int ret = bx = by = bt = 0; - - int fallback = 1; - float s = Fl::screen_driver()->scale(screen_num()); - int minw, minh, maxw, maxh; - pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (!w->parent()) { - if (fl_xid(w) || style) { - // The block below calculates the window borders by requesting the - // required decorated window rectangle for a desired client rectangle. - // If any part of the function above fails, we will drop to a - // fallback to get the best guess which is always available. - - if (!style) { - HWND hwnd = fl_xid(w); - // request the style flags of this window, as Windows sees them - style = GetWindowLong(hwnd, GWL_STYLE); - styleEx = GetWindowLong(hwnd, GWL_EXSTYLE); - } - - RECT r; - int drawingX, drawingY; // drawing coordinates of window top-left - r.left = drawingX = int(round(w->x() * s)); - r.top = drawingY = int(round(w->y() * s)); - r.right = drawingX + int(w->w() * s); - r.bottom = drawingY + int(w->h() * s); - // get the decoration rectangle for the desired client rectangle - - typedef BOOL(WINAPI* AdjustWindowRectExForDpi_type)(LPRECT, DWORD, BOOL, DWORD, UINT); - static AdjustWindowRectExForDpi_type fl_AdjustWindowRectExForDpi = - (AdjustWindowRectExForDpi_type)GetProcAddress(LoadLibrary("User32.DLL"), "AdjustWindowRectExForDpi"); - BOOL ok; - if (is_dpi_aware && fl_AdjustWindowRectExForDpi) { - Fl_WinAPI_Screen_Driver *sd = (Fl_WinAPI_Screen_Driver*)Fl::screen_driver(); - UINT dpi = UINT(sd->dpi[screen_num()][0]); - ok = fl_AdjustWindowRectExForDpi(&r, style, FALSE, styleEx, dpi); - } else - ok = AdjustWindowRectEx(&r, style, FALSE, styleEx); - if (ok) { - X = r.left; - Y = r.top; - W = r.right - r.left; - H = r.bottom - r.top; - bx = drawingX - r.left; - by = r.bottom - int(drawingY + w->h() * s); // height of the bottom frame - bt = drawingY - r.top - by; // height of top caption bar - xoff = bx; - yoff = by + bt; - dx = W - int(w->w() * s); - dy = H - int(w->h() * s); - if (maxw != minw || maxh != minh) - ret = 2; - else - ret = 1; - fallback = 0; - } - } - } - // This is the original (pre 1.1.7) routine to calculate window border sizes. - if (fallback) { - if (w->border() && !w->parent()) { - if (maxw != minw || maxh != minh) { - ret = 2; - bx = GetSystemMetrics(SM_CXSIZEFRAME); - by = GetSystemMetrics(SM_CYSIZEFRAME); - } else { - ret = 1; - int padding = GetSystemMetrics(SM_CXPADDEDBORDER); - NONCLIENTMETRICS ncm; - ncm.cbSize = sizeof(NONCLIENTMETRICS); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); - bx = GetSystemMetrics(SM_CXFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0); - by = GetSystemMetrics(SM_CYFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0); - } - bt = GetSystemMetrics(SM_CYCAPTION); - } - // The coordinates of the whole window, including non-client area - xoff = bx; - yoff = by + bt; - dx = 2 * bx; - dy = 2 * by + bt; - X = w->x() - xoff; - Y = w->y() - yoff; - W = w->w() + dx; - H = w->h() + dy; - } - - // Proceed to positioning the window fully inside the screen, if possible - // Find screen that contains most of the window - // FIXME: this ought to be the "work area" instead of the entire screen ! - int scr_x = 0, scr_y = 0, scr_w = 0, scr_h = 0; - int ns = Fl::screen_num(int(round(X / s)), int(round(Y / s)), int(W / s), int(H / s)); - ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->screen_xywh_unscaled(scr_x, scr_y, scr_w, scr_h, ns); - // Make border's lower right corner visible - if (scr_x + scr_w < X + W) - X = scr_x + scr_w - W; - if (scr_y + scr_h < Y + H) - Y = scr_y + scr_h - H; - // Make border's upper left corner visible - if (X < scr_x) - X = scr_x; - if (Y < scr_y) - Y = scr_y; - // Make client area's lower right corner visible - if (scr_x + scr_w < X + dx + w->w()) - X = scr_x + scr_w - int(w->w() * s) - dx; - if (scr_y + scr_h < Y + dy + w->h()) - Y = scr_y + scr_h - int(w->h() * s) - dy; - // Make client area's upper left corner visible - if (X + xoff < scr_x) - X = scr_x - xoff; - if (Y + yoff < scr_y) - Y = scr_y - yoff; - // Return the client area's top left corner in (X,Y) - X += xoff; - Y += yoff; - - if (w->fullscreen_active()) { - bx = by = bt = 0; - } - - return ret; -} - -//////////////////////////////////////////////////////////////// - -static void delayed_fullscreen(Fl_Window *win) { - Fl::remove_check((Fl_Timeout_Handler)delayed_fullscreen, win); - win->fullscreen_off(); - win->fullscreen(); -} - - -static void delayed_maximize(Fl_Window *win) { - Fl::remove_check((Fl_Timeout_Handler)delayed_maximize, win); - win->un_maximize(); - win->maximize(); -} - - -void Fl_WinAPI_Window_Driver::resize(int X, int Y, int W, int H) { -//fprintf(stderr, "resize w()=%d W=%d h()=%d H=%d\n",pWindow->w(), W,pWindow->h(), H); - if (Fl_Window::is_a_rescale() && pWindow->fullscreen_active()) { - Fl::add_check((Fl_Timeout_Handler)delayed_fullscreen, pWindow); - } else if (Fl_Window::is_a_rescale() && pWindow->maximize_active()) { - Fl::add_check((Fl_Timeout_Handler)delayed_maximize, pWindow); - } - UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER; - int is_a_resize = (W != w() || H != h() || Fl_Window::is_a_rescale()); - int resize_from_program = (pWindow != resize_bug_fix); - if (!resize_from_program) - resize_bug_fix = 0; - if (X != x() || Y != y() || Fl_Window::is_a_rescale()) { - force_position(1); - } else { - if (!is_a_resize) - return; - flags |= SWP_NOMOVE; - } - if (is_a_resize) { - if (resize_from_program && shown()) { - // don't obey "resize from program" when window is maximized - WINDOWPLACEMENT wplace; - wplace.length = sizeof(WINDOWPLACEMENT); - BOOL ok = GetWindowPlacement(fl_xid(pWindow), &wplace); - if (ok && wplace.showCmd == SW_SHOWMAXIMIZED) return; - } - pWindow->Fl_Group::resize(X, Y, W, H); - if (visible_r()) { - pWindow->redraw(); - // only wait for exposure if this window has a size - a window - // with no width or height will never get an exposure event - Fl_X *i = Fl_X::flx(pWindow); - if (i && W > 0 && H > 0) - wait_for_expose_value = 1; - } - } else { - x(X); - y(Y); - flags |= SWP_NOSIZE; - } - if (!border()) - flags |= SWP_NOACTIVATE; - if (resize_from_program && shown()) { - int dummy_x, dummy_y, bt, bx, by; - // compute window position and size in scaled units - float s = Fl::screen_driver()->scale(screen_num()); - int scaledX = int(round(X * s)), scaledY = int(round(Y * s)), scaledW = int(W * s), scaledH = int(H * s); - // Ignore window managing when resizing, so that windows (and more - // specifically menus) can be moved offscreen. - if (fake_X_wm(dummy_x, dummy_y, bt, bx, by)) { - scaledX -= bx; - scaledY -= by + bt; - scaledW += 2 * bx; - scaledH += 2 * by + bt; - } - // avoid zero size windows. A zero sized window on Win32 - // will cause continouly new redraw events. - if (scaledW <= 0) - scaledW = 1; - if (scaledH <= 0) - scaledH = 1; - SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, flags); - } -} - - -//////////////////////////////////////////////////////////////// - -/* - This silly little class remembers the name of all window classes - we register to avoid double registration. It has the added bonus - of freeing everything on application close as well. - */ -class NameList { -public: - NameList() { - name = (char **)malloc(sizeof(char **)); - NName = 1; - nName = 0; - } - ~NameList() { - int i; - for (i = 0; i < nName; i++) - free(name[i]); - if (name) - free(name); - } - void add_name(const char *n) { - if (NName == nName) { - NName += 5; - name = (char **)realloc(name, NName * sizeof(char *)); - } - name[nName++] = fl_strdup(n); - } - char has_name(const char *n) { - int i; - for (i = 0; i < nName; i++) { - if (strcmp(name[i], n) == 0) - return 1; - } - return 0; - } - -private: - char **name; - int nName, NName; -}; - -void fl_fix_focus(); // in Fl.cxx - -UINT fl_wake_msg = 0; -int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR - -void Fl_WinAPI_Window_Driver::makeWindow() { - Fl_Group::current(0); // get rid of very common user bug: forgot end() - - fl_open_display(); - - // if the window is a subwindow and our parent is not mapped yet, we - // mark this window visible, so that mapping the parent at a later - // point in time will call this function again to finally map the subwindow. - Fl_Window *w = pWindow; - if (w->parent() && !Fl_X::flx(w->window())) { - w->set_visible(); - return; - } - - static NameList class_name_list; - static const char *first_class_name = 0L; - const char *class_name = w->xclass(); - if (!class_name) - class_name = first_class_name; // reuse first class name used - if (!class_name) - class_name = "FLTK"; // default to create a "FLTK" WNDCLASS - if (!first_class_name) { - first_class_name = class_name; - } -// Prefix user-set window class name by "FLTK", unless it's already here, -// to avoid collision with system-defined window class names (example "edit") - if (strncmp(class_name, "FLTK", 4)) { - static char new_class_name[100]; - snprintf(new_class_name, sizeof(new_class_name), "FLTK-%s", class_name); - class_name = new_class_name; - } - //fprintf(stderr,"makeWindow: class_name=%s\n",class_name);fflush(stderr); - - wchar_t class_namew[100]; // (limited) buffer for Windows class name - - // convert UTF-8 class_name to wchar_t for RegisterClassExW and CreateWindowExW - - fl_utf8toUtf16(class_name, - (unsigned)strlen(class_name), // in - (unsigned short *)class_namew, // out - (unsigned)sizeof(class_namew) / sizeof(wchar_t)); // max. size - - if (!class_name_list.has_name(class_name)) { - WNDCLASSEXW wcw; - memset(&wcw, 0, sizeof(wcw)); - wcw.cbSize = sizeof(WNDCLASSEXW); - - // Documentation states a device context consumes about 800 bytes - // of memory... so who cares? If 800 bytes per window is what it - // takes to speed things up, I'm game. - wcw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - wcw.lpfnWndProc = (WNDPROC)WndProc; - wcw.cbClsExtra = wcw.cbWndExtra = 0; - wcw.hInstance = fl_display; - if (!w->icon() && !icon_->count) - w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); - wcw.hIcon = wcw.hIconSm = (HICON)w->icon(); - wcw.hCursor = LoadCursor(NULL, IDC_ARROW); - wcw.hbrBackground = NULL; - wcw.lpszMenuName = NULL; - wcw.lpszClassName = class_namew; - RegisterClassExW(&wcw); - class_name_list.add_name(class_name); - } - - const wchar_t *message_namew = L"FLTK::ThreadWakeup"; - if (!fl_wake_msg) - fl_wake_msg = RegisterWindowMessageW(message_namew); - - HWND parent; - DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - DWORD styleEx = WS_EX_LEFT; - - // compute adequate screen where to put the window - int nscreen = 0; - if (w->parent()) { - nscreen = Fl_Window_Driver::driver(w->top_window())->screen_num(); - } else if (Fl_Window_Driver::driver(w)->force_position() && Fl_WinAPI_Window_Driver::driver(w)->screen_num_ >= 0) { - nscreen = Fl_Window_Driver::driver(w)->screen_num(); - } else { - Fl_Window *hint = Fl::first_window(); - if (hint) { - nscreen = Fl_Window_Driver::driver(hint->top_window())->screen_num(); - } else if (Fl::screen_driver()->screen_count() > 1 ) { - // put the new window on same screen as mouse - int mx, my, X, Y, W, H; - nscreen = Fl::screen_driver()->get_mouse(mx, my); - Fl::screen_xywh(X, Y, W, H, nscreen); - if (mx + w->w() >= X + W) mx = X + W - w->w(); - if (my + w->h() >= Y + H) my = Y + H - w->h(); - w->position(mx, my); - } - } - Fl_Window_Driver::driver(w)->screen_num(nscreen); - float s = Fl::screen_driver()->scale(nscreen); - int xp = int(round(w->x() * s)); // these are in graphical units - int yp = int(round(w->y() * s)); - int wp = int(w->w() * s); - int hp = int(w->h() * s); - - int showit = 1; - - if (w->parent()) { - style |= WS_CHILD; - styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - parent = fl_xid(w->window()); - } else { // top level window - styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - - int wintype = 0; - if (w->border()) { - if (is_resizable()) - wintype = 2; - else - wintype = 1; - } - - switch (wintype) { - // No border (used for menus) - case 0: - style |= WS_POPUP; - styleEx |= WS_EX_TOOLWINDOW; - break; - - // Thin border and title bar - case 1: - style |= WS_DLGFRAME | WS_CAPTION; - if (!w->modal()) - style |= WS_SYSMENU | WS_MINIMIZEBOX; - break; - - // Thick, resizable border and title bar, with maximize button - case 2: - style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION; - if (!w->modal()) - style |= WS_MINIMIZEBOX; - break; - } - - int xwm = xp, ywm = yp, bt, bx, by; // these are in graphical units - - fake_X_wm(xwm, ywm, bt, bx, by, style, styleEx); - - if (by + bt) { - wp += 2 * bx; - hp += 2 * by + bt; - } - if (!force_position()) { - xp = yp = CW_USEDEFAULT; - } else { - if (!Fl::grab()) { - xp = xwm; - yp = ywm; - x(int(round(xp / s))); - y(int(round(yp / s))); - } - xp -= bx; - yp -= by + bt; - } - - parent = 0; - if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) { - // find some other window to be "transient for": - Fl_Window *w = Fl_X::first->w; - while (w->parent()) - w = w->window(); - parent = fl_xid(w); - if (!w->visible()) - showit = 0; -// https://www.fltk.org/str.php?L1115 -// Mike added the code below to fix issues with tooltips that unfortunately -// he does not specify in detail. After extensive testing, I can't see -// how this fixes things, but I do see how a window opened by a timer will -// link that window to the current popup, which is wrong. -// Matt, Apr 30th, 2023 -// } else if (Fl::grab()) { -// parent = fl_xid(Fl::grab()); - } - } - - Fl_X *x = new Fl_X; - other_xid = 0; - x->w = w; - flx(x); - x->region = 0; - Fl_WinAPI_Window_Driver::driver(w)->private_dc = 0; - cursor = LoadCursor(NULL, IDC_ARROW); - custom_cursor = 0; - if (!fl_codepage) - fl_get_codepage(); - - WCHAR *lab = NULL; - if (w->label()) { - size_t l = strlen(w->label()); - unsigned wlen = fl_utf8toUtf16(w->label(), (unsigned)l, NULL, 0); // Pass NULL to query length - wlen++; - lab = (WCHAR *)malloc(sizeof(WCHAR) * wlen); - wlen = fl_utf8toUtf16(w->label(), (unsigned)l, (unsigned short *)lab, wlen); - lab[wlen] = 0; - } - x->xid = (fl_uintptr_t)CreateWindowExW(styleEx, - class_namew, lab, style, - xp, yp, wp, hp, - parent, - NULL, // menu - fl_display, - NULL // creation parameters - ); - if (lab) - free(lab); - - x->next = Fl_X::first; - Fl_X::first = x; - - set_icons(); - - if (w->fullscreen_active()) { - /* We need to make sure that the fullscreen is created on the - default monitor, ie the desktop where the shortcut is located - etc. This requires that CreateWindow is called with CW_USEDEFAULT - for x and y. We can then use GetWindowRect to determine which - monitor the window was placed on. */ - RECT rect; - GetWindowRect((HWND)x->xid, &rect); - make_fullscreen(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); - } - - // Setup clipboard monitor target if there are registered handlers and - // no window is targeted. - if (!fl_clipboard_notify_empty() && clipboard_wnd == NULL) - fl_clipboard_notify_target((HWND)x->xid); - - wait_for_expose_value = ((wp == 0 || hp == 0) && !w->border() && !w->parent() ? 0 : 1); // issue #985 - if (show_iconic()) { - showit = 0; - show_iconic(0); - } - if (showit) { - w->set_visible(); - int old_event = Fl::e_number; - w->handle(Fl::e_number = FL_SHOW); // get child windows to appear - Fl::e_number = old_event; - w->redraw(); // force draw to happen - } - - // Needs to be done before ShowWindow() to get the correct behavior - // when we get WM_SETFOCUS. - if (w->modal()) { - Fl::modal_ = w; - fl_fix_focus(); - } - - // If we've captured the mouse, we don't want to activate any - // other windows from the code, or we lose the capture. - ShowWindow((HWND)x->xid, !showit ? SW_SHOWMINNOACTIVE : - (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); - - // Register all windows for potential drag'n'drop operations - RegisterDragDrop((HWND)x->xid, flIDropTarget); - - if (!im_enabled) - flImmAssociateContextEx((HWND)x->xid, 0, 0); - - if (w->fullscreen_active()) Fl::handle(FL_FULLSCREEN, w); -} - - -//////////////////////////////////////////////////////////////// - -HINSTANCE fl_display = GetModuleHandle(NULL); - -HINSTANCE fl_win32_display() { return fl_display; } - -void Fl_WinAPI_Window_Driver::set_minmax(LPMINMAXINFO minmax) { - int td, wd, hd, dummy_x, dummy_y; - - fake_X_wm(dummy_x, dummy_y, td, wd, hd); - wd *= 2; - hd *= 2; - hd += td; - - int minw, minh, maxw, maxh; - pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - float s = Fl::screen_driver()->scale(screen_num()); - minmax->ptMinTrackSize.x = LONG(s * minw) + wd; - minmax->ptMinTrackSize.y = LONG(s * minh) + hd; - if (maxw) { - minmax->ptMaxTrackSize.x = LONG(s * maxw) + wd; - minmax->ptMaxSize.x = LONG(s * maxw) + wd; - } - if (maxh) { - minmax->ptMaxTrackSize.y = LONG(s * maxh) + hd; - minmax->ptMaxSize.y = LONG(s * maxh) + hd; - } -} - - -//////////////////////////////////////////////////////////////// - -// returns pointer to the filename, or null if name ends with '/' -const char *Fl_WinAPI_System_Driver::filename_name(const char *name) { - const char *p, *q; - if (!name) - return (0); - q = name; - if (q[0] && q[1] == ':') - q += 2; // skip leading drive letter - for (p = q; *p; p++) { - if (*p == '/' || *p == '\\') - q = p + 1; - } - return q; -} - - -//////////////////////////////////////////////////////////////// - -static HICON image_to_icon(const Fl_RGB_Image *image, bool is_icon, int hotx, int hoty) { - BITMAPV5HEADER bi; - HBITMAP bitmap, mask; - DWORD *bits; - HICON icon; - - if (!is_icon) { - if ((hotx < 0) || (hotx >= image->data_w())) - return NULL; - if ((hoty < 0) || (hoty >= image->data_h())) - return NULL; - } - - memset(&bi, 0, sizeof(BITMAPV5HEADER)); - - bi.bV5Size = sizeof(BITMAPV5HEADER); - bi.bV5Width = image->data_w(); - bi.bV5Height = -image->data_h(); // Negative for top-down - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - bi.bV5RedMask = 0x00FF0000; - bi.bV5GreenMask = 0x0000FF00; - bi.bV5BlueMask = 0x000000FF; - bi.bV5AlphaMask = 0xFF000000; - - HDC hdc; - - hdc = GetDC(NULL); - bitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&bits, NULL, 0); - ReleaseDC(NULL, hdc); - - if (bits == NULL) - return NULL; - - const uchar *i = (const uchar *)*image->data(); - const int extra_data = image->ld() ? (image->ld() - image->data_w() * image->d()) : 0; - - for (int y = 0; y < image->data_h(); y++) { - for (int x = 0; x < image->data_w(); x++) { - switch (image->d()) { - case 1: - *bits = (0xff << 24) | (i[0] << 16) | (i[0] << 8) | i[0]; - break; - case 2: - *bits = (i[1] << 24) | (i[0] << 16) | (i[0] << 8) | i[0]; - break; - case 3: - *bits = (0xff << 24) | (i[0] << 16) | (i[1] << 8) | i[2]; - break; - case 4: - *bits = (i[3] << 24) | (i[0] << 16) | (i[1] << 8) | i[2]; - break; - } - i += image->d(); - bits++; - } - i += extra_data; - } - - // A mask bitmap is still needed even though it isn't used - mask = CreateBitmap(image->data_w(), image->data_h(), 1, 1, NULL); - if (mask == NULL) { - DeleteObject(bitmap); - return NULL; - } - - ICONINFO ii; - - ii.fIcon = is_icon; - ii.xHotspot = hotx; - ii.yHotspot = hoty; - ii.hbmMask = mask; - ii.hbmColor = bitmap; - - icon = CreateIconIndirect(&ii); - - DeleteObject(bitmap); - DeleteObject(mask); - - return icon; -} - -//////////////////////////////////////////////////////////////// - -static HICON default_big_icon = NULL; -static HICON default_small_icon = NULL; - -static const Fl_RGB_Image *find_best_icon(int ideal_width, const Fl_RGB_Image *icons[], int count) { - const Fl_RGB_Image *best; - - best = NULL; - - for (int i = 0; i < count; i++) { - if (best == NULL) - best = icons[i]; - else { - if (best->w() < ideal_width) { - if (icons[i]->w() > best->w()) - best = icons[i]; - } else { - if ((icons[i]->w() >= ideal_width) && (icons[i]->w() < best->w())) - best = icons[i]; - } - } - } - - return best; -} - -void Fl_WinAPI_Screen_Driver::default_icons(const Fl_RGB_Image *icons[], int count) { - const Fl_RGB_Image *best_big, *best_small; - - if (default_big_icon != NULL) - DestroyIcon(default_big_icon); - if (default_small_icon != NULL) - DestroyIcon(default_small_icon); - - default_big_icon = NULL; - default_small_icon = NULL; - - best_big = find_best_icon(GetSystemMetrics(SM_CXICON), icons, count); - best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), icons, count); - - bool need_delete; - if (best_big != NULL) { - need_delete = false; - if (best_big->w() != best_big->data_w() || best_big->h() != best_big->data_h()) { - best_big = (Fl_RGB_Image *)best_big->copy(); - need_delete = true; - } - default_big_icon = image_to_icon(best_big, true, 0, 0); - if (need_delete) delete best_big; - } - - if (best_small != NULL) { - need_delete = false; - if (best_small->w() != best_small->data_w() || - best_small->h() != best_small->data_h()) { - best_small = (Fl_RGB_Image *)best_small->copy(); - need_delete = true; - } - default_small_icon = image_to_icon(best_small, true, 0, 0); - if (need_delete) delete best_small; - } -} - - -void Fl_Window::icons(HICON big_icon, HICON small_icon) { - free_icons(); - if (big_icon != NULL) - Fl_WinAPI_Window_Driver::driver(this)->icon_->big_icon = CopyIcon(big_icon); - if (small_icon != NULL) - Fl_WinAPI_Window_Driver::driver(this)->icon_->small_icon = CopyIcon(small_icon); - if (Fl_X::flx(this)) - Fl_WinAPI_Window_Driver::driver(this)->set_icons(); -} - -void Fl_Window::default_icons(HICON big_icon, HICON small_icon) { - if (default_big_icon != NULL) - DestroyIcon(default_big_icon); - if (default_small_icon != NULL) - DestroyIcon(default_small_icon); - - default_big_icon = NULL; - default_small_icon = NULL; - - if (big_icon != NULL) - default_big_icon = CopyIcon(big_icon); - if (small_icon != NULL) - default_small_icon = CopyIcon(small_icon); -} - -void Fl_WinAPI_Window_Driver::set_icons() { - HICON big_icon, small_icon; - - // Windows doesn't copy the icons, so we have to "leak" them when - // setting, and clean up when we change to some other icons. - big_icon = (HICON)SendMessage(fl_xid(pWindow), WM_GETICON, ICON_BIG, 0); - if ((big_icon != NULL) && (big_icon != default_big_icon)) - DestroyIcon(big_icon); - small_icon = (HICON)SendMessage(fl_xid(pWindow), WM_GETICON, ICON_SMALL, 0); - if ((small_icon != NULL) && (small_icon != default_small_icon)) - DestroyIcon(small_icon); - - big_icon = NULL; - small_icon = NULL; - - if (icon_->count) { - const Fl_RGB_Image *best_big, *best_small; - - best_big = find_best_icon(GetSystemMetrics(SM_CXICON), - (const Fl_RGB_Image **)icon_->icons, - icon_->count); - best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), - (const Fl_RGB_Image **)icon_->icons, - icon_->count); - - if (best_big != NULL) - big_icon = image_to_icon(best_big, true, 0, 0); - if (best_small != NULL) - small_icon = image_to_icon(best_small, true, 0, 0); - } else { - if ((icon_->big_icon != NULL) || (icon_->small_icon != NULL)) { - big_icon = icon_->big_icon; - small_icon = icon_->small_icon; - } else { - big_icon = default_big_icon; - small_icon = default_small_icon; - } - } - - SendMessage(fl_xid(pWindow), WM_SETICON, ICON_BIG, (LPARAM)big_icon); - SendMessage(fl_xid(pWindow), WM_SETICON, ICON_SMALL, (LPARAM)small_icon); -} - - -//////////////////////////////////////////////////////////////// - -#ifndef IDC_HAND -#define IDC_HAND MAKEINTRESOURCE(32649) -#endif // !IDC_HAND - -int Fl_WinAPI_Window_Driver::set_cursor(Fl_Cursor c) { - LPSTR n; - HCURSOR new_cursor; - - if (c == FL_CURSOR_NONE) - new_cursor = NULL; - else { - switch (c) { - case FL_CURSOR_ARROW: - n = IDC_ARROW; - break; - case FL_CURSOR_CROSS: - n = IDC_CROSS; - break; - case FL_CURSOR_WAIT: - n = IDC_WAIT; - break; - case FL_CURSOR_INSERT: - n = IDC_IBEAM; - break; - case FL_CURSOR_HAND: - n = IDC_HAND; - break; - case FL_CURSOR_HELP: - n = IDC_HELP; - break; - case FL_CURSOR_MOVE: - n = IDC_SIZEALL; - break; - case FL_CURSOR_N: - case FL_CURSOR_S: - // FIXME: Should probably have fallbacks for these instead - case FL_CURSOR_NS: - n = IDC_SIZENS; - break; - case FL_CURSOR_NE: - case FL_CURSOR_SW: - // FIXME: Dito. - case FL_CURSOR_NESW: - n = IDC_SIZENESW; - break; - case FL_CURSOR_E: - case FL_CURSOR_W: - // FIXME: Dito. - case FL_CURSOR_WE: - n = IDC_SIZEWE; - break; - case FL_CURSOR_SE: - case FL_CURSOR_NW: - // FIXME: Dito. - case FL_CURSOR_NWSE: - n = IDC_SIZENWSE; - break; - default: - return 0; - } - - new_cursor = LoadCursor(NULL, n); - if (new_cursor == NULL) - return 0; - } - - if ((cursor != NULL) && custom_cursor) - DestroyIcon(cursor); - - cursor = new_cursor; - custom_cursor = 0; - - SetCursor(cursor); - - return 1; -} - -int Fl_WinAPI_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { - HCURSOR new_cursor; - Fl_RGB_Image *scaled_image = (Fl_RGB_Image*)image->copy(); - scaled_image->normalize(); - new_cursor = image_to_icon(scaled_image, false, hotx, hoty); - delete scaled_image; - if (new_cursor == NULL) - return 0; - - if ((cursor != NULL) && custom_cursor) - DestroyIcon(cursor); - - cursor = new_cursor; - custom_cursor = 1; - - SetCursor(cursor); - - return 1; -} - - -//////////////////////////////////////////////////////////////// -// Implement the virtual functions for the base Fl_Window class: - -void Fl_WinAPI_Window_Driver::show() { - if (!shown()) { - makeWindow(); - } else { - // Once again, we would lose the capture if we activated the window. - Fl_X *i = Fl_X::flx(pWindow); - if (IsIconic((HWND)i->xid)) - OpenIcon((HWND)i->xid); - if (!fl_capture) - BringWindowToTop((HWND)i->xid); - // ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE); - } -} - -// the current context -// the current window handle, initially set to -1 so we can correctly -// allocate fl_GetDC(0) -HWND fl_window = NULL; - -// Here we ensure only one GetDC is ever in place. -HDC fl_GetDC(HWND w) { - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - if (gc) { - if (w == fl_window && fl_window != NULL) - return gc; - if (fl_window) - fl_release_dc(fl_window, gc); // ReleaseDC - } - gc = GetDC(w); - Fl_Graphics_Driver::default_driver().gc(gc); - fl_save_dc(w, gc); - fl_window = w; - // calling GetDC seems to always reset these: (?) - SetTextAlign(gc, TA_BASELINE | TA_LEFT); - SetBkMode(gc, TRANSPARENT); - - return gc; -} - - -/* Make sure that all allocated fonts are released. This works only if - Fl::run() is allowed to exit by closing all windows. Calling 'exit(int)' - will not automatically free any fonts. */ -void fl_free_fonts(void) { - // remove the Fl_Font_Descriptor chains - int i; - Fl_Fontdesc *s; - Fl_Font_Descriptor *f; - Fl_Font_Descriptor *ff; - for (i = 0; i < FL_FREE_FONT; i++) { - s = fl_fonts + i; - for (f = s->first; f; f = ff) { - ff = f->next; - delete (Fl_GDI_Font_Descriptor*)f; - s->first = ff; - } - } -} - - -/////////////////////////////////////////////////////////////////////// -// -// The following routines help fix a problem with the leaking of Windows -// Device Context (DC) objects. The 'proper' protocol is for a program to -// acquire a DC, save its state, do the modifications needed for drawing, -// perform the drawing, restore the initial state, and release the DC. In -// FLTK, the save and restore steps have previously been omitted and DCs are -// not properly released, leading to a great number of DC leaks. As some -// Windows "OSs" will hang when any process exceeds roughly 10,000 GDI objects, -// it is important to control GDI leaks, which are much more important than memory -// leaks. The following struct, global variable, and routines help implement -// the above protocol for those cases where the GetDC and RestoreDC are not in -// the same routine. For each GetDC, fl_save_dc is used to create an entry in -// a linked list that saves the window handle, the DC handle, and the initial -// state. When the DC is to be released, 'fl_release_dc' is called. It restores -// the initial state and releases the DC. When the program exits, 'fl_cleanup_dc_list' -// frees any remaining nodes in the list. - -struct Win_DC_List { // linked list - HWND window; // window handle - HDC dc; // device context handle - int saved_dc; // initial state of DC - Win_DC_List *next; // pointer to next item -}; - -static Win_DC_List *win_DC_list = 0; - -void fl_save_dc(HWND w, HDC dc) { - Win_DC_List *t; - t = new Win_DC_List; - t->window = w; - t->dc = dc; - t->saved_dc = SaveDC(dc); - if (win_DC_list) - t->next = win_DC_list; - else - t->next = NULL; - win_DC_list = t; -} - -void fl_release_dc(HWND w, HDC dc) { - Win_DC_List *t = win_DC_list; - Win_DC_List *prev = 0; - if (!t) - return; - do { - if (t->dc == dc) { - RestoreDC(dc, t->saved_dc); - ReleaseDC(w, dc); - if (!prev) { - win_DC_list = t->next; // delete first item - } else { - prev->next = t->next; // one in the middle - } - delete (t); - return; - } - prev = t; - t = t->next; - } while (t); -} - -void fl_cleanup_dc_list(void) { // clean up the list - Win_DC_List *t = win_DC_list; - if (!t) - return; - do { - RestoreDC(t->dc, t->saved_dc); - ReleaseDC(t->window, t->dc); - win_DC_list = t->next; - delete (t); - t = win_DC_list; - } while (t); -} - -/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders. - This function exploits a feature of Fl_WinAPI_Screen_Driver::read_win_rectangle() which, - when fl_gc is set to the screen device context, captures the window decoration. - */ -void Fl_WinAPI_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image *&top, Fl_RGB_Image *&left, - Fl_RGB_Image *&bottom, Fl_RGB_Image *&right) { - top = left = bottom = right = NULL; - if (!shown() || parent() || !border() || !visible()) - return; - int wsides, hbottom, bt; - float scaling = Fl::screen_driver()->scale(screen_num()); - RECT r = border_width_title_bar_height(wsides, hbottom, bt); - int htop = bt + hbottom; - Fl_Surface_Device::push_current(Fl_Display_Device::display_device()); - pWindow->show(); - while (Fl::ready()) - Fl::check(); - HDC save_gc = (HDC)fl_graphics_driver->gc(); - fl_graphics_driver->gc(GetDC(NULL)); - int ww = int(w() * scaling) + 2 * wsides; - wsides = int(wsides / scaling); - if (wsides < 1) - wsides = 1; - ww = int(ww / scaling); - if (wsides <= 1) - ww = w() + 2 * wsides; - // capture the 4 window sides from screen - int offset = r.left < 0 ? -r.left : 0; - Fl_WinAPI_Screen_Driver *dr = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver(); - if (htop && r.right - r.left > offset) { - top = dr->read_win_rectangle_unscaled(r.left+offset, r.top, r.right - r.left-offset, htop, 0); - if (scaling != 1 && top) - top->scale(ww, int(htop / scaling), 0, 1); - } - if (wsides) { - left = dr->read_win_rectangle_unscaled(r.left + offset, r.top + htop, wsides, int(h() * scaling), 0); - right = dr->read_win_rectangle_unscaled(r.right - wsides, r.top + htop, wsides, int(h() * scaling), 0); - bottom = dr->read_win_rectangle_unscaled(r.left+offset, r.bottom - hbottom, ww, hbottom, 0); - if (scaling != 1) { - if (left) left->scale(wsides, h(), 0, 1); - if (right) right->scale(wsides, h(), 0, 1); - if (bottom) bottom->scale(ww, hbottom, 0, 1); - } - } - ReleaseDC(NULL, (HDC)fl_graphics_driver->gc()); - fl_graphics_driver->gc(save_gc); - Fl_Surface_Device::pop_current(); -} diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index fce02de32..7da44acf2 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -62,7 +62,7 @@ #if FLTK_USE_CAIRO # include <cairo-xlib.h> -# include <cairo/cairo.h> +# include <cairo.h> #endif // FLTK_USE_CAIRO #define USE_XRANDR (HAVE_DLSYM && HAVE_DLFCN_H) // means attempt to dynamically load libXrandr.so diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index eee10900d..ca0cf5095 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H @@ -23,7 +23,7 @@ #include <FL/Fl_Graphics_Driver.H> #include "../../Fl_Scalable_Graphics_Driver.H" // Fl_Font_Descriptor -#include <cairo/cairo.h> +#include <cairo.h> typedef struct _PangoLayout PangoLayout; typedef struct _PangoContext PangoContext; diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index 236a677b1..bf2e2d361 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx @@ -26,7 +26,7 @@ #include <FL/platform.H> #include <FL/fl_draw.H> #include <FL/fl_utf8.h> -#include <cairo/cairo.h> +#include <cairo.h> #include <pango/pangocairo.h> #if ! PANGO_VERSION_CHECK(1,16,0) # error "Requires Pango 1.16 or higher" diff --git a/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx index ed04d1167..a400460d8 100644 --- a/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx @@ -20,7 +20,7 @@ #include "Fl_X11_Cairo_Graphics_Driver.H" #include <FL/platform.H> -#include <cairo/cairo.h> +#include <cairo.h> #include <pango/pangocairo.h> #include <stdlib.h> diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H deleted file mode 100644 index d5ba9c21c..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H +++ /dev/null @@ -1,60 +0,0 @@ -// -// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Gl_Window_Driver.H" - -class Fl_Gl_Choice; -#ifdef __OBJC__ - @class NSOpenGLContext; -#else - class NSOpenGLContext; -#endif - -class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { - NSOpenGLContext *gl1ctxt; // GL1 context in addition to GL3 context - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win); - float pixels_per_unit() FL_OVERRIDE; - void before_show(int& need_after) FL_OVERRIDE; - void after_show() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void make_current_before() FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void resize(int is_a_resize, int w, int h) FL_OVERRIDE; - char swap_type() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void gl_start() FL_OVERRIDE; - char *alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) FL_OVERRIDE; - Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h) FL_OVERRIDE; - bool need_scissor() FL_OVERRIDE { return true; } - void* GetProcAddress(const char *procName) FL_OVERRIDE; - void apply_scissor(); - void switch_to_GL1() FL_OVERRIDE; - void switch_back() FL_OVERRIDE; -}; - - -#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm deleted file mode 100644 index 561aa2ce5..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm +++ /dev/null @@ -1,527 +0,0 @@ -// -// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include <FL/gl.h> -#include "../../Fl_Gl_Choice.H" -#include "../../Fl_Screen_Driver.H" -#include "Fl_Cocoa_Window_Driver.H" -#include "Fl_Cocoa_Gl_Window_Driver.H" -#include <FL/Fl_Graphics_Driver.H> -#include <OpenGL/OpenGL.h> -#include <FL/Fl_Image_Surface.H> -#include <dlfcn.h> - -#import <Cocoa/Cocoa.h> - -/* macOS offers only core contexts when using GL3. This forbids to draw - FLTK widgets in a GL3-using NSOpenGLContext because these widgets are drawn - with the GL1-based Fl_OpenGL_Graphics_Driver. The solution implemented here - is to create an additional NSView and an associated additional NSOpenGLContext - (gl1ctxt) placed above and sized as the GL3-based window, to set the new - NSOpenGLContext non opaque and GL1-based, and to draw the FLTK widgets in the - new view/GL1 context. - */ - -// Describes crap needed to create a GLContext. -class Fl_Cocoa_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_Cocoa_Gl_Window_Driver; -private: - NSOpenGLPixelFormat* pixelformat; -public: - Fl_Cocoa_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - pixelformat = NULL; - } -}; - - -Fl_Cocoa_Gl_Window_Driver::Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : - Fl_Gl_Window_Driver(win) { - gl1ctxt = NULL; -} - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_Cocoa_Gl_Window_Driver(w); -} - - -static NSOpenGLPixelFormat* mode_to_NSOpenGLPixelFormat(int m, const int *alistp) -{ - NSOpenGLPixelFormatAttribute attribs[32]; - int n = 0; - // AGL-style code remains commented out for comparison - if (!alistp) { - if (m & FL_INDEX) { - //list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; - } else { - //list[n++] = AGL_RGBA; - //list[n++] = AGL_GREEN_SIZE; - //list[n++] = (m & FL_RGB8) ? 8 : 1; - attribs[n++] = NSOpenGLPFAColorSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 32 : 1); - if (m & FL_ALPHA) { - //list[n++] = AGL_ALPHA_SIZE; - attribs[n++] = NSOpenGLPFAAlphaSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 8 : 1); - } - if (m & FL_ACCUM) { - //list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAAccumSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - if (m & FL_ALPHA) { - //list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; - } - } - } - if (m & FL_DOUBLE) { - //list[n++] = AGL_DOUBLEBUFFER; - attribs[n++] = NSOpenGLPFADoubleBuffer; - } - if (m & FL_DEPTH32) { - //list[n++] = AGL_DEPTH_SIZE; list[n++] = 32; - attribs[n++] = NSOpenGLPFADepthSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)32; - } else if (m & FL_DEPTH) { - //list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; - attribs[n++] = NSOpenGLPFADepthSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)24; - } - if (m & FL_STENCIL) { - //list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAStencilSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - } - if (m & FL_STEREO) { - //list[n++] = AGL_STEREO; - attribs[n++] = 6/*NSOpenGLPFAStereo*/; - } - if (m & FL_MULTISAMPLE) { - attribs[n++] = NSOpenGLPFAMultisample; // 10.4 - attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - attribs[n++] = NSOpenGLPFASamples; attribs[n++] = (NSOpenGLPixelFormatAttribute)4; - } - attribs[n++] = NSOpenGLPFAOpenGLProfile; - attribs[n++] = (m & FL_OPENGL3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy; - } else { - while (alistp[n] && n < 30) { - attribs[n] = (NSOpenGLPixelFormatAttribute)alistp[n]; - n++; - } - } - attribs[n] = (NSOpenGLPixelFormatAttribute)0; - NSOpenGLPixelFormat *pixform = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - /*GLint color,alpha,accum,depth; - [pixform getValues:&color forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0]; - [pixform getValues:&alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0]; - [pixform getValues:&accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:0]; - [pixform getValues:&depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0]; - NSLog(@"color=%d alpha=%d accum=%d depth=%d",color,alpha,accum,depth);*/ - return pixform; -} - - -Fl_Gl_Choice *Fl_Cocoa_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl::screen_driver()->open_display(); // useful when called through gl_start() - Fl_Cocoa_Gl_Choice *g = (Fl_Cocoa_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - NSOpenGLPixelFormat* fmt = mode_to_NSOpenGLPixelFormat(m, alistp); - if (!fmt) return 0; - g = new Fl_Cocoa_Gl_Choice(m, alistp, first); - first = g; - g->pixelformat = fmt; - return g; -} - - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -# define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity -#endif - -static void remove_gl_context_opacity(NSOpenGLContext *ctx) { - GLint gl_opacity; - [ctx getValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - if (gl_opacity != 0) { - gl_opacity = 0; - [ctx setValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - } -} - - -static NSOpenGLContext *create_GLcontext_for_window( - NSOpenGLPixelFormat *pixelformat, - NSOpenGLContext *shared_ctx, Fl_Window *window) -{ - NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:shared_ctx]; - if (shared_ctx && !context) context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:nil]; - if (context) { - NSView *view = [fl_xid(window) contentView]; - [view setWantsBestResolutionOpenGLSurface:(Fl::use_high_res_GL() != 0)]; - [context setView:view]; - if (Fl_Cocoa_Window_Driver::driver(window)->subRect()) { - remove_gl_context_opacity(context); - } - } - return context; -} - -GLContext Fl_Cocoa_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) { - GLContext context, shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - // resets the pile of string textures used to draw strings - // necessary before the first context is created - if (!shared_ctx) gl_texture_reset(); - context = create_GLcontext_for_window(((Fl_Cocoa_Gl_Choice*)g)->pixelformat, (NSOpenGLContext*)shared_ctx, window); - if (!context) return 0; - add_context(context); - [(NSOpenGLContext*)context makeCurrentContext]; - glClearColor(0., 0., 0., 1.); - apply_scissor(); - return (context); -} - -void Fl_Cocoa_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - if (context != current_context || w != cached_window) { - cached_window = w; - [(NSOpenGLContext*)context makeCurrentContext]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::delete_gl_context(GLContext context) { - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - if (current_context == context) { - cached_window = 0; - [current_context clearDrawable]; - } - [(NSOpenGLContext*)context release]; - del_context(context); - if (gl1ctxt) { - [[gl1ctxt view] release]; - [gl1ctxt release]; - gl1ctxt = 0; - } -} - -void Fl_Cocoa_Gl_Window_Driver::make_overlay_current() { - // this is not very useful, but unfortunately, Apple decided - // that front buffer drawing can no longer (OS X 10.4) be supported on their platforms. - if (pWindow->shown()) pWindow->make_current(); -} - -void Fl_Cocoa_Gl_Window_Driver::redraw_overlay() { - pWindow->redraw(); -} - -void Fl_Cocoa_Gl_Window_Driver::before_show(int& need_after) { - need_after = 1; -} - -void Fl_Cocoa_Gl_Window_Driver::after_show() { - // Makes sure the GL context is created to avoid drawing twice the window when first shown - pWindow->make_current(); - if ((mode() & FL_OPENGL3) && !gl1ctxt) { - // Create transparent GL1 scene above the GL3 scene to hold child widgets and/or text - NSView *view = [fl_mac_xid(pWindow) contentView]; - NSView *gl1view = [[NSView alloc] initWithFrame:[view frame]]; - [gl1view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - static NSOpenGLContext *shared_gl1_ctxt = nil; - static NSOpenGLPixelFormat *gl1pixelformat = mode_to_NSOpenGLPixelFormat( - FL_RGB8 | FL_ALPHA | FL_SINGLE, NULL); - gl1ctxt = [[NSOpenGLContext alloc] initWithFormat:gl1pixelformat shareContext:shared_gl1_ctxt]; - if (!shared_gl1_ctxt) { - shared_gl1_ctxt = gl1ctxt; - [shared_gl1_ctxt retain]; - } - [view addSubview:gl1view]; - if (Fl::use_high_res_GL()) { - [gl1view setWantsBestResolutionOpenGLSurface:YES]; - } - [gl1ctxt setView:gl1view]; - remove_gl_context_opacity(gl1ctxt); - } -} - -float Fl_Cocoa_Gl_Window_Driver::pixels_per_unit() -{ - int retina = (Fl::use_high_res_GL() && Fl_X::flx(pWindow) && - Fl_Cocoa_Window_Driver::driver(pWindow)->mapped_to_retina()) ? 2 : 1; - return retina * Fl_Graphics_Driver::default_driver().scale(); -} - -int Fl_Cocoa_Gl_Window_Driver::mode_(int m, const int *a) { - if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, - // the FL_DOUBLE flag must be set in the mode_ member variable - const int *aa = a; - while (*aa) { - if (*(aa++) == - kCGLPFADoubleBuffer - ) { m |= FL_DOUBLE; break; } - } - } - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - pWindow->redraw(); - } else { - g(0); - } - return 1; -} - -void Fl_Cocoa_Gl_Window_Driver::make_current_before() { - // detect if the window was moved between low and high resolution displays - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(pWindow); - if (d->changed_resolution()){ - d->changed_resolution(false); - pWindow->invalidate(); - [(NSOpenGLContext*)pWindow->context() update]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::swap_buffers() { - if (overlay() != NULL) { - // STR# 2944 [1] - // Save matrixmode/proj/modelview/rasterpos before doing overlay. - // - int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); - GLint matrixmode; - GLfloat pos[4]; - glGetIntegerv(GL_MATRIX_MODE, &matrixmode); - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos - glMatrixMode(GL_PROJECTION); // save proj/model matrices - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(2.0f/wo, 2.0f/ho, 1.0f); - glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window - glRasterPos2i(0,0); // set glRasterPos to bottom left corner - { - // Emulate overlay by doing copypixels - glReadBuffer(GL_BACK); - glDrawBuffer(GL_FRONT); - glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT - } - glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(matrixmode); - glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos - } else { - [(NSOpenGLContext*)pWindow->context() flushBuffer]; - } -} - -char Fl_Cocoa_Gl_Window_Driver::swap_type() {return copy;} - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -# define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval -#endif - -void Fl_Cocoa_Gl_Window_Driver::swap_interval(int n) { - GLint interval = (GLint)n; - NSOpenGLContext* ctx = (NSOpenGLContext*)pWindow->context(); - if (ctx) - [ctx setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; -} - -int Fl_Cocoa_Gl_Window_Driver::swap_interval() const { - GLint interval = (GLint)-1; - NSOpenGLContext* ctx = (NSOpenGLContext*)pWindow->context(); - if (ctx) - [ctx getValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; - return interval; -} - -void Fl_Cocoa_Gl_Window_Driver::resize(int is_a_resize, int w, int h) { - if (pWindow->shown()) apply_scissor(); - [(NSOpenGLContext*)pWindow->context() update]; - if (gl1ctxt) { - [gl1ctxt update]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::apply_scissor() { - if (glIsEnabled(GL_SCISSOR_TEST)) glDisable(GL_SCISSOR_TEST); - CGRect *extents = Fl_Cocoa_Window_Driver::driver(pWindow)->subRect(); - if (extents) { - remove_gl_context_opacity((NSOpenGLContext*)pWindow->context()); - GLdouble vals[4]; - glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(vals[0], vals[1], vals[2], vals[3]); - float s = pWindow->pixels_per_unit(); - glScissor(s*extents->origin.x, s*extents->origin.y, s*extents->size.width, s*extents->size.height); -//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - glEnable(GL_SCISSOR_TEST); - } -} - - -/* Some old Apple hardware doesn't implement the GL_EXT_texture_rectangle extension. - For it, draw_string_legacy_glut() is used to draw text. */ - -char *Fl_Cocoa_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) -{ - // write str to a bitmap just big enough - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Font f=fl_font(); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); - fl_font(f, fs); - fl_draw(str, n, 0, fl_height() - fl_descent()); - // get the alpha channel only of the bitmap - char *alpha_buf = new char[w*h], *r = alpha_buf, *q; - q = (char*)CGBitmapContextGetData((CGContextRef)surf->offscreen()); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - *r++ = *(q+3); - q += 4; - } - } - Fl_Surface_Device::pop_current(); - delete surf; - return alpha_buf; -} - -void Fl_Cocoa_Gl_Window_Driver::gl_start() { - [(NSOpenGLContext*)gl_start_context update]; -} - -// convert BGRA to RGB and also exchange top and bottom -static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) -{ - uchar *newimg = new uchar[3*w*h]; - uchar *to = newimg; - for (int i = h-1; i >= 0; i--) { - uchar *from = baseAddress + i * mByteWidth; - for (int j = 0; j < w; j++, from += 4) { -#if defined(__ppc__) && __ppc__ - memcpy(to, from + 1, 3); - to += 3; -#else - *(to++) = *(from+2); - *(to++) = *(from+1); - *(to++) = *from; -#endif - } - } - delete[] baseAddress; - return newimg; -} - - -static Fl_RGB_Image *cgimage_to_rgb4(CGImageRef img) { - int w = (int)CGImageGetWidth(img); - int h = (int)CGImageGetHeight(img); - CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - uchar *rgba = new uchar[4 * w * h]; - CGContextRef auxgc = CGBitmapContextCreate(rgba, w, h, 8, 4 * w, cspace, - kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(cspace); - CGContextDrawImage(auxgc, CGRectMake(0, 0, w, h), img); - CGContextRelease(auxgc); - Fl_RGB_Image *rgb = new Fl_RGB_Image(rgba, w, h, 4); - rgb->alloc_array = 1; - return rgb; -} - - -Fl_RGB_Image* Fl_Cocoa_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) -{ - Fl_Gl_Window* glw = pWindow; - float factor = glw->pixels_per_unit(); - if (factor != 1) { - w *= factor; h *= factor; x *= factor; y *= factor; - } - NSWindow *nswin = (NSWindow*)fl_mac_xid(pWindow); - CGImageRef img_full = Fl_Cocoa_Window_Driver::capture_decorated_window_10_5(nswin); - int bt = [nswin frame].size.height - [[nswin contentView] frame].size.height; - bt *= (factor / Fl_Graphics_Driver::default_driver().scale()); - CGRect cgr = CGRectMake(x, y + bt, w, h); // add vertical offset to bypass titlebar - CGImageRef cgimg = CGImageCreateWithImageInRect(img_full, cgr); // 10.4 - CGImageRelease(img_full); - Fl_RGB_Image *rgb = cgimage_to_rgb4(cgimg); - CGImageRelease(cgimg); - return rgb; - [(NSOpenGLContext*)glw->context() makeCurrentContext]; - // to capture also the overlay and for directGL demo - [(NSOpenGLContext*)glw->context() flushBuffer]; - // Read OpenGL context pixels directly. - // For extra safety, save & restore OpenGL states that are changed - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ - glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - // Read a block of pixels from the frame buffer - int mByteWidth = w * 4; - mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes - uchar *baseAddress = new uchar[mByteWidth * h]; - glReadPixels(x, glw->pixel_h() - (y+h), w, h, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); - glPopClientAttrib(); - baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); - Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); - img->alloc_array = 1; - [(NSOpenGLContext*)glw->context() flushBuffer]; - return img; -} - - -void* Fl_Cocoa_Gl_Window_Driver::GetProcAddress(const char *procName) { - return dlsym(RTLD_DEFAULT, procName); -} - - -FL_EXPORT NSOpenGLContext *fl_mac_glcontext(GLContext rc) { - return (NSOpenGLContext*)rc; -} - - -void Fl_Cocoa_Gl_Window_Driver::switch_to_GL1() { - [gl1ctxt makeCurrentContext]; - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); -} - - -void Fl_Cocoa_Gl_Window_Driver::switch_back() { - glFlush(); - [(NSOpenGLContext*)pWindow->context() makeCurrentContext]; -} - - -class Fl_Gl_Cocoa_Plugin : public Fl_Cocoa_Plugin { -public: - Fl_Gl_Cocoa_Plugin() : Fl_Cocoa_Plugin(name()) { } - const char *name() FL_OVERRIDE { return "gl.cocoa.fltk.org"; } - void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) FL_OVERRIDE { - glw->Fl_Gl_Window::resize(x, y, w, h); - } -}; - -static Fl_Gl_Cocoa_Plugin Gl_Cocoa_Plugin; - -#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm b/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm deleted file mode 100644 index 9c75c7ff2..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm +++ /dev/null @@ -1,439 +0,0 @@ -// -// Definition of macOS Cocoa Pen/Tablet event driver. -// -// Copyright 2025-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "src/drivers/Base/Fl_Base_Pen_Events.H" - -#include <FL/platform.H> -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include "../../Fl_Screen_Driver.H" - -#import <Cocoa/Cocoa.h> - - -extern Fl_Window *fl_xmousewin; - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 - -typedef short NSEventSubtype; -#define NSPointingDeviceTypePen NSPenPointingDevice -#define NSEventTypeMouseEntered NSMouseEntered -#define NSEventTypeMouseExited NSMouseExited -#define NSEventTypeTabletProximity NSTabletProximity -#define NSEventTypeTabletPoint NSTabletPoint -#define NSEventSubtypeTabletProximity NSTabletProximityEventSubtype -#define NSEventSubtypeTabletPoint NSTabletPointEventSubtype -#define NSEventSubtypeMouseEvent NSMouseEventSubtype -#define NSEventTypeLeftMouseDown NSLeftMouseDown -#define NSEventTypeLeftMouseUp NSLeftMouseUp -#define NSEventTypeLeftMouseDragged NSLeftMouseDragged -#define NSEventTypeMouseMoved NSMouseMoved -#define NSEventTypeRightMouseDown NSRightMouseDown -#define NSEventTypeRightMouseUp NSRightMouseUp -#define NSEventTypeRightMouseDragged NSRightMouseDragged -#define NSEventTypeOtherMouseUp NSOtherMouseUp -#define NSEventTypeOtherMouseDown NSOtherMouseDown -#define NSEventTypeOtherMouseDragged NSOtherMouseDragged -#define NSPointingDeviceTypeEraser NSEraserPointingDevice - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 - -static NSPointingDeviceType device_type_ { NSPointingDeviceTypePen }; - -// The trait list keeps track of traits for every pen ID that appears while -// handling events. -// AppKit does not tell us what traits are available per pen or tablet, so -// we use the first 5 motion events to discover event values that are not -// the default value, and enter that knowledge into the traits database. -typedef std::map<int, Fl::Pen::Trait> TraitList; -static TraitList trait_list_; -static int trait_countdown_ { 5 }; -static int current_pen_id_ { -1 }; -static Fl::Pen::Trait current_pen_trait_ { Fl::Pen::Trait::DRIVER_AVAILABLE }; -static Fl::Pen::Trait driver_traits_ { - Fl::Pen::Trait::DRIVER_AVAILABLE | Fl::Pen::Trait::PEN_ID | - Fl::Pen::Trait::ERASER | Fl::Pen::Trait::PRESSURE | - Fl::Pen::Trait::BARREL_PRESSURE | Fl::Pen::Trait::TILT_X | - Fl::Pen::Trait::TILT_Y | Fl::Pen::Trait::TWIST - // Notably missing: PROXIMITY -}; - -// Temporary storage of event data for the driver; -static Fl::Pen::EventData ev; - - -namespace Fl { - -namespace Private { - -// Global mouse position at mouse down event -extern int e_x_down; -extern int e_y_down; - -}; // namespace Private - -namespace Pen { - -class Cocoa_Driver : public Driver { -public: - Cocoa_Driver() = default; - //virtual void subscribe(Fl_Widget* widget) override; - //virtual void unsubscribe(Fl_Widget* widget) override; - //virtual void release() override; - virtual Trait traits() override { return driver_traits_; } - virtual Trait pen_traits(int pen_id) override { - auto it = trait_list_.find(pen_id); - if (pen_id == 0) - return current_pen_trait_; - if (it == trait_list_.end()) { - return Trait::DRIVER_AVAILABLE; - } else { - return it->second; - } - } -}; - -Cocoa_Driver cocoa_driver; -Driver& driver = cocoa_driver; - -} // namespace Pen - -} // namespace Fl - - -using namespace Fl::Pen; - - -/* - Copy the event state. - */ -static void copy_state() { - Fl::Pen::State tr = (Fl::Pen::State)((uint32_t)Fl::Pen::e.state ^ (uint32_t)ev.state); - Fl::Pen::e = ev; - Fl::Pen::e.trigger = tr; - Fl::e_x = (int)ev.x; - Fl::e_y = (int)ev.y; - Fl::e_x_root = (int)ev.rx; - Fl::e_y_root = (int)ev.ry; -} - -/* - Offset coordinates for subwindows and subsubwindows. - */ -static void offset_subwindow_event(Fl_Widget *w, double &x, double &y) { - Fl_Widget *p = w, *q; - while (p) { - q = p->parent(); - if (p->as_window() && q) { - x -= p->x(); - y -= p->y(); - } - p = q; - }; -} - -/* - Check if coordinates are within the widget box. - Coordinates are in top_window space. We iterate up the hierarchy to ensure - that we handle subwindows correctly. - */ -static bool event_inside(Fl_Widget *w, double x, double y) { - offset_subwindow_event(w, x, y); - if (w->as_window()) { - return ((x >= 0) && (y >= 0) && (x < w->w()) && (y < w->h())); - } else { - return ((x >= w->x()) && (y >= w->y()) && (x < w->x() + w->w()) && (y < w->y() + w->h())); - } -} - -/* - Find the widget under the pen event. - Search the subscriber list for widgets that are inside the same top window, - are visible, and are within the give coordinates. Subwindow aware. - */ -static Fl_Widget *find_below_pen(Fl_Window *win, double x, double y) { - for (auto &sub: subscriber_list_) { - Fl_Widget *candidate = sub.second->widget(); - if (candidate && (candidate->top_window() == win)) { - if (candidate->visible() && event_inside(candidate, x, y)) { - return candidate; - } - } - } - return nullptr; -} - -/* - Send the current event and event data to a widget. - Note: we will get the wrong coordinates if the widget is not a child of - the current event window (LEAVE events between windows). - */ -static int pen_send(Fl_Widget *w, int event, State trigger, bool &copied) { - // Copy most event data only once - if (!copied) { - copy_state(); - copied = true; - } - // Copy the top_window coordinates again as they may change when w changes - e.x = ev.x; - e.y = ev.y; - offset_subwindow_event(w, e.x, e.y); - Fl::e_x = e.x; - Fl::e_y = e.y; - // Send the event. - e.trigger = trigger; - return w->handle(event); -} - -/* - Send an event to all subscribers. - */ -static int pen_send_all(int event, State trigger) { - bool copied = false; - // use local value because handler may still change ev values - for (auto &it: subscriber_list_) { - auto w = it.second->widget(); - if (w) - pen_send(w, event, trigger, copied); - } - return 1; -} - -/* - Convert the NSEvent button number to Fl::Pen::State, - */ -static State button_to_trigger(NSInteger button, bool down) { - switch (button) { - case 0: - if ( (ev.state & (State::ERASER_DOWN | State::ERASER_HOVERS)) != State::NONE ) { - return down ? State::ERASER_DOWN : State::ERASER_HOVERS; - } else { - return down ? State::TIP_DOWN : State::TIP_HOVERS; - } - case 1: return State::BUTTON0; - case 2: return State::BUTTON1; - case 3: return State::BUTTON2; - case 4: return State::BUTTON3; - default: return State::NONE; - } -} - -/* - Handle events coming from Cocoa. - `capabilityMask` is useless, because it is vendor defined - If a modal window is open, AppKit will send window specific events only there. - */ -bool fl_cocoa_tablet_handler(NSEvent *event, Fl_Window *eventWindow) { - // Quick access to the main type. - auto type = [event type]; - - // There seems nothing useful here. Ignore for now. - if ((type == NSEventTypeMouseEntered) || (type == NSEventTypeMouseExited)) { - return false; - } - - // Sort out tablet-only events and mouse plus tablet events. - bool is_mouse = ((type != NSEventTypeTabletPoint) && (type != NSEventTypeTabletProximity)); - - // Set the subtype if one is available. Only NSEventSubtypeTabletPoint and - // NSEventSubtypeTabletProximity matter in this context - NSEventSubtype subtype = is_mouse ? [event subtype] : NSEventSubtypeMouseEvent; - - // Is this a change in proximity event? - bool is_proximity = ((type == NSEventTypeTabletProximity) || (subtype == NSEventSubtypeTabletProximity)); - - // Is this a pen pointer event? - bool is_point = ((type == NSEventTypeTabletPoint) || (subtype == NSEventSubtypeTabletPoint)); - - // Check if any of the pen down, move, drag, or up events was triggered. - bool is_down = ((type == NSEventTypeLeftMouseDown) || (type == NSEventTypeRightMouseDown) || (type == NSEventTypeOtherMouseDown)); - bool is_up = ((type == NSEventTypeLeftMouseUp) || (type == NSEventTypeRightMouseUp) || (type == NSEventTypeOtherMouseUp)); - bool is_drag = ((type == NSEventTypeLeftMouseDragged) || (type == NSEventTypeRightMouseDragged) || (type == NSEventTypeOtherMouseDragged)); - bool is_motion = is_drag || (type == NSEventTypeMouseMoved); - - // Find out if we can get the pen position - bool has_position = (eventWindow != nullptr) && (is_up || is_down || is_motion || is_proximity || is_point); - - // Event has extended pen data set: - if (has_position) { - // Get the position data. - auto pt = [event locationInWindow]; - double s = Fl::screen_driver()->scale(0); - ev.x = pt.x/s; - ev.y = eventWindow->h() - pt.y/s; - ev.rx = ev.x + eventWindow->x(); - ev.ry = ev.y + eventWindow->y(); - if (!is_proximity) { - // Get the pressure data. - ev.pressure = [event pressure]; - ev.barrel_pressure = [event tangentialPressure]; - // Get the tilt - auto tilt = [event tilt]; - ev.tilt_x = -tilt.x; - ev.tilt_y = tilt.y; - // Other stuff - ev.twist = [event rotation]; // TODO: untested - // ev.proximity = [event proximity]; // not supported in AppKit - } - if (device_type_ == NSPointingDeviceTypeEraser) { - if ([event buttonMask] & 1) - ev.state = State::ERASER_DOWN; - else - ev.state = State::ERASER_HOVERS; - } else { - if ([event buttonMask] & 1) - ev.state = State::TIP_DOWN; - else - ev.state = State::TIP_HOVERS; - } - if ([event buttonMask] & 0x0002) ev.state |= State::BUTTON0; - if ([event buttonMask] & 0x0004) ev.state |= State::BUTTON1; - if ([event buttonMask] & 0x0008) ev.state |= State::BUTTON2; - if ([event buttonMask] & 0x0010) ev.state |= State::BUTTON3; - // printf("0x%08x\n", [event buttonMask]); - } - if (is_proximity) { - ev.pen_id = (int)[event vendorID]; - device_type_ = [event pointingDeviceType]; - } - if (type == NSEventTypeTabletProximity) { - if ([event isEnteringProximity]) { - // Check if this is the first time we see this pen, or if the pen changed - if (current_pen_id_ != ev.pen_id) { - current_pen_id_ = ev.pen_id; - auto it = trait_list_.find(current_pen_id_); - if (it == trait_list_.end()) { // not found, create a new entry - trait_list_[current_pen_id_] = Trait::DRIVER_AVAILABLE; - trait_countdown_ = 5; - pen_send_all(Fl::Pen::DETECTED, State::NONE); - // printf("IN RANGE, NEW PEN\n"); - } else { - pen_send_all(Fl::Pen::CHANGED, State::NONE); - // printf("IN RANGE, CHANGED PEN\n"); - } - trait_list_[0] = trait_list_[current_pen_id_]; // set current pen traits - } else { - pen_send_all(Fl::Pen::IN_RANGE, State::NONE); - // printf("IN RANGE\n"); - } - } else { - pen_send_all(Fl::Pen::OUT_OF_RANGE, State::NONE); - // printf("OUT OF RANGE\n"); - } - } - - Fl_Widget *receiver = nullptr; - bool pushed = false; - bool event_data_copied = false; - - if (has_position) { - if (trait_countdown_) { - trait_countdown_--; - if (ev.tilt_x != 0.0) current_pen_trait_ |= Trait::TILT_X; - if (ev.tilt_y != 0.0) current_pen_trait_ |= Trait::TILT_Y; - if (ev.pressure != 1.0) current_pen_trait_ |= Trait::PRESSURE; - if (ev.barrel_pressure != 0.0) current_pen_trait_ |= Trait::BARREL_PRESSURE; - if (ev.pen_id != 0) current_pen_trait_ |= Trait::PEN_ID; - if (ev.twist != 0.0) current_pen_trait_ |= Trait::TWIST; - //if (ev.proximity != 0) current_pen_trait_ |= Trait::PROXIMITY; - trait_list_[current_pen_id_] = current_pen_trait_; - } - fl_xmousewin = eventWindow; - if (pushed_ && pushed_->widget() && (Fl::pushed() == pushed_->widget())) { - receiver = pushed_->widget(); - if (Fl::grab() && (Fl::grab() != receiver->top_window())) - return 0; - if (Fl::modal() && (Fl::modal() != receiver->top_window())) - return 0; - pushed = true; - } else { - if (Fl::grab() && (Fl::grab() != eventWindow)) - return 0; - if (Fl::modal() && (Fl::modal() != eventWindow)) - return 0; - auto bpen = below_pen_ ? below_pen_->widget() : nullptr; - auto bmouse = Fl::belowmouse(); - auto bpen_old = bmouse && (bmouse == bpen) ? bpen : nullptr; - auto bpen_now = find_below_pen(eventWindow, ev.x, ev.y); - - if (bpen_now != bpen_old) { - if (bpen_old) { - pen_send(bpen_old, Fl::Pen::LEAVE, State::NONE, event_data_copied); - } - below_pen_ = nullptr; - if (bpen_now) { - State state = (device_type_ == NSPointingDeviceTypeEraser) ? State::ERASER_HOVERS : State::TIP_HOVERS; - if (pen_send(bpen_now, Fl::Pen::ENTER, state, event_data_copied)) { - below_pen_ = subscriber_list_[bpen_now]; - Fl::belowmouse(bpen_now); - } - } - } - - receiver = below_pen_ ? below_pen_->widget() : nullptr; - if (!receiver) - return 0; - } - } else { - // Proximity events were handled earlier. - } - - if (!receiver) - return 0; - - if (is_down) { - if (!pushed) { - pushed_ = subscriber_list_[receiver]; - Fl::pushed(receiver); - } - State trigger = button_to_trigger([event buttonNumber], true); - if ([event buttonNumber] == 0) { - Fl::e_is_click = 1; - Fl::Private::e_x_down = (int)ev.x; - Fl::Private::e_y_down = (int)ev.y; - if ([event clickCount] > 1) - Fl::e_clicks++; - else - Fl::e_clicks = 0; - pen_send(receiver, Fl::Pen::TOUCH, trigger, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::BUTTON_PUSH, trigger, event_data_copied); - } - } else if (is_up) { - if ( (ev.state & State::ANY_DOWN) == State::NONE ) { - Fl::pushed(nullptr); - pushed_ = nullptr; - } - State trigger = button_to_trigger([event buttonNumber], true); - if ([event buttonNumber] == 0) - pen_send(receiver, Fl::Pen::LIFT, trigger, event_data_copied); - else - pen_send(receiver, Fl::Pen::BUTTON_RELEASE, trigger, event_data_copied); - } else if (is_motion) { - if ( Fl::e_is_click && - ( (fabs((int)ev.x - Fl::Private::e_x_down) > 5) || - (fabs((int)ev.y - Fl::Private::e_y_down) > 5) ) ) - Fl::e_is_click = 0; - if (pushed) { - pen_send(receiver, Fl::Pen::DRAW, State::NONE, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::HOVER, State::NONE, event_data_copied); - } - } - // Always return 1 because at this point, we capture pen events and don't - // want mouse events anymore! - return 1; -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm b/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm deleted file mode 100644 index a40f1feb4..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm +++ /dev/null @@ -1,455 +0,0 @@ -// -// Mac OS X-specific printing support (objective-c++) for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/Fl_Paged_Device.H> -#include <FL/Fl_Printer.H> -#include "../../Fl_Window_Driver.H" -#include "../../Fl_Screen_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include <FL/Fl_PDF_File_Surface.H> -#include "Fl_Cocoa_Window_Driver.H" - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_ask.H> -#include <FL/fl_draw.H> -#include <FL/fl_string_functions.h> -#import <Cocoa/Cocoa.h> - -typedef OSStatus (*PMSessionSetDocumentFormatGeneration_type)( - PMPrintSession printSession, - CFStringRef docFormat, - CFArrayRef graphicsContextTypes, - CFTypeRef options); -typedef OSStatus (*PMSessionBeginDocumentNoDialog_type)( - PMPrintSession printSession, - PMPrintSettings printSettings, - PMPageFormat pageFormat); -typedef OSStatus -(*PMSessionGetGraphicsContext_type)( - PMPrintSession printSession, - CFStringRef graphicsContextType, - void ** graphicsContext); - - -/** Support for printing on the Apple OS X platform */ -class Fl_Cocoa_Printer_Driver : public Fl_Paged_Device { - friend class Fl_Printer; -protected: - float scale_x; - float scale_y; - float angle; // rotation angle in radians - PMPrintSession printSession; - PMPageFormat pageFormat; - PMPrintSettings printSettings; - Fl_Cocoa_Printer_Driver(void); - int begin_job(int pagecount = 0, int *frompage = NULL, int *topage = NULL, char **perr_message = NULL) FL_OVERRIDE; - int begin_page (void) FL_OVERRIDE; - int printable_rect(int *w, int *h) FL_OVERRIDE; - void margins(int *left, int *top, int *right, int *bottom) FL_OVERRIDE; - void origin(int *x, int *y) FL_OVERRIDE; - void origin(int x, int y) FL_OVERRIDE; - void scale (float scale_x, float scale_y = 0.) FL_OVERRIDE; - void rotate(float angle) FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate(void) FL_OVERRIDE; - int end_page (void) FL_OVERRIDE; - void end_job (void) FL_OVERRIDE; - ~Fl_Cocoa_Printer_Driver(void); -}; - - -Fl_Cocoa_Printer_Driver::Fl_Cocoa_Printer_Driver(void) -{ - x_offset = 0; - y_offset = 0; - scale_x = scale_y = 1.; - driver(new Fl_Quartz_Printer_Graphics_Driver); -} - -Fl_Paged_Device* Fl_Printer::newPrinterDriver(void) -{ - return new Fl_Cocoa_Printer_Driver(); -} - -Fl_Cocoa_Printer_Driver::~Fl_Cocoa_Printer_Driver(void) { - delete driver(); -} - -@interface print_panel_delegate : NSObject -- (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(NSInteger)returnCode contextInfo:(NSInteger *)contextInfo; -@end -@implementation print_panel_delegate -- (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(NSInteger)returnCode contextInfo:(NSInteger *)contextInfo -{ - *contextInfo = returnCode; -} -@end - -int Fl_Cocoa_Printer_Driver::begin_job (int pagecount, int *frompage, int *topage, char **perr_message) -//printing using a Quartz graphics context -//returns 0 iff OK -{ - OSStatus status = 0; - fl_open_display(); - Fl_Cocoa_Window_Driver::q_release_context(); - NSPrintInfo *info = [NSPrintInfo sharedPrintInfo]; - NSPrintPanel *panel = [NSPrintPanel printPanel]; - //from 10.5 - [panel setOptions:NSPrintPanelShowsCopies | NSPrintPanelShowsPageRange | - NSPrintPanelShowsPageSetupAccessory | NSPrintPanelShowsOrientation | NSPrintPanelShowsPaperSize]; - NSInteger retval = -1; - Fl_Window *top = Fl::first_window(); - NSWindow *main = (top ? (NSWindow*)fl_xid(top->top_window()) : nil); - if (main) { - [panel beginSheetWithPrintInfo:info - modalForWindow:main - delegate:[[[print_panel_delegate alloc] init] autorelease] - didEndSelector:@selector(printPanelDidEnd:returnCode:contextInfo:) - contextInfo:&retval]; - while (retval < 0) Fl::wait(100); - [main makeKeyAndOrderFront:nil]; - } else { - retval = [panel runModalWithPrintInfo:info]; //from 10.5 - } -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 - const NSInteger NSModalResponseOK = NSOKButton; -#endif - if (retval != NSModalResponseOK) return 1; - printSession = (PMPrintSession)[info PMPrintSession]; //from 10.5 - pageFormat = (PMPageFormat)[info PMPageFormat]; //from 10.5 - printSettings = (PMPrintSettings)[info PMPrintSettings];//from 10.5 - UInt32 from32, to32; - PMGetFirstPage(printSettings, &from32); - if (frompage) *frompage = (int)from32; - PMGetLastPage(printSettings, &to32); - if (topage) { - *topage = (int)to32; - if (*topage > pagecount && pagecount > 0) *topage = pagecount; - } - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 - - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - return 2; - } - y_offset = x_offset = 0; - return 0; -} - -void Fl_Cocoa_Printer_Driver::margins(int *left, int *top, int *right, int *bottom) -{ - PMPaper paper; - PMGetPageFormatPaper(pageFormat, &paper); - PMOrientation orientation; - PMGetOrientation(pageFormat, &orientation); - PMPaperMargins margins; - PMPaperGetMargins(paper, &margins); - if(orientation == kPMPortrait) { - if (left) *left = (int)(margins.left / scale_x + 0.5); - if (top) *top = (int)(margins.top / scale_y + 0.5); - if (right) *right = (int)(margins.right / scale_x + 0.5); - if (bottom) *bottom = (int)(margins.bottom / scale_y + 0.5); - } else { - if (left) *left = (int)(margins.top / scale_x + 0.5); - if (top) *top = (int)(margins.left / scale_y + 0.5); - if (right) *right = (int)(margins.bottom / scale_x + 0.5); - if (bottom) *bottom = (int)(margins.right / scale_y + 0.5); - } -} - -int Fl_Cocoa_Printer_Driver::printable_rect(int *w, int *h) -//returns 0 iff OK -{ - OSStatus status; - PMRect pmRect; - int x, y; - - status = PMGetAdjustedPageRect(pageFormat, &pmRect); - if (status != noErr) return 1; - - x = (int)pmRect.left; - y = (int)pmRect.top; - *w = int((int)(pmRect.right - x) / scale_x + 1); - *h = int((int)(pmRect.bottom - y) / scale_y + 1); - return 0; -} - -void Fl_Cocoa_Printer_Driver::origin(int x, int y) -{ - x_offset = x; - y_offset = y; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextTranslateCTM(gc, x, y); - CGContextRotateCTM(gc, angle); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::scale (float s_x, float s_y) -{ - if (s_y == 0.) s_y = s_x; - scale_x = s_x; - scale_y = s_y; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextRotateCTM(gc, angle); - x_offset = y_offset = 0; - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::rotate (float rot_angle) -{ - angle = - rot_angle * M_PI / 180.; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextTranslateCTM(gc, x_offset, y_offset); - CGContextRotateCTM(gc, angle); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::translate(int x, int y) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, x, y ); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::untranslate(void) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); -} - -int Fl_Cocoa_Printer_Driver::begin_page (void) -{ - OSStatus status = PMSessionBeginPageNoDialog(printSession, pageFormat, NULL); - CGContextRef gc; - status = PMSessionGetCGGraphicsContext(printSession, &gc); // 10.4 - driver()->gc(gc); - Fl_Surface_Device::push_current(this); - PMRect pmRect; - float win_scale_x, win_scale_y; - - PMPaper paper; - PMGetPageFormatPaper(pageFormat, &paper); - PMPaperMargins margins; - PMPaperGetMargins(paper, &margins); - PMOrientation orientation; - PMGetOrientation(pageFormat, &orientation); - - status = PMGetAdjustedPageRect(pageFormat, &pmRect); - double h = pmRect.bottom - pmRect.top; - x_offset = 0; - y_offset = 0; - angle = 0; - scale_x = scale_y = 1; - win_scale_x = win_scale_y = 1; - if(orientation == kPMPortrait) - CGContextTranslateCTM(gc, margins.left, margins.bottom + h); - else - CGContextTranslateCTM(gc, margins.top, margins.right + h); - CGContextScaleCTM(gc, win_scale_x, - win_scale_y); - ((Fl_Quartz_Graphics_Driver*)driver())->quartz_restore_line_style(); - CGContextSetShouldAntialias(gc, false); - CGContextSaveGState(gc); - CGContextSaveGState(gc); - fl_line_style(FL_SOLID); - fl_window = (FLWindow*)1; // TODO: something better - fl_clip_region(0); - return status != noErr; -} - -int Fl_Cocoa_Printer_Driver::end_page (void) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextFlush(gc); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - OSStatus status = PMSessionEndPageNoDialog(printSession); - gc = NULL; - Fl_Surface_Device::pop_current(); - return status != noErr; -} - -void Fl_Cocoa_Printer_Driver::end_job (void) -{ - OSStatus status; - - status = PMSessionError(printSession); - if (status != noErr) { - fl_alert ("PM Session error %d", (int)status); - } - PMSessionEndDocumentNoDialog(printSession); - Fl_Window *w = Fl::first_window(); - if (w) w->show(); -} - -void Fl_Cocoa_Printer_Driver::origin(int *x, int *y) -{ - Fl_Paged_Device::origin(x, y); -} - - -class Fl_PDF_Cocoa_File_Surface : public Fl_Cocoa_Printer_Driver -{ -public: - char *doc_fname; - Fl_PDF_Cocoa_File_Surface(); - ~Fl_PDF_Cocoa_File_Surface() { if (doc_fname) free(doc_fname); } - int begin_job(const char *defaultname, - char **perr_message = NULL); - int begin_job(int, int*, int *, char **) FL_OVERRIDE {return 1;} // don't use - int begin_document(const char* outname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message); -}; - - -Fl_PDF_Cocoa_File_Surface::Fl_PDF_Cocoa_File_Surface() { - driver(new Fl_Quartz_Graphics_Driver()); - doc_fname = NULL; -} - - -int Fl_PDF_Cocoa_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - OSStatus status = 0; - if (fl_mac_os_version < 100900) return 1; - Fl_Window *top = Fl::first_window(); - NSWindow *main = (top ? (NSWindow*)fl_xid(top->top_window()) : nil); - if (!main) return 1; - Fl_Cocoa_Window_Driver::q_release_context(); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 && defined(__BLOCKS__) - NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9 - NSPDFPanel *pdf_panel = [NSPDFPanel panel]; // 10.9 - char buf[FL_PATH_MAX]; - strcpy(buf, defaultfilename); - fl_filename_setext(buf, sizeof(buf), NULL); - [pdf_panel setDefaultFileName:[NSString stringWithUTF8String:buf]]; - [pdf_panel setOptions: NSPrintPanelShowsOrientation | NSPrintPanelShowsPaperSize]; - NSInteger retval = -1; - __block NSInteger complete = -1; - [pdf_panel beginSheetWithPDFInfo:pdf_info - modalForWindow:main - completionHandler:^(NSInteger returnCode) { - // this block runs after OK or Cancel was triggered in file dialog - complete = returnCode; - } - ]; - while (complete == -1) Fl::wait(100); // loop until end of file dialog - retval = complete; - [main makeKeyAndOrderFront:nil]; - if (retval != NSModalResponseOK) return 1; - NSURL *url = [pdf_info URL]; - doc_fname = fl_strdup([url fileSystemRepresentation]); - NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo]; - [pr_info takeSettingsFromPDFInfo:pdf_info]; - [pdf_info release]; - printSession = (PMPrintSession)[pr_info PMPrintSession]; - printSettings = (PMPrintSettings)[pr_info PMPrintSettings]; - pageFormat = (PMPageFormat)[pr_info PMPageFormat]; - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 -#endif - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - free(doc_fname); - doc_fname = NULL; - return 2; - } - y_offset = x_offset = 0; - return 0; -} - - -int Fl_PDF_Cocoa_File_Surface::begin_document(const char* outfname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - OSStatus status = 0; - fl_open_display(); - if (fl_mac_os_version < 100900) return 1; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 - NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9 - doc_fname = fl_strdup(outfname); - NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:doc_fname]]; - [pdf_info setURL:url]; - NSSize psize = {(CGFloat)Fl_Paged_Device::page_formats[format].width, (CGFloat)Fl_Paged_Device::page_formats[format].height}; - [pdf_info setPaperSize:psize]; - [pdf_info setOrientation:(layout == PORTRAIT ? NSPaperOrientationPortrait : NSPaperOrientationLandscape)]; - NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo]; - [pr_info takeSettingsFromPDFInfo:pdf_info]; - [pdf_info release]; - printSession = (PMPrintSession)[pr_info PMPrintSession]; - printSettings = (PMPrintSettings)[pr_info PMPrintSettings]; - pageFormat = (PMPageFormat)[pr_info PMPageFormat]; - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 -#endif - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - free(doc_fname); - doc_fname = NULL; - return 2; - } - y_offset = x_offset = 0; - return 0; -} - - -Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { - Fl_PDF_Cocoa_File_Surface *surf = new Fl_PDF_Cocoa_File_Surface(); - *pfname = (const char**)&surf->doc_fname; - return surf; -} - - -int Fl_PDF_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - return ((Fl_PDF_Cocoa_File_Surface*)platform_surface_)->begin_job(defaultfilename, perr_message); -} - - -int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - return ((Fl_PDF_Cocoa_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message); -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H deleted file mode 100644 index 9e3d2386a..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ /dev/null @@ -1,114 +0,0 @@ -// -// Definition of Apple Cocoa Screen interface -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Cocoa_Screen_Driver.H - \brief Definition of Apple Cocoa Screen interface. - */ - -#ifndef FL_COCOA_SCREEN_DRIVER_H -#define FL_COCOA_SCREEN_DRIVER_H - -#include "../../Fl_Screen_Driver.H" - -/* - Move everything here that manages the native screen interface. - - There is exactly one screen driver in the system. - - - screen configuration and sizes - - multiple screens - - native dialog boxes -*/ - - -class Fl_Window; -class Fl_Input; -class Fl_RGB_Image; -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif - -class Fl_Cocoa_Screen_Driver : public Fl_Screen_Driver -{ -protected: - struct XRectangle {int x, y, width, height;}; - XRectangle screens[MAX_SCREENS]; - float dpi_h[MAX_SCREENS]; - float dpi_v[MAX_SCREENS]; - static int insertion_point_x; - static int insertion_point_y; - static int insertion_point_height; - static bool insertion_point_location_is_valid; -public: - NSImage *default_icon; - Fl_Cocoa_Screen_Driver(); - static int next_marked_length; // next length of marked text after current marked text will have been replaced - static void breakMacEventLoop(); - // --- display management - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - // implemented in Fl_cocoa.mm because uses Objective-c - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - int has_marked_text() const FL_OVERRIDE; - static void reset_marked_text(); - static void insertion_point_location(int x, int y, int height); - static int insertion_point_location(int *px, int *py, int *pheight); - int dnd(int use_selection) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - int input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input) FL_OVERRIDE; - int get_mouse(int &x, int &y) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - // --- compute dimensions of an Fl_Offscreen - void offscreen_size(Fl_Offscreen o, int &width, int &height) FL_OVERRIDE; - - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { return SYSTEMWIDE_APP_SCALING; } - float scale(int /*nscreen*/) FL_OVERRIDE {return scale_;} - void scale(int /*nscreen*/, float f) FL_OVERRIDE { scale_ = f;} - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - void default_icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - int clipboard_contains(const char *type) FL_OVERRIDE; - void set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) FL_OVERRIDE; - void reset_spot() FL_OVERRIDE; - int need_menu_handle_part2() FL_OVERRIDE {return 1;} - // these 2 are in Fl_get_key_mac.cxx - int event_key(int) FL_OVERRIDE; - int get_key(int) FL_OVERRIDE; -private: - float scale_; -}; - - -#endif // FL_COCOA_SCREEN_DRIVER_H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx deleted file mode 100644 index 7eb98b291..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ /dev/null @@ -1,434 +0,0 @@ -// -// Definition of Apple Cocoa Screen interface. -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_Cocoa_Screen_Driver.H" -#include "Fl_Cocoa_Window_Driver.H" -#include "../Quartz/Fl_Font.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> -#include <FL/Fl_Input.H> -#include <FL/fl_ask.H> -#include <FL/Fl_Image_Surface.H> -#include <stdio.h> - - -extern "C" void NSBeep(void); -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); - -int Fl_Cocoa_Screen_Driver::next_marked_length = 0; - - -// This key table is used for the Darwin system driver. It is defined here -// "static" and assigned in the constructor to avoid static initialization -// race conditions. It is used in fl_shortcut.cxx. -// -// This table must be in numeric order by fltk (X) keysym number: - -Fl_Screen_Driver::Keyname darwin_key_table[] = { - // v - this column may contain UTF-8 characters - {' ', "Space"}, - {FL_BackSpace, "⌫"/*"\xe2\x8c\xab"*/}, // U+232B : erase to the left - {FL_Tab, "⇥"/*"\xe2\x87\xa5"*/}, // U+21E5 rightwards arrow to bar - {FL_Enter, "↩"/*"\xe2\x86\xa9"*/}, // U+21A9 leftwards arrow with hook - {FL_Pause, "Pause"}, - {FL_Scroll_Lock, "Scroll_Lock"}, - {FL_Escape, "⎋"/*"\xe2\x8e\x8b"*/}, // U+238B : broken circle with northwest arrow - {FL_Home, "↖"/*"\xe2\x86\x96"*/}, // U+2196 north west arrow - {FL_Left, "←"/*"\xe2\x86\x90"*/}, // U+2190 leftwards arrow - {FL_Up, "↑"/*"\xe2\x86\x91"*/}, // U+2191 upwards arrow - {FL_Right, "→"/*"\xe2\x86\x92"*/}, // U+2192 rightwards arrow - {FL_Down, "↓"/*"\xe2\x86\x93"*/}, // U+2193 downwards arrow - {FL_Page_Up, "⇞"/*"\xe2\x87\x9e"*/}, // U+21DE upwards arrow with double stroke - {FL_Page_Down, "⇟"/*"\xe2\x87\x9f"*/}, // U+21DF downwards arrow with double stroke - {FL_End, "↘"/*"\xe2\x86\x98"*/}, // U+2198 south east arrow - {FL_Print, "Print"}, - {FL_Insert, "Insert"}, - {FL_Menu, "Menu"}, - {FL_Num_Lock, "Num_Lock"}, - {FL_KP_Enter, "⌤"/*"\xe2\x8c\xa4"*/}, // U+2324 up arrow head between two horizontal bars - {FL_Shift_L, "Shift_L"}, - {FL_Shift_R, "Shift_R"}, - {FL_Control_L, "Control_L"}, - {FL_Control_R, "Control_R"}, - {FL_Caps_Lock, "⇪"/*"\xe2\x87\xaa"*/}, // U+21EA upwards white arrow from bar - {FL_Meta_L, "Meta_L"}, - {FL_Meta_R, "Meta_R"}, - {FL_Alt_L, "Alt_L"}, - {FL_Alt_R, "Alt_R"}, - {FL_Delete, "⌦"/*"\xe2\x8c\xa6"*/} // U+2326 : erase to the right -}; - - -static Fl_Text_Editor::Key_Binding extra_bindings[] = { - // Define CMD+key accelerators... - { 'z', FL_COMMAND, Fl_Text_Editor::kf_undo ,0}, - { 'z', FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_redo ,0}, - { 'x', FL_COMMAND, Fl_Text_Editor::kf_cut ,0}, - { 'c', FL_COMMAND, Fl_Text_Editor::kf_copy ,0}, - { 'v', FL_COMMAND, Fl_Text_Editor::kf_paste ,0}, - { 'a', FL_COMMAND, Fl_Text_Editor::kf_select_all ,0}, - { FL_Left, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Right, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Up, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Down, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Left, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Right, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Up, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Down, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { 0, 0, 0 ,0} -}; - - -Fl_Cocoa_Screen_Driver::Fl_Cocoa_Screen_Driver() { - text_editor_extra_key_bindings = extra_bindings; - scale_ = 1.; - default_icon = nil; - // initialize key table - key_table = darwin_key_table; - key_table_size = sizeof(darwin_key_table)/sizeof(*darwin_key_table); -} - - -void Fl_Cocoa_Screen_Driver::init() -{ - open_display(); - CGDirectDisplayID displays[MAX_SCREENS]; - CGDisplayCount count, i; - CGRect r; - CGGetActiveDisplayList(MAX_SCREENS, displays, &count); - for( i = 0; i < count; i++) { - r = CGDisplayBounds(displays[i]); - screens[i].x = int(r.origin.x); - screens[i].y = int(r.origin.y); - screens[i].width = int(r.size.width); - screens[i].height = int(r.size.height); - //fprintf(stderr,"screen %d %dx%dx%dx%d\n",i,screens[i].x,screens[i].y,screens[i].width,screens[i].height); - if (&CGDisplayScreenSize != NULL) { - CGSize s = CGDisplayScreenSize(displays[i]); // from 10.3 - dpi_h[i] = screens[i].width / (s.width/25.4); - dpi_v[i] = screens[i].height / (s.height/25.4); - } else { - dpi_h[i] = dpi_v[i] = 75.; - } - } - num_screens = count; -} - - -void Fl_Cocoa_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - float s = scale(0); - X = screens[n].x/s; - Y = screens[n].y/s; - W = screens[n].width/s; - H = screens[n].height/s; -} - - -void Fl_Cocoa_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - - if (n >= 0 && n < num_screens) { - h = dpi_h[n]; - v = dpi_v[n]; - } -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_Cocoa_Screen_Driver::beep(int type) { - switch (type) { - case FL_BEEP_DEFAULT : - case FL_BEEP_ERROR : - NSBeep(); - break; - default : - break; - } -} - - -extern void fl_fix_focus(); // in Fl.cxx - -extern void *fl_capture; - - -void Fl_Cocoa_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab_) { - fl_capture = (FLWindow*)(Fl_X::flx(Fl::first_window())->xid); - Fl_Cocoa_Window_Driver::driver(Fl::first_window())->set_key_window(); - } - Fl::grab_ = win; - } else { - if (Fl::grab_) { - fl_capture = 0; - Fl::grab_ = 0; - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -// MacOS X currently supports two color schemes - Blue and Graphite. -// Since we aren't emulating the Aqua interface (even if Apple would -// let us), we use some defaults that are similar to both. The -// Fl::scheme("plastic") color/box scheme provides a usable Aqua-like -// look-n-feel... -void Fl_Cocoa_Screen_Driver::get_system_colors() -{ - open_display(); - - Fl_Screen_Driver::get_system_colors(); - - if (!bg2_set) Fl::background2(0xff, 0xff, 0xff); - if (!fg_set) Fl::foreground(0, 0, 0); - if (!bg_set) Fl::background(0xd8, 0xd8, 0xd8); - -#if 0 - // this would be the correct code, but it does not run on all versions - // of OS X. Also, setting a bright selection color would require - // some updates in Fl_Adjuster and Fl_Help_Browser - OSStatus err; - RGBColor c; - err = GetThemeBrushAsColor(kThemeBrushPrimaryHighlightColor, 24, true, &c); - if (err) - set_selection_color(0x00, 0x00, 0x80); - else - set_selection_color(c.red, c.green, c.blue); -#else - set_selection_color(0x00, 0x00, 0x80); -#endif -} - - -int Fl_Cocoa_Screen_Driver::has_marked_text() const { - return 1; -} - - -int Fl_Cocoa_Screen_Driver::insertion_point_x = 0; -int Fl_Cocoa_Screen_Driver::insertion_point_y = 0; -int Fl_Cocoa_Screen_Driver::insertion_point_height = 0; -bool Fl_Cocoa_Screen_Driver::insertion_point_location_is_valid = false; - -void Fl_Cocoa_Screen_Driver::reset_marked_text() { - Fl::compose_state = 0; - next_marked_length = 0; - insertion_point_location_is_valid = false; -} - -// computes window coordinates & height of insertion point -int Fl_Cocoa_Screen_Driver::insertion_point_location(int *px, int *py, int *pheight) -// return true if the current coordinates of the insertion point are available -{ - if ( ! insertion_point_location_is_valid ) return false; - *px = insertion_point_x; - *py = insertion_point_y; - *pheight = insertion_point_height; - return true; -} - -void Fl_Cocoa_Screen_Driver::insertion_point_location(int x, int y, int height) { - insertion_point_location_is_valid = true; - insertion_point_x = x; - insertion_point_y = y; - insertion_point_height = height; -} - -int Fl_Cocoa_Screen_Driver::compose(int &del) { - int condition; - int has_text_key = Fl::compose_state || Fl::e_keysym <= '~' || Fl::e_keysym == FL_Iso_Key || - Fl::e_keysym == FL_JIS_Underscore || Fl::e_keysym == FL_Yen || - (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last && Fl::e_keysym != FL_KP_Enter); - condition = Fl::e_state&(FL_META | FL_CTRL) || - (Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || // called from flagsChanged - !has_text_key ; - if (condition) { del = 0; return 0;} // this stuff is to be treated as a function key - del = Fl::compose_state; - Fl::compose_state = next_marked_length; - return 1; -} - - -int Fl_Cocoa_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input) -{ - switch (key) { - case FL_Delete: { - if (mods==0) return input->kf_delete_char_right(); // Delete (OSX-HIG,TE,SA,WOX) - if (mods==FL_CTRL) return input->kf_delete_char_right(); // Ctrl-Delete (??? TE,!SA,!WOX) - if (mods==FL_ALT) return input->kf_delete_word_right(); // Alt-Delete (OSX-HIG,TE,SA) - return 0; // ignore other combos, pass to parent - } - - case FL_Left: - if (mods==0) return input->kf_move_char_left(); // Left (OSX-HIG) - if (mods==FL_ALT) return input->kf_move_word_left(); // Alt-Left (OSX-HIG) - if (mods==FL_META) return input->kf_move_sol(); // Meta-Left (OSX-HIG) - if (mods==FL_CTRL) return input->kf_move_sol(); // Ctrl-Left (TE/SA) - return 0; // ignore other combos, pass to parent - - case FL_Right: - if (mods==0) return input->kf_move_char_right(); // Right (OSX-HIG) - if (mods==FL_ALT) return input->kf_move_word_right(); // Alt-Right (OSX-HIG) - if (mods==FL_META) return input->kf_move_eol(); // Meta-Right (OSX-HIG) - if (mods==FL_CTRL) return input->kf_move_eol(); // Ctrl-Right (TE/SA) - return 0; // ignore other combos, pass to parent - - case FL_Up: - if (mods==0) return input->kf_lines_up(1); // Up (OSX-HIG) - if (mods==FL_CTRL) return input->kf_page_up(); // Ctrl-Up (TE !HIG) - if (mods==FL_ALT) return input->kf_move_up_and_sol(); // Alt-Up (OSX-HIG) - if (mods==FL_META) return input->kf_top(); // Meta-Up (OSX-HIG) - return 0; // ignore other combos, pass to parent - - case FL_Down: - if (mods==0) return input->kf_lines_down(1); // Dn (OSX-HIG) - if (mods==FL_CTRL) return input->kf_page_down(); // Ctrl-Dn (TE !HIG) - if (mods==FL_ALT) return input->kf_move_down_and_eol(); // Alt-Dn (OSX-HIG) - if (mods==FL_META) return input->kf_bottom(); // Meta-Dn (OSX-HIG) - return 0; // ignore other combos, pass to parent - - case FL_Page_Up: - // Fl_Input has no scroll control, so instead we move the cursor by one page - // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. - if (mods==0) return input->kf_page_up(); // PgUp (OSX-HIG) - if (mods==FL_ALT) return input->kf_page_up(); // Alt-PageUp (OSX-HIG) - if (mods==FL_META) return input->kf_top(); // Meta-PageUp (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - - case FL_Page_Down: - // Fl_Input has no scroll control, so instead we move the cursor by one page - // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. - if (mods==0) return input->kf_page_down(); // PgDn (OSX-HIG) - if (mods==FL_ALT) return input->kf_page_down(); // Alt-PageDn (OSX-HIG) - if (mods==FL_META) return input->kf_bottom(); // Meta-PageDn (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - - case FL_Home: - if (mods==0) return input->kf_top(); // Home (OSX-HIG) - if (mods==FL_ALT) return input->kf_top(); // Alt-Home (???) - return 0; // ignore other combos, pass to parent - - case FL_End: - if (mods==0) return input->kf_bottom(); // End (OSX-HIG) - if (mods==FL_ALT) return input->kf_bottom(); // Alt-End (???) - return 0; // ignore other combos, pass to parent - - case FL_BackSpace: - if (mods==0) return input->kf_delete_char_left(); // Backspace (OSX-HIG) - if (mods==FL_CTRL) return input->kf_delete_char_left(); // Ctrl-Backspace (TE/SA) - if (mods==FL_ALT) return input->kf_delete_word_left(); // Alt-Backspace (OSX-HIG) - if (mods==FL_META) return input->kf_delete_sol(); // Meta-Backspace (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - } - return -1; -} - -void Fl_Cocoa_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) -{ - width = (int)CGBitmapContextGetWidth((CGContextRef)off); - height = (int)CGBitmapContextGetHeight((CGContextRef)off); -} - -Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window, - bool may_capture_subwins, bool *did_capture_subwins) -{ - int bpp, bpr; - uchar *base, *p; - if (!window) { // read from offscreen buffer - float s = 1; - CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context - base = (uchar *)CGBitmapContextGetData(src); // get data - if(!base) return NULL; - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - if( (sw - X < w) || (sh - Y < h) ) return NULL; - bpr = (int)CGBitmapContextGetBytesPerRow(src); - bpp = (int)CGBitmapContextGetBitsPerPixel(src)/8; - Fl_Image_Surface *imgs = (Fl_Image_Surface*)Fl_Surface_Device::surface(); - int fltk_w, fltk_h; - imgs->printable_rect(&fltk_w, &fltk_h); - s = sw / float(fltk_w); - X *= s; Y *= s; w *= s; h *= s; - if (X + w > sw) w = sw - X; - if (Y + h > sh) h = sh - Y; - // Copy the image from the off-screen buffer to the memory buffer. - int idx, idy; // Current X & Y in image - uchar *pdst, *psrc; - p = new uchar[w * h * 4]; - for (idy = Y, pdst = p; idy < h + Y; idy ++) { - for (idx = 0, psrc = base + idy * bpr + X * bpp; idx < w; idx ++, psrc += bpp, pdst += 4) { - pdst[0] = psrc[0]; // R - pdst[1] = psrc[1]; // G - pdst[2] = psrc[2]; // B - } - } - bpr = 0; - } else { // read from window - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, may_capture_subwins); - if (did_capture_subwins) *did_capture_subwins = may_capture_subwins; - if (!cgimg) { - return NULL; - } - w = (int)CGImageGetWidth(cgimg); - h = (int)CGImageGetHeight(cgimg); - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Surface_Device::push_current(surf); - ((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(cgimg, 0, 0, w, h, 0, 0, w, h); - CGContextRef gc = (CGContextRef)fl_graphics_driver->gc(); - w = (int)CGBitmapContextGetWidth(gc); - h = (int)CGBitmapContextGetHeight(gc); - bpr = (int)CGBitmapContextGetBytesPerRow(gc); - bpp = (int)CGBitmapContextGetBitsPerPixel(gc)/8; - base = (uchar*)CGBitmapContextGetData(gc); - p = new uchar[bpr * h]; - memcpy(p, base, bpr * h); - Fl_Surface_Device::pop_current(); - delete surf; - CFRelease(cgimg); - } - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, 4, bpr); - rgb->alloc_array = 1; - return rgb; -} - -void Fl_Cocoa_Screen_Driver::set_spot(int /*font*/, int size, int X, int Y, int /*W*/, int /*H*/, Fl_Window* /*win*/) { - Fl_Cocoa_Screen_Driver::insertion_point_location(X, Y, size); -} - -void Fl_Cocoa_Screen_Driver::reset_spot() { - Fl_Cocoa_Screen_Driver::reset_marked_text(); -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H deleted file mode 100644 index 358523dbd..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ /dev/null @@ -1,168 +0,0 @@ -// -// Definition of Apple Cocoa window driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Cocoa_Window_Driver.H - \brief Definition of Apple Cocoa window driver. - */ - -#ifndef FL_COCOA_WINDOW_DRIVER_H -#define FL_COCOA_WINDOW_DRIVER_H - -#include "../../Fl_Window_Driver.H" -#include <FL/Fl_Plugin.H> -#include <ApplicationServices/ApplicationServices.h> - -class Fl_Image; -class Fl_Window; -#ifdef __OBJC__ -@class CALayer; -@class NSCursor; -@class NSImage; -@class FLWindow; -@class NSOpenGLContext; -@class NSOpenGLPixelFormat; -@class NSView; -@class NSWindow; -#else -class CALayer; -class NSCursor; -class NSImage; -class FLWindow; -class NSOpenGLContext; -class NSOpenGLPixelFormat; -class NSView; -class NSWindow; -#endif // __OBJC__ - -/** - \cond DriverDev - \addtogroup DriverDeveloper - \{ - */ - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - - ? where do we handle the interface between OpenGL/DirectX and Cocoa/Windows/Glx? - */ - -/** - \} - \endcond - */ - - -class Fl_Cocoa_Window_Driver : public Fl_Window_Driver -{ -private: - struct shape_data_type { - Fl_Image* shape_; ///< shape image - CGImageRef mask; - } *shape_data_; - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) FL_OVERRIDE; - CGRect* subRect_; // makes sure subwindow remains inside its parent window - // stores 3 binary flags: whether window is mapped to retina display; whether resolution just changed; - // whether window's view received the [FLView view_did_resize] message - unsigned window_flags_; -public: - Fl_Cocoa_Window_Driver(Fl_Window*); - ~Fl_Cocoa_Window_Driver(); - static inline Fl_Cocoa_Window_Driver* driver(const Fl_Window *w) {return (Fl_Cocoa_Window_Driver*)Fl_Window_Driver::driver(w);} - CGContextRef gc; // graphics context - NSCursor *cursor; - static void q_release_context(Fl_Cocoa_Window_Driver *x = 0); // free all resources associated with gc - static CGImageRef capture_decorated_window_10_5(NSWindow *nswin); - void set_key_window(); - bool mapped_to_retina(); // is window mapped to retina display? - void mapped_to_retina(bool); // sets whether window is mapped to retina display - bool changed_resolution(); // did window just moved to display with another resolution? - void changed_resolution(bool);// sets whether window just moved to display with another resolution - bool view_resized(); // did window's view receive [FLView view_did_resize] message? - void view_resized(bool b); // sets whether window's view received [FLView view_did_resize] message - bool through_resize(); // did Fl_Window::resize() run already - void through_resize(bool b); // set whether Fl_Window::resize() run already - CGRect* subRect() { return subRect_; } // getter - void subRect(CGRect *r) { subRect_ = r; } // setter - static void destroy(FLWindow*); - CGImageRef CGImage_from_window_rect(int x, int y, int w, int h, bool capture_subwins = true); - - // --- window data - int decorated_w() FL_OVERRIDE; - int decorated_h() FL_OVERRIDE; - const Fl_Image* shape() FL_OVERRIDE; - - // --- window management - void makeWindow() FL_OVERRIDE; - void take_focus() FL_OVERRIDE; - void flush() FL_OVERRIDE; - void flush_overlay() FL_OVERRIDE; - void draw_begin() FL_OVERRIDE; - void draw_end() FL_OVERRIDE; - void make_current() FL_OVERRIDE; - void label(const char *name, const char *mininame) FL_OVERRIDE; - void show() FL_OVERRIDE; - void resize(int X,int Y,int W,int H) FL_OVERRIDE; - void hide() FL_OVERRIDE; - void map() FL_OVERRIDE; - void unmap() FL_OVERRIDE; - void fullscreen_on() FL_OVERRIDE; - void fullscreen_off(int X, int Y, int W, int H) FL_OVERRIDE; - void fullscreen_screens(bool on_off) FL_OVERRIDE; - void maximize() FL_OVERRIDE; - void un_maximize() FL_OVERRIDE; - void use_border() FL_OVERRIDE; - void size_range() FL_OVERRIDE; - void iconize() FL_OVERRIDE; - void decoration_sizes(int *top, int *left, int *right, int *bottom) FL_OVERRIDE; - // --- window cursor stuff - int set_cursor(Fl_Cursor) FL_OVERRIDE; - int set_cursor(const Fl_RGB_Image*, int, int) FL_OVERRIDE; - - void shape(const Fl_Image* img) FL_OVERRIDE; - // next 4 are in Fl_cocoa.mm because they use Objective-c - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) FL_OVERRIDE; - void wait_for_expose() FL_OVERRIDE; - void draw_titlebar_to_context(CGContextRef gc, int w, int h); - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data) FL_OVERRIDE; - - //icons - void icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - NSImage *icon_image; - - fl_uintptr_t os_id() FL_OVERRIDE; -}; - -class Fl_Cocoa_Plugin : public Fl_Plugin { -public: - Fl_Cocoa_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "fltk:cocoa"; } - virtual const char *name() = 0; - virtual void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) = 0; -}; - -#endif // FL_COCOA_WINDOW_DRIVER_H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx deleted file mode 100644 index 55d1bea32..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx +++ /dev/null @@ -1,294 +0,0 @@ -// -// Definition of Apple Cocoa window driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_Cocoa_Window_Driver.H" -#include "../../Fl_Screen_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include <FL/Fl_Double_Window.H> -#include <FL/Fl_Overlay_Window.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/fl_draw.H> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <math.h> - - -Fl_Cocoa_Window_Driver::Fl_Cocoa_Window_Driver(Fl_Window *win) -: Fl_Window_Driver(win) -{ - cursor = nil; - window_flags_ = 0; - icon_image = NULL; - screen_num_ = 0; - shape_data_ = NULL; -} - - -void Fl_Cocoa_Window_Driver::take_focus() -{ - set_key_window(); -} - - -void Fl_Cocoa_Window_Driver::flush_overlay() -{ - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - int erase_overlay = (pWindow->damage()&FL_DAMAGE_OVERLAY) | (overlay() == oWindow); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - - if (!oWindow->shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - if (!other_xid) { - other_xid = new Fl_Image_Surface(oWindow->w(), oWindow->h(), 1); - oWindow->clear_damage(FL_DAMAGE_ALL); - } - if (oWindow->damage() & ~FL_DAMAGE_EXPOSE) { - Fl_X *myi = Fl_X::flx(pWindow); - fl_clip_region(myi->region); myi->region = 0; - Fl_Surface_Device::push_current(other_xid); - draw(); - Fl_Surface_Device::pop_current(); - } - if (erase_overlay) fl_clip_region(0); - fl_copy_offscreen(0, 0, oWindow->w(), oWindow->h(), other_xid->offscreen(), 0, 0); - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -void Fl_Cocoa_Window_Driver::draw_begin() -{ - if (!Fl_Surface_Device::surface()->driver()->has_feature(Fl_Graphics_Driver::NATIVE)) return; - CGContextRef my_gc = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); - if (shape_data_) { - if (shape_data_->mask) { - CGContextClipToMask(my_gc, CGRectMake(0,0,w(),h()), shape_data_->mask); // requires Mac OS 10.4 - } - CGContextSaveGState(my_gc); - } -} - - -void Fl_Cocoa_Window_Driver::draw_end() -{ - if (Fl_Surface_Device::surface()->driver()->has_feature(Fl_Graphics_Driver::NATIVE)) { - CGContextRef my_gc = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); - if (shape_data_) CGContextRestoreGState(my_gc); - } -} - - - -static void MyProviderReleaseData (void *info, const void *data, size_t size) { - delete[] (uchar*)data; -} - -// bitwise inversion of all 4-bit quantities -static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; - -static inline uchar swap_byte(const uchar b) { - // reverse the order of bits of byte b: 1->8 becomes 8->1 - return (swapped[b & 0xF] << 4) | swapped[b >> 4]; -} - - -void Fl_Cocoa_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->shape_ = b; - if (b) { - // complement mask bits and perform bitwise inversion of all bytes and also reverse top and bottom - int bytes_per_row = (b->w() + 7)/8; - uchar *from = new uchar[bytes_per_row * b->h()]; - for (int i = 0; i < b->h(); i++) { - uchar *p = (uchar*)(*b->data()) + bytes_per_row * i; - uchar *last = p + bytes_per_row; - uchar *q = from + (b->h() - 1 - i) * bytes_per_row; - while (p < last) { - *q++ = swap_byte(~*p++); - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, bytes_per_row * b->h(), MyProviderReleaseData); - shape_data_->mask = CGImageMaskCreate(b->w(), b->h(), 1, 1, bytes_per_row, provider, NULL, false); - CFRelease(provider); - } -} - - -void Fl_Cocoa_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, d = img->d(), w = img->w(), h = img->h(); - shape_data_->shape_ = img; - if (shape_data_->shape_) { - // reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits - int bytes_per_row = w * d; - uchar *from = new uchar[w * h]; - for ( i = 0; i < h; i++) { - uchar *p = (uchar*)(*img->data()) + bytes_per_row * i + offset; - uchar *last = p + bytes_per_row; - uchar *q = from + (h - 1 - i) * w; - while (p < last) { - if (d == 3) { - unsigned u = *p++; - u += *p++; - u += *p++; - *q++ = ~(u/3); - } - else { - *q++ = ~(*p); - p += d; - } - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, w * h, MyProviderReleaseData); - shape_data_->mask = CGImageMaskCreate(w, h, 8, 8, w, provider, NULL, false); - CFRelease(provider); - } -} - - -void Fl_Cocoa_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->mask) { CGImageRelease(shape_data_->mask); } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); - pWindow->border(false); -} - - -void Fl_Cocoa_Window_Driver::hide() { - Fl_X* ip = Fl_X::flx(pWindow); - // MacOS X manages a single pointer per application. Make sure that hiding - // a toplevel window will not leave us with some random pointer shape, or - // worst case, an invisible pointer - if (ip && !parent()) pWindow->cursor(FL_CURSOR_DEFAULT); - if ( hide_common() ) return; - q_release_context(this); - if ( ip->xid == (fl_uintptr_t)fl_window ) - fl_window = 0; - if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - destroy((FLWindow*)ip->xid); - delete subRect(); - delete ip; -} - - -int Fl_Cocoa_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data) -{ - if ( (src_x < 0) || (src_y < 0) ) - return 1; - if ( (src_x+src_w > pWindow->w()) || (src_y+src_h > pWindow->h()) ) - return 1; - CGImageRef img = CGImage_from_window_rect(src_x, src_y, src_w, src_h); - if (!img) - return 1; - // the current surface is generally the display, but is an Fl_Image_Surface when scrolling an Fl_Overlay_Window - Fl_Quartz_Graphics_Driver *qgd = (Fl_Quartz_Graphics_Driver*)Fl_Surface_Device::surface()->driver(); - float s = qgd->scale(); - qgd->draw_CGImage(img, dest_x, dest_y, (int)lround(s*src_w), (int)lround(s*src_h), 0, 0, src_w, src_h); - CFRelease(img); - return 0; -} - -static const unsigned mapped_mask = 1; -static const unsigned changed_mask = 2; -static const unsigned view_resized_mask = 4; -static const unsigned through_resize_mask = 8; - -bool Fl_Cocoa_Window_Driver::mapped_to_retina() { - return window_flags_ & mapped_mask; -} - -void Fl_Cocoa_Window_Driver::mapped_to_retina(bool b) { - if (b) window_flags_ |= mapped_mask; - else window_flags_ &= ~mapped_mask; -} - -bool Fl_Cocoa_Window_Driver::changed_resolution() { - return window_flags_ & changed_mask; -} - -void Fl_Cocoa_Window_Driver::changed_resolution(bool b) { - if (b) window_flags_ |= changed_mask; - else window_flags_ &= ~changed_mask; -} - -bool Fl_Cocoa_Window_Driver::view_resized() { - return window_flags_ & view_resized_mask; -} - -void Fl_Cocoa_Window_Driver::view_resized(bool b) { - if (b) window_flags_ |= view_resized_mask; - else window_flags_ &= ~view_resized_mask; -} - -bool Fl_Cocoa_Window_Driver::through_resize() { - return window_flags_ & through_resize_mask; -} - -void Fl_Cocoa_Window_Driver::through_resize(bool b) { - if (b) window_flags_ |= through_resize_mask; - else window_flags_ &= ~through_resize_mask; -} - -const Fl_Image* Fl_Cocoa_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - -/* Returns images of the capture of the window title-bar. - On the Mac OS platform, left, bottom and right are returned NULL; top is returned with depth 4. - */ -void Fl_Cocoa_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) -{ - top = left = bottom = right = NULL; - int htop, hleft, hright, hbottom; - Fl_Cocoa_Window_Driver::decoration_sizes(&htop, &hleft, &hright, &hbottom); - if (htop == 0) return; // when window is fullscreen - CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - float s = Fl::screen_driver()->scale(screen_num()); - int scaled_w = int(w() * s); - const int factor = (mapped_to_retina() ? 2 : 1); - int data_w = factor * scaled_w, data_h = factor * htop; - uchar *rgba = new uchar[4 * data_w * data_h]; - CGContextRef auxgc = CGBitmapContextCreate(rgba, data_w, data_h, 8, 4 * data_w, cspace, kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(cspace); - CGContextClearRect(auxgc, CGRectMake(0,0,data_w,data_h)); - CGContextScaleCTM(auxgc, factor, factor); - draw_titlebar_to_context(auxgc, scaled_w, htop); - top = new Fl_RGB_Image(rgba, data_w, data_h, 4); - top->alloc_array = 1; - top->scale(w(),htop, s <1 ? 0 : 1, 1); - CGContextRelease(auxgc); -} - - -FLWindow *fl_mac_xid(const Fl_Window *win) { - return (FLWindow*)Fl_Window_Driver::xid(win); -} - - -Fl_Window *fl_mac_find(FLWindow *xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} diff --git a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H b/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H deleted file mode 100644 index 2de8bde64..000000000 --- a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H +++ /dev/null @@ -1,51 +0,0 @@ -// -// Definition of class Fl_MacOS_Sys_Menu_Bar_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2017 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef Fl_MacOS_Sys_Menu_Bar_Driver_H -#define Fl_MacOS_Sys_Menu_Bar_Driver_H - -#include "../../Fl_Sys_Menu_Bar_Driver.H" - -class Fl_MacOS_Sys_Menu_Bar_Driver : public Fl_Sys_Menu_Bar_Driver { -public: - Fl_Menu_Item *window_menu_items; - int first_window_menu_item; - Fl_MacOS_Sys_Menu_Bar_Driver(); - virtual ~Fl_MacOS_Sys_Menu_Bar_Driver(); - void update() FL_OVERRIDE; - void draw() FL_OVERRIDE; - void about(Fl_Callback *cb, void *data) FL_OVERRIDE; - int add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) FL_OVERRIDE; - int add(const char* str) FL_OVERRIDE; - int insert(int index, const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) FL_OVERRIDE; - void menu(const Fl_Menu_Item *m) FL_OVERRIDE; - void shortcut (int i, int s) FL_OVERRIDE; - void setonly (Fl_Menu_Item *item) FL_OVERRIDE; - void clear() FL_OVERRIDE; - int clear_submenu(int index) FL_OVERRIDE; - void remove(int index) FL_OVERRIDE; - void replace(int index, const char *name) FL_OVERRIDE; - void mode(int i, int fl) FL_OVERRIDE; - void create_window_menu() FL_OVERRIDE; - void new_window(Fl_Window *win); - void remove_window(Fl_Window *win); - void rename_window(Fl_Window *win); - static Fl_MacOS_Sys_Menu_Bar_Driver* driver(); - void play_menu(const Fl_Menu_Item *) FL_OVERRIDE; -}; - - -#endif /* Fl_MacOS_Sys_Menu_Bar_Driver_H */ diff --git a/src/drivers/Darwin/Fl_Darwin_System_Driver.H b/src/drivers/Darwin/Fl_Darwin_System_Driver.H deleted file mode 100644 index 7dd0ae6da..000000000 --- a/src/drivers/Darwin/Fl_Darwin_System_Driver.H +++ /dev/null @@ -1,85 +0,0 @@ -// -// Definition of Apple Darwin system driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Darwin_System_Driver.H - \brief Definition of Apple Darwin system driver. - */ - -#ifndef FL_DARWIN_SYSTEM_DRIVER_H -#define FL_DARWIN_SYSTEM_DRIVER_H - -#include "../Posix/Fl_Posix_System_Driver.H" -#include <stdlib.h> -#include <unistd.h> - -/* - Move everything here that manages the system interface. - - There is exactly one system driver. - - - filename and pathname management - - directory and file access - - system time and system timer - - multithreading - */ - -class Fl_Darwin_System_Driver : public Fl_Posix_System_Driver -{ -public: - Fl_Darwin_System_Driver(); - int single_arg(const char *arg) FL_OVERRIDE; - int arg_and_value(const char *name, const char *value) FL_OVERRIDE; - int clocale_vprintf(FILE *output, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsscanf(const char *input, const char *format, va_list args) FL_OVERRIDE; - static void *get_carbon_function(const char *name); - static int calc_mac_os_version(); // computes the fl_mac_os_version global variable - static unsigned short *compute_macKeyLookUp(); - - int filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - int open_uri(const char *uri, char *msg, int msglen) FL_OVERRIDE; - int need_test_shortcut_extra() FL_OVERRIDE {return 1;} - int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) FL_OVERRIDE; - void newUUID(char *uuidBuffer) FL_OVERRIDE; - char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor, - const char *application) FL_OVERRIDE; - const char *local_to_latin1(const char *t, int n) FL_OVERRIDE; - const char *latin1_to_local(const char *t, int n) FL_OVERRIDE; - const char *local_to_mac_roman(const char *t, int n) FL_OVERRIDE; - const char *mac_roman_to_local(const char *t, int n) FL_OVERRIDE; - void tree_draw_expando_button(int x, int y, bool state, bool active) FL_OVERRIDE; - int tree_connector_style() FL_OVERRIDE; - const char *filename_name(const char *buf) FL_OVERRIDE; - void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void add_fd(int fd, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void remove_fd(int, int when) FL_OVERRIDE; - void remove_fd(int) FL_OVERRIDE; - void open_callback(void (*)(const char *)) FL_OVERRIDE; - const char *shift_name() FL_OVERRIDE; - const char *meta_name() FL_OVERRIDE; - const char *alt_name() FL_OVERRIDE; - const char *control_name() FL_OVERRIDE; - Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() FL_OVERRIDE; - double wait(double time_to_wait) FL_OVERRIDE; - int ready() FL_OVERRIDE; - int filename_relative(char *to, int tolen, const char *dest_dir, const char *base_dir) FL_OVERRIDE; -}; - -#endif // FL_DARWIN_SYSTEM_DRIVER_H diff --git a/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx b/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx deleted file mode 100644 index c11a95f94..000000000 --- a/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx +++ /dev/null @@ -1,339 +0,0 @@ -// -// Definition of Apple Darwin system driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H" -#include <FL/Fl.H> -#include <FL/Fl_File_Browser.H> -#include <FL/Fl_Tree_Prefs.H> -#include <FL/Fl_Pixmap.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "../../flstring.h" -#include <string.h> -#include <xlocale.h> // 10.4 -#include <locale.h> -#include <stdio.h> -#include <dlfcn.h> -#include <pwd.h> -#include <sys/param.h> -#include <sys/ucred.h> -#include <sys/mount.h> -#include <sys/stat.h> - - -const char *Fl_Darwin_System_Driver::shift_name() { - return "⇧\\"; // "\xe2\x87\xa7\\"; // U+21E7 (upwards white arrow) -} -const char *Fl_Darwin_System_Driver::meta_name() { - return "⌘\\"; // "\xe2\x8c\x98\\"; // U+2318 (place of interest sign) -} -const char *Fl_Darwin_System_Driver::alt_name() { - return "⌥\\"; // "\xe2\x8c\xa5\\"; // U+2325 (option key) -} -const char *Fl_Darwin_System_Driver::control_name() { - return "⌃\\"; // "\xe2\x8c\x83\\"; // U+2303 (up arrowhead) -} - -Fl_Darwin_System_Driver::Fl_Darwin_System_Driver() : Fl_Posix_System_Driver() { - if (fl_mac_os_version == 0) fl_mac_os_version = calc_mac_os_version(); - command_key = FL_META; - control_key = FL_CTRL; -} - -int Fl_Darwin_System_Driver::single_arg(const char *arg) { - // The Finder application in MacOS X passes the "-psn_N_NNNNN" option to all apps. - return (strncmp(arg, "psn_", 4) == 0); -} - -int Fl_Darwin_System_Driver::arg_and_value(const char *name, const char *value) { - // Xcode in MacOS X may pass "-NSDocumentRevisionsDebugMode YES" - return strcmp(name, "NSDocumentRevisionsDebugMode") == 0; -} - -static locale_t postscript_locale = NULL; - -int Fl_Darwin_System_Driver::clocale_vprintf(FILE *output, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vfprintf_l(output, postscript_locale, format, args); // 10.4 -} - -int Fl_Darwin_System_Driver::clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vsnprintf_l(output, output_size, postscript_locale, format, args); // 10.4 -} - -int Fl_Darwin_System_Driver::clocale_vsscanf(const char *input, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vsscanf_l(input, postscript_locale, format, args); // 10.4 -} - - -// Returns the address of a Carbon function after dynamically loading the Carbon library if needed. -void *Fl_Darwin_System_Driver::get_carbon_function(const char *function_name) { - static void *carbon = ::dlopen("/System/Library/Frameworks/Carbon.framework/Carbon", RTLD_LAZY); - return (carbon ? dlsym(carbon, function_name) : NULL); -} - -int Fl_Darwin_System_Driver::filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_sz) { - int dirlen; - char *dirloc; - // Assume that locale encoding is no less dense than UTF-8 - dirlen = (int)strlen(d); - dirloc = (char *)d; -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - int n = scandir(dirloc, list, 0, (int(*)(const struct dirent**,const struct dirent**))sort); -# else - int n = scandir(dirloc, list, 0, (int(*)(const void*,const void*))sort); -# endif - if (n==-1) { - if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno)); - return -1; - } - // convert every filename to UTF-8, and append a '/' to all - // filenames that are directories - int i; - char *fullname = (char*)malloc(dirlen+FL_PATH_MAX+3); // Add enough extra for two /'s and a nul - // Use memcpy for speed since we already know the length of the string... - memcpy(fullname, d, dirlen+1); - char *name = fullname + dirlen; - if (name!=fullname && name[-1]!='/') *name++ = '/'; - for (i=0; i<n; i++) { - int newlen; - dirent *de = (*list)[i]; - int len = (int)strlen(de->d_name); - newlen = len; - dirent *newde = (dirent*)malloc(de->d_name - (char*)de + newlen + 2); // Add space for a / and a nul - // Conversion to UTF-8 - memcpy(newde, de, de->d_name - (char*)de); - strcpy(newde->d_name, de->d_name); - // Check if dir (checks done on "old" name as we need to interact with - // the underlying OS) - if (de->d_name[len-1]!='/' && len<=FL_PATH_MAX) { - // Use memcpy for speed since we already know the length of the string... - memcpy(name, de->d_name, len+1); - if (fl_filename_isdir(fullname)) { - char *dst = newde->d_name + newlen; - *dst++ = '/'; - *dst = 0; - } - } - free(de); - (*list)[i] = newde; - } - free(fullname); - return n; -} - - -int Fl_Darwin_System_Driver::open_uri(const char *uri, char *msg, int msglen) -{ - char *argv[3]; // Command-line arguments - argv[0] = (char*)"open"; - argv[1] = (char*)uri; - argv[2] = (char*)0; - if (msg) snprintf(msg, msglen, "open %s", uri); - return run_program("/usr/bin/open", argv, msg, msglen) != 0; -} - -int Fl_Darwin_System_Driver::file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) -{ - // MacOS X and Darwin use getfsstat() system call... - int numfs; // Number of file systems - struct statfs *fs; // Buffer for file system info - int num_files = 0; - - // We always have the root filesystem. - browser->add("/", icon); - - // Get the mounted filesystems... - numfs = getfsstat(NULL, 0, MNT_NOWAIT); - if (numfs > 0) { - // We have file systems, get them... - fs = new struct statfs[numfs]; - getfsstat(fs, sizeof(struct statfs) * numfs, MNT_NOWAIT); - - // Add filesystems to the list... - for (int i = 0; i < numfs; i ++) { - // Ignore "/", "/dev", and "/.vol"... - if (fs[i].f_mntonname[1] && strcmp(fs[i].f_mntonname, "/dev") && - strcmp(fs[i].f_mntonname, "/.vol")) { - snprintf(filename, lname, "%s/", fs[i].f_mntonname); - browser->add(filename, icon); - } - num_files ++; - } - - // Free the memory used for the file system info array... - delete[] fs; - } - return num_files; -} - -void Fl_Darwin_System_Driver::newUUID(char *uuidBuffer) -{ - CFUUIDRef theUUID = CFUUIDCreate(NULL); - CFUUIDBytes b = CFUUIDGetUUIDBytes(theUUID); - snprintf(uuidBuffer, 36+1, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - b.byte0, b.byte1, b.byte2, b.byte3, b.byte4, b.byte5, b.byte6, b.byte7, - b.byte8, b.byte9, b.byte10, b.byte11, b.byte12, b.byte13, b.byte14, b.byte15); - CFRelease(theUUID); -} - -/* - * returns pointer to the filename, or null if name ends with ':' - */ -const char *Fl_Darwin_System_Driver::filename_name( const char *name ) -{ - const char *p, *q; - if (!name) return (0); - for ( p = q = name ; *p ; ) { - if ( ( p[0] == ':' ) && ( p[1] == ':' ) ) { - q = p+2; - p++; - } - else if (p[0] == '/') { - q = p + 1; - } - p++; - } - return q; -} - -// These function assume a western code page. If you need to support -// scripts that are not part of this code page, you might want to -// take a look at FLTK2, which uses utf8 for text encoding. -// -// By keeping these conversion tables in their own module, they will not -// be statically linked (by a smart linker) unless actually used. -// -// On MS-Windows, nothing need to be converted. We simply return the -// original pointer. -// -// Most X11 implementations seem to default to Latin-1 as a code since it -// is a superset of ISO 8859-1, the original Western codepage on X11. -// -// Apple's OS X however renders text in MacRoman for western settings. The -// lookup tables below will convert all common character codes and replace -// unknown characters with an upside-down question mark. - -// This table converts Windows-1252/Latin 1 into MacRoman encoding -static uchar latin2roman[128] = { -0xdb, 0xc0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xc0, 0xdc, 0xce, 0xc0, 0xc0, 0xc0, -0xc0, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xc0, 0xdd, 0xcf, 0xc0, 0xc0, 0xd9, -0xca, 0xc1, 0xa2, 0xa3, 0xc0, 0xb4, 0xc0, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xc0, 0xa8, 0xf8, -0xa1, 0xb1, 0xc0, 0xc0, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc0, 0xbc, 0xc8, 0xc0, 0xc0, 0xc0, 0xc0, -0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, -0xc0, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xc0, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xc0, 0xc0, 0xa7, -0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, -0xc0, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xc0, 0xc0, 0xd8 -}; - -// This table converts MacRoman into Windows-1252/Latin 1 -static uchar roman2latin[128] = { -0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, -0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, -0x86, 0xb0, 0xa2, 0xa3, 0xa7, 0x95, 0xb6, 0xdf, 0xae, 0xa9, 0x99, 0xb4, 0xa8, 0xbf, 0xc6, 0xd8, -0xbf, 0xb1, 0xbf, 0xbf, 0xa5, 0xb5, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xaa, 0xba, 0xbf, 0xe6, 0xf8, -0xbf, 0xa1, 0xac, 0xbf, 0x83, 0xbf, 0xbf, 0xab, 0xbb, 0x85, 0xa0, 0xc0, 0xc3, 0xd5, 0x8c, 0x9c, -0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xf7, 0xbf, 0xff, 0x9f, 0xbf, 0x80, 0x8b, 0x9b, 0xbf, 0xbf, -0x87, 0xb7, 0x82, 0x84, 0x89, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, -0xbf, 0xd2, 0xda, 0xdb, 0xd9, 0xbf, 0x88, 0x98, 0xaf, 0xbf, 0xbf, 0xbf, 0xb8, 0xbf, 0xbf, 0xbf -}; - -static char *buf = 0; -static int n_buf = 0; - -const char *Fl_Darwin_System_Driver::latin1_to_local(const char *t, int n) -{ - if (n==-1) n = (int)strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src++; - if (c>127) - *dst = latin2roman[c-128]; - else - *dst = c; - } - //*dst = 0; // this would be wrong! - return buf; -} - -const char *Fl_Darwin_System_Driver::local_to_latin1(const char *t, int n) -{ - if (n==-1) n = (int)strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src++; - if (c>127) - *dst++ = roman2latin[c-128]; - else - *dst++ = c; - } - //*dst = 0; // this would be wrong - return buf; -} - -// On Mac OS X, nothing need to be converted. We simply return the -// original pointer. -const char *Fl_Darwin_System_Driver::mac_roman_to_local(const char *t, int) -{ - return t; -} - -// On Mac OS X, nothing need to be converted. We simply return the -// original pointer. -const char *Fl_Darwin_System_Driver::local_to_mac_roman(const char *t, int) -{ - return t; -} - -Fl_Sys_Menu_Bar_Driver *Fl_Darwin_System_Driver::sys_menu_bar_driver() -{ - return Fl_MacOS_Sys_Menu_Bar_Driver::driver(); -} - -// Draw Mac-specific Fl_Tree open/close icons -void Fl_Darwin_System_Driver::tree_draw_expando_button(int x, int y, bool state, bool active) { - fl_color(active ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR); - if(state) fl_polygon(x + 3, y, x + 3, y + 11, x + 8, y + 5); // right arrow: ▶ - else fl_polygon(x, y + 3, x + 11, y + 3, x + 5, y + 8); // down arrow: ▼ -} -int Fl_Darwin_System_Driver::tree_connector_style() { - return FL_TREE_CONNECTOR_NONE; -} - - -int Fl_Darwin_System_Driver::filename_relative(char *to, int tolen, const char *dest_dir, const char *base_dir) { - return Fl_System_Driver::filename_relative_(to, tolen, dest_dir, base_dir, false); -} diff --git a/src/drivers/Darwin/fl_macOS_platform_init.cxx b/src/drivers/Darwin/fl_macOS_platform_init.cxx deleted file mode 100644 index fc18e90db..000000000 --- a/src/drivers/Darwin/fl_macOS_platform_init.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// -// macOS-specific code to initialize macOS support. -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "../Quartz/Fl_Quartz_Copy_Surface_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include "../Cocoa/Fl_Cocoa_Screen_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" -#include "../Quartz/Fl_Quartz_Image_Surface_Driver.H" - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) -{ - return new Fl_Quartz_Copy_Surface_Driver(w, h); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() -{ - return new Fl_Quartz_Graphics_Driver(); -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() -{ - return new Fl_Cocoa_Screen_Driver(); -} - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() -{ - return new Fl_Darwin_System_Driver(); -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ - return new Fl_Cocoa_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ - return new Fl_Quartz_Image_Surface_Driver(w, h, high_res, off); -} diff --git a/src/drivers/GDI/Fl_Font.H b/src/drivers/GDI/Fl_Font.H deleted file mode 100644 index 3e8b1296f..000000000 --- a/src/drivers/GDI/Fl_Font.H +++ /dev/null @@ -1,43 +0,0 @@ -// -// Font definitions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Two internal fltk data structures: -// -// Fl_Fontdesc: an entry into the fl_font() table. There is one of these -// for each fltk font number. -// -#ifndef FL_FONT_ -#define FL_FONT_ - -#include <config.h> -#include "../../Fl_Scalable_Graphics_Driver.H" - -class Fl_GDI_Font_Descriptor : public Fl_Font_Descriptor { -public: - HFONT fid; - int *width[64]; - TEXTMETRIC metr; - int angle; - FL_EXPORT Fl_GDI_Font_Descriptor(const char* fontname, Fl_Fontsize size); -# if HAVE_GL - char glok[64]; -# endif // HAVE_GL - virtual FL_EXPORT ~Fl_GDI_Font_Descriptor(); -}; - -extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H deleted file mode 100644 index 7eae4c2bc..000000000 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_GDI_COPY_SURFACE_DRIVER_H -#define FL_GDI_COPY_SURFACE_DRIVER_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> - -class Fl_GDI_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; -protected: - HDC oldgc; - HDC gc; - Fl_GDI_Copy_Surface_Driver(int w, int h); - ~Fl_GDI_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif // FL_GDI_COPY_SURFACE_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx deleted file mode 100644 index c44c0a77b..000000000 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_GDI_Copy_Surface_Driver.H" -#include <FL/platform.H> -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_Screen_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include <windows.h> - - -Fl_GDI_Copy_Surface_Driver::Fl_GDI_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - driver(Fl_Graphics_Driver::newMainGraphicsDriver()); - oldgc = (HDC)Fl_Surface_Device::surface()->driver()->gc(); - // exact computation of factor from screen units to EnhMetaFile units (0.01 mm) - HDC hdc = GetDC(NULL); - int hmm = GetDeviceCaps(hdc, HORZSIZE); - int hdots = GetDeviceCaps(hdc, HORZRES); - int vmm = GetDeviceCaps(hdc, VERTSIZE); - int vdots = GetDeviceCaps(hdc, VERTRES); - ReleaseDC(NULL, hdc); - float factorw = (100.f * hmm) / hdots; - float factorh = (100.f * vmm) / vdots; - // Global display scaling factor: 1, 1.25, 1.5, 1.75, etc... - float scaling = Fl_Graphics_Driver::default_driver().scale(); - driver()->scale(scaling); - RECT rect; rect.left = 0; rect.top = 0; rect.right = (LONG)((w*scaling) * factorw); rect.bottom = (LONG)((h*scaling) * factorh); - gc = CreateEnhMetaFile (NULL, NULL, &rect, NULL); - if (gc != NULL) { - SetTextAlign(gc, TA_BASELINE|TA_LEFT); - SetBkMode(gc, TRANSPARENT); - } -} - - -Fl_GDI_Copy_Surface_Driver::~Fl_GDI_Copy_Surface_Driver() { - if (oldgc == (HDC)Fl_Surface_Device::surface()->driver()->gc()) oldgc = NULL; - HENHMETAFILE hmf = CloseEnhMetaFile (gc); - if ( hmf != NULL ) { - if ( OpenClipboard (NULL) ){ - EmptyClipboard (); - // put first the vectorial form of the graphics in the clipboard - SetClipboardData (CF_ENHMETAFILE, hmf); - // then put a BITMAP version of the graphics in the clipboard - float scaling = driver()->scale(); - int W = Fl_Scalable_Graphics_Driver::floor(width, scaling), H = Fl_Scalable_Graphics_Driver::floor(height, scaling); - RECT rect = {0, 0, W, H}; - Fl_Image_Surface *surf = new Fl_Image_Surface(W, H); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); // draw white background - fl_rectf(0, 0, W, H); - PlayEnhMetaFile((HDC)surf->driver()->gc(), hmf, &rect); // draw metafile to offscreen buffer - SetClipboardData(CF_BITMAP, (HBITMAP)surf->offscreen()); - Fl_Surface_Device::pop_current(); - delete surf; - - CloseClipboard (); - } - DeleteEnhMetaFile(hmf); - } - DeleteDC(gc); - Fl_Surface_Device::surface()->driver()->gc(oldgc); - delete driver(); -} - - -void Fl_GDI_Copy_Surface_Driver::set_current() { - driver()->gc(gc); - fl_window = (HWND)1; - Fl_Surface_Device::set_current(); -} - - -void Fl_GDI_Copy_Surface_Driver::translate(int x, int y) { - ((Fl_GDI_Graphics_Driver*)driver())->translate_all(x, y); -} - - -void Fl_GDI_Copy_Surface_Driver::untranslate() { - ((Fl_GDI_Graphics_Driver*)driver())->untranslate_all(); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H deleted file mode 100644 index 336fa1ebc..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ /dev/null @@ -1,230 +0,0 @@ -// -// Definition of classes Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver.H - \brief Definition of Windows GDI graphics driver. - */ - -#ifndef FL_GDI_GRAPHICS_DRIVER_H -#define FL_GDI_GRAPHICS_DRIVER_H - -#include "../../Fl_Scalable_Graphics_Driver.H" -#include <windows.h> -#include <stdlib.h> -#include <config.h> - -#if USE_GDIPLUS -# if defined(_MSC_VER) -# include <objidl.h> -# else -# include <wtypes.h> // for PROPID needed with gcc 4.9.0 but not with 4.9.3 -# endif -# include <gdiplus.h> -#endif - -/** - \brief The Windows-specific graphics driver class. - - This class is implemented only on the Windows platform. -*/ -class Fl_GDI_Graphics_Driver : public Fl_Scalable_Graphics_Driver { -private: - BOOL alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch); - int depth; // to support translation - POINT *origins; // to support translation - void set_current_() FL_OVERRIDE; - void draw_fixed(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_fixed(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void make_unused_color_(unsigned char &r, unsigned char &g, unsigned char &b, int color_count, void **data) FL_OVERRIDE; -protected: - void draw_fixed(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void cache(Fl_RGB_Image *rgb) FL_OVERRIDE; - HDC gc_; - int numcount; - int counts[20]; - uchar *mask_bitmap_; - uchar **mask_bitmap() FL_OVERRIDE {return &mask_bitmap_;} - POINT *long_point; - int style_; -public: - Fl_GDI_Graphics_Driver(); - ~Fl_GDI_Graphics_Driver() FL_OVERRIDE; - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & NATIVE; } - char can_do_alpha_blending() FL_OVERRIDE; - void gc(void *ctxt) FL_OVERRIDE { gc_ = (HDC)ctxt; global_gc(); } - void *gc() FL_OVERRIDE {return gc_;} - - // --- bitmap stuff - static HBITMAP create_bitmask(int w, int h, const uchar *array); // NOT virtual - static HBITMAP calc_HBITMAP_mask(Fl_RGB_Image *mask); - void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE; - HBITMAP create_alphamask(int w, int h, int d, int ld, const uchar *array); - void draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE; - void draw_unscaled(int angle, const char *str, int n, int x, int y) FL_OVERRIDE; - void rtl_draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE; - void font_unscaled(Fl_Font face, Fl_Fontsize size) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) FL_OVERRIDE; - void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) FL_OVERRIDE; - void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) FL_OVERRIDE; - void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) FL_OVERRIDE; - void cache(Fl_Pixmap *img) FL_OVERRIDE; - void uncache_pixmap(fl_uintptr_t p) FL_OVERRIDE; - void cache(Fl_Bitmap *img) FL_OVERRIDE; - void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) FL_OVERRIDE; - double width_unscaled(const char *str, int n) FL_OVERRIDE; - double width_unscaled(unsigned int c) FL_OVERRIDE; - void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h) FL_OVERRIDE; - int height_unscaled() FL_OVERRIDE; - int descent_unscaled() FL_OVERRIDE; - Fl_Fontsize size_unscaled() FL_OVERRIDE; -#if ! defined(FL_DOXYGEN) - void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy); -#endif - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) FL_OVERRIDE; - void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h) FL_OVERRIDE; - Fl_Region XRectangleRegion(int x, int y, int w, int h) FL_OVERRIDE; - void XDestroyRegion(Fl_Region r) FL_OVERRIDE; - void translate_all(int x, int y); - void untranslate_all(void); - static HRGN scale_region(HRGN r, float f, Fl_GDI_Graphics_Driver *dr); - void scale(float f) FL_OVERRIDE; - float scale() {return Fl_Graphics_Driver::scale();} -protected: - void transformed_vertex0(float x, float y) FL_OVERRIDE; - void fixloop() FL_OVERRIDE; - void point(int x, int y) FL_OVERRIDE; - void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; - void rect_unscaled(int x, int y, int w, int h) FL_OVERRIDE; - void rectf_unscaled(int x, int y, int w, int h) FL_OVERRIDE; -#if USE_COLORMAP - void colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) FL_OVERRIDE; -#endif - void line_unscaled(int x, int y, int x1, int y1) FL_OVERRIDE; - void line_unscaled(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void xyline_unscaled(int x, int y, int x1) FL_OVERRIDE; - void yxline_unscaled(int x, int y, int y1) FL_OVERRIDE; - void loop_unscaled(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop_unscaled(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon_unscaled(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon_unscaled(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - // --- clipping - void push_clip(int x, int y, int w, int h) FL_OVERRIDE; - int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) FL_OVERRIDE; - int not_clipped(int x, int y, int w, int h) FL_OVERRIDE; - void restore_clip() FL_OVERRIDE; - Fl_Region scale_clip(float f) FL_OVERRIDE; - // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx - void begin_complex_polygon() FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_loop() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void gap() FL_OVERRIDE; - void ellipse_unscaled(double xt, double yt, double rx, double ry) FL_OVERRIDE; - void arc_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void line_style_unscaled(int style, int width, char* dashes) FL_OVERRIDE; - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void set_color(Fl_Color i, unsigned int c) FL_OVERRIDE; - void free_color(Fl_Color i, int overlay) FL_OVERRIDE; - Fl_Font set_fonts(const char *name) FL_OVERRIDE; - int get_font_sizes(Fl_Font fnum, int*& sizep) FL_OVERRIDE; - const char* get_font_name(Fl_Font fnum, int* ap) FL_OVERRIDE; - const char *font_name(int num) FL_OVERRIDE; - void font_name(int num, const char *name) FL_OVERRIDE; - void global_gc() FL_OVERRIDE; - void overlay_rect(int x, int y, int w , int h) FL_OVERRIDE; - void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE; - void* change_pen_width(int width) FL_OVERRIDE; - void reset_pen_width(void *data) FL_OVERRIDE; -}; - - -/** - The graphics driver used when printing on Windows. - - This class is implemented only on the Windows platform. - It is extremely similar to Fl_GDI_Graphics_Driver. -*/ -class Fl_GDI_Printer_Graphics_Driver : public Fl_GDI_Graphics_Driver { -private: - typedef BOOL (WINAPI* transparent_f_type) (HDC,int,int,int,int,HDC,int,int,int,int,UINT); - transparent_f_type TransparentBlt(); -public: - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & (NATIVE | PRINTER); } - void draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) FL_OVERRIDE; -}; - -#if USE_GDIPLUS - -class Fl_GDIplus_Graphics_Driver : public Fl_GDI_Graphics_Driver { - friend class Fl_Graphics_Driver; -private: - Gdiplus::Color gdiplus_color_; - Gdiplus::Pen *pen_; - Gdiplus::SolidBrush *brush_; - // The code below ensures that a connection to GDIplus is only made once, and that the - // matching connection shutdown is also done exactly once. - enum { - STATE_CLOSED = 0, // no connection, token is invalid - STATE_STARTUP, // attempt to start up, avoid recursions for whatever reason - STATE_OPEN, // connection was successful and the token is valid - STATE_SHUTDOWN // shutting down the gdi connection, avoid possible recursion - }; - static int gdiplus_state_; // reflect the state of the GDIplus driver connection - static ULONG_PTR gdiplus_token_; // the token that GDIplus gives to us -public: - Fl_GDIplus_Graphics_Driver(); - virtual ~Fl_GDIplus_Graphics_Driver(); - bool active; - static void shutdown(void); - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void line(int x, int y, int x1, int y1) FL_OVERRIDE; - void line(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void line_style(int style, int width, char* dashes) FL_OVERRIDE; - void arc_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void draw_circle(int x, int y, int d, Fl_Color c) FL_OVERRIDE; - void transformed_vertex(double xf, double yf) FL_OVERRIDE; - void vertex(double x,double y) FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_loop() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void circle(double x, double y, double r) FL_OVERRIDE; - void antialias(int state) FL_OVERRIDE; - int antialias() FL_OVERRIDE; -}; - -#endif // USE_GDIPLUS - -#endif // FL_GDI_GRAPHICS_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx deleted file mode 100644 index 97b3244d1..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx +++ /dev/null @@ -1,322 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_GDI_Graphics_Driver.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "../../Fl_Screen_Driver.H" -#include "Fl_Font.H" - -#if USE_GDIPLUS - -Fl_GDIplus_Graphics_Driver::Fl_GDIplus_Graphics_Driver() : Fl_GDI_Graphics_Driver() { - if (!fl_current_xmap) color(FL_BLACK); - pen_ = new Gdiplus::Pen(gdiplus_color_, 1); - pen_->SetLineJoin(Gdiplus::LineJoinRound); - pen_->SetStartCap(Gdiplus::LineCapFlat); - pen_->SetEndCap(Gdiplus::LineCapFlat); - brush_ = new Gdiplus::SolidBrush(gdiplus_color_); - active = true; -} - -Fl_GDIplus_Graphics_Driver::~Fl_GDIplus_Graphics_Driver() { - delete pen_; - delete brush_; -} - -void Fl_GDIplus_Graphics_Driver::antialias(int state) { - active = state; -} - -int Fl_GDIplus_Graphics_Driver::antialias() { - return active; -} - -void Fl_GDIplus_Graphics_Driver::draw_circle(int x, int y, int d, Fl_Color c) { - Fl_Graphics_Driver::draw_circle(x, y, d, c); -} - -int Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_CLOSED; -ULONG_PTR Fl_GDIplus_Graphics_Driver::gdiplus_token_ = 0; - -void Fl_GDIplus_Graphics_Driver::shutdown() { - if (gdiplus_state_ == STATE_OPEN) { - gdiplus_state_ = STATE_SHUTDOWN; - Gdiplus::GdiplusShutdown(Fl_GDIplus_Graphics_Driver::gdiplus_token_); - gdiplus_token_ = 0; - gdiplus_state_ = STATE_CLOSED; - } else if (gdiplus_state_ == STATE_CLOSED) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called, but driver is closed."); - } else if (gdiplus_state_ == STATE_SHUTDOWN) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called recursively."); - } else if (gdiplus_state_ == STATE_STARTUP) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called while driver is starting up."); - } -} -#endif - -// Code used to switch output to an off-screen window. See macros in -// win32.H which save the old state in local variables. - -typedef struct { BYTE a; BYTE b; BYTE c; BYTE d; } FL_BLENDFUNCTION; -typedef BOOL (WINAPI* fl_alpha_blend_func) -(HDC,int,int,int,int,HDC,int,int,int,int,FL_BLENDFUNCTION); -static fl_alpha_blend_func fl_alpha_blend = NULL; -static FL_BLENDFUNCTION blendfunc = { 0, 0, 255, 1}; - -/* Reference to the current device context - For back-compatibility only. The preferred procedure to get this reference is - Fl_Surface_Device::surface()->driver()->gc(). - */ -HDC fl_gc = 0; - - -HDC fl_win32_gc() { return fl_gc; } - - -Fl_GDI_Graphics_Driver::Fl_GDI_Graphics_Driver() { - mask_bitmap_ = NULL; - gc_ = NULL; - long_point = NULL; - depth = -1; - origins = NULL; - style_ = FL_SOLID; -} - -Fl_GDI_Graphics_Driver::~Fl_GDI_Graphics_Driver() { - if (long_point) free(long_point); - delete[] origins; -} - -void Fl_GDI_Graphics_Driver::global_gc() -{ - fl_gc = (HDC)gc(); -} - -/* - * This function checks if the version of Windows that we - * curently run on supports alpha blending for bitmap transfers - * and finds the required function if so. - */ -char Fl_GDI_Graphics_Driver::can_do_alpha_blending() { - static char been_here = 0; - static char can_do = 0; - // do this test only once - if (been_here) return can_do; - been_here = 1; - // load the library that implements alpha blending - HMODULE hMod = LoadLibrary("MSIMG32.DLL"); - // give up if that doesn't exist (Win95?) - if (!hMod) return 0; - // now find the blending function inside that dll - fl_alpha_blend = (fl_alpha_blend_func)GetProcAddress(hMod, "AlphaBlend"); - // give up if we can't find it (Win95) - if (!fl_alpha_blend) return 0; - // we have the call, but does our display support alpha blending? - // get the desktop's device context - HDC dc = GetDC(0L); - if (!dc) return 0; - // check the device capabilities flags. However GetDeviceCaps - // does not return anything useful, so we have to do it manually: - - HBITMAP bm = CreateCompatibleBitmap(dc, 1, 1); - HDC new_gc = CreateCompatibleDC(dc); - int save = SaveDC(new_gc); - SelectObject(new_gc, bm); - /*COLORREF set = */ SetPixel(new_gc, 0, 0, 0x01010101); - BOOL alpha_ok = fl_alpha_blend(dc, 0, 0, 1, 1, new_gc, 0, 0, 1, 1, blendfunc); - RestoreDC(new_gc, save); - DeleteDC(new_gc); - DeleteObject(bm); - ReleaseDC(0L, dc); - - if (alpha_ok) can_do = 1; - return can_do; -} - -HDC fl_makeDC(HBITMAP bitmap) { - HDC new_gc = CreateCompatibleDC((HDC)Fl_Graphics_Driver::default_driver().gc()); - SetTextAlign(new_gc, TA_BASELINE|TA_LEFT); - SetBkMode(new_gc, TRANSPARENT); -#if USE_COLORMAP - if (fl_palette) SelectPalette(new_gc, fl_palette, FALSE); -#endif - SelectObject(new_gc, bitmap); - return new_gc; -} - -void Fl_GDI_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) { - x = int(x * scale()); y = int(y * scale()); w = int(w * scale()); h = int(h * scale()); - srcx = int(srcx * scale()); srcy = int(srcy * scale()); - if (srcx < 0) {w += srcx; x -= srcx; srcx = 0;} - if (srcy < 0) {h += srcy; y -= srcy; srcy = 0;} - int off_width, off_height; - Fl::screen_driver()->offscreen_size(bitmap, off_width, off_height); - if (srcx + w >= off_width) {w = off_width - srcx;} - if (srcy + h >= off_height) {h = off_height - srcy;} - if (w <= 0 || h <= 0) return; - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (HBITMAP)bitmap); - BitBlt(gc_, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); - RestoreDC(new_gc, save); - DeleteDC(new_gc); -} - -void Fl_GDI_Printer_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) { - Fl_Graphics_Driver::copy_offscreen(x, y, w, h, bitmap, srcx, srcy); -} - -BOOL Fl_GDI_Graphics_Driver::alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch) { - return fl_alpha_blend(gc_, x, y, w, h, src_gc, srcx, srcy, srcw, srch, blendfunc); -} - -#if ! defined(FL_DOXYGEN) -void Fl_GDI_Graphics_Driver::copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, bitmap); - BOOL alpha_ok = 0; - // first try to alpha blend - if ( fl_can_do_alpha_blending() ) { - alpha_ok = alpha_blend_(x, y, w, h, new_gc, srcx, srcy, w, h); - } - // if that failed (it shouldn't), still copy the bitmap over, but now alpha is 1 - if (!alpha_ok) { - BitBlt(gc_, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); - } - RestoreDC(new_gc, save); - DeleteDC(new_gc); -} - -void Fl_GDI_Graphics_Driver::translate_all(int x, int y) { - const int stack_height = 10; - if (depth == -1) { - origins = new POINT[stack_height]; - depth = 0; - } - if (depth >= stack_height) { - Fl::warning("Fl_Copy/Image_Surface: translate stack overflow!"); - depth = stack_height - 1; - } - GetWindowOrgEx((HDC)gc(), origins+depth); - SetWindowOrgEx((HDC)gc(), int(origins[depth].x - x*scale()), int(origins[depth].y - y*scale()), NULL); - depth++; -} - -void Fl_GDI_Graphics_Driver::untranslate_all() { - if (depth > 0) depth--; - SetWindowOrgEx((HDC)gc(), origins[depth].x, origins[depth].y, NULL); -} -#endif - -void Fl_GDI_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H) { - HRGN R = (HRGN)XRectangleRegion(X, Y, W, H); - CombineRgn((HRGN)r, (HRGN)r, R, RGN_OR); - XDestroyRegion(R); -} - -void Fl_GDI_Graphics_Driver::transformed_vertex0(float x, float y) { - if (!n || x != long_point[n-1].x || y != long_point[n-1].y) { - if (n >= p_size) { - p_size = long_point ? 2*p_size : 16; - long_point = (POINT*)realloc((void*)long_point, p_size*sizeof(*long_point)); - } - long_point[n].x = LONG(x); - long_point[n].y = LONG(y); - n++; - } -} - -void Fl_GDI_Graphics_Driver::fixloop() { // remove equal points from closed path - while (n>2 && long_point[n-1].x == long_point[0].x && long_point[n-1].y == long_point[0].y) n--; -} - -Fl_Region Fl_GDI_Graphics_Driver::XRectangleRegion(int x, int y, int w, int h) { - if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) return CreateRectRgn(x,y,x+w,y+h); - // because rotation may apply, the rectangle becomes a polygon in device coords - POINT pt[4] = { {x, y}, {x + w, y}, {x + w, y + h}, {x, y + h} }; - LPtoDP((HDC)fl_graphics_driver->gc(), pt, 4); - return CreatePolygonRgn(pt, 4, ALTERNATE); -} - -void Fl_GDI_Graphics_Driver::XDestroyRegion(Fl_Region r) { - DeleteObject((HRGN)r); -} - - -void Fl_GDI_Graphics_Driver::scale(float f) { - if (f != scale()) { - size_ = 0; - Fl_Graphics_Driver::scale(f); - color(FL_BLACK); - line_style(FL_SOLID); // scale also default line width - } -} - - -/* Rescale region r with factor f and returns the scaled region. - Region r is returned unchanged if r is null or f is 1. - */ -HRGN Fl_GDI_Graphics_Driver::scale_region(HRGN r, float f, Fl_GDI_Graphics_Driver *dr) { - if (r && f != 1) { - DWORD size = GetRegionData(r, 0, NULL); - RGNDATA *pdata = (RGNDATA*)malloc(size); - GetRegionData(r, size, pdata); - POINT pt = {0, 0}; - if (dr && dr->depth >= 1) { // account for translation - GetWindowOrgEx((HDC)dr->gc(), &pt); - pt.x = int(pt.x * (f - 1)); - pt.y = int(pt.y * (f - 1)); - } - RECT *rects = (RECT*)&(pdata->Buffer); - for (DWORD i = 0; i < pdata->rdh.nCount; i++) { - int x = Fl_Scalable_Graphics_Driver::floor(rects[i].left, f) + pt.x; - int y = Fl_Scalable_Graphics_Driver::floor(rects[i].top, f) + pt.y; - RECT R2; - R2.left = x; - R2.top = y; - R2.right = Fl_Scalable_Graphics_Driver::floor(rects[i].right, f) + pt.x - x + R2.left; - R2.bottom = Fl_Scalable_Graphics_Driver::floor(rects[i].bottom, f) + pt.y - y + R2.top; - rects[i] = R2; - } - r = ExtCreateRegion(NULL, size, pdata); - free(pdata); - } - return r; -} - - -Fl_Region Fl_GDI_Graphics_Driver::scale_clip(float f) { - HRGN r = (HRGN)rstack[rstackptr]; - HRGN r2 = scale_region(r, f, this); - return (r == r2 ? NULL : (rstack[rstackptr] = r2, r)); -} - -void Fl_GDI_Graphics_Driver::set_current_() { - restore_clip(); -} - -void Fl_GDI_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) -{ - float s = scale(); - width = (s == int(s) ? width * int(s) : floor(width+1)); - height = (s == int(s) ? height * int(s) : floor(height+1)); - cache_size_finalize(img, width, height); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx deleted file mode 100644 index 0c1e90064..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx +++ /dev/null @@ -1,89 +0,0 @@ -// -// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_arci.cxx - \brief Utility functions for drawing circles using integers -*/ - -// "integer" circle drawing functions. These draw the limited -// circle types provided by X and NT graphics. The advantage of -// these is that small ones draw quite nicely (probably due to stored -// hand-drawn bitmaps of small circles!) and may be implemented by -// hardware and thus are fast. - -#include "Fl_GDI_Graphics_Driver.H" - -#include <FL/math.h> -#include <FL/platform.H> - -void Fl_GDI_Graphics_Driver::arc_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - w++; h++; - int xa = int( x+w/2+int(w*cos(a1/180.0*M_PI)) ); - int ya = int( y+h/2-int(h*sin(a1/180.0*M_PI)) ); - int xb = int( x+w/2+int(w*cos(a2/180.0*M_PI)) ); - int yb = int( y+h/2-int(h*sin(a2/180.0*M_PI)) ); - if (fabs(a1 - a2) < 90) { - if (xa == xb && ya == yb) SetPixel(gc_, xa, ya, fl_RGB()); - else Arc(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); - } else Arc(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); -} - -void Fl_GDI_Graphics_Driver::pie_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (a1 == a2) return; - x++; y++; w--; h--; - if (scale() >= 3) {x++; y++; w-=2; h-=2;} - int xa = int( x+w/2+int(w*cos(a1/180.0*M_PI)) ); - int ya = int( y+h/2-int(h*sin(a1/180.0*M_PI)) ); - int xb = int( x+w/2+int(w*cos(a2/180.0*M_PI)) ); - int yb = int( y+h/2-int(h*sin(a2/180.0*M_PI)) ); - SelectObject(gc_, fl_brush()); - if (fabs(a1 - a2) < 90) { - if (xa == xb && ya == yb) { - MoveToEx(gc_, int(x+w/2), int(y+h/2), 0L); - LineTo(gc_, xa, ya); - SetPixel(gc_, xa, ya, fl_RGB()); - } else Pie(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); - } else Pie(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::arc_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (!active) return Fl_GDI_Graphics_Driver::arc_unscaled(x, y, w, h, a1, a2); - Gdiplus::Graphics graphics_(gc_); - pen_->SetColor(gdiplus_color_); - Gdiplus::REAL oldw = pen_->GetWidth(); - Gdiplus::REAL new_w = (line_width_ <= scale() ? 1 : line_width_) * scale(); - pen_->SetWidth(new_w); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawArc(pen_, x, y, w, h, Gdiplus::REAL(-a1), Gdiplus::REAL(a1-a2)); - pen_->SetWidth(oldw); -} - -void Fl_GDIplus_Graphics_Driver::pie_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (!active) return Fl_GDI_Graphics_Driver::pie_unscaled(x, y, w, h, a1, a2); - Gdiplus::Graphics graphics_(gc_); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPie(brush_, x, y, w, h, Gdiplus::REAL(-a1), Gdiplus::REAL(a1-a2)); -} - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx deleted file mode 100644 index c05a255d0..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx +++ /dev/null @@ -1,259 +0,0 @@ -// -// MSWidnows' GDI color functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// The fltk "colormap". This allows ui colors to be stored in 8-bit -// locations, and provides a level of indirection so that global color -// changes can be made. Not to be confused with the X colormap, which -// I try to hide completely. - -#include "Fl_GDI_Graphics_Driver.H" - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -// FIXME: all the global functions in this file should probably be protected -// members of the driver class. Starting with 1.4 we will allow multiple drivers -// to co-exist, creating conflicts with multipe mapping. - -// FIXME: maybe we can forget about color mapping and assume RGB? -// FIXME: ... but for now we still have it ... -extern unsigned fl_cmap[256]; // defined in fl_color.cxx - -// Translations to win32 data structures: -Fl_XMap fl_xmap[256]; - -Fl_XMap* fl_current_xmap; - -HPALETTE fl_palette; -static HGDIOBJ tmppen=0; -static HPEN savepen=0; - -void fl_cleanup_pens(void) { - for (int i=0; i<256; i++) { - if (fl_xmap[i].pen) DeleteObject(fl_xmap[i].pen); - } -} - -void fl_save_pen(void) { - if(!tmppen) tmppen = CreatePen(PS_SOLID, 1, 0); - savepen = (HPEN)SelectObject((HDC)fl_graphics_driver->gc(), tmppen); -} - -void fl_restore_pen(void) { - if (savepen) SelectObject((HDC)fl_graphics_driver->gc(), savepen); - DeleteObject(tmppen); - tmppen = 0; - savepen = 0; -} - -static void clear_xmap(Fl_XMap& xmap) { - if (xmap.pen) { - HDC gc = (HDC)fl_graphics_driver->gc(); - HGDIOBJ tmppen = GetStockObject(BLACK_PEN); - HGDIOBJ oldpen = SelectObject(gc, tmppen); // Push out the current pen of the gc - if(oldpen != xmap.pen) SelectObject(gc, oldpen); // Put it back if it is not the one we are about to delete - DeleteObject((HGDIOBJ)(xmap.pen)); - xmap.pen = 0; - xmap.brush = -1; - } -} - -static void set_xmap(Fl_XMap& xmap, COLORREF c, int lw) { - xmap.rgb = c; - if (xmap.pen) { - HDC gc = (HDC)fl_graphics_driver->gc(); - HGDIOBJ oldpen = SelectObject(gc,GetStockObject(BLACK_PEN)); // replace current pen with safe one - if (oldpen != xmap.pen)SelectObject(gc,oldpen); // if old one not xmap.pen, need to put it back - DeleteObject(xmap.pen); // delete pen - } -// xmap.pen = CreatePen(PS_SOLID, 1, xmap.rgb); // get a pen into xmap.pen - LOGBRUSH penbrush = {BS_SOLID, xmap.rgb, 0}; - xmap.pen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_ROUND, lw, &penbrush, 0, 0); - xmap.pwidth = lw; - xmap.brush = -1; -} - -void Fl_GDI_Graphics_Driver::color(Fl_Color i) { - if (i & 0xffffff00) { - unsigned rgb = (unsigned)i; - color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); - } else { - Fl_Graphics_Driver::color(i); - Fl_XMap &xmap = fl_xmap[i]; - int tw = line_width_ ? line_width_ : int(scale()); if (!tw) tw = 1; - if (!xmap.pen || xmap.pwidth != tw) { -#if USE_COLORMAP - if (fl_palette) { - set_xmap(xmap, PALETTEINDEX(i), tw); - } else { -#endif - unsigned c = fl_cmap[i]; - set_xmap(xmap, RGB(uchar(c>>24), uchar(c>>16), uchar(c>>8)), tw); -#if USE_COLORMAP - } -#endif - } - fl_current_xmap = ⟼ - SelectObject(gc_, (HGDIOBJ)(xmap.pen)); - } -} - -void Fl_GDI_Graphics_Driver::color(uchar r, uchar g, uchar b) { - static Fl_XMap xmap; - COLORREF c = RGB(r,g,b); - Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); - int tw = line_width_ ? line_width_ : int(scale()); if (!tw) tw = 1; - if (!xmap.pen || c != xmap.rgb || tw != xmap.pwidth) { - clear_xmap(xmap); - set_xmap(xmap, c, tw); - } - fl_current_xmap = ⟼ - SelectObject(gc_, (HGDIOBJ)(xmap.pen)); -} - -HBRUSH fl_brush() { - return fl_brush_action(0); -} - -HBRUSH fl_brush_action(int action) { - Fl_XMap *xmap = fl_current_xmap; - HDC gc = (HDC)fl_graphics_driver->gc(); - // Wonko: we use some statistics to cache only a limited number - // of brushes: -#define FL_N_BRUSH 16 - static struct Fl_Brush { - HBRUSH brush; - unsigned short usage; - Fl_XMap* backref; - } brushes[FL_N_BRUSH]; - - if (action) { - SelectObject(gc, GetStockObject(BLACK_BRUSH)); // Load stock object - for (int i=0; i<FL_N_BRUSH; i++) { - if (brushes[i].brush) - DeleteObject(brushes[i].brush); // delete all brushes in array - } - return NULL; - } - - int i = xmap->brush; // find the associated brush - if (i != -1) { // if the brush was allready allocated - if (brushes[i].brush == NULL) goto CREATE_BRUSH; - if ( (++brushes[i].usage) > 32000 ) { // keep a usage statistic - for (int j=0; j<FL_N_BRUSH; j++) { - if (brushes[j].usage>16000) - brushes[j].usage -= 16000; - else - brushes[j].usage = 0; - } - } - return brushes[i].brush; - } else { - int umin = 32000, imin = 0; - for (i=0; i<FL_N_BRUSH; i++) { - if (brushes[i].brush == NULL) goto CREATE_BRUSH; - if (brushes[i].usage<umin) { - umin = brushes[i].usage; - imin = i; - } - } - i = imin; - HGDIOBJ tmpbrush = GetStockObject(BLACK_BRUSH); // get a stock brush - HGDIOBJ oldbrush = SelectObject(gc,tmpbrush); // load in into current context - if (oldbrush != brushes[i].brush) SelectObject(gc,oldbrush); // reload old one - DeleteObject(brushes[i].brush); // delete the one in list - brushes[i].brush = NULL; - brushes[i].backref->brush = -1; - } -CREATE_BRUSH: - brushes[i].brush = CreateSolidBrush(xmap->rgb); - brushes[i].usage = 0; - brushes[i].backref = xmap; - xmap->brush = i; - return brushes[i].brush; -} - -void Fl_GDI_Graphics_Driver::free_color(Fl_Color i, int overlay) { - if (overlay) return; // do something about GL overlay? - clear_xmap(fl_xmap[i]); -} - -void Fl_GDI_Graphics_Driver::set_color(Fl_Color i, unsigned c) { - if (fl_cmap[i] != c) { - clear_xmap(fl_xmap[i]); - fl_cmap[i] = c; - } -} - -#if USE_COLORMAP - -// 'fl_select_palette()' - Make a color palette for 8-bit displays if necessary -// Thanks to Michael Sweet @ Easy Software Products for this - -HPALETTE -fl_select_palette(void) -{ - static char beenhere; - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!beenhere) { - beenhere = 1; - - int nColors = GetDeviceCaps(gc, SIZEPALETTE); - if (nColors <= 0 || nColors > 256) return NULL; - // this will try to work on < 256 color screens, but will probably - // come out quite badly. - - // I lamely try to get this variable-sized object allocated on stack: - ulong foo[(sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY))/sizeof(ulong)+1]; - LOGPALETTE *pPal = (LOGPALETTE*)foo; - - pPal->palVersion = 0x300; - pPal->palNumEntries = nColors; - - // Build 256 colors from the standard FLTK colormap... - - for (int i = 0; i < nColors; i ++) { - pPal->palPalEntry[i].peRed = (fl_cmap[i] >> 24) & 255; - pPal->palPalEntry[i].peGreen = (fl_cmap[i] >> 16) & 255; - pPal->palPalEntry[i].peBlue = (fl_cmap[i] >> 8) & 255; - pPal->palPalEntry[i].peFlags = 0; - }; - - // Create the palette: - fl_palette = CreatePalette(pPal); - } - if (fl_palette) { - SelectPalette(gc, fl_palette, FALSE); - RealizePalette(gc); - } - return fl_palette; -} - -#endif - -#if USE_GDIPLUS -void Fl_GDIplus_Graphics_Driver::color(uchar r, uchar g, uchar b) { - Fl_GDI_Graphics_Driver::color(r, g, b); - gdiplus_color_.SetFromCOLORREF(fl_RGB()); -} - -void Fl_GDIplus_Graphics_Driver::color(Fl_Color i) { - Fl_GDI_Graphics_Driver::color(i); - gdiplus_color_.SetFromCOLORREF(fl_RGB()); -} -#endif // USE_GDIPLUS diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx deleted file mode 100644 index 49111f10e..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx +++ /dev/null @@ -1,678 +0,0 @@ -// -// Windows font utilities for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> - -#ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif -/* We require Windows 2000 features such as GetGlyphIndices */ -#if !defined(WINVER) || (WINVER < 0x0500) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0500 -#endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0500 -#endif - -// Select fonts from the FLTK font table. -#include "Fl_GDI_Graphics_Driver.H" -#include "../../flstring.h" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include "Fl_Font.H" - -#include <stdio.h> -#include <stdlib.h> -#include <FL/fl_string_functions.h> - -// This function fills in the FLTK font table with all the fonts that -// are found on the X server. It tries to place the fonts into families -// and to sort them so the first 4 in a family are normal, bold, italic, -// and bold italic. -#include <FL/fl_utf8.h> -#ifdef __CYGWIN__ -# include <wchar.h> -#endif - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 - -// turn a stored font name into a pretty name: -const char* Fl_GDI_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) { - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - const char* p = f->name; - if (!p || !*p) {if (ap) *ap = 0; return "";} - int type; - switch (*p) { - case 'B': type = FL_BOLD; break; - case 'I': type = FL_ITALIC; break; - case 'P': type = FL_BOLD | FL_ITALIC; break; - default: type = 0; break; - } - strlcpy(f->fontname, p+1, ENDOFBUFFER); - if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); - if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - -static int fl_free_font = FL_FREE_FONT; - -// helper function for `enumcbw()` to avoid code repetition -// input: -// ft: font "type", i.e. ' ', 'B', 'I', or 'P' -// fn: font name whose first byte is overwritten and then stored - -static void set_font_name(const char ft, char *fn) { - fn[0] = ft; - Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(fn)); -} - -// Callback for EnumFontFamiliesW(): -// return 1 to continue, 0 to stop enumeration - -static int CALLBACK -enumcbw(CONST LOGFONTW *lpelf, - CONST TEXTMETRICW * /* lpntm */, - DWORD /* FontType */, - LPARAM p) { - if (!p && lpelf->lfCharSet != ANSI_CHARSET) return 1; - char *fn = nullptr; // FLTK font name - unsigned lw = (unsigned)wcslen(lpelf->lfFaceName); - unsigned dstlen = fl_utf8fromwc(fn, 0, (wchar_t*)lpelf->lfFaceName, lw); // measure the string - fn = (char*)malloc((size_t)dstlen + 2); // "?" + name + NUL - if (!fn) return 1; - fn[0] = ' '; - dstlen = fl_utf8fromwc(fn+1, dstlen+1, (wchar_t*)lpelf->lfFaceName, lw); // convert the string - fn[dstlen + 1] = 0; - // skip if it is one of our built-in fonts - for (int i = 0; i < FL_FREE_FONT; i++) { - if (!strcmp(Fl::get_font_name((Fl_Font)i), fn+1)) { - free(fn); - return 1; - } - } - set_font_name(' ', fn); - if (lpelf->lfWeight <= 400) - set_font_name('B', fn); - set_font_name('I', fn); - if (lpelf->lfWeight <= 400) - set_font_name('P', fn); - free(fn); - return 1; -} /* enumcbw */ - -Fl_Font Fl_GDI_Graphics_Driver::set_fonts(const char* xstarname) { - HDC gc = (HDC)fl_graphics_driver->gc(); - if (fl_free_font == FL_FREE_FONT) {// if not already been called - if (!gc) gc = fl_GetDC(0); - - EnumFontFamiliesW(gc, NULL, (FONTENUMPROCW)enumcbw, xstarname != 0); - - } - return (Fl_Font)fl_free_font; -} - - -static int nbSize; -static int cyPerInch; -static int sizes[128]; -static int CALLBACK - -EnumSizeCbW(CONST LOGFONTW * /*lpelf*/, - CONST TEXTMETRICW *lpntm, - DWORD fontType, - LPARAM /*p*/) { - if ((fontType & RASTER_FONTTYPE) == 0) { - sizes[0] = 0; - nbSize = 1; - - // Scalable font - return 0; - } - - int add = lpntm->tmHeight - lpntm->tmInternalLeading; - add = MulDiv(add, 72, cyPerInch); - - int start = 0; - while ((start < nbSize) && (sizes[start] < add)) { - start++; - } - - if ((start < nbSize) && (sizes[start] == add)) { - return 1; - } - - for (int i=nbSize; i>start; i--) sizes[i] = sizes[i - 1]; - - sizes[start] = add; - nbSize++; - - // Stop enum if buffer overflow - return nbSize < 128; -} - - -int Fl_GDI_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { - nbSize = 0; - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!gc) gc = fl_GetDC(0); - cyPerInch = GetDeviceCaps(gc, LOGPIXELSY); - if (cyPerInch < 1) cyPerInch = 1; - -// int l = fl_utf_nb_char((unsigned char*)s->name+1, strlen(s->name+1)); -// unsigned short *b = (unsigned short*) malloc((l + 1) * sizeof(short)); -// fl_utf2unicode((unsigned char*)s->name+1, l, (wchar_t*)b); - const char *nm = (const char*)s->name+1; - size_t len = strlen(s->name+1); - unsigned l = fl_utf8toUtf16(nm, (unsigned) len, NULL, 0); // Pass NULL to query length required - unsigned short *b = (unsigned short*) malloc((l + 1) * sizeof(short)); - l = fl_utf8toUtf16(nm, (unsigned) len, b, (l+1)); // Now do the conversion - b[l] = 0; - EnumFontFamiliesW(gc, (WCHAR*)b, (FONTENUMPROCW)EnumSizeCbW, 0); - free(b); - - sizep = sizes; - return nbSize; -} - -const char *Fl_GDI_Graphics_Driver::font_name(int num) { - return fl_fonts[num].name; -} - -void Fl_GDI_Graphics_Driver::font_name(int num, const char *name) { - Fl_Fontdesc *s = fl_fonts + num; - if (s->name) { - if (!strcmp(s->name, name)) {s->name = name; return;} - for (Fl_Font_Descriptor* f = s->first; f;) { - Fl_Font_Descriptor* n = f->next; delete f; f = n; - } - s->first = 0; - } - s->name = name; - s->fontname[0] = 0; - s->first = 0; -} - - -static int fl_angle_ = 0; -// Unicode string buffer -static unsigned short *wstr = NULL; -static int wstr_len = 0; - -#ifndef FL_DOXYGEN -Fl_GDI_Font_Descriptor::Fl_GDI_Font_Descriptor(const char* name, Fl_Fontsize fsize) : Fl_Font_Descriptor(name,fsize) { - int weight = FW_NORMAL; - int italic = 0; - switch (*name++) { - case 'I': italic = 1; break; - case 'P': italic = 1; - case 'B': weight = FW_BOLD; break; - case ' ': break; - default: name--; - } - int wn = fl_utf8toUtf16(name, (unsigned int)strlen(name), wstr, wstr_len); - if (wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(name, (unsigned int)strlen(name), wstr, wstr_len); - } - - fid = CreateFontW( - -fsize, // negative makes it use "char size" - 0, // logical average character width - fl_angle_*10, // angle of escapement - fl_angle_*10, // base-line orientation angle - weight, - italic, - FALSE, // underline attribute flag - FALSE, // strikeout attribute flag - DEFAULT_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS,// clipping precision - DEFAULT_QUALITY, // output quality - DEFAULT_PITCH, // pitch and family - (LPCWSTR)wstr // pointer to typeface name string - ); - angle = fl_angle_; - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!gc) gc = fl_GetDC(0); - SelectObject(gc, fid); - GetTextMetrics(gc, &metr); -// BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar); -// ...would be the right call, but is not implemented into Window95! (WinNT?) - //GetCharWidth(fl_gc, 0, 255, width); - int i; - memset(width, 0, 64 * sizeof(int*)); -#if HAVE_GL - for (i = 0; i < 64; i++) glok[i] = 0; -#endif - size = fsize; -} - -Fl_GDI_Font_Descriptor::~Fl_GDI_Font_Descriptor() { -#if HAVE_GL -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -#endif - if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); - DeleteObject(fid); - for (int i = 0; i < 64; i++) { - if ( width[i] ) free(width[i]); - } -} - -//////////////////////////////////////////////////////////////// - -// WARNING: if you add to this table, you must redefine FL_FREE_FONT -// in Enumerations.H & recompile!! -static Fl_Fontdesc built_in_table[] = { - {" Microsoft Sans Serif"}, - {"BMicrosoft Sans Serif"}, - {"IMicrosoft Sans Serif"}, - {"PMicrosoft Sans Serif"}, -{" Courier New"}, -{"BCourier New"}, -{"ICourier New"}, -{"PCourier New"}, -{" Times New Roman"}, -{"BTimes New Roman"}, -{"ITimes New Roman"}, -{"PTimes New Roman"}, -{" Symbol"}, -{" Terminal"}, -{"BTerminal"}, -{" Wingdings"}, -}; - -Fl_Fontdesc* fl_fonts = built_in_table; - -static Fl_GDI_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size, int angle) { - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_GDI_Font_Descriptor* f; - for (f = (Fl_GDI_Font_Descriptor*)s->first; f; f = (Fl_GDI_Font_Descriptor*)f->next) - if (f->size == size && f->angle == angle) return f; - f = new Fl_GDI_Font_Descriptor(s->name, size); - f->next = s->first; - s->first = f; - return f; -} - -//////////////////////////////////////////////////////////////// -// Public interface: - -static void fl_font(Fl_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) { - if (fnum==-1) { // just make sure that we will load a new font next time - fl_angle_ = 0; - driver->Fl_Graphics_Driver::font(0, 0); - return; - } - if (fnum == driver->Fl_Graphics_Driver::font() && size == ((Fl_GDI_Graphics_Driver*)driver)->size_unscaled() && angle == fl_angle_) return; - fl_angle_ = angle; - driver->Fl_Graphics_Driver::font(fnum, size); - driver->font_descriptor( find(fnum, size, angle) ); -} - -void Fl_GDI_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { - fl_font(this, fnum, size, 0); -} - -int Fl_GDI_Graphics_Driver::height_unscaled() { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent); - else return -1; -} - -int Fl_GDI_Graphics_Driver::descent_unscaled() { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (fl_fontsize) return fl_fontsize->metr.tmDescent; - else return -1; -} - -Fl_Fontsize Fl_GDI_Graphics_Driver::size_unscaled() { - if (font_descriptor()) return size_; - return -1; -} - -double Fl_GDI_Graphics_Driver::width_unscaled(const char* c, int n) { - if (n == 0) return 0; - int len1 = fl_utf8len1(*c); - if (n > len1 && len1 > 0) { // a text with several codepoints: compute its typographical width - int wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - if (wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - } - HDC gc2 = gc_; - HWND hWnd; - if (!gc2) { - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - SelectObject(gc2, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - SIZE s; - GetTextExtentPoint32W(gc2, (WCHAR*)wstr, wn, &s); - if (gc2 && gc2 != gc_) ReleaseDC(hWnd, gc2); - return (double)s.cx; - } - int i = 0; - if (!font_descriptor()) return -1.0; - double w = 0.0; - char *end = (char *)&c[n]; - while (i < n) { - unsigned int ucs; - int l; - ucs = fl_utf8decode((const char*)(c + i), end, &l); -// if (l < 1) l = 1; - i += l; - if (!fl_nonspacing(ucs)) { - w += width_unscaled(ucs); - } - } - return w; -} - -double Fl_GDI_Graphics_Driver::width_unscaled(unsigned int c) { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - unsigned int r; - SIZE s; - // Special Case Handling of Unicode points over U+FFFF. - // The logic (below) computes a lookup table for char widths - // on-the-fly, but the table only covers codepoints up to - // U+FFFF, which covers the basic multilingual plane, but - // not any higher plane, or glyphs that require surrogate-pairs - // to encode them in WinXX, which is UTF16. - // This code assumes that these glyphs are rarely used and simply - // measures them explicitly if they occur - This will be slow... - if(c > 0x0000FFFF) { // UTF16 surrogate pair is needed - if (!gc_) { // We have no valid gc, so nothing to measure - bail out - return 0.0; - } - int cc; // cell count - unsigned short u16[4]; // Array for UTF16 representation of c - // Creates a UTF16 string from a UCS code point. - cc = fl_ucs_to_Utf16(c, u16, 4); - // Make sure the current font is selected before we make the measurement - SelectObject(gc_, fl_fontsize->fid); - // measure the glyph width - GetTextExtentPoint32W(gc_, (WCHAR*)u16, cc, &s); - return (double)s.cx; - } - // else - this falls through to the lookup-table for glyph widths - // in the basic multilingual plane - r = (c & 0xFC00) >> 10; - if (!fl_fontsize->width[r]) { - fl_fontsize->width[r] = (int*) malloc(sizeof(int) * 0x0400); - for (int i = 0; i < 0x0400; i++) fl_fontsize->width[r][i] = -1; - } else { - if ( fl_fontsize->width[r][c&0x03FF] >= 0 ) { // already cached - return (double) fl_fontsize->width[r][c & 0x03FF]; - } - } - unsigned short ii = r * 0x400; - // The following code makes a best effort attempt to obtain a valid fl_gc. - // If no fl_gc is available at the time we call fl_width(), then we first - // try to obtain a gc from the first fltk window. - // If that is null then we attempt to obtain the gc from the current screen - // using (GetDC(NULL)). - // This should resolve STR #2086 - HDC gc2 = gc_; - HWND hWnd = 0; - if (!gc2) { // We have no valid gc, try and obtain one - // Use our first fltk window, or fallback to using the screen via GetDC(NULL) - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - if (!gc2) Fl::fatal("Invalid graphic context: fl_width() failed because no valid HDC was found!"); - SelectObject(gc2, fl_fontsize->fid); - ii += c &0x03FF; - GetTextExtentPoint32W(gc2, (WCHAR*)&ii, 1, &s); - fl_fontsize->width[r][c&0x03FF] = s.cx; - if (gc2 && gc2 != gc_) ReleaseDC(hWnd, gc2); - return (double) fl_fontsize->width[r][c & 0x03FF]; -} - -/* Add function pointer to allow us to access GetGlyphIndicesW on systems that have it, - * without crashing on systems that do not. */ -/* DWORD WINAPI GetGlyphIndicesW(HDC,LPCWSTR,int,LPWORD,DWORD) */ -typedef DWORD (WINAPI* fl_GetGlyphIndices_func)(HDC,LPCWSTR,int,LPWORD,DWORD); - -static fl_GetGlyphIndices_func fl_GetGlyphIndices = NULL; // used to hold a proc pointer for GetGlyphIndicesW -static int have_loaded_GetGlyphIndices = 0; // Set this non-zero once we have tried to load GetGlyphIndices - -// Function that tries to dynamically load GetGlyphIndicesW at runtime -static void GetGlyphIndices_init() { - // Since not all versions of Windows include GetGlyphIndicesW support, - // we do a run-time check for the required function. - HMODULE hMod = GetModuleHandle("GDI32.DLL"); - if (hMod) { - // check that GetGlyphIndicesW is available - fl_GetGlyphIndices = (fl_GetGlyphIndices_func)GetProcAddress(hMod, "GetGlyphIndicesW"); - } - have_loaded_GetGlyphIndices = -1; // set this non-zero when we have attempted to load GetGlyphIndicesW -} // GetGlyphIndices_init function - -static void on_printer_extents_update(int &dx, int &dy, int &w, int &h, HDC gc) -// converts text extents from device coords to logical coords -{ - POINT pt[3] = { {0, 0}, {dx, dy}, {dx+w, dy+h} }; - DPtoLP(gc, pt, 3); - w = pt[2].x - pt[1].x; - h = pt[2].y - pt[1].y; - dx = pt[1].x - pt[0].x; - dy = pt[1].y - pt[0].y; -} - -// if printer context, extents shd be converted to logical coords -#define EXTENTS_UPDATE(x,y,w,h,gc) \ - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { \ - on_printer_extents_update(x,y,w,h,gc); \ - } - -// Function to determine the extent of the "inked" area of the glyphs in a string -void Fl_GDI_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) { - - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (!fl_fontsize) { // no valid font, nothing to measure - w = 0; h = 0; - dx = dy = 0; - return; - } - - static unsigned short *ext_buff = NULL; // UTF-16 converted version of input UTF-8 string - static WORD *w_buff = NULL; // glyph indices array - static unsigned wc_len = 0; // current string buffer dimensions - static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; // identity mat for GetGlyphOutlineW - GLYPHMETRICS metrics; - int maxw = 0, maxh = 0, dh; - int minx = 0, miny = -999999; - unsigned len = 0, idx = 0; - HWND hWnd = 0; - HDC gc2 = gc_; // local copy of current gc - make a copy in case we change it... - int has_surrogates; // will be set if the string contains surrogate pairs - - // Have we loaded the GetGlyphIndicesW function yet? - if (have_loaded_GetGlyphIndices == 0) { - GetGlyphIndices_init(); - } - // Do we have a usable GetGlyphIndices function? - if(!fl_GetGlyphIndices) goto exit_error; // No GetGlyphIndices function, use fallback mechanism instead - - // The following code makes a best effort attempt to obtain a valid fl_gc. - // See description in fl_width() above for an explanation. - if (!gc2) { // We have no valid gc, try and obtain one - // Use our first fltk window, or fallback to using the screen via GetDC(NULL) - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - if (!gc2) goto exit_error; // no valid gc, attempt to use fallback measure - - // now convert the string to WCHAR and measure it - len = fl_utf8toUtf16(c, n, ext_buff, wc_len); - if(len >= wc_len) { - if(ext_buff) {delete [] ext_buff;} - if(w_buff) {delete [] w_buff;} - wc_len = len + 64; - ext_buff = new unsigned short[wc_len]; - w_buff = new WORD[wc_len]; - len = fl_utf8toUtf16(c, n, ext_buff, wc_len); - } - SelectObject(gc2, fl_fontsize->fid); - - // Are there surrogate-pairs in this string? If so GetGlyphIndicesW will fail - // since it can only handle the BMP range. - // We ideally want to use GetGlyphIndicesW, as it is the Right Thing, but it - // only works for the BMP, so we leverage GetCharacterPlacementW instead, which - // is not ideal, but works adequately well, and does handle surrogate pairs. - has_surrogates = 0; - for(unsigned ll = 0; ll < len; ll++) { - if((ext_buff[ll] >= 0xD800) && (ext_buff[ll] < 0xE000)) { - has_surrogates = -1; - break; - } - } - if (has_surrogates) { - // GetGlyphIndices will not work - use GetCharacterPlacementW() instead - GCP_RESULTSW gcp_res; - memset(w_buff, 0, (sizeof(WORD) * wc_len)); - memset(&gcp_res, 0, sizeof(GCP_RESULTSW)); - gcp_res.lpGlyphs = (LPWSTR)w_buff; - gcp_res.nGlyphs = wc_len; - gcp_res.lStructSize = sizeof(gcp_res); - - DWORD dr = GetCharacterPlacementW(gc2, (WCHAR*)ext_buff, len, 0, &gcp_res, GCP_GLYPHSHAPE); - if(dr) { - len = gcp_res.nGlyphs; - } else goto exit_error; - } else { - if (fl_GetGlyphIndices(gc_, (WCHAR*)ext_buff, len, w_buff, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) { - // some error occurred here - just return fl_measure values - goto exit_error; - } - } - - // now we have the glyph array we measure each glyph in turn... - for(idx = 0; idx < len; idx++){ - if (GetGlyphOutlineW (gc2, w_buff[idx], GGO_METRICS | GGO_GLYPH_INDEX, - &metrics, 0, NULL, &matrix) == GDI_ERROR) { - goto exit_error; - } - maxw += metrics.gmCellIncX; - if(idx == 0) minx = metrics.gmptGlyphOrigin.x; - dh = metrics.gmBlackBoxY - metrics.gmptGlyphOrigin.y; - if(dh > maxh) maxh = dh; - if(miny < metrics.gmptGlyphOrigin.y) miny = metrics.gmptGlyphOrigin.y; - } - // for the last cell, we only want the bounding X-extent, not the glyphs increment step - maxw = maxw - metrics.gmCellIncX + metrics.gmBlackBoxX + metrics.gmptGlyphOrigin.x; - w = maxw - minx; - h = maxh + miny; - dx = minx; - dy = -miny; - EXTENTS_UPDATE(dx, dy, w, h, gc_); - return; // normal exit - -exit_error: - // some error here - just return fl_measure values - w = (int)width(c, n); - h = height_unscaled(); - dx = 0; - dy = descent_unscaled() - h; - EXTENTS_UPDATE(dx, dy, w, h, gc_); - return; -} // fl_text_extents - -void Fl_GDI_Graphics_Driver::draw_unscaled(const char* str, int n, int x, int y) { - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - // avoid crash if no font has been set yet - if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - int wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - if(wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - } - TextOutW(gc_, x, y, (WCHAR*)wstr, wn); - SetTextColor(gc_, oldColor); // restore initial state -} - -void Fl_GDI_Graphics_Driver::draw_unscaled(int angle, const char* str, int n, int x, int y) { - fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), angle); - int wn = 0; // count of UTF16 cells to render full string - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - if(wn >= wstr_len) { // Array too small - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); // respin the translation - } - TextOutW(gc_, x, y, (WCHAR*)wstr, wn); - SetTextColor(gc_, oldColor); - fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), 0); -} - -void Fl_GDI_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) { - int wn; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - if(wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - } - - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); -#ifdef RTL_CHAR_BY_CHAR - int i = 0; - int lx = 0; - while (i < wn) { // output char by char is very bad for Arabic but coherent with fl_width() - lx = (int) width(wstr[i]); - x -= lx; - TextOutW(gc_, x, y, (WCHAR*)wstr + i, 1); - if (fl_nonspacing(wstr[i])) { - x += lx; - } - i++; - } -#else - UINT old_align = SetTextAlign(gc_, TA_RIGHT | TA_RTLREADING); - TextOutW(gc_, x, y - height_unscaled() + descent_unscaled(), (WCHAR*)wstr, wn); - SetTextAlign(gc_, old_align); -#endif - SetTextColor(gc_, oldColor); -} -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx deleted file mode 100644 index 3a8e70689..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ /dev/null @@ -1,826 +0,0 @@ -// -// Windows image drawing code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// I hope a simple and portable method of drawing color and monochrome -// images. To keep this simple, only a single storage type is -// supported: 8 bit unsigned data, byte order RGB, and pixels are -// stored packed into rows with the origin at the top-left. It is -// possible to alter the size of pixels with the "delta" argument, to -// add alpha or other information per pixel. It is also possible to -// change the origin and direction of the image data by messing with -// the "delta" and "linedelta", making them negative, though this may -// defeat some of the shortcuts in translating the image for X. - -// Unbelievably (since it conflicts with how most PC software works) -// Micro$oft picked a bottom-up and BGR storage format for their -// DIB images. I'm pretty certain there is a way around this, but -// I can't find any other than the brute-force method of drawing -// each line as a separate image. This may also need to be done -// if the delta is any amount other than 1, 3, or 4. - -//////////////////////////////////////////////////////////////// - -#include <config.h> -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_System_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> - -#define MAXBUFFER 0x40000 // 256k - -void fl_release_dc(HWND, HDC); // from Fl_win32.cxx - -#if USE_COLORMAP - -// error-diffusion dither into the FLTK colormap -static void dither(uchar* to, const uchar* from, int w, int delta) { - static int ri, gi, bi, dir; - int r=ri, g=gi, b=bi; - int d, td; - if (dir) { - dir = 0; - from = from+(w-1)*delta; - to = to+(w-1); - d = -delta; - td = -1; - } else { - dir = 1; - d = delta; - td = 1; - } - for (; w--; from += d, to += td) { - r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; - int rr = r*FL_NUM_RED/256; - r -= rr*255/(FL_NUM_RED-1); - g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; - int gg = g*FL_NUM_GREEN/256; - g -= gg*255/(FL_NUM_GREEN-1); - b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; - int bb = b*FL_NUM_BLUE/256; - b -= bb*255/(FL_NUM_BLUE-1); - *to = uchar(FL_COLOR_CUBE+(bb*FL_NUM_RED+rr)*FL_NUM_GREEN+gg); - } - ri = r; gi = g; bi = b; -} - -// error-diffusion dither into the FLTK colormap -static void monodither(uchar* to, const uchar* from, int w, int delta) { - static int ri,dir; - int r=ri; - int d, td; - if (dir) { - dir = 0; - from = from+(w-1)*delta; - to = to+(w-1); - d = -delta; - td = -1; - } else { - dir = 1; - d = delta; - td = 1; - } - for (; w--; from += d, to += td) { - r += *from; if (r < 0) r = 0; else if (r>255) r = 255; - int rr = r*FL_NUM_GRAY/256; - r -= rr*255/(FL_NUM_GRAY-1); - *to = uchar(FL_GRAY_RAMP+rr); - } - ri = r; -} - -#endif // USE_COLORMAP - -static int fl_abs(int v) { return v<0 ? -v : v; } - -static void innards(const uchar *buf, int X, int Y, int W, int H, - int delta, int linedelta, int depth, - Fl_Draw_Image_Cb cb, void* userdata, HDC gc) -{ - char indexed = 0; - -#if USE_COLORMAP - indexed = (fl_palette != 0); -#endif - - if (depth==0) depth = 3; - if (indexed || !fl_can_do_alpha_blending()) - depth = (depth-1)|1; - - if (!linedelta) linedelta = W*fl_abs(delta); - - int x = 0, y = 0, w = 0, h = 0; - fl_clip_box(X, Y, W, H, x, y, w, h); - if (w<=0 || h<=0) return; - if (buf) buf += (x-X)*delta + (y-Y)*linedelta; - - // bmibuffer: BITMAPINFOHEADER + 256 colors (RGBQUAD) + 1 (rounding effects ?) - static U32 bmibuffer[sizeof(BITMAPINFOHEADER)/4 + 257]; - BITMAPINFO *bmi = (BITMAPINFO*)bmibuffer; - if (!bmi->bmiHeader.biSize) { - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biCompression = BI_RGB; - bmi->bmiHeader.biXPelsPerMeter = 0; - bmi->bmiHeader.biYPelsPerMeter = 0; - bmi->bmiHeader.biClrUsed = 0; - bmi->bmiHeader.biClrImportant = 0; - } -#if USE_COLORMAP - if (indexed) { - for (short i=0; i<256; i++) { - *((short*)(bmi->bmiColors)+i) = i; - } - } else -#endif - if (depth<3) { - RGBQUAD *bmi_colors = &(bmi->bmiColors[0]); // use pointer to suppress warning (STR #3199) - for (int i=0; i<256; i++) { - bmi_colors[i].rgbBlue = (uchar)i; // = bmi->bmiColors[i] - bmi_colors[i].rgbGreen = (uchar)i; - bmi_colors[i].rgbRed = (uchar)i; - bmi_colors[i].rgbReserved = (uchar)0; // must be zero - } - } - bmi->bmiHeader.biWidth = w; -#if USE_COLORMAP - bmi->bmiHeader.biBitCount = indexed ? 8 : depth*8; - int pixelsize = indexed ? 1 : depth; -#else - bmi->bmiHeader.biBitCount = depth*8; - int pixelsize = depth; -#endif - if (depth==2) { // special case: gray with alpha - bmi->bmiHeader.biBitCount = 32; - pixelsize = 4; - } - int linesize = (pixelsize*w+3)&~3; - - static U32* buffer; - static long buffer_size; - int blocking = h; - { - int size = linesize * h; - // when printing, don't limit buffer size not to get a crash in StretchDIBits - if (size > MAXBUFFER && !fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { - size = MAXBUFFER; - blocking = MAXBUFFER / linesize; - } - if (size > buffer_size) { - delete[] buffer; - buffer_size = size; - buffer = new U32[(size + 3) / 4]; - } - } - bmi->bmiHeader.biHeight = blocking; - static U32* line_buffer; - if (!buf) { - int size = W*delta; - static int line_buf_size; - if (size > line_buf_size) { - delete[] line_buffer; - line_buf_size = size; - line_buffer = new U32[(size+3)/4]; - } - } - for (int j=0; j<h; ) { - int k; - for (k = 0; j<h && k<blocking; k++, j++) { - const uchar* from; - if (!buf) { // run the converter: - cb(userdata, x-X, y-Y+j, w, (uchar*)line_buffer); - from = (uchar*)line_buffer; - } else { - from = buf; - buf += linedelta; - } - uchar *to = (uchar*)buffer+(blocking-k-1)*linesize; -#if USE_COLORMAP - if (indexed) { - if (depth<3) - monodither(to, from, w, delta); - else - dither(to, from, w, delta); - } else -#endif - { - int i; - switch (depth) { - case 1: - for (i=w; i--; from += delta) *to++ = *from; - break; - case 2: - for (i=w; i--; from += delta, to += 4) { - uchar a = from[1]; - uchar gray = (from[0]*a)>>8; - to[0] = gray; - to[1] = gray; - to[2] = gray; - to[3] = a; - } - break; - case 3: - for (i=w; i--; from += delta, to += 3) { - uchar r = from[0]; - to[0] = from[2]; - to[1] = from[1]; - to[2] = r; - } - break; - case 4: - for (i=w; i--; from += delta, to += 4) { - uchar a = from[3]; - uchar r = from[0]; - to[0] = (from[2]*a)>>8; - to[1] = (from[1]*a)>>8; - to[2] = (r*a)>>8; - to[3] = from[3]; - } - break; - } - } - } // for (k = 0; j<h && k<blocking ...) - - if (fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { - // if print context, device and logical units are not equal, so SetDIBitsToDevice - // does not do the expected job, whereas StretchDIBits does it. - StretchDIBits(gc, x, y+j-k, w, k, 0, 0, w, k, - (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - bmi, -#if USE_COLORMAP - indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS -#else - DIB_RGB_COLORS -#endif - , SRCCOPY ); - delete[] buffer; - buffer = NULL; - buffer_size = 0; - } - else { - SetDIBitsToDevice(gc, x, y+j-k, w, k, 0, 0, 0, k, - (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - bmi, -#if USE_COLORMAP - indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS -#else - DIB_RGB_COLORS -#endif - ); - } - } // for (int j=0; j<h; ) -} - -void Fl_GDI_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,fl_abs(d),0,0, gc_); - } else { - innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data, gc_); - } else { - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,1,0,0, gc_); - } else { - innards(buf,x,y,w,h,d,l,1,0,0, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(0,x,y,w,h,d,0,1,cb,data, gc_); - } else { - innards(0,x,y,w,h,d,0,1,cb,data, gc_); - } -} - -#if USE_COLORMAP -void Fl_GDI_Graphics_Driver::colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { - // use the error diffusion dithering code to produce a much nicer block: - if (fl_palette) { - uchar c[3]; - c[0] = r; c[1] = g; c[2] = b; - innards(c, floor(x), floor(y), floor(x + w) - floor(x), floor(y + h) - floor(y), - 0,0,0,0,0, (HDC)gc()); - return; - } - Fl_Graphics_Driver::colored_rectf(x, y, w, h, r, g, b); -} -#endif - -// Create an N-bit bitmap for masking... -HBITMAP Fl_GDI_Graphics_Driver::create_bitmask(int w, int h, const uchar *data) { - // this won't work when the user changes display mode during run or - // has two screens with different depths - HBITMAP bm; - static uchar hiNibble[16] = - { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 }; - static uchar loNibble[16] = - { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, - 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f }; - HDC current_gc = (HDC)Fl_Surface_Device::surface()->driver()->gc(); - int np = GetDeviceCaps(current_gc, PLANES); //: was always one on sample machines - int bpp = GetDeviceCaps(current_gc, BITSPIXEL);//: 1,4,8,16,24,32 and more odd stuff? - int Bpr = (bpp*w+7)/8; //: bytes per row - int pad = Bpr&1, w1 = (w+7)/8, shr = ((w-1)&7)+1; - if (bpp==4) shr = (shr+1)/2; - uchar *newarray = new uchar[(Bpr+pad)*h]; - uchar *dst = newarray; - const uchar *src = data; - - for (int i=0; i<h; i++) { - // This is slooow, but we do it only once per pixmap - for (int j=w1; j>0; j--) { - uchar b = *src++; - if (bpp==1) { - *dst++ = (uchar)( hiNibble[b&15] ) | ( loNibble[(b>>4)&15] ); - } else if (bpp==4) { - for (int k=(j==1)?shr:4; k>0; k--) { - *dst++ = (uchar)("\377\360\017\000"[b&3]); - b = b >> 2; - } - } else { - for (int k=(j==1)?shr:8; k>0; k--) { - if (b&1) { - *dst++=0; - if (bpp>8) *dst++=0; - if (bpp>16) *dst++=0; - if (bpp>24) *dst++=0; - } else { - *dst++=0xff; - if (bpp>8) *dst++=0xff; - if (bpp>16) *dst++=0xff; - if (bpp>24) *dst++=0xff; - } - - b = b >> 1; - } - } - } - - dst += pad; - } - - bm = CreateBitmap(w, h, np, bpp, newarray); - delete[] newarray; - - return bm; -} - -void Fl_GDI_Graphics_Driver::delete_bitmask(fl_uintptr_t bm) { - DeleteObject((HGDIOBJ)bm); -} - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(bm, W, H); - cx = this->floor(cx); cy = this->floor(cy); - - HDC tempdc = CreateCompatibleDC(gc_); - int save = SaveDC(tempdc); - SelectObject(tempdc, (HGDIOBJ)*Fl_Graphics_Driver::id(bm)); - SelectObject(gc_, fl_brush()); - // secret bitblt code found in old Windows reference manual: - BitBlt(gc_, X, Y, W, H, tempdc, cx, cy, 0xE20746L); - RestoreDC(tempdc, save); - DeleteDC(tempdc); -} - -Fl_GDI_Printer_Graphics_Driver::transparent_f_type Fl_GDI_Printer_Graphics_Driver::TransparentBlt() { - HMODULE hMod; - static transparent_f_type fpter = ( (hMod = LoadLibrary("MSIMG32.DLL")) ? - (transparent_f_type)GetProcAddress(hMod, "TransparentBlt") : NULL - ); - return fpter; -} - -void Fl_GDI_Printer_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (Fl_Graphics_Driver::start_image(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - transparent_f_type fl_TransparentBlt = TransparentBlt(); - if (!fl_TransparentBlt) { - Fl_Graphics_Driver::draw_bitmap(bm, X, Y, W, H, cx, cy); - return; - } - bool recache = false; - if (*id(bm)) { - int *pw, *ph; - cache_w_h(bm, pw, ph); - recache = (*pw != bm->data_w() || *ph != bm->data_h()); - } - if (recache || !*id(bm)) { - bm->uncache(); - cache(bm); - } - HDC tempdc; - int save; - // algorithm for bitmap output to Fl_GDI_Printer - Fl_Color save_c = fl_color(); // save bitmap's desired color - uchar r, g, b; - Fl::get_color(save_c, r, g, b); - r = 255-r; - g = 255-g; - b = 255-b; - Fl_Color background = fl_rgb_color(r, g, b); // a color very different from the bitmap's - Fl_Image_Surface *img_surf = new Fl_Image_Surface(bm->data_w(), bm->data_h()); - Fl_Surface_Device::push_current(img_surf); - fl_color(background); - fl_rectf(0,0, bm->data_w(), bm->data_h()); // use this color as offscreen background - fl_color(save_c); // back to bitmap's color - HDC off_gc = (HDC)fl_graphics_driver->gc(); - tempdc = CreateCompatibleDC(off_gc); - save = SaveDC(tempdc); - SelectObject(tempdc, (HGDIOBJ)*Fl_Graphics_Driver::id(bm)); - SelectObject(off_gc, fl_brush()); // use bitmap's desired color - BitBlt(off_gc, 0, 0, bm->data_w(), bm->data_h(), tempdc, 0, 0, 0xE20746L); // draw bitmap to offscreen - Fl_Surface_Device::pop_current(); - SelectObject(tempdc, (HGDIOBJ)img_surf->offscreen()); // use offscreen data - // draw it to printer context with background color as transparent - float scaleW = bm->data_w()/float(bm->w()); - float scaleH = bm->data_h()/float(bm->h()); - fl_TransparentBlt(gc_, X, Y, W, H, tempdc, - int(cx * scaleW), int(cy * scaleH), int(W * scaleW), int(H * scaleH), RGB(r, g, b) ); - delete img_surf; - RestoreDC(tempdc, save); - DeleteDC(tempdc); - if (recache) bm->uncache(); -} - - -// Create a 1-bit mask used for alpha blending -HBITMAP Fl_GDI_Graphics_Driver::create_alphamask(int w, int h, int d, int ld, const uchar *array) { - HBITMAP bm; - int bmw = (w + 7) / 8; - uchar *bitmap = new uchar[bmw * h]; - uchar *bitptr, bit; - const uchar *dataptr; - int x, y; - static uchar dither[16][16] = { // Simple 16x16 Floyd dither - { 0, 128, 32, 160, 8, 136, 40, 168, - 2, 130, 34, 162, 10, 138, 42, 170 }, - { 192, 64, 224, 96, 200, 72, 232, 104, - 194, 66, 226, 98, 202, 74, 234, 106 }, - { 48, 176, 16, 144, 56, 184, 24, 152, - 50, 178, 18, 146, 58, 186, 26, 154 }, - { 240, 112, 208, 80, 248, 120, 216, 88, - 242, 114, 210, 82, 250, 122, 218, 90 }, - { 12, 140, 44, 172, 4, 132, 36, 164, - 14, 142, 46, 174, 6, 134, 38, 166 }, - { 204, 76, 236, 108, 196, 68, 228, 100, - 206, 78, 238, 110, 198, 70, 230, 102 }, - { 60, 188, 28, 156, 52, 180, 20, 148, - 62, 190, 30, 158, 54, 182, 22, 150 }, - { 252, 124, 220, 92, 244, 116, 212, 84, - 254, 126, 222, 94, 246, 118, 214, 86 }, - { 3, 131, 35, 163, 11, 139, 43, 171, - 1, 129, 33, 161, 9, 137, 41, 169 }, - { 195, 67, 227, 99, 203, 75, 235, 107, - 193, 65, 225, 97, 201, 73, 233, 105 }, - { 51, 179, 19, 147, 59, 187, 27, 155, - 49, 177, 17, 145, 57, 185, 25, 153 }, - { 243, 115, 211, 83, 251, 123, 219, 91, - 241, 113, 209, 81, 249, 121, 217, 89 }, - { 15, 143, 47, 175, 7, 135, 39, 167, - 13, 141, 45, 173, 5, 133, 37, 165 }, - { 207, 79, 239, 111, 199, 71, 231, 103, - 205, 77, 237, 109, 197, 69, 229, 101 }, - { 63, 191, 31, 159, 55, 183, 23, 151, - 61, 189, 29, 157, 53, 181, 21, 149 }, - { 254, 127, 223, 95, 247, 119, 215, 87, - 253, 125, 221, 93, 245, 117, 213, 85 } - }; - - // Generate a 1-bit "screen door" alpha mask; not always pretty, but - // definitely fast... In the future we may be able to support things - // like the RENDER extension in XFree86, when available, to provide - // true RGBA-blended rendering. See: - // - // http://www.xfree86.org/~keithp/render/protocol.html - // - // for more info on XRender... - // - memset(bitmap, 0, bmw * h); - - for (dataptr = array + d - 1, y = 0; y < h; y ++, dataptr += ld) - for (bitptr = bitmap + y * bmw, bit = 1, x = 0; x < w; x ++, dataptr += d) { - if (*dataptr > dither[x & 15][y & 15]) - *bitptr |= bit; - if (bit < 128) bit <<= 1; - else { - bit = 1; - bitptr ++; - } - } - - bm = create_bitmask(w, h, bitmap); - delete[] bitmap; - - return bm; -} - - -void Fl_GDI_Graphics_Driver::cache(Fl_RGB_Image *img) -{ - Fl_Image_Surface *surface = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surface); - if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { - fl_draw_image(img->array, 0, 0, img->data_w(), img->data_h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); - } else { - fl_draw_image(img->array, 0, 0, img->data_w(), img->data_h(), img->d(), img->ld()); - if (img->d() == 2 || img->d() == 4) { - *Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)create_alphamask(img->data_w(), img->data_h(), img->d(), img->ld(), img->array); - } - } - Fl_Surface_Device::pop_current(); - Fl_Offscreen offs = Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surface); - int *pw, *ph; - cache_w_h(img, pw, ph); - *pw = img->data_w(); - *ph = img->data_h(); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)offs; -} - - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(img, W, H); - cx = this->floor(cx); cy = this->floor(cy); - if (W + cx > img->data_w()) W = img->data_w() - cx; - if (H + cy > img->data_h()) H = img->data_h() - cy; - if (!*Fl_Graphics_Driver::id(img)) { - cache(img); - } - if (*Fl_Graphics_Driver::mask(img)) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::mask(img)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(img)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else if (img->d()==2 || img->d()==4) { - copy_offscreen_with_alpha(X, Y, W, H, (HBITMAP)*Fl_Graphics_Driver::id(img), cx, cy); - } else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(img), cx, cy); - } -} - - -void Fl_GDI_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) { - if (Fl_Graphics_Driver::start_image(rgb, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { - return; - } - if ((rgb->d() % 2) == 0 && !fl_can_do_alpha_blending()) { - Fl_Graphics_Driver::draw_rgb(rgb, XP, YP, WP, HP, cx, cy); - return; - } - if (!*Fl_Graphics_Driver::id(rgb)) { - cache(rgb); - } - push_clip(XP, YP, WP, HP); - XP -= cx; YP -= cy; - WP = rgb->w(); HP = rgb->h(); - cache_size(rgb, WP, HP); - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); - if ( (rgb->d() % 2) == 0 ) { - alpha_blend_(this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h()); - } else { - SetStretchBltMode(gc_, (Fl_Image::scaling_algorithm() == FL_RGB_SCALING_BILINEAR ? HALFTONE : BLACKONWHITE)); - StretchBlt(gc_, this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h(), SRCCOPY); - } - RestoreDC(new_gc, save); - DeleteDC(new_gc); - pop_clip(); -} - - -void Fl_GDI_Printer_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) { - if (Fl_Graphics_Driver::start_image(rgb, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { - return; - } - XFORM old_tr, tr; - GetWorldTransform(gc_, &old_tr); // storing old transform - tr.eM11 = float(rgb->w())/float(rgb->data_w()); - tr.eM22 = float(rgb->h())/float(rgb->data_h()); - tr.eM12 = tr.eM21 = 0; - tr.eDx = float(XP); - tr.eDy = float(YP); - ModifyWorldTransform(gc_, &tr, MWT_LEFTMULTIPLY); - if (*id(rgb)) { - int *pw, *ph; - cache_w_h(rgb, pw, ph); - if ( *pw != rgb->data_w() || *ph != rgb->data_h()) rgb->uncache(); - } - if (!*id(rgb)) cache(rgb); - draw_fixed(rgb, 0, 0, int(WP / tr.eM11), int(HP / tr.eM22), int(cx / tr.eM11), int(cy / tr.eM22)); - SetWorldTransform(gc_, &old_tr); -} - - -void Fl_GDI_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) -{ - if (id_) { - DeleteObject((HBITMAP)id_); - id_ = 0; - } - - if (mask_) { - delete_bitmask(mask_); - mask_ = 0; - } -} - -// 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing... -static HBITMAP fl_create_bitmap(int w, int h, const uchar *data) { - // we need to pad the lines out to words & swap the bits - // in each byte. - int w1 = (w + 7) / 8; - int w2 = ((w + 15) / 16) * 2; - uchar* newarray = new uchar[w2*h]; - const uchar* src = data; - uchar* dest = newarray; - HBITMAP bm; - static uchar reverse[16] = /* Bit reversal lookup table */ - { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, - 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; - - for (int y = 0; y < h; y++) { - for (int n = 0; n < w1; n++, src++) - *dest++ = (uchar)((reverse[*src & 0x0f] & 0xf0) | - (reverse[(*src >> 4) & 0x0f] & 0x0f)); - dest += w2 - w1; - } - - bm = CreateBitmap(w, h, 1, 1, newarray); - - delete[] newarray; - - return bm; -} - -void Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm) { - int *pw, *ph; - cache_w_h(bm, pw, ph); - *pw = bm->data_w(); - *ph = bm->data_h(); - *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)fl_create_bitmap(bm->data_w(), bm->data_h(), bm->array); -} - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(pxm, W, H); - cx = this->floor(cx); cy = this->floor(cy); - Fl_Region r2 = scale_clip(scale()); - if (*Fl_Graphics_Driver::mask(pxm)) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::mask(pxm)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(pxm)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else { - float s = scale(); Fl_Graphics_Driver::scale(1); - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy); - Fl_Graphics_Driver::scale(s); - } - unscale_clip(r2); -} - -/* ===== Implementation note about how Fl_Pixmap objects get printed under Windows ===== - Fl_Pixmap objects are printed with the print-specific Fl_GDI_Printer_Graphics_Driver - which uses the TransparentBlt() system function that can scale the image and treat one - of its colors as transparent. - Fl_GDI_Printer_Graphics_Driver::draw_pixmap(Fl_Pixmap *,...) sets need_pixmap_bg_color, - a static class variable, to 1 and recaches the image. This calls fl_convert_pixmap() - that checks the value of need_pixmap_bg_color. When this value is not 0, fl_convert_pixmap - runs in a way that memorizes the list of all colors in the pixmap, computes - a color absent from this list, uses it for the transparent pixels of the pixmap and puts - this color value in need_pixmap_bg_color. As a result, the transparent areas of the image - are correcty handled by the printing operation. Variable need_pixmap_bg_color is ultimately - reset to 0. - Fl_GDI_Graphics_Driver::make_unused_color_() which does the color computation mentioned - above is implemented in file src/fl_draw_pixmap.cxx - */ -void Fl_GDI_Printer_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; - transparent_f_type fl_TransparentBlt = TransparentBlt(); - if (fl_TransparentBlt) { - need_pixmap_bg_color = 1; - pxm->uncache(); - cache(pxm); - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(pxm)); - // print all of offscreen but its parts in background color - float scaleW = pxm->data_w()/float(pxm->w()); - float scaleH = pxm->data_h()/float(pxm->h()); - fl_TransparentBlt(gc_, X, Y, W, H, new_gc, - int(cx * scaleW), int(cy * scaleH), int(W * scaleW), int(H * scaleH), need_pixmap_bg_color ); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - need_pixmap_bg_color = 0; - } - else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy); - } -} - -// Makes an RGB triplet different from all the colors used in the pixmap -// and computes Fl_Graphics_Driver::need_pixmap_bg_color from this triplet -void Fl_GDI_Graphics_Driver::make_unused_color_(uchar &r, uchar &g, uchar &b, int color_count, void **data) { - typedef struct { uchar r; uchar g; uchar b; } UsedColor; - UsedColor *used_colors = *(UsedColor**)data; - int i; - r = 2; g = 3; b = 4; - while (1) { - for ( i=0; i<color_count; i++ ) - if ( used_colors[i].r == r && - used_colors[i].g == g && - used_colors[i].b == b ) - break; - if (i >= color_count) { - free((void*)used_colors); - *(UsedColor**)data = NULL; - need_pixmap_bg_color = RGB(r, g, b); - return; - } - if (r < 255) { - r++; - } else { - r = 0; - if (g < 255) { - g++; - } else { - g = 0; - b++; - } - } - } -} - -void Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img) { - Fl_Image_Surface *surf = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surf); - uchar **pbitmap = surf->driver()->mask_bitmap(); - *pbitmap = (uchar*)1;// will instruct fl_draw_pixmap() to compute the image's mask - fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); - uchar *bitmap = *pbitmap; - if (bitmap) { - *Fl_Graphics_Driver::mask(img) = - (fl_uintptr_t)create_bitmask(img->data_w(), img->data_h(), bitmap); - delete[] bitmap; - } - *pbitmap = 0; - Fl_Surface_Device::pop_current(); - Fl_Offscreen id = Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surf); - int *pw, *ph; - cache_w_h(img, pw, ph); - *pw = img->data_w(); - *ph = img->data_h(); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)id; -} - -void Fl_GDI_Graphics_Driver::uncache_pixmap(fl_uintptr_t offscreen) { - DeleteObject((HBITMAP)offscreen); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx deleted file mode 100644 index 9d086f353..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx +++ /dev/null @@ -1,111 +0,0 @@ -// -// Line style code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_line_style.cxx - - \brief Line style drawing utility for Windows (GDI) platform. -*/ - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -#include "Fl_GDI_Graphics_Driver.H" - - -void Fl_GDI_Graphics_Driver::line_style_unscaled(int style, int width, char* dashes) { - - // According to Bill, the "default" cap and join should be the - // "fastest" mode supported for the platform. I don't know why - // they should be different (same graphics cards, etc., right?) MRS - - static const DWORD Cap[4] = {PS_ENDCAP_FLAT, PS_ENDCAP_FLAT, PS_ENDCAP_ROUND, PS_ENDCAP_SQUARE}; - static const DWORD Join[4] = {PS_JOIN_ROUND, PS_JOIN_MITER, PS_JOIN_ROUND, PS_JOIN_BEVEL}; - - int s1 = PS_GEOMETRIC | Cap[(style>>8)&3] | Join[(style>>12)&3]; - DWORD a[16]; - int n = 0; - if (dashes && dashes[0]) { - s1 |= PS_USERSTYLE; - for (n = 0; n < 16 && *dashes; n++) a[n] = *dashes++; - } else { - s1 |= style & 0xff; // allow them to pass any low 8 bits for style - } - if ((style || n) && !width) width = int(scale()); // fix cards that do nothing for 0? - if (!width) width = 1; - if (!fl_current_xmap) color(FL_BLACK); - LOGBRUSH penbrush = {BS_SOLID,fl_RGB(),0}; // can this be fl_brush()? - HPEN newpen = ExtCreatePen(s1, width, &penbrush, n, n ? a : 0); - if (!newpen) { - Fl::error("fl_line_style(): Could not create GDI pen object."); - return; - } - HPEN oldpen = (HPEN)SelectObject(gc_, newpen); - DeleteObject(oldpen); - DeleteObject(fl_current_xmap->pen); - fl_current_xmap->pen = newpen; - style_ = style; -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::line_style(int style, int width, char* dashes) { - if (!active) return Fl_Scalable_Graphics_Driver::line_style(style, width, dashes); - int gdi_width = (width ? width : 1); - pen_->SetWidth(Gdiplus::REAL(gdi_width)); - int standard_dash = style & 0x7; - if (standard_dash == FL_DASH ) - pen_->SetDashStyle(Gdiplus::DashStyleDash); - else if (standard_dash == FL_DOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDot); - else if (standard_dash == FL_DASHDOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDashDot); - else if (standard_dash == FL_DASHDOTDOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDashDotDot); - else if(!dashes || !*dashes) - pen_->SetDashStyle(Gdiplus::DashStyleSolid); - - if (style & FL_CAP_ROUND ) { - pen_->SetStartCap(Gdiplus::LineCapRound); - pen_->SetEndCap(Gdiplus::LineCapRound); - } else if (style & FL_CAP_SQUARE ) { - pen_->SetStartCap(Gdiplus::LineCapSquare); - pen_->SetEndCap(Gdiplus::LineCapSquare); - } else { - pen_->SetStartCap(Gdiplus::LineCapFlat); - pen_->SetEndCap(Gdiplus::LineCapFlat); - } - - if (style & FL_JOIN_MITER ) { - pen_->SetLineJoin(Gdiplus::LineJoinMiter); - } else if (style & FL_JOIN_BEVEL ) { - pen_->SetLineJoin(Gdiplus::LineJoinBevel); - } else { - pen_->SetLineJoin(Gdiplus::LineJoinRound); - } - - if (dashes && *dashes) { - int n = 0; while (dashes[n]) n++; - Gdiplus::REAL *gdi_dashes = new Gdiplus::REAL[n]; - for (int i = 0; i < n; i++) gdi_dashes[i] = dashes[i]/float(gdi_width); - pen_->SetDashPattern(gdi_dashes, n); - delete[] gdi_dashes; - } - Fl_Scalable_Graphics_Driver::line_style(style, width, dashes); -} - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx deleted file mode 100644 index a86242e12..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx +++ /dev/null @@ -1,320 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -/** - \file Fl_GDI_Graphics_Driver_rect.cxx - \brief Windows GDI specific line and polygon drawing with integer coordinates. - */ - -#include <config.h> -#include <FL/Fl.H> -#include <FL/Fl_Widget.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> - -#include "Fl_GDI_Graphics_Driver.H" - - -// --- line and polygon drawing with integer coordinates - -void Fl_GDI_Graphics_Driver::point(int x, int y) { - rectf(x, y, 1, 1); -} - -void Fl_GDI_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { - // make pen have a one-pixel width - line_style_unscaled( (color()==FL_WHITE?FL_SOLID:FL_DOT), 1, NULL); - int right = this->floor(x+w-1), bottom = this->floor(y+h-1); - x = this->floor(x); y = this->floor(y); - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, right, y); - LineTo(gc_, right, bottom); - LineTo(gc_, x, bottom); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) { - // Windows 95/98/ME do not implement the dotted line style, so draw - // every other pixel around the focus area... - w = floor(x+w-1) - floor(x) + 1; - h = floor(y+h-1) - floor(y) + 1; - x = floor(x); y = floor(y); - int i=1, xx, yy; - COLORREF c = fl_RGB(); - for (xx = 0; xx < w; xx++, i++) if (i & 1) SetPixel(gc_, x+xx, y, c); - for (yy = 0; yy < h; yy++, i++) if (i & 1) SetPixel(gc_, x+w, y+yy, c); - for (xx = w; xx > 0; xx--, i++) if (i & 1) SetPixel(gc_, x+xx, y+h, c); - for (yy = h; yy > 0; yy--, i++) if (i & 1) SetPixel(gc_, x, y+yy, c); -} - -void Fl_GDI_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) { - if (is_solid_ && line_width_ > 1) { - line_style_unscaled(FL_CAP_SQUARE, line_width_, 0); // see issue #1052 - } - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x+w, y); - if (is_solid_ && line_width_ <= 1) LineTo(gc_, x+w, y+h+1); // see issue #1052 - LineTo(gc_, x+w, y+h); - LineTo(gc_, x, y+h); - LineTo(gc_, x, y); - if (is_solid_ && line_width_ > 1) { - line_style_unscaled(style_, line_width_, 0); - } -} - -void Fl_GDI_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) { - RECT rect; - rect.left = x; rect.top = y; - rect.right = (x + w); rect.bottom = (y + h); - FillRect(gc_, &rect, fl_brush()); -} - -void Fl_GDI_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - SetPixel(gc_, x1, y1, fl_RGB()); -} - -void Fl_GDI_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - SetPixel(gc_, x2, y2, fl_RGB()); -} - -void* Fl_GDI_Graphics_Driver::change_pen_width(int width) { // set the width of the pen, return previous pen - LOGBRUSH penbrush = {BS_SOLID, fl_RGB(), 0}; - HPEN newpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_ROUND, width, &penbrush, 0, 0); - return SelectObject(gc_, newpen); -} - -void Fl_GDI_Graphics_Driver::reset_pen_width(void *data) { - DeleteObject(SelectObject(gc_, (HPEN)data)); -} - -void Fl_GDI_Graphics_Driver::xyline_unscaled(int x, int y, int x1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1+1 , y); -} - -void Fl_GDI_Graphics_Driver::yxline_unscaled(int x, int y, int y1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x, y1+1); -} - -void Fl_GDI_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - LineTo(gc_, x3, y3); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - POINT p[3]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - SelectObject(gc_, fl_brush()); - Polygon(gc_, p, 3); -} - -void Fl_GDI_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - POINT p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; - SelectObject(gc_, fl_brush()); - Polygon(gc_, p, 4); -} - -// --- clipping - -void Fl_GDI_Graphics_Driver::push_clip(int x, int y, int w, int h) { - HRGN r; - if (w > 0 && h > 0) { - r = (HRGN)XRectangleRegion(x,y,w,h); - HRGN current = (HRGN)rstack[rstackptr]; - if (current) { - CombineRgn(r,r,current,RGN_AND); - } - } else { // make empty clip region: - r = CreateRectRgn(0,0,0,0); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_GDI_Graphics_Driver::push_clip: clip stack overflow!\n"); - fl_restore_clip(); -} - -int Fl_GDI_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - HRGN r = (HRGN)rstack[rstackptr]; - if (!r) return 0; - // The win32 API makes no distinction between partial and complete - // intersection, so we have to check for partial intersection ourselves. - // However, given that the regions may be composite, we have to do - // some voodoo stuff... - HRGN rr = (HRGN)XRectangleRegion(x,y,w,h); - HRGN temp = CreateRectRgn(0,0,0,0); - int ret; - if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint - W = H = 0; - ret = 2; - } else if (EqualRgn(temp, rr)) { // complete - ret = 0; - } else { // partial intersection - RECT rect; - GetRgnBox(temp, &rect); - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // if print context, convert coords from device to logical - POINT pt[2] = { {rect.left, rect.top}, {rect.right, rect.bottom} }; - DPtoLP(gc_, pt, 2); - X = pt[0].x; Y = pt[0].y; W = pt[1].x - X; H = pt[1].y - Y; - } - else { - X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y; - } - ret = 1; - } - DeleteObject(temp); - DeleteObject(rr); - return ret; -} - -int Fl_GDI_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - HRGN r = (HRGN)rstack[rstackptr]; - if (!r) return 1; - RECT rect; - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // in case of print context, convert coords from logical to device - POINT pt[2] = { {x, y}, {x + w, y + h} }; - LPtoDP(gc_, pt, 2); - rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y; - } else { - rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; - } - return RectInRegion(r,&rect); -} - -void Fl_GDI_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - if (gc_) { - HRGN r = NULL; - if (rstack[rstackptr]) r = (HRGN)scale_clip(scale()); - SelectClipRgn(gc_, (HRGN)rstack[rstackptr]); // if region is NULL, clip is automatically cleared - if (r) unscale_clip(r); - } -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::line(int x, int y, int x1, int y1) { - if (!active) return Fl_Scalable_Graphics_Driver::line(x, y, x1, y1); - bool AA = !(x == x1 || y == y1); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - if (AA) graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawLine(pen_, x, y, x1, y1); -} - -void Fl_GDIplus_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::line(x, y, x1, y1, x2, y2); - line(x, y, x1, y1); - line(x1, y1, x2, y2); -} - -void Fl_GDIplus_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2); - Gdiplus::GraphicsPath path; - Gdiplus::Point gdi2_p[3] = {Gdiplus::Point(x0, y0), Gdiplus::Point(x1, y1), Gdiplus::Point(x2, y2)}; - path.AddLines(gdi2_p, 3); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawPath(pen_, &path); -} - -#define fl_min(a,b) (a < b ? a : b) -#define fl_max(a,b) (a > b ? a : b) -void Fl_GDIplus_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - if ( (x0 == x3 && x1 == x2 && y0 == y1 && y3 == y2) || - (x0 == x1 && y1 == y2 && x2 == x3 && y3 == y0) ) { // rectangular loop - int left = fl_min(x0, fl_min(x1, fl_min(x2, x3))); - int right = fl_max(x0, fl_max(x1, fl_max(x2, x3))); - int top = fl_min(y0, fl_min(y1, fl_min(y2, y3))); - int bottom = fl_max(y0, fl_max(y1, fl_max(y2, y3))); - rect(left, top, right-left+1, bottom-top+1); - } else { - if (!active) return Fl_Scalable_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2, x3, y3); - Gdiplus::GraphicsPath path; - Gdiplus::PointF gdi2_p[4] = {Gdiplus::PointF(x0+1-line_width_/2.f, y0+1-line_width_/2.f), Gdiplus::PointF(x1+1-line_width_/2.f, y1+1-line_width_/2.f), Gdiplus::PointF(x2+1-line_width_/2.f, y2+1-line_width_/2.f), Gdiplus::PointF(x3+1-line_width_/2.f, y3+1-line_width_/2.f)}; - path.AddLines(gdi2_p, 4); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2); - Gdiplus::GraphicsPath path; - path.AddLine(x0, y0, x1, y1); - path.AddLine(x1, y1, x2, y2); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPath(brush_, &path); -} - -void Fl_GDIplus_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - if ( (x0 == x3 && x1 == x2 && y0 == y1 && y3 == y2) || - (x0 == x1 && y1 == y2 && x2 == x3 && y3 == y0) ) { - int left = fl_min(x0, fl_min(x1, fl_min(x2, x3))); - int right = fl_max(x0, fl_max(x1, fl_max(x2, x3))); - int top = fl_min(y0, fl_min(y1, fl_min(y2, y3))); - int bottom = fl_max(y0, fl_max(y1, fl_max(y2, y3))); - rectf(left, top, right-left, bottom-top); - } else { - if (!active) return Fl_Scalable_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2, x3, y3); - Gdiplus::GraphicsPath path; - path.AddLine(x0, y0, x1, y1); - path.AddLine(x1, y1, x2, y2); - path.AddLine(x2, y2, x3, y3); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPath(brush_, &path); - } -} -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx deleted file mode 100644 index e469bb11b..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx +++ /dev/null @@ -1,231 +0,0 @@ -// -// Portable drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_vertex.cxx - - \brief Portable drawing code for drawing arbitrary shapes with - simple 2D transformations, implemented for Windows GDI. -*/ - -#include "Fl_GDI_Graphics_Driver.H" - -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/math.h> - - -void Fl_GDI_Graphics_Driver::end_points() { - for (int i=0; i<n; i++) SetPixel(gc_, long_point[i].x, long_point[i].y, fl_RGB()); -} - -void Fl_GDI_Graphics_Driver::end_line() { - if (n < 2) { - end_points(); - return; - } - if (n>1) Polyline(gc_, long_point, n); -} - -void Fl_GDI_Graphics_Driver::end_loop() { - fixloop(); - if (n>2) transformed_vertex0(float(long_point[0].x), float(long_point[0].y)); - end_line(); -} - -void Fl_GDI_Graphics_Driver::end_polygon() { - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - SelectObject(gc_, fl_brush()); - Polygon(gc_, long_point, n); - } -} - -void Fl_GDI_Graphics_Driver::begin_complex_polygon() { - Fl_Graphics_Driver::begin_complex_polygon(); - numcount = 0; -} - -void Fl_GDI_Graphics_Driver::gap() { - while (n>gap_+2 && long_point[n-1].x == long_point[gap_].x && long_point[n-1].y == long_point[gap_].y) n--; - if (n > gap_+2) { - transformed_vertex0(float(long_point[gap_].x), float(long_point[gap_].y)); - counts[numcount++] = n-gap_; - gap_ = n; - } else { - n = gap_; - } -} - -void Fl_GDI_Graphics_Driver::end_complex_polygon() { - gap(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - SelectObject(gc_, fl_brush()); - PolyPolygon(gc_, long_point, counts, numcount); - } -} - -void Fl_GDI_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) { - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - - if (what==POLYGON) { - SelectObject(gc_, fl_brush()); - Pie(gc_, llx, lly, llx+w, lly+h, 0,0, 0,0); - } else - Arc(gc_, llx, lly, llx+w, lly+h, 0,0, 0,0); -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::transformed_vertex(double xf, double yf) { - if (!active) return Fl_Scalable_Graphics_Driver::transformed_vertex(xf, yf); - transformed_vertex0(float(xf) , float(yf) ); -} - -void Fl_GDIplus_Graphics_Driver::vertex(double x,double y) { - if (!active) return Fl_Scalable_Graphics_Driver::vertex(x, y); - transformed_vertex0(float(x*m.a + y*m.c + m.x) , float(x*m.b + y*m.d + m.y) ); -} - -void Fl_GDIplus_Graphics_Driver::end_points() { - if (!active) return Fl_GDI_Graphics_Driver::end_points(); - for (int i = 0; i < n; i++) point(long_point[i].x, long_point[i].y); -} - -void Fl_GDIplus_Graphics_Driver::end_line() { - if (!active) return Fl_GDI_Graphics_Driver::end_line(); - if (n < 2) { - end_points(); - return; - } - if (n>1) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddLines(gdi2_p, n); - delete[] gdi2_p; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - pen_->SetColor(gdiplus_color_); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_loop() { - if (!active) return Fl_GDI_Graphics_Driver::end_loop(); - fixloop(); - if (n >= 2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddLines(gdi2_p, n); - path.CloseFigure(); - delete[] gdi2_p; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - pen_->SetColor(gdiplus_color_); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_polygon() { - if (!active) return Fl_GDI_Graphics_Driver::end_polygon(); - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddPolygon(gdi2_p, n); - delete[] gdi2_p; - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - brush_->SetColor(gdiplus_color_); - graphics_.FillPath(brush_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_complex_polygon() { - if (!active) return Fl_GDI_Graphics_Driver::end_complex_polygon(); - gap(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddPolygon(gdi2_p, n); - delete[] gdi2_p; - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - brush_->SetColor(gdiplus_color_); - graphics_.FillPath(brush_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::circle(double x, double y, double r) { - if (!active) return Fl_Scalable_Graphics_Driver::circle(x, y, r); - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - if (what==POLYGON) { - brush_->SetColor(gdiplus_color_); - graphics_.FillPie(brush_, llx, lly, w, h, 0, 360); - } else { - pen_->SetColor(gdiplus_color_); - graphics_.DrawArc(pen_, llx, lly, w, h, 0, 360); - } -} -#endif - diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H deleted file mode 100644 index 129a4ecbc..000000000 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H +++ /dev/null @@ -1,44 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_GDI_IMAGE_SURFACE_DRIVER_H -#define FL_GDI_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_RGB_Image.H> -#include <FL/platform.H> - -class Fl_GDI_Image_Surface_Driver : public Fl_Image_Surface_Driver { - void end_current() FL_OVERRIDE; -public: - HWND pre_window; - int _savedc; - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - struct shape_data_type { - HBITMAP background; - uchar *vBits; - Fl_RGB_Image* mask; - } *shape_data_; - Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_GDI_Image_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; - POINT origin; -}; - -#endif // FL_GDI_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx deleted file mode 100644 index a14524ee2..000000000 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_Screen_Driver.H" -#include "Fl_GDI_Image_Surface_Driver.H" -#include <FL/platform.H> -#include <FL/Fl_Bitmap.H> -#include <windows.h> - - -Fl_GDI_Image_Surface_Driver::Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - Fl_Display_Device::display_device(); // make sure fl_graphics_driver was initialized - float d = fl_graphics_driver->scale(); - if (!off && d != 1 && high_res) { - w = int(w*d); - h = int(h*d); - } - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - offscreen = off ? off : (Fl_Offscreen)CreateCompatibleBitmap( (gc ? gc : fl_GetDC(0) ) , w, h); - if (!offscreen) offscreen = (Fl_Offscreen)CreateCompatibleBitmap(fl_GetDC(0), w, h); - driver(Fl_Graphics_Driver::newMainGraphicsDriver()); - if (d != 1 && high_res) ((Fl_GDI_Graphics_Driver*)driver())->scale(d); - origin.x = origin.y = 0; - shape_data_ = NULL; -} - - -Fl_GDI_Image_Surface_Driver::~Fl_GDI_Image_Surface_Driver() { - if (shape_data_ && shape_data_->background) { - DeleteObject(shape_data_->background); - delete shape_data_->mask; - free(shape_data_); - } - if (offscreen && !external_offscreen) DeleteObject((HBITMAP)offscreen); - delete driver(); -} - - -void Fl_GDI_Image_Surface_Driver::set_current() { - HDC gc = fl_makeDC((HBITMAP)offscreen); - driver()->gc(gc); - SetWindowOrgEx(gc, origin.x, origin.y, NULL); - Fl_Surface_Device::set_current(); - pre_window = fl_window; - _savedc = SaveDC(gc); - fl_window=(HWND)offscreen; -} - - -void Fl_GDI_Image_Surface_Driver::translate(int x, int y) { - ((Fl_GDI_Graphics_Driver*)driver())->translate_all(x, y); -} - - -void Fl_GDI_Image_Surface_Driver::untranslate() { - ((Fl_GDI_Graphics_Driver*)driver())->untranslate_all(); -} - - -Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image() -{ - if (shape_data_ && shape_data_->background) { - // get the offscreen size in pixels - HDC gc = fl_makeDC((HBITMAP)offscreen); - BITMAPINFO bmi; - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 0; - bmi.bmiHeader.biSizeImage = 0; - GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS); - int W = bmi.bmiHeader.biWidth; - int H = bmi.bmiHeader.biHeight; - int line_size = ((3*W+3)/4) * 4; - - // read bits of main offscreen - uchar *dib_src = new uchar[line_size * H]; - bmi.bmiHeader.biWidth = W; - bmi.bmiHeader.biHeight = H; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 24; - GetDIBits(gc, (HBITMAP)offscreen, 0, H, - dib_src, &bmi, DIB_RGB_COLORS); - - // draw above the secondary offscreen the main offscreen masked by shape_data_->mask - GdiFlush(); - Fl_Image_Surface_Driver::copy_with_mask(shape_data_->mask, shape_data_->vBits, dib_src, ((3*W+3)/4) * 4, true); - delete shape_data_->mask; - delete[] dib_src; - - // write bits of main offscreen - SetDIBits(gc, (HBITMAP)offscreen, 0, H, shape_data_->vBits, &bmi, DIB_RGB_COLORS); - DeleteDC(gc); - DeleteObject(shape_data_->background); - shape_data_->background = NULL; - free(shape_data_); - shape_data_ = NULL; - } - Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height, 0); - return image; -} - - -void Fl_GDI_Image_Surface_Driver::end_current() -{ - HDC gc = (HDC)driver()->gc(); - GetWindowOrgEx(gc, &origin); - RestoreDC(gc, _savedc); - DeleteDC(gc); - fl_window = pre_window; - Fl_Surface_Device::end_current(); -} - - -void Fl_GDI_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) { - shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type)); - // get the offscreen size in pixels - HDC gc = fl_makeDC((HBITMAP)offscreen); - BITMAPINFO bmi; - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 0; - bmi.bmiHeader.biSizeImage = 0; - - GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS); - int W = bmi.bmiHeader.biWidth; - int H = bmi.bmiHeader.biHeight; - - shape_data_->mask = Fl_Image_Surface_Driver::RGB3_to_RGB1(mask, W, H); - - // duplicate current offscreen content to new offscreen - int line_size = ((3*W+3)/4) * 4; - uchar *dib = new uchar[line_size * H]; // create temporary buffer to read DIB - bmi.bmiHeader.biWidth = W; - bmi.bmiHeader.biHeight = H; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 24; - - GetDIBits(gc, (HBITMAP)offscreen, 0, H, dib, &bmi, DIB_RGB_COLORS); - - HDC background_gc = CreateCompatibleDC(gc); - shape_data_->background = - CreateDIBSection(background_gc, &bmi, DIB_RGB_COLORS, - (void**)&shape_data_->vBits, NULL, 0); - if (!shape_data_->background) { - Fl::error("CreateDIBSection error=%lu", GetLastError()); - } - memcpy(shape_data_->vBits, dib, H * line_size); - delete[] dib; - DeleteDC(background_gc); - DeleteDC(gc); -} - diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx index 324d1c6f9..9cece371d 100644 --- a/src/drivers/PostScript/Fl_PostScript.cxx +++ b/src/drivers/PostScript/Fl_PostScript.cxx @@ -38,8 +38,8 @@ #if USE_PANGO #include <FL/math.h> // for M_PI #include <pango/pangocairo.h> -#include <cairo/cairo-ps.h> -#include <cairo/cairo-pdf.h> +#include <cairo-ps.h> +#include <cairo-pdf.h> #include <FL/Fl_Preferences.H> # if ! PANGO_VERSION_CHECK(1,10,0) # error "Requires Pango 1.10 or higher" @@ -1470,7 +1470,7 @@ void Fl_PostScript_Graphics_Driver::ps_untranslate(void) fprintf(output, "GR GR\n"); } -#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) +#if defined(FLTK_USE_X11) Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { *pfname = NULL; @@ -1492,7 +1492,7 @@ int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, return begin_job(NULL, perr_message); } -#endif // defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) +#endif // defined(FLTK_USE_X11) # else // USE_PANGO diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx index 9b5fe1668..ebb91cf03 100644 --- a/src/drivers/PostScript/Fl_PostScript_image.cxx +++ b/src/drivers/PostScript/Fl_PostScript_image.cxx @@ -26,7 +26,7 @@ #include <string.h> // memcpy() #if USE_PANGO -# include <cairo/cairo.h> +# include <cairo.h> #else # include <stdio.h> // fprintf() #endif diff --git a/src/drivers/Quartz/Fl_Font.H b/src/drivers/Quartz/Fl_Font.H deleted file mode 100644 index f1a710eea..000000000 --- a/src/drivers/Quartz/Fl_Font.H +++ /dev/null @@ -1,42 +0,0 @@ -// -// Font definitions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Two internal fltk data structures: -// -// Fl_Fontdesc: an entry into the fl_font() table. There is one of these -// for each fltk font number. -// -#ifndef FL_FONT_ -#define FL_FONT_ - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include "../../Fl_Scalable_Graphics_Driver.H" // Fl_Font_Descriptor -#include <ApplicationServices/ApplicationServices.h> - -class Fl_Quartz_Font_Descriptor : public Fl_Font_Descriptor { -public: - Fl_Quartz_Font_Descriptor(const char* fontname, Fl_Fontsize size); - virtual FL_EXPORT ~Fl_Quartz_Font_Descriptor(); - CTFontRef fontref; - // the unicode span is divided in 512 blocks of 128 characters - float *width[512]; // array of arrays of character widths - short q_width; -}; - -extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table - -#endif diff --git a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H deleted file mode 100644 index 8ef586624..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H +++ /dev/null @@ -1,39 +0,0 @@ -// -// Definition of Apple Quartz graphics driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2016 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#ifndef Fl_Quartz_Copy_Surface_Driver_H -#define Fl_Quartz_Copy_Surface_Driver_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> - -class Fl_Quartz_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; -protected: - CFMutableDataRef pdfdata; - CGContextRef gc; - static size_t MyPutBytes(void* info, const void* buffer, size_t count); - Fl_Quartz_Copy_Surface_Driver(int w, int h); - // implemented in Fl_cocoa.mm because uses Objective-c - ~Fl_Quartz_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif /* Fl_Quartz_Copy_Surface_Driver_H */ diff --git a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx deleted file mode 100644 index 77ecdaa0a..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2019 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> -#include "Fl_Quartz_Graphics_Driver.H" -#include "Fl_Quartz_Copy_Surface_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" - - -Fl_Quartz_Copy_Surface_Driver::Fl_Quartz_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - driver(new Fl_Quartz_Printer_Graphics_Driver); - pdfdata = CFDataCreateMutable(NULL, 0); - CGDataConsumerRef myconsumer; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 - if (&CGDataConsumerCreateWithCFData != NULL) { - myconsumer = CGDataConsumerCreateWithCFData(pdfdata); // 10.4 - } - else -#endif - { - static CGDataConsumerCallbacks callbacks = { Fl_Quartz_Copy_Surface_Driver::MyPutBytes, NULL }; - myconsumer = CGDataConsumerCreate((void*) pdfdata, &callbacks); - } - float d = fl_graphics_driver->scale(); - CGRect bounds = CGRectMake(0, 0, w * d, h * d); - gc = CGPDFContextCreate(myconsumer, &bounds, NULL); - CGDataConsumerRelease(myconsumer); - if (gc) { - CGContextBeginPage(gc, &bounds); - CGContextScaleCTM(gc, d, -d); - CGContextTranslateCTM(gc, 0.5, -h + 0.5); - CGContextSaveGState(gc); - } -} - -void Fl_Quartz_Copy_Surface_Driver::set_current() { - driver()->gc(gc); - fl_window = (FLWindow*)1; - Fl_Surface_Device::set_current(); -} - -size_t Fl_Quartz_Copy_Surface_Driver::MyPutBytes(void* info, const void* buffer, size_t count) -{ - CFDataAppendBytes ((CFMutableDataRef) info, (const UInt8 *)buffer, count); - return count; -} - -void Fl_Quartz_Copy_Surface_Driver::translate(int x, int y) { - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, x, y); - CGContextSaveGState(gc); -} - -void Fl_Quartz_Copy_Surface_Driver::untranslate() { - CGContextRestoreGState(gc); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H deleted file mode 100644 index 0afc7369e..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H +++ /dev/null @@ -1,149 +0,0 @@ -// -// Definition of Apple Quartz graphics driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Quartz_Graphics_Driver.H - \brief Definition of Apple Quartz graphics driver. - */ - -#ifndef FL_QUARTZ_GRAPHICS_DRIVER_H -#define FL_QUARTZ_GRAPHICS_DRIVER_H - -#include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> -#include <ApplicationServices/ApplicationServices.h> - -struct Fl_Fontdesc; -class Fl_Quartz_Font_Descriptor; - -/** - \brief The Mac OS X-specific graphics class. - - This class is implemented only on the Mac OS X platform. - */ -class Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { - friend class Fl_Cocoa_Printer_Driver; - friend class Fl_Quartz_Font_Descriptor; -protected: - CGContextRef gc_; - bool high_resolution_; - float quartz_line_width_; - CGLineCap quartz_line_cap_; - CGLineJoin quartz_line_join_; - CGFloat *quartz_line_pattern; - int quartz_line_pattern_size; - void cache_size(Fl_Image* img, int &width, int &height) FL_OVERRIDE; -public: - Fl_Quartz_Graphics_Driver(); - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & NATIVE; } - void gc(void *ctxt) FL_OVERRIDE { gc_ = (CGContextRef)ctxt; global_gc(); } - void *gc() FL_OVERRIDE {return gc_;} - char can_do_alpha_blending() FL_OVERRIDE; - - // --- bitmap stuff - static CGImageRef create_bitmask(int w, int h, const uchar *array); // NOT virtual - void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE; - void draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_bitmap(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) FL_OVERRIDE; - void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) FL_OVERRIDE; - void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) FL_OVERRIDE; - void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) FL_OVERRIDE; - void cache(Fl_Pixmap *img) FL_OVERRIDE; - void cache(Fl_Bitmap *img) FL_OVERRIDE; - void cache(Fl_RGB_Image *img) FL_OVERRIDE; - void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) FL_OVERRIDE; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) FL_OVERRIDE; - void draw_CGImage(CGImageRef cgimg, int x, int y, int w, int h, int srcx, int srcy, int sw, int sh); - static CGRect fl_cgrectmake_cocoa(int x, int y, int w, int h); - void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h) FL_OVERRIDE; - Fl_Region XRectangleRegion(int x, int y, int w, int h) FL_OVERRIDE; - void XDestroyRegion(Fl_Region r) FL_OVERRIDE; - void high_resolution(bool b) { high_resolution_ = b; } -protected: - void point(int x, int y) FL_OVERRIDE; - void rect(int x, int y, int w, int h) FL_OVERRIDE; - void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; - void rectf(int x, int y, int w, int h) FL_OVERRIDE; - void line(int x, int y, int x1, int y1) FL_OVERRIDE; - void line(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void xyline(int x, int y, int x1) FL_OVERRIDE; - void xyline(int x, int y, int x1, int y2) FL_OVERRIDE; - void xyline(int x, int y, int x1, int y2, int x3) FL_OVERRIDE; - void yxline(int x, int y, int y1) FL_OVERRIDE; - void yxline(int x, int y, int y1, int x2) FL_OVERRIDE; - void yxline(int x, int y, int y1, int x2, int y3) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - // --- clipping - void push_clip(int x, int y, int w, int h) FL_OVERRIDE; - int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) FL_OVERRIDE; - int not_clipped(int x, int y, int w, int h) FL_OVERRIDE; - void restore_clip() FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void circle(double x, double y, double r) FL_OVERRIDE; - void arc(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void line_style(int style, int width=0, char* dashes=0) FL_OVERRIDE; - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void draw(const char *str, int n, int x, int y) FL_OVERRIDE; - void draw(const char *str, int n, float x, float y) FL_OVERRIDE; - void draw(int angle, const char *str, int n, int x, int y) FL_OVERRIDE; - double width(const UniChar* txt, int n); - void rtl_draw(const char *str, int n, int x, int y) FL_OVERRIDE; - void font(Fl_Font face, Fl_Fontsize fsize) FL_OVERRIDE; - double width(const char *str, int n) FL_OVERRIDE; - double width(unsigned int c) FL_OVERRIDE; - int height() FL_OVERRIDE; - int descent() FL_OVERRIDE; - virtual bool high_resolution() { return high_resolution_; } - void global_gc() FL_OVERRIDE; - void quartz_restore_line_style(); - inline Fl_Quartz_Font_Descriptor *valid_font_descriptor(); - const char* get_font_name(Fl_Font fnum, int* ap) FL_OVERRIDE; - int get_font_sizes(Fl_Font fnum, int*& sizep) FL_OVERRIDE; - const char *font_name(int num) FL_OVERRIDE; - void font_name(int num, const char *name) FL_OVERRIDE; - Fl_Fontdesc* calc_fl_fonts(void) FL_OVERRIDE; - - void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h) FL_OVERRIDE; - Fl_Font set_fonts(const char* xstarname) FL_OVERRIDE; - void set_fontname_in_fontdesc(Fl_Fontdesc *f); - void uncache_pixmap(fl_uintptr_t p) FL_OVERRIDE; - - void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Quartz_Font_Descriptor *d); - void overlay_rect(int x, int y, int w , int h) FL_OVERRIDE; - float override_scale() FL_OVERRIDE; - void restore_scale(float) FL_OVERRIDE; - void antialias(int state) FL_OVERRIDE; - int antialias() FL_OVERRIDE; -}; - -class Fl_Quartz_Printer_Graphics_Driver : public Fl_Quartz_Graphics_Driver { -public: - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & (NATIVE | PRINTER); } -}; - -#endif // FL_QUARTZ_GRAPHICS_DRIVER_H diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx deleted file mode 100644 index 21c5eda4c..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx +++ /dev/null @@ -1,133 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_Cocoa_Screen_Driver.H" -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include <FL/Fl_Image_Surface.H> - - -void Fl_Quartz_Graphics_Driver::antialias(int state) { -} - -int Fl_Quartz_Graphics_Driver::antialias() { - return 1; -} - -Fl_Quartz_Graphics_Driver::Fl_Quartz_Graphics_Driver() : Fl_Graphics_Driver(), gc_(NULL) { - quartz_line_width_ = 1.f; - quartz_line_cap_ = kCGLineCapButt; - quartz_line_join_ = kCGLineJoinMiter; - quartz_line_pattern = 0; - quartz_line_pattern_size = 0; - high_resolution_ = false; -} - -char Fl_Quartz_Graphics_Driver::can_do_alpha_blending() { - return 1; -} - -static void bmProviderRelease (void *src, const void *data, size_t size) { - CFIndex count = CFGetRetainCount(src); - CFRelease(src); - if(count == 1) free((void*)data); -} - -/* Reference to the current CGContext - For back-compatibility only. The preferred procedure to get this reference is - Fl_Surface_Device::surface()->driver()->gc(). - */ -CGContextRef fl_gc = 0; - -void Fl_Quartz_Graphics_Driver::global_gc() -{ - fl_gc = (CGContextRef)gc(); -} - - -CGContextRef fl_mac_gc() { return fl_gc; } - - -void Fl_Quartz_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface - CGContextRef src = (CGContextRef)osrc; - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - CGImageRef img; - img = CGBitmapContextCreateImage(src); // requires 10.4 - CGAffineTransform at = CGContextGetCTM(src); - float s = at.a; - draw_CGImage(img, x, y, w, h, srcx, srcy, sw/s, sh/s); - CGImageRelease(img); -} - -// so a CGRect matches exactly what is denoted x,y,w,h for clipping purposes -CGRect Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(int x, int y, int w, int h) { - return CGRectMake(x - 0.5, y - 0.5, w, h); -} - -void Fl_Quartz_Graphics_Driver::add_rectangle_to_region(Fl_Region r_, int X, int Y, int W, int H) { - struct flCocoaRegion *r = (struct flCocoaRegion*)r_; - CGRect arg = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(X, Y, W, H); - int j; // don't add a rectangle totally inside the Fl_Region - for(j = 0; j < r->count; j++) { - if(CGRectContainsRect(r->rects[j], arg)) break; - } - if( j >= r->count) { - r->rects = (CGRect*)realloc(r->rects, (++(r->count)) * sizeof(CGRect)); - r->rects[r->count - 1] = arg; - } -} - -Fl_Region Fl_Quartz_Graphics_Driver::XRectangleRegion(int x, int y, int w, int h) { - struct flCocoaRegion* R = (struct flCocoaRegion*)malloc(sizeof(struct flCocoaRegion)); - R->count = 1; - R->rects = (CGRect *)malloc(sizeof(CGRect)); - *(R->rects) = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(x, y, w, h); - return R; -} - -void Fl_Quartz_Graphics_Driver::XDestroyRegion(Fl_Region r_) { - if (r_) { - struct flCocoaRegion *r = (struct flCocoaRegion*)r_; - free(r->rects); - free(r); - } -} - -void Fl_Quartz_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) { - width *= 2 * scale(); - height *= 2 * scale(); -} - -float Fl_Quartz_Graphics_Driver::override_scale() { - float s = scale(); - if (s != 1.f && Fl_Display_Device::display_device()->is_current()) { - CGContextScaleCTM(gc_, 1./s, 1./s); - Fl_Graphics_Driver::scale(1); - } - return s; -} - -void Fl_Quartz_Graphics_Driver::restore_scale(float s) { - if (s != 1.f && Fl_Display_Device::display_device()->is_current()) { - CGContextScaleCTM(gc_, s, s); - Fl_Graphics_Driver::scale(s); - } -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx deleted file mode 100644 index 4163de685..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// -// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Quartz_Graphics_Driver.H" -#include <FL/platform.H> - -/** - \file quartz_arci.cxx - \brief Utility functions for drawing circles using integers -*/ - -void Fl_Quartz_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; - float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; - CGContextSetShouldAntialias(gc_, true); - if (w!=h) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, cx, cy); - CGContextScaleCTM(gc_, w-1.0f, h-1.0f); - CGContextAddArc(gc_, 0, 0, 0.5, a1, a2, 1); - CGContextRestoreGState(gc_); - } else { - float r = (w+h)*0.25f-0.5f; - CGContextAddArc(gc_, cx, cy, r, a1, a2, 1); - } - CGContextStrokePath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; - float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; - CGContextSetShouldAntialias(gc_, true); - if (w!=h) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, cx, cy); - CGContextScaleCTM(gc_, w, h); - CGContextAddArc(gc_, 0, 0, 0.5, a1, a2, 1); - CGContextAddLineToPoint(gc_, 0, 0); - CGContextClosePath(gc_); - CGContextRestoreGState(gc_); - } else { - float r = (w+h)*0.25f; - CGContextAddArc(gc_, cx, cy, r, a1, a2, 1); - CGContextAddLineToPoint(gc_, cx, cy); - CGContextClosePath(gc_); - } - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx deleted file mode 100644 index 9d31f8573..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx +++ /dev/null @@ -1,70 +0,0 @@ -// -// MacOS color functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// The fltk "colormap". This allows ui colors to be stored in 8-bit -// locations, and provides a level of indirection so that global color -// changes can be made. Not to be confused with the X colormap, which -// I try to hide completely. - -// matt: Neither Quartz nor Quickdraw support colormaps in this implementation -// matt: Quartz support done - -#include "Fl_Quartz_Graphics_Driver.H" - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -extern unsigned fl_cmap[256]; // defined in fl_color.cxx - -void Fl_Quartz_Graphics_Driver::color(Fl_Color i) { - Fl_Graphics_Driver::color(i); - uchar r, g, b; - float fa = 1.0f; - if (i & 0xFFFFFF00) { - // translate rgb colors into color index - r = i>>24; - g = i>>16; - b = i>> 8; - } else { - // translate index into rgb: - unsigned c = fl_cmap[i]; - c = c ^ 0x000000ff; // trick to restore the color's correct alpha value - r = c>>24; - g = c>>16; - b = c>> 8; - uchar a = c & 0xff; - //printf("i=%d rgb=%u,%u,%u a=%u\n",i,r,g,b,a); - fa = a/255.0f; - } - if (!gc_) return; // no context yet? We will assign the color later. - float fr = r/255.0f; - float fg = g/255.0f; - float fb = b/255.0f; - CGContextSetRGBFillColor(gc_, fr, fg, fb, fa); - CGContextSetRGBStrokeColor(gc_, fr, fg, fb, fa); -} - -void Fl_Quartz_Graphics_Driver::color(uchar r, uchar g, uchar b) { - Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); - float fr = r/255.0f; - float fg = g/255.0f; - float fb = b/255.0f; - if (!gc_) return; // no context yet? We will assign the color later. - CGContextSetRGBFillColor(gc_, fr, fg, fb, 1.0f); - CGContextSetRGBStrokeColor(gc_, fr, fg, fb, 1.0f); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx deleted file mode 100644 index d373c1768..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx +++ /dev/null @@ -1,561 +0,0 @@ -// -// MacOS font selection routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Quartz_Graphics_Driver.H" -#include "Fl_Font.H" -#include <math.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_utf8.h> // for fl_utf8toUtf16() -#include <FL/fl_string_functions.h> // fl_strdup() - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 -const NSUInteger kCTFontOrientationHorizontal = kCTFontHorizontalOrientation; -#endif - -Fl_Fontdesc* fl_fonts = NULL; - -static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; - -static int fl_free_font = FL_FREE_FONT; - - -static CFMutableDictionaryRef attributes = NULL; - -static Fl_Fontdesc built_in_table_PS[] = { // PostScript font names preferred when Mac OS ≥ 10.5 - {"ArialMT"}, - {"Arial-BoldMT"}, - {"Arial-ItalicMT"}, - {"Arial-BoldItalicMT"}, - {"Courier"}, - {"Courier-Bold"}, - {"Courier-Oblique"}, - {"Courier-BoldOblique"}, - {"TimesNewRomanPSMT"}, - {"TimesNewRomanPS-BoldMT"}, - {"TimesNewRomanPS-ItalicMT"}, - {"TimesNewRomanPS-BoldItalicMT"}, - {"Symbol"}, - {"Monaco"}, - {"AndaleMono"}, // there is no bold Monaco font on standard Mac - {"ZapfDingbatsITC"} -}; - - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER sizeof(fl_fonts->fontname)-1 - -// turn a stored font name into a pretty name: -const char* Fl_Quartz_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) { - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - this->set_fontname_in_fontdesc(f); - const char* thisFont = f->name; - if (!thisFont || !*thisFont) {if (ap) *ap = 0; return "";} - int type = 0; - if (strstr(f->name, "Bold")) type |= FL_BOLD; - if (strstr(f->name, "Italic") || strstr(f->name, "Oblique")) type |= FL_ITALIC; - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - - -int Fl_Quartz_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { - static int array[128]; - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - int cnt = 0; - - // ATS supports all font size - array[0] = 0; - sizep = array; - cnt = 1; - - return cnt; -} - -Fl_Quartz_Font_Descriptor::Fl_Quartz_Font_Descriptor(const char* name, Fl_Fontsize Size) : Fl_Font_Descriptor(name, Size) { - fontref = NULL; - Fl_Quartz_Graphics_Driver *driver = (Fl_Quartz_Graphics_Driver*)&Fl_Graphics_Driver::default_driver(); - driver->descriptor_init(name, size, this); -} - - -Fl_Quartz_Font_Descriptor::~Fl_Quartz_Font_Descriptor() { -/* -#if HAVE_GL - // ++ todo: remove OpenGL font allocations -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -#endif - */ - if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); - if (fontref) { - CFRelease(fontref); - for (unsigned i = 0; i < sizeof(width)/sizeof(float*); i++) { - if (width[i]) free(width[i]); - } - } -} - - -static UniChar *utfWbuf = 0; -static unsigned utfWlen = 0; - -static UniChar *mac_Utf8_to_Utf16(const char *txt, int len, int *new_len) -{ - unsigned wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); - if (wlen >= utfWlen) - { - utfWlen = wlen + 100; - if (utfWbuf) free(utfWbuf); - utfWbuf = (UniChar*)malloc((utfWlen)*sizeof(UniChar)); - wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); - } - *new_len = wlen; - return utfWbuf; -} - - -static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { - if (!fl_fonts) fl_fonts = Fl_Graphics_Driver::default_driver().calc_fl_fonts(); - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_Font_Descriptor* f; - for (f = s->first; f; f = f->next) - if (f->size == size) return f; - f = new Fl_Quartz_Font_Descriptor(s->name, size); - f->next = s->first; - s->first = f; - return f; -} - - -void Fl_Quartz_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { - if (fnum == -1) { - Fl_Graphics_Driver::font(0, 0); - return; - } - Fl_Graphics_Driver::font(fnum, size); - font_descriptor( find(fnum, size) ); -} - -Fl_Quartz_Font_Descriptor *Fl_Quartz_Graphics_Driver::valid_font_descriptor() { - // avoid a crash if no font has been selected by user yet - if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); - return (Fl_Quartz_Font_Descriptor*)font_descriptor(); -} - -int Fl_Quartz_Graphics_Driver::height() { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - return fl_fontsize->ascent + fl_fontsize->descent; -} - -int Fl_Quartz_Graphics_Driver::descent() { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - return fl_fontsize->descent + 1; -} - -void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) { - draw(str, n, (float)x, y+0.5f); -} - -void Fl_Quartz_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, x, y); - CGContextRotateCTM(gc_, - angle*(M_PI/180) ); - draw(str, n, 0, 0); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { - int dx, dy, w, h; - text_extents(c, n, dx, dy, w, h); - draw(c, n, x - w - dx, y); -} - -double Fl_Quartz_Graphics_Driver::width(const char* txt, int n) { - if (n == 0) return 0; - int len1 = fl_utf8len1(*txt); - if (len1 > 0 && n > len1) { // a text with several codepoints: compute its typographical width - CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n, kCFStringEncodingUTF8, false); - if (str) { - CFDictionarySetValue(attributes, kCTFontAttributeName, valid_font_descriptor()->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str, attributes); - CFRelease(str); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - double d = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL); - CFRelease(ctline); - return d; - } - } - int wc_len = n; - UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len); - return width(uniStr, wc_len); -} - -double Fl_Quartz_Graphics_Driver::width(unsigned int wc) { - UniChar utf16[3]; - int l = 1; - if (wc <= 0xFFFF) { - *utf16 = wc; - } - else { - l = (int)fl_ucs_to_Utf16(wc, utf16, 3); - } - return width(utf16, l); -} - -void Fl_Quartz_Graphics_Driver::set_fontname_in_fontdesc(Fl_Fontdesc *f) { - CFStringRef cfname = CFStringCreateWithCString(NULL, f->name, kCFStringEncodingUTF8); - CTFontRef ctfont = cfname ? CTFontCreateWithName(cfname, 0, NULL) : NULL; - if (cfname) { CFRelease(cfname); cfname = NULL; } - if (ctfont) { - cfname = CTFontCopyFullName(ctfont); - CFRelease(ctfont); - if (cfname) { - CFStringGetCString(cfname, f->fontname, ENDOFBUFFER, kCFStringEncodingUTF8); - CFRelease(cfname); - } - } - if (!cfname) strlcpy(f->fontname, f->name, ENDOFBUFFER); -} - -const char *Fl_Quartz_Graphics_Driver::font_name(int num) { - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - return fl_fonts[num].name; -} - -void Fl_Quartz_Graphics_Driver::font_name(int num, const char *name) { - Fl_Fontdesc *s = fl_fonts + num; - if (s->name) { - if (!strcmp(s->name, name)) {s->name = name; return;} - for (Fl_Font_Descriptor* f = s->first; f;) { - Fl_Font_Descriptor* n = f->next; delete f; f = n; - } - s->first = 0; - } - s->name = name; - s->fontname[0] = 0; - s->first = 0; -} - - -Fl_Fontdesc* Fl_Quartz_Graphics_Driver::calc_fl_fonts(void) -{ - return built_in_table_PS; -} - - -void Fl_Quartz_Graphics_Driver::descriptor_init(const char* name, - Fl_Fontsize size, Fl_Quartz_Font_Descriptor *d) -{ - CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); - d->fontref = CTFontCreateWithName(str, size, NULL); - CGGlyph glyph[2]; - const UniChar A[2]={'W','.'}; - CTFontGetGlyphsForCharacters(d->fontref, A, glyph, 2); - CGSize advances[2]; - double w; - CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, advances, 2); - w = advances[0].width; - if ( fabs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font - // slightly rescale fixed-width fonts so the character width has an integral value - CFRelease(d->fontref); - CGFloat fsize = size / ( w/floor(w + 0.5) ); - d->fontref = CTFontCreateWithName(str, fsize, NULL); - w = CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, NULL, 1); - } - CFRelease(str); - d->ascent = (short)(CTFontGetAscent(d->fontref) + 0.5); - d->descent = (short)(CTFontGetDescent(d->fontref) + 0.5); - d->q_width = w + 0.5; - for (unsigned i = 0; i < sizeof(d->width)/sizeof(float*); i++) d->width[i] = NULL; - if (!attributes) { - static CFNumberRef zero_ref; - float zero = 0.; - zero_ref = CFNumberCreate(NULL, kCFNumberFloat32Type, &zero); - // deactivate kerning for all fonts, so that string width = sum of character widths - // which allows fast fl_width() implementation. - attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 3, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue (attributes, kCTKernAttributeName, zero_ref); - } - if (d->ascent == 0) { // this may happen with some third party fonts - CFDictionarySetValue (attributes, kCTFontAttributeName, d->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("Wj"), attributes); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGFloat fascent, fdescent; - CTLineGetTypographicBounds(ctline, &fascent, &fdescent, NULL); - CFRelease(ctline); - d->ascent = (short)(fascent + 0.5); - d->descent = (short)(fdescent + 0.5); - } -} - -// returns width of a pair of UniChar's in the surrogate range -static CGFloat surrogate_width(const UniChar *txt, Fl_Quartz_Font_Descriptor *fl_fontsize) -{ - CTFontRef font2 = fl_fontsize->fontref; - bool must_release = false; - CGGlyph glyphs[2]; - bool b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); - CGSize a; - if(!b) { // the current font doesn't contain this char - CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, txt, 2, kCFAllocatorNull); - // find a font that contains it - font2 = CTFontCreateForString(font2, str, CFRangeMake(0,2)); - must_release = true; - CFRelease(str); - b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); - } - if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, glyphs, &a, 1); - else a.width = fl_fontsize->q_width; - if(must_release) CFRelease(font2); - return a.width; -} - -static CGFloat variation_selector_width(CFStringRef str16, Fl_Quartz_Font_Descriptor *fl_fontsize) -{ - CGFloat retval; - CFDictionarySetValue(attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - retval = CTLineGetOffsetForStringIndex(ctline, 2, NULL); - CFRelease(ctline); - return retval; -} - -double Fl_Quartz_Graphics_Driver::width(const UniChar* txt, int n) -{ - double retval = 0; - UniChar uni; - int i; - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - for (i = 0; i < n; i++) { // loop over txt - uni = txt[i]; - if (uni >= 0xD800 && uni <= 0xDBFF) { // handles the surrogate range - retval += surrogate_width(&txt[i], fl_fontsize); - i++; // because a pair of UniChar's represent a single character - continue; - } - if (i+1 < n && txt[i+1] >= 0xFE00 && txt[i+1] <= 0xFE0F) { // handles variation selectors - CFStringRef substr = CFStringCreateWithCharacters(NULL, txt + i, 2); - retval += variation_selector_width(substr, fl_fontsize); - CFRelease(substr); - i++; - continue; - } - const int block = 0x10000 / (sizeof(fl_fontsize->width)/sizeof(float*)); // block size - // r: index of the character block containing uni - unsigned int r = uni >> 7; // change 7 if sizeof(width) is changed - if (!fl_fontsize->width[r]) { // this character block has not been hit yet - //fprintf(stderr,"r=%d size=%d name=%s\n",r,fl_fontsize->size,fl_fonts[fl_font()].name); - // allocate memory to hold width of each character in the block - fl_fontsize->width[r] = (float*) malloc(sizeof(float) * block); - UniChar ii = r * block; - CGSize advance_size; - CGGlyph glyph; - for (int j = 0; j < block; j++) { // loop over the block - // ii spans all characters of this block - bool b = CTFontGetGlyphsForCharacters(fl_fontsize->fontref, &ii, &glyph, 1); - if (b) - CTFontGetAdvancesForGlyphs(fl_fontsize->fontref, kCTFontOrientationHorizontal, &glyph, &advance_size, 1); - else - advance_size.width = -1e9; // calculate this later - // the width of one character of this block of characters - fl_fontsize->width[r][j] = advance_size.width; - ii++; - } - } - // sum the widths of all characters of txt - double wdt = fl_fontsize->width[r][uni & (block-1)]; - if (wdt == -1e9) { - CGSize advance_size; - CGGlyph glyph; - CTFontRef font2 = fl_fontsize->fontref; - bool must_release = false; - bool b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); - if (!b) { // the current font doesn't contain this char - CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, &uni, 1, kCFAllocatorNull); - // find a font that contains it - font2 = CTFontCreateForString(font2, str, CFRangeMake(0,1)); - must_release = true; - CFRelease(str); - b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); - } - if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, &glyph, &advance_size, 1); - else advance_size.width = 0.; - // the width of the 'uni' character - wdt = fl_fontsize->width[r][uni & (block-1)] = advance_size.width; - if (must_release) CFRelease(font2); - } - retval += wdt; - } - return retval; -} - - -// text extent calculation -void Fl_Quartz_Graphics_Driver::text_extents(const char *str8, int n, - int &dx, int &dy, int &w, int &h) { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n); - CFStringRef str16 = CFStringCreateWithCharactersNoCopy(NULL, txt, n, kCFAllocatorNull); - CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CFRelease(str16); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGContextSetTextPosition(gc_, 0, 0); - CGContextSetShouldAntialias(gc_, true); - CGRect rect = CTLineGetImageBounds(ctline, gc_); - CGContextSetShouldAntialias(gc_, false); - CFRelease(ctline); - dx = floor(rect.origin.x + 0.5); - dy = floor(- rect.origin.y - rect.size.height + 0.5); - w = rect.size.width + 0.5; - h = rect.size.height + 0.5; -} - - -static CGColorRef flcolortocgcolor(Fl_Color i) -{ - uchar r, g, b; - Fl::get_color(i, r, g, b); - CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.}; - static CGColorSpaceRef cspace = NULL; - if (cspace == NULL) { - cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - } - return CGColorCreate(cspace, components); -} - -void Fl_Quartz_Graphics_Driver::draw(const char *str, int n, float x, float y) -{ - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - // convert to UTF-16 first - UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n); - CGContextRef gc = (CGContextRef)this->gc(); - CFMutableStringRef str16 = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, uniStr, n, n, kCFAllocatorNull); - if (str16 == NULL) return; // shd not happen - CGColorRef color = flcolortocgcolor(this->color()); - CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFDictionarySetValue (attributes, kCTForegroundColorAttributeName, color); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CFRelease(str16); - CFRelease(color); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGContextSetTextMatrix(gc, font_mx); - CGContextSetTextPosition(gc, x, y); - CGContextSetShouldAntialias(gc, true); - CTLineDraw(ctline, gc); - CGContextSetShouldAntialias(gc, false); - CFRelease(ctline); -} - -// Skip over bold/italic/oblique qualifiers part of PostScript font names -// Example: -// input: '-Regular_Light-Condensed' -// return: '_Light-Condensed' -// -static char *skip(char *p, int& derived) -{ - // 0 5 10 - // | | | - if (strncmp(p, "-BoldItalic", 11) == 0) { p += 11; derived = 3; } - else if (strncmp(p, "-BoldOblique", 12) == 0) { p += 12; derived = 3; } - else if (strncmp(p, "-Bold", 5) == 0) { p += 5; derived = 1; } - else if (strncmp(p, "-Italic", 7) == 0) { p += 7; derived = 2; } - else if (strncmp(p, "-Oblique", 8) == 0) { p += 8; derived = 2; } - else if (strncmp(p, "-Regular", 8) == 0) { p += 8; } - else if (strncmp(p, "-Roman", 6) == 0) { p += 6; } - return p; -} - -static int name_compare(const void *a, const void *b) -{ - /* Compare PostScript font names. - First compare font family names ignoring bold, italic and oblique qualifiers. - When families are identical, order them according to regular, bold, italic, bolditalic. - */ - char *n1 = *(char**)a; - char *n2 = *(char**)b; - int derived1 = 0; - int derived2 = 0; - while (true) { - if (*n1 == '-') n1 = skip(n1, derived1); - if (*n2 == '-') n2 = skip(n2, derived2); - if (*n1 < *n2) return -1; - if (*n1 > *n2) return +1; - if (*n1 == 0) { - return derived1 - derived2; - } - n1++; n2++; - } -} - -Fl_Font Fl_Quartz_Graphics_Driver::set_fonts(const char* xstarname) -{ -#pragma unused ( xstarname ) - if (fl_free_font > FL_FREE_FONT) return (Fl_Font)fl_free_font; // if already called - - int value[1] = {1}; - CFDictionaryRef dict = CFDictionaryCreate(NULL, - (const void **)kCTFontCollectionRemoveDuplicatesOption, - (const void **)&value, 1, NULL, NULL); - CTFontCollectionRef fcref = CTFontCollectionCreateFromAvailableFonts(dict); - CFRelease(dict); - CFArrayRef arrayref = CTFontCollectionCreateMatchingFontDescriptors(fcref); - CFRelease(fcref); - CFIndex count = CFArrayGetCount(arrayref); - CFIndex i; - char **tabfontnames = new char*[count]; - for (i = 0; i < count; i++) { - CTFontDescriptorRef fdesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arrayref, i); - CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, 0., NULL); - CFStringRef cfname = CTFontCopyPostScriptName(font); - CFRelease(font); - CFDataRef cfdata = CFStringCreateExternalRepresentation(NULL, cfname, kCFStringEncodingUTF8, '?'); - CFIndex l = CFDataGetLength(cfdata); - tabfontnames[i] = (char*)malloc(l+1); // never free'ed - memcpy(tabfontnames[i], CFDataGetBytePtr(cfdata), l); - tabfontnames[i][l] = 0; - CFRelease(cfdata); - CFRelease(cfname); - } - CFRelease(arrayref); - qsort(tabfontnames, count, sizeof(char*), name_compare); - for (i = 0; i < count; i++) { - Fl::set_font((Fl_Font)(fl_free_font++), tabfontnames[i]); - } - delete[] tabfontnames; - return (Fl_Font)fl_free_font; -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx deleted file mode 100644 index 932ef7d82..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx +++ /dev/null @@ -1,284 +0,0 @@ -// -// MacOS image drawing code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> - -#define MAXBUFFER 0x40000 // 256k - -static void dataReleaseCB(void *info, const void *data, size_t size) -{ - delete[] (uchar *)data; -} - -/* - draw an image based on the input parameters - - buf: image source data - X, Y: position (in buffer?!) - W, H: size of picture (in pixel?) - delta: distance from pixel to pixel in buf in bytes - linedelta: distance from line to line in buf in bytes - mono: if set, pixel is one byte - if zero, pixel is 3 byte - cb: callback to copy image data into (RGB?) buffer - buf: pointer to first byte in image source - x, y: position in buffer - w: width (in bytes?) - dst: destination buffer - userdata: ? - */ -static void innards(const uchar *buf, int X, int Y, int W, int H, - int delta, int linedelta, int mono, - Fl_Draw_Image_Cb cb, void* userdata, CGContextRef gc, Fl_Quartz_Graphics_Driver *driver) -{ - if (!linedelta) linedelta = W*abs(delta); - - uchar *tmpBuf = 0; - if (!cb) { - if (delta < 0) buf -= (W-1)*(-delta); - if (linedelta < 0) buf -= (H-1)*abs(linedelta); - } - const void *array = buf; - if (cb || driver->has_feature(Fl_Quartz_Graphics_Driver::PRINTER)) { - tmpBuf = new uchar[ H*W*abs(delta) ]; - if (cb) { - for (int i=0; i<H; i++) { - cb(userdata, 0, i, W, tmpBuf+i*W*abs(delta)); - } - } else { - uchar *p = tmpBuf; - for (int i=0; i<H; i++) { - memcpy(p, buf+i*abs(linedelta), W*abs(delta)); - p += W*abs(delta); - } - } - array = (void*)tmpBuf; - linedelta = W*abs(delta); - } - // create an image context - CGColorSpaceRef lut = 0; - if (abs(delta)<=2) - lut = CGColorSpaceCreateDeviceGray(); - else - lut = CGColorSpaceCreateDeviceRGB(); - // a release callback is necessary when the gc is a print context because the image data - // must be kept until the page is closed. Thus tmpBuf can't be deleted here. It's too early. - CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, abs(linedelta)*H, - tmpBuf ? dataReleaseCB : NULL - ); - CGImageRef img = CGImageCreate( W, H, 8, 8*abs(delta), abs(linedelta), - lut, abs(delta)&1?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(lut); - CGDataProviderRelease(src); - // draw the image into the destination context - if (img) { - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, X, Y); - if (linedelta < 0) { - CGContextTranslateCTM(gc, 0, H-1); - CGContextScaleCTM(gc, 1, -1); - } - if (delta < 0) { - CGContextTranslateCTM(gc, W-1, 0); - CGContextScaleCTM(gc, -1, 1); - } - driver->draw_CGImage(img, 0,0,W,H, 0,0,W,H); - CGImageRelease(img); - CGContextRestoreGState(gc); - } -} - -void Fl_Quartz_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ - d &= ~FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ - innards(buf,x,y,w,h,d,l,1,0,0,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - innards(0,x,y,w,h,d,0,1,cb,data,gc_,this); -} - - -void Fl_Quartz_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (!bm->array) { - draw_empty(bm, XP, YP); - return; - } - if (start_image(bm, XP,YP,WP,HP,cx,cy,X,Y,W,H)) return; - if (!*id(bm)) - cache(bm); - - if (*Fl_Graphics_Driver::id(bm) && gc_) { - draw_CGImage((CGImageRef)*Fl_Graphics_Driver::id(bm), X,Y,W,H, cx, cy, bm->w(), bm->h()); - } -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_RGB_Image *rgb) { - CGColorSpaceRef lut = rgb->d()<=2 ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); - int ld = rgb->ld(); - if (!ld) ld = rgb->data_w() * rgb->d(); - CGDataProviderRef src; - if ( has_feature(PRINTER) ) { - // When printing or copying to clipboard, the data at rgb->array are used when - // the PDF page is completed, that is, after return from this function. - // At that stage, the rgb object has possibly been deleted. It is therefore necessary - // to use a copy of rgb->array. The mask_ member of rgb - // is used to avoid repeating the copy operation if rgb is drawn again. - // The CGImage data provider deletes the copy at the latest of these two events: - // deletion of rgb, and completion of the PDF page where rgb was drawn. - size_t total = ld * rgb->data_h(); - uchar *copy = new uchar[total]; - memcpy(copy, rgb->array, total); - src = CGDataProviderCreateWithData(NULL, copy, total, dataReleaseCB); - *Fl_Graphics_Driver::mask(rgb) = 1; - } else { - // the CGImage data provider must not release the image data. - src = CGDataProviderCreateWithData(NULL, rgb->array, ld * rgb->data_h(), NULL); - } - CGImageRef cgimg = CGImageCreate(rgb->data_w(), rgb->data_h(), 8, rgb->d()*8, ld, - lut, (rgb->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, false, kCGRenderingIntentDefault); - *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)cgimg; - CGColorSpaceRelease(lut); - CGDataProviderRelease(src); -} - -void Fl_Quartz_Graphics_Driver::draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!img->d() || !img->array) { - Fl_Graphics_Driver::draw_empty(img, XP, YP); - return; - } - if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - CGImageRef cgimg = (CGImageRef)*Fl_Graphics_Driver::id(img); - if (cgimg && has_feature(PRINTER) && !*Fl_Graphics_Driver::mask(img)) { - CGImageRelease(cgimg); - *Fl_Graphics_Driver::id(img) = 0; - cgimg = NULL; - } - if (!cgimg) { - cache(img); - cgimg = (CGImageRef)*Fl_Graphics_Driver::id(img); - } - if (cgimg && gc_) { - draw_CGImage(cgimg, X,Y,W,H, cx,cy, img->w(), img->h()); - } -} - -void Fl_Quartz_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (!pxm->data() || !pxm->w()) { - draw_empty(pxm, XP, YP); - return; - } - if ( start_image(pxm, XP,YP,WP,HP,cx,cy,X,Y,W,H) ) return; - if (!*id(pxm)) { - cache(pxm); - } - - CGImageRef cgimg = (CGImageRef)*Fl_Graphics_Driver::id(pxm); - draw_CGImage(cgimg, X,Y,W,H, cx,cy, pxm->w(), pxm->h()); -} - -CGImageRef Fl_Quartz_Graphics_Driver::create_bitmask(int w, int h, const uchar *array) { - static uchar reverse[16] = /* Bit reversal lookup table */ - { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, - 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; - int rowBytes = (w+7)>>3 ; - uchar *bmask = new uchar[rowBytes*h]; - uchar *dst = bmask; - const uchar *src = array; - for ( int i=rowBytes*h; i>0; i--,src++ ) { - *dst++ = ((reverse[*src & 0x0f] & 0xf0) | (reverse[(*src >> 4) & 0x0f] & 0x0f))^0xff; - } - CGDataProviderRef srcp = CGDataProviderCreateWithData( NULL, bmask, rowBytes*h, dataReleaseCB); - CGImageRef id_ = CGImageMaskCreate( w, h, 1, 1, rowBytes, srcp, 0L, false); - CGDataProviderRelease(srcp); - return id_; -} - -void Fl_Quartz_Graphics_Driver::delete_bitmask(fl_uintptr_t bm) { - if (bm) CGImageRelease((CGImageRef)bm); -} - -void Fl_Quartz_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) { - if (id_) { - CGImageRelease((CGImageRef)id_); - id_ = 0; - mask_ = 0; - } -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_Bitmap *bm) { - *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)create_bitmask(bm->data_w(), bm->data_h(), bm->array); -} - - -static void pmProviderRelease (void *ctxt, const void *data, size_t size) { - CFRelease(ctxt); -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_Pixmap *img) { - Fl_Image_Surface *surf = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surf); - fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); - Fl_Surface_Device::pop_current(); - CGContextRef src = (CGContextRef)Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surf); - void *cgdata = CGBitmapContextGetData(src); - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(src); - CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef src_bytes = CGDataProviderCreateWithData(src, cgdata, sw*sh*4, pmProviderRelease); - CGImageRef cgimg = CGImageCreate( sw, sh, 8, 4*8, 4*sw, lut, alpha, - src_bytes, 0L, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(lut); - CGDataProviderRelease(src_bytes); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)cgimg; -} - -void Fl_Quartz_Graphics_Driver::draw_CGImage(CGImageRef cgimg, int x, int y, int w, int h, int srcx, int srcy, int sw, int sh) -{ - CGRect rect = CGRectMake(x, y, w, h); - CGContextSaveGState(gc_); - CGContextClipToRect(gc_, CGRectOffset(rect, -0.5, -0.5 )); - // move graphics context to origin of vertically reversed image - // The 0.5 here cancels the 0.5 offset present in Quartz graphics contexts. - // Thus, image and surface pixels are in phase. - CGContextTranslateCTM(gc_, rect.origin.x - srcx - 0.5, rect.origin.y - srcy + sh - 0.5); - CGContextScaleCTM(gc_, 1, -1); - CGContextDrawImage(gc_, CGRectMake(0, 0, sw, sh), cgimg); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::uncache_pixmap(fl_uintptr_t pixmap_ref) { - CGImageRelease((CGImageRef)pixmap_ref); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx deleted file mode 100644 index 6a63ae483..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx +++ /dev/null @@ -1,83 +0,0 @@ -// -// Line style code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/fl_draw.H> -#include <FL/platform.H> - - -/** - \file quartz_line_style.cxx - \brief Line style drawing utility hiding different platforms. -*/ - -#include "Fl_Quartz_Graphics_Driver.H" - -void Fl_Quartz_Graphics_Driver::quartz_restore_line_style() { - CGContextSetLineWidth(gc_, quartz_line_width_); - CGContextSetLineCap(gc_, quartz_line_cap_); - CGContextSetLineJoin(gc_, quartz_line_join_); - CGContextSetLineDash(gc_, 0, quartz_line_pattern, quartz_line_pattern_size); -} - -void Fl_Quartz_Graphics_Driver::line_style(int style, int width, char* dashes) { - - static CGLineCap Cap[4] = { kCGLineCapButt, kCGLineCapButt, - kCGLineCapRound, kCGLineCapSquare }; - static CGLineJoin Join[4] = { kCGLineJoinMiter, kCGLineJoinMiter, - kCGLineJoinRound, kCGLineJoinBevel }; - if (width<1) width = 1; - quartz_line_width_ = (float)width; - quartz_line_cap_ = Cap[(style>>8)&3]; - // when printing kCGLineCapSquare seems better for solid lines - if ( Fl_Surface_Device::surface() != Fl_Display_Device::display_device() - && style == FL_SOLID && dashes == NULL ) - { - quartz_line_cap_ = kCGLineCapSquare; - } - quartz_line_join_ = Join[(style>>12)&3]; - char *d = dashes; - static CGFloat pattern[16]; - if (d && *d) { - CGFloat *pDst = pattern; - while (*d) { *pDst++ = (float)*d++; } - quartz_line_pattern = pattern; - quartz_line_pattern_size = (int)(d-dashes); - } else if (style & 0xff) { - char dash, dot, gap; - // adjust lengths to account for cap: - if (style & 0x200) { - dash = char(2*width); - dot = 1; - gap = char(2*width-1); - } else { - dash = char(3*width); - dot = gap = char(width); - } - CGFloat *pDst = pattern; - switch (style & 0xff) { - case FL_DASH: *pDst++ = dash; *pDst++ = gap; break; - case FL_DOT: *pDst++ = dot; *pDst++ = gap; break; - case FL_DASHDOT: *pDst++ = dash; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; break; - case FL_DASHDOTDOT: *pDst++ = dash; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; break; - } - quartz_line_pattern_size = (int)(pDst-pattern); - quartz_line_pattern = pattern; - } else { - quartz_line_pattern = 0; - quartz_line_pattern_size = 0; - } - quartz_restore_line_style(); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx deleted file mode 100644 index 234853ad6..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx +++ /dev/null @@ -1,310 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <math.h> - - -/** - \file quartz_rect.cxx - \brief Apple Quartz specific line and polygon drawing with integer coordinates. -*/ - - -#include "Fl_Quartz_Graphics_Driver.H" - - -// --- line and polygon drawing with integer coordinates - -void Fl_Quartz_Graphics_Driver::point(int x, int y) { - CGContextFillRect(gc_, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); -} - -void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - double offset = (quartz_line_width_ >= 2 ? quartz_line_width_/4 : 0); - CGRect rect = CGRectMake(x - offset, y - offset, w-1, h-1); - CGContextStrokeRect(gc_, rect); -} - -void Fl_Quartz_Graphics_Driver::focus_rect(int x, int y, int w, int h) -{ - CGContextSaveGState(gc_); - float s = scale(); - CGContextScaleCTM(gc_, 1/s, 1/s); - CGFloat lw = (s >= 1 ? floor(s) : 1); - CGContextSetLineWidth(gc_, lw); - CGFloat dots[2] = {lw, lw}; - CGContextSetLineDash(gc_, 0, dots, 2); - CGContextStrokeRect(gc_, CGRectMake(x*s, y*s, (w-1)*s, (h-1)*s)); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); - CGContextFillRect(gc_, rect); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit - (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles - of size one unit by line-width. - */ - CGContextFillRect(gc_, CGRectMake(x-0.5 , y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x1-0.5 , y - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextAddLineToPoint(gc_, x1, y2); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x1 - quartz_line_width_/2, y2-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextAddLineToPoint(gc_, x1, y2); - CGContextAddLineToPoint(gc_, x3, y2); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x3-0.5, y2 - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y1-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextAddLineToPoint(gc_, x2, y1); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x2-0.5, y1 - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextAddLineToPoint(gc_, x2, y1); - CGContextAddLineToPoint(gc_, x2, y3); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x2 - quartz_line_width_/2, y3-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextAddLineToPoint(gc_, x3, y3); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { - float s = scale(); if (s < 2) s = 0; - CGContextSetLineWidth(gc_, 0.05); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x+w-1 +s/8, y); - CGContextAddLineToPoint(gc_, x+w-1 +s/8, y+h-1 -s/8); - CGContextAddLineToPoint(gc_, x, y+h-1 -s/8); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - CGContextSetLineWidth(gc_, quartz_line_width_); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextAddLineToPoint(gc_, x3, y3); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -// --- clipping - -// intersects current and x,y,w,h rectangle and returns result as a new Fl_Region -static Fl_Region intersect_region_and_rect(Fl_Region current_, int x,int y,int w, int h) -{ - if (current_ == NULL) return Fl_Graphics_Driver::default_driver().XRectangleRegion(x,y,w,h); - struct flCocoaRegion* current = (struct flCocoaRegion*)current_; - CGRect r = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(x, y, w, h); - struct flCocoaRegion* outr = (struct flCocoaRegion*)malloc(sizeof(struct flCocoaRegion)); - outr->count = current->count; - outr->rects =(CGRect*)malloc(outr->count * sizeof(CGRect)); - int j = 0; - for(int i = 0; i < current->count; i++) { - CGRect test = CGRectIntersection(current->rects[i], r); - if (!CGRectIsEmpty(test)) outr->rects[j++] = test; - } - if (j) { - outr->count = j; - outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect)); - } - else { - Fl_Graphics_Driver::default_driver().XDestroyRegion(outr); - outr = (struct flCocoaRegion*)Fl_Graphics_Driver::default_driver().XRectangleRegion(0,0,0,0); - } - return outr; -} - - -void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { - Fl_Region r; - if (w > 0 && h > 0) { - r = XRectangleRegion(x,y,w,h); - Fl_Region current = rstack[rstackptr]; - if (current) { - XDestroyRegion(r); - r = intersect_region_and_rect(current, x,y,w,h); - } - } else { // make empty clip region: - r = XRectangleRegion(0,0,0,0); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); - restore_clip(); -} - -int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if (!r) return 0; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - CGRect u = CGRectMake(0,0,0,0); - CGRect test; - for (int i = 0; i < r->count; i++) { - test = CGRectIntersection(r->rects[i], arg); - if ( !CGRectIsEmpty(test) ) { - if(CGRectIsEmpty(u)) u = test; - else u = CGRectUnion(u, test); - } - } - X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() - Y = int(u.origin.y + 0.5); - W = int(u.size.width + 0.5); // round to nearest integer - H = int(u.size.height + 0.5); - if (CGRectIsEmpty(u)) W = H = 0; - return !CGRectEqualToRect(arg, u); -} - -int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if (!r) return 1; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - for (int i = 0; i < r->count; i++) { - CGRect test = CGRectIntersection(r->rects[i], arg); - if (!CGRectIsEmpty(test)) return 1; - } - return 0; -} - -void Fl_Quartz_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if ( fl_window || gc_ ) { // clipping for a true window or an offscreen buffer - if (gc_) { - CGContextRestoreGState(gc_); - CGContextSaveGState(gc_); - } - color(color()); - quartz_restore_line_style(); - if (r) { //apply program clip - CGContextClipToRects(gc_, r->rects, r->count); - } - } -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx deleted file mode 100644 index 16c6c6c29..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx +++ /dev/null @@ -1,98 +0,0 @@ -// -// Portable drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file quartz_vertex.cxx - \brief Portable drawing code for drawing arbitrary shapes with - simple 2D transformations, implemented for OS X Quartz. -*/ - -#include "Fl_Quartz_Graphics_Driver.H" - -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/math.h> - - -void Fl_Quartz_Graphics_Driver::end_points() { - for (int i = 0; i < n; i++) { - point(xpoint[i].x, xpoint[i].y); - } -} - -void Fl_Quartz_Graphics_Driver::end_line() { - if (n < 2) { - end_points(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextStrokePath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::end_polygon() { - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::end_complex_polygon() { - gap(); - if (n < 3) { - end_line(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::circle(double x, double y,double r) { - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - - // Quartz warning: circle won't scale to current matrix! - // Last argument must be 0 (counter-clockwise) or it draws nothing under __LP64__ !!!! - CGContextSetShouldAntialias(gc_, true); - CGContextAddArc(gc_, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 0); - (what == POLYGON ? CGContextFillPath : CGContextStrokePath)(gc_); - CGContextSetShouldAntialias(gc_, false); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H deleted file mode 100644 index 3849ea4df..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H +++ /dev/null @@ -1,38 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_QUARTZ_IMAGE_SURFACE_DRIVER_H -#define FL_QUARTZ_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> -#include <FL/platform.H> - -class Fl_Quartz_Image_Surface_Driver : public Fl_Image_Surface_Driver { -private: - CGImageRef mask_; - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - void end_current() FL_OVERRIDE; -public: - FLWindow *pre_window; - Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_Quartz_Image_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; -}; - -#endif // FL_QUARTZ_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx deleted file mode 100644 index 4615ba475..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx +++ /dev/null @@ -1,167 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "Fl_Quartz_Image_Surface_Driver.H" -#include "Fl_Quartz_Graphics_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" -#include <ApplicationServices/ApplicationServices.h> - - -Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - mask_ = NULL; - int W = w, H = h; - float s = 1; - if (high_res) { - s = Fl_Graphics_Driver::default_driver().scale(); - Fl_Window *cw = Fl::first_window(); - Fl_Cocoa_Window_Driver *dr = cw ? Fl_Cocoa_Window_Driver::driver(cw) : NULL; - if (dr && dr->mapped_to_retina()) s *= 2; - W *= s; H *= s; - } - CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); - offscreen = off ? off : (Fl_Offscreen)CGBitmapContextCreate(calloc(W*H,4), W, H, 8, W*4, lut, kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(lut); - driver(new Fl_Quartz_Graphics_Driver); - CGContextTranslateCTM((CGContextRef)offscreen, 0.5*s, -0.5*s); // as when drawing to a window - if (high_res) { - CGContextScaleCTM((CGContextRef)offscreen, s, s); - driver()->scale(s); - } - CGContextSetShouldAntialias((CGContextRef)offscreen, false); - CGContextTranslateCTM((CGContextRef)offscreen, 0, height); - CGContextScaleCTM((CGContextRef)offscreen, 1.0f, -1.0f); - CGContextSaveGState((CGContextRef)offscreen); - CGContextSetRGBFillColor((CGContextRef)offscreen, 1, 1, 1, 0); - CGContextFillRect((CGContextRef)offscreen, CGRectMake(0,0,w,h)); -} - -Fl_Quartz_Image_Surface_Driver::~Fl_Quartz_Image_Surface_Driver() { - if (mask_) { - CGImageRelease(mask_); - } - if (offscreen) CGContextRestoreGState((CGContextRef)offscreen); - if (offscreen && !external_offscreen) { - void *data = CGBitmapContextGetData((CGContextRef)offscreen); - free(data); - CGContextRelease((CGContextRef)offscreen); - } - delete driver(); -} - - -void Fl_Quartz_Image_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - pre_window = fl_window; - driver()->gc((CGContextRef)offscreen); - fl_window = 0; - ((Fl_Quartz_Graphics_Driver*)driver())->high_resolution( CGBitmapContextGetWidth((CGContextRef)offscreen) > (size_t)width ); - if (mask_) { - int W, H; - printable_rect(&W, &H); - CGContextSaveGState((CGContextRef)offscreen); - CGContextClipToMask((CGContextRef)offscreen, CGRectMake(0,0,W,H), mask_); // 10.4 - CGContextSaveGState((CGContextRef)offscreen); - } -} - -void Fl_Quartz_Image_Surface_Driver::translate(int x, int y) { - CGContextRestoreGState((CGContextRef)offscreen); - CGContextSaveGState((CGContextRef)offscreen); - CGContextTranslateCTM((CGContextRef)offscreen, x, y); - CGContextSaveGState((CGContextRef)offscreen); -} - -void Fl_Quartz_Image_Surface_Driver::untranslate() { - CGContextRestoreGState((CGContextRef)offscreen); -} - -Fl_RGB_Image* Fl_Quartz_Image_Surface_Driver::image() -{ - CGContextFlush((CGContextRef)offscreen); - if (mask_) { - CGContextRestoreGState((CGContextRef)offscreen); - CGImageRelease(mask_); - mask_ = NULL; - } - int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen); - int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen); - int bpr = (int)CGBitmapContextGetBytesPerRow((CGContextRef)offscreen); - int bpp = (int)CGBitmapContextGetBitsPerPixel((CGContextRef)offscreen)/8; - uchar *base = (uchar*)CGBitmapContextGetData((CGContextRef)offscreen); - int idx, idy; - uchar *pdst, *psrc; - unsigned char *data = new uchar[W * H * 3]; - for (idy = 0, pdst = data; idy < H; idy ++) { - for (idx = 0, psrc = base + idy * bpr; idx < W; idx ++, psrc += bpp, pdst += 3) { - pdst[0] = psrc[0]; // R - pdst[1] = psrc[1]; // G - pdst[2] = psrc[2]; // B - } - } - Fl_RGB_Image *image = new Fl_RGB_Image(data, W, H); - image->alloc_array = 1; - return image; -} - -void Fl_Quartz_Image_Surface_Driver::end_current() -{ - if (mask_) { - CGContextRestoreGState((CGContextRef)offscreen); - CGContextRestoreGState((CGContextRef)offscreen); - } - fl_window = pre_window; - Fl_Surface_Device::end_current(); -} - - -static void MyProviderReleaseData (void *info, const void *data, size_t size) { - delete[] (uchar*)data; -} - - -void Fl_Quartz_Image_Surface_Driver::mask(const Fl_RGB_Image *img) { - if (!&CGContextClipToMask) return; - int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen); - int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen); - bool using_copy = false; - if (W != img->data_w() || H != img->data_h()) { - Fl_RGB_Image *copy = (Fl_RGB_Image*)img->copy(W, H); - img = copy; - using_copy = true; - } - - int i, d = img->d(), w = img->data_w(), h = img->data_h(); - // reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits - int bytes_per_row = (img->ld() ? img->ld() : w * d); - uchar *from = new uchar[w * h]; - for ( i = 0; i < h; i++) { - const uchar *p = img->array + bytes_per_row * i; - const uchar *last = p + bytes_per_row; - uchar *q = from + (h - 1 - i) * w; - while (p < last) { - unsigned u = *p++; - u += *p++; - u += *p++; - *q++ = ~(u/3); - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, w * h, MyProviderReleaseData); - mask_ = CGImageMaskCreate(w, h, 8, 8, w, provider, NULL, false); - CFRelease(provider); - if (using_copy) delete img; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H deleted file mode 100644 index e10a801ce..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_COPY_SURFACE_DRIVER_H -#define FL_WAYLAND_COPY_SURFACE_DRIVER_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/Fl_Image_Surface.H> - -class Fl_Wayland_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; - Fl_Image_Surface *img_surf; -protected: - Fl_Wayland_Copy_Surface_Driver(int w, int h); - ~Fl_Wayland_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif // FL_WAYLAND_COPY_SURFACE_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx deleted file mode 100644 index 043114781..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Copy_Surface_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" - - -Fl_Wayland_Copy_Surface_Driver::Fl_Wayland_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - float os_scale = Fl_Graphics_Driver::default_driver().scale(); - int d = 1; - if (Fl::first_window()) { - d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale(); - } - img_surf = new Fl_Image_Surface(int(w * os_scale) * d, int(h * os_scale) * d); - driver(img_surf->driver()); - driver()->scale(d * os_scale); -} - - -Fl_Wayland_Copy_Surface_Driver::~Fl_Wayland_Copy_Surface_Driver() { - Fl_RGB_Image *rgb = img_surf->image(); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - scr_driver->copy_image(rgb->array, rgb->data_w(), rgb->data_h()); - delete rgb; - delete img_surf; - driver(NULL); -} - - -void Fl_Wayland_Copy_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver(); - if (!dr->cr()) dr->set_cairo((cairo_t*)img_surf->offscreen()); -} - - -void Fl_Wayland_Copy_Surface_Driver::translate(int x, int y) { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y); -} - - -void Fl_Wayland_Copy_Surface_Driver::untranslate() { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate(); -} diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H deleted file mode 100644 index ad67c01bf..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H +++ /dev/null @@ -1,62 +0,0 @@ -// -// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_GL_WINDOW_DRIVER_H -#define FL_WAYLAND_GL_WINDOW_DRIVER_H - -#include <config.h> -#if HAVE_GL -#include "../../Fl_Gl_Window_Driver.H" -#include <wayland-egl.h> -#include <EGL/egl.h> -#include <FL/gl.h> - - -class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - friend class Fl_Wayland_Gl_Plugin; -private: - static EGLDisplay egl_display; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; - bool need_swap; - Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win); - float pixels_per_unit() FL_OVERRIDE; - void make_current_before() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void resize(int is_a_resize, int w, int h) FL_OVERRIDE; - char swap_type() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void gl_start() FL_OVERRIDE; - void gl_visual(Fl_Gl_Choice *c) FL_OVERRIDE; - void init(); - void* GetProcAddress(const char *procName) FL_OVERRIDE; -public: - static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time); - //virtual bool need_scissor() { return true; } // CONTROL_LEAKING_SUB_GL_WINDOWS - //void apply_scissor(); // CONTROL_LEAKING_SUB_GL_WINDOWS -}; - -#endif // HAVE_GL -#endif // FL_WAYLAND_GL_WINDOW_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx deleted file mode 100644 index d20b941b7..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx +++ /dev/null @@ -1,486 +0,0 @@ -// -// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> -#include "../../Fl_Gl_Choice.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Gl_Window_Driver.H" -#include "../Posix/Fl_Posix_System_Driver.H" -#ifdef FLTK_USE_X11 -# include "../X11/Fl_X11_Gl_Window_Driver.H" -#endif -#include <wayland-egl.h> -#include <EGL/egl.h> -#include <FL/gl.h> - -/* Implementation notes about OpenGL drawing on the Wayland platform - -* After eglCreateWindowSurface() with attributes {EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER, EGL_NONE}, -eglQueryContext() reports that EGL_RENDER_BUFFER equals EGL_BACK_BUFFER. -This experiment suggests that the platform only supports double-buffer drawing. -Consequently, FL_DOUBLE is enforced in all Fl_Gl_Window::mode_ values under Wayland. - -* Commented out code marked with CONTROL_LEAKING_SUB_GL_WINDOWS aims to prevent - sub GL windows from leaking out from their parent by making leaking parts fully transparent. - This code is commented out because it requires the FL_ALPHA flag to be on - which not all client applications do. -*/ - -// Describes crap needed to create a GLContext. -class Fl_Wayland_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_Wayland_Gl_Window_Driver; -private: - EGLConfig egl_conf; -public: - Fl_Wayland_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - egl_conf = 0; - } -}; - - -struct gl_start_support { // to support use of gl_start / gl_finish - struct wl_surface *surface; - struct wl_subsurface *subsurface; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; -}; - - -static EGLConfig wld_egl_conf = NULL; -static EGLint swap_interval_ = 1; -static EGLint max_swap_interval = 1000; -static EGLint min_swap_interval = 0; - - -EGLDisplay Fl_Wayland_Gl_Window_Driver::egl_display = EGL_NO_DISPLAY; - - -Fl_Wayland_Gl_Window_Driver::Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win) : - Fl_Gl_Window_Driver(win) { - if (egl_display == EGL_NO_DISPLAY) init(); - egl_window = NULL; - egl_surface = NULL; - need_swap = false; -} - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ -#ifdef FLTK_USE_X11 - if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_X11_Gl_Window_Driver(w); -#endif - return new Fl_Wayland_Gl_Window_Driver(w); -} - - -void Fl_Wayland_Gl_Window_Driver::init() { - EGLint major, minor; - - if (!fl_wl_display()) fl_open_display(); - egl_display = eglGetDisplay((EGLNativeDisplayType) fl_wl_display()); - if (egl_display == EGL_NO_DISPLAY) { - Fl::fatal("Can't create egl display\n"); - } - - if (eglInitialize(egl_display, &major, &minor) != EGL_TRUE) { - Fl::fatal("Can't initialise egl display\n"); - } - //printf("EGL major: %d, minor %d\n", major, minor); - //eglGetConfigs(egl_display, NULL, 0, &configs_count); - //printf("EGL has %d configs\n", configs_count); - eglBindAPI(EGL_OPENGL_API); -} - - -Fl_Gl_Choice *Fl_Wayland_Gl_Window_Driver::find(int m, const int *alistp) -{ - m |= FL_DOUBLE; - //if (pWindow->parent()) m |= FL_ALPHA; // CONTROL_LEAKING_SUB_GL_WINDOWS - Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)Fl_Gl_Window_Driver::find_begin( - m, alistp); - if (g) return g; - - EGLint n; - EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_DEPTH_SIZE, 0, // set at 11 - EGL_SAMPLE_BUFFERS, 0, // set at 13 - EGL_STENCIL_SIZE, 0, // set at 15 - EGL_ALPHA_SIZE, 0, // set at 17 - EGL_NONE - }; - - if (m & FL_DEPTH32) - config_attribs[11] = 32; // request at least 32 bits - else if (m & FL_DEPTH) - config_attribs[11] = 1; // accept any size - - if (m & FL_MULTISAMPLE) config_attribs[13] = 1; - if (m & FL_STENCIL) config_attribs[15] = 1; - if (m & FL_ALPHA) config_attribs[17] = (m & FL_RGB8) ? 8 : 1; - - g = new Fl_Wayland_Gl_Choice(m, alistp, first); - eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n); - if (n == 0 && (m & FL_MULTISAMPLE)) { - config_attribs[13] = 0; - eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n); - } - if (n == 0) { - Fl::fatal("failed to choose an EGL config\n"); - } - - eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MAX_SWAP_INTERVAL, &max_swap_interval); - eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MIN_SWAP_INTERVAL, &min_swap_interval); - - first = g; - return g; -} - - -GLContext Fl_Wayland_Gl_Window_Driver::create_gl_context(Fl_Window* window, - const Fl_Gl_Choice* g) { - GLContext shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - - static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - GLContext ctx = (GLContext)eglCreateContext(egl_display, - ((Fl_Wayland_Gl_Choice*)g)->egl_conf, - (shared_ctx ? (EGLContext)shared_ctx : EGL_NO_CONTEXT), - context_attribs); -//fprintf(stderr, "eglCreateContext=%p shared_ctx=%p\n", ctx, shared_ctx); - if (ctx) { - add_context(ctx); - /* CONTROL_LEAKING_SUB_GL_WINDOWS - if (egl_surface) { - eglMakeCurrent(egl_display, egl_surface, egl_surface, (EGLContext)ctx); - glClearColor(0., 0., 0., 1.); // set opaque black as starting background color - apply_scissor(); - }*/ - } - return ctx; -} - - -void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - struct wld_window *win = fl_wl_xid(w); - if (!win) return; - Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(w); - EGLSurface target_egl_surface = NULL; - if (egl_surface) target_egl_surface = egl_surface; - else if (dr->gl_start_support_) target_egl_surface = dr->gl_start_support_->egl_surface; - if (!target_egl_surface) { // useful for gl_start() - dr->gl_start_support_ = new struct gl_start_support; - float s = Fl::screen_scale(w->screen_num()); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - // the GL scene will be a transparent subsurface above the cairo-drawn surface - dr->gl_start_support_->surface = - wl_compositor_create_surface(scr_driver->wl_compositor); - dr->gl_start_support_->subsurface = wl_subcompositor_get_subsurface( - scr_driver->wl_subcompositor, dr->gl_start_support_->surface, win->wl_surface); - wl_subsurface_set_position(dr->gl_start_support_->subsurface, w->x() * s, w->y() * s); - wl_subsurface_place_above(dr->gl_start_support_->subsurface, win->wl_surface); - dr->gl_start_support_->egl_window = wl_egl_window_create( - dr->gl_start_support_->surface, w->w() * s, w->h() * s); - target_egl_surface = dr->gl_start_support_->egl_surface = eglCreateWindowSurface( - egl_display, wld_egl_conf, dr->gl_start_support_->egl_window, NULL); - } - GLContext current_context = eglGetCurrentContext(); - if (context != current_context || w != cached_window) { - cached_window = w; - if (eglMakeCurrent(egl_display, target_egl_surface, target_egl_surface, - (EGLContext)context)) { -//fprintf(stderr, "EGLContext %p made current\n", context); - } else { - Fl::error("eglMakeCurrent() failed\n"); - } - } - if (!(mode() & FL_ALPHA)) { // useful at least for Linux on MacBook hardware - GLfloat vals[4]; - glGetFloatv(GL_COLOR_CLEAR_VALUE, vals); - if (vals[3] == 0.) glClearColor(vals[0], vals[1], vals[2], 1.); - } -} - -/* CONTROL_LEAKING_SUB_GL_WINDOWS -void Fl_Wayland_Gl_Window_Driver::apply_scissor() { - cairo_rectangle_int_t *extents = Fl_Wayland_Window_Driver::driver(pWindow)->subRect(); - if (extents) { - glDisable(GL_SCISSOR_TEST); - GLdouble vals[4]; - glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(vals[0], vals[1], vals[2], vals[3]); - float s = pWindow->pixels_per_unit(); - glScissor(s*extents->x, s*extents->y, s*extents->width, s*extents->height); -//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - glEnable(GL_SCISSOR_TEST); - } -}*/ - - -void Fl_Wayland_Gl_Window_Driver::delete_gl_context(GLContext context) { - GLContext current_context = eglGetCurrentContext(); - if (current_context == context) { - cached_window = 0; - } - if (current_context == (EGLContext)context) { - eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - eglDestroyContext(egl_display, (EGLContext)context); - eglDestroySurface(egl_display, egl_surface); - egl_surface = NULL; - wl_egl_window_destroy(egl_window); - egl_window = NULL; - del_context(context); -} - - -void Fl_Wayland_Gl_Window_Driver::make_overlay_current() { - glDrawBuffer(GL_FRONT); -} - - -void Fl_Wayland_Gl_Window_Driver::redraw_overlay() { - pWindow->redraw(); -} - - -void Fl_Wayland_Gl_Window_Driver::make_current_before() { - if (!egl_window) { - struct wld_window *win = fl_wl_xid(pWindow); - struct wl_surface *surface = win->wl_surface; - int W = pWindow->pixel_w(); - int H = pWindow->pixel_h(); - int scale = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale(); - egl_window = wl_egl_window_create(surface, (W/scale)*scale, (H/scale)*scale); - if (egl_window == EGL_NO_SURFACE) { - Fl::fatal("Can't create egl window with wl_egl_window_create()\n"); - } - Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)this->g(); - egl_surface = eglCreateWindowSurface(egl_display, g->egl_conf, egl_window, NULL); - wl_surface_set_buffer_scale(surface, scale); - if (mode() & FL_ALPHA) wl_surface_set_opaque_region(surface, NULL); - // Tested apps: shape, glpuzzle, cube, fractals, gl_overlay, fullscreen, unittests, - // OpenGL3-glut-test, OpenGL3test. - // Tested wayland compositors: mutter, kde-plasma, weston, sway on FreeBSD. - if (pWindow->parent()) win = fl_wl_xid(pWindow->top_window()); - while (wl_list_empty(&win->outputs)) wl_display_dispatch(fl_wl_display()); - } -} - - -float Fl_Wayland_Gl_Window_Driver::pixels_per_unit() -{ - int ns = pWindow->screen_num(); - int wld_scale = (pWindow->shown() ? - Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale() : 1); - return wld_scale * Fl::screen_driver()->scale(ns); -} - - -int Fl_Wayland_Gl_Window_Driver::mode_(int m, const int *a) { - mode(m | FL_DOUBLE); - return 1; -} - - -void Fl_Wayland_Gl_Window_Driver::surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - Fl_Wayland_Gl_Window_Driver *gl_dr = (Fl_Wayland_Gl_Window_Driver *)data; - wl_callback_destroy(cb); - struct wld_window *window = fl_wl_xid(gl_dr->pWindow); - window->frame_cb = NULL; - if (gl_dr->need_swap) { - eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, gl_dr->egl_surface); - gl_dr->need_swap = false; - } -} - - -static const struct wl_callback_listener surface_frame_listener = { - .done = Fl_Wayland_Gl_Window_Driver::surface_frame_done, -}; - - -void Fl_Wayland_Gl_Window_Driver::swap_buffers() { - if (overlay()) { - static bool overlay_buffer = true; - int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); - GLint matrixmode; - GLfloat pos[4]; - glGetIntegerv(GL_MATRIX_MODE, &matrixmode); - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos - glMatrixMode(GL_PROJECTION); // save proj/model matrices - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(2.0f/wo, 2.0f/ho, 1.0f); - glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of window - glRasterPos2i(0,0); // set glRasterPos to bottom left corner - { - // Emulate overlay by doing copypixels - glReadBuffer(overlay_buffer?GL_BACK:GL_FRONT); - glDrawBuffer(overlay_buffer?GL_FRONT:GL_BACK); - overlay_buffer = ! overlay_buffer; - glCopyPixels(0, 0, wo, ho, GL_COLOR); - } - glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(matrixmode); - glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos - if (!overlay_buffer) return; // don't call eglSwapBuffers until overlay has been drawn - } - - if (egl_surface) { - Fl_Window *parent = pWindow->parent() ? pWindow->window() : NULL; - struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL; - if (parent_xid) { // issue #967 - struct wld_window *xid = fl_wl_xid(pWindow); - if (xid->frame_cb) { - need_swap = true; - return; - } - if (!parent_xid->frame_cb) { - xid->frame_cb = wl_surface_frame(xid->wl_surface); - wl_callback_add_listener(xid->frame_cb, &surface_frame_listener, this); - } - } - eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, egl_surface); - need_swap = false; - } -} - - -class Fl_Wayland_Gl_Plugin : public Fl_Wayland_Plugin { -public: - Fl_Wayland_Gl_Plugin() : Fl_Wayland_Plugin(name()) { } - const char *name() FL_OVERRIDE { return "gl.wayland.fltk.org"; } - void do_swap(Fl_Window *w) FL_OVERRIDE { - Fl_Gl_Window_Driver *gldr = Fl_Gl_Window_Driver::driver(w->as_gl_window()); - if (gldr->overlay() == w) gldr->swap_buffers(); - } - void invalidate(Fl_Window *w) FL_OVERRIDE { - w->as_gl_window()->valid(0); - } - void terminate() FL_OVERRIDE { - if (Fl_Wayland_Gl_Window_Driver::egl_display != EGL_NO_DISPLAY) { - eglTerminate(Fl_Wayland_Gl_Window_Driver::egl_display); - } - } - void destroy(struct gl_start_support *gl_start_support_) FL_OVERRIDE { - eglDestroySurface(Fl_Wayland_Gl_Window_Driver::egl_display, - gl_start_support_->egl_surface); - wl_egl_window_destroy(gl_start_support_->egl_window); - wl_subsurface_destroy(gl_start_support_->subsurface); - wl_surface_destroy(gl_start_support_->surface); - delete gl_start_support_; - } -}; - - -static Fl_Wayland_Gl_Plugin Gl_Overlay_Plugin; - - -/* CONTROL_LEAKING_SUB_GL_WINDOWS -static void delayed_scissor(Fl_Wayland_Gl_Window_Driver *dr) { - dr->apply_scissor(); -}*/ - - -void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { - if (!egl_window) return; - float f = Fl::screen_scale(pWindow->screen_num()); - int s = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale(); - W = int(W * f) * s; // W, H must be multiples of int s - H = int(H * f) * s; - int W2, H2; - wl_egl_window_get_attached_size(egl_window, &W2, &H2); - if (W2 != W || H2 != H) { - struct wld_window *xid = fl_wl_xid(pWindow); - if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && !xid->frame_cb) { - xid->frame_cb = wl_surface_frame(xid->wl_surface); - wl_callback_add_listener(xid->frame_cb, - Fl_Wayland_Graphics_Driver::p_surface_frame_listener, xid); - } - wl_egl_window_resize(egl_window, W, H, 0, 0); - wl_surface_set_buffer_scale(xid->wl_surface, s); - } - /* CONTROL_LEAKING_SUB_GL_WINDOWS - if (Fl_Wayland_Window_Driver::driver(pWindow)->subRect()) { - pWindow->redraw(); - Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_scissor, this); - }*/ -} - - -char Fl_Wayland_Gl_Window_Driver::swap_type() { - return copy; -} - - -void Fl_Wayland_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) { - Fl_Gl_Window_Driver::gl_visual(c); - wld_egl_conf = ((Fl_Wayland_Gl_Choice*)c)->egl_conf; -} - - -void Fl_Wayland_Gl_Window_Driver::gl_start() { - float f = Fl::screen_scale(Fl_Window::current()->screen_num()); - int W = Fl_Window::current()->w() * f; - int H = Fl_Window::current()->h() * f; - int W2, H2; - Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(Fl_Window::current()); - wl_egl_window_get_attached_size(dr->gl_start_support_->egl_window, &W2, &H2); - if (W2 != W || H2 != H) { - wl_egl_window_resize(dr->gl_start_support_->egl_window, W, H, 0, 0); - } - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); -} - -void Fl_Wayland_Gl_Window_Driver::swap_interval(int interval) { - if (interval < min_swap_interval) interval = min_swap_interval; - if (interval > max_swap_interval) interval = max_swap_interval; - if (egl_display && eglSwapInterval(egl_display, interval)) - swap_interval_ = interval; - // printf("swap_interval_=%d\n",swap_interval_); -} - - -int Fl_Wayland_Gl_Window_Driver::swap_interval() const { - return swap_interval_; -} - - -void* Fl_Wayland_Gl_Window_Driver::GetProcAddress(const char *procName) { - return Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, procName); -} - - -FL_EXPORT EGLContext fl_wl_glcontext(GLContext rc) { return (EGLContext)rc; } - -#endif // HAVE_GL diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H deleted file mode 100644 index ac8786a47..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ /dev/null @@ -1,72 +0,0 @@ -// -// Definition of class Fl_Wayland_Graphics_Driver. -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Graphics_Driver.H - \brief Definition of Wayland graphics driver. - */ - -#ifndef FL_WAYLAND_GRAPHICS_DRIVER_H -#define FL_WAYLAND_GRAPHICS_DRIVER_H - -#include "../Cairo/Fl_Cairo_Graphics_Driver.H" -#include <stdint.h> // for uint32_t -#include <wayland-client.h> // for wl_list - - -class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver { -public: - struct draw_buffer { - unsigned char *buffer; - cairo_t *cairo_; - size_t data_size; // of wl_buffer and buffer - int stride; - int width; - }; - struct wld_buffer { - struct draw_buffer draw_buffer; - struct wl_list link; // links all buffers from the same wl_shm_pool - struct wl_buffer *wl_buffer; - void *data; - struct wl_shm_pool *shm_pool; - bool draw_buffer_needs_commit; - bool in_use; // true while being committed - bool released; // true after buffer_release() was called - }; - struct wld_shm_pool_data { // one record attached to each wl_shm_pool object - char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool - size_t pool_size; // size of encapsulated memory - struct wl_list buffers; // to list of fl_wld_buffer's from this pool - }; - static const uint32_t wld_format; - static struct wl_shm_pool *current_pool; - static FL_EXPORT const struct wl_callback_listener *p_surface_frame_listener; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, - int srcx, int srcy) FL_OVERRIDE; - void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE; - static struct wld_buffer *create_wld_buffer(int width, int height, bool with_shm = true); - static void create_shm_buffer(wld_buffer *buffer); - static void buffer_release(struct wld_window *window); - static void buffer_commit(struct wld_window *window, cairo_region_t *r = NULL); - static void cairo_init(struct draw_buffer *buffer, int width, int height, int stride, - cairo_format_t format); - // used by class Fl_Wayland_Gl_Window_Driver - static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen); - static const cairo_user_data_key_t key; - static Fl_Image_Surface *custom_offscreen(int w, int h, struct wld_buffer **buffer); -}; - -#endif // FL_WAYLAND_GRAPHICS_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx deleted file mode 100644 index 5c9539a8c..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ /dev/null @@ -1,310 +0,0 @@ -// -// Implementation of the Wayland graphics driver. -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include <sys/mman.h> -#include <unistd.h> // for close() -#include <errno.h> -#include <string.h> // for strerror() -#include <cairo/cairo.h> - -extern "C" { -# include "../../../libdecor/src/os-compatibility.h" // for libdecor_os_create_anonymous_file() -} - -// used by create_shm_buffer and do_buffer_release -struct wl_shm_pool *Fl_Wayland_Graphics_Driver::current_pool = NULL; - - -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *); - - -static void buffer_release_listener(void *user_data, struct wl_buffer *wl_buffer) -{ - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = - (struct Fl_Wayland_Graphics_Driver::wld_buffer*)user_data; - buffer->in_use = false; - if (buffer->released) do_buffer_release(buffer); -} - - -static const struct wl_buffer_listener buffer_listener = { - buffer_release_listener -}; - - -void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - int width = buffer->draw_buffer.width; - int stride = buffer->draw_buffer.stride; - int height = buffer->draw_buffer.data_size / stride; - const size_t default_pool_size = 10000000; // larger pools are possible if needed - int chunk_offset = 0; // offset to start of available memory in pool - struct wld_shm_pool_data *pool_data = current_pool ? // data record attached to current pool - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(current_pool) : NULL; - size_t pool_size = current_pool ? pool_data->pool_size : default_pool_size; // current pool size - if (current_pool && !wl_list_empty(&pool_data->buffers)) { - // last wld_buffer created from current pool - struct wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); - chunk_offset = ((char*)record->data - pool_data->pool_memory) + - record->draw_buffer.data_size; - } - if (!current_pool || chunk_offset + buffer->draw_buffer.data_size > pool_size) { - // if true, a new pool is needed - if (current_pool && wl_list_empty(&pool_data->buffers)) { - wl_shm_pool_destroy(current_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); -// printf("create_shm_buffer munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - chunk_offset = 0; - pool_size = default_pool_size; - if (buffer->draw_buffer.data_size > pool_size) - pool_size = 2 * buffer->draw_buffer.data_size; // a larger pool is needed - int fd = libdecor_os_create_anonymous_file(pool_size); - if (fd < 0) { - Fl::fatal("libdecor_os_create_anonymous_file failed: %s\n", strerror(errno)); - } - pool_data = (struct wld_shm_pool_data*)calloc(1, sizeof(struct wld_shm_pool_data)); - pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (pool_data->pool_memory == MAP_FAILED) { - close(fd); - Fl::fatal("mmap failed: %s\n", strerror(errno)); - } - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - current_pool = wl_shm_create_pool(scr_driver->wl_shm, fd, (int32_t)pool_size); - close(fd); // does not prevent the mmap'ed memory from being used - //printf("wl_shm_create_pool %p size=%lu\n",pool_data->pool_memory , pool_size); - pool_data->pool_size = pool_size; - wl_list_init(&pool_data->buffers); - wl_shm_pool_set_user_data(current_pool, pool_data); - } - buffer->wl_buffer = wl_shm_pool_create_buffer(current_pool, chunk_offset, - width, height, stride, wld_format); - wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); - // add this buffer to head of list of current pool's buffers - wl_list_insert(&pool_data->buffers, &buffer->link); - buffer->shm_pool = current_pool; - buffer->data = (void*)(pool_data->pool_memory + chunk_offset); -//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset); -//fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size); -} - - -struct Fl_Wayland_Graphics_Driver::wld_buffer * - Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm) { - struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer)); - int stride = cairo_format_stride_for_width(cairo_format, width); - cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format); - buffer->draw_buffer_needs_commit = true; - if (with_shm) create_shm_buffer(buffer); - return buffer; -} - - -// used to support both normal and progressive drawing and for top-level GL windows -static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - struct wld_window *window = (struct wld_window *)data; - wl_callback_destroy(cb); - window->frame_cb = NULL; - if (window->buffer && window->buffer->draw_buffer_needs_commit) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } -} - - -static const struct wl_callback_listener surface_frame_listener = { - .done = surface_frame_done, -}; - - -const struct wl_callback_listener *Fl_Wayland_Graphics_Driver::p_surface_frame_listener = - &surface_frame_listener; - - -// copy pixels in region r from the Cairo surface to the Wayland buffer -static void copy_region(struct wld_window *window, cairo_region_t *r) { - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer; - float f = Fl::screen_scale(window->fl_win->screen_num()); - int d = Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); - int count = cairo_region_num_rectangles(r); - cairo_rectangle_int_t rect; - for (int i = 0; i < count; i++) { - cairo_region_get_rectangle(r, i, &rect); - int left = d * int(rect.x * f); - int top = d * int(rect.y * f); - int right = d * ceil((rect.x + rect.width) * f); - if (right > d * int(window->fl_win->w() * f)) right = d * int(window->fl_win->w() * f); - int width = right - left; - int bottom = d * ceil((rect.y + rect.height) * f); - if (bottom > d * int(window->fl_win->h() * f)) bottom = d * int(window->fl_win->h() * f); - int height = bottom - top; - int offset = top * buffer->draw_buffer.stride + 4 * left; - int W4 = 4 * width; - for (int l = 0; l < height; l++) { - if (offset + W4 >= (int)buffer->draw_buffer.data_size) { - W4 = buffer->draw_buffer.data_size - offset; - if (W4 <= 0) break; - } - memcpy((uchar*)buffer->data + offset, buffer->draw_buffer.buffer + offset, W4); - offset += buffer->draw_buffer.stride; - } - wl_surface_damage_buffer(window->wl_surface, left, top, width, height); - } -} - - -void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r) -{ - if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer); - cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_); - cairo_surface_flush(surf); - if (r) copy_region(window, r); - else { - memcpy(window->buffer->data, window->buffer->draw_buffer.buffer, - window->buffer->draw_buffer.data_size); - wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000); - } - window->buffer->in_use = true; - wl_surface_attach(window->wl_surface, window->buffer->wl_buffer, 0, 0); - wl_surface_set_buffer_scale( window->wl_surface, - Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale() ); - if (!window->covered) { // see issue #878 - window->frame_cb = wl_surface_frame(window->wl_surface); - wl_callback_add_listener(window->frame_cb, p_surface_frame_listener, window); - } - wl_surface_commit(window->wl_surface); - window->buffer->draw_buffer_needs_commit = false; -} - - -void Fl_Wayland_Graphics_Driver::cairo_init(struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer, - int width, int height, int stride, - cairo_format_t format) { - buffer->data_size = stride * height; - buffer->stride = stride; - buffer->buffer = new uchar[buffer->data_size]; - buffer->width = width; - cairo_surface_t *surf = cairo_image_surface_create_for_data(buffer->buffer, format, - width, height, stride); - if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Can't create Cairo surface with cairo_image_surface_create_for_data()\n"); - return; - } - buffer->cairo_ = cairo_create(surf); - cairo_status_t err; - if ((err = cairo_status(buffer->cairo_)) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Cairo error during cairo_create() %s\n", cairo_status_to_string(err)); - return; - } - cairo_surface_destroy(surf); - memset(buffer->buffer, 0, buffer->data_size); // useful for transparent windows - cairo_set_source_rgba(buffer->cairo_, .0, .0, .0, 1.0); // Black default color - cairo_save(buffer->cairo_); -} - - -// runs when buffer->in_use is false and buffer->released is true -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - struct wl_shm_pool *my_pool = buffer->shm_pool; - if (buffer->wl_buffer) { - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data = - (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*) - wl_shm_pool_get_user_data(my_pool); - wl_buffer_destroy(buffer->wl_buffer); - // remove wld_buffer from list of pool's buffers - wl_list_remove(&buffer->link); - if (wl_list_empty(&pool_data->buffers) && my_pool != Fl_Wayland_Graphics_Driver::current_pool) { - // all buffers from pool are gone - wl_shm_pool_destroy(my_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); - //printf("do_buffer_release munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - } - free(buffer); -} - - -void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) -{ - if (window->buffer && !window->buffer->released) { - window->buffer->released = true; - if (window->frame_cb) { wl_callback_destroy(window->frame_cb); window->frame_cb = NULL; } - delete[] window->buffer->draw_buffer.buffer; - window->buffer->draw_buffer.buffer = NULL; - cairo_destroy(window->buffer->draw_buffer.cairo_); - if (!window->buffer->in_use) do_buffer_release(window->buffer); - window->buffer = NULL; - } -} - - -// this refers to the same memory layout for pixel data as does CAIRO_FORMAT_ARGB32 -const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888; - - -void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, - Fl_Offscreen src, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of - // the graphics driver's surface - cairo_matrix_t matrix; - cairo_get_matrix(cairo_, &matrix); - double s = matrix.xx; - cairo_save(cairo_); - cairo_rectangle(cairo_, x - 0.5, y - 0.5, w, h); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); - cairo_clip(cairo_); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT); - cairo_surface_t *surf = cairo_get_target((cairo_t *)src); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - cairo_set_source(cairo_, pat); - cairo_matrix_init_scale(&matrix, s, s); - cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy)); - cairo_pattern_set_matrix(pat, &matrix); - cairo_paint(cairo_); - cairo_pattern_destroy(pat); - cairo_restore(cairo_); - surface_needs_commit(); -} - - -const cairo_user_data_key_t Fl_Wayland_Graphics_Driver::key = {}; - - -struct Fl_Wayland_Graphics_Driver::draw_buffer* -Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen offscreen) { - return (struct draw_buffer*)cairo_get_user_data((cairo_t*)offscreen, &key); -} - - -Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h, - struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) { - struct wld_buffer *off = create_wld_buffer(w, h); - *p_off = off; - cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL); - return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_); -} - - -void Fl_Wayland_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) { - Fl_Graphics_Driver::cache_size(img, width, height); - width *= wld_scale; - height *= wld_scale; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H deleted file mode 100644 index ae32ac3df..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H +++ /dev/null @@ -1,40 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_IMAGE_SURFACE_DRIVER_H -#define FL_WAYLAND_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> - -class Fl_Wayland_Image_Surface_Driver : public Fl_Image_Surface_Driver { - void end_current() FL_OVERRIDE; - struct wld_window *pre_window; -public: - Fl_Wayland_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_Wayland_Image_Surface_Driver(); - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - struct shape_data_type { - double scale; - cairo_pattern_t *mask_pattern_; - cairo_t *bg_cr; - } *shape_data_; - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; -}; - -#endif // FL_WAYLAND_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx deleted file mode 100644 index ec9c56cb7..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx +++ /dev/null @@ -1,185 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Image_Surface_Driver.H" - - -Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h, - int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - shape_data_ = NULL; - float s = 1; - int d = 1; - if (!off) { - fl_open_display(); - if (Fl::first_window()) { - d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale(); - } - s = Fl_Graphics_Driver::default_driver().scale(); - if (d*s != 1 && high_res) { - w = int(w * s) * d; - h = int(h * s) * d; - } - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1, - sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer)); - Fl_Wayland_Graphics_Driver::cairo_init(off_, w, h, - cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w), CAIRO_FORMAT_RGB24); - offscreen = (Fl_Offscreen)off_->cairo_; - cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL); - if (d*s != 1 && high_res) cairo_scale((cairo_t*)offscreen, d*s, d*s); - } - driver(new Fl_Wayland_Graphics_Driver()); - if (d*s != 1 && high_res) driver()->scale(d*s); -} - - -Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() { - if (shape_data_) { - cairo_surface_t *surf; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf); - unsigned char *bits = cairo_image_surface_get_data(surf); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] bits; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr); - delete[] off_->buffer; - free(off_); - cairo_destroy(shape_data_->bg_cr); - free(shape_data_); - } - if (offscreen && !external_offscreen) { - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - cairo_destroy((cairo_t *)offscreen); - delete[] buffer->buffer; - free(buffer); - } - delete driver(); -} - - -void Fl_Wayland_Image_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver(); - if (!dr->cr()) dr->set_cairo((cairo_t*)offscreen); - pre_window = Fl_Wayland_Window_Driver::wld_window; - Fl_Wayland_Window_Driver::wld_window = NULL; - fl_window = 0; -} - - -void Fl_Wayland_Image_Surface_Driver::end_current() { - cairo_surface_t *surf = cairo_get_target((cairo_t*)offscreen); - cairo_surface_flush(surf); - Fl_Wayland_Window_Driver::wld_window = pre_window; - fl_window = (Window)pre_window; - Fl_Surface_Device::end_current(); -} - - -void Fl_Wayland_Image_Surface_Driver::translate(int x, int y) { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y); -} - - -void Fl_Wayland_Image_Surface_Driver::untranslate() { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate(); -} - - -Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() { - if (shape_data_ && shape_data_->mask_pattern_) { - // draw above the secondary offscreen the main offscreen masked by mask_pattern_ - cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr(); - cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c)); - cairo_set_source(shape_data_->bg_cr, paint_pattern); - cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_); - cairo_pattern_destroy(paint_pattern); - // copy secondary offscreen to the main offscreen - cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr)); - cairo_scale(c, shape_data_->scale, shape_data_->scale); - cairo_set_source(c, pat), - cairo_paint(c); - cairo_pattern_destroy(pat); - // delete secondary offscreen - cairo_surface_t *surf; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf); - unsigned char *bits = cairo_image_surface_get_data(surf); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] bits; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr); - delete[] off_->buffer; - free(off_); - cairo_destroy(shape_data_->bg_cr); - free(shape_data_); - shape_data_ = NULL; - } - - // Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - int height = int(off_buf->data_size / off_buf->stride); - uchar *rgb = new uchar[off_buf->width * height * 3]; - uchar *p = rgb; - uchar *q; - for (int j = 0; j < height; j++) { - q = off_buf->buffer + j*off_buf->stride; - for (int i = 0; i < off_buf->width; i++) { // exchange R and B colors, transmit G - *p = *(q+2); - *(p+1) = *(q+1); - *(p+2) = *q; - p += 3; q += 4; - } - } - Fl_RGB_Image *image = new Fl_RGB_Image(rgb, off_buf->width, height, 3); - image->alloc_array = 1; - return image; -} - - -void Fl_Wayland_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) { - bool using_copy = false; - shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type)); - int W, H; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - W = off_buf->width; - H = (int)(off_buf->data_size / off_buf->stride); - if (W != mask->data_w() || H != mask->data_h()) { - Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H); - mask = copy; - using_copy = true; - } - shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask); - //duplicate current offscreen content to new cairo_t* shape_data_->bg_cr - int width, height; - printable_rect(&width, &height); - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1, - sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer)); - Fl_Wayland_Graphics_Driver::cairo_init(off_, W, H, - cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, W), - CAIRO_FORMAT_RGB24); - cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL); - shape_data_->bg_cr = off_->cairo_; - memcpy(off_->buffer, off_buf->buffer, off_buf->data_size); - shape_data_->scale = double(width) / W; - if (using_copy) delete mask; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H deleted file mode 100644 index 83efd79a3..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H +++ /dev/null @@ -1,193 +0,0 @@ -// -// Definition of the Wayland Screen interface -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Screen_Driver.H - \brief Definition of Wayland Screen interface - */ - -#ifndef FL_WAYLAND_SCREEN_DRIVER_H -#define FL_WAYLAND_SCREEN_DRIVER_H - -#include <config.h> -#include "../Unix/Fl_Unix_Screen_Driver.H" -#include <wayland-client.h> - -class Fl_Window; - -class Fl_Wayland_Screen_Driver : public Fl_Unix_Screen_Driver -{ -private: - static int insertion_point_x; - static int insertion_point_y; - static int insertion_point_width; - static int insertion_point_height; - static bool insertion_point_location_is_valid; -public: -// type definitions - typedef enum {unspecified, MUTTER, WESTON, KWIN, OWL, WAYFIRE} compositor_name; - struct seat { - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - struct wl_keyboard *wl_keyboard; - uint32_t keyboard_enter_serial; - struct wl_surface *keyboard_surface; - struct wl_list pointer_outputs; - struct wl_cursor_theme *cursor_theme; - struct wl_cursor *default_cursor; - struct wl_surface *cursor_surface; - struct wl_surface *pointer_focus; - int pointer_scale; - uint32_t serial; - uint32_t pointer_enter_serial; - struct wl_data_device_manager *data_device_manager; - struct wl_data_device *data_device; - struct wl_data_source *data_source; - struct xkb_state *xkb_state; - struct xkb_context *xkb_context; - struct xkb_keymap *xkb_keymap; - struct xkb_compose_state *xkb_compose_state; - char *name; - struct zwp_text_input_v3 *text_input; - struct gtk_shell1 *gtk_shell; - }; - struct output { // one record for each screen - uint32_t id; - int x, y; // logical position of screen - int pixel_width; // in pixels - int pixel_height; // in pixels - int width; // in pixels, account for fractional scaling - int height; // in pixels, account for fractional scaling - float dpi; - struct wl_output *wl_output; - int wld_scale; // Wayland scale factor - float gui_scale; // FLTK scale factor - bool done; - struct wl_list link; - }; - enum cursor_shapes {arrow = 0, wait, insert, hand, help, cross, move, - north, south, west, east, north_south, west_east, south_west, south_east, north_east, north_west, nesw, nwse}; - static const int cursor_count = nwse + 1; // nber of elements of 'enum cursor_shapes' - -// static member variables - static FL_EXPORT struct wl_display *wl_display; - static const struct wl_data_device_listener *p_data_device_listener; - // next length of marked text after current marked text will have been replaced - static int next_marked_length; - static compositor_name compositor; // identifies the used Wayland compositor - -// static member functions - static void insertion_point_location(int x, int y, int height); - static bool insertion_point_location(int *px, int *py, int *pwidth, int *pheight); - static bool own_output(struct wl_output *output); - static void do_set_cursor(struct Fl_Wayland_Screen_Driver::seat *, - struct wl_cursor *wl_cursor = NULL, Fl_Cursor c = FL_CURSOR_NONE); -// member variables - struct wl_cursor *xc_cursor[cursor_count]; // one for each element of enum cursor_shapes - struct wl_registry *wl_registry; - struct wl_compositor *wl_compositor; - struct wl_subcompositor *wl_subcompositor; - struct wl_shm *wl_shm; - struct seat *seat; - struct wl_list outputs; // linked list of struct output records for all screens in system - struct libdecor *libdecor_context; - struct xdg_wm_base *xdg_wm_base; - struct zwp_text_input_manager_v3 *text_input_base; -#if HAVE_XDG_DIALOG - struct xdg_wm_dialog_v1 *xdg_wm_dialog; -#endif -#if HAVE_CURSOR_SHAPE - struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager; - struct wp_cursor_shape_device_v1 *wp_cursor_shape_device; -#endif - -// constructor - Fl_Wayland_Screen_Driver(); - -// overridden functions from parent class Fl_Screen_Driver - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { return PER_SCREEN_APP_SCALING; } - float scale(int n) FL_OVERRIDE; - void scale(int n, float f) FL_OVERRIDE; - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void flush() FL_OVERRIDE; - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - int dnd(int unused) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - void compose_reset() FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, - bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - int get_mouse(int &x, int &y) FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - void close_display() FL_OVERRIDE; - void display(const char *d) FL_OVERRIDE; - // --- compute dimensions of an Fl_Offscreen - void offscreen_size(Fl_Offscreen o, int &width, int &height) FL_OVERRIDE; - int has_marked_text() const FL_OVERRIDE; - // --- clipboard operations - // this one is in fl_wayland_clipboard_dnd.cxx - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - int clipboard_contains(const char *type) FL_OVERRIDE; - void set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) FL_OVERRIDE; - void reset_spot() FL_OVERRIDE; - void *control_maximize_button(void *data) FL_OVERRIDE; - int event_key(int k) FL_OVERRIDE; - int get_key(int k) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - bool screen_boundaries_known() FL_OVERRIDE { return false; } - float base_scale(int numscreen) FL_OVERRIDE; - - // overridden functions from parent class Fl_Unix_Screen_Driver - int poll_or_select_with_delay(double time_to_wait) FL_OVERRIDE; - int poll_or_select() FL_OVERRIDE; - -// Wayland-specific member functions - void screen_count_set(int count) {num_screens = count;} - int screen_count_get() {return num_screens;} - void reset_cursor(); - // this one is in fl_wayland_clipboard_dnd.cxx - void copy_image(const unsigned char* data, int W, int H); - void init_workarea(); - void set_cursor(); - struct wl_cursor *default_cursor(); - void default_cursor(struct wl_cursor *cursor); - struct wl_cursor *cache_cursor(const char *cursor_name); - uint32_t get_serial(); - struct wl_seat *get_wl_seat(); - char *get_seat_name(); - struct xkb_keymap *get_xkb_keymap(); -}; - - -#endif // FL_WAYLAND_SCREEN_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx deleted file mode 100644 index 9199f3a5f..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx +++ /dev/null @@ -1,2204 +0,0 @@ -// -// Implementation of Wayland Screen interface -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "../../Fl_Scalable_Graphics_Driver.H" -#include <wayland-cursor.h> -#include "../../../libdecor/build/fl_libdecor.h" -#include "xdg-shell-client-protocol.h" -#include "../Posix/Fl_Posix_System_Driver.H" -#include <FL/Fl.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/platform.H> -#include <FL/fl_ask.H> -#include <FL/filename.H> -#include <vector> -#include "../../print_button.h" -#include <dlfcn.h> -#include <linux/input.h> -#include <stdlib.h> -#include <xkbcommon/xkbcommon.h> -#include <xkbcommon/xkbcommon-compose.h> -#include "text-input-client-protocol.h" -#include "gtk-shell-client-protocol.h" -#if HAVE_XDG_DIALOG -# include "xdg-dialog-client-protocol.h" -#endif -#if HAVE_CURSOR_SHAPE -# include "cursor-shape-client-protocol.h" -#endif -#include <assert.h> -#include <sys/mman.h> -#include <poll.h> -#include <errno.h> -#include <string.h> // for strerror() -#include <map> -extern "C" { - bool libdecor_get_cursor_settings(char **theme, int *size); - bool fl_is_surface_from_GTK_titlebar (struct wl_surface *surface, struct libdecor_frame *frame, - bool *using_GTK); -} - -// set this to 1 for keyboard debug output, 0 for no debug output -#define DEBUG_KEYBOARD 0 - -#define fl_max(a,b) ((a) > (b) ? (a) : (b)) -#define fl_min(a,b) ((a) < (b) ? (a) : (b)) - -struct pointer_output { - Fl_Wayland_Screen_Driver::output* output; - struct wl_list link; -}; - -/* Implementation note: - -- About CSD and SSD : - * Mutter and Weston use CSD (client-side decoration) which means that libdecor.so draws all window - titlebars and responds to resize, minimization and maximization events. - * KWin uses SSD (server-side decoration) which means the OS draws titlebars according to its own rules - and triggers resize, minimization and maximization events. - -- Function registry_handle_global() runs within fl_open_display() and sets public static variable - Fl_Wayland_Screen_Driver::compositor to either Fl_Wayland_Screen_Driver::MUTTER, ::WESTON, or ::KWIN. - -- Specific operations for WESTON: - * When a libdecor-framed window is minimized under Weston, the frame remains on display. To avoid - that, function libdecor_frame_set_minimized() is modified so it turns off the frame's visibility, with - function libdecor_frame_set_visibility(), when the window is minimized. That's implemented in file - libdecor/build/fl_libdecor.c. The modified libdecor_frame_set_minimized() function, part of libdecor.so, - needs access to variable Fl_Wayland_Screen_Driver::compositor, part of libfltk.a. This is achieved - calling FLTK function fl_libdecor_using_weston() which returns whether the running compositor - is Weston. This Weston bug has been corrected in Weston version 10. Thus, this special processing - is not performed when Weston version is ≥ 10. - -- Support of Fl_Window::border(int) : - FLTK uses libdecor_frame_set_visibility() to show or hide a toplevel window's frame. This doesn't work - with KWin which uses Server-Side Decoration. In that case, FLTK hides and re-shows the window to toggle - between presence and absence of a window's frame. -*/ - - -static std::vector<int> key_vector; // used by Fl_Wayland_Screen_Driver::event_key() -static struct wl_surface *gtk_shell_surface = NULL; - -Fl_Wayland_Screen_Driver::compositor_name Fl_Wayland_Screen_Driver::compositor = - Fl_Wayland_Screen_Driver::unspecified; - - -extern "C" { - bool fl_libdecor_using_weston(void) { - return Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON; - } -} - - -static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) -{ - xdg_wm_base_pong(xdg_wm_base, serial); -} - - -static const struct xdg_wm_base_listener xdg_wm_base_listener = { - .ping = xdg_wm_base_ping, -}; - - -// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx -extern const char *fl_fg; -extern const char *fl_bg; -extern const char *fl_bg2; -// end of extern additions workaround - - -void Fl_Wayland_Screen_Driver::do_set_cursor( - struct Fl_Wayland_Screen_Driver::seat *seat, struct wl_cursor *wl_cursor, Fl_Cursor cursor) { - /* - wl_cursor: when non-NULL means a custom cursor; - when NULL: - - with "Cursor shape" protocol, cursor is meaningful if != FL_CURSOR_NONE; - - with old-school cursors, seat->default_cursor gives the desired cursor. - cursor: used with "Cursor shape" protocol for enumerated cursor shape, otherwise equal to FL_CURSOR_NONE - */ - struct wl_cursor_image *image; - struct wl_buffer *buffer; - const int scale = seat->pointer_scale; - -#if HAVE_CURSOR_SHAPE - static std::map<int, int> cursor_shape_map = { - {FL_CURSOR_DEFAULT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT }, - {FL_CURSOR_ARROW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT }, - {FL_CURSOR_CROSS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR }, - {FL_CURSOR_WAIT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT }, - {FL_CURSOR_INSERT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT }, - {FL_CURSOR_HAND, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB }, - {FL_CURSOR_HELP, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP }, - {FL_CURSOR_MOVE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE }, - {FL_CURSOR_N, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE }, - {FL_CURSOR_E, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE }, - {FL_CURSOR_W, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE }, - {FL_CURSOR_S, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE }, - {FL_CURSOR_NS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE }, - {FL_CURSOR_WE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE }, - {FL_CURSOR_SW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE }, - {FL_CURSOR_SE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE }, - {FL_CURSOR_NE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE }, - {FL_CURSOR_NW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE }, - {FL_CURSOR_NESW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE }, - {FL_CURSOR_NWSE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE } - }; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->wp_cursor_shape_device && !wl_cursor) { - if (cursor != FL_CURSOR_NONE) wp_cursor_shape_device_v1_set_shape( - scr_driver->wp_cursor_shape_device, seat->pointer_enter_serial, cursor_shape_map[cursor]); - return; - } -#endif - - if ((!seat->cursor_theme && !wl_cursor) || !seat->wl_pointer) - return; - - if (!wl_cursor) wl_cursor = seat->default_cursor; - image = wl_cursor->images[0]; - buffer = wl_cursor_image_get_buffer(image); - wl_pointer_set_cursor(seat->wl_pointer, seat->pointer_enter_serial, - seat->cursor_surface, - image->hotspot_x / scale, - image->hotspot_y / scale); - wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width, image->height); - wl_surface_commit(seat->cursor_surface); -} - - -static uint32_t ptime; -static uint32_t wld_event_time; -static int px, py; - - -static void set_event_xy(Fl_Window *win) { - // turn off is_click if enough time or mouse movement has passed: - if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 || - wld_event_time >= ptime+1000) { - Fl::e_is_click = 0; -//fprintf(stderr, "Fl::e_is_click = 0\n"); - } -} - - -// if this is same event as last && is_click, increment click count: -static inline void checkdouble() { - if (Fl::e_is_click == Fl::e_keysym) { - Fl::e_clicks++; -//fprintf(stderr, "Fl::e_clicks = %d\n", Fl::e_clicks); - } else { - Fl::e_clicks = 0; - Fl::e_is_click = Fl::e_keysym; -//fprintf(stderr, "Fl::e_is_click = %d\n", Fl::e_is_click); - } - px = Fl::e_x_root; - py = Fl::e_y_root; - ptime = wld_event_time; -} - - -struct wl_display *Fl_Wayland_Screen_Driver::wl_display = NULL; - - -static Fl_Window *event_coords_from_surface(struct wl_surface *surface, - wl_fixed_t surface_x, wl_fixed_t surface_y) { - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (!win) return NULL; - int delta_x = 0, delta_y = 0; - while (win->parent()) { - delta_x += win->x(); - delta_y += win->y(); - win = win->window(); - } - float f = Fl::screen_scale(win->screen_num()); - Fl::e_x = wl_fixed_to_int(surface_x) / f + delta_x; - Fl::e_x_root = Fl::e_x + win->x(); - Fl::e_y = wl_fixed_to_int(surface_y) / f + delta_y; - int *poffset = Fl_Window_Driver::menu_offset_y(win); - if (poffset) Fl::e_y -= *poffset; - Fl::e_y_root = Fl::e_y + win->y(); - return win; -} - -static Fl_Window *need_leave = NULL; - -static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, - struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y); - static bool using_GTK = seat->gtk_shell && - (gtk_shell1_get_version(seat->gtk_shell) >= GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION); - if (!win && using_GTK) { - // check whether surface is the headerbar of a GTK-decorated window - Fl_X *xp = Fl_X::first; - while (xp && using_GTK) { // all mapped windows - struct wld_window *xid = (struct wld_window*)xp->xid; - if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && - fl_is_surface_from_GTK_titlebar(surface, xid->frame, &using_GTK)) { - gtk_shell_surface = surface; - break; - } - xp = xp->next; - } - } - if (!win) return; - //fprintf(stderr, "pointer_enter window=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface)); - seat->pointer_focus = surface; - // use custom cursor if present - struct wl_cursor *cursor = - fl_wl_xid(win)->custom_cursor ? fl_wl_xid(win)->custom_cursor->wl_cursor : NULL; - seat->serial = serial; - seat->pointer_enter_serial = serial; - Fl_Wayland_Screen_Driver::do_set_cursor(seat, cursor, Fl_Wayland_Window_Driver::driver(win)->standard_cursor()); - set_event_xy(win); - need_leave = NULL; - win = Fl_Wayland_Window_Driver::surface_to_window(surface); - // Caution: with an Fl_Tooltip this call can hide the window being entered (#1317) - if (!win->parent()) Fl::handle(FL_ENTER, win); -} - - -static void pointer_leave(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - if (seat->pointer_focus == surface) seat->pointer_focus = NULL; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - gtk_shell_surface = NULL; - if (win) { - //fprintf(stderr, "pointer_leave window=%p [%s]\n", win, (win->parent()?"sub":"top")); - set_event_xy(win); - need_leave = win->top_window(); // we leave a sub or toplevel window - wl_display_roundtrip(fl_wl_display()); // pointer_enter to other win, if applicable, will run - if (need_leave) { // we really left the sub-or-top win and did not enter another - extern Fl_Window *fl_xmousewin; - fl_xmousewin = 0; - Fl::handle(FL_LEAVE, need_leave); - } - } -} - - -static void pointer_motion(void *data, struct wl_pointer *wl_pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = event_coords_from_surface(seat->pointer_focus, surface_x, surface_y); - if (!win) return; - if (Fl::grab() && !Fl::grab()->menu_window() && Fl::grab() != win) { - // If there's an active, non-menu grab() and the pointer is in a window other than - // the grab(), make e_x_root too large to be in any window - Fl::e_x_root = 1000000; - } - else if (Fl_Window_Driver::menu_parent(NULL) && // any kind of menu is active now, and - !win->menu_window() && // we enter a non-menu window - win != Fl_Window_Driver::menu_parent(NULL) // that's not the window below the menu - ) { - Fl::e_x_root = 1000000; // make it too large to be in any window - } -//fprintf(stderr, "FL_MOVE on win=%p to x:%dx%d root:%dx%d\n", win, Fl::e_x, Fl::e_y, Fl::e_x_root, Fl::e_y_root); - wld_event_time = time; - set_event_xy(win); - Fl::handle(FL_MOVE, win); -} - - -//#include <FL/names.h> -static void pointer_button(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - if (gtk_shell_surface && state == WL_POINTER_BUTTON_STATE_PRESSED && - button == BTN_MIDDLE) { - struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(seat->gtk_shell,gtk_shell_surface); - gtk_surface1_titlebar_gesture(gtk_surface, serial, seat->wl_seat, - GTK_SURFACE1_GESTURE_MIDDLE_CLICK); - gtk_surface1_release(gtk_surface); // very necessary - return; - } - seat->serial = serial; - int event = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return; - win = win->top_window(); - wld_event_time = time; - int b = 0; - // Fl::e_state &= ~FL_BUTTONS; // DO NOT reset the mouse button state! - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; } - else if (button == BTN_BACK) { Fl::e_state |= FL_BUTTON4; b = 4; } // ? - else if (button == BTN_SIDE) { Fl::e_state |= FL_BUTTON4; b = 4; } // OK: Debian 12 - else if (button == BTN_FORWARD) { Fl::e_state |= FL_BUTTON5; b = 5; } // ? - else if (button == BTN_EXTRA) { Fl::e_state |= FL_BUTTON5; b = 5; } // OK: Debian 12 - } else { // must be WL_POINTER_BUTTON_STATE_RELEASED - if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; } - else if (button == BTN_BACK) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // ? - else if (button == BTN_SIDE) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // OK: Debian 12 - else if (button == BTN_FORWARD) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // ? - else if (button == BTN_EXTRA) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // OK: Debian 12 - } - Fl::e_keysym = FL_Button + b; - Fl::e_dx = Fl::e_dy = 0; - - set_event_xy(win); - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - event = FL_PUSH; - checkdouble(); - } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) { - event = FL_RELEASE; - } - // fprintf(stderr, "%s %s\n", fl_eventnames[event], win->label() ? win->label():"[]"); - Fl::handle(event, win); -} - - -static void pointer_axis(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return; - wld_event_time = time; - int delta = wl_fixed_to_int(value); - if (abs(delta) >= 10) delta /= 10; - // fprintf(stderr, "FL_MOUSEWHEEL: %c delta=%d\n", axis==WL_POINTER_AXIS_HORIZONTAL_SCROLL?'H':'V', delta); - // allow both horizontal and vertical movements to be processed by the widget - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - if (Fl::event_shift()) { // shift key pressed: send vertical mousewheel event - Fl::e_dx = 0; - Fl::e_dy = delta; - } else { // shift key not pressed (normal behavior): send horizontal mousewheel event - Fl::e_dx = delta; - Fl::e_dy = 0; - } - Fl::handle(FL_MOUSEWHEEL, win->top_window()); - } - if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - if (Fl::event_shift()) { // shift key pressed: send horizontal mousewheel event - Fl::e_dx = delta; - Fl::e_dy = 0; - } else {// shift key not pressed (normal behavior): send vertical mousewheel event - Fl::e_dx = 0; - Fl::e_dy = delta; - } - Fl::handle(FL_MOUSEWHEEL, win->top_window()); - } -} - - -static struct wl_pointer_listener pointer_listener = { - pointer_enter, - pointer_leave, - pointer_motion, - pointer_button, - pointer_axis -}; - - -static const char *proxy_tag = "FLTK for Wayland"; - - -bool Fl_Wayland_Screen_Driver::own_output(struct wl_output *output) -{ - return wl_proxy_get_tag((struct wl_proxy *)output) == &proxy_tag; -} - - -static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat); - - -static void try_update_cursor(struct Fl_Wayland_Screen_Driver::seat *seat) { - if (wl_list_empty(&seat->pointer_outputs)) return; - struct pointer_output *pointer_output; - int scale = 1; - - wl_list_for_each(pointer_output, &seat->pointer_outputs, link) { - scale = fl_max(scale, pointer_output->output->wld_scale); - } - - if (scale != seat->pointer_scale) { - seat->pointer_scale = scale; - init_cursors(seat); - Fl_Wayland_Screen_Driver::do_set_cursor(seat); - } -} - - -static void output_scale(void *data, struct wl_output *wl_output, int32_t factor); - - -static void cursor_surface_enter(void *data, - struct wl_surface *wl_surface, struct wl_output *wl_output) { - // Runs when the seat's cursor_surface enters a display - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - struct pointer_output *pointer_output; - - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - - pointer_output = (struct pointer_output *)calloc(1, sizeof(struct pointer_output)); - pointer_output->output = - (Fl_Wayland_Screen_Driver::output *)wl_output_get_user_data(wl_output); -//fprintf(stderr, "cursor_surface_enter: wl_output_get_user_data(%p)=%p\n", wl_output, pointer_output->output); - wl_list_insert(&seat->pointer_outputs, &pointer_output->link); - try_update_cursor(seat); - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - output_scale(output, wl_output, output->wld_scale); // rescale custom cursors - // maintain custom or standard window cursor - Fl_Window *win = Fl::first_window(); - if (win) { - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win); - struct wld_window *xid = fl_wl_xid(win); - if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor); - else if (driver->cursor_default()) driver->set_cursor(driver->cursor_default()); - else win->cursor(driver->standard_cursor()); - } -} - - -static void cursor_surface_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - struct pointer_output *pointer_output, *tmp; - wl_list_for_each_safe(pointer_output, tmp, &seat->pointer_outputs, link) { - if (pointer_output->output->wl_output == wl_output) { - wl_list_remove(&pointer_output->link); - free(pointer_output); - } - } - try_update_cursor(seat); - // maintain custom window cursor - Fl_Window *win = Fl::first_window(); - if (win) { - struct wld_window *xid = fl_wl_xid(win); - if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor); - } -} - - -static struct wl_surface_listener cursor_surface_listener = { - cursor_surface_enter, - cursor_surface_leave, -}; - - -static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (!seat->cursor_surface) { - seat->cursor_surface = wl_compositor_create_surface(scr_driver->wl_compositor); - wl_surface_add_listener(seat->cursor_surface, &cursor_surface_listener, seat); - } -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_manager) return; -#endif - - char *name; - int size; - struct wl_cursor_theme *theme; - - if (!libdecor_get_cursor_settings(&name, &size)) { - name = NULL; - size = 24; - } - size *= seat->pointer_scale; - theme = wl_cursor_theme_load(name, size, scr_driver->wl_shm); - free(name); - if (theme != NULL) { - if (seat->cursor_theme) { - // caution to destroy theme because Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor) caches used cursors - scr_driver->reset_cursor(); - wl_cursor_theme_destroy(seat->cursor_theme); - } - seat->cursor_theme = theme; - } - if (seat->cursor_theme) { - seat->default_cursor = scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow] = - wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr"); - } -} - - -static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, - uint32_t format, int32_t fd, uint32_t size) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - - char *map_shm = (char*)mmap(NULL, size, PROT_READ, - wl_keyboard_get_version(wl_keyboard) >= 7 ? MAP_PRIVATE : MAP_SHARED, fd, 0); - assert(map_shm != MAP_FAILED); - - struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(seat->xkb_context, map_shm, - XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - munmap(map_shm, size); - close(fd); - if (xkb_keymap) { - struct xkb_state *xkb_state = xkb_state_new(xkb_keymap); - xkb_keymap_unref(seat->xkb_keymap); - if (seat->xkb_state) xkb_state_unref(seat->xkb_state); - seat->xkb_keymap = xkb_keymap; - seat->xkb_state = xkb_state; - } -} - - -static int search_int_vector(std::vector<int>& v, int val) { - for (unsigned pos = 0; pos < v.size(); pos++) { - if (v[pos] == val) return pos; - } - return -1; -} - - -static void remove_int_vector(std::vector<int>& v, int val) { - int pos = search_int_vector(v, val); - if (pos < 0) return; - v.erase(v.begin()+pos); -} - - -static int process_wld_key(struct xkb_state *xkb_state, uint32_t key, - uint32_t *p_keycode, xkb_keysym_t *p_sym) { - uint32_t keycode = key + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, keycode); - if (sym == 0xfe20) sym = FL_Tab; - if (sym == 0xffeb) sym = FL_Meta_L; // repair value libxkb gives for FL_Meta_L - if (sym == 0xffec) sym = FL_Meta_R; // repair value libxkb gives for FL_Meta_R - if (sym >= 'A' && sym <= 'Z') sym += 32; // replace uppercase by lowercase letter - int for_key_vector = sym; // for support of Fl::event_key(int) - // special processing for number keys == keycodes 10-19 : - if (keycode >= 10 && keycode <= 18) { - for_key_vector = '1' + (keycode - 10); - } else if (keycode == 19) { - for_key_vector = '0'; - } - if (p_keycode) *p_keycode = keycode; - if (p_sym) *p_sym = sym; - return for_key_vector; -} - - -static uint32_t last_keydown_serial = 0; // serial of last keydown event - - -static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; -//fprintf(stderr, "keyboard enter fl_win=%p; keys pressed are: ", Fl_Wayland_Window_Driver::surface_to_window(surface)); - key_vector.clear(); - // Replace wl_array_for_each(p, keys) rejected by C++ - for (uint32_t *p = (uint32_t *)(keys)->data; - (const char *) p < ((const char *) (keys)->data + (keys)->size); - (p)++) { - int for_key_vector = process_wld_key(seat->xkb_state, *p, NULL, NULL); -//fprintf(stderr, "%d ", for_key_vector); - if (search_int_vector(key_vector, for_key_vector) < 0) { - key_vector.push_back(for_key_vector); - } - } -//fprintf(stderr, "\n"); - seat->keyboard_surface = surface; - seat->keyboard_enter_serial = serial; - last_keydown_serial = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (win) { - Fl::handle(FL_FOCUS, win); - fl_wl_find(fl_wl_xid(win)); - } -} - - -struct key_repeat_data_t { - uint32_t serial; - Fl_Window *window; -}; - -#define KEY_REPEAT_DELAY 0.5 // sec -#define KEY_REPEAT_INTERVAL 0.05 // sec - - -static void key_repeat_timer_cb(key_repeat_data_t *key_repeat_data) { - if (last_keydown_serial == key_repeat_data->serial) { - Fl::handle(FL_KEYDOWN, key_repeat_data->window); - Fl::add_timeout(KEY_REPEAT_INTERVAL, (Fl_Timeout_Handler)key_repeat_timer_cb, key_repeat_data); - } - else delete key_repeat_data; -} - - -int Fl_Wayland_Screen_Driver::next_marked_length = 0; - - -int Fl_Wayland_Screen_Driver::has_marked_text() const { - return 1; -} - - -int Fl_Wayland_Screen_Driver::insertion_point_x = 0; -int Fl_Wayland_Screen_Driver::insertion_point_y = 0; -int Fl_Wayland_Screen_Driver::insertion_point_width = 0; -int Fl_Wayland_Screen_Driver::insertion_point_height = 0; -bool Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false; - -static int previous_cursor_x = 0, previous_cursor_y = 0, previous_cursor_h = 0; -static uint32_t commit_serial = 0; -static char *current_pre_edit = NULL; -static char *pending_pre_edit = NULL; -static char *pending_commit = NULL; - - -static void send_commit(struct zwp_text_input_v3 *zwp_text_input_v3) { - zwp_text_input_v3_commit(zwp_text_input_v3); - commit_serial++; -} - - -// inform TIM about location of the insertion point, and memorize this info. -void Fl_Wayland_Screen_Driver::insertion_point_location(int x, int y, int height) { -//printf("insertion_point_location %dx%d\n",x,y); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->seat->text_input /*&& !current_pre_edit*/ && - (x != previous_cursor_x || y != previous_cursor_y || height != previous_cursor_h)) { - previous_cursor_x = x; - previous_cursor_y = y; - previous_cursor_h = height; - if (Fl::focus()) { - Fl_Widget *focuswin = Fl::focus()->window(); - while (focuswin && focuswin->parent()) { - x += focuswin->x(); y += focuswin->y(); - focuswin = focuswin->window(); - } - } - float s = fl_graphics_driver->scale(); - insertion_point_location_is_valid = true; - insertion_point_x = s*x; - insertion_point_y = s*(y-height); - insertion_point_width = s*5; - insertion_point_height = s*height; - if (zwp_text_input_v3_get_user_data(scr_driver->seat->text_input) ) { - zwp_text_input_v3_set_cursor_rectangle(scr_driver->seat->text_input, - insertion_point_x, insertion_point_y, - insertion_point_width, insertion_point_height); - send_commit(scr_driver->seat->text_input); - } - } -} - - -// computes window coordinates & size of insertion point -bool Fl_Wayland_Screen_Driver::insertion_point_location(int *px, int *py, - int *pwidth, int *pheight) { - // return true if the current coordinates and size of the insertion point are available - if ( ! insertion_point_location_is_valid ) return false; - *px = insertion_point_x; - *py = insertion_point_y; - *pwidth = insertion_point_width; - *pheight = insertion_point_height; - return true; -} - - -int Fl_Wayland_Screen_Driver::compose(int& del) { - unsigned char ascii = (unsigned char)Fl::e_text[0]; - // letter+modifier key - int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && ascii < 128 ; - // pressing modifier key - // FL_Shift_L, FL_Shift_R, FL_Control_L, FL_Control_R, FL_Caps_Lock - // FL_Meta_L, FL_Meta_R, FL_Alt_L, FL_Alt_R - condition |= ((Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || - Fl::e_keysym == FL_Alt_Gr); - // FL_Home FL_Left FL_Up FL_Right FL_Down FL_Page_Up FL_Page_Down FL_End - // FL_Print FL_Insert FL_Menu FL_Help and more - condition |= (Fl::e_keysym >= FL_Home && Fl::e_keysym <= FL_Num_Lock); - condition |= (Fl::e_keysym >= FL_F && Fl::e_keysym <= FL_F_Last); - condition |= Fl::e_keysym == FL_Tab || Fl::e_keysym == FL_Scroll_Lock || Fl::e_keysym == FL_Pause; -//fprintf(stderr, "compose: condition=%d e_state=%x ascii=%d\n", condition, Fl::e_state, ascii); - if (condition) { del = 0; return 0;} -//fprintf(stderr, "compose: del=%d compose_state=%d next_marked_length=%d \n", del, Fl::compose_state, next_marked_length); - del = Fl::compose_state; - Fl::compose_state = next_marked_length; - // no-underlined-text && (ascii non-printable || ascii == delete) - if (ascii && (!Fl::compose_state) && (ascii <= 31 || ascii == 127)) { del = 0; return 0; } - return 1; -} - - -void Fl_Wayland_Screen_Driver::compose_reset() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl::compose_state = 0; - next_marked_length = 0; - if (seat->xkb_compose_state) xkb_compose_state_reset(seat->xkb_compose_state); -} - - -struct dead_key_struct { - xkb_keysym_t keysym; // the keysym obtained when hitting a dead key - const char *marked_text; // the temporary text to display for that dead key -}; - - -static dead_key_struct dead_keys[] = { - {XKB_KEY_dead_grave, "`"}, - {XKB_KEY_dead_acute, "´"}, - {XKB_KEY_dead_circumflex, "^"}, - {XKB_KEY_dead_tilde, "~"}, - {XKB_KEY_dead_macron, "¯"}, - {XKB_KEY_dead_breve, "˘"}, - {XKB_KEY_dead_abovedot, "˙"}, - {XKB_KEY_dead_diaeresis, "¨"}, - {XKB_KEY_dead_abovering, "˚"}, - {XKB_KEY_dead_doubleacute, "˝"}, - {XKB_KEY_dead_caron, "ˇ"}, - {XKB_KEY_dead_cedilla, "¸"}, - {XKB_KEY_dead_ogonek, "˛"}, - {XKB_KEY_dead_iota, "ι"}, - {XKB_KEY_dead_doublegrave, " ̏"}, -}; - - -const int dead_key_count = sizeof(dead_keys)/sizeof(struct dead_key_struct); - -static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - seat->serial = serial; - static char buf[128]; - uint32_t keycode; - xkb_keysym_t sym; - int for_key_vector = process_wld_key(seat->xkb_state, key, &keycode, &sym); -#if (DEBUG_KEYBOARD) - xkb_keysym_get_name(sym, buf, sizeof(buf)); - const char *action = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release"); - fprintf(stderr, "wl_keyboard_key: key %s: sym: %-12s(%d) code:%u fl_win=%p, ", - action, buf, sym, keycode, - Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface)); -#endif - xkb_state_key_get_utf8(seat->xkb_state, keycode, buf, sizeof(buf)); -#if (DEBUG_KEYBOARD) - fprintf(stderr, "utf8: '%s' e_length=%d [%d]\n", buf, (int)strlen(buf), *buf); -#endif - Fl::e_keysym = Fl::e_original_keysym = for_key_vector; - if (!(Fl::e_state & FL_NUM_LOCK) && sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete) { - // compute e_keysym and e_original_keysym for keypad number keys and '.|,' when NumLock is off - static const int table[11] = {FL_Home /* 7 */, FL_Left /* 4 */, FL_Up /* 8 */, - FL_Right /* 6 */, FL_Down /* 2 */, FL_Page_Up /* 9 */, - FL_Page_Down /* 3 */, FL_End /* 1 */, 0xff0b /* 5 */, - FL_Insert /* 0 */, FL_Delete /* .|, */}; - static const int table_original[11] = {0xffb7 /* 7 */, 0xffb4 /* 4 */, 0xffb8 /* 8 */, - 0xffb6 /* 6 */, 0xffb2 /* 2 */, 0xffb9 /* 9 */, - 0xffb3 /* 3 */, 0xffb1 /* 1 */, 0xffb5 /* 5 */, - 0xffb0 /* 0 */, 0xffac /* .|, */}; - Fl::e_keysym = table[sym - XKB_KEY_KP_Home]; - Fl::e_original_keysym = table_original[sym - XKB_KEY_KP_Home]; - for_key_vector = Fl::e_original_keysym; - } -#if (DEBUG_KEYBOARD) - fprintf(stderr, "wl_keyboard_key: e_keysym=%x e_original_keysym=%x\n", Fl::e_keysym, Fl::e_original_keysym); -#endif - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - if (search_int_vector(key_vector, for_key_vector) < 0) { - key_vector.push_back(for_key_vector); - } - } else { - last_keydown_serial = 0; - remove_int_vector(key_vector, for_key_vector); - } - Fl::e_text = buf; - Fl::e_length = (int)strlen(buf); - // Process dead keys and compose sequences : - enum xkb_compose_status status = XKB_COMPOSE_NOTHING; - // This part is useful only if the compositor doesn't support protocol text-input-unstable-v3 - if (seat->xkb_compose_state && state == WL_KEYBOARD_KEY_STATE_PRESSED && - !(sym >= FL_Shift_L && sym <= FL_Alt_R) && sym != XKB_KEY_ISO_Level3_Shift) { - xkb_compose_state_feed(seat->xkb_compose_state, sym); - status = xkb_compose_state_get_status(seat->xkb_compose_state); - if (status == XKB_COMPOSE_COMPOSING) { - if (Fl::e_length == 0) { // dead keys produce e_length = 0 - int i; - for (i = 0; i < dead_key_count; i++) { - if (dead_keys[i].keysym == sym) break; - } - if (i < dead_key_count) strcpy(buf, dead_keys[i].marked_text); - else buf[0] = 0; - Fl::e_length = (int)strlen(buf); - Fl::compose_state = 0; - } - Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length; - } else if (status == XKB_COMPOSE_COMPOSED) { - Fl::e_length = xkb_compose_state_get_utf8(seat->xkb_compose_state, buf, sizeof(buf)); - Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - } else if (status == XKB_COMPOSE_CANCELLED) { - Fl::e_length = 0; - Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - } -//fprintf(stderr, "xkb_compose_status=%d ctxt=%p state=%p l=%d[%s]\n", status, seat->xkb_context, seat->xkb_compose_state, Fl::e_length, buf); - } - // end of part used only without text-input-unstable-v3 - - wld_event_time = time; - int event = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? FL_KEYDOWN : FL_KEYUP); - // Send event to focus-containing top window as defined by FLTK, - // otherwise send it to Wayland-defined focus window - Fl_Window *win = ( Fl::focus() ? Fl::focus()->top_window() : - Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface) ); - if (win) { - set_event_xy(win); - Fl::e_is_click = 0; - Fl::handle(event, win); - } - if (event == FL_KEYDOWN && status == XKB_COMPOSE_NOTHING && - !(sym >= FL_Shift_L && sym <= FL_Alt_R)) { - // Handling of key repeats : - // Use serial argument rather than time to detect repeated keys because - // serial value changes at each key up or down in all tested OS and compositors, - // whereas time value changes in Ubuntu24.04 KDE/Plasma 5.27.11 and Ubuntu22.04 KDE/Plasma 5.24.7 - // but not in Debian-testing KDE/Plasma 5.27.10. - // Unexplained difference in behaviors of KDE/Plasma compositor: - // Consider KDE settings -> input -> keyboard -> when a key is held: repeat/do nothing. - // This setting (repeat) has key-down wayland events repeated when key is held under Debian/KDE - // but not under Ubuntu/KDE ! - key_repeat_data_t *key_repeat_data = new key_repeat_data_t; - key_repeat_data->serial = serial; - key_repeat_data->window = win; - last_keydown_serial = serial; - Fl::add_timeout(KEY_REPEAT_DELAY, (Fl_Timeout_Handler)key_repeat_timer_cb, - key_repeat_data); - } -} - - -static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; -//fprintf(stderr, "keyboard leave fl_win=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface)); - seat->keyboard_surface = NULL; - last_keydown_serial = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (!win && Fl::focus()) win = Fl::focus()->top_window(); - if (win) Fl::handle(FL_UNFOCUS, win); - key_vector.clear(); -} - - -static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t mods_depressed, - uint32_t mods_latched, uint32_t mods_locked, - uint32_t group) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched, mods_locked, - 0, 0, group); - Fl::e_state &= ~(FL_SHIFT+FL_CTRL+FL_ALT+FL_META+FL_CAPS_LOCK+FL_NUM_LOCK); - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_SHIFT, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_SHIFT; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_CTRL; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_ALT, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_ALT; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_LOGO, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_META; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CAPS, - XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_CAPS_LOCK; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_NUM, - XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_NUM_LOCK; -//fprintf(stderr, "mods_depressed=%u Fl::e_state=%X\n", mods_depressed, Fl::e_state); -} - - -static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) -{ - // wl_keyboard is version 3 under Debian, but that event isn't sent until version 4 -} - - -static const struct wl_keyboard_listener wl_keyboard_listener = { - .keymap = wl_keyboard_keymap, - .enter = wl_keyboard_enter, - .leave = wl_keyboard_leave, - .key = wl_keyboard_key, - .modifiers = wl_keyboard_modifiers, - .repeat_info = wl_keyboard_repeat_info, -}; - - -void text_input_enter(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - struct wl_surface *surface) { -//puts("text_input_enter"); - zwp_text_input_v3_set_user_data(zwp_text_input_v3, surface); - zwp_text_input_v3_enable(zwp_text_input_v3); - zwp_text_input_v3_set_content_type(zwp_text_input_v3, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL); - int x, y, width, height; - if (Fl_Wayland_Screen_Driver::insertion_point_location(&x, &y, &width, &height)) { - zwp_text_input_v3_set_cursor_rectangle(zwp_text_input_v3, x, y, width, height); - } - send_commit(zwp_text_input_v3); -} - - -void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - struct wl_surface *surface) { -//puts("text_input_leave"); - zwp_text_input_v3_disable(zwp_text_input_v3); - zwp_text_input_v3_set_user_data(zwp_text_input_v3, NULL); - send_commit(zwp_text_input_v3); - free(pending_pre_edit); pending_pre_edit = NULL; - free(current_pre_edit); current_pre_edit = NULL; - free(pending_commit); pending_commit = NULL; -} - - -static void send_text_to_fltk(const char *text, bool is_marked, struct wl_surface *current_surface) { -//printf("send_text_to_fltk(%s, %d)\n",text,is_marked); - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(current_surface); - Fl::e_text = text ? (char*)text : (char*)""; - Fl::e_length = text ? (int)strlen(text) : 0; - Fl::e_keysym = 'a'; // fake a simple key - set_event_xy(win); - Fl::e_is_click = 0; - if (is_marked) { // goes to widget as marked text - Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length; - Fl::handle(FL_KEYDOWN, win); - } else if (text) { - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl::handle(FL_KEYDOWN, win); - Fl::compose_state = 0; - } else { - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl::handle(FL_KEYDOWN, win); - } -} - - -void text_input_preedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - const char *text, int32_t cursor_begin, int32_t cursor_end) { -//printf("text_input_preedit_string %s cursor_begin=%d cursor_end=%d\n",text, cursor_begin, cursor_end); - free(pending_pre_edit); - pending_pre_edit = text ? strdup(text) : NULL; -} - - -void text_input_commit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - const char *text) { -//printf("text_input_commit_string %s\n",text); - free(pending_commit); - pending_commit = (text ? strdup(text) : NULL); -} - - -void text_input_delete_surrounding_text(void *data, - struct zwp_text_input_v3 *zwp_text_input_v3, - uint32_t before_length, uint32_t after_length) { - fprintf(stderr, "delete_surrounding_text before=%d adfter=%d\n", - before_length,after_length); -} - - -void text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - uint32_t serial) { -//puts("text_input_done"); - struct wl_surface *current_surface = (struct wl_surface*)data; - const bool bad_event = (serial != commit_serial); - if ((pending_pre_edit == NULL && current_pre_edit == NULL) || - (pending_pre_edit && current_pre_edit && strcmp(pending_pre_edit, current_pre_edit) == 0)) { - free(pending_pre_edit); pending_pre_edit = NULL; - } else { - free(current_pre_edit); - current_pre_edit = pending_pre_edit; - pending_pre_edit = NULL; - if (current_pre_edit) { - send_text_to_fltk(current_pre_edit, !bad_event, current_surface); - } else { - send_text_to_fltk(NULL, false, current_surface); - } - } - if (pending_commit) { - send_text_to_fltk(pending_commit, false, current_surface); - free(pending_commit); pending_commit = NULL; - } -} - - -static const struct zwp_text_input_v3_listener text_input_listener = { - .enter = text_input_enter, - .leave = text_input_leave, - .preedit_string = text_input_preedit_string, - .commit_string = text_input_commit_string, - .delete_surrounding_text = text_input_delete_surrounding_text, - .done = text_input_done, -}; - - -void Fl_Wayland_Screen_Driver::enable_im() { - if (text_input_base && !seat->text_input) { - seat->text_input = zwp_text_input_manager_v3_get_text_input(text_input_base, - seat->wl_seat); - //printf("seat->text_input=%p\n",seat->text_input); - zwp_text_input_v3_add_listener(seat->text_input, &text_input_listener, NULL); - } -} - - -void Fl_Wayland_Screen_Driver::disable_im() { - if (seat->text_input) { - zwp_text_input_v3_disable(seat->text_input); - zwp_text_input_v3_commit(seat->text_input); - zwp_text_input_v3_destroy(seat->text_input); - seat->text_input = NULL; - free(pending_pre_edit); pending_pre_edit = NULL; - free(current_pre_edit); current_pre_edit = NULL; - free(pending_commit); pending_commit = NULL; - } -} - - -static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) -{ - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); - seat->pointer_scale = 1; -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_manager) { - scr_driver->wp_cursor_shape_device = - wp_cursor_shape_manager_v1_get_pointer(scr_driver->wp_cursor_shape_manager, seat->wl_pointer); - } -#endif // HAVE_CURSOR_SHAPE - init_cursors(seat); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) { - wl_pointer_release(seat->wl_pointer); - seat->wl_pointer = NULL; - } - - bool have_keyboard = seat->xkb_context && (capabilities & WL_SEAT_CAPABILITY_KEYBOARD); - if (have_keyboard && seat->wl_keyboard == NULL) { - seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(seat->wl_keyboard, - &wl_keyboard_listener, seat); -//fprintf(stderr, "wl_keyboard version=%d\n", wl_keyboard_get_version(seat->wl_keyboard)); - - } else if (!have_keyboard && seat->wl_keyboard != NULL) { - wl_keyboard_release(seat->wl_keyboard); - seat->wl_keyboard = NULL; - } - scr_driver->enable_im(); -} - - -static void seat_name(void *data, struct wl_seat *wl_seat, const char *name) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - seat->name = strdup(name); -} - - -static struct wl_seat_listener seat_listener = { - seat_capabilities, - seat_name -}; - - -static void output_geometry(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform) -{ - //fprintf(stderr, "output_geometry: x=%d y=%d physical=%dx%d\n",x,y,physical_width,physical_height); - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->x = int(x); - output->y = int(y); - output->dpi = 96; // to elaborate -} - - -static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags, - int32_t width, int32_t height, int32_t refresh) -{ - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->pixel_width = int(width); - output->pixel_height = int(height); - output->width = output->pixel_width; // until further notice - output->height = output->pixel_height; -//fprintf(stderr, "output_mode: [%p]=%dx%d\n",output->wl_output,width,height); -} - - -static void output_done(void *data, struct wl_output *wl_output) -{ - // Runs at startup and when desktop scale factor is changed or screen added - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; -//fprintf(stderr, "output_done output=%p\n",output); - Fl_X *xp = Fl_X::first; - while (xp) { // all mapped windows - struct wld_window *win = (struct wld_window*)xp->xid; - Fl_Window *W = win->fl_win; - if (win->buffer || W->as_gl_window()) { - if (W->as_gl_window()) { - wl_surface_set_buffer_scale(win->wl_surface, output->wld_scale); - Fl_Window_Driver::driver(W)->is_a_rescale(true); - W->resize(W->x(), W->y(), W->w(), W->h()); - Fl_Window_Driver::driver(W)->is_a_rescale(false); - } else { - Fl_Wayland_Graphics_Driver::buffer_release(win); - } - W->redraw(); - Fl_Window_Driver::driver(W)->flush(); - } - xp = xp->next; - } - output->done = true; - - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->screen_count_get() > 0) { // true when output_done runs after initial screen dectection - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - scr_driver->init_workarea(); - } -} - - -static void output_scale(void *data, struct wl_output *wl_output, int32_t factor) { - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->wld_scale = factor; -//fprintf(stderr,"output_scale: wl_output=%p factor=%d\n",wl_output, factor); - // rescale cursors of windows that map here and have a custom cursor - Fl_Window *win = Fl::first_window(); - while (win) { - struct wld_window *xid = fl_wl_xid(win); - struct Fl_Wayland_Window_Driver::surface_output *s_output; - // get 1st screen where window appears - s_output = wl_container_of(xid->outputs.next, s_output, link); - if (xid->custom_cursor && output == s_output->output) { - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win); - driver->set_cursor_4args(xid->custom_cursor->rgb, - xid->custom_cursor->hotx, xid->custom_cursor->hoty, false); - }; - win = Fl::next_window(win); - } -} - - -static struct wl_output_listener output_listener = { - output_geometry, - output_mode, - output_done, - output_scale -}; - - -struct pair_bool { - bool found_gtk_shell; - bool found_wf_shell; -}; - - -// Notice: adding use of unstable protocol "XDG output" would allow FLTK to be notified -// in real time of changes to the relative location of multiple displays; -// with the present code, that information is received at startup only. -static void registry_handle_global(void *user_data, struct wl_registry *wl_registry, - uint32_t id, const char *interface, uint32_t version) { -//fprintf(stderr, "interface=%s version=%u\n", interface, version); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (strcmp(interface, "wl_compositor") == 0) { - if (version < 4) { - Fl::fatal("wl_compositor version >= 4 required"); - } - scr_driver->wl_compositor = (struct wl_compositor*)wl_registry_bind(wl_registry, - id, &wl_compositor_interface, 4); - - } else if (strcmp(interface, "wl_subcompositor") == 0) { - scr_driver->wl_subcompositor = (struct wl_subcompositor*)wl_registry_bind(wl_registry, - id, &wl_subcompositor_interface, 1); - - } else if (strcmp(interface, "wl_shm") == 0) { - scr_driver->wl_shm = (struct wl_shm*)wl_registry_bind(wl_registry, - id, &wl_shm_interface, 1); - - } else if (strcmp(interface, "wl_seat") == 0) { - if (version < 3) { - Fl::fatal("%s version 3 required but only version %i is available\n", - interface, version); - } - if (!scr_driver->seat) scr_driver->seat = - (struct Fl_Wayland_Screen_Driver::seat*)calloc(1, - sizeof(struct Fl_Wayland_Screen_Driver::seat)); -//fprintf(stderr, "registry_handle_global: seat=%p\n", scr_driver->seat); - wl_list_init(&scr_driver->seat->pointer_outputs); - scr_driver->seat->wl_seat = (wl_seat*)wl_registry_bind(wl_registry, id, - &wl_seat_interface, 3); - scr_driver->seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (scr_driver->seat->xkb_context) { - const char *locale = getenv("LC_ALL"); - if (!locale || !*locale) - locale = getenv("LC_CTYPE"); - if (!locale || !*locale) - locale = getenv("LANG"); - if (!locale || !*locale) - locale = "C"; - struct xkb_compose_table *table = - xkb_compose_table_new_from_locale(scr_driver->seat->xkb_context, locale, - XKB_COMPOSE_COMPILE_NO_FLAGS); - if (table) { - scr_driver->seat->xkb_compose_state = - xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS); - } - } - wl_seat_add_listener(scr_driver->seat->wl_seat, &seat_listener, scr_driver->seat); - if (scr_driver->seat->data_device_manager) { - scr_driver->seat->data_device = - wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager, - scr_driver->seat->wl_seat); - wl_data_device_add_listener(scr_driver->seat->data_device, - Fl_Wayland_Screen_Driver::p_data_device_listener, NULL); - } - - } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { - if (!scr_driver->seat) scr_driver->seat = - (struct Fl_Wayland_Screen_Driver::seat*)calloc(1, - sizeof(struct Fl_Wayland_Screen_Driver::seat)); - scr_driver->seat->data_device_manager = - (struct wl_data_device_manager*)wl_registry_bind(wl_registry, id, - &wl_data_device_manager_interface, - fl_min(version, 3)); - if (scr_driver->seat->wl_seat) { - scr_driver->seat->data_device = - wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager, - scr_driver->seat->wl_seat); - wl_data_device_add_listener(scr_driver->seat->data_device, - Fl_Wayland_Screen_Driver::p_data_device_listener, NULL); - } -//fprintf(stderr, "registry_handle_global: %s\n", interface); - - } else if (strcmp(interface, "wl_output") == 0) { - if (version < 2) { - Fl::fatal("%s version 2 required but only version %i is available\n", - interface, version); - } - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output); - output->id = id; - output->wld_scale = 1; -#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION - const int used_version = WL_OUTPUT_RELEASE_SINCE_VERSION; -#else - const int used_version = 2; -#endif - output->wl_output = (struct wl_output*)wl_registry_bind(wl_registry, - id, &wl_output_interface, fl_min(used_version, version)); - output->gui_scale = 1.f; - wl_proxy_set_tag((struct wl_proxy *) output->wl_output, &proxy_tag); - wl_output_add_listener(output->wl_output, &output_listener, output); - // Put new screen in list of screens, but make sure it's not in list already - // which may occur after having removed a screen. - bool found = false; - Fl_Wayland_Screen_Driver::output *elt; - wl_list_for_each(elt, &scr_driver->outputs, link) { - if (elt == output) found = true; - } - if (!found) { // add to end of the linked list of displays - struct wl_list *e = &scr_driver->outputs; - while (e->next != &scr_driver->outputs) e = e->next; // move e to end of linked list - wl_list_insert(e, &output->link); - } -//fprintf(stderr, "wl_output: id=%d wl_output=%p \n", id, output->wl_output); - - } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { -//fprintf(stderr, "registry_handle_global interface=%s\n", interface); - scr_driver->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, id, - &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(scr_driver->xdg_wm_base, &xdg_wm_base_listener, NULL); - } else if (strstr(interface, "wf_shell_manager")) { - ((pair_bool*)user_data)->found_wf_shell = true; - } else if (strcmp(interface, "gtk_shell1") == 0) { - ((pair_bool*)user_data)->found_gtk_shell = true; - //fprintf(stderr, "Running the Mutter compositor\n"); - scr_driver->seat->gtk_shell = (struct gtk_shell1*)wl_registry_bind(wl_registry, id, - >k_shell1_interface, version); - } else if (strcmp(interface, "weston_desktop_shell") == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::WESTON; - //fprintf(stderr, "Running the Weston compositor\n"); - } else if (strcmp(interface, "org_kde_plasma_shell") == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::KWIN; - //fprintf(stderr, "Running the KWin compositor\n"); - } else if (strncmp(interface, "zowl_mach_ipc", 13) == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::OWL; - //fprintf(stderr, "Running the Owl compositor\n"); - if (wl_list_length(&scr_driver->outputs) == 0) { - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output); - output->id = 1; - output->wld_scale = 1; - output->gui_scale = 1.f; - output->width = 1440; output->height = 900; - output->pixel_width = 1440; output->pixel_height = 900; - output->done = true; - wl_list_insert(&(scr_driver->outputs), &output->link); - scr_driver->screen_count_set(1); - } - } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { - scr_driver->text_input_base = (struct zwp_text_input_manager_v3 *) - wl_registry_bind(wl_registry, id, &zwp_text_input_manager_v3_interface, 1); -//printf("scr_driver->text_input_base=%p version=%d\n",scr_driver->text_input_base,version); -#if HAVE_XDG_DIALOG - } else if (strcmp(interface, xdg_wm_dialog_v1_interface.name) == 0) { - scr_driver->xdg_wm_dialog = (struct xdg_wm_dialog_v1 *) - wl_registry_bind(wl_registry, id, &xdg_wm_dialog_v1_interface, 1); -#endif // HAVE_XDG_DIALOG -#if HAVE_CURSOR_SHAPE - } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { - scr_driver->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *) - wl_registry_bind(wl_registry, id, &wp_cursor_shape_manager_v1_interface, 1); -#endif // HAVE_CURSOR_SHAPE - } -} - - -static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { - Fl_Wayland_Screen_Driver::output *output; -//fprintf(stderr, "registry_handle_global_remove data=%p id=%u\n", data, name); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - bool has_removed_screen = false; - wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens - if (output->id == name) { // the screen being removed - wl_list_remove(&output->link); - wl_output_destroy(output->wl_output); - free(output); - has_removed_screen = true; - break; - } - } - if (has_removed_screen) { - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - scr_driver->init_workarea(); - } -} - - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - - -static void wayland_socket_callback(int fd, struct wl_display *display) -{ - if (wl_display_prepare_read(display) == -1) { - wl_display_dispatch_pending(display); - return; - } - wl_display_flush(display); - struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 }; - if (poll(&fds, 1, 0) <= 0) { - wl_display_cancel_read(display); - return; - } - if (fds.revents & (POLLERR | POLLHUP)) { - wl_display_cancel_read(display); - goto fatal; - } - if (wl_display_read_events(display) == -1) - goto fatal; - if (wl_display_dispatch_pending(display) == -1) - goto fatal; - return; -fatal: - if (wl_display_get_error(display) == EPROTO) { - const struct wl_interface *interface; - int code = wl_display_get_protocol_error(display, &interface, NULL); - Fl::fatal("Fatal error %d in Wayland protocol: %s", - code, (interface ? interface->name : "unknown") ); - } else { - Fl::fatal("Fatal error while communicating with Wayland server: %s", - strerror(errno)); - } -} - - -Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() { - libdecor_context = NULL; - seat = NULL; - text_input_base = NULL; - reset_cursor(); - wl_registry = NULL; -#if HAVE_XDG_DIALOG - xdg_wm_dialog = NULL; -#endif -#if HAVE_CURSOR_SHAPE - wp_cursor_shape_manager = NULL; - wp_cursor_shape_device = NULL; -#endif -} - - -static void sync_done(void *data, struct wl_callback *cb, uint32_t time) { - // runs after all calls to registry_handle_global() - *(struct wl_callback **)data = NULL; - wl_callback_destroy(cb); - // keep processing until output_done() has run for each screen - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &scr_driver->outputs, link) { // each screen of the system - while (!output->done) wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - // Now all screens have been initialized - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - struct pair_bool *pair = (struct pair_bool*)wl_registry_get_user_data(scr_driver->wl_registry); - if (pair->found_gtk_shell || pair->found_wf_shell) { - Fl_Wayland_Screen_Driver::compositor = (pair->found_wf_shell ? - Fl_Wayland_Screen_Driver::WAYFIRE : Fl_Wayland_Screen_Driver::MUTTER); - } - if (scr_driver->seat) { -#if HAVE_CURSOR_SHAPE - if (!scr_driver->wp_cursor_shape_manager) -#endif - try_update_cursor(scr_driver->seat); - } - if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::OWL) scr_driver->init_workarea(); -} - - -static const struct wl_callback_listener sync_listener = { - sync_done -}; - - -static void do_atexit() { - if (Fl_Wayland_Screen_Driver::wl_display) { - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } -} - - -void Fl_Wayland_Screen_Driver::open_display_platform() { - static bool beenHereDoneThat = false; - if (beenHereDoneThat) - return; - - beenHereDoneThat = true; - - if (!wl_display) { - wl_display = wl_display_connect(NULL); - if (!wl_display) { - Fl::fatal("No Wayland connection\n"); - } - } - //puts("Using Wayland backend"); - wl_list_init(&outputs); - - wl_registry = wl_display_get_registry(wl_display); - struct pair_bool pair = {false, false}; - wl_registry_add_listener(wl_registry, ®istry_listener, &pair); - struct wl_callback *registry_cb = wl_display_sync(wl_display); - wl_callback_add_listener(registry_cb, &sync_listener, ®istry_cb); - while (registry_cb) wl_display_dispatch(wl_display); - Fl::add_fd(wl_display_get_fd(wl_display), FL_READ, (Fl_FD_Handler)wayland_socket_callback, - wl_display); - fl_create_print_window(); - /* This is useful to avoid crash of the Wayland compositor after - FLTK apps terminate in certain situations: - - gnome-shell version < 44 (e.g. version 42.9) - - focus set to "follow-mouse" - See issue #821 for details. - */ - atexit(do_atexit); -} - - -void Fl_Wayland_Screen_Driver::close_display() { - if (!Fl_Wayland_Screen_Driver::wl_display) return; - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (text_input_base) { - disable_im(); - zwp_text_input_manager_v3_destroy(text_input_base); - text_input_base = NULL; - } - while (wl_list_length(&outputs) > 0) { - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - wl_list_remove(&output->link); - screen_count_set( wl_list_length(&outputs) ); - if (output->wl_output) { -#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION - if (wl_output_get_version(output->wl_output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) - wl_output_release(output->wl_output); - else -#endif - wl_output_destroy(output->wl_output); - } - free(output); - break; - } - } - wl_subcompositor_destroy(wl_subcompositor); wl_subcompositor = NULL; - wl_surface_destroy(seat->cursor_surface); seat->cursor_surface = NULL; - if (seat->cursor_theme) { - wl_cursor_theme_destroy(seat->cursor_theme); - seat->cursor_theme = NULL; - } - wl_compositor_destroy(wl_compositor); wl_compositor = NULL; - // wl_shm-related data - if (Fl_Wayland_Graphics_Driver::current_pool) { - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data = - (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*) - wl_shm_pool_get_user_data(Fl_Wayland_Graphics_Driver::current_pool); - wl_shm_pool_destroy(Fl_Wayland_Graphics_Driver::current_pool); - Fl_Wayland_Graphics_Driver::current_pool = NULL; - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); - //printf("close_display munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - wl_shm_destroy(wl_shm); wl_shm = NULL; - if (seat->wl_keyboard) { - if (seat->xkb_state) { - xkb_state_unref(seat->xkb_state); - seat->xkb_state = NULL; - } - if (seat->xkb_keymap) { - xkb_keymap_unref(seat->xkb_keymap); - seat->xkb_keymap = NULL; - } - wl_keyboard_destroy(seat->wl_keyboard); - seat->wl_keyboard = NULL; - } - wl_pointer_destroy(seat->wl_pointer); seat->wl_pointer = NULL; - if (seat->xkb_compose_state) { - xkb_compose_state_unref(seat->xkb_compose_state); - seat->xkb_compose_state = NULL; - } - if (seat->xkb_context) { - xkb_context_unref(seat->xkb_context); - seat->xkb_context = NULL; - } - if (seat->data_source) { - wl_data_source_destroy(seat->data_source); - seat->data_source = NULL; - } - wl_data_device_destroy(seat->data_device); seat->data_device = NULL; - wl_data_device_manager_destroy(seat->data_device_manager); - seat->data_device_manager = NULL; - wl_seat_destroy(seat->wl_seat); seat->wl_seat = NULL; - if (seat->name) free(seat->name); - free(seat); seat = NULL; - if (libdecor_context) { - libdecor_unref(libdecor_context); - libdecor_context = NULL; - } - xdg_wm_base_destroy(xdg_wm_base); xdg_wm_base = NULL; - Fl_Wayland_Plugin *plugin = Fl_Wayland_Window_Driver::gl_plugin(); - if (plugin) plugin->terminate(); -#if HAVE_XDG_DIALOG - if (xdg_wm_dialog) { - xdg_wm_dialog_v1_destroy(xdg_wm_dialog); - xdg_wm_dialog = NULL; - } -#endif // HAVE_XDG_DIALOG -#if HAVE_CURSOR_SHAPE - if (wp_cursor_shape_device ) { - wp_cursor_shape_device_v1_destroy(wp_cursor_shape_device); - wp_cursor_shape_device = NULL; - } - if (wp_cursor_shape_manager ) { - wp_cursor_shape_manager_v1_destroy(wp_cursor_shape_manager); - wp_cursor_shape_manager = NULL; - } -#endif // HAVE_CURSOR_SHAPE - - Fl::remove_fd(wl_display_get_fd(Fl_Wayland_Screen_Driver::wl_display)); - wl_registry_destroy(wl_registry); wl_registry = NULL; - wl_display_disconnect(Fl_Wayland_Screen_Driver::wl_display); - Fl_Wayland_Screen_Driver::wl_display = NULL; - delete Fl_Display_Device::display_device()->driver(); - delete Fl_Display_Device::display_device(); - delete Fl::system_driver(); - delete this; -} - - -struct configure_s { int W, H; uint32_t state; }; - -static void xdg_toplevel_configure(void *v, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - struct configure_s *data = (struct configure_s*)v; - data->W = width; - data->H = height; - data->state = (width && height && states ? *(uint32_t *)(states->data) : 0); -} - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure, -}; - - -static bool compute_full_and_maximized_areas(Fl_Wayland_Screen_Driver::output *output, - int& Wfullscreen, int& Hfullscreen, - int& Wworkarea, int& Hworkarea) { - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::unspecified) { - Wfullscreen = 0; - return false; - } - bool found_workarea = false; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wl_surface *wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor); - wl_surface_set_opaque_region(wl_surface, NULL); - struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface); - struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); - struct configure_s data = {0, 0, 0}; - xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, &data); - xdg_toplevel_set_fullscreen(xdg_toplevel, output->wl_output); - wl_surface_commit(wl_surface); // necessary under KWin - while (data.state != XDG_TOPLEVEL_STATE_FULLSCREEN) - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - Wfullscreen = data.W; - Hfullscreen = data.H; - if (Wfullscreen && Hfullscreen && wl_list_length(&scr_driver->outputs) == 1) { - struct wl_surface *wl_surface2 = wl_compositor_create_surface(scr_driver->wl_compositor); - struct xdg_surface *xdg_surface2 = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface2); - struct xdg_toplevel *xdg_toplevel2 = xdg_surface_get_toplevel(xdg_surface2); - struct configure_s data2 = {0, 0, 0}; - xdg_toplevel_add_listener(xdg_toplevel2, &xdg_toplevel_listener, &data2); - xdg_toplevel_set_parent(xdg_toplevel2, xdg_toplevel); - xdg_toplevel_set_maximized(xdg_toplevel2); - wl_surface_commit(wl_surface2); // necessary under KWin - while (data2.state != XDG_TOPLEVEL_STATE_MAXIMIZED) - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - Wworkarea = data2.W; - Hworkarea = data2.H; - xdg_toplevel_destroy(xdg_toplevel2); - xdg_surface_destroy(xdg_surface2); - wl_surface_destroy(wl_surface2); - if (Wworkarea == Wfullscreen && Hworkarea < Hfullscreen && Hworkarea > Hfullscreen - 80) - found_workarea = true; - if (Hworkarea == Hfullscreen && Wworkarea < Wfullscreen && Wworkarea > Wfullscreen - 80) - found_workarea = true; - } else { - Wworkarea = Wfullscreen; - Hworkarea = Hfullscreen; - } - xdg_toplevel_destroy(xdg_toplevel); - xdg_surface_destroy(xdg_surface); - wl_surface_destroy(wl_surface); - /*int fractional_scale = int(100 * (output->pixel_width / float(Wfullscreen))); - printf("fullscreen=%dx%d workarea=%dx%d fractional_scale=%d%% wld_s=%d\n", - Wfullscreen,Hfullscreen,Wworkarea,Hworkarea,fractional_scale,output->wld_scale);*/ - return found_workarea; -} - -static int workarea_xywh[4] = { -1, -1, -1, -1 }; - - -/* Implementation note about computing work area and about handling fractional scaling. - - FLTK computes 2 pairs of (WxH) values for each display: - 1) (pixel_width x pixel_height) gives the size in pixel of a display. It's unchanged by - any scaling applied by the compositor; it's assigned by function output_mode(). - 2) (width x height) gives the size in pixels of a buffer that would fully cover the display. - When the active scaling is non-fractional, these equations hold: - pixel_width = width = wld_scale * configured-width-of-fullscreen-window - pixel_height = height = wld_scale * configured-height-of-fullscreen-window - - When fractional scaling is active, buffers received from client are scaled down - by the compositor and mapped to screen. These equations hold: - pixel_width < width = wld_scale * configured-width-of-fullscreen-window - pixel_height < height = wld_scale * configured-height-of-fullscreen-window - - One way for a client to discover that fractional scaling is active on a given display - is to ask for a fullscreen window on that display, get its configured size and compare - it to that display's pixel size. That's what function compute_full_and_maximized_areas() does. - - One way for a client to discover the work area size of a display is to get the configured size - of a maximized window on that display. FLTK didn't find a way to control in general - on what display the compositor puts a maximized window. Therefore, FLTK computes an exact - work area size only when the system contains a single display. We create first a fullscreen - window on the display and then we create a maximized window made a child of the - fullscreen one and record its configured size. That's also done by function - compute_full_and_maximized_areas(). - */ - -void Fl_Wayland_Screen_Driver::init_workarea() -{ - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); // important after screen removal - bool need_init_workarea = true; - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - int Wfullscreen, Hfullscreen, Wworkarea, Hworkarea; - bool found_workarea = compute_full_and_maximized_areas(output, Wfullscreen, Hfullscreen, Wworkarea, Hworkarea); - if (Wfullscreen && Hfullscreen) { // skip sway which puts 0 there - output->width = Wfullscreen * output->wld_scale; // pixels - output->height = Hfullscreen * output->wld_scale; // pixels - if (found_workarea) { - workarea_xywh[0] = output->x; // pixels - workarea_xywh[1] = output->y; // pixels - workarea_xywh[2] = Wworkarea * output->wld_scale; // pixels - workarea_xywh[3] = Hworkarea * output->wld_scale; // pixels - need_init_workarea = false; - } - } - } - if (need_init_workarea) { - screen_xywh(workarea_xywh[0], workarea_xywh[1], workarea_xywh[2], workarea_xywh[3], 0); - } - Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); -} - - -int Fl_Wayland_Screen_Driver::x() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[0] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::y() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[1] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::w() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[2] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::h() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[3] / (output->gui_scale * output->wld_scale); -} - - -void Fl_Wayland_Screen_Driver::init() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); -} - - -void Fl_Wayland_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - if (n == 0) { // for the main screen, these return the work area - X = Fl::x(); - Y = Fl::y(); - W = Fl::w(); - H = Fl::h(); - } else { // for other screens, work area is full screen, - screen_xywh(X, Y, W, H, n); - } -} - - -void Fl_Wayland_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - if (num_screens > 0) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { // n'th screen of the system - float s = output->gui_scale * output->wld_scale; - X = output->x / s; - Y = output->y / s; - W = output->width / s; - H = output->height / s; - break; - } - } - } -} - - -void Fl_Wayland_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - - if (n >= 0 && n < num_screens) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { // n'th screen of the system - h = output->dpi; - v = output->dpi; - break; - } - } - } -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_Wayland_Screen_Driver::beep(int type) -{ - fprintf(stderr, "\007"); -} - - -void Fl_Wayland_Screen_Driver::flush() -{ - if (Fl_Wayland_Screen_Driver::wl_display) { - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - } -} - - -extern void fl_fix_focus(); // in Fl.cxx - - -void Fl_Wayland_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab()) { - } - Fl::grab_ = win; // FIXME: Fl::grab_ "should be private", but we need - // a way to *set* the variable from the driver! - } else { - if (Fl::grab()) { - // We must keep the grab in the non-EWMH fullscreen case - Fl::grab_ = 0; // FIXME: Fl::grab_ "should be private", but we need - // a way to *set* the variable from the driver! - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -static void getsyscolor(const char *key1, const char* key2, const char *arg, - const char *defarg, void (*func)(uchar,uchar,uchar)) { - uchar r, g, b; - if (!arg) arg = defarg; - if (!Fl::screen_driver()->parse_color(arg, r, g, b)) - Fl::error("Unknown color: %s", arg); - else - func(r, g, b); -} - - -void Fl_Wayland_Screen_Driver::get_system_colors() -{ - open_display(); - const char* key1 = 0; - if (Fl::first_window()) key1 = Fl::first_window()->xclass(); - if (!key1) key1 = "fltk"; - if (!bg2_set) - getsyscolor("Text","background", fl_bg2, "#ffffff", Fl::background2); - if (!fg_set) - getsyscolor(key1, "foreground", fl_fg, "#000000", Fl::foreground); - if (!bg_set) - getsyscolor(key1, "background", fl_bg, "#c0c0c0", Fl::background); - getsyscolor("Text", "selectBackground", 0, "#000080", set_selection_color); -} - - -Fl_RGB_Image *Fl_Wayland_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, - Fl_Window *win, - bool ignore, bool *p_ignore) { - struct wld_window* xid = win ? fl_wl_xid(win) : NULL; - if (win && (!xid || !xid->buffer)) return NULL; - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer; - if (win) buffer = &xid->buffer->draw_buffer; - else { - Fl_Image_Surface_Driver *dr = (Fl_Image_Surface_Driver*)Fl_Surface_Device::surface(); - buffer = Fl_Wayland_Graphics_Driver::offscreen_buffer( - dr->image_surface()->offscreen()); - } - float s = win ? - Fl_Wayland_Window_Driver::driver(win)->wld_scale() * scale(win->screen_num()) : - Fl_Surface_Device::surface()->driver()->scale(); - int Xs, Ys, ws, hs; - if (s == 1) { - Xs = X; Ys = Y; ws = w; hs = h; - } else { - Xs = Fl_Scalable_Graphics_Driver::floor(X, s); - Ys = Fl_Scalable_Graphics_Driver::floor(Y, s); - ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Xs; - hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Ys; - } - if (ws == 0 || hs == 0) return NULL; - uchar *data = new uchar[ws * hs * 3]; - uchar *p = data, *q; - for (int j = 0; j < hs; j++) { - q = buffer->buffer + (j+Ys) * buffer->stride + 4 * Xs; - for (int i = 0; i < ws; i++) { - *p++ = *(q+2); // R - *p++ = *(q+1); // G - *p++ = *q; // B - q += 4; - } - } - Fl_RGB_Image *rgb = new Fl_RGB_Image(data, ws, hs, 3); - rgb->alloc_array = 1; - return rgb; -} - - -void Fl_Wayland_Screen_Driver::offscreen_size(Fl_Offscreen off_, int &width, int &height) -{ - struct Fl_Wayland_Graphics_Driver::draw_buffer *off = Fl_Wayland_Graphics_Driver::offscreen_buffer(off_); - width = off->width; - height = off->data_size / off->stride; -} - - -float Fl_Wayland_Screen_Driver::scale(int n) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) break; - } - return output->gui_scale; -} - - -void Fl_Wayland_Screen_Driver::scale(int n, float f) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { - output->gui_scale = f; - return; - } - } -} - - -void Fl_Wayland_Screen_Driver::set_cursor() { - do_set_cursor(seat); -} - - -struct wl_cursor *Fl_Wayland_Screen_Driver::default_cursor() { - return seat->default_cursor; -} - - -void Fl_Wayland_Screen_Driver::default_cursor(struct wl_cursor *cursor) { - seat->default_cursor = cursor; - do_set_cursor(seat); -} - - -struct wl_cursor *Fl_Wayland_Screen_Driver::cache_cursor(const char *cursor_name) { - return wl_cursor_theme_get_cursor(seat->cursor_theme, cursor_name); -} - - -void Fl_Wayland_Screen_Driver::reset_cursor() { - for (int i = 0; i < cursor_count; i++) xc_cursor[i] = NULL; -} - - -uint32_t Fl_Wayland_Screen_Driver::get_serial() { - return seat->serial; -} - - -struct wl_seat*Fl_Wayland_Screen_Driver::get_wl_seat() { - return seat->wl_seat; -} - - -char *Fl_Wayland_Screen_Driver::get_seat_name() { - return seat->name; -} - - -struct xkb_keymap *Fl_Wayland_Screen_Driver::get_xkb_keymap() { - return seat->xkb_keymap; -} - - -int Fl_Wayland_Screen_Driver::get_mouse(int &xx, int &yy) { - open_display(); - xx = Fl::e_x_root; yy = Fl::e_y_root; - if (!seat->pointer_focus) return 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return 0; - int snum = Fl_Window_Driver::driver(win)->screen_num(); -//printf("get_mouse(%dx%d)->%d\n", xx, yy, snum); - return snum; -} - - -void Fl_Wayland_Screen_Driver::set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) { - Fl_Wayland_Screen_Driver::insertion_point_location(x, y, height); -} - - -void Fl_Wayland_Screen_Driver::reset_spot() { - Fl::compose_state = 0; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false; -} - - -void Fl_Wayland_Screen_Driver::display(const char *d) -{ - if (d && !wl_registry) { // if display was opened, it's too late - if (wl_display) { - // only the wl_display_connect() call was done, redo it because the target - // Wayland compositor may be different - wl_display_disconnect(wl_display); - } - wl_display = wl_display_connect(d); - if (!wl_display) { - fprintf(stderr, "Error: '%s' is not an active Wayland socket\n", d); - exit(1); - } - } -} - - -void *Fl_Wayland_Screen_Driver::control_maximize_button(void *data) { - // The code below aims at removing the calling window's fullscreen button - // while dialog runs. Unfortunately, it doesn't work with some X11 window managers - // (e.g., KDE, xfce) because the button goes away but doesn't come back, - // so we move this code to a virtual member function. - // Noticeably, this code works OK under Wayland. - struct win_dims { - Fl_Widget_Tracker *tracker; - int minw, minh, maxw, maxh; - struct win_dims *next; - }; - - if (!data) { // this call turns each decorated window's maximize button off - struct win_dims *first_dim = NULL; - // consider all bordered, top-level FLTK windows - Fl_Window *win = Fl::first_window(); - while (win) { - if (!win->parent() && win->border() && - !( ((struct wld_window*)Fl_X::flx(win)->xid)->state & - LIBDECOR_WINDOW_STATE_MAXIMIZED) ) { - win_dims *dim = new win_dims; - dim->tracker = new Fl_Widget_Tracker(win); - win->get_size_range(&dim->minw, &dim->minh, &dim->maxw, &dim->maxh, NULL, NULL, NULL); - //make win un-resizable - win->size_range(win->w(), win->h(), win->w(), win->h()); - dim->next = first_dim; - first_dim = dim; - } - win = Fl::next_window(win); - } - return first_dim; - } else { // this call returns each decorated window's maximize button to its previous state - win_dims *first_dim = (win_dims *)data; - while (first_dim) { - win_dims *dim = first_dim; - //give back win its resizing parameters - if (dim->tracker->exists()) { - Fl_Window *win = (Fl_Window*)dim->tracker->widget(); - win->size_range(dim->minw, dim->minh, dim->maxw, dim->maxh); - } - first_dim = dim->next; - delete dim->tracker; - delete dim; - } - return NULL; - } -} - - -int Fl_Wayland_Screen_Driver::poll_or_select_with_delay(double time_to_wait) { - if (wl_display_dispatch_pending(wl_display) > 0) return 1; - return Fl_Unix_Screen_Driver::poll_or_select_with_delay(time_to_wait); -} - - -// like Fl_Wayland_Screen_Driver::poll_or_select_with_delay(0.0) except no callbacks are done: -int Fl_Wayland_Screen_Driver::poll_or_select() { - int ret = wl_display_prepare_read(wl_display); - if (ret == 0) wl_display_cancel_read(wl_display); - else return 1; - return Fl_Unix_Screen_Driver::poll_or_select(); -} - - -int Fl_Wayland_Screen_Driver::event_key(int k) { - if (k >= 'A' && k <= 'Z') k += 32; - return (search_int_vector(key_vector, k) >= 0); -} - - -int Fl_Wayland_Screen_Driver::get_key(int k) { - return event_key(k); -} - - -float Fl_Wayland_Screen_Driver::base_scale(int numscreen) { - const char *p; - float factor = 1; - if ((p = fl_getenv("FLTK_SCALING_FACTOR"))) { - sscanf(p, "%f", &factor); - } - return factor; -} - - -struct wl_display *fl_wl_display() { - return Fl_Wayland_Screen_Driver::wl_display; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H deleted file mode 100644 index c5c1bee50..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H +++ /dev/null @@ -1,185 +0,0 @@ -// -// Definition of Wayland window driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Window_Driver.H - \brief Definition of Wayland window driver. - */ - -#ifndef FL_WAYLAND_WINDOW_DRIVER_H -#define FL_WAYLAND_WINDOW_DRIVER_H - -#include <config.h> -#include "../../Fl_Window_Driver.H" -#include <FL/Fl_Plugin.H> -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" - - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - */ - -typedef struct _cairo_pattern cairo_pattern_t; -typedef struct _cairo_rectangle_int cairo_rectangle_int_t; -class Fl_Wayland_Plugin; - - -class Fl_Wayland_Window_Driver : public Fl_Window_Driver -{ - friend class Fl_Wayland_Gl_Window_Driver; -private: - struct shape_data_type { - int lw_; ///< width of shape image - int lh_; ///< height of shape image - Fl_Image* shape_; ///< shape image - cairo_pattern_t *mask_pattern_; - } *shape_data_; - bool can_expand_outside_parent_; // specially to allow window docking (#987) - cairo_rectangle_int_t *subRect_; // makes sure subwindow remains inside its parent window - static bool in_flush_; // useful for progressive window drawing - Fl_Cursor standard_cursor_; // window's standard custom kind - struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish - bool is_popup_window_; -public: - inline Fl_Cursor standard_cursor() { return standard_cursor_; } - bool in_handle_configure; // distinguish OS and user window resize - - struct surface_output { // for linked list of displays where a surface maps - struct Fl_Wayland_Screen_Driver::output *output; - struct wl_list link; - }; - struct custom_cursor { - struct wl_cursor *wl_cursor; - const Fl_RGB_Image *rgb; - int hotx, hoty; - }; - static void delete_cursor(struct custom_cursor *custom, bool delete_rgb = true); - void decorated_win_size(int &w, int &h); - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) override; - FL_EXPORT int wld_scale(); // used by class Fl_Wayland_Gl_Window_Driver - cairo_rectangle_int_t *subRect() { return subRect_; } // getter - void subRect(cairo_rectangle_int_t *r); // setter - void checkSubwindowFrame(); - enum kind {DECORATED, SUBWINDOW, POPUP, UNFRAMED}; - struct xdg_toplevel *xdg_toplevel(); - Fl_Wayland_Window_Driver(Fl_Window*); - virtual ~Fl_Wayland_Window_Driver(); - static struct wld_window *wld_window; - static Fl_Window *surface_to_window(struct wl_surface *); - - static inline Fl_Wayland_Window_Driver* driver(const Fl_Window *w) { - return (Fl_Wayland_Window_Driver*)Fl_Window_Driver::driver(w); - } - static Fl_Wayland_Plugin *gl_plugin(); - - // --- window data - int decorated_w() override; - int decorated_h() override; - const Fl_Image* shape() override; - - // --- window management - void makeWindow() override; - void take_focus() override; - void flush() override; - void flush_overlay() override; - void draw_end() override; - void make_current() override; - void show() override; - void resize(int X,int Y,int W,int H) override; - void label(const char *name, const char *mininame) override; - void hide() override; - void map() override; - void unmap() override; - void fullscreen_on() override; - void fullscreen_off(int X, int Y, int W, int H) override; - void maximize() override; - void un_maximize() override; - void use_border() override; - void size_range() override; - void iconize() override; - void decoration_sizes(int *top, int *left, int *right, int *bottom) override; - // --- window cursor stuff - int set_cursor(Fl_Cursor) override; - int set_cursor(const Fl_RGB_Image*, int, int) override; - int set_cursor_4args(const Fl_RGB_Image*, int, int, bool); - - void shape(const Fl_Image* img) override; - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, - Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) override; - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) override; - void wait_for_expose() override; - // menu-related stuff - void reposition_menu_window(int x, int y) override; - void menu_window_area(int &X, int &Y, int &W, int &H, int nscreen = -1) override; - static bool new_popup; // to support tall menu buttons - bool process_menu_or_tooltip(struct wld_window *); - static Fl_Window *previous_floatingtitle; // to support floating menuwindow w/ title - void allow_expand_outside_parent() override { can_expand_outside_parent_ = true; } -}; - - -struct wld_window { - Fl_Window *fl_win; - struct wl_list outputs; // linked list of displays where part or whole of window maps - struct wl_surface *wl_surface; - struct wl_callback *frame_cb; - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer; - struct xdg_surface *xdg_surface; - union { // for each value of kind - struct libdecor_frame *frame; - struct wl_subsurface *subsurface; - struct xdg_popup *xdg_popup; - struct xdg_toplevel *xdg_toplevel; - }; - // non-null when using custom cursor - struct Fl_Wayland_Window_Driver::custom_cursor *custom_cursor; -#if HAVE_XDG_DIALOG - struct xdg_dialog_v1 *xdg_dialog; -#endif - enum Fl_Wayland_Window_Driver::kind kind; - int configured_width; - int configured_height; - int floating_width; - int floating_height; - int state; - bool covered; // specially for Mutter and issue #878 -}; - - -class Fl_Wayland_Plugin : public Fl_Plugin { -public: - Fl_Wayland_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "wayland.fltk.org"; } - virtual const char *name() = 0; - virtual void do_swap(Fl_Window*) = 0; - virtual void invalidate(Fl_Window*) = 0; - virtual void terminate() = 0; - virtual void destroy(struct gl_start_support *) = 0; -}; - -#endif // FL_WAYLAND_WINDOW_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx deleted file mode 100644 index 0495fb7bc..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ /dev/null @@ -1,2191 +0,0 @@ -// -// Implementation of the Wayland window driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include <FL/filename.H> -#include <wayland-cursor.h> -#include "../../../libdecor/build/fl_libdecor.h" -#include "xdg-shell-client-protocol.h" -#include "gtk-shell-client-protocol.h" -#if HAVE_XDG_DIALOG -# include "xdg-dialog-client-protocol.h" -#endif -#include <pango/pangocairo.h> -#include <FL/Fl_Overlay_Window.H> -#include <FL/Fl_Tooltip.H> -#include <FL/fl_draw.H> -#include <FL/fl_ask.H> -#include <FL/Fl.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_Menu_Button.H> -#include <string.h> -#include <math.h> // for ceil() -#include <sys/types.h> // for pid_t -#include <unistd.h> // for getpid() - -struct cursor_image { // as in wayland-cursor.c of the Wayland project source code - struct wl_cursor_image image; - struct wl_cursor_theme *theme; - struct wl_buffer *buffer; - int offset; /* data offset of this image in the shm pool */ -}; - -extern "C" { -# include "../../../libdecor/src/libdecor-plugin.h" - uchar *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame, int *w, int *h, int *stride); -} - -#define fl_max(a,b) ((a) > (b) ? (a) : (b)) -#define fl_min(a,b) ((a) < (b) ? (a) : (b)) - -#if !defined(FLTK_USE_X11) -Window fl_window = 0; -#endif - - -struct wld_window *Fl_Wayland_Window_Driver::wld_window = NULL; -bool Fl_Wayland_Window_Driver::new_popup = false; // to support tall menu buttons -// A menutitle to be mapped later as the child of a menuwindow -Fl_Window *Fl_Wayland_Window_Driver::previous_floatingtitle = NULL; - - -Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_Driver(win) -{ - shape_data_ = NULL; - standard_cursor_ = FL_CURSOR_DEFAULT; - in_handle_configure = false; - screen_num_ = -1; - gl_start_support_ = NULL; - subRect_ = NULL; - is_popup_window_ = false; - can_expand_outside_parent_ = false; -} - - -void Fl_Wayland_Window_Driver::delete_cursor( - struct Fl_Wayland_Window_Driver::custom_cursor *custom, bool delete_rgb) { - struct wl_cursor *wl_cursor = custom->wl_cursor; - struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0]; - struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen = - (struct Fl_Wayland_Graphics_Driver::wld_buffer *) - wl_buffer_get_user_data(new_image->buffer); - struct wld_window fake_xid; - memset(&fake_xid, 0, sizeof(fake_xid)); - fake_xid.buffer = offscreen; - Fl_Wayland_Graphics_Driver::buffer_release(&fake_xid); - free(new_image); - free(wl_cursor->images); - free(wl_cursor->name); - free(wl_cursor); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->default_cursor() == wl_cursor) { - scr_driver->default_cursor(scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow]); - } - if (delete_rgb) delete custom->rgb; - delete custom; -} - - -Fl_Wayland_Window_Driver::~Fl_Wayland_Window_Driver() -{ - if (shape_data_) { - cairo_surface_t *surface; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface); - uchar *data = cairo_image_surface_get_data(surface); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] data; - delete shape_data_; - } - if (subRect_) delete subRect_; - if (gl_start_support_) { // occurs only if gl_start/gl_finish was used - gl_plugin()->destroy(gl_start_support_); - } -} - - -void Fl_Wayland_Window_Driver::decorated_win_size(int &w, int &h) -{ - Fl_Window *win = pWindow; - w = win->w(); - h = win->h(); - if (!win->shown() || win->parent() || !win->border() || !win->visible()) return; - int X, titlebar_height; - libdecor_frame_translate_coordinate(fl_wl_xid(win)->frame, 0, 0, &X, &titlebar_height); -//printf("titlebar_height=%d\n",titlebar_height); - h = win->h() + ceil(titlebar_height / Fl::screen_scale(win->screen_num())); -} - - -int Fl_Wayland_Window_Driver::decorated_h() -{ - int w, h; - decorated_win_size(w, h); - return h; -} - - -int Fl_Wayland_Window_Driver::decorated_w() -{ - int w, h; - decorated_win_size(w, h); - return w; -} - - -struct xdg_toplevel *Fl_Wayland_Window_Driver::xdg_toplevel() { - struct wld_window * w = fl_wl_xid(pWindow); - struct xdg_toplevel *top = NULL; - if (w->kind == DECORATED) top = libdecor_frame_get_xdg_toplevel(w->frame); - else if (w->kind == UNFRAMED) top = w->xdg_toplevel; - return top; -} - - -void Fl_Wayland_Window_Driver::take_focus() -{ - struct wld_window *w = fl_wl_xid(pWindow); - if (w) { - Fl_Window *old_first = Fl::first_window(); - struct wld_window *first_xid = (old_first ? fl_wl_xid(old_first->top_window()) : NULL); - if (first_xid && first_xid != w && xdg_toplevel()) { - // this will move the target window to the front - Fl_Wayland_Window_Driver *top_dr = - Fl_Wayland_Window_Driver::driver(old_first->top_window()); - xdg_toplevel_set_parent(xdg_toplevel(), top_dr->xdg_toplevel()); - // this will remove the parent-child relationship - xdg_toplevel_set_parent(xdg_toplevel(), NULL); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } - // this sets the first window - fl_wl_find(w); - } -} - - -void Fl_Wayland_Window_Driver::flush_overlay() -{ - if (!shown()) return; - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - int erase_overlay = (pWindow->damage()&FL_DAMAGE_OVERLAY) | (overlay() == oWindow); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - pWindow->make_current(); - if (!other_xid) { - other_xid = new Fl_Image_Surface(oWindow->w(), oWindow->h(), 1); - oWindow->clear_damage(FL_DAMAGE_ALL); - } - if (oWindow->damage() & ~FL_DAMAGE_EXPOSE) { - Fl_X *myi = Fl_X::flx(pWindow); - fl_clip_region(myi->region); myi->region = 0; - Fl_Surface_Device::push_current(other_xid); - draw(); - Fl_Surface_Device::pop_current(); - } - if (erase_overlay) fl_clip_region(0); - if (other_xid) { - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer = - Fl_Wayland_Graphics_Driver::offscreen_buffer(other_xid->offscreen()); - struct wld_window *xid = fl_wl_xid(pWindow); - struct Fl_Wayland_Graphics_Driver::wld_buffer *wbuffer = xid->buffer; - if (wbuffer->draw_buffer.data_size != buffer->data_size) { - fl_copy_offscreen(0, 0, oWindow->w(), oWindow->h(), other_xid->offscreen(), 0, 0); - } else { - memcpy(wbuffer->draw_buffer.buffer, buffer->buffer, wbuffer->draw_buffer.data_size); - } - } - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -const Fl_Image* Fl_Wayland_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - - -void Fl_Wayland_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::bitmap_to_pattern( - (Fl_Bitmap*)b, true, NULL); - shape_data_->shape_ = b; - shape_data_->lw_ = b->data_w(); - shape_data_->lh_ = b->data_h(); -} - - -void Fl_Wayland_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, j, d = img->d(), w = img->data_w(), h = img->data_h(); - int bytesperrow = cairo_format_stride_for_width(CAIRO_FORMAT_A1, w); - unsigned u; - uchar byte, onebit; - // build a CAIRO_FORMAT_A1 surface covering the non-fully transparent/black part of the image - uchar* bits = new uchar[h*bytesperrow]; // to store the surface data - const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of pixels - for (i = 0; i < h; i++) { - uchar *p = (uchar*)bits + i * bytesperrow; - byte = 0; - onebit = 1; - for (j = 0; j < w; j++) { - if (d == 3) { - u = *alpha; - u += *(alpha+1); - u += *(alpha+2); - } - else u = *alpha; - if (u > 0) { // if the pixel is not fully transparent/black - byte |= onebit; // turn on the corresponding bit of the bitmap - } - onebit = onebit << 1; // move the single set bit one position to the left - if (onebit == 0 || j == w-1) { - onebit = 1; - *p++ = ~byte; // store in bitmap one pack of bits, complemented - byte = 0; - } - alpha += d; // point to alpha value of next img pixel - } - } - cairo_surface_t *mask_surf = cairo_image_surface_create_for_data(bits, CAIRO_FORMAT_A1, - w, h, bytesperrow); - shape_data_->mask_pattern_ = cairo_pattern_create_for_surface(mask_surf); - cairo_surface_destroy(mask_surf); - shape_data_->shape_ = img; - shape_data_->lw_ = w; - shape_data_->lh_ = h; -} - - -void Fl_Wayland_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->mask_pattern_) { - cairo_surface_t *surface; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface); - uchar *data = cairo_image_surface_get_data(surface); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] data; - } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - pWindow->border(false); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); -} - - -void Fl_Wayland_Window_Driver::draw_end() -{ - if (shape_data_ && shape_data_->mask_pattern_) { - Fl_Wayland_Graphics_Driver *gr_dr = (Fl_Wayland_Graphics_Driver*)fl_graphics_driver; - cairo_t *cr = gr_dr->cr(); - cairo_matrix_t matrix; - cairo_matrix_init_scale(&matrix, double(shape_data_->lw_) / (pWindow->w() + 1), - double(shape_data_->lh_) / (pWindow->h() + 1) ); - cairo_matrix_translate(&matrix, 1, 1); - cairo_pattern_set_matrix(shape_data_->mask_pattern_, &matrix); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_mask(cr, shape_data_->mask_pattern_); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - } -} - - -/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders - (or NULL if a particular border is absent). - Returned images can be deleted after use. Their depth and size may be platform-dependent. - The top and bottom images extend from left of the left border to right of the right border. - */ -void Fl_Wayland_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, - Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) -{ - top = left = bottom = right = NULL; - if (pWindow->decorated_h() == h()) return; - int htop = pWindow->decorated_h() - pWindow->h(); - struct wld_window *wwin = fl_wl_xid(pWindow); - int width, height, stride; - uchar *cairo_data = fl_libdecor_titlebar_buffer(wwin->frame, &width, &height, &stride); - if (!cairo_data) return; - uchar *data = new uchar[width * height * 4]; - uchar *p = data; - for (int j = 0; j < height; j++) { - uchar *q = cairo_data + j * stride; - for (int i = 0; i < width; i++) { - *p++ = *(q+2); // R - *p++ = *(q+1); // G - *p++ = *q; // B - *p++ = *(q+3); // A - q += 4; - } - } - top = new Fl_RGB_Image(data, width, height, 4); - top->alloc_array = 1; - top->scale(pWindow->w(), htop); -} - - -// make drawing go into this window (called by subclass flush() impl.) -void Fl_Wayland_Window_Driver::make_current() { - if (!shown()) { - static const char err_message[] = "Fl_Window::make_current(), but window is not shown()."; - fl_alert(err_message); - Fl::fatal(err_message); - } - - struct wld_window *window = fl_wl_xid(pWindow); - if (window->buffer) { - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( - &window->buffer->draw_buffer_needs_commit); - } - - // to support progressive drawing - if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->frame_cb) && - (!wait_for_expose_value) ) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } - - Fl_Wayland_Window_Driver::wld_window = window; - fl_window = (Window)window; - float f = Fl::screen_scale(pWindow->screen_num()); - int wld_s = wld_scale(); - if (!window->buffer) { - window->buffer = Fl_Wayland_Graphics_Driver::create_wld_buffer( - int(pWindow->w() * f) * wld_s, int(pWindow->h() * f) * wld_s, false); - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( - &window->buffer->draw_buffer_needs_commit); - } - ((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_cairo( - window->buffer->draw_buffer.cairo_, f * wld_s); - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->wld_scale = wld_s; - int *poffset = Fl_Window_Driver::menu_offset_y(pWindow); - if (poffset) { // for tall menu windows under KWIN to offset drawing inside window - cairo_translate(window->buffer->draw_buffer.cairo_, 0, *poffset); - } - cairo_rectangle_int_t *extents = subRect(); - if (extents) { // make damage-to-buffer not to leak outside parent - Fl_Region clip_region = fl_graphics_driver->XRectangleRegion(extents->x, extents->y, - extents->width, extents->height); -//printf("make_current: %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - Fl_X::flx(pWindow)->region = clip_region; - } - else fl_graphics_driver->clip_region(0); - -#ifdef FLTK_HAVE_CAIROEXT - // update the cairo_t context - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -#endif -} - - -void Fl_Wayland_Window_Driver::flush() { - if (!pWindow->damage()) return; - if (pWindow->as_gl_window()) { - int W = pWindow->w(); - int H = pWindow->h(); - float scale = fl_graphics_driver->scale(); - Fl_Wayland_Window_Driver::in_flush_ = true; - Fl_Window_Driver::flush(); - Fl_Wayland_Window_Driver::in_flush_ = false; - gl_plugin()->do_swap(pWindow); // useful only for GL win with overlay - if (scale != fl_graphics_driver->scale() || W != pWindow->w() || H != pWindow->h()) { - gl_plugin()->invalidate(pWindow); - } - return; - } - struct wld_window *window = fl_wl_xid(pWindow); - if (!window || !window->configured_width) return; - - Fl_X *ip = Fl_X::flx(pWindow); - cairo_region_t* r = (cairo_region_t*)ip->region; - if (!window->buffer || pWindow->as_overlay_window()) r = NULL; - - Fl_Wayland_Window_Driver::in_flush_ = true; - Fl_Window_Driver::flush(); - Fl_Wayland_Window_Driver::in_flush_ = false; - if (!window->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(window, r); -} - - -void Fl_Wayland_Window_Driver::show() { - if (!shown()) { - fl_open_display(); - makeWindow(); - } else { - // Wayland itself gives no way to programmatically unminimize a minimized window - Fl::handle(FL_SHOW, pWindow); - } -} - - -static void popup_done(void *data, struct xdg_popup *xdg_popup); - - -static void destroy_surface_caution_pointer_focus(struct wl_surface *surface, - struct Fl_Wayland_Screen_Driver::seat *seat) { - if (seat->pointer_focus == surface) seat->pointer_focus = NULL; - if (seat->keyboard_surface == surface) seat->keyboard_surface = NULL; - wl_surface_destroy(surface); -} - - -void Fl_Wayland_Window_Driver::hide() { - if (pWindow == Fl_Screen_Driver::transient_scale_parent) { - // Delete also the running transient scale window - // because the transient is a popup and MUST be deleted - // before its parent. - Fl::remove_timeout(Fl_Screen_Driver::del_transient_window); - Fl_Screen_Driver::del_transient_window(NULL); - } - Fl_X* ip = Fl_X::flx(pWindow); - if (hide_common()) return; - if (ip->region) { - Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - ip->region = 0; - } - screen_num_ = -1; - struct wld_window *wld_win = (struct wld_window*)ip->xid; - if (wld_win) { // this test makes sure ip->xid has not been destroyed already - Fl_Wayland_Graphics_Driver::buffer_release(wld_win); - if (wld_win->kind == SUBWINDOW && wld_win->subsurface) { - wl_subsurface_destroy(wld_win->subsurface); - wld_win->subsurface = NULL; - } -#if HAVE_XDG_DIALOG - if (wld_win->xdg_dialog) { - xdg_dialog_v1_destroy(wld_win->xdg_dialog); - wld_win->xdg_dialog = NULL; - } -#endif - if (wld_win->kind == DECORATED) { - libdecor_frame_unref(wld_win->frame); - wld_win->frame = NULL; - wld_win->xdg_surface = NULL; - } else { - if (wld_win->kind == POPUP && wld_win->xdg_popup) { - popup_done(xdg_popup_get_user_data(wld_win->xdg_popup), wld_win->xdg_popup); - wld_win->xdg_popup = NULL; - } - if (wld_win->kind == UNFRAMED && wld_win->xdg_toplevel) { - xdg_toplevel_destroy(wld_win->xdg_toplevel); - wld_win->xdg_toplevel = NULL; - } - if (wld_win->xdg_surface) { - xdg_surface_destroy(wld_win->xdg_surface); - wld_win->xdg_surface = NULL; - } - } - if (wld_win->custom_cursor) delete_cursor(wld_win->custom_cursor); - if (wld_win->wl_surface) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - destroy_surface_caution_pointer_focus(wld_win->wl_surface, scr_driver->seat); - wld_win->wl_surface = NULL; - } - while (!wl_list_empty(&wld_win->outputs)) { // remove from screens where it belongs - struct surface_output *s_output; - s_output = wl_container_of(wld_win->outputs.next, s_output, link); - wl_list_remove(&s_output->link); - free(s_output); - } - if (Fl_Wayland_Window_Driver::wld_window == wld_win) { - Fl_Wayland_Window_Driver::wld_window = NULL; - } - if (wld_win->frame_cb) wl_callback_destroy(wld_win->frame_cb); // useful for GL subwins - free(wld_win); - } - delete ip; -} - - -void Fl_Wayland_Window_Driver::map() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == SUBWINDOW && !wl_win->subsurface) { - struct wld_window *parent = fl_wl_xid(pWindow->window()); - if (parent) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - wl_win->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor, - wl_win->wl_surface, parent->wl_surface); - float f = Fl::screen_scale(pWindow->top_window()->screen_num()); - wl_subsurface_set_position(wl_win->subsurface, pWindow->x() * f, pWindow->y() * f); - wl_subsurface_set_desync(wl_win->subsurface); // important - wl_subsurface_place_above(wl_win->subsurface, parent->wl_surface); - wl_win->configured_width = pWindow->w(); - wl_win->configured_height = pWindow->h(); - wait_for_expose_value = 0; - pWindow->redraw(); - } - } -} - - -void Fl_Wayland_Window_Driver::unmap() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == SUBWINDOW && wl_win->wl_surface) { - wl_surface_attach(wl_win->wl_surface, NULL, 0, 0); - Fl_Wayland_Graphics_Driver::buffer_release(wl_win); - wl_subsurface_destroy(wl_win->subsurface); - wl_win->subsurface = NULL; - } -} - - -void Fl_Wayland_Window_Driver::size_range() { - if (shown()) { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - float f = Fl::screen_scale(pWindow->screen_num()); - int minw, minh, maxw, maxh; - pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (wl_win->kind == DECORATED && wl_win->frame) { - int X,Y,W,H; - Fl::screen_work_area(X,Y,W,H, Fl::screen_num(x(),y(),w(),h())); - if (maxw && maxw < W && maxh && maxh < H) { - libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN); - } else { - libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN); - } - if (maxw && maxh && (minw >= maxw || minh >= maxh)) { - libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE); - } else { - libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE); - } - libdecor_frame_set_min_content_size(wl_win->frame, minw*f, minh*f); - libdecor_frame_set_max_content_size(wl_win->frame, maxw*f, maxh*f); - if (xdg_toplevel()) { - struct libdecor_state *state = libdecor_state_new(int(w() * f), int(h() * f)); - libdecor_frame_commit(wl_win->frame, state, NULL); - libdecor_state_free(state); - } - } else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) { - xdg_toplevel_set_min_size(wl_win->xdg_toplevel, minw*f, minh*f); - if (maxw && maxh) - xdg_toplevel_set_max_size(wl_win->xdg_toplevel, maxw*f, maxh*f); - } - } -} - - -void Fl_Wayland_Window_Driver::iconize() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == DECORATED) { - libdecor_frame_set_minimized(wl_win->frame); - if (xdg_toplevel_get_version(xdg_toplevel()) < 6) { - Fl::handle(FL_HIDE, pWindow); - } - } - else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) xdg_toplevel_set_minimized(wl_win->xdg_toplevel); -} - - -void Fl_Wayland_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) -{ - struct wld_window *xid = (struct wld_window*)fl_xid(pWindow); - if (xid && xid->kind == DECORATED) { - libdecor_frame_translate_coordinate(xid->frame, 0, 0, left, top); - *right = *left; - *bottom = 0; - } else { - Fl_Window_Driver::decoration_sizes(top, left, right, bottom); - } -} - - -int Fl_Wayland_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, - int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) -{ - struct wld_window * xid = fl_wl_xid(pWindow); - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = xid->buffer; - float s = wld_scale() * fl_graphics_driver->scale(); - if (s != 1) { - src_x = src_x * s; - src_y = src_y * s; - src_w = src_w * s; - src_h = src_h * s; - dest_x = dest_x * s; - dest_y = dest_y * s; - } - if (src_x == dest_x) { // vertical scroll - int i, to, step; - if (src_y > dest_y) { - i = 0; to = src_h; step = 1; - } else { - i = src_h - 1; to = -1; step = -1; - } - while (i != to) { - memcpy( - buffer->draw_buffer.buffer + (dest_y + i) * buffer->draw_buffer.stride + 4 * dest_x, - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x, - 4 * src_w); - i += step; - } - } else { // horizontal scroll - int i, to, step; - if (src_x > dest_x) { - i = 0; to = src_h; step = 1; - } else { - i = src_h - 1; to = -1; step = -1; - } - while (i != to) { - memmove( - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * dest_x, - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x, - 4 * src_w); - i += step; - } - } - return 0; -} - - -static void handle_error(struct libdecor *libdecor_context, enum libdecor_error error, const char *message) -{ - Fl::fatal("Caught error (%d): %s\n", error, message); -} - - -static struct libdecor_interface libdecor_iface = { - .error = handle_error, -}; - - - -static void delayed_rescale(Fl_Window *win) { - Fl_Window_Driver::driver(win)->is_a_rescale(true); - win->size(win->w(), win->h()); - Fl_Window_Driver::driver(win)->is_a_rescale(false); -} - - -void change_scale(Fl_Wayland_Screen_Driver::output *output, struct wld_window *window, - float pre_scale) { - Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - if (!window->fl_win->parent()) { - // for top-level, set its screen number when the 1st screen for this surface changes - Fl_Wayland_Screen_Driver::output *running_output; - Fl_Wayland_Screen_Driver *scr_dr = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - int i = 0; - wl_list_for_each(running_output, &scr_dr->outputs, link) { // each screen of the system - if (running_output == output) { // we've found our screen of the system - win_driver->screen_num(i); - break; - } - i++; - } - } - float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; -//printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); - if (post_scale != pre_scale) { - if (window->kind == Fl_Wayland_Window_Driver::POPUP) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - window->fl_win->redraw(); - } else { - // delaying the rescaling is necessary to set first the window's size_range according to the new screen - Fl::add_timeout(0, (Fl_Timeout_Handler)delayed_rescale, window->fl_win); - } - } -} - - -static void surface_enter(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - struct wld_window *window = (struct wld_window*)data; - - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - if (output == NULL) - return; - - bool list_was_empty = wl_list_empty(&window->outputs); - struct Fl_Wayland_Window_Driver::surface_output *surface_output = - (struct Fl_Wayland_Window_Driver::surface_output*)malloc( - sizeof(struct Fl_Wayland_Window_Driver::surface_output)); - surface_output->output = output; - // add to end of the linked list of displays of this surface - struct wl_list *e = &window->outputs; - while (e->next != &window->outputs) e = e->next; // move e to end of linked list - wl_list_insert(e, &surface_output->link); -//printf("window %p enters screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs)); - if (list_was_empty && !window->fl_win->parent()) { - change_scale(output, window, 0); - } -} - - -static void surface_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - struct wld_window *window = (struct wld_window*)data; - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale(); - struct Fl_Wayland_Window_Driver::surface_output *s_output; - int count = 0; - wl_list_for_each(s_output, &window->outputs, link) { - count++; - if (s_output->output == output) { - wl_list_remove(&s_output->link); - free(s_output); -//printf("window %p leaves screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs)); - break; - } - } - if (count == 1 && !wl_list_empty(&window->outputs) && !window->fl_win->parent()) { - s_output = wl_container_of(window->outputs.next, s_output, link); - change_scale(s_output->output, window, pre_scale); - } -} - - -static struct wl_surface_listener surface_listener = { - surface_enter, - surface_leave, -}; - - -Fl_Window *Fl_Wayland_Window_Driver::surface_to_window(struct wl_surface *surface) { - if (surface) { - if (wl_proxy_get_listener((struct wl_proxy *)surface) == &surface_listener) { - return ((struct wld_window *)wl_surface_get_user_data(surface))->fl_win; - } - } - return NULL; -} - - -static struct Fl_Wayland_Screen_Driver::output *screen_num_to_output(int num_screen) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - int i = 0; - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens of the system - if (i++ == num_screen) return output; - } - return NULL; -} - - -#define LIBDECOR_MR131 1 // this means libdecor does not include MR!131 yet - -#ifdef LIBDECOR_MR131 -/* === Beginning of hack that would become un-needed if libdecor accepted MR!131 === */ - -// true while the GUI is interactively resizing a decorated window -static bool in_decorated_window_resizing = false; - - -// libdecor's configure cb function for xdg_toplevel objects -static void (*decor_xdg_toplevel_configure)(void*, struct xdg_toplevel *, int32_t, - int32_t, struct wl_array *); - - -static void fltk_xdg_toplevel_configure(void *user_data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, - struct wl_array *states) { - uint32_t *p; - in_decorated_window_resizing = false; - // Replace wl_array_for_each(p, states) rejected by C++ - for (p = (uint32_t *)(states)->data; - (const char *) p < ((const char *) (states)->data + (states)->size); - (p)++) { - if (*p == XDG_TOPLEVEL_STATE_RESIZING) { - in_decorated_window_resizing = true; - break; - } - } - decor_xdg_toplevel_configure(user_data, xdg_toplevel, width, height, states); -} - - -struct wl_object { // copied from wayland-private.h - const struct wl_interface *interface; - const void *implementation; - uint32_t id; -}; - - -// replace libdecor's toplevel configure cb by FLTK's -static void use_FLTK_toplevel_configure_cb(struct libdecor_frame *frame) { - struct wl_object *object = (struct wl_object *)libdecor_frame_get_xdg_toplevel(frame); - static struct xdg_toplevel_listener *fltk_listener = NULL; - if (!fltk_listener) { - struct xdg_toplevel_listener *decor_listener = (struct xdg_toplevel_listener*) - object->implementation; - fltk_listener = (struct xdg_toplevel_listener*) - malloc(sizeof(struct xdg_toplevel_listener)); - // initialize FLTK's listener with libdecor's values - *fltk_listener = *decor_listener; - // memorize libdecor's toplevel configure cb - decor_xdg_toplevel_configure = decor_listener->configure; - // replace libdecor's toplevel configure cb by FLTK's - fltk_listener->configure = fltk_xdg_toplevel_configure; - } - // replace the toplevel listener by a copy whose configure member is FLTK's - object->implementation = fltk_listener; -} - -/* === End of hack that would become un-needed if libdecor accepted MR!131 === */ -#endif // LIBDECOR_MR131 - - -// does win entirely cover its parent ? -static void does_window_cover_parent(Fl_Window *win) { - Fl_Window *parent = win->window(); - fl_wl_xid(parent)->covered = (win->x() <= 0 && win->y() <= 0 && - win->w() >= parent->w() && win->h() >= parent->h()); -} - - -// recursively explore all shown subwindows in a window and call f for each -static void scan_subwindows(Fl_Group *g, void (*f)(Fl_Window *)) { - for (int i = 0; i < g->children(); i++) { - Fl_Widget *o = g->child(i); - if (o->as_window()) { - if (!o->as_window()->shown()) continue; - f(o->as_window()); - } - if (o->as_group()) scan_subwindows(o->as_group(), f); - } -} - -// Generate FL_APP_ACTIVATE and FL_APP_DEACTIVATE events -static bool app_has_active_window = false; - -// If a window is deactivated, check after a short delay if any other window has -// become active. If not, send an FL_APP_DEACTIVATE event. -static void deferred_check_app_deactivate(void*) { - if (!app_has_active_window) return; - app_has_active_window = false; - // Check all FLTK windows to see if any are still active - for (Fl_Window *w = Fl::first_window(); w; w = Fl::next_window(w)) { - if (w->visible_r()) { - struct wld_window* xid = fl_wl_xid(w); - if (xid && (xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - app_has_active_window = true; - break; - } - } - } - if (!app_has_active_window) Fl::handle(FL_APP_DEACTIVATE, nullptr); -} - -static void handle_configure(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, void *user_data) -{ - struct wld_window *window = (struct wld_window*)user_data; - if (!window->wl_surface) return; - int width, height; - enum libdecor_window_state window_state; - struct libdecor_state *state; - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - // true exactly for the 1st run of handle_configure() for this window - bool is_1st_run = (window->xdg_surface == 0); - // true exactly for the 2nd run of handle_configure() for this window - bool is_2nd_run = (window->xdg_surface != 0 && driver->wait_for_expose_value); - float f = Fl::screen_scale(window->fl_win->screen_num()); - - if (!window->xdg_surface) window->xdg_surface = libdecor_frame_get_xdg_surface(frame); - -#ifdef LIBDECOR_MR131 - if (is_1st_run) use_FLTK_toplevel_configure_cb(frame); -#endif - struct wl_output *wl_output = NULL; - if (window->fl_win->fullscreen_active()) { - if (!(window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN)) { - if (Fl_Window_Driver::driver(window->fl_win)->force_position()) { - struct Fl_Wayland_Screen_Driver::output *output = - screen_num_to_output(window->fl_win->screen_num()); - if (output) wl_output = output->wl_output; - } - libdecor_frame_set_fullscreen(window->frame, wl_output); - } - } else if (driver->show_iconic()) { - libdecor_frame_set_minimized(window->frame); - driver->show_iconic(0); - } - if (!libdecor_configuration_get_window_state(configuration, &window_state)) - window_state = LIBDECOR_WINDOW_STATE_NONE; - if ((window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) && - !(window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) && !window->fl_win->border()) { - // necessary so Mutter correctly positions borderless window back from fullscreen - window->fl_win->redraw(); - } - window->state = window_state; - - // Weston, KWin, and some old versions of Mutter, on purpose, don't set the - // window width x height when xdg_toplevel_configure runs twice - // during resizable window creation - // (see https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/6). - // Consequently, libdecor_configuration_get_content_size() may return false twice. - // Weston and KWin, at least, don't change the window size asked by the client application - // which is available here in floating_{width,height}. - if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) { - if (is_2nd_run) { - width = window->floating_width; - height = window->floating_height; - if (!driver->is_resizable()) { - libdecor_frame_set_min_content_size(frame, width, height); - libdecor_frame_set_max_content_size(frame, width, height); - } - } else { width = height = 0; } - } - if (is_2nd_run && Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER) { - scan_subwindows(window->fl_win, does_window_cover_parent); // issue #878 - } - - if (window->fl_win->fullscreen_active() && - Fl_Window_Driver::driver(window->fl_win)->force_position()) { - int X, Y, W, H; - Fl::screen_xywh(X, Y, W, H, window->fl_win->screen_num()); - width = W * f; height = H * f; - } - - if (width == 0) { - width = window->floating_width; - height = window->floating_height; - //fprintf(stderr,"handle_configure: using floating %dx%d\n",width,height); - } - -#ifndef LIBDECOR_MR131 - bool in_decorated_window_resizing = (window->state & LIBDECOR_WINDOW_STATE_RESIZING); -#endif - bool condition = in_decorated_window_resizing; - if (condition) { // see issue #878 - condition = (window->covered ? (window->buffer && window->buffer->in_use) : (window->frame_cb != NULL)); - } - if (condition) { - // Skip resizing & redrawing. The last resize request won't be skipped because - // LIBDECOR_WINDOW_STATE_RESIZING will be off or cb will be NULL then. - return; - } - - driver->in_handle_configure = true; - window->fl_win->resize(0, 0, ceil(width / f), ceil(height / f)); - driver->in_handle_configure = false; - if (wl_output) window->fl_win->redraw(); - window->configured_width = ceil(width / f); - window->configured_height = ceil(height / f); - if (is_2nd_run) driver->wait_for_expose_value = 0; -//fprintf(stderr, "handle_configure fl_win=%p size:%dx%d state=%x wait_for_expose_value=%d is_2nd_run=%d\n", window->fl_win, width,height,window_state,driver->wait_for_expose_value, is_2nd_run); - - // When no window is active, and one window gets activated, generate an FL_APP_ACTIVATE event - if (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) { - if (!app_has_active_window) { - app_has_active_window = true; - Fl::handle(FL_APP_ACTIVATE, nullptr); - } - - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON) { - // After click on titlebar, weston calls wl_keyboard_enter() for a - // titlebar-related surface that FLTK can't identify, so we send FL_FOCUS here. - Fl::handle(FL_FOCUS, window->fl_win); - } - if (!window->fl_win->border()) libdecor_frame_set_visibility(window->frame, false); - else if (!libdecor_frame_is_visible(window->frame)) { - libdecor_frame_set_visibility(window->frame, true); - } else if (!window->fl_win->visible()) { - Fl::handle(FL_SHOW, window->fl_win); // useful when un-minimizing - } - } else if (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) { // window is minimized - Fl::handle(FL_HIDE, window->fl_win); - } - - // When a window gets deactivated and there are no other active windows, - // generate an FL_APP_DEACTIVATE event - if ( ((window_state & LIBDECOR_WINDOW_STATE_ACTIVE) == 0) && app_has_active_window) { - Fl::add_timeout(0.1, deferred_check_app_deactivate, nullptr); - } - - if (window->fl_win->border()) - driver->is_maximized(window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED); - if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) state = libdecor_state_new(width, - height); - else state = libdecor_state_new(int(ceil(width/f)*f), int(ceil(height/f)*f)); - libdecor_frame_commit(frame, state, configuration); - if (libdecor_frame_is_floating(frame)) { // store floating dimensions - window->floating_width = int(ceil(width/f)*f); - window->floating_height = int(ceil(height/f)*f); - //fprintf(stderr,"set floating_width+height %dx%d\n",width,height); - } - libdecor_state_free(state); - - driver->flush(); - if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::WESTON || !is_1st_run) { - window->fl_win->clear_damage(); - } -} - - -void Fl_Wayland_Window_Driver::wait_for_expose() -{ - Fl_Window_Driver::wait_for_expose(); - struct wld_window * xid = fl_wl_xid(pWindow); - if (!xid) return; - if (pWindow->fullscreen_active()) { - if (xid->kind == DECORATED) { - while (!(xid->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) || - !(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - } else if (xid->kind == UNFRAMED) { - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } - } else if (xid->kind == DECORATED) { - // necessary for the windowfocus demo program with recent Wayland versions - if (!(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - } -} - - -static void delayed_close(Fl_Window *win) { - Fl::remove_check((Fl_Timeout_Handler)delayed_close, win); - Fl::handle(FL_CLOSE, win); -} - - -static void handle_close(struct libdecor_frame *frame, void *user_data) -{ // runs when the close button of a window titlebar is pushed - // or after "Quit" of the application menu - // or after the Kill command of Sway - Fl_Window* win = ((struct wld_window*)user_data)->fl_win; - int X, Y; - libdecor_frame_translate_coordinate(frame, 0, 0, &X, &Y); - if (Y == 0) Fl::handle(FL_CLOSE, win); - else { - // the close window attempt is delayed because libdecor - // uses the frame after return from this function - Fl::add_check((Fl_Timeout_Handler)delayed_close, win); - } -} - - -static void handle_commit(struct libdecor_frame *frame, void *user_data) -{ - struct wld_window* wl_win = (struct wld_window*)user_data; - if (wl_win->wl_surface) wl_surface_commit(wl_win->wl_surface); -} - - -static void handle_dismiss_popup(struct libdecor_frame *frame, const char *seat_name, void *user_data) -{ -} - - -static struct libdecor_frame_interface libdecor_frame_iface = { - handle_configure, - handle_close, - handle_commit, - handle_dismiss_popup, -}; - - -static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) -{ - // runs for borderless windows and popup (menu,tooltip) windows - struct wld_window *window = (struct wld_window*)data; - xdg_surface_ack_configure(xdg_surface, serial); -//fprintf(stderr, "xdg_surface_configure: surface=%p\n", window->wl_surface); - - if (window->fl_win->w() != window->configured_width || - window->fl_win->h() != window->configured_height) { - if (window->buffer) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - } - } - window->configured_width = window->fl_win->w(); - window->configured_height = window->fl_win->h(); - Fl_Window_Driver::driver(window->fl_win)->flush(); - window->fl_win->clear_damage(); -} - - -static const struct xdg_surface_listener xdg_surface_listener = { - .configure = xdg_surface_configure, -}; - - -static bool parse_states_fullscreen(struct wl_array *states) -{ - uint32_t *p; - // Replace wl_array_for_each(p, states) rejected by C++ - for (p = (uint32_t *)(states)->data; - (const char *) p < ((const char *) (states)->data + (states)->size); - (p)++) { - if (*p == XDG_TOPLEVEL_STATE_FULLSCREEN) return true; - } - return false; -} - - -static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - // runs for borderless top-level windows - // under Weston: width & height are 0 during both calls, except if fullscreen - struct wld_window *window = (struct wld_window*)data; -//fprintf(stderr, "xdg_toplevel_configure: surface=%p size: %dx%d\n", window->wl_surface, width, height); - if (window->fl_win->fullscreen_active() && !parse_states_fullscreen(states)) { - struct wl_output *wl_output = NULL; - if (Fl_Window_Driver::driver(window->fl_win)->force_position()) { - struct Fl_Wayland_Screen_Driver::output *output = - screen_num_to_output(window->fl_win->screen_num()); - if (output) wl_output = output->wl_output; - } - xdg_toplevel_set_fullscreen(xdg_toplevel, wl_output); - if (wl_output) { - int X, Y; - Fl::screen_xywh(X, Y, width, height, window->fl_win->screen_num()); - } - } - if (window->configured_width) { - Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0; - } - float f = Fl::screen_scale(window->fl_win->screen_num()); - if (width == 0 || height == 0) { - width = window->fl_win->w() * f; - height = window->fl_win->h() * f; - } - window->fl_win->size(ceil(width / f), ceil(height / f)); - if (window->buffer && (ceil(width / f) != window->configured_width || - ceil(height / f) != window->configured_height)) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - } - window->configured_width = ceil(width / f); - window->configured_height = ceil(height / f); -} - - -static void xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel) -{ -} - - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure, - .close = xdg_toplevel_close, -}; - - -struct win_positioner { - struct wld_window *window; - int x, y; - Fl_Window *child_popup; -}; - - -static void popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, - int32_t width, int32_t height) { - struct win_positioner *win_pos = (struct win_positioner *)data; - struct wld_window *window = win_pos->window; -//printf("popup_configure %p asked:%dx%d got:%dx%d\n",window->fl_win, win_pos->x,win_pos->y, x,y); - Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0; - int HH; - Fl_Window_Driver::menu_parent(&HH); - if (window->fl_win->h() > HH && y != win_pos->y) { // A menu taller than the display - // Under KWin, height is set to the display height or less: we ignore that. - window->state = (y - win_pos->y); - // make selected item visible, if there's one - Fl_Window_Driver::scroll_to_selected_item(window->fl_win); - } - if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(window->fl_win)) { - int X, Y; - Fl_Window_Driver::current_menu_button->top_window_offset(X, Y); - if (y < Y) { - Fl_Window *win = window->fl_win; - win->Fl_Widget::resize(win->x(), Y - win->h(), win->w(), win->h()); - } - } -} - - -static struct xdg_popup *mem_grabbing_popup = NULL; - - -static void popup_done(void *data, struct xdg_popup *xdg_popup) { - struct win_positioner *win_pos = (struct win_positioner *)data; - struct wld_window *window = win_pos->window; -//fprintf(stderr, "popup_done: popup=%p data=%p xid=%p fl_win=%p\n", xdg_popup, data, window, window->fl_win); - if (win_pos->child_popup) win_pos->child_popup->hide(); - xdg_popup_destroy(xdg_popup); - delete win_pos; - // The sway compositor calls popup_done directly and hides the menu - // when the app looses focus. - // Thus, we hide the window so FLTK and Wayland are in matching states. - window->xdg_popup = NULL; - window->fl_win->hide(); - if (mem_grabbing_popup == xdg_popup) { - mem_grabbing_popup = NULL; - } -} - - -static const struct xdg_popup_listener popup_listener = { - .configure = popup_configure, - .popup_done = popup_done, -}; - - -bool Fl_Wayland_Window_Driver::in_flush_ = false; - - -static const char *get_prog_name() { - pid_t pid = getpid(); - char fname[100]; - snprintf(fname, 100, "/proc/%u/cmdline", pid); - FILE *in = fopen(fname, "r"); - if (in) { - static char line[200]; - const char *p = fgets(line, sizeof(line), in); - fclose(in); - p = strrchr(line, '/'); if (!p) p = line; else p++; - return p; - } - return "unknown"; -} - - -/* Implementation note about menu windows under Wayland. - Wayland offers a way to position popup windows such as menu windows using constraints. - Each popup is located relatively to a parent window which can be a popup itself and - MUST overlap or at least touch this parent. - Constraints determine how a popup is positioned relatively to a defined area (called - the anchor rectangle) of its parent popup/window and what happens when this position - would place the popup all or partly outside the display. - In contrast, FLTK computes the adequate positions of menu windows in the display using - knowledge about the display size and the location of the window in the display, and then - maps them at these positions. - These 2 logics are quite different because Wayland hides the position of windows inside the - display, whereas FLTK uses the location of windows inside the display to position popups. - Let's call "source window" the non-popup window above which all popups are mapped. - The approach implemented here is two-fold. - 1) If a menu window is not taller than the display, use Wayland constraints to position it. - Wayland imposes that the first constructed popup must overlap or touch the source window. - Other popups can be placed below, above, at right, or at left of a previous popup which - allows them to expand outside the source window, while constraints can ensure they won't - extend outside the display. - 2) A menu window taller than the display is initially mapped with the constraint to - begin at the top border of the display. This allows FLTK to know the distance between - the source window and the display top. FLTK can later reposition the same tall popup, - without the constraint not to go beyond the display top, at the exact position so that - the desired series of menu items appear in the visible part of the tall popup. - - In case 1) above, the values that represent the display bounds are given very - large values. That's done by member function Fl_Wayland_Window_Driver::menu_window_area(). - Consequently, FLTK computes an initial layout of future popups relatively to - the source window as if it was mapped on an infinitely large display. Then, the location - of the first popup to be mapped is modified if necessary so it overlaps or touches the - source window. Finally, other popups are located using Wayland logic below, above or to the - right of previous popups. Wayland constraints mechanism also allows a popup tentatively - placed below a previous one to be flipped above it if that prevents the popup from expanding - beyond display limits. This is used to unfold menu bar menus below or above the menu bar. - After each popup is created and scheduled for being mapped on display by function - process_menu_or_tooltip(), makeWindow() calls Fl_Window::wait_for_expose() so its constrained - position is known before computing the position of the next popup. This ensures each - popup is correctly placed relatively to its parent. - - Groups of popups containing a menutitle, the associated menuwindow, and optionally - a submenu window and that don't belong to an Fl_Menu_Bar are mapped in a different order: - the menuwindow is mapped first, and the menutitle is mapped second above it as a child popup. - Fl_Window_Driver::is_floating_title() detects when such a menutitle is created, - static member variable previous_floatingtitle is assigned the value of this menutitle, and - the menutitle is mapped only after the menuwindow has been mapped, as a child of it. - This positions better the popup group in the display relatively to where the popup - was created. - - In case 2) above, a tall popup is mapped with XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y - which puts its top at the display top border. The Wayland system then calls the - popup_configure() callback function with the x,y coordinates of the top left corner - where the popup is mapped relatively to an anchor point in the source window. - The difference between the asked window position and the effective position is stored - in the state member variable of the tall popup's struct wld_window. This information - allows FLTK to compute the distance between the source window top and the display top border. - Function Fl_Wayland_Window_Driver::menu_window_area() sets the top of the display to - a value such that function Fl_Wayland_Window_Driver::reposition_menu_window(), called by - menuwindow::autoscroll(int n), ensures that menu item #n is visible. Static boolean member - variable Fl_Wayland_Window_Driver::new_popup is useful to position tall menuwindows created - by an Fl_Menu_Button or Fl_Choice. It is set to true when any menu popup is created. - It is used each time menu_window_area() runs for a particular Fl_Menu_Button or Fl_Choice, - and is reset to false after its first use. This allows menu_window_area() to give the top of - the display an adequate value the first time and to keep this value next times it runs. - Fl_Window_Driver::scroll_to_selected_item() scrolls the tall popup so its selected - item, when there's one, is visible immediately after the tall popup is mapped on display. - */ - - -bool Fl_Wayland_Window_Driver::process_menu_or_tooltip(struct wld_window *new_window) { - // a menu window or tooltip - new_window->kind = Fl_Wayland_Window_Driver::POPUP; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (Fl_Window_Driver::is_floating_title(pWindow)) { - previous_floatingtitle = pWindow; - return true; - } - new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, - new_window->wl_surface); - xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window); - Fl_Wayland_Window_Driver::new_popup = true; - Fl_Window *menu_origin = NULL; - if (pWindow->menu_window()) { - menu_origin = Fl_Window_Driver::menu_leftorigin(pWindow); - if (!menu_origin && !previous_floatingtitle) menu_origin = - Fl_Window_Driver::menu_title(pWindow); - } - Fl_Widget *target = (pWindow->tooltip_window() ? Fl_Tooltip::current() : NULL); - if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display && - Fl_Screen_Driver::transient_scale_parent) { - target = Fl_Screen_Driver::transient_scale_parent; - } - if (!target) target = Fl_Window_Driver::menu_parent(); - if (!target) target = Fl::belowmouse(); - if (!target) target = Fl::first_window(); - Fl_Window *parent_win = target->top_window(); - while (parent_win && parent_win->menu_window() && driver(parent_win)->popup_window()) { - parent_win = Fl::next_window(parent_win); - } - Fl_Window *origin_win = (menu_origin ? menu_origin : parent_win); - struct wld_window * parent_xid = fl_wl_xid(origin_win); - struct xdg_surface *parent_xdg = parent_xid->xdg_surface; - float f = Fl::screen_scale(parent_win->screen_num()); - //fprintf(stderr, "menu parent_win=%p pos:%dx%d size:%dx%d\n", parent_win, pWindow->x(), pWindow->y(), pWindow->w(), pWindow->h()); -//printf("window=%p menutitle=%p bartitle=%d leftorigin=%p y=%d\n", pWindow, Fl_Window_Driver::menu_title(pWindow), Fl_Window_Driver::menu_bartitle(pWindow), Fl_Window_Driver::menu_leftorigin(pWindow), pWindow->y()); - struct xdg_positioner *positioner = xdg_wm_base_create_positioner(scr_driver->xdg_wm_base); - //xdg_positioner_get_version(positioner) <== gives 1 under Debian and Sway - int popup_x, popup_y; - if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(pWindow)) { - int X, Y; - Fl_Window_Driver::current_menu_button->top_window_offset(X, Y); - xdg_positioner_set_anchor_rect(positioner, X * f, Y * f, - Fl_Window_Driver::current_menu_button->w() * f, - Fl_Window_Driver::current_menu_button->h() * f); - popup_x = X * f; - popup_y = 0; - if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active()) - libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y, - &popup_x, &popup_y); - } else if (Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow)) { - xdg_positioner_set_anchor_rect(positioner, 0, 0, - Fl_Window_Driver::menu_title(pWindow)->w() * f, - Fl_Window_Driver::menu_title(pWindow)->h() * f); - popup_x = 0; - popup_y = Fl_Window_Driver::menu_title(pWindow)->h() * f; - } else { - popup_x = pWindow->x() * f; popup_y = pWindow->y() * f; - if (popup_x + pWindow->w() * f < 0) popup_x = - pWindow->w() * f; - if (menu_origin) { - popup_x -= menu_origin->x() * f; - popup_y -= menu_origin->y() * f; - } - if (popup_x >= origin_win->w() * f) popup_x = origin_win->w() * f - 1; - if (!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_bartitle(pWindow) && - !Fl_Window_Driver::menu_leftorigin(pWindow)) { - // prevent first popup from going above the permissible source window - popup_y = fl_max(popup_y, - pWindow->h() * f); - } - if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active()) - libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y, - &popup_x, &popup_y); - xdg_positioner_set_anchor_rect(positioner, popup_x, 0, 1, 1); - popup_y++; - } - int positioner_H = pWindow->h(); - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::KWIN) { - // Under KWIN, limiting the height of the positioner to the work area height - // results in tall popup windows starting at the top of the screen, what we want. - // Unfortunately, we know the work area height exactly only for single-screen systems, - // otherwise FLTK returns work area height == screen height. In that case we estimate - // work area height ≈ screen height - 44. - int V, work_area_H, screen_H; - Fl::screen_work_area(V, V, V, work_area_H, origin_win->screen_num()); - Fl::screen_xywh(V, V, V, screen_H, origin_win->screen_num()); - if (work_area_H == screen_H) work_area_H -= 44; - if (positioner_H > work_area_H) positioner_H = work_area_H; - } - xdg_positioner_set_size(positioner, pWindow->w() * f , positioner_H * f ); - xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); - xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); - // prevent menuwindow from expanding beyond display limits - int constraint = 0; - int top_menubar = pWindow->y() - - (Fl_Window_Driver::menu_bartitle(pWindow) && Fl_Window_Driver::menu_title(pWindow) ? - Fl_Window_Driver::menu_title(pWindow)->h() : 0); - if ( !(parent_win->fullscreen_active() && - Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER && - ((!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) || - Fl_Window_Driver::menu_bartitle(pWindow)) && top_menubar < 10 && - !Fl_Window_Driver::current_menu_button) - ) { - // Condition above is only to bypass Mutter bug for fullscreen windows (see #1061) - constraint |= (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - if ((Fl_Window_Driver::current_menu_button || Fl_Window_Driver::menu_bartitle(pWindow)) && - !Fl_Window_Driver::menu_leftorigin(pWindow)) { - constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; - } - xdg_positioner_set_constraint_adjustment(positioner, constraint); - } - if (!(Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow))) { - xdg_positioner_set_offset(positioner, 0, popup_y); - } - new_window->xdg_popup = xdg_surface_get_popup(new_window->xdg_surface, - parent_xdg, positioner); - struct win_positioner *win_pos = new struct win_positioner; - win_pos->window = new_window; - win_pos->x = popup_x; - win_pos->y = popup_y; - win_pos->child_popup = NULL; -//printf("create xdg_popup=%p data=%p xid=%p fl_win=%p\n",new_window->xdg_popup,win_pos,new_window,new_window->fl_win); - xdg_positioner_destroy(positioner); - xdg_popup_add_listener(new_window->xdg_popup, &popup_listener, win_pos); - if (!mem_grabbing_popup) { - mem_grabbing_popup = new_window->xdg_popup; - //xdg_popup_grab(new_window->xdg_popup, scr_driver->get_wl_seat(), scr_driver->get_serial()); - //libdecor_frame_popup_grab(parent_xid->frame, scr_driver->get_seat_name()); - } - wl_surface_commit(new_window->wl_surface); - // put it on same screen as parent_win - this->screen_num(parent_win->screen_num()); - return false; -} - - -void Fl_Wayland_Window_Driver::makeWindow() -{ - Fl_Group::current(0); // get rid of very common user bug: forgot end() - struct wld_window *new_window; - bool is_floatingtitle = false; - wait_for_expose_value = 1; - - if (pWindow->parent() && !pWindow->window()) return; - if (pWindow->parent() && !pWindow->window()->shown()) return; - - if (!pWindow->parent() && !popup_window()) { - x(0); y(0); // toplevel, non-popup windows must have origin at 0,0 - } - new_window = (struct wld_window *)calloc(1, sizeof *new_window); - new_window->fl_win = pWindow; - wl_list_init(&new_window->outputs); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - - new_window->wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor); -//printf("makeWindow:%p %s %s\n", pWindow, pWindow->parent()?"SUB":"", pWindow->as_gl_window()?"GL":""); - wl_surface_add_listener(new_window->wl_surface, &surface_listener, new_window); - - if (!shape()) { // rectangular FLTK windows are opaque - struct wl_region *opaque = wl_compositor_create_region(scr_driver->wl_compositor); - wl_region_add(opaque, 0, 0, 1000000, 1000000); - wl_surface_set_opaque_region(new_window->wl_surface, opaque); - wl_region_destroy(opaque); - } - - if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display && - Fl::first_window()) { - // put transient scale win at center of top window by making it a tooltip of top - Fl_Screen_Driver::transient_scale_parent = Fl::first_window(); - pWindow->set_tooltip_window(); - set_popup_window(); - pWindow->position( - (Fl_Screen_Driver::transient_scale_parent->w() - pWindow->w())/2 , - (Fl_Screen_Driver::transient_scale_parent->h() - pWindow->h())/2); - } - - if (popup_window()) { // a menu window or tooltip - is_floatingtitle = process_menu_or_tooltip(new_window); - - } else if (pWindow->border() && !pWindow->parent() ) { // a decorated window - new_window->kind = DECORATED; - if (!scr_driver->libdecor_context) - scr_driver->libdecor_context = libdecor_new(Fl_Wayland_Screen_Driver::wl_display, - &libdecor_iface); - new_window->frame = libdecor_decorate(scr_driver->libdecor_context, new_window->wl_surface, - &libdecor_frame_iface, new_window); - // appears in the Gnome desktop menu bar - libdecor_frame_set_app_id(new_window->frame, get_prog_name()); - libdecor_frame_set_title(new_window->frame, pWindow->label()?pWindow->label():""); - if (!is_resizable()) { - libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_RESIZE); - libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_FULLSCREEN); - } - libdecor_frame_map(new_window->frame); - float f = Fl::screen_scale(pWindow->screen_num()); - new_window->floating_width = pWindow->w() * f; - new_window->floating_height = pWindow->h() * f; - - } else if (pWindow->parent()) { // for subwindows (GL or non-GL) - new_window->kind = SUBWINDOW; - struct wld_window *parent = fl_wl_xid(pWindow->window()); - new_window->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor, - new_window->wl_surface, - parent->wl_surface); -//fprintf(stderr, "makeWindow: subsurface=%p\n", new_window->subsurface); - float f = Fl::screen_scale(pWindow->top_window()->screen_num()); - wl_subsurface_set_position(new_window->subsurface, pWindow->x() * f, pWindow->y() * f); - wl_subsurface_set_desync(new_window->subsurface); // important - // Next 5 statements ensure the subsurface will be mapped because: - // "The effect of adding a sub-surface becomes visible on the next time - // the state of the parent surface is applied." - new_window->configured_width = pWindow->w(); - new_window->configured_height = pWindow->h(); - if (!pWindow->as_gl_window()) { - parent->fl_win->wait_for_expose(); - wl_surface_commit(parent->wl_surface); - } - wait_for_expose_value = 0; - pWindow->border(0); - checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent - - } else { // a window without decoration - new_window->kind = UNFRAMED; - new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, - new_window->wl_surface); -//fprintf(stderr, "makeWindow: xdg_wm_base_get_xdg_surface=%p\n", new_window->xdg_surface); - xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window); - new_window->xdg_toplevel = xdg_surface_get_toplevel(new_window->xdg_surface); - xdg_toplevel_add_listener(new_window->xdg_toplevel, &xdg_toplevel_listener, new_window); - if (pWindow->label()) xdg_toplevel_set_title(new_window->xdg_toplevel, pWindow->label()); - wl_surface_commit(new_window->wl_surface); - pWindow->border(0); - } - - Fl_Window *old_first = Fl::first_window(); - struct wld_window * first_xid = (old_first ? fl_wl_xid(old_first) : NULL); - Fl_X *xp = new Fl_X; - xp->xid = (fl_uintptr_t)new_window; - other_xid = 0; - xp->w = pWindow; - flx(xp); - xp->region = 0; - if (!pWindow->parent()) { - xp->next = Fl_X::first; - Fl_X::first = xp; - } else if (Fl_X::first) { - xp->next = Fl_X::first->next; - Fl_X::first->next = xp; - } else { - xp->next = NULL; - Fl_X::first = xp; - } - - if (pWindow->modal() || pWindow->non_modal()) { - if (pWindow->modal()) Fl::modal_ = pWindow; - if (new_window->kind == DECORATED && first_xid && first_xid->kind == DECORATED) { - if (first_xid->frame) libdecor_frame_set_parent(new_window->frame, first_xid->frame); - } else if (new_window->kind == UNFRAMED && new_window->xdg_toplevel && first_xid) { - Fl_Wayland_Window_Driver *top_dr = Fl_Wayland_Window_Driver::driver(first_xid->fl_win); - if (top_dr->xdg_toplevel()) xdg_toplevel_set_parent(new_window->xdg_toplevel, - top_dr->xdg_toplevel()); - } - if (new_window->kind == DECORATED || new_window->kind == UNFRAMED) { -#if HAVE_XDG_DIALOG - if (scr_driver->xdg_wm_dialog) { - new_window->xdg_dialog = xdg_wm_dialog_v1_get_xdg_dialog(scr_driver->xdg_wm_dialog, xdg_toplevel()); - if (pWindow->modal()) xdg_dialog_v1_set_modal(new_window->xdg_dialog); - } else -#endif - if (scr_driver->seat->gtk_shell && pWindow->modal()) { - // Useful to position modal windows above their parent with "gnome-shell --version" ≤ 45.2, - // useless but harmless with "gnome-shell --version" ≥ 46.0. - struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(scr_driver->seat->gtk_shell, - new_window->wl_surface); - gtk_surface1_set_modal(gtk_surface); - if (gtk_surface1_get_version(gtk_surface) >= GTK_SURFACE1_RELEASE_SINCE_VERSION) - gtk_surface1_release(gtk_surface); // very necessary - else - gtk_surface1_destroy(gtk_surface); - } - } - } - - size_range(); - pWindow->set_visible(); - int old_event = Fl::e_number; - pWindow->redraw(); - pWindow->handle(Fl::e_number = FL_SHOW); // get child windows to appear - Fl::e_number = old_event; - if (pWindow->menu_window() && popup_window() && !is_floatingtitle) { - // make sure each menu window is mapped with its constraints before mapping next popup - pWindow->wait_for_expose(); - if (previous_floatingtitle) { // a menuwindow with a menutitle - //puts("previous_floatingtitle"); - int HH; - Fl_Window_Driver::menu_parent(&HH); - if (pWindow->h() > HH) { - // a tall menuwindow with a menutitle: don't create the menutitle at all - // and undo what has been created/allocated before - struct wld_window *xid = fl_wl_xid(previous_floatingtitle); - destroy_surface_caution_pointer_focus(xid->wl_surface, scr_driver->seat); - free(xid); - Fl_Window_Driver::driver(previous_floatingtitle)->hide_common(); - previous_floatingtitle = NULL; - return; - } - // map the menutitle popup now as child of pWindow - struct wld_window *xid = fl_wl_xid(previous_floatingtitle); - xid->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, xid->wl_surface); - xdg_surface_add_listener(xid->xdg_surface, &xdg_surface_listener, xid); - struct xdg_positioner *positioner = - xdg_wm_base_create_positioner(scr_driver->xdg_wm_base); - xdg_positioner_set_anchor_rect(positioner, 0, 0, 1, 1); - int snum = Fl_Window_Driver::menu_parent()->screen_num(); - float f = Fl::screen_scale(snum); - // put it on same screen as parent menu - Fl_Window_Driver::driver(previous_floatingtitle)->screen_num(snum); - xdg_positioner_set_size(positioner, previous_floatingtitle->w() * f , - previous_floatingtitle->h() * f ); - xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); - xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_TOP_RIGHT); - xid->xdg_popup = xdg_surface_get_popup(xid->xdg_surface, new_window->xdg_surface, - positioner); - xdg_positioner_destroy(positioner); - struct win_positioner *win_pos = new struct win_positioner; - win_pos->window = xid; - win_pos->x = 0; - win_pos->y = 0; - win_pos->child_popup = NULL; - xdg_popup_add_listener(xid->xdg_popup, &popup_listener, win_pos); - wl_surface_commit(xid->wl_surface); - struct win_positioner *parent_win_pos = - (struct win_positioner*)xdg_popup_get_user_data(new_window->xdg_popup); - parent_win_pos->child_popup = previous_floatingtitle; - previous_floatingtitle = NULL; - } - } - if (pWindow->fullscreen_active()) Fl::handle(FL_FULLSCREEN, pWindow); -} - - -int Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor c) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_device) { - if (xid->custom_cursor) { - delete_cursor(xid->custom_cursor); - xid->custom_cursor = NULL; - } - if (c == FL_CURSOR_NONE) return 0; - standard_cursor_ = c; - Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, NULL, c); - return 1; - } -#endif // HAVE_CURSOR_SHAPE - if (!scr_driver->seat->cursor_theme) return 1; - // Cursor names are the files of directory /usr/share/icons/XXXX/cursors/ - // where XXXX is the name of the current 'cursor theme'. - static struct cursor_file_struct { - Fl_Cursor c; - const char *fname; - Fl_Wayland_Screen_Driver::cursor_shapes wld_c; - } cursor_file_array[] = { - {FL_CURSOR_ARROW, "left_ptr", Fl_Wayland_Screen_Driver::arrow }, - {FL_CURSOR_CROSS, "cross", Fl_Wayland_Screen_Driver::cross }, - {FL_CURSOR_WAIT, "watch", Fl_Wayland_Screen_Driver::wait }, - {FL_CURSOR_INSERT, "xterm", Fl_Wayland_Screen_Driver::insert }, - {FL_CURSOR_HAND, "hand1", Fl_Wayland_Screen_Driver::hand }, - {FL_CURSOR_HELP, "help", Fl_Wayland_Screen_Driver::help }, - {FL_CURSOR_MOVE, "move", Fl_Wayland_Screen_Driver::move }, - {FL_CURSOR_N, "top_side", Fl_Wayland_Screen_Driver::north }, - {FL_CURSOR_E, "right_side", Fl_Wayland_Screen_Driver::east }, - {FL_CURSOR_W, "left_side", Fl_Wayland_Screen_Driver::west }, - {FL_CURSOR_S, "bottom_side", Fl_Wayland_Screen_Driver::south }, - {FL_CURSOR_NS, "sb_v_double_arrow", Fl_Wayland_Screen_Driver::north_south }, - {FL_CURSOR_WE, "sb_h_double_arrow", Fl_Wayland_Screen_Driver::west_east }, - {FL_CURSOR_SW, "bottom_left_corner", Fl_Wayland_Screen_Driver::south_west }, - {FL_CURSOR_SE, "bottom_right_corner", Fl_Wayland_Screen_Driver::south_east }, - {FL_CURSOR_NE, "top_right_corner", Fl_Wayland_Screen_Driver::north_east }, - {FL_CURSOR_NW, "top_left_corner", Fl_Wayland_Screen_Driver::north_west }, - {FL_CURSOR_NESW, "fd_double_arrow", Fl_Wayland_Screen_Driver::nesw }, - {FL_CURSOR_NWSE, "bd_double_arrow", Fl_Wayland_Screen_Driver::nwse } - }; - - int found = -1; - for (unsigned i = 0; i < sizeof(cursor_file_array) / sizeof(struct cursor_file_struct); i++) { - if (cursor_file_array[i].c == c) { - found = cursor_file_array[i].wld_c; - if (!scr_driver->xc_cursor[found]) scr_driver->xc_cursor[found] = - scr_driver->cache_cursor(cursor_file_array[i].fname); - if (scr_driver->xc_cursor[found]) { - scr_driver->default_cursor(scr_driver->xc_cursor[found]); - } - break; - } - } - if (found < 0 || !scr_driver->xc_cursor[found]) return 0; - - if (xid->custom_cursor) { - delete_cursor(xid->custom_cursor); - xid->custom_cursor = NULL; - } - standard_cursor_ = c; - scr_driver->set_cursor(); - return 1; -} - - -void Fl_Wayland_Window_Driver::use_border() { - if (!shown() || pWindow->parent()) return; - pWindow->wait_for_expose(); // useful for border(0) just after show() - struct libdecor_frame *frame = fl_wl_xid(pWindow)->frame; - if (frame && Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::KWIN) { - if (fl_wl_xid(pWindow)->kind == DECORATED) { - libdecor_frame_set_visibility(frame, pWindow->border()); - } else { - pWindow->hide(); - pWindow->show(); - } - pWindow->redraw(); - } else { - Fl_Window_Driver::use_border(); - } -} - - -/* Change an existing window to fullscreen */ -void Fl_Wayland_Window_Driver::fullscreen_on() { - int top, bottom, left, right; - - top = fullscreen_screen_top(); - bottom = fullscreen_screen_bottom(); - left = fullscreen_screen_left(); - right = fullscreen_screen_right(); - - if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { - top = screen_num(); - bottom = top; - left = top; - right = top; - } - pWindow->wait_for_expose(); // make sure ->xdg_toplevel is initialized - if (xdg_toplevel()) { - xdg_toplevel_set_fullscreen(xdg_toplevel(), NULL); - pWindow->_set_fullscreen(); - Fl::handle(FL_FULLSCREEN, pWindow); - } -} - - -void Fl_Wayland_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { - pWindow->hide(); - pWindow->_clear_fullscreen(); - // avoid being called with W=H=0 in suboptimal scenario of #1299 - if (!W) W = w(); - if (!H) H = h(); - pWindow->resize(X, Y, W, H); - pWindow->show(); - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_Wayland_Window_Driver::label(const char *name, const char *iname) { - if (shown() && !parent() && fl_wl_xid(pWindow)->kind == DECORATED) { - if (!name) name = ""; - if (!iname) iname = fl_filename_name(name); - libdecor_frame_set_title(fl_wl_xid(pWindow)->frame, name); - } -} - - -int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int hoty) { - int retval = set_cursor_4args(rgb, hotx, hoty, true); - if (retval) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); - Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, xid->custom_cursor->wl_cursor); - } - return retval; -} - - -int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx, int hoty, - bool keep_copy) { - if (keep_copy) { - if (rgb->as_svg_image()) { - int scale = wld_scale(); - Fl_RGB_Image *svg = (Fl_RGB_Image*)rgb->copy(rgb->w() * scale, rgb->h() * scale); - svg->normalize(); - svg->scale(rgb->w(), rgb->h(), 0, 1); - rgb = svg; - } else { - int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); - uchar *data = new uchar[ld * rgb->data_h()]; - memcpy(data, rgb->array, ld * rgb->data_h()); - Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld()); - rgb2->alloc_array = 1; - rgb2->scale(rgb->w(), rgb->h(), 0, 1); - rgb = rgb2; - } - } -// build a new wl_cursor and its image - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); - struct wl_cursor *new_cursor = (struct wl_cursor*)malloc(sizeof(struct wl_cursor)); - struct cursor_image *new_image = (struct cursor_image*)calloc(1, - sizeof(struct cursor_image)); - int scale = wld_scale(); - new_image->image.width = rgb->w() * scale; - new_image->image.height = rgb->h() * scale; - new_image->image.hotspot_x = hotx * scale; - new_image->image.hotspot_y = hoty * scale; - new_image->image.delay = 0; - new_image->offset = 0; - //create a Wayland buffer and have it used as an image of the new cursor - struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen; - Fl_Image_Surface *img_surf = Fl_Wayland_Graphics_Driver::custom_offscreen( - new_image->image.width, new_image->image.height, &offscreen); - new_image->buffer = offscreen->wl_buffer; - wl_buffer_set_user_data(new_image->buffer, offscreen); - new_cursor->image_count = 1; - new_cursor->images = (struct wl_cursor_image**)malloc(sizeof(struct wl_cursor_image*)); - new_cursor->images[0] = (struct wl_cursor_image*)new_image; - new_cursor->name = strdup("custom cursor"); - // draw the rgb image to the cursor's drawing buffer - Fl_Surface_Device::push_current(img_surf); - Fl_Wayland_Graphics_Driver *driver = (Fl_Wayland_Graphics_Driver*)img_surf->driver(); - cairo_scale(driver->cr(), scale, scale); - ((Fl_RGB_Image*)rgb)->draw(0, 0); - Fl_Surface_Device::pop_current(); - delete img_surf; - memcpy(offscreen->data, offscreen->draw_buffer.buffer, offscreen->draw_buffer.data_size); - // delete the previous custom cursor, if there was one, - // and keep its Fl_RGB_Image if appropriate - if (xid->custom_cursor) delete_cursor(xid->custom_cursor, keep_copy); - //have this new cursor used - xid->custom_cursor = new custom_cursor; - xid->custom_cursor->wl_cursor = new_cursor; - xid->custom_cursor->rgb = rgb; - xid->custom_cursor->hotx = hotx; - xid->custom_cursor->hoty = hoty; - return 1; -} - - -void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) { - static int depth = 0; - struct wld_window *fl_win = fl_wl_xid(pWindow); - if (fl_win && fl_win->kind == DECORATED && !xdg_toplevel()) { - pWindow->wait_for_expose(); - } - int is_a_move = (X != x() || Y != y()); - bool true_rescale = Fl_Window::is_a_rescale(); - float f = fl_win ? Fl::screen_scale(pWindow->screen_num()) : 1; - if (fl_win && fl_win->buffer) { - int scale = wld_scale(); - int stride = cairo_format_stride_for_width( - Fl_Cairo_Graphics_Driver::cairo_format, int(W * f) * scale ); - size_t bsize = stride * int(H * f) * scale; - true_rescale = (bsize != fl_win->buffer->draw_buffer.data_size); - } - int is_a_resize = (W != w() || H != h() || true_rescale); - if (is_a_move) force_position(1); - else if (!is_a_resize && !is_a_move) return; - depth++; - if (shown() && !(parent() || popup_window())) { - X = Y = 0; - } - Fl_Window *parent = this->parent() ? pWindow->window() : NULL; - struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL; -//printf("resize[%p] %dx%d is_a_resize=%d is_a_move=%d depth=%d parent_xid->frame_cb=%p\n", pWindow,W,H,is_a_resize,is_a_move,depth, (parent_xid?parent_xid->frame_cb:0) ); - if (depth == 1 && fl_win && parent_xid && parent_xid->frame_cb && can_expand_outside_parent_) { - // When moving or resizing a subwindow independently from its parent while the parent window - // is being redrawn, the processing depends on whether the moved/resize window - // is a draggable-subwindow. For a draggable subwindow having can_expand_outside_parent_ != 0, - // skip the X,Y,W,H tuple to process only tuples received when parent window is ready. - // This smoothes the movement of the draggable subwindow. - // Process regular subwindows normally. - depth--; - return; - } - if (is_a_resize) { - if (pWindow->parent()) { - if (W < 1) W = 1; - if (H < 1) H = 1; - } - pWindow->Fl_Group::resize(X,Y,W,H); - //fprintf(stderr, "resize: win=%p to %dx%d\n", pWindow, W, H); - if (shown()) {pWindow->redraw();} - } else { - x(X); y(Y); - //fprintf(stderr, "move win=%p to %dx%d\n", pWindow, X, Y); - } - if (!fl_win) { - depth--; - return; - } - - if (is_a_resize) { - if (pWindow->as_overlay_window() && other_xid) { - destroy_double_buffer(); - } - if (fl_win->kind == DECORATED) { // a decorated window - if (fl_win->buffer) { - Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - } - fl_win->configured_width = W; - fl_win->configured_height = H; - if (!in_handle_configure && xdg_toplevel()) { - if (Fl_Window::is_a_rescale()) size_range(); - struct libdecor_state *state = libdecor_state_new(int(W * f), int(H * f)); - // necessary only if resize is initiated by prog - libdecor_frame_commit(fl_win->frame, state, NULL); - libdecor_state_free(state); - if (libdecor_frame_is_floating(fl_win->frame)) { - fl_win->floating_width = int(W*f); - fl_win->floating_height = int(H*f); - } - } - } else if (fl_win->kind == SUBWINDOW && fl_win->subsurface) { // a subwindow - wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - fl_win->configured_width = W; - fl_win->configured_height = H; - } else if (fl_win->xdg_surface) { // a window without border - if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - fl_win->configured_width = W; - fl_win->configured_height = H; - W *= f; H *= f; - xdg_surface_set_window_geometry(fl_win->xdg_surface, 0, 0, W, H); - //printf("xdg_surface_set_window_geometry: %dx%d\n",W, H); - } - } else if (!in_handle_configure && xdg_toplevel() && Fl::e_state == FL_BUTTON1) { - // Wayland doesn't provide a way for the app to set the window position on screen. - // This is functional when the move is mouse-driven. - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - xdg_toplevel_move(xdg_toplevel(), scr_driver->seat->wl_seat, scr_driver->seat->serial); - Fl::pushed(NULL); - Fl::e_state = 0; - } - - if (parent_xid) { - if (depth > 1) { - if (fl_win->subsurface) { - wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - wl_surface_commit(parent_xid->wl_surface); - } - } else if (parent_xid->buffer && is_a_move) { - if (fl_win->subsurface) wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - if (!parent_xid->buffer->wl_buffer || parent_xid->buffer->draw_buffer_needs_commit) { - if (!parent_xid->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(parent_xid); - else wl_surface_commit(parent_xid->wl_surface); - } else { - if (!parent_xid->frame_cb) { - // Use the frame callback mechanism applied to the object's parent window - parent_xid->frame_cb = wl_surface_frame(parent_xid->wl_surface); - wl_callback_add_listener(parent_xid->frame_cb, - Fl_Wayland_Graphics_Driver::p_surface_frame_listener, parent_xid); - } - wl_surface_commit(parent_xid->wl_surface); - } - } - checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent - } - depth--; -} - - -static void crect_intersect(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) { - int x = fl_max(to->x, with->x); - to->width = fl_min(to->x + to->width, with->x + with->width) - x; - if (to->width < 0) to->width = 0; - int y = fl_max(to->y, with->y); - to->height = fl_min(to->y + to->height, with->y + with->height) - y; - if (to->height < 0) to->height = 0; - to->x = x; - to->y = y; -} - - -static bool crect_equal(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) { - return (to->x == with->x && to->y == with->y && to->width == with->width && - to->height == with->height); -} - - -void Fl_Wayland_Window_Driver::checkSubwindowFrame() { - if (!pWindow->parent() || can_expand_outside_parent_) return; - // make sure this subwindow doesn't leak out of its parent window - Fl_Window *from = pWindow, *parent; - cairo_rectangle_int_t full = {0, 0, pWindow->w(), pWindow->h()}; // full subwindow area - cairo_rectangle_int_t srect = full; // will become new subwindow clip - int fromx = 0, fromy = 0; - while ((parent = from->window()) != NULL) { // loop over all parent windows - fromx -= from->x(); // parent origin in subwindow's coordinates - fromy -= from->y(); - cairo_rectangle_int_t prect = {fromx, fromy, parent->w(), parent->h()}; - crect_intersect(&srect, &prect); // area of subwindow inside its parent - from = parent; - } - cairo_rectangle_int_t *r = subRect(); - // current subwindow clip - cairo_rectangle_int_t current_clip = (r ? *r : full); - if (!crect_equal(&srect, ¤t_clip)) { // if new clip differs from current clip - if (crect_equal(&srect, &full)) r = NULL; - else { - r = &srect; - if (r->width == 0 || r->height == 0) { - r = NULL; - } - } - subRect(r); - } -} - - -void Fl_Wayland_Window_Driver::subRect(cairo_rectangle_int_t *r) { - if (subRect_) delete subRect_; - cairo_rectangle_int_t *r2 = NULL; - if (r) { - r2 = new cairo_rectangle_int_t; - *r2 = *r; - } - subRect_ = r2; -} - - -void Fl_Wayland_Window_Driver::reposition_menu_window(int x, int y) { - if (y == pWindow->y()) return; - // The top of the tall popup window was positioned at the top of the screen - // Instead of sliding up the popup window on the display, we slide up the - // drawing inside the fixed popup via member variable offset_y of the - // menuwindow class, and we redraw the popup content. - // It's also useful to make such tall popup window transparent. - *Fl_Window_Driver::menu_offset_y(pWindow) += (y - pWindow->y()); - struct wld_window *xid = fl_wl_xid(pWindow); - wl_surface_set_opaque_region(xid->wl_surface, NULL); - if (xid->buffer) memset(xid->buffer->draw_buffer.buffer, 0, - xid->buffer->draw_buffer.data_size); - //printf("offset_y=%d\n", *Fl_Window_Driver::menu_offset_y(pWindow)); - this->y(y); - pWindow->redraw(); -} - - -void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int nscreen) { - int HH; - Fl_Window *parent = Fl_Window_Driver::menu_parent(&HH); - if (parent) { - if (pWindow->menu_window() && popup_window() && pWindow->h() > HH) { - // tall menu: set top (Y) and bottom (Y+H) bounds relatively to reference window - int ih = Fl_Window_Driver::menu_itemheight(pWindow); - X = -50000; - W = 1000000; - H = HH - 2 * ih; - Fl_Window *origin = Fl_Window_Driver::menu_leftorigin(pWindow); - if (origin) { // has left parent - int selected = fl_max(Fl_Window_Driver::menu_selected(origin), 0); - Y = origin->y() + (selected + 0.5) * ih; - } else if (!Fl_Window_Driver::menu_bartitle(pWindow)) { // tall menu button - static int y_offset = 0; - if (new_popup) { - y_offset = pWindow->y()- ih; - new_popup = false; - } - Y = 1.5 * ih + y_offset; - } else { // has a menutitle - Y = 1.5 * ih; - } - } else { // position the menu window by wayland constraints - X = -50000; - Y = -50000; - W = 1000000; - H = 1000000; - } - //printf("menu_window_area: %dx%d - %dx%d\n",X,Y,W,H); - } else Fl_Window_Driver::menu_window_area(X, Y, W, H, nscreen); -} - - -int Fl_Wayland_Window_Driver::wld_scale() { - Fl_X *flx = Fl_X::flx(pWindow); - struct wld_window *xid = (flx ? (struct wld_window *)flx->xid : NULL); - if (!xid || wl_list_empty(&xid->outputs)) { - int scale = 1; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &(scr_driver->outputs), link) { - scale = fl_max(scale, output->wld_scale); - } - return scale; - } - struct surface_output *s_output; - s_output = wl_container_of(xid->outputs.next, s_output, link); - return s_output->output->wld_scale; -} - - -FL_EXPORT struct wl_surface *fl_wl_surface(struct wld_window *xid) { - return xid->wl_surface; -} - - -cairo_t *fl_wl_gc() { - return ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->cr(); -} - - -Fl_Window *fl_wl_find(struct wld_window *xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} - - -struct wld_window *fl_wl_xid(const Fl_Window *win) { - return (struct wld_window *)Fl_Window_Driver::xid(win); -} - - -struct wl_compositor *fl_wl_compositor() { - Fl_Wayland_Screen_Driver *screen_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - return screen_driver->wl_compositor; -} - - -int fl_wl_buffer_scale(Fl_Window *window) { - return Fl_Wayland_Window_Driver::driver(window)->wld_scale(); -} - - -Fl_Wayland_Plugin *Fl_Wayland_Window_Driver::gl_plugin() { - static Fl_Wayland_Plugin *plugin = NULL; - if (!plugin) { - Fl_Plugin_Manager pm("wayland.fltk.org"); - plugin = (Fl_Wayland_Plugin*)pm.plugin("gl.wayland.fltk.org"); - } - return plugin; -} - - -void Fl_Wayland_Window_Driver::maximize() { - struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; - if (xid->kind == DECORATED) libdecor_frame_set_maximized(xid->frame); - else Fl_Window_Driver::maximize(); -} - - -void Fl_Wayland_Window_Driver::un_maximize() { - struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; - if (xid->kind == DECORATED) libdecor_frame_unset_maximized(xid->frame); - else Fl_Window_Driver::un_maximize(); -} diff --git a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx b/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx deleted file mode 100644 index 12c525c46..000000000 --- a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx +++ /dev/null @@ -1,741 +0,0 @@ -// -// Wayland-specific code for clipboard and drag-n-drop support. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#if !defined(FL_DOXYGEN) - -# include <FL/Fl.H> -# include <FL/platform.H> -# include <FL/Fl_Window.H> -# include <FL/Fl_Shared_Image.H> -# include <FL/Fl_Image_Surface.H> -# include "Fl_Wayland_Screen_Driver.H" -# include "Fl_Wayland_Window_Driver.H" -# include "../Unix/Fl_Unix_System_Driver.H" -# include "Fl_Wayland_Graphics_Driver.H" -# include "../../flstring.h" // includes <string.h> - -# include <errno.h> -# include <stdio.h> -# include <stdlib.h> -# include <map> - - -//////////////////////////////////////////////////////////////// -// Code used for copy and paste and DnD into the program: - -static char *fl_selection_buffer[2]; -static int fl_selection_length[2]; -static const char * fl_selection_type[2]; -static int fl_selection_buffer_length[2]; -static char fl_i_own_selection[2] = {0,0}; -static struct wl_data_offer *fl_selection_offer = NULL; -// The MIME type Wayland uses for text-containing clipboard: -static const char wld_plain_text_clipboard[] = "text/plain;charset=utf-8"; - - -int Fl_Wayland_Screen_Driver::clipboard_contains(const char *type) -{ - return fl_selection_type[1] == type; -} - - -struct data_source_write_struct { - size_t rest; - char *from; -}; - -void write_data_source_cb(FL_SOCKET fd, data_source_write_struct *data) { - while (data->rest) { - ssize_t n = write(fd, data->from, data->rest); - if (n == -1) { - if (errno == EAGAIN) return; - Fl::error("write_data_source_cb: error while writing clipboard data\n"); - break; - } - data->from += n; - data->rest -= n; - } - Fl::remove_fd(fd, FL_WRITE); - delete data; - close(fd); -} - - -static void data_source_handle_send(void *data, struct wl_data_source *source, - const char *mime_type, int fd) { - fl_intptr_t rank = (fl_intptr_t)data; -//fprintf(stderr, "data_source_handle_send: %s fd=%d l=%d\n", mime_type, fd, fl_selection_length[1]); - if (((!strcmp(mime_type, wld_plain_text_clipboard) || !strcmp(mime_type, "text/plain")) && - fl_selection_type[rank] == Fl::clipboard_plain_text) - || - (!strcmp(mime_type, "image/bmp") && fl_selection_type[rank] == Fl::clipboard_image) ) { - data_source_write_struct *write_data = new data_source_write_struct; - write_data->rest = fl_selection_length[rank]; - write_data->from = fl_selection_buffer[rank]; - Fl::add_fd(fd, FL_WRITE, (Fl_FD_Handler)write_data_source_cb, write_data); - } else { - //Fl::error("Destination client requested unsupported MIME type: %s\n", mime_type); - close(fd); - } -} - - -static Fl_Window *fl_dnd_target_window = 0; -static wl_surface *fl_dnd_target_surface = 0; -static bool doing_dnd = false; // true when DnD is in action -static wl_surface *dnd_icon = NULL; // non null when DnD uses text as cursor -static wl_cursor* save_cursor = NULL; // non null when DnD uses "dnd-copy" cursor - - -static void data_source_handle_cancelled(void *data, struct wl_data_source *source) { - // An application has replaced the clipboard contents or DnD finished - wl_data_source_destroy(source); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->seat->data_source == source) scr_driver->seat->data_source = NULL; - doing_dnd = false; - if (dnd_icon) { - struct Fl_Wayland_Graphics_Driver::wld_buffer *off = - (struct Fl_Wayland_Graphics_Driver::wld_buffer *) - wl_surface_get_user_data(dnd_icon); - struct wld_window fake_window; - memset(&fake_window, 0, sizeof(fake_window)); - fake_window.buffer = off; - Fl_Wayland_Graphics_Driver::buffer_release(&fake_window); - wl_surface_destroy(dnd_icon); - dnd_icon = NULL; - } - fl_i_own_selection[1] = 0; - if (data == 0) { // at end of DnD - if (save_cursor) { - scr_driver->default_cursor(save_cursor); - scr_driver->set_cursor(); - save_cursor = NULL; - } - if (fl_dnd_target_window) { - Fl::handle(FL_RELEASE, fl_dnd_target_window); - fl_dnd_target_window = 0; - } - Fl::pushed(0); - } -} - - -static void data_source_handle_target(void *data, struct wl_data_source *source, const char *mime_type) { - if (!Fl::pushed()) { - data_source_handle_cancelled(data, source); - return; - } - if (mime_type != NULL) { - //printf("Destination would accept MIME type if dropped: %s\n", mime_type); - } else { - //printf("Destination would reject if dropped\n"); - } -} - - -static uint32_t last_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - - -static void data_source_handle_action(void *data, struct wl_data_source *source, - uint32_t dnd_action) { - last_dnd_action = dnd_action; - switch (dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("Destination would perform a copy action if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: - //printf("Destination would reject the drag if dropped\n"); - break; - } -} - - -static void data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *source) { - //printf("Drop performed\n"); -} - - -static void data_source_handle_dnd_finished(void *data, struct wl_data_source *source) { - switch (last_dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: - //printf("Destination has accepted the drop with a move action\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("Destination has accepted the drop with a copy action\n"); - break; - } -} - - -static const struct wl_data_source_listener data_source_listener = { - .target = data_source_handle_target, - .send = data_source_handle_send, - .cancelled = data_source_handle_cancelled, - .dnd_drop_performed = data_source_handle_dnd_drop_performed, - .dnd_finished = data_source_handle_dnd_finished, - .action = data_source_handle_action, -}; - - -static struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen_from_text(const char *text, - int scale) { - const char *p, *q; - int width = 0, height, w2, ltext = strlen(text); - fl_font(FL_HELVETICA, 10 * scale); - p = text; - int nl = 0; - while(nl < 20 && (q=strchr(p, '\n')) != NULL) { - nl++; - w2 = int(fl_width(p, q - p)); - if (w2 > width) width = w2; - p = q + 1; - } - if (nl < 20 && text[ ltext - 1] != '\n') { - nl++; - w2 = int(fl_width(p)); - if (w2 > width) width = w2; - } - if (width > 300*scale) width = 300*scale; - height = nl * fl_height() + 3; - width += 6; - width = ceil(width/float(scale)) * scale; // these must be multiples of scale - height = ceil(height/float(scale)) * scale; - struct Fl_Wayland_Graphics_Driver::wld_buffer *off; - Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen( - width, height, &off); - Fl_Surface_Device::push_current(surf); - p = text; - fl_font(FL_HELVETICA, 10 * scale); - int y = fl_height(); - while (nl > 0) { - q = strchr(p, '\n'); - if (q) { - fl_draw(p, q - p, 3, y); - } else { - fl_draw(p, 3, y); - break; - } - y += fl_height(); - p = q + 1; - nl--; - } - Fl_Surface_Device::pop_current(); - delete surf; - cairo_surface_flush( cairo_get_target(off->draw_buffer.cairo_) ); - memcpy(off->data, off->draw_buffer.buffer, off->draw_buffer.data_size); - return off; -} - - -int Fl_Wayland_Screen_Driver::dnd(int use_selection) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - - struct wl_data_source *source = - wl_data_device_manager_create_data_source(scr_driver->seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(source, &data_source_listener, (void*)0); - wl_data_source_offer(source, wld_plain_text_clipboard); - wl_data_source_set_actions(source, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); - struct Fl_Wayland_Graphics_Driver::wld_buffer *off = NULL; - int s = 1; - if (use_selection) { - // use the text as dragging icon - Fl_Widget *current = Fl::pushed() ? Fl::pushed() : Fl::first_window(); - s = Fl_Wayland_Window_Driver::driver(current->top_window())->wld_scale(); - off = (struct Fl_Wayland_Graphics_Driver::wld_buffer *)offscreen_from_text(fl_selection_buffer[0], s); - dnd_icon = wl_compositor_create_surface(scr_driver->wl_compositor); - } else dnd_icon = NULL; - doing_dnd = true; - wl_data_device_start_drag(scr_driver->seat->data_device, source, - scr_driver->seat->pointer_focus, dnd_icon, - scr_driver->seat->serial); - if (use_selection) { - wl_surface_attach(dnd_icon, off->wl_buffer, 0, 0); - wl_surface_set_buffer_scale(dnd_icon, s); - wl_surface_damage(dnd_icon, 0, 0, 10000, 10000); - wl_surface_commit(dnd_icon); - wl_surface_set_user_data(dnd_icon, off); - } else { - static struct wl_cursor *dnd_cursor = scr_driver->cache_cursor("dnd-copy"); - if (dnd_cursor) { - save_cursor = scr_driver->default_cursor(); - scr_driver->default_cursor(dnd_cursor); - scr_driver->set_cursor(); - } else save_cursor = NULL; - } - return 1; -} - - -struct compare_utf8 { // used as key_comp member of following map object - bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; } -}; - -// map: for each clipboard mime-type FLTK has interest in, give FLTK clipboard type and priority. -// A mime-type with higher priority for same FLTK clipboard type is preferred. -typedef struct { const char * const fltk_type; int priority; } type_prio_struct; -static std::map<const char * const, type_prio_struct, compare_utf8> clipboard_mimetypes_map { -// mime-type FLTK-clipboard-type priority - {"image/png", {Fl::clipboard_image, 1} }, - {"image/bmp", {Fl::clipboard_image, 2} }, - {"text/plain", {Fl::clipboard_plain_text, 1} }, - {"text/uri-list", {Fl::clipboard_plain_text, 2} }, - {"UTF8_STRING", {Fl::clipboard_plain_text, 3} }, - {wld_plain_text_clipboard, {Fl::clipboard_plain_text, 4} }, -}; - -// map: for each FLTK-clipboard-type, give current preferred mime-type and priority -typedef struct { const char *mime_type; int priority; } mime_prio_struct; -static std::map<const char * const, mime_prio_struct> clipboard_kinds_map { -// FLTK-clipboard-type current mime-type current highest priority - {Fl::clipboard_image, {NULL, 0} }, - {Fl::clipboard_plain_text, {NULL, 0} }, -}; - - -static void data_offer_handle_offer(void *data, struct wl_data_offer *offer, - const char *mime_type) { - // runs when app becomes active once for each offered clipboard type -//fprintf(stderr, "Clipboard offer=%p supports MIME type: %s\n", offer, mime_type); - std::map<const char*const, type_prio_struct, compare_utf8>::iterator iter_mime = - clipboard_mimetypes_map.find(mime_type); - if (iter_mime == clipboard_mimetypes_map.end()) return; // FLTK doesn't handle this mime_type - std::map<const char*const, mime_prio_struct>::iterator iter_kind = - clipboard_kinds_map.find(iter_mime->second.fltk_type); - if (iter_mime->second.priority > iter_kind->second.priority) { // found mime-type with higher priority - iter_kind->second.priority = iter_mime->second.priority; - iter_kind->second.mime_type = iter_mime->first; - fl_selection_type[1] = iter_kind->first; -//fprintf(stderr,"mime_type=%s priority=%d [%s]\n",iter_kind->second.mime_type, iter_kind->second.priority, fl_selection_type[1]); - } -} - - -static void data_offer_handle_source_actions(void *data, struct wl_data_offer *offer, - uint32_t actions) { - if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { - //printf("Drag supports the copy action\n"); - } -} - - -static void data_offer_handle_action(void *data, struct wl_data_offer *offer, - uint32_t dnd_action) { - switch (dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: - //printf("A move action would be performed if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("A copy action would be performed if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: - //printf("The drag would be rejected if dropped\n"); - break; - } -} - - -static const struct wl_data_offer_listener data_offer_listener = { - .offer = data_offer_handle_offer, - .source_actions = data_offer_handle_source_actions, - .action = data_offer_handle_action, -}; - - -static void data_device_handle_data_offer(void *data, struct wl_data_device *data_device, - struct wl_data_offer *offer) { - // An application has created a new data source -//fprintf(stderr, "data_device_handle_data_offer offer=%p\n", offer); - fl_selection_type[1] = NULL; - wl_data_offer_add_listener(offer, &data_offer_listener, NULL); - // reset current best mime-type and priority - std::map<const char*const, mime_prio_struct>::iterator iter = clipboard_kinds_map.begin(); - while (iter != clipboard_kinds_map.end()) { - iter->second.mime_type = NULL; - iter->second.priority = 0; - iter++; - } -} - - -static void data_device_handle_selection(void *data, struct wl_data_device *data_device, - struct wl_data_offer *offer) { - // An application has set the clipboard contents. W -//fprintf(stderr, "data_device_handle_selection\n"); - if (fl_selection_offer) wl_data_offer_destroy(fl_selection_offer); - fl_selection_offer = offer; -//if (offer == NULL) fprintf(stderr, "Clipboard is empty\n"); -} - - -// Gets from the system the clipboard or dnd text and puts it in fl_selection_buffer[1] -// which is enlarged if necessary. -static void get_clipboard_or_dragged_text(struct wl_data_offer *offer) { - int fds[2]; - char *from; - if (pipe(fds)) return; - // preferred mime-type for the text clipboard type - const char *type = clipboard_kinds_map[Fl::clipboard_plain_text].mime_type; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - // read in fl_selection_buffer - char *to = fl_selection_buffer[1]; - ssize_t rest = fl_selection_buffer_length[1]; - while (rest) { - ssize_t n = read(fds[0], to, rest); - if (n <= 0) { - close(fds[0]); - fl_selection_length[1] = to - fl_selection_buffer[1]; - fl_selection_buffer[1][ fl_selection_length[1] ] = 0; - goto way_out; - } - n = Fl_Screen_Driver::convert_crlf(to, n); - to += n; - rest -= n; - } - // compute size of unread clipboard data - rest = fl_selection_buffer_length[1]; - while (true) { - char buf[1000]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) { - close(fds[0]); - break; - } - rest += n; - } -//fprintf(stderr, "get_clipboard_or_dragged_text: size=%ld\n", rest); - // read full clipboard data - if (pipe(fds)) goto way_out; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - if (rest+1 > fl_selection_buffer_length[1]) { - delete[] fl_selection_buffer[1]; - fl_selection_buffer[1] = new char[rest+1000+1]; - fl_selection_buffer_length[1] = rest+1000; - } - from = fl_selection_buffer[1]; - while (rest > 0) { - ssize_t n = read(fds[0], from, rest); - if (n <= 0) break; - n = Fl_Screen_Driver::convert_crlf(from, n); - from += n; - rest -= n; - } - close(fds[0]); - fl_selection_length[1] = from - fl_selection_buffer[1]; - fl_selection_buffer[1][fl_selection_length[1]] = 0; -way_out: - if (strcmp(type, "text/uri-list") == 0) { - fl_decode_uri(fl_selection_buffer[1]); // decode encoded bytes - char *p = fl_selection_buffer[1]; - while (*p) { // remove prefixes - if (strncmp(p, "file://", 7) == 0) { - memmove(p, p+7, strlen(p+7)+1); - } - p = strchr(p, '\n'); - if (!p) break; - if (*++p == 0) *(p-1) = 0; // remove last '\n' - } - fl_selection_length[1] = strlen(fl_selection_buffer[1]); - } - Fl::e_clipboard_type = Fl::clipboard_plain_text; -} - - -static struct wl_data_offer *current_drag_offer = NULL; -static uint32_t fl_dnd_serial; - - -static void data_device_handle_enter(void *data, struct wl_data_device *data_device, - uint32_t serial, struct wl_surface *surface, - wl_fixed_t x, wl_fixed_t y, - struct wl_data_offer *offer) { - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); -//printf("Drag entered our surface %p(win=%p) at %dx%d\n", surface, win, wl_fixed_to_int(x), wl_fixed_to_int(y)); - if (win) { - fl_dnd_target_surface = surface; - float f = Fl::screen_scale(win->screen_num()); - Fl::e_x = wl_fixed_to_int(x) / f; - Fl::e_y = wl_fixed_to_int(y) / f; - while (win->parent()) { - Fl::e_x += win->x(); - Fl::e_y += win->y(); - win = win->window(); - } - fl_dnd_target_window = win; - Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x(); - Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y(); - Fl::handle(FL_DND_ENTER, fl_dnd_target_window); - current_drag_offer = offer; - fl_dnd_serial = serial; - } else fl_dnd_target_window = NULL; // we enter a non-FLTK window (titlebar, shade) - uint32_t supported_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - uint32_t preferred_action = supported_actions; - wl_data_offer_set_actions(offer, supported_actions, preferred_action); -} - - -static void data_device_handle_motion(void *data, struct wl_data_device *data_device, - uint32_t time, wl_fixed_t x, wl_fixed_t y) { - if (!current_drag_offer) return; -//printf("data_device_handle_motion fl_dnd_target_window=%p\n", fl_dnd_target_window); - int ret = 0; - if (fl_dnd_target_window) { - float f = Fl::screen_scale(fl_dnd_target_window->screen_num()); - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(fl_dnd_target_surface); - Fl::e_x = wl_fixed_to_int(x) / f; - Fl::e_y = wl_fixed_to_int(y) / f; - while (win->parent()) { - Fl::e_x += win->x(); - Fl::e_y += win->y(); - win = win->window(); - } - Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x(); - Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y(); - ret = Fl::handle(FL_DND_DRAG, fl_dnd_target_window); - if (Fl::belowmouse()) Fl::belowmouse()->take_focus(); - } - uint32_t supported_actions = ret && (Fl::pushed() || !doing_dnd) ? - WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY : WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - uint32_t preferred_action = supported_actions; - wl_data_offer_set_actions(current_drag_offer, supported_actions, preferred_action); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (ret && current_drag_offer) wl_data_offer_accept(current_drag_offer, fl_dnd_serial, "text/plain"); -} - - -static void data_device_handle_leave(void *data, struct wl_data_device *data_device) { - //printf("Drag left our surface\n"); - if (current_drag_offer) Fl::handle(FL_DND_LEAVE, fl_dnd_target_window); -} - - -static void data_device_handle_drop(void *data, struct wl_data_device *data_device) { - if (!current_drag_offer) return; - Fl::handle(FL_ENTER, fl_dnd_target_window); // useful to set the belowmouse widget - int ret = Fl::handle(FL_DND_RELEASE, fl_dnd_target_window); -//printf("data_device_handle_drop ret=%d doing_dnd=%d\n", ret, doing_dnd); - - if (!ret) { - wl_data_offer_destroy(current_drag_offer); - current_drag_offer = NULL; - return; - } - - if (doing_dnd) { - Fl::e_text = fl_selection_buffer[0]; - Fl::e_length = fl_selection_length[0]; - } else { - get_clipboard_or_dragged_text(current_drag_offer); - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - } - int old_event = Fl::e_number; - Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); - Fl::e_number = old_event; - - wl_data_offer_finish(current_drag_offer); - wl_data_offer_destroy(current_drag_offer); - current_drag_offer = NULL; -} - - -static const struct wl_data_device_listener data_device_listener = { - .data_offer = data_device_handle_data_offer, - .enter = data_device_handle_enter, - .leave = data_device_handle_leave, - .motion = data_device_handle_motion, - .drop = data_device_handle_drop, - .selection = data_device_handle_selection, -}; - - -const struct wl_data_device_listener *Fl_Wayland_Screen_Driver::p_data_device_listener = - &data_device_listener; - - -// Reads from the clipboard an image which can be in image/bmp or image/png MIME type. -// Returns 0 if OK, != 0 if error. -static int get_clipboard_image(struct wl_data_offer *offer) { - int fds[2]; - if (pipe(fds)) return 1; - // preferred mime-type for the image clipboard type - const char *type = clipboard_kinds_map[Fl::clipboard_image].mime_type; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (strcmp(type, "image/png") == 0) { - char tmp_fname[21]; - Fl_Shared_Image *shared = 0; - strcpy(tmp_fname, "/tmp/clipboardXXXXXX"); - int fd = mkstemp(tmp_fname); - if (fd >= 0) { - while (true) { - char buf[10000]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) break; - n = write(fd, buf, n); - } - close(fd); - shared = Fl_Shared_Image::get(tmp_fname); - fl_unlink(tmp_fname); - } - close(fds[0]); - if (!shared) return 1; - int ld = shared->ld() ? shared->ld() : shared->w() * shared->d(); - uchar *rgb = new uchar[shared->w() * shared->h() * shared->d()]; - memcpy(rgb, shared->data()[0], ld * shared->h() ); - Fl_RGB_Image *image = new Fl_RGB_Image(rgb, shared->w(), shared->h(), shared->d(), - shared->ld()); - shared->release(); - image->alloc_array = 1; - Fl::e_clipboard_data = (void*)image; - } else { // process image/bmp - uchar buf[54]; - size_t rest = 1; - char *bmp = NULL; - ssize_t n = read(fds[0], buf, sizeof(buf)); // read size info of the BMP image - if (n == sizeof(buf)) { - int w, h; // size of the BMP image - Fl_Unix_System_Driver::read_int(buf + 18, w); - Fl_Unix_System_Driver::read_int(buf + 22, h); - // the number of bytes per row of BMP image, rounded up to multiple of 4 - int R = ((3*w+3)/4) * 4; - bmp = new char[R * h + 54]; - memcpy(bmp, buf, 54); - char *from = bmp + 54; - rest = R * h; - while (rest) { - ssize_t n = read(fds[0], from, rest); - if (n <= 0) break; - from += n; - rest -= n; - } -//fprintf(stderr, "get_clipboard_image: image/bmp %dx%d rest=%lu\n", w,h,rest); - } - close(fds[0]); - if (!rest) Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(bmp); - delete[] bmp; - if (rest) return 1; - } - Fl::e_clipboard_type = Fl::clipboard_image; - return 0; -} - - -void Fl_Wayland_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) { - if (clipboard != 1) return; - if (fl_i_own_selection[1]) { - // We already have it, do it quickly without compositor. - if (type == Fl::clipboard_plain_text && fl_selection_type[1] == type) { - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - if (!Fl::e_text) Fl::e_text = (char *)""; - } else if (type == Fl::clipboard_image && fl_selection_type[1] == type) { - Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(fl_selection_buffer[1]); - Fl::e_clipboard_type = Fl::clipboard_image; - } else return; - receiver.handle(FL_PASTE); - return; - } - // otherwise get the compositor to return it: - if (!fl_selection_offer) return; - if (type == Fl::clipboard_plain_text && clipboard_contains(Fl::clipboard_plain_text)) { - get_clipboard_or_dragged_text(fl_selection_offer); - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - receiver.handle(FL_PASTE); - } else if (type == Fl::clipboard_image && clipboard_contains(Fl::clipboard_image)) { - if (get_clipboard_image(fl_selection_offer)) return; - struct wld_window * xid = fl_wl_xid(receiver.top_window()); - if (xid) { - int s = Fl_Wayland_Window_Driver::driver(receiver.top_window())->wld_scale(); - if ( s > 1) { - Fl_RGB_Image *rgb = (Fl_RGB_Image*)Fl::e_clipboard_data; - rgb->scale(rgb->data_w() / s, rgb->data_h() / s); - } - } - int done = receiver.handle(FL_PASTE); - Fl::e_clipboard_type = ""; - if (done == 0) { - delete (Fl_RGB_Image*)Fl::e_clipboard_data; - Fl::e_clipboard_data = NULL; - } - } -} - - -void Fl_Wayland_Screen_Driver::copy(const char *stuff, int len, int clipboard, - const char *type) { - if (!stuff || len < 0) return; - - if (clipboard >= 2) - clipboard = 1; // Only on X11 do multiple clipboards make sense. - - if (len+1 > fl_selection_buffer_length[clipboard]) { - delete[] fl_selection_buffer[clipboard]; - fl_selection_buffer[clipboard] = new char[len+100]; - fl_selection_buffer_length[clipboard] = len+100; - } - memcpy(fl_selection_buffer[clipboard], stuff, len); - fl_selection_buffer[clipboard][len] = 0; // needed for direct paste - fl_selection_length[clipboard] = len; - fl_i_own_selection[clipboard] = 1; - fl_selection_type[clipboard] = Fl::clipboard_plain_text; - if (clipboard == 1) { - if (seat->data_source) wl_data_source_destroy(seat->data_source); - seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1); - wl_data_source_offer(seat->data_source, wld_plain_text_clipboard); - wl_data_device_set_selection(seat->data_device, - seat->data_source, - seat->keyboard_enter_serial); -//fprintf(stderr, "wl_data_device_set_selection len=%d to %d\n", len, clipboard); - } -} - - -// takes a raw RGB image and puts it in the copy/paste buffer -void Fl_Wayland_Screen_Driver::copy_image(const unsigned char *data, int W, int H){ - if (!data || W <= 0 || H <= 0) return; - delete[] fl_selection_buffer[1]; - fl_selection_buffer[1] = - (char *)Fl_Unix_System_Driver::create_bmp(data,W,H,&fl_selection_length[1]); - fl_selection_buffer_length[1] = fl_selection_length[1]; - fl_i_own_selection[1] = 1; - fl_selection_type[1] = Fl::clipboard_image; - if (seat->data_source) wl_data_source_destroy(seat->data_source); - seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1); - wl_data_source_offer(seat->data_source, "image/bmp"); - wl_data_device_set_selection(seat->data_device, seat->data_source, - seat->keyboard_enter_serial); -//fprintf(stderr, "copy_image: len=%d\n", fl_selection_length[1]); -} - -//////////////////////////////////////////////////////////////// -// Code for tracking clipboard changes: - -// is that possible with Wayland ? - -//////////////////////////////////////////////////////////////// - -#endif // !defined(FL_DOXYGEN) diff --git a/src/drivers/Wayland/fl_wayland_platform_init.cxx b/src/drivers/Wayland/fl_wayland_platform_init.cxx deleted file mode 100644 index 4c4477740..000000000 --- a/src/drivers/Wayland/fl_wayland_platform_init.cxx +++ /dev/null @@ -1,157 +0,0 @@ -// -// Wayland-specific code to initialize wayland support. -// -// Copyright 2022-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/fl_config.h> -#include "Fl_Wayland_Copy_Surface_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "../Unix/Fl_Unix_System_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Image_Surface_Driver.H" -#include "../Base/Fl_Base_Pen_Events.H" -#ifdef FLTK_USE_X11 -# include "../Xlib/Fl_Xlib_Copy_Surface_Driver.H" -# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H" -# include "../X11/Fl_X11_Screen_Driver.H" -# include "../X11/Fl_X11_Window_Driver.H" -# include "../Xlib/Fl_Xlib_Image_Surface_Driver.H" -#endif -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - - -#ifdef FLTK_USE_X11 - -static bool attempt_wayland() { - if (Fl_Wayland_Screen_Driver::wl_display) return true; - static bool first = true; - static bool disable_wl = false; - if (first) { // get the value if it exists and cache it - void *sym = Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, "fl_disable_wayland"); - if (sym) { - disable_wl = *(bool *)sym; - // printf("fl_disable_wayland = %s\n", disable_wl ? "true" : "false"); - } - first = false; - } - if (disable_wl) - return false; - const char *backend = ::getenv("FLTK_BACKEND"); - // fprintf(stderr, "FLTK_BACKEND='%s'\n", backend ? backend : ""); - if (backend && strcmp(backend, "x11") == 0) { - return false; - } - - if (backend && strcmp(backend, "wayland") == 0) { - Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL); - if (!Fl_Wayland_Screen_Driver::wl_display) { - fprintf(stderr, "Error: no Wayland connection available, FLTK_BACKEND='wayland'\n"); - exit(1); - } - return true; - } - - if (!backend) { - // env var XDG_RUNTIME_DIR is required for Wayland - const char *xdgrt = ::getenv("XDG_RUNTIME_DIR"); - if (xdgrt) { - // is a Wayland connection available ? - Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL); - if (Fl_Wayland_Screen_Driver::wl_display) { // Yes, use Wayland drivers - // puts("using wayland"); - return true; - } - } - // no Wayland connection or environment variable XDG_RUNTIME_DIR not set, - // falling back to X11 - return false; - } - - fprintf(stderr, "Error: unexpected value of FLTK_BACKEND: '%s'\n", backend); - exit(1); - return false; -} - -#endif // FLTK_USE_X11 - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() { - return new Fl_Unix_System_Driver(); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() { -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) return new Fl_X11_Cairo_Graphics_Driver(); -#endif - return new Fl_Wayland_Graphics_Driver(); -} - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) { -#ifdef FLTK_USE_X11 - if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_Xlib_Copy_Surface_Driver(w, h); -#endif - return new Fl_Wayland_Copy_Surface_Driver(w, h); -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() { - if (!Fl_Screen_Driver::system_driver) Fl::system_driver(); -#ifdef FLTK_USE_X11 - if (attempt_wayland()) { - return new Fl_Wayland_Screen_Driver(); - } - - Fl_X11_Screen_Driver *d = new Fl_X11_Screen_Driver(); - for (int i = 0; i < MAX_SCREENS; i++) d->screens[i].scale = 1; - d->current_xft_dpi = 0.; // means the value of the Xft.dpi resource is still unknown - return d; -#else - return new Fl_Wayland_Screen_Driver(); -#endif -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) return new Fl_X11_Window_Driver(w); -#endif - return new Fl_Wayland_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) - return new Fl_Xlib_Image_Surface_Driver(w, h, high_res, off); -#endif - return new Fl_Wayland_Image_Surface_Driver(w, h, high_res, off); -} - -#if defined(FLTK_HAVE_PEN_SUPPORT) - -namespace Fl { -namespace Pen { -Driver default_driver; -Driver& driver = default_driver; -} // namespace Pen -} // namespace Fl - -#endif // FLTK_HAVE_PEN_SUPPORT diff --git a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H deleted file mode 100644 index 2958fe6e5..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H +++ /dev/null @@ -1,62 +0,0 @@ -// -// Class Fl_WinAPI_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WINAPI_GL_WINDOW_DRIVER_H -#define FL_WINAPI_GL_WINDOW_DRIVER_H - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Gl_Window_Driver.H" -#include <FL/gl.h> - -class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - Fl_WinAPI_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} - float pixels_per_unit() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void make_current_after() FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - void invalidate() FL_OVERRIDE {} - int flush_begin(char& valid_f) FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - GLContext do_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, - int layer); - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void* GetProcAddress(const char *procName) FL_OVERRIDE; - void draw_string_legacy(const char* str, int n) FL_OVERRIDE; - void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) FL_OVERRIDE; - void get_list(Fl_Font_Descriptor *fd, int r) FL_OVERRIDE; - int genlistsize() FL_OVERRIDE; - void switch_to_GL1() FL_OVERRIDE; - void switch_back() FL_OVERRIDE; -#if HAVE_GL_OVERLAY - void gl_hide_before(void *& overlay) FL_OVERRIDE; - int can_do_overlay() FL_OVERRIDE; - int overlay_color(Fl_Color i) FL_OVERRIDE; - void make_overlay(void*&overlay) FL_OVERRIDE; -#endif -}; - -#endif // HAVE_GL - -#endif // FL_WINAPI_GL_WINDOW_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx deleted file mode 100644 index 8e199b09c..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx +++ /dev/null @@ -1,472 +0,0 @@ -// -// Class Fl_WinAPI_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Screen_Driver.H" -#include <FL/gl.h> -#include "Fl_WinAPI_Gl_Window_Driver.H" -#include "../../Fl_Gl_Choice.H" -#include "Fl_WinAPI_Window_Driver.H" -#include "../GDI/Fl_Font.H" -extern void fl_save_dc(HWND, HDC); - -#ifndef GL_CURRENT_PROGRAM -# define GL_CURRENT_PROGRAM 0x8B8D // from glew.h -#endif - -// STR #3119: select pixel format with composition support -// ... and no more than 32 color bits (8 bits/color) -// Ref: PixelFormatDescriptor Object -// https://msdn.microsoft.com/en-us/library/cc231189.aspx -#if !defined(PFD_SUPPORT_COMPOSITION) -# define PFD_SUPPORT_COMPOSITION (0x8000) -#endif - -#define DEBUG_PFD (0) // 1 = PFD selection debug output, 0 = no debug output - - -// Describes crap needed to create a GLContext. -class Fl_WinAPI_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_WinAPI_Gl_Window_Driver; -private: - int pixelformat; // the visual to use - PIXELFORMATDESCRIPTOR pfd; // some wgl calls need this thing -public: - Fl_WinAPI_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - pixelformat = 0; - } -}; - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_WinAPI_Gl_Window_Driver(w); -} - - -Fl_Gl_Choice *Fl_WinAPI_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl_WinAPI_Gl_Choice *g = (Fl_WinAPI_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - - // Replacement for ChoosePixelFormat() that finds one with an overlay if possible: - HDC gc = (HDC)(fl_graphics_driver ? fl_graphics_driver->gc() : 0); - if (!gc) gc = fl_GetDC(0); - int pixelformat = 0; - PIXELFORMATDESCRIPTOR chosen_pfd; - for (int i = 1; ; i++) { - PIXELFORMATDESCRIPTOR pfd; - if (!DescribePixelFormat(gc, i, sizeof(pfd), &pfd)) break; - // continue if it does not satisfy our requirements: - if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; - if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; - if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; - if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; - if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; - if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; - // Skipt his descriptor if we want a depth buffer, but this one has none - if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; - // Skipt his descriptor if we want a 32 bit depth buffer, but this one has less or none - if ((m & FL_DEPTH32) && pfd.cDepthBits < 32) continue; - if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; - -#if DEBUG_PFD - printf("pfd #%d supports composition: %s\n", i, (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - printf(" ... & PFD_GENERIC_FORMAT: %s\n", (pfd.dwFlags & PFD_GENERIC_FORMAT) ? "generic" : "accelerated"); - printf(" ... Overlay Planes : %d\n", pfd.bReserved & 15); - printf(" ... Color & Depth : %d, %d\n", pfd.cColorBits, pfd.cDepthBits); - if (pixelformat) - printf(" current pixelformat : %d\n", pixelformat); - fflush(stdout); -#endif // DEBUG_PFD - - // see if better than the one we have already: - if (pixelformat) { - // offering non-generic rendering is better (read: hardware acceleration) - if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && - (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; - // offering overlay is better: - else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} - // otherwise prefer a format that supports composition (STR #3119) - else if ((chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) && - !(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) continue; - // otherwise more bit planes is better, but no more than 32 (8 bits per channel): - else if (pfd.cColorBits > 32 || chosen_pfd.cColorBits > pfd.cColorBits) continue; - else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; - } - pixelformat = i; - chosen_pfd = pfd; - } - -#if DEBUG_PFD - static int bb = 0; - if (!bb) { - bb = 1; - printf("PFD_SUPPORT_COMPOSITION = 0x%x\n", PFD_SUPPORT_COMPOSITION); - } - printf("Chosen pixel format is %d\n", pixelformat); - printf("Color bits = %d, Depth bits = %d\n", chosen_pfd.cColorBits, chosen_pfd.cDepthBits); - printf("Pixel format supports composition: %s\n", (chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - fflush(stdout); -#endif // DEBUG_PFD - - if (!pixelformat) return 0; - - g = new Fl_WinAPI_Gl_Choice(m, alistp, first); - first = g; - - g->pixelformat = pixelformat; - g->pfd = chosen_pfd; - - return g; -} - - -GLContext Fl_WinAPI_Gl_Window_Driver::do_create_gl_context(Fl_Window* window, - const Fl_Gl_Choice* g, int layer) -{ - Fl_X* i = Fl_X::flx(window); - HDC hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc; - if (!hdc) { - hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc = GetDCEx((HWND)i->xid, 0, DCX_CACHE); - fl_save_dc((HWND)i->xid, hdc); - SetPixelFormat(hdc, ((Fl_WinAPI_Gl_Choice*)g)->pixelformat, (PIXELFORMATDESCRIPTOR*)(&((Fl_WinAPI_Gl_Choice*)g)->pfd)); -# if USE_COLORMAP - if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); -# endif - } - GLContext context = layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); - if (context) { - if (context_list && nContext) - wglShareLists((HGLRC)context_list[0], (HGLRC)context); - add_context(context); - } - return context; -} - - -GLContext Fl_WinAPI_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) -{ - return do_create_gl_context(window, g, 0); -} - -void Fl_WinAPI_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - GLContext current_context = wglGetCurrentContext(); - if (context != current_context || w != cached_window) { - cached_window = w; - wglMakeCurrent(Fl_WinAPI_Window_Driver::driver(w)->private_dc, (HGLRC)context); - } -} - -void Fl_WinAPI_Gl_Window_Driver::delete_gl_context(GLContext context) { - GLContext current_context = wglGetCurrentContext(); - if (current_context == context) { - cached_window = 0; - wglMakeCurrent(0, 0); - } - wglDeleteContext((HGLRC)context); - del_context(context); -} - - -void Fl_WinAPI_Gl_Window_Driver::make_overlay_current() { -#if HAVE_GL_OVERLAY - if (overlay() != this) { - set_gl_context(pWindow, (GLContext)overlay()); - // if (fl_overlay_depth) - // wglRealizeLayerPalette(Fl_X::flx(this)->private_dc, 1, TRUE); - } else -#endif - glDrawBuffer(GL_FRONT); -} - -void Fl_WinAPI_Gl_Window_Driver::redraw_overlay() { - pWindow->damage(FL_DAMAGE_OVERLAY); -} - -#if HAVE_GL_OVERLAY - -// Methods on Fl_Gl_Window_driver that create an overlay window. - -// Under win32 another GLX context is created to draw into the overlay -// and it is stored in the "overlay" pointer. - -// If overlay hardware is unavailable, the overlay is -// "faked" by drawing into the main layers. This is indicated by -// setting overlay == this. - -//static COLORREF *palette; -static int fl_overlay_depth = 0; - -void Fl_WinAPI_Gl_Window_Driver::gl_hide_before(void *& overlay) { - if (overlay && overlay != pWindow) { - delete_gl_context((GLContext)overlay); - overlay = 0; - } -} - -void Fl_WinAPI_Gl_Window_Driver::make_overlay(void*&overlay) { - if (overlay) return; - - GLContext context = do_create_gl_context(pWindow, g(), 1); - if (!context) {overlay = pWindow; return;} // fake the overlay - - HDC hdc = Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc; - overlay = context; - LAYERPLANEDESCRIPTOR pfd; - wglDescribeLayerPlane(hdc, g()->pixelformat, 1, sizeof(pfd), &pfd); - if (!pfd.iPixelType) { - ; // full-color overlay - } else { - fl_overlay_depth = pfd.cColorBits; // used by gl_color() - if (fl_overlay_depth > 8) fl_overlay_depth = 8; - COLORREF palette[256]; - int n = (1<<fl_overlay_depth)-1; - // copy all colors except #0 into the overlay palette: - for (int i = 0; i <= n; i++) { - uchar r,g,b; Fl::get_color((Fl_Color)i,r,g,b); - palette[i] = RGB(r,g,b); - } - // always provide black & white in the last 2 pixels: - if (fl_overlay_depth < 8) { - palette[n-1] = RGB(0,0,0); - palette[n] = RGB(255,255,255); - } - // and use it: - wglSetLayerPaletteEntries(hdc, 1, 1, n, palette+1); - wglRealizeLayerPalette(hdc, 1, TRUE); - } - pWindow->valid(0); - return; -} - -int Fl_WinAPI_Gl_Window_Driver::can_do_overlay() { - if (!g()) { - g( find(mode(), alist()) ); - if (!g()) return 0; - } - return (g()->pfd.bReserved & 15) != 0; -} - -int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) { - if (Fl_Xlib_Graphics_Driver::fl_overlay && fl_overlay_depth) { - if (fl_overlay_depth < 8) { - // only black & white produce the expected colors. This could - // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx - int size = 1<<fl_overlay_depth; - if (!i) glIndexi(size-2); - else if (i >= size-2) glIndexi(size-1); - else glIndexi(i); - } else { - glIndexi(i ? i : FL_GRAY_RAMP); - } - return 1; - } - return 0; -} - -#endif // HAVE_GL_OVERLAY - - -float Fl_WinAPI_Gl_Window_Driver::pixels_per_unit() -{ - int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); - return Fl::screen_driver()->scale(ns); -} - - -int Fl_WinAPI_Gl_Window_Driver::mode_(int m, const int *a) { - int oldmode = mode(); - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - if (!g() || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { - pWindow->hide(); - pWindow->show(); - } - } else { - g(0); - } - return 1; -} - -void Fl_WinAPI_Gl_Window_Driver::make_current_after() { -#if USE_COLORMAP - if (fl_palette) { - fl_GetDC(fl_xid(pWindow)); - SelectPalette((HDC)fl_graphics_driver->gc(), fl_palette, FALSE); - RealizePalette((HDC)fl_graphics_driver->gc()); - } -#endif // USE_COLORMAP -} - -//#define HAVE_GL_OVERLAY 1 //test only - -void Fl_WinAPI_Gl_Window_Driver::swap_buffers() { -# if HAVE_GL_OVERLAY - // Do not swap the overlay, to match GLX: - BOOL ret = wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_MAIN_PLANE); - DWORD err = GetLastError(); -# else - SwapBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc); -# endif -} - - -// Start of swap_interval implementation in the three possibel ways for X11 - -// -1 = not yet initialized, 0 = none found, 1 = GLX, 2 = MESA, 3 = SGI -static signed char swap_interval_type = -1; - -typedef const char *(WINAPI *WGL_Get_Extension_String_Proc)(); -typedef BOOL (WINAPI *WGL_Swap_Iterval_Proc)(int interval); -typedef int (WINAPI *WGL_Get_Swap_Iterval_Proc)(); - -static WGL_Swap_Iterval_Proc wglSwapIntervalEXT = NULL; -static WGL_Get_Swap_Iterval_Proc wglGetSwapIntervalEXT = NULL; - -static void init_swap_interval() { - if (swap_interval_type != -1) - return; - swap_interval_type = 0; - WGL_Get_Extension_String_Proc wglGetExtensionsStringEXT = NULL; - wglGetExtensionsStringEXT = (WGL_Get_Extension_String_Proc)wglGetProcAddress("wglGetExtensionsStringEXT"); - if (!wglGetExtensionsStringEXT) - return; - const char *extensions = wglGetExtensionsStringEXT(); - if (extensions && strstr(extensions, "WGL_EXT_swap_control")) { - wglSwapIntervalEXT = (WGL_Swap_Iterval_Proc)wglGetProcAddress("wglSwapIntervalEXT"); - wglGetSwapIntervalEXT = (WGL_Get_Swap_Iterval_Proc)wglGetProcAddress("wglGetSwapIntervalEXT"); - swap_interval_type = 1; - } -} - -void Fl_WinAPI_Gl_Window_Driver::swap_interval(int interval) { - if (swap_interval_type == -1) - init_swap_interval(); - if (swap_interval_type == 1) { - if (wglSwapIntervalEXT) - wglSwapIntervalEXT(interval); - } -} - -int Fl_WinAPI_Gl_Window_Driver::swap_interval() const { - if (swap_interval_type == -1) - init_swap_interval(); - int interval = -1; - if (swap_interval_type == 1) { - if (wglGetSwapIntervalEXT) - interval = wglGetSwapIntervalEXT(); - } - return interval; -} - -// end of swap_interval implementation - -#if HAVE_GL_OVERLAY -#endif - -int Fl_WinAPI_Gl_Window_Driver::flush_begin(char& valid_f_) { -#if HAVE_GL_OVERLAY - char save_valid_f = valid_f_; - // Draw into hardware overlay planes if they are damaged: - if (overlay() && overlay() != pWindow - && (pWindow->damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid_f & 1)) { - set_gl_context(pWindow, (GLContext)overlay()); - if (fl_overlay_depth) - wglRealizeLayerPalette(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, 1, TRUE); - glDisable(GL_SCISSOR_TEST); - glClear(GL_COLOR_BUFFER_BIT); - Fl_Xlib_Graphics_Driver::fl_overlay = 1; - draw_overlay(); - Fl_Xlib_Graphics_Driver::fl_overlay = 0; - valid_f_ = save_valid_f; - wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_OVERLAY1); - // if only the overlay was damaged we are done, leave main layer alone: - if (pWindow->damage() == FL_DAMAGE_OVERLAY) { - return 1; - } - } -#endif - return 0; -} - -void* Fl_WinAPI_Gl_Window_Driver::GetProcAddress(const char *procName) { - return (void*)wglGetProcAddress((LPCSTR)procName); -} - - -void Fl_WinAPI_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { - draw_string_legacy_get_list(str, n); -} - -int Fl_WinAPI_Gl_Window_Driver::genlistsize() { - return 0x10000; -} - -void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { - if (!fl_fontsize->listbase) { - fl_fontsize->listbase = glGenLists(genlistsize()); - } - glListBase(fl_fontsize->listbase); -} - -void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { - Fl_GDI_Font_Descriptor* gl_fd = (Fl_GDI_Font_Descriptor*)fd; - if (gl_fd->glok[r]) return; - gl_fd->glok[r] = 1; - unsigned int ii = r * 0x400; - HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid); - wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, 0x400, gl_fd->listbase+ii); - SelectObject((HDC)fl_graphics_driver->gc(), oldFid); -} - - -typedef void (WINAPI *glUseProgram_type)(GLint); -static glUseProgram_type glUseProgram_f = NULL; - -void Fl_WinAPI_Gl_Window_Driver::switch_to_GL1() { - if (!glUseProgram_f) { - glUseProgram_f = (glUseProgram_type)GetProcAddress("glUseProgram"); - } - glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_prog); - if (current_prog) glUseProgram_f(0); -} - -void Fl_WinAPI_Gl_Window_Driver::switch_back() { - if (current_prog) glUseProgram_f((GLuint)current_prog); -} - - -class Fl_WinAPI_Gl_Plugin : public Fl_WinAPI_Plugin { -public: - Fl_WinAPI_Gl_Plugin() : Fl_WinAPI_Plugin(name()) { } - const char *name() override { return "gl.winapi.fltk.org"; } - void invalidate(Fl_Window *w) override { - w->as_gl_window()->valid(0); - } -}; - - -static Fl_WinAPI_Gl_Plugin Gl_Invalidate_Plugin; - - -FL_EXPORT HGLRC fl_win32_glcontext(GLContext rc) { return (HGLRC)rc; } - -#endif // HAVE_GL diff --git a/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx deleted file mode 100644 index 06cc1e477..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx +++ /dev/null @@ -1,518 +0,0 @@ -// -// Definition of Windows Pen/Tablet event driver. -// -// Copyright 2025-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: We require Windows 8 or later features for Pen/Tablet support. -// Defining WINVER and _WIN32_WINNT to 0x0602 *may* be required on some -// Windows build platforms. Must be done before all #include's. - -#if !defined(WINVER) || (WINVER < 0x0602) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0602 -#endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0602 -#endif - -#include "src/drivers/Base/Fl_Base_Pen_Events.H" - -#include <FL/platform.H> -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include "../../Fl_Screen_Driver.H" -#include <math.h> -#include <windows.h> -#include <ole2.h> -#include <shellapi.h> -// Some versions of MinGW now require us to explicitly include winerror to get S_OK defined -#include <winerror.h> - -extern Fl_Window *fl_xmousewin; - -static constexpr uint8_t _FL_PEN = 0; // internal use -static constexpr uint8_t _FL_ERASER = 1; // internal use -static uint8_t device_type_ = _FL_PEN; - -static int _e_x_down = 0; -static int _e_y_down = 0; - -// Click counting state -static DWORD last_click_time_ = 0; -static int last_click_x_ = 0; -static int last_click_y_ = 0; -static Fl::Pen::State last_click_trigger_ = Fl::Pen::State::NONE; - -// The trait list keeps track of traits for every pen ID that appears while -// handling events. -// AppKit does not tell us what traits are available per pen or tablet, so -// we use the first 5 motion events to discover event values that are not -// the default value, and enter that knowledge into the traits database. -typedef std::map<int, Fl::Pen::Trait> TraitList; -static TraitList trait_list_; -static int trait_countdown_ { 5 }; -static int current_pen_id_ { -1 }; -static Fl::Pen::Trait current_pen_trait_ { Fl::Pen::Trait::DRIVER_AVAILABLE }; -static Fl::Pen::Trait driver_traits_ { - Fl::Pen::Trait::DRIVER_AVAILABLE | Fl::Pen::Trait::PEN_ID | - Fl::Pen::Trait::ERASER | Fl::Pen::Trait::PRESSURE | - Fl::Pen::Trait::TILT_X | - Fl::Pen::Trait::TILT_Y | Fl::Pen::Trait::TWIST - // Notably missing: PROXIMITY, BARREL_PRESSURE -}; - -// Temporary storage of event data for the driver; -static Fl::Pen::EventData ev; - - -namespace Fl { - -// namespace Private { - -// // Global mouse position at mouse down event -// extern int e_x_down; -// extern int e_y_down; - -// }; // namespace Private - -namespace Pen { - -class Windows_Driver : public Driver { -public: - Windows_Driver() = default; - //virtual void subscribe(Fl_Widget* widget) override; - //virtual void unsubscribe(Fl_Widget* widget) override; - //virtual void release() override; - virtual Trait traits() override { return driver_traits_; } - virtual Trait pen_traits(int pen_id) override { - auto it = trait_list_.find(pen_id); - if (pen_id == 0) - return current_pen_trait_; - if (it == trait_list_.end()) { - return Trait::DRIVER_AVAILABLE; - } else { - return it->second; - } - } -}; - -Windows_Driver windows_driver; -Driver& driver { windows_driver }; - -} // namespace Pen - -} // namespace Fl - - -using namespace Fl::Pen; - -/* - Copy the event state. - */ -static void copy_state() { - Fl::Pen::State tr = (Fl::Pen::State)((uint32_t)Fl::Pen::e.state ^ (uint32_t)ev.state); - Fl::Pen::e = ev; - Fl::Pen::e.trigger = tr; - Fl::e_x = (int)ev.x; - Fl::e_y = (int)ev.y; - Fl::e_x_root = (int)ev.rx; - Fl::e_y_root = (int)ev.ry; -} - -/* - Check if coordinates are within the widget box. - Coordinates are in top_window space. We iterate up the hierarchy to ensure - that we handle subwindows correctly. - */ -static bool event_inside(Fl_Widget *w, double x, double y) { - if (w->as_window()) { - return ((x >= 0) && (y >= 0) && (x < w->w()) && (y < w->h())); - } else { - return ((x >= w->x()) && (y >= w->y()) && (x < w->x() + w->w()) && (y < w->y() + w->h())); - } -} - -/* - Find the widget under the pen event. - Search the subscriber list for widgets that are inside the same window, - are visible, and are within the give coordinates. Subwindow aware. - */ -static Fl_Widget *find_below_pen(Fl_Window *win, double x, double y) { - for (auto &sub: subscriber_list_) { - Fl_Widget *candidate = sub.second->widget(); - if (candidate && ((candidate == win) || (!candidate->as_window() && candidate->window() == win))) { - if (candidate->visible() && event_inside(candidate, x, y)) { - return candidate; - } - } - } - return nullptr; -} - -/* - Send the current event and event data to a widget. - Note: we will get the wrong coordinates if the widget is not a child of - the current event window (LEAVE events between windows). - */ -static int pen_send(Fl_Widget *w, int event, State trigger, bool &copied) { - // Copy most event data only once - if (!copied) { - copy_state(); - copied = true; - } - // Copy the top_window coordinates again as they may change when w changes - Fl::e_x = e.x = ev.x; - Fl::e_y = e.y = ev.y; - // Send the event. - e.trigger = trigger; - return w->handle(event); -} - -/* - Send an event to all subscribers. - */ -static int pen_send_all(int event, State trigger) { - bool copied = false; - // use local value because handler may still change ev values - for (auto &it: subscriber_list_) { - auto w = it.second->widget(); - if (w) - pen_send(w, event, trigger, copied); - } - return 1; -} - -/* - Convert the NSEvent button number to Fl::Pen::State, - */ -static State button_to_trigger(POINTER_BUTTON_CHANGE_TYPE button, bool down) { - switch (button) { - case POINTER_CHANGE_FIRSTBUTTON_DOWN: - case POINTER_CHANGE_FIRSTBUTTON_UP: - if ( (ev.state & (State::ERASER_DOWN | State::ERASER_HOVERS)) != State::NONE ) { - return down ? State::ERASER_DOWN : State::ERASER_HOVERS; - } else { - return down ? State::TIP_DOWN : State::TIP_HOVERS; - } - case POINTER_CHANGE_SECONDBUTTON_DOWN: - case POINTER_CHANGE_SECONDBUTTON_UP: - return State::BUTTON0; - case POINTER_CHANGE_THIRDBUTTON_DOWN: - case POINTER_CHANGE_THIRDBUTTON_UP: - return State::BUTTON1; - case POINTER_CHANGE_FOURTHBUTTON_DOWN: - case POINTER_CHANGE_FOURTHBUTTON_UP: - return State::BUTTON2; - case POINTER_CHANGE_FIFTHBUTTON_DOWN: - case POINTER_CHANGE_FIFTHBUTTON_UP: - return State::BUTTON3; - default: return State::NONE; - } -} - -/* - Handle events coming from the Win32 API. - WM_TABLET (Windows 2000 and up) - WM_POINTER (Windows 8 and up) - https://learn.microsoft.com/en-us/windows/win32/inputmsg/messages-and-notifications-portal - #if(WINVER >= 0x0602) ... #endif - \return -1 if we did not handle the event and want the main event handler to call DefWindowProc() - \return any other value that will then be return from WndProc() directly. - */ -LRESULT fl_win32_tablet_handler(MSG& msg) { - auto message = msg.message; - if (message < WM_NCPOINTERUPDATE || message > WM_POINTERROUTEDRELEASED) { - return -1; - } - - Fl_Window *eventWindow = fl_find(msg.hwnd); // can be nullptr - bool is_proximity = false; - bool is_down = false; - bool is_up = false; - bool is_motion = false; - - switch (msg.message) { - case WM_NCPOINTERDOWN: // pen pushed over window decoration, don't care - case WM_NCPOINTERUP: // pen released over window decoration, don't care - case WM_NCPOINTERUPDATE: // pen moved over decoration, don't care - case WM_POINTERACTIVATE: // shall the pointer activate an inactive window? - return -1; // let the system handle this forwarding this to DefWindowProc - - case WM_POINTERENTER: // pointer moved into window area from top or sides - is_proximity = true; - break; - case WM_POINTERLEAVE: // left window area to top or sides - is_proximity = true; - break; - - - case WM_POINTERDOWN: - is_down = true; - break; - case WM_POINTERUP: - is_up = true; - break; - case WM_POINTERUPDATE: - is_motion = true; - break; - - case WM_POINTERCAPTURECHANGED: - case WM_TOUCHHITTESTING: - case WM_POINTERWHEEL: - case WM_POINTERHWHEEL: - case DM_POINTERHITTEST: - case WM_POINTERROUTEDTO: - case WM_POINTERROUTEDAWAY: - case WM_POINTERROUTEDRELEASED: - default: - // printf("Windows message: msg=0x%04X wParam=0x%08X lParam=0x%08X\n", - // msg.message, (unsigned)msg.wParam, (unsigned)msg.lParam); - return -1; - } - // printf(" msg=0x%04X wParam=0x%08X lParam=0x%08X\n", - // msg.message, (unsigned)msg.wParam, (unsigned)msg.lParam); - - POINTER_PEN_INFO info; - BOOL has_position = GetPointerPenInfo( - GET_POINTERID_WPARAM(msg.wParam), - &info - ); - // if (has_position && info.pointerInfo.ButtonChangeType!=0) { - // printf(" pointerFlags: %08x [", (unsigned)info.pointerInfo.pointerFlags); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIRSTBUTTON) printf(" 1ST"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_SECONDBUTTON) printf(" 2ND"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_THIRDBUTTON) printf(" 3RD"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FOURTHBUTTON) printf(" 4TH"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIFTHBUTTON) printf(" 5TH"); - // printf(" ]\n penFlags: %08x [", (unsigned)info.penFlags); - // if (info.penFlags & PEN_FLAG_BARREL) printf(" BARREL"); - // if (info.penFlags & PEN_FLAG_INVERTED) printf(" INVERTED"); - // if (info.penFlags & PEN_FLAG_ERASER) printf(" ERASER"); - // printf(" ]\n penMask: %08x ButtonChangeType: %d\n", - // (unsigned)info.penMask, info.pointerInfo.ButtonChangeType); - // } - - // Event has extended pen data set: - if (has_position) { - // Get the position data. - double s = Fl::screen_driver()->scale(0); - double ex = info.pointerInfo.ptPixelLocation.x/s; - double ey = info.pointerInfo.ptPixelLocation.y/s; - // Go from global coordinates to event window coordinates - Fl_Widget *p = eventWindow; - while (p) { - if (p->as_window()) { - ex -= p->x(); - ey -= p->y(); - } - p = p->parent(); - }; - ev.x = ex; - ev.y = ey; - ev.rx = info.pointerInfo.ptPixelLocation.x/s; - ev.ry = info.pointerInfo.ptPixelLocation.y/s; - if (!is_proximity) { - // Get the extended data. - if (info.penMask & PEN_MASK_PRESSURE) - ev.pressure = info.pressure / 1024.0; - if (info.penMask & PEN_MASK_TILT_X) - ev.tilt_x = -info.tiltX / 90.0; - if (info.penMask & PEN_MASK_TILT_Y) - ev.tilt_y = -info.tiltY / 90.0; - if (info.penMask & PEN_MASK_ROTATION) - ev.twist = info.rotation > 180 ? (info.rotation - 360) : info.rotation; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.proximity = 0.0; - else - ev.proximity = 1.0; - } - if (info.penFlags & PEN_FLAG_INVERTED) { - device_type_ = _FL_ERASER; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.state = State::ERASER_DOWN; - else - ev.state = State::ERASER_HOVERS; - } else { - device_type_ = _FL_PEN; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.state = State::TIP_DOWN; - else - ev.state = State::TIP_HOVERS; - } - // Add pen barrel button states - // Note: POINTER_FLAG_FIRSTBUTTON is the pen tip - // PEN_FLAG_BARREL and POINTER_FLAG_SECONDBUTTON both indicate the primary barrel button - if ((info.penFlags & PEN_FLAG_BARREL) || (info.pointerInfo.pointerFlags & POINTER_FLAG_SECONDBUTTON)) - ev.state |= State::BUTTON0; - // Note: the following code does not work very well with the Wayland driver - // More research is needed to find out how to get these button states reliably. - if (info.pointerInfo.pointerFlags & POINTER_FLAG_THIRDBUTTON) ev.state |= State::BUTTON1; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_FOURTHBUTTON) ev.state |= State::BUTTON2; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIFTHBUTTON) ev.state |= State::BUTTON3; - } - // printf(" %08x\n", (unsigned)ev.state); - if (is_proximity) { - ev.pen_id = GET_POINTERID_WPARAM(msg.wParam); - } - if ((msg.message == WM_POINTERENTER) || (msg.message == WM_POINTERLEAVE)) { - if (msg.message == WM_POINTERENTER) { - // Check if this is the first time we see this pen, or if the pen changed - if (current_pen_id_ != ev.pen_id) { - current_pen_id_ = ev.pen_id; - auto it = trait_list_.find(current_pen_id_); - if (it == trait_list_.end()) { // not found, create a new entry - trait_list_[current_pen_id_] = Trait::DRIVER_AVAILABLE; - trait_countdown_ = 5; - pen_send_all(Fl::Pen::DETECTED, State::NONE); - // printf("IN RANGE, NEW PEN\n"); - } else { - pen_send_all(Fl::Pen::CHANGED, State::NONE); - // printf("IN RANGE, CHANGED PEN\n"); - } - trait_list_[0] = trait_list_[current_pen_id_]; // set current pen traits - } else { - pen_send_all(Fl::Pen::IN_RANGE, State::NONE); - // printf("IN RANGE\n"); - } - } else { - pen_send_all(Fl::Pen::OUT_OF_RANGE, State::NONE); - // printf("OUT OF RANGE\n"); - } - } - - Fl_Widget *receiver = nullptr; - bool pushed = false; - bool event_data_copied = false; - - if (has_position) { - if (trait_countdown_) { - trait_countdown_--; - if (ev.tilt_x != 0.0) current_pen_trait_ |= Trait::TILT_X; - if (ev.tilt_y != 0.0) current_pen_trait_ |= Trait::TILT_Y; - if (ev.pressure != 1.0) current_pen_trait_ |= Trait::PRESSURE; - if (ev.barrel_pressure != 0.0) current_pen_trait_ |= Trait::BARREL_PRESSURE; - if (ev.pen_id != 0) current_pen_trait_ |= Trait::PEN_ID; - if (ev.twist != 0.0) current_pen_trait_ |= Trait::TWIST; - //if (ev.proximity != 0) current_pen_trait_ |= Trait::PROXIMITY; - trait_list_[current_pen_id_] = current_pen_trait_; - } - fl_xmousewin = eventWindow; - if (pushed_ && pushed_->widget() && (Fl::pushed() == pushed_->widget())) { - receiver = pushed_->widget(); - if (Fl::grab() && (Fl::grab() != receiver->top_window())) - return -1; - if (Fl::modal() && (Fl::modal() != receiver->top_window())) - return -1; - pushed = true; - } else { - if (Fl::grab() && (Fl::grab() != eventWindow)) - return -1; - if (Fl::modal() && (Fl::modal() != eventWindow)) - return -1; - auto bpen = below_pen_ ? below_pen_->widget() : nullptr; - auto bmouse = Fl::belowmouse(); - auto bpen_old = bmouse && (bmouse == bpen) ? bpen : nullptr; - auto bpen_now = find_below_pen(eventWindow, ev.x, ev.y); - - if (bpen_now != bpen_old) { - if (bpen_old) { - pen_send(bpen_old, Fl::Pen::LEAVE, State::NONE, event_data_copied); - } - below_pen_ = nullptr; - if (bpen_now) { - State state = (device_type_ == _FL_ERASER) ? State::ERASER_HOVERS : State::TIP_HOVERS; - if (pen_send(bpen_now, Fl::Pen::ENTER, state, event_data_copied)) { - below_pen_ = subscriber_list_[bpen_now]; - Fl::belowmouse(bpen_now); - } - } - } - - receiver = below_pen_ ? below_pen_->widget() : nullptr; - if (!receiver) - return -1; - } - } else { - // Proximity events were handled earlier. - } - - if (!receiver) - return -1; - - if (is_down) { - if (!pushed) { - pushed_ = subscriber_list_[receiver]; - Fl::pushed(receiver); - } - State trigger = button_to_trigger(info.pointerInfo.ButtonChangeType, true); - if (msg.message == WM_POINTERDOWN) { - Fl::e_is_click = 1; - _e_x_down = (int)ev.x; - _e_y_down = (int)ev.y; - - // Implement click counting using Windows system metrics - DWORD current_time = GetMessageTime(); - DWORD double_click_time = GetDoubleClickTime(); - int double_click_dx = GetSystemMetrics(SM_CXDOUBLECLK) / 2; - int double_click_dy = GetSystemMetrics(SM_CYDOUBLECLK) / 2; - - // Check if this is a multi-click: same trigger, within time and distance thresholds - if (trigger == last_click_trigger_ && - (current_time - last_click_time_) < double_click_time && - abs((int)ev.rx - last_click_x_) < double_click_dx && - abs((int)ev.ry - last_click_y_) < double_click_dy) { - Fl::e_clicks++; - } else { - Fl::e_clicks = 0; - } - - last_click_time_ = current_time; - last_click_x_ = (int)ev.rx; - last_click_y_ = (int)ev.ry; - last_click_trigger_ = trigger; - - pen_send(receiver, Fl::Pen::TOUCH, trigger, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::BUTTON_PUSH, trigger, event_data_copied); - } - } else if (is_up) { - if ( (ev.state & State::ANY_DOWN) == State::NONE ) { - Fl::pushed(nullptr); - pushed_ = nullptr; - } - State trigger = button_to_trigger(info.pointerInfo.ButtonChangeType, true); - if (info.pointerInfo.ButtonChangeType == 0) - pen_send(receiver, Fl::Pen::LIFT, trigger, event_data_copied); - else - pen_send(receiver, Fl::Pen::BUTTON_RELEASE, trigger, event_data_copied); - } else if (is_motion) { - if ( Fl::e_is_click && - ( (fabs((int)ev.x - _e_x_down) > 5) || - (fabs((int)ev.y - _e_y_down) > 5) ) ) - Fl::e_is_click = 0; - if (pushed) { - pen_send(receiver, Fl::Pen::DRAW, State::NONE, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::HOVER, State::NONE, event_data_copied); - } - } - // Always return 0 because at this point, we capture pen events and don't - // want mouse events anymore! - return 0; -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx deleted file mode 100644 index 4b74c76cb..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx +++ /dev/null @@ -1,518 +0,0 @@ -// -// Printing support for Windows for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include <FL/Fl_PDF_File_Surface.H> -#include <FL/Fl_Paged_Device.H> -#include <FL/Fl_Printer.H> -#include <FL/Fl_Native_File_Chooser.H> -#include <FL/fl_ask.H> -#include <FL/math.h> -#include <FL/fl_draw.H> -#include <FL/platform.H> // for fl_win32_xid() -#include <FL/fl_string_functions.h> // fl_strdup() -#include <commdlg.h> -#include <winspool.h> // DocumentProperties(), OpenPrinter(), ClosePrinter() - -extern HWND fl_window; - -/** Support for printing on the Windows platform */ -class Fl_WinAPI_Printer_Driver : public Fl_Paged_Device { - friend class Fl_Printer; -protected: - int abortPrint; - PRINTDLG pd; - HDC hPr; - int prerr; - int left_margin; - int top_margin; - void absolute_printable_rect(int *x, int *y, int *w, int *h); - Fl_WinAPI_Printer_Driver(void); - int begin_job(int pagecount = 0, int *frompage = NULL, int *topage = NULL, char **perr_message = NULL) FL_OVERRIDE; - int begin_page (void) FL_OVERRIDE; - int printable_rect(int *w, int *h) FL_OVERRIDE; - void margins(int *left, int *top, int *right, int *bottom) FL_OVERRIDE; - void origin(int *x, int *y) FL_OVERRIDE; - void origin(int x, int y) FL_OVERRIDE; - void scale (float scale_x, float scale_y = 0.) FL_OVERRIDE; - void rotate(float angle) FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate(void) FL_OVERRIDE; - int end_page (void) FL_OVERRIDE; - void end_job (void) FL_OVERRIDE; - ~Fl_WinAPI_Printer_Driver(void); -}; - -Fl_WinAPI_Printer_Driver::Fl_WinAPI_Printer_Driver(void) : Fl_Paged_Device() { - hPr = NULL; - driver(new Fl_GDI_Printer_Graphics_Driver); -} - -Fl_Paged_Device* Fl_Printer::newPrinterDriver(void) -{ - return new Fl_WinAPI_Printer_Driver(); -} - - -Fl_WinAPI_Printer_Driver::~Fl_WinAPI_Printer_Driver(void) { - if (hPr) end_job(); - delete driver(); -} - -static void WIN_SetupPrinterDeviceContext(HDC prHDC) -{ - if ( !prHDC ) return; - - fl_window = 0; - SetGraphicsMode(prHDC, GM_ADVANCED); // to allow for rotations - SetMapMode(prHDC, MM_ANISOTROPIC); - SetTextAlign(prHDC, TA_BASELINE|TA_LEFT); - SetBkMode(prHDC, TRANSPARENT); - // this matches 720 logical units to the number of device units in 10 inches of paper - // thus the logical unit is the point (= 1/72 inch) - SetWindowExtEx(prHDC, 720, 720, NULL); - SetViewportExtEx(prHDC, 10*GetDeviceCaps(prHDC, LOGPIXELSX), 10*GetDeviceCaps(prHDC, LOGPIXELSY), NULL); -} - - -class Fl_PDF_GDI_File_Surface : public Fl_WinAPI_Printer_Driver -{ -private: - static LPSTR pdf_printer_name_; -public: - char *doc_fname; - Fl_PDF_GDI_File_Surface(); - ~Fl_PDF_GDI_File_Surface() { if (doc_fname) free(doc_fname); } - int begin_job(const char *defaultname, - char **perr_message = NULL); - int begin_job(int, int*, int *, char **) FL_OVERRIDE {return 1;} // don't use - int begin_document(const char* outname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message); - void end_job() FL_OVERRIDE; -}; - -LPSTR Fl_PDF_GDI_File_Surface::pdf_printer_name_ = _strdup("Microsoft Print to PDF"); - -Fl_PDF_GDI_File_Surface::Fl_PDF_GDI_File_Surface() { - driver(new Fl_GDI_Graphics_Driver()); - doc_fname = NULL; -} - -Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { - Fl_PDF_GDI_File_Surface *surf = new Fl_PDF_GDI_File_Surface(); - *pfname = (const char**)&surf->doc_fname; - return surf; -} - -int Fl_PDF_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - return ((Fl_PDF_GDI_File_Surface*)platform_surface_)->begin_job(defaultfilename, perr_message); -} - -int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - return ((Fl_PDF_GDI_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message); -} - - -int Fl_PDF_GDI_File_Surface::begin_job(const char *defaultfname, char **perr_message) { - int err = 0; - abortPrint = FALSE; - - HANDLE hPr2; - err = OpenPrinterA(pdf_printer_name_, &hPr2, NULL); - if (err == 0) { - if (perr_message) { - int l = 240; - *perr_message = new char[l]; - snprintf(*perr_message, l, - "Class Fl_PDF_File_Surface requires printer '%s' available in Windows 10+.", - pdf_printer_name_); - } - return 1; - } - HWND hwndOwner = fl_win32_xid(Fl::first_window()); - LONG count = DocumentPropertiesA(hwndOwner, hPr2, pdf_printer_name_, NULL, NULL, 0); - if (count <= 0) { ClosePrinter(hPr2); return 1; } - char *buffer = new char[count]; - DEVMODEA *pDevMode = (DEVMODEA*)buffer; - memset(buffer, 0, count); - pDevMode->dmSize = (WORD)count; - count = DocumentPropertiesA(hwndOwner, hPr2, pdf_printer_name_, pDevMode, NULL, DM_OUT_BUFFER | DM_IN_PROMPT); - ClosePrinter(hPr2); - if (count == IDCANCEL || count < 0) { delete[] buffer; return 1; } - - Fl_Native_File_Chooser fnfc; - fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); - fnfc.filter("PDF\t*.pdf\n"); - if (defaultfname && strlen(defaultfname) > 0) fnfc.preset_file(defaultfname); - fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); - if (fnfc.show() == 0) this->hPr = CreateDCA(NULL, pdf_printer_name_, NULL, pDevMode); - delete[] buffer; - if (!this->hPr) return 1; - DOCINFOW di; - wchar_t docName [256]; - wchar_t outName [256]; - fl_utf8towc("FLTK", 4, docName, 256); - fl_utf8towc(fnfc.filename(), (unsigned int)strlen(fnfc.filename()), outName, 256); - memset(&di, 0, sizeof(DOCINFOW)); - di.cbSize = sizeof(DOCINFOW); - di.lpszDocName = (LPCWSTR)docName; - di.lpszOutput = (LPCWSTR)outName; - err = StartDocW(this->hPr, &di); - if (err <= 0) { - DWORD dw = GetLastError(); - DeleteDC(this->hPr); - this->hPr = NULL; - if (dw != ERROR_CANCELLED) { - if (perr_message) { - int l = 40; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Error %lu in StartDoc() call", dw); - } - return 2; - } - return 1; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext(this->hPr); - driver()->gc(this->hPr); - doc_fname = fl_strdup(fnfc.filename()); - return 0; -} - - -int Fl_PDF_GDI_File_Surface::begin_document(const char* outfname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - int err = 0; - abortPrint = FALSE; - - DEVMODEA inDevMode; - memset(&inDevMode, 0, sizeof(DEVMODEA)); inDevMode.dmSize = sizeof(DEVMODEA); - inDevMode.dmOrientation = (layout == PORTRAIT ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE); - inDevMode.dmPaperSize = (format == A4 ? DMPAPER_A4 : DMPAPER_LETTER); - inDevMode.dmFields = DM_ORIENTATION | DM_PAPERSIZE ; - - this->hPr = CreateDCA(NULL, pdf_printer_name_, NULL, &inDevMode); - if (!this->hPr) { - if (perr_message) { - int l = 150; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Class Fl_PDF_File_Surface requires printer '%s'.", - pdf_printer_name_); - } - return 2; - } - DOCINFOW di; - wchar_t docName[256]; - wchar_t outName[256]; - fl_utf8towc("FLTK", 4, docName, 256); - memset(&di, 0, sizeof(DOCINFOW)); - di.cbSize = sizeof(DOCINFOW); - di.lpszDocName = (LPCWSTR)docName; - di.lpszOutput = (LPCWSTR)outName; - fl_utf8towc(outfname, (unsigned int)strlen(outfname), outName, 256); - err = StartDocW(hPr, &di); - if (err <= 0) { - DWORD dw = GetLastError(); - DeleteDC(this->hPr); - this->hPr = NULL; - if (perr_message) { - int l = 50; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Error %lu in StartDoc() call", dw); - } - return 2; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext(this->hPr); - driver()->gc(this->hPr); - doc_fname = fl_strdup(outfname); - return 0; -} - - -int Fl_WinAPI_Printer_Driver::begin_job (int pagecount, int *frompage, int *topage, char **perr_message) -// returns 0 iff OK -{ - if (pagecount == 0) pagecount = 10000; - DOCINFO di; - char docName [256]; - int err = 0; - - abortPrint = FALSE; - memset (&pd, 0, sizeof (PRINTDLG)); - pd.lStructSize = sizeof (PRINTDLG); - pd.hwndOwner = GetForegroundWindow(); - pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION; - pd.nMinPage = 1; - pd.nMaxPage = pagecount; - BOOL b = PrintDlg (&pd); - if (pd.hwndOwner) { // restore the correct state of mouse buttons and keyboard modifier keys (STR #3221) - WNDPROC windproc = (WNDPROC)GetWindowLongPtrW(pd.hwndOwner, GWLP_WNDPROC); - CallWindowProc(windproc, pd.hwndOwner, WM_ACTIVATEAPP, 1, 0); - } - if (b != 0) { - hPr = pd.hDC; - if (hPr != NULL) { - strcpy (docName, "FLTK"); - memset(&di, 0, sizeof(DOCINFO)); - di.cbSize = sizeof (DOCINFO); - di.lpszDocName = (LPCSTR) docName; - prerr = StartDoc (hPr, &di); - if (prerr < 1) { - abortPrint = TRUE; - DWORD dw = GetLastError(); - err = (dw == ERROR_CANCELLED ? 1 : 2); - if (perr_message && err == 2) { - wchar_t *lpMsgBuf; - DWORD retval = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR) &lpMsgBuf, - 0, NULL); - if (retval) { - unsigned srclen = lstrlenW(lpMsgBuf); - while (srclen > 0 && (lpMsgBuf[srclen-1] == '\n' || lpMsgBuf[srclen-1] == '\r')) srclen--; - unsigned l = fl_utf8fromwc(NULL, 0, lpMsgBuf, srclen); - *perr_message = new char[l+51]; - snprintf(*perr_message, l+51, "begin_job() failed with error %lu: ", dw); - fl_utf8fromwc(*perr_message + strlen(*perr_message), l+1, lpMsgBuf, srclen); - LocalFree(lpMsgBuf); - } - } - } - } - } else { - err = 1; - } - if(!err) { - if((pd.Flags & PD_PAGENUMS) != 0 ) { - if (frompage) *frompage = pd.nFromPage; - if (topage) *topage = pd.nToPage; - } - else { - if (frompage) *frompage = 1; - if (topage) *topage = pagecount; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext (hPr); - driver()->gc(hPr); - } - return err; -} - -void Fl_PDF_GDI_File_Surface::end_job(void) -{ - if (hPr != NULL) { - if (! abortPrint) { - if (EndDoc (hPr) <= 0) { - fl_message ("Error in EndDoc() call"); - } - DeleteDC (hPr); - } - hPr = NULL; - } -} - -void Fl_WinAPI_Printer_Driver::end_job (void) -{ - if (hPr != NULL) { - if (! abortPrint) { - prerr = EndDoc (hPr); - if (prerr < 0) { - fl_alert ("EndDoc error %d", prerr); - } - } - DeleteDC (hPr); - if (pd.hDevMode != NULL) { - GlobalFree (pd.hDevMode); - } - if (pd.hDevNames != NULL) { - GlobalFree (pd.hDevNames); - } - } - hPr = NULL; -} - -void Fl_WinAPI_Printer_Driver::absolute_printable_rect(int *x, int *y, int *w, int *h) -{ - POINT physPageSize; - POINT pixelsPerInch; - XFORM transform; - - if (hPr == NULL) return; - HDC gc = (HDC)driver()->gc(); - GetWorldTransform(gc, &transform); - ModifyWorldTransform(gc, NULL, MWT_IDENTITY); - SetWindowOrgEx(gc, 0, 0, NULL); - - physPageSize.x = GetDeviceCaps(hPr, HORZRES); - physPageSize.y = GetDeviceCaps(hPr, VERTRES); - DPtoLP(hPr, &physPageSize, 1); - *w = physPageSize.x + 1; - *h = physPageSize.y + 1; - pixelsPerInch.x = GetDeviceCaps(hPr, LOGPIXELSX); - pixelsPerInch.y = GetDeviceCaps(hPr, LOGPIXELSY); - DPtoLP(hPr, &pixelsPerInch, 1); - left_margin = (pixelsPerInch.x / 4); - *w -= (pixelsPerInch.x / 2); - top_margin = (pixelsPerInch.y / 4); - *h -= (pixelsPerInch.y / 2); - - *x = left_margin; - *y = top_margin; - origin(x_offset, y_offset); - SetWorldTransform(gc, &transform); -} - -void Fl_WinAPI_Printer_Driver::margins(int *left, int *top, int *right, int *bottom) -{ - int x = 0, y = 0, w = 0, h = 0; - absolute_printable_rect(&x, &y, &w, &h); - if (left) *left = x; - if (top) *top = y; - if (right) *right = x; - if (bottom) *bottom = y; -} - -int Fl_WinAPI_Printer_Driver::printable_rect(int *w, int *h) -{ - int x, y; - absolute_printable_rect(&x, &y, w, h); - return 0; -} - -int Fl_WinAPI_Printer_Driver::begin_page (void) -{ - int rsult, w, h; - - rsult = 0; - if (hPr != NULL) { - Fl_Surface_Device::push_current(this); - WIN_SetupPrinterDeviceContext (hPr); - prerr = StartPage (hPr); - if (prerr < 0) { - Fl_Surface_Device::pop_current(); - fl_alert ("StartPage error %d", prerr); - rsult = 1; - } - printable_rect(&w, &h); - origin(0, 0); - fl_clip_region(0); - } - return rsult; -} - -void Fl_WinAPI_Printer_Driver::origin (int deltax, int deltay) -{ - SetWindowOrgEx( (HDC)driver()->gc(), - left_margin - deltax, - top_margin - deltay, NULL); - x_offset = deltax; - y_offset = deltay; -} - -void Fl_WinAPI_Printer_Driver::scale (float scalex, float scaley) -{ - if (scaley == 0.) scaley = scalex; - int w, h; - SetWindowExtEx((HDC)driver()->gc(), (int)(720 / scalex + 0.5), (int)(720 / scaley + 0.5), NULL); - printable_rect(&w, &h); - origin(0, 0); -} - -void Fl_WinAPI_Printer_Driver::rotate (float rot_angle) -{ - XFORM mat; - float angle; - angle = (float) - (rot_angle * M_PI / 180.); - mat.eM11 = (float)cos(angle); - mat.eM12 = (float)sin(angle); - mat.eM21 = - mat.eM12; - mat.eM22 = mat.eM11; - mat.eDx = mat.eDy = 0; - SetWorldTransform((HDC)driver()->gc(), &mat); -} - -int Fl_WinAPI_Printer_Driver::end_page (void) -{ - int rsult; - - rsult = 0; - if (hPr != NULL) { - Fl_Surface_Device::pop_current(); - prerr = EndPage (hPr); - if (prerr < 0) { - abortPrint = TRUE; - fl_alert ("EndPage error %d", prerr); - rsult = 1; - } - else { // make sure rotation is not transferred to next page - ModifyWorldTransform(hPr, NULL, MWT_IDENTITY); - } - } - return rsult; -} - -static int translate_stack_depth = 0; -const int translate_stack_max = 5; -static int translate_stack_x[translate_stack_max]; -static int translate_stack_y[translate_stack_max]; - -static void do_translate(int x, int y, HDC gc) -{ - XFORM tr; - tr.eM11 = tr.eM22 = 1; - tr.eM12 = tr.eM21 = 0; - tr.eDx = (FLOAT) x; - tr.eDy = (FLOAT) y; - ModifyWorldTransform(gc, &tr, MWT_LEFTMULTIPLY); -} - -void Fl_WinAPI_Printer_Driver::translate (int x, int y) -{ - do_translate(x, y, (HDC)driver()->gc()); - if (translate_stack_depth < translate_stack_max) { - translate_stack_x[translate_stack_depth] = x; - translate_stack_y[translate_stack_depth] = y; - translate_stack_depth++; - } -} - -void Fl_WinAPI_Printer_Driver::untranslate (void) -{ - if (translate_stack_depth > 0) { - translate_stack_depth--; - do_translate( - translate_stack_x[translate_stack_depth], - translate_stack_y[translate_stack_depth], (HDC)driver()->gc() ); - } -} - -void Fl_WinAPI_Printer_Driver::origin(int *x, int *y) -{ - Fl_Paged_Device::origin(x, y); -} - - diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H deleted file mode 100644 index b038fc5f1..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ /dev/null @@ -1,104 +0,0 @@ -// -// Windows screen interface for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_Screen_Driver.H - \brief Definition of Windows screen interface. - */ - -#ifndef FL_WINAPI_SCREEN_DRIVER_H -#define FL_WINAPI_SCREEN_DRIVER_H - -#include "../../Fl_Screen_Driver.H" -#include <windows.h> - -class Fl_Window; - - -class Fl_WinAPI_Screen_Driver : public Fl_Screen_Driver -{ -protected: - RECT screens[MAX_SCREENS]; - RECT work_area[MAX_SCREENS]; - float scale_of_screen[MAX_SCREENS]; - - static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM); - BOOL screen_cb(HMONITOR mon, HDC, LPRECT r); - int get_mouse_unscaled(int &mx, int &my); - -public: - float dpi[MAX_SCREENS][2]; - enum APP_SCALING_CAPABILITY scaling_capability; - void update_scaling_capability(); - Fl_WinAPI_Screen_Driver(); - // --- display management - int visual(int flags) FL_OVERRIDE; - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_xywh_unscaled(int &X, int &Y, int &W, int &H, int n); - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - int screen_num_unscaled(int x, int y); - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void flush() FL_OVERRIDE; - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - int dnd(int unused) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win); - int get_mouse(int &x, int &y) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - void offscreen_size(Fl_Offscreen off, int &width, int &height) FL_OVERRIDE; - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { - return scaling_capability; - } - float scale(int n) FL_OVERRIDE { - return scale_of_screen[n]; - } - void scale(int n, float f) FL_OVERRIDE { - scale_of_screen[n] = f; - } - void desktop_scale_factor() FL_OVERRIDE; - void default_icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - int clipboard_contains(const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void clipboard_notify_change() FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) FL_OVERRIDE; - // these two are implemented in Fl_get_key_win32.cxx - int event_key(int) FL_OVERRIDE; - int get_key(int) FL_OVERRIDE; - float base_scale(int numscreen) FL_OVERRIDE; -}; - - -#endif // FL_WINAPI_SCREEN_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx deleted file mode 100644 index b1ddc9f91..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ /dev/null @@ -1,493 +0,0 @@ -// -// Windows screen interface for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_WinAPI_Screen_Driver.H" -#include "../GDI/Fl_Font.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/Fl_RGB_Image.H> -#include <FL/fl_ask.H> -#include <stdio.h> - - -// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx -extern const char *fl_fg; -extern const char *fl_bg; -extern const char *fl_bg2; -// end of extern additions workaround - - -#if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500) -# define COMPILE_MULTIMON_STUBS -# include <multimon.h> -#endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500 - -static Fl_Text_Editor::Key_Binding extra_bindings[] = { - // Define Windows specific accelerators... - { 'y', FL_CTRL, Fl_Text_Editor::kf_redo ,0}, - { 0, 0, 0 ,0} -}; - - -Fl_WinAPI_Screen_Driver::Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { - text_editor_extra_key_bindings = extra_bindings; - for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1; - scaling_capability = SYSTEMWIDE_APP_SCALING; -} - -int Fl_WinAPI_Screen_Driver::visual(int flags) -{ - fl_GetDC(0); - if (flags & FL_DOUBLE) return 0; - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - if (!(flags & FL_INDEX) && - GetDeviceCaps(gc,BITSPIXEL) <= 8) return 0; - if ((flags & FL_RGB8) && GetDeviceCaps(gc,BITSPIXEL)<24) return 0; - return 1; -} - - -// We go the much more difficult route of individually picking some multi-screen -// functions from the USER32.DLL . If these functions are not available, we -// will gracefully fall back to single monitor support. -// -// If we were to insist on the existence of "EnumDisplayMonitors" and -// "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000 -// before SP2 or earlier. - -// BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM) -typedef BOOL(WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); -// BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO) -typedef BOOL(WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO); - -static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC hdc, LPRECT r, LPARAM d) -{ - Fl_WinAPI_Screen_Driver *drv = (Fl_WinAPI_Screen_Driver*)d; - return drv->screen_cb(mon, hdc, r); -} - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r) -{ - if (num_screens >= MAX_SCREENS) return TRUE; - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - - // GetMonitorInfo(mon, &mi); - // (but we use our self-acquired function pointer instead) - if (fl_gmi(mon, &mi)) { - screens[num_screens] = mi.rcMonitor; - // If we also want to record the work area, we would also store mi.rcWork at this point - work_area[num_screens] = mi.rcWork; - num_screens++; - } - return TRUE; -} - - -void Fl_WinAPI_Screen_Driver::init() -{ - open_display(); - // Since not all versions of Windows include multiple monitor support, - // we do a run-time check for the required functions... - HMODULE hMod = GetModuleHandle("USER32.DLL"); - - if (hMod) { - // check that EnumDisplayMonitors is available - fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors"); - - if (fl_edm) { - // we have EnumDisplayMonitors - do we also have GetMonitorInfoA ? - fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA"); - if (fl_gmi) { - // We have GetMonitorInfoA, enumerate all the screens... - // EnumDisplayMonitors(0,0,screen_cb,0); - // (but we use our self-acquired function pointer instead) - // NOTE: num_screens is incremented in screen_cb so we must first reset it here... - num_screens = 0; - fl_edm(0, 0, screen_cb, (LPARAM)this); - return; - } - } - } - - // If we get here, assume we have 1 monitor... - num_screens = 1; - screens[0].top = 0; - screens[0].left = 0; - screens[0].right = GetSystemMetrics(SM_CXSCREEN); - screens[0].bottom = GetSystemMetrics(SM_CYSCREEN); - work_area[0] = screens[0]; -} - - -void Fl_WinAPI_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - X = int(work_area[n].left/scale_of_screen[n]); - Y = int(work_area[n].top/scale_of_screen[n]); - W = int((work_area[n].right - work_area[n].left)/scale_of_screen[n]); - H = int((work_area[n].bottom - work_area[n].top)/scale_of_screen[n]); -} - - -void Fl_WinAPI_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - if (num_screens > 0) { - X = int(screens[n].left/scale_of_screen[n]); - Y = int(screens[n].top/scale_of_screen[n]); - W = int((screens[n].right - screens[n].left)/scale_of_screen[n]); - H = int((screens[n].bottom - screens[n].top)/scale_of_screen[n]); - } else { - /* Fallback if something is broken... */ - X = 0; - Y = 0; - W = GetSystemMetrics(SM_CXSCREEN); - H = GetSystemMetrics(SM_CYSCREEN); - } -} - - -void Fl_WinAPI_Screen_Driver::screen_xywh_unscaled(int &X, int &Y, int &W, int &H, int n) { - if (num_screens < 0) init(); - if ((n < 0) || (n >= num_screens)) n = 0; - X = screens[n].left; - Y = screens[n].top; - W = screens[n].right - screens[n].left; - H = screens[n].bottom - screens[n].top; -}; - - -void Fl_WinAPI_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - if (n >= 0 && n < num_screens) { - h = float(dpi[n][0]); - v = float(dpi[n][1]); - } -} - - -int Fl_WinAPI_Screen_Driver::x() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.left;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return X; -} - - -int Fl_WinAPI_Screen_Driver::y() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.top;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return Y; -} - - -int Fl_WinAPI_Screen_Driver::h() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.bottom - r.top;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return H; -} - - -int Fl_WinAPI_Screen_Driver::w() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.right - r.left;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return W; -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_WinAPI_Screen_Driver::beep(int type) -{ - switch (type) { - case FL_BEEP_QUESTION : - case FL_BEEP_PASSWORD : - MessageBeep(MB_ICONQUESTION); - break; - case FL_BEEP_MESSAGE : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_NOTIFICATION : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_ERROR : - MessageBeep(MB_ICONERROR); - break; - default : - MessageBeep(0xFFFFFFFF); - break; - } -} - - -void Fl_WinAPI_Screen_Driver::flush() -{ - GdiFlush(); -} - - -extern void fl_fix_focus(); // in Fl.cxx - -// We have to keep track of whether we have captured the mouse, since -// Windows shows little respect for this... Grep for fl_capture to -// see where and how this is used. -extern HWND fl_capture; - - -void Fl_WinAPI_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab_) { - SetActiveWindow(fl_capture = fl_xid(Fl::first_window())); - SetCapture(fl_capture); - } - Fl::grab_ = win; - } else { - if (Fl::grab_) { - fl_capture = 0; - ReleaseCapture(); - Fl::grab_ = 0; - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -static void getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar)) -{ - if (arg) { - uchar r,g,b; - if (!fl_parse_color(arg, r,g,b)) - Fl::error("Unknown color: %s", arg); - else - func(r,g,b); - } else { - DWORD x = GetSysColor(what); - func(uchar(x&255), uchar(x>>8), uchar(x>>16)); - } -} - - -void Fl_WinAPI_Screen_Driver::get_system_colors() -{ - if (!bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2); - if (!fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground); - if (!bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background); - getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color); -} - - -int Fl_WinAPI_Screen_Driver::compose(int &del) { - unsigned char ascii = (unsigned char)Fl::e_text[0]; - /* WARNING: The [AltGr] key on international keyboards sets FL_CTRL. - 2nd line in condition below asks [AltGr] key (a.k.a. VK_RMENU) not to be down. - */ - int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && !(ascii & 128) && - !( (Fl::e_state & FL_CTRL) && (GetAsyncKeyState(VK_RMENU) >> 15) ); - if (condition) { // this stuff is to be treated as a function key - del = 0; - return 0; - } - del = Fl::compose_state; - Fl::compose_state = 0; - // Only insert non-control characters: - if ( (!Fl::compose_state) && ! (ascii & ~31 && ascii!=127)) { - return 0; - } - return 1; -} - - -Fl_RGB_Image * // O - image or NULL if failed -Fl_WinAPI_Screen_Driver::read_win_rectangle( - int X, // I - Left position - int Y, // I - Top position - int w, // I - Width of area to read - int h, // I - Height of area to read - Fl_Window *win, // I - window to capture from or NULL to capture from current offscreen - bool may_capture_subwins, bool *did_capture_subwins) -{ - float s = Fl_Surface_Device::surface()->driver()->scale(); - int ws, hs; - if (int(s) == s) { ws = w * int(s); hs = h * int(s);} - else { - ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Fl_Scalable_Graphics_Driver::floor(X, s), - hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Fl_Scalable_Graphics_Driver::floor(Y, s); - if (ws < 1) ws = 1; - if (hs < 1) hs = 1; - } - return read_win_rectangle_unscaled(Fl_Scalable_Graphics_Driver::floor(X, s), Fl_Scalable_Graphics_Driver::floor(Y, s), ws, hs, win); -} - -Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win) -{ - // Depth of image is always 3 here - - // Grab all of the pixels in the image... - - // Assure that we are not trying to read non-existing data. If it is so, the - // function should still work, but the out-of-bounds part of the image is - // untouched (initialized with the alpha value or 0 (black), resp.). - - int ww = w; // We need the original width for output data line size - - int shift_x = 0; // X target shift if X modified - int shift_y = 0; // Y target shift if X modified - - if (X < 0) { - shift_x = -X; - w += X; - X = 0; - } - if (Y < 0) { - shift_y = -Y; - h += Y; - Y = 0; - } - - if (h < 1 || w < 1) return 0; // nothing to copy - - // Allocate and initialize the image data array - size_t arraySize = ((size_t)w * h) * 3; - uchar *p = new uchar[arraySize]; - memset(p, 0, arraySize); - - int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes) - uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB - - // fill in bitmap info for GetDIBits - - BITMAPINFO bi; - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = w; - bi.bmiHeader.biHeight = -h; // negative => top-down DIB - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 24; // 24 bits RGB - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = 0; - bi.bmiHeader.biXPelsPerMeter = 0; - bi.bmiHeader.biYPelsPerMeter = 0; - bi.bmiHeader.biClrUsed = 0; - bi.bmiHeader.biClrImportant = 0; - - // copy bitmap from original DC (Window, Fl_Offscreen, ...) - if (win && Fl_Window::current() != win) win->make_current(); - HDC gc = (HDC)fl_graphics_driver->gc(); - HDC hdc = CreateCompatibleDC(gc); - HBITMAP hbm = CreateCompatibleBitmap(gc,w,h); - - int save_dc = SaveDC(hdc); // save context for cleanup - SelectObject(hdc,hbm); // select bitmap - BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB - - // copy RGB image data to the allocated DIB - - GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS); - - // finally copy the image data to the user buffer - - for (int j = 0; j<h; j++) { - const uchar *src = dib + j * line_size; // source line - uchar *tg = p + (j + shift_y) * 3 * ww + shift_x * 3; // target line - for (int i = 0; i<w; i++) { - uchar b = *src++; - uchar g = *src++; - *tg++ = *src++; // R - *tg++ = g; // G - *tg++ = b; // B - } - } - - // free used GDI and other structures - - RestoreDC(hdc,save_dc); // reset DC - DeleteDC(hdc); - DeleteObject(hbm); - delete[] dib; // delete DIB temporary buffer - - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, 3); - rgb->alloc_array = 1; - return rgb; -} - - -void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) -{ - BITMAP bitmap; - if ( GetObject((HBITMAP)off, sizeof(BITMAP), &bitmap) ) { - width = bitmap.bmWidth; - height = bitmap.bmHeight; - } -} - -//NOTICE: returns -1 if x,y is not in any screen -int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y) -{ - int screen = -1; - if (num_screens < 0) init(); - for (int i = 0; i < num_screens; i ++) { - if (x >= screens[i].left && x < screens[i].right && - y >= screens[i].top && y < screens[i].bottom) { - screen = i; - break; - } - } - return screen; -} - - -float Fl_WinAPI_Screen_Driver::base_scale(int numscreen) { - return float(dpi[numscreen][0] / 96.); -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H deleted file mode 100644 index 016cad9fa..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H +++ /dev/null @@ -1,124 +0,0 @@ -// -// Windows system driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_System_Driver.H - \brief Definition of Windows system driver. - */ - -#ifndef FL_WINAPI_SYSTEM_DRIVER_H -#define FL_WINAPI_SYSTEM_DRIVER_H - -#include "../../Fl_System_Driver.H" -#include <stdarg.h> -#include <string.h> // strdup - -/* - Move everything here that manages the system interface. - - There is exactly one system driver. - - - filename and pathname management - - directory and file access - - system time and system timer - - multithreading - - string management - */ - -class Fl_WinAPI_System_Driver : public Fl_System_Driver -{ -public: - void warning(const char *format, va_list args) FL_OVERRIDE; - void error(const char *format, va_list args) FL_OVERRIDE; - void fatal(const char *format, va_list args) FL_OVERRIDE; - char *utf2mbcs(const char *s) FL_OVERRIDE; - char *getenv(const char *var) FL_OVERRIDE; - int putenv(const char *var) FL_OVERRIDE; - int open(const char *fnam, int oflags, int pmode) FL_OVERRIDE; - int open_ext(const char *fnam, int binary, int oflags, int pmode) FL_OVERRIDE; - FILE *fopen(const char *fnam, const char *mode) FL_OVERRIDE; - int system(const char *cmd) FL_OVERRIDE; - int execvp(const char *file, char *const *argv) FL_OVERRIDE; - int chmod(const char *fnam, int mode) FL_OVERRIDE; - int access(const char *fnam, int mode) FL_OVERRIDE; - int flstat(const char *fnam, struct stat *b) FL_OVERRIDE; - char *getcwd(char *b, int l) FL_OVERRIDE; - int chdir(const char *path) FL_OVERRIDE; - int unlink(const char *fnam) FL_OVERRIDE; - int mkdir(const char *fnam, int mode) FL_OVERRIDE; - int rmdir(const char *fnam) FL_OVERRIDE; - int rename(const char *fnam, const char *newnam) FL_OVERRIDE; - // Windows commandline argument conversion to UTF-8 - int args_to_utf8(int argc, char ** &argv) FL_OVERRIDE; - // Windows specific UTF-8 conversions - unsigned utf8towc(const char *src, unsigned srclen, wchar_t* dst, unsigned dstlen) FL_OVERRIDE; - unsigned utf8fromwc(char *dst, unsigned dstlen, const wchar_t* src, unsigned srclen) FL_OVERRIDE; - int utf8locale() FL_OVERRIDE; - unsigned utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen) FL_OVERRIDE; - unsigned utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen) FL_OVERRIDE; - - int clocale_vprintf(FILE *output, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsscanf(const char *input, const char *format, va_list args) FL_OVERRIDE; - int filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - int filename_expand(char *to,int tolen, const char *from) FL_OVERRIDE; - int filename_relative(char *to, int tolen, const char *from, const char *base) FL_OVERRIDE; - int filename_absolute(char *to, int tolen, const char *from, const char *base) FL_OVERRIDE; - int filename_isdir(const char *n) FL_OVERRIDE; - int filename_isdir_quick(const char *n) FL_OVERRIDE; - const char *filename_ext(const char *buf) FL_OVERRIDE; - int open_uri(const char *uri, char *msg, int msglen) FL_OVERRIDE; - int use_recent_tooltip_fix() FL_OVERRIDE {return 1;} - int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) FL_OVERRIDE; - int file_browser_load_directory(const char *directory, char *filename, size_t name_size, - dirent ***pfiles, Fl_File_Sort_F *sort, - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - void newUUID(char *uuidBuffer) FL_OVERRIDE; - char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor, - const char *application) FL_OVERRIDE; - void *load(const char *filename) FL_OVERRIDE; - void png_extra_rgba_processing(unsigned char *array, int w, int h) FL_OVERRIDE; - const char *next_dir_sep(const char *start) FL_OVERRIDE; - // these 3 are implemented in Fl_lock.cxx - void awake(void*) FL_OVERRIDE; - int lock() FL_OVERRIDE; - void unlock() FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void* thread_message() FL_OVERRIDE; - int file_type(const char *filename) FL_OVERRIDE; - const char *home_directory_name() FL_OVERRIDE; - const char *filesystems_label() FL_OVERRIDE { return "My Computer"; } - int backslash_as_slash() FL_OVERRIDE {return 1;} - int colon_is_drive() FL_OVERRIDE {return 1;} - int case_insensitive_filenames() FL_OVERRIDE {return 1;} - // this one is implemented in Fl_win32.cxx - const char *filename_name(const char *buf) FL_OVERRIDE; - void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void add_fd(int fd, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void remove_fd(int, int when) FL_OVERRIDE; - void remove_fd(int) FL_OVERRIDE; - void gettime(time_t *sec, int *usec) FL_OVERRIDE; - char* strdup(const char *s) FL_OVERRIDE { return ::_strdup(s); } - void lock_ring() FL_OVERRIDE; - void unlock_ring() FL_OVERRIDE; - double wait(double time_to_wait) FL_OVERRIDE; - int ready() FL_OVERRIDE; - int close_fd(int fd) FL_OVERRIDE; -}; - -#endif // FL_WINAPI_SYSTEM_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx deleted file mode 100644 index 9eab455df..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx +++ /dev/null @@ -1,1134 +0,0 @@ -// -// Definition of Windows system driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include <FL/platform.H> -#include "Fl_WinAPI_System_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_utf8.h> -#include <FL/filename.H> -#include <FL/Fl_File_Browser.H> -#include <FL/Fl_File_Icon.H> -#include "../../flstring.h" -#include <stdio.h> -#include <stdarg.h> -#include <windows.h> -#include <rpc.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/timeb.h> -#include <shellapi.h> -#include <wchar.h> -#include <process.h> -#include <locale.h> -#include <time.h> -#include <direct.h> -#include <io.h> -#include <fcntl.h> -#include <string> - -// We must define _WIN32_IE at least to 0x0500 before inclusion of 'shlobj.h' to enable -// the declaration of SHGFP_TYPE_CURRENT for some older versions of MinGW, notably -// header versions 5.3.0 and earlier, whereas 5.4.2 seems to define _WIN32_IE as needed. -#if !(defined _WIN32_IE) || (_WIN32_IE < 0x0500) -# undef _WIN32_IE -# define _WIN32_IE 0x0500 -#endif /* _WIN32_WINNT checks */ - -#include <shlobj.h> - -// function pointer for the UuidCreate Function -// RPC_STATUS RPC_ENTRY UuidCreate(UUID __RPC_FAR *Uuid); -typedef RPC_STATUS (WINAPI *uuid_func)(UUID __RPC_FAR *Uuid); - -// Apparently Borland C++ defines DIRECTORY in <direct.h>, which -// interferes with the Fl_File_Icon enumeration of the same name. -# ifdef DIRECTORY -# undef DIRECTORY -# endif // DIRECTORY - -#ifdef __CYGWIN__ -# include <mntent.h> -#endif - -// Optional helper function to debug Fl_WinAPI_System_Driver::home_directory_name() -#ifndef DEBUG_HOME_DIRECTORY_NAME -#define DEBUG_HOME_DIRECTORY_NAME 0 -#endif -#if DEBUG_HOME_DIRECTORY_NAME -static void print_env(const char *ev) { - const char *val = getenv(ev); - printf("%-30.30s = \"%s\"\n", ev, val ? val : "<null>"); - fflush(stdout); -} -#endif // DEBUG_HOME_DIRECTORY_NAME - -static inline int isdirsep(char c) { return c == '/' || c == '\\'; } - -static wchar_t *mbwbuf = NULL; -static wchar_t *wbuf = NULL; -static wchar_t *wbuf1 = NULL; - -extern "C" { - int fl_scandir(const char *dirname, struct dirent ***namelist, - int (*select)(struct dirent *), - int (*compar)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_len); -} - -/* - Convert UTF-8 string to Windows wide character encoding (UTF-16). - - This helper function is used throughout this file to convert UTF-8 - strings to Windows specific UTF-16 encoding for filenames, paths, or - other strings to be used by system functions. - - The input string can be a null-terminated string or its length can be - provided by the optional argument 'lg'. If 'lg' is omitted or less than 0 - (default = -1) the string length is determined with strlen(), otherwise - 'lg' takes precedence. Zero (0) is a valid string length (an empty string). - - The argument 'wbuf' must have been initialized with NULL or a previous - call to malloc() or realloc(). - - If the converted string doesn't fit into the allocated size of 'wbuf' or if - 'wbuf' is NULL a new buffer is allocated with realloc(). Hence the pointer - 'wbuf' can be shared among multiple calls to this function if it has been - initialized with NULL (or malloc or realloc) before the first call. - - The return value is either the old value of 'wbuf' (if the string fits) - or a pointer to the (re)allocated buffer. - - Pseudo doxygen docs (static function intentionally not documented): - - param[in] utf8 input string (UTF-8) - param[in,out] wbuf in: pointer to output string buffer or NULL - out: new string (the pointer may be changed) - param[in] lg optional: input string length (default = -1) - - returns pointer to string buffer -*/ -static wchar_t *utf8_to_wchar(const char *utf8, wchar_t *&wbuf, int lg = -1) { - unsigned len = (lg >= 0) ? (unsigned)lg : (unsigned)strlen(utf8); - unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 1; // Query length - wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * wn); - wn = fl_utf8toUtf16(utf8, len, (unsigned short *)wbuf, wn); // Convert string - wbuf[wn] = 0; - return wbuf; -} - -/* - Convert a Windows wide character (UTF-16) string to UTF-8 encoding. - - This helper function is used throughout this file to convert Windows - wide character strings as returned by system functions to UTF-8 - encoding for internal usage. - - The argument 'utf8' must have been initialized with NULL or a previous - call to malloc() or realloc(). - - If the converted string doesn't fit into the allocated size of 'utf8' or if - 'utf8' is NULL a new buffer is allocated with realloc(). Hence the pointer - 'utf8' can be shared among multiple calls to this function if it has been - initialized with NULL (or malloc or realloc) before the first call. - Ideally every call to this function has its own static pointer though. - - The return value is either the old value of 'utf8' (if the string fits) - or a pointer at the (re)allocated buffer. - - Pseudo doxygen docs (static function intentionally not documented): - - param[in] wstr input string (wide character, UTF-16) - param[in,out] utf8 in: pointer to output string buffer - out: new string (pointer may be changed) - - returns pointer to string buffer -*/ -static char *wchar_to_utf8(const wchar_t *wstr, char *&utf8) { - unsigned len = (unsigned)wcslen(wstr); - unsigned wn = fl_utf8fromwc(NULL, 0, wstr, len) + 1; // query length - utf8 = (char *)realloc(utf8, wn); - wn = fl_utf8fromwc(utf8, wn, wstr, len); // convert string - utf8[wn] = 0; - return utf8; -} - -void Fl_WinAPI_System_Driver::warning(const char *format, va_list args) { - // Show nothing for warnings under Windows... -} - -void Fl_WinAPI_System_Driver::error(const char *format, va_list args) { - char buf[1024]; - vsnprintf(buf, 1024, format, args); - MessageBox(0, buf, "Error", MB_ICONEXCLAMATION | MB_SYSTEMMODAL); -} - -void Fl_WinAPI_System_Driver::fatal(const char *format, va_list args) { - char buf[1024]; - vsnprintf(buf, 1024, format, args); - MessageBox(0, buf, "Error", MB_ICONSTOP | MB_SYSTEMMODAL); - ::exit(1); -} - -char *Fl_WinAPI_System_Driver::utf2mbcs(const char *utf8) { - static char *buf = NULL; - if (!utf8) return NULL; - - unsigned len = (unsigned)strlen(utf8); - - unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 7; // Query length - mbwbuf = (wchar_t *)realloc(mbwbuf, sizeof(wchar_t) * wn); - len = fl_utf8toUtf16(utf8, len, (unsigned short *)mbwbuf, wn); // Convert string - mbwbuf[len] = 0; - - buf = (char*)realloc(buf, len * 6 + 2); - len = (unsigned)wcstombs(buf, mbwbuf, len * 6); - buf[len] = 0; - buf[len+1] = 0; // in case the result is a UTF-16 string - return buf; -} - -char *Fl_WinAPI_System_Driver::getenv(const char *var) { - static char *buf = NULL; - wchar_t *ret = _wgetenv(utf8_to_wchar(var, wbuf)); - if (!ret) return NULL; - return wchar_to_utf8(ret, buf); -} - -int Fl_WinAPI_System_Driver::putenv(const char *var) { - unsigned len = (unsigned)strlen(var); - unsigned wn = fl_utf8toUtf16(var, len, NULL, 0) + 1; // Query length - wchar_t *wbuf = (wchar_t *)malloc(sizeof(wchar_t) * wn); - wn = fl_utf8toUtf16(var, len, (unsigned short *)wbuf, wn); - wbuf[wn] = 0; - int ret = _wputenv(wbuf); - free(wbuf); - return ret; -} - -int Fl_WinAPI_System_Driver::open(const char *fnam, int oflags, int pmode) { - utf8_to_wchar(fnam, wbuf); - if (pmode == -1) return _wopen(wbuf, oflags); - else return _wopen(wbuf, oflags, pmode); -} - -int Fl_WinAPI_System_Driver::open_ext(const char *fnam, int binary, int oflags, int pmode) { - if (oflags == 0) oflags = _O_RDONLY; - oflags |= (binary ? _O_BINARY : _O_TEXT); - return this->open(fnam, oflags, pmode); -} - -FILE *Fl_WinAPI_System_Driver::fopen(const char *fnam, const char *mode) { - utf8_to_wchar(fnam, wbuf); - utf8_to_wchar(mode, wbuf1); - return _wfopen(wbuf, wbuf1); -} - -int Fl_WinAPI_System_Driver::system(const char *cmd) { - return _wsystem(utf8_to_wchar(cmd, wbuf)); -} - -int Fl_WinAPI_System_Driver::execvp(const char *file, char *const *argv) { - int n = 0; - while (argv[n]) n++; // count args - wchar_t **ar = (wchar_t **)calloc(sizeof(wchar_t *), n + 1); - // convert arguments first; trailing NULL provided by calloc() - for (int i = 0; i < n; i++) - ar[i] = utf8_to_wchar(argv[i], ar[i]); // alloc and assign - // convert executable file and execute it ... - utf8_to_wchar(file, wbuf); - _wexecvp(wbuf, ar); // STR #3040 - // clean up (reached only if _wexecvp() failed) - for (int i = 0; i < n; i++) - free(ar[i]); - free(ar); - return -1; // STR #3040 -} - -int Fl_WinAPI_System_Driver::chmod(const char *fnam, int mode) { - return _wchmod(utf8_to_wchar(fnam, wbuf), mode); -} - -int Fl_WinAPI_System_Driver::access(const char *fnam, int mode) { - return _waccess(utf8_to_wchar(fnam, wbuf), mode); -} - -int Fl_WinAPI_System_Driver::flstat(const char *fnam, struct stat *b) { - - // remove trailing '/' or '\' - unsigned len = (unsigned)strlen(fnam); - if (len > 0 && (fnam[len-1] == '/' || fnam[len-1] == '\\')) - len--; - // convert filename and execute _wstat() - return _wstat(utf8_to_wchar(fnam, wbuf, len), (struct _stat *)b); -} - -char *Fl_WinAPI_System_Driver::getcwd(char *buf, int len) { - - static wchar_t *wbuf = NULL; - wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * (len + 1)); - wchar_t *ret = _wgetcwd(wbuf, len); - if (!ret) return NULL; - - unsigned dstlen = (unsigned)len; - len = (int)wcslen(wbuf); - dstlen = fl_utf8fromwc(buf, dstlen, wbuf, (unsigned)len); - buf[dstlen] = 0; - return buf; -} - -int Fl_WinAPI_System_Driver::chdir(const char *path) { - return _wchdir(utf8_to_wchar(path, wbuf)); -} - -int Fl_WinAPI_System_Driver::unlink(const char *fnam) { - return _wunlink(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::mkdir(const char *fnam, int mode) { - return _wmkdir(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::rmdir(const char *fnam) { - return _wrmdir(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::rename(const char *fnam, const char *newnam) { - utf8_to_wchar(fnam, wbuf); - utf8_to_wchar(newnam, wbuf1); - return _wrename(wbuf, wbuf1); -} - -// See Fl::args_to_utf8() -int Fl_WinAPI_System_Driver::args_to_utf8(int argc, char ** &argv) { - int i; - - // Convert the command line arguments to UTF-8 - LPWSTR *wideArgv = CommandLineToArgvW(GetCommandLineW(), &argc); - argv = (char **)malloc((argc + 1) * sizeof(char *)); - for (i = 0; i < argc; i++) { - // find the required size of the buffer - int u8size = WideCharToMultiByte(CP_UTF8, // CodePage - 0, // dwFlags - wideArgv[i], // lpWideCharStr - -1, // cchWideChar - NULL, // lpMultiByteStr - 0, // cbMultiByte - NULL, // lpDefaultChar - NULL); // lpUsedDefaultChar - if (u8size > 0) { - char *strbuf = (char*)::malloc(u8size); - int ret = WideCharToMultiByte(CP_UTF8, // CodePage - 0, // dwFlags - wideArgv[i], // lpWideCharStr - -1, // cchWideChar - strbuf, // lpMultiByteStr - u8size, // cbMultiByte - NULL, // lpDefaultChar - NULL); // lpUsedDefaultChar - - if (ret) { - argv[i] = strbuf; - } else { - argv[i] = _strdup(""); - ::free(strbuf); - } - } else { - argv[i] = _strdup(""); - } - } - argv[argc] = NULL; // required NULL pointer at end of list - - // Free the wide character string array - LocalFree(wideArgv); - - // Note: the allocated memory or argv[] will not be free'd by the system - // on exit. This does not constitute a memory leak. - - return argc; -} - - -// Two Windows-specific functions fl_utf8_to_locale() and fl_locale_to_utf8() -// from file fl_utf8.cxx are put here for API compatibility - -static char *buf = NULL; -static int buf_len = 0; -static unsigned short *wbufa = NULL; -unsigned int fl_codepage = 0; - - -// FIXME: This should *maybe* return 'const char *' instead of 'char *' -char *fl_utf8_to_locale(const char *s, int len, UINT codepage) -{ - if (!s) return (char *)""; - int l = 0; - unsigned wn = fl_utf8toUtf16(s, len, NULL, 0); // Query length - wn = wn * 2 + 1; - if (wn >= (unsigned)buf_len) { - buf_len = wn; - buf = (char*) realloc(buf, buf_len); - wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short)); - } - if (codepage < 1) codepage = fl_codepage; - l = fl_utf8toUtf16(s, len, wbufa, wn); // Convert string - wbufa[l] = 0; - buf[l] = 0; - l = WideCharToMultiByte(codepage, 0, (WCHAR*)wbufa, l, buf, buf_len, NULL, NULL); - if (l < 0) l = 0; - buf[l] = 0; - return buf; -} - -// FIXME: This should maybe return 'const char *' instead of 'char *' -char *fl_locale_to_utf8(const char *s, int len, UINT codepage) -{ - if (!s) return (char *)""; - int l = 0; - if (buf_len < len * 5 + 1) { - buf_len = len * 5 + 1; - buf = (char*) realloc(buf, buf_len); - wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short)); - } - if (codepage < 1) codepage = fl_codepage; - buf[l] = 0; - - l = MultiByteToWideChar(codepage, 0, s, len, (WCHAR*)wbufa, buf_len); - if (l < 0) l = 0; - wbufa[l] = 0; - l = fl_utf8fromwc(buf, buf_len, (wchar_t*)wbufa, l); - buf[l] = 0; - return buf; -} - -/////////////////////////////////// - -unsigned Fl_WinAPI_System_Driver::utf8towc(const char *src, unsigned srclen, wchar_t *dst, unsigned dstlen) { - return fl_utf8toUtf16(src, srclen, (unsigned short*)dst, dstlen); -} - -unsigned Fl_WinAPI_System_Driver::utf8fromwc(char *dst, unsigned dstlen, const wchar_t *src, unsigned srclen) { - unsigned i = 0; - unsigned count = 0; - if (dstlen) for (;;) { - unsigned ucs; - if (i >= srclen) { - dst[count] = 0; - return count; - } - ucs = src[i++]; - if (ucs < 0x80U) { - dst[count++] = ucs; - if (count >= dstlen) {dst[count-1] = 0; break;} - } else if (ucs < 0x800U) { /* 2 bytes */ - if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;} - dst[count++] = 0xc0 | (ucs >> 6); - dst[count++] = 0x80 | (ucs & 0x3F); - } else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen && - src[i] >= 0xdc00 && src[i] <= 0xdfff) { - /* surrogate pair */ - unsigned ucs2 = src[i++]; - ucs = 0x10000U + ((ucs&0x3ff)<<10) + (ucs2&0x3ff); - /* all surrogate pairs turn into 4-byte UTF-8 */ - if (count+4 >= dstlen) {dst[count] = 0; count += 4; break;} - dst[count++] = 0xf0 | (ucs >> 18); - dst[count++] = 0x80 | ((ucs >> 12) & 0x3F); - dst[count++] = 0x80 | ((ucs >> 6) & 0x3F); - dst[count++] = 0x80 | (ucs & 0x3F); - } else { - /* all others are 3 bytes: */ - if (count+3 >= dstlen) {dst[count] = 0; count += 3; break;} - dst[count++] = 0xe0 | (ucs >> 12); - dst[count++] = 0x80 | ((ucs >> 6) & 0x3F); - dst[count++] = 0x80 | (ucs & 0x3F); - } - } - /* we filled dst, measure the rest: */ - while (i < srclen) { - unsigned ucs = src[i++]; - if (ucs < 0x80U) { - count++; - } else if (ucs < 0x800U) { /* 2 bytes */ - count += 2; - } else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen-1 && - src[i+1] >= 0xdc00 && src[i+1] <= 0xdfff) { - /* surrogate pair */ - ++i; - count += 4; - } else { - count += 3; - } - } - return count; -} - -int Fl_WinAPI_System_Driver::utf8locale() -{ - static int ret = (GetACP() == CP_UTF8); - return ret; -} - -unsigned Fl_WinAPI_System_Driver::utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen) { - wchar_t lbuf[1024]; - wchar_t *buf = lbuf; - unsigned length = fl_utf8towc(src, srclen, buf, 1024); - unsigned ret; - if (length >= 1024) { - buf = (wchar_t*)(malloc((length+1)*sizeof(wchar_t))); - fl_utf8towc(src, srclen, buf, length+1); - } - if (dstlen) { - // apparently this does not null-terminate, even though msdn documentation claims it does: - ret = - WideCharToMultiByte(GetACP(), 0, buf, length, dst, dstlen, 0, 0); - dst[ret] = 0; - } - // if it overflows or measuring length, get the actual length: - if (dstlen==0 || ret >= dstlen-1) - ret = WideCharToMultiByte(GetACP(), 0, buf, length, 0, 0, 0, 0); - if (buf != lbuf) free(buf); - return ret; -} - -unsigned Fl_WinAPI_System_Driver::utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen) { - wchar_t lbuf[1024]; - wchar_t *buf = lbuf; - unsigned length; - unsigned ret; - length = MultiByteToWideChar(GetACP(), 0, src, srclen, buf, 1024); - if ((length == 0)&&(GetLastError()==ERROR_INSUFFICIENT_BUFFER)) { - length = MultiByteToWideChar(GetACP(), 0, src, srclen, 0, 0); - buf = (wchar_t*)(malloc(length*sizeof(wchar_t))); - MultiByteToWideChar(GetACP(), 0, src, srclen, buf, length); - } - ret = fl_utf8fromwc(dst, dstlen, buf, length); - if (buf != lbuf) free((void*)buf); - return ret; -} - -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) -static _locale_t c_locale = NULL; -#endif - -int Fl_WinAPI_System_Driver::clocale_vprintf(FILE *output, const char *format, va_list args) { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) - if (!c_locale) - c_locale = _create_locale(LC_NUMERIC, "C"); - int retval = _vfprintf_l(output, format, c_locale, args); -#else - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vfprintf(output, format, args); - setlocale(LC_NUMERIC, saved_locale); -#endif - return retval; -} - -int Fl_WinAPI_System_Driver::clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) - if (!c_locale) - c_locale = _create_locale(LC_NUMERIC, "C"); - int retval = _vsnprintf_l(output, output_size, format, c_locale, args); -#else - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vsnprintf(output, output_size, format, args); - setlocale(LC_NUMERIC, saved_locale); -#endif - return retval; -} - -int Fl_WinAPI_System_Driver::clocale_vsscanf(const char *input, const char *format, va_list args) { - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vsscanf(input, format, args); - setlocale(LC_NUMERIC, saved_locale); - return retval; -} - - -int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_sz) { - // For Windows we have a special scandir implementation that uses - // the Win32 "wide" functions for lookup, avoiding the code page mess - // entirely. It also fixes up the trailing '/'. - return fl_scandir(d, list, 0, sort, errmsg, errmsg_sz); -} - -int Fl_WinAPI_System_Driver::filename_expand(char *to, int tolen, const char *from) { - char *temp = new char[tolen]; - strlcpy(temp,from, tolen); - char *start = temp; - char *end = temp+strlen(temp); - int ret = 0; - for (char *a=temp; a<end; ) { // for each slash component - char *e; for (e=a; e<end && !isdirsep(*e); e++) {/*empty*/} // find next slash - const char *value = 0; // this will point at substitute value - switch (*a) { - case '~': // a home directory name - if (e <= a+1) { // current user's directory - value = home_directory_name(); - } - break; - case '$': /* an environment variable */ - {char t = *e; *(char *)e = 0; value = getenv(a+1); *(char *)e = t;} - break; - } - if (value) { - // substitutions that start with slash delete everything before them: - if (isdirsep(value[0])) start = a; - // also if it starts with "A:" - if (value[0] && value[1]==':') start = a; - int t = (int) strlen(value); if (isdirsep(value[t-1])) t--; - if ((end+1-e+t) >= tolen) end += tolen - (end+1-e+t); - memmove(a+t, e, end+1-e); - end = a+t+(end-e); - *end = '\0'; - memcpy(a, value, t); - ret++; - } else { - a = e+1; - if (*e == '\\') {*e = '/'; ret++;} // ha ha! - } - } - strlcpy(to, start, tolen); - delete[] temp; - return ret; -} - -int // O - 0 if no change, 1 if changed -Fl_WinAPI_System_Driver::filename_relative(char *to, // O - Relative filename - int tolen, // I - Size of "to" buffer - const char *dest_dir, // I - Absolute filename - const char *base_dir) // I - Find path relative to this path -{ - // Find the relative path from base_dir to dest_dir. - // Both paths must be absolute and well formed (contain no /../ and /./ segments). - - // return if any of the pointers is NULL - if (!to || !dest_dir || !base_dir) { - return 0; - } - - // if there is a drive letter, make sure both paths use the same drive - if ( (unsigned)base_dir[0] < 128 && isalpha(base_dir[0]) && base_dir[1] == ':' - && (unsigned)dest_dir[0] < 128 && isalpha(dest_dir[0]) && dest_dir[1] == ':') { - if (tolower(base_dir[0]) != tolower(dest_dir[0])) { - strlcpy(to, dest_dir, tolen); - return 0; - } - // same drive, so skip to the start of the path - base_dir += 2; - dest_dir += 2; - } - - // return if `base_dir` or `dest_dir` is not an absolute path - if (!isdirsep(*base_dir) || !isdirsep(*dest_dir)) { - strlcpy(to, dest_dir, tolen); - return 0; - } - - const char *base_i = base_dir; // iterator through the base directory string - const char *base_s = base_dir; // pointer to the last dir separator found - const char *dest_i = dest_dir; // iterator through the destination directory - const char *dest_s = dest_dir; // pointer to the last dir separator found - - // compare both path names until we find a difference - for (;;) { -#if 0 // case sensitive - base_i++; - dest_i++; - char b = *base_i, d = *dest_i; -#else // case insensitive - base_i += fl_utf8len1(*base_i); - int b = fl_tolower(fl_utf8decode(base_i, NULL, NULL)); - dest_i += fl_utf8len1(*dest_i); - int d = fl_tolower(fl_utf8decode(dest_i, NULL, NULL)); -#endif - int b0 = (b == 0) || (isdirsep(b)); - int d0 = (d == 0) || (isdirsep(d)); - if (b0 && d0) { - base_s = base_i; - dest_s = dest_i; - } - if (b == 0 || d == 0) - break; - if (b != d) - break; - } - // base_s and dest_s point at the last separator we found - // base_i and dest_i point at the first character that differs - - // test for the exact same string and return "." if so - if ( (base_i[0] == 0 || (isdirsep(base_i[0]) && base_i[1] == 0)) - && (dest_i[0] == 0 || (isdirsep(dest_i[0]) && dest_i[1] == 0))) { - strlcpy(to, ".", tolen); - return 0; - } - - // prepare the destination buffer - to[0] = '\0'; - to[tolen - 1] = '\0'; - - // count the directory segments remaining in `base_dir` - int n_up = 0; - for (;;) { - char b = *base_s++; - if (b == 0) - break; - if (isdirsep(b) && *base_s) - n_up++; - } - - // now add a "previous dir" sequence for every following slash in the cwd - if (n_up > 0) - strlcat(to, "..", tolen); - for (; n_up > 1; --n_up) - strlcat(to, "/..", tolen); - - // finally add the differing path from "from" - if (*dest_s) { - if (n_up) - strlcat(to, "/", tolen); - strlcat(to, dest_s + 1, tolen); - } - - return 1; -} - -int Fl_WinAPI_System_Driver::filename_absolute(char *to, int tolen, const char *from, const char *base) { - if (isdirsep(*from) || *from == '|' || from[1]==':' || !base) { - strlcpy(to, from, tolen); - return 0; - } - char *a; - char *temp = new char[tolen]; - const char *start = from; - strlcpy(temp, base, tolen); - for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha - /* remove trailing '/' in current working directory */ - if (isdirsep(*(a-1))) a--; - /* remove intermediate . and .. names: */ - while (*start == '.') { - if (start[1]=='.' && (isdirsep(start[2]) || start[2]==0) ) { - // found "..", remove the last directory segment form cwd - char *b; - for (b = a-1; b >= temp && !isdirsep(*b); b--) {/*empty*/} - if (b < temp) break; - a = b; - if (start[2] == 0) - start += 2; - else - start += 3; - } else if (isdirsep(start[1])) { - // found "./" in path, just skip it - start += 2; - } else if (!start[1]) { - // found "." at end of path, just skip it - start ++; - break; - } else - break; - } - *a++ = '/'; - strlcpy(a,start,tolen - (a - temp)); - strlcpy(to, temp, tolen); - delete[] temp; - return 1; -} - -int Fl_WinAPI_System_Driver::filename_isdir(const char *n) { - char fn[4]; // used for drive letter only: "X:/" - int length = (int)strlen(n); - // Strip trailing slash from name... - if (length > 0 && isdirsep(n[length - 1])) - length --; - if (length < 1) - return 0; - - // This workaround brought to you by the fine folks at Microsoft! - // (read lots of sarcasm in that...) - - if (length == 2 && isalpha(n[0]) && n[1] == ':') { // trailing '/' already "removed" - // Always use "X:/" for drive letters - fn[0] = n[0]; - strcpy(fn + 1, ":/"); - n = fn; - length = 3; - } - - // convert filename to wide chars using *length* - utf8_to_wchar(n, wbuf, length); - - DWORD fa = GetFileAttributesW(wbuf); - return (fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY); -} - -int Fl_WinAPI_System_Driver::filename_isdir_quick(const char *n) { - // Do a quick optimization for filenames with a trailing slash... - if (*n && isdirsep(n[strlen(n) - 1])) return 1; - return filename_isdir(n); -} - -const char *Fl_WinAPI_System_Driver::filename_ext(const char *buf) { - const char *q = 0; - const char *p = buf; - for (p = buf; *p; p++) { - if (isdirsep(*p) ) q = 0; - else if (*p == '.') q = p; - } - return q ? q : p; -} - -int Fl_WinAPI_System_Driver::open_uri(const char *uri, char *msg, int msglen) { - if (msg) snprintf(msg, msglen, "open %s", uri); - return (int)(ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > (void *)32); -} - -int Fl_WinAPI_System_Driver::file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, - int lname, Fl_File_Icon *icon) { - int num_files = 0; -# ifdef __CYGWIN__ - // - // Cygwin provides an implementation of setmntent() to get the list - // of available drives... - // - FILE *m = setmntent("/-not-used-", "r"); - struct mntent *p; - while ((p = getmntent (m)) != NULL) { - browser->add(p->mnt_dir, icon); - num_files ++; - } - endmntent(m); -# else - // - // Normal Windows code uses drive bits... - // - DWORD drives; // Drive available bits - drives = GetLogicalDrives(); - for (int i = 'A'; i <= 'Z'; i ++, drives >>= 1) { - if (drives & 1) { - snprintf(filename, lname, "%c:/", i); - if (i < 'C') // see also: GetDriveType and GetVolumeInformation in Windows - browser->add(filename, icon); - else - browser->add(filename, icon); - num_files ++; - } - } -# endif // __CYGWIN__ - return num_files; -} - -int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory, char *filename, - size_t name_size, dirent ***pfiles, - Fl_File_Sort_F *sort, - char *errmsg, int errmsg_sz) -{ - strlcpy(filename, directory, name_size); - int i = (int) (strlen(filename) - 1); - if (i == 2 && filename[1] == ':' && - (filename[2] == '/' || filename[2] == '\\')) - filename[2] = '/'; - else if (filename[i] != '/' && filename[i] != '\\') - strlcat(filename, "/", name_size); - return filename_list(filename, pfiles, sort, errmsg, errmsg_sz); -} - -void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer) -{ - // First try and use the win API function UuidCreate(), but if that is not - // available, fall back to making something up from scratch. - // We do not want to link against the Rpcrt4.dll, as we will rarely use it, - // so we load the DLL dynamically, if it is available, and work from there. - static HMODULE hMod = NULL; - UUID ud; - UUID *pu = &ud; - int got_uuid = 0; - - if (!hMod) { // first time in? - hMod = LoadLibrary("Rpcrt4.dll"); - } - - if (hMod) { // do we have a usable handle to Rpcrt4.dll? - uuid_func uuid_crt = (uuid_func)GetProcAddress(hMod, "UuidCreate"); - if (uuid_crt != NULL) { - RPC_STATUS rpc_res = uuid_crt(pu); - if ( // is the return status OK for our needs? - (rpc_res == RPC_S_OK) || // all is well - (rpc_res == RPC_S_UUID_LOCAL_ONLY) || // only unique to this machine - (rpc_res == RPC_S_UUID_NO_ADDRESS) // probably only locally unique - ) { - got_uuid = -1; - snprintf(uuidBuffer, 36+1, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - pu->Data1, pu->Data2, pu->Data3, pu->Data4[0], pu->Data4[1], - pu->Data4[2], pu->Data4[3], pu->Data4[4], - pu->Data4[5], pu->Data4[6], pu->Data4[7]); - } - } - } - if (got_uuid == 0) { // did not make a UUID - use fallback logic - unsigned char b[16]; - time_t t = time(0); // first 4 byte - b[0] = (unsigned char)t; - b[1] = (unsigned char)(t>>8); - b[2] = (unsigned char)(t>>16); - b[3] = (unsigned char)(t>>24); - int r = rand(); // four more bytes - b[4] = (unsigned char)r; - b[5] = (unsigned char)(r>>8); - b[6] = (unsigned char)(r>>16); - b[7] = (unsigned char)(r>>24); - // Now we try to find 4 more "random" bytes. We extract the - // lower 4 bytes from the address of t - it is created on the - // stack so *might* be in a different place each time... - // This is now done via a union to make it compile OK on 64-bit systems. - union { void *pv; unsigned char a[sizeof(void*)]; } v; - v.pv = (void *)(&t); - // NOTE: This assume that all WinXX systems are little-endian - b[8] = v.a[0]; - b[9] = v.a[1]; - b[10] = v.a[2]; - b[11] = v.a[3]; - TCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; // only used to make last four bytes - DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1; - // GetComputerName() does not depend on any extra libs, and returns something - // analogous to gethostname() - GetComputerName(name, &nSize); - // use the first 4 TCHAR's of the name to create the last 4 bytes of our UUID - for (int ii = 0; ii < 4; ii++) { - b[12 + ii] = (unsigned char)name[ii]; - } - snprintf(uuidBuffer, 36+1, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]); - } -} - -/* - Note: `prefs` can be NULL! - */ -char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, const char *vendor, - const char *application) -{ - static char *filename = 0L; - // make enough room for a UTF-16 pathname - if (!filename) filename = (char*)::malloc(2 * FL_PATH_MAX); - HRESULT res; - - // https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw - - int appdata = CSIDL_APPDATA; // assume user preferences - if ((root & Fl_Preferences::ROOT_MASK) == Fl_Preferences::SYSTEM) - appdata = CSIDL_COMMON_APPDATA; // use system preferences - - res = SHGetFolderPathW(NULL, // hwnd: Reserved! - appdata, // csidl: User or common Application Data (Roaming) - NULL, // hToken (unused) - SHGFP_TYPE_CURRENT, // dwFlags: use current, potentially redirected path - (LPWSTR)filename); // out: filename in Windows wide string encoding - if (res != S_OK) { - // don't write data into some arbitrary directory! Just return NULL. - return 0L; - } - - // convert the path from Windows wide character (UTF-16) to UTF-8 - // FIXME: can this be simplified? Don't allocate/copy/move/free more than necessary! - char *buf = NULL; - wchar_to_utf8((wchar_t *)filename, buf); // allocates buf for conversion - strcpy(filename, buf); - free(buf); - - // Make sure that the parameters are not NULL - if ( (vendor==0L) || (vendor[0]==0) ) - vendor = "unknown"; - if ( (application==0L) || (application[0]==0) ) - application = "unknown"; - - // append vendor, application, and ".prefs", and convert '\' to '/' - snprintf(filename + strlen(filename), FL_PATH_MAX - strlen(filename), - "/%s/%s.prefs", vendor, application); - for (char *s = filename; *s; s++) if (*s == '\\') *s = '/'; - return filename; -} - -void *Fl_WinAPI_System_Driver::load(const char *filename) { - return LoadLibraryW(utf8_to_wchar(filename, wbuf)); -} - -void Fl_WinAPI_System_Driver::png_extra_rgba_processing(unsigned char *ptr, int w, int h) -{ - // Some Windows graphics drivers don't honor transparency when RGB == white - // Convert RGB to 0 when alpha == 0... - for (int i = w * h; i > 0; i --, ptr += 4) { - if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0; - } -} - -const char *Fl_WinAPI_System_Driver::next_dir_sep(const char *start) -{ - const char *p = strchr(start, '/'); - if (!p) p = strchr(start, '\\'); - return p; -} - -int Fl_WinAPI_System_Driver::file_type(const char *filename) -{ - int filetype; - if (filename[strlen(filename) - 1] == '/') - filetype = Fl_File_Icon::DIRECTORY; - else if (filename_isdir(filename)) - filetype = Fl_File_Icon::DIRECTORY; - else - filetype = Fl_File_Icon::PLAIN; - return filetype; -} - -// Note: the result is cached in a static variable -const char *Fl_WinAPI_System_Driver::home_directory_name() -{ - static std::string home; - if (!home.empty()) - return home.c_str(); - -#if (DEBUG_HOME_DIRECTORY_NAME) - print_env("HOMEDRIVE"); - print_env("HOMEPATH"); - print_env("UserProfile"); - print_env("HOME"); -#endif - - // Implement various ways to retrieve the HOME path. - // Note, from `man getenv`: - // "The implementation of getenv() is not required to be reentrant. - // The string pointed to by the return value of getenv() may be statically - // allocated, and can be modified by a subsequent call to getenv()...". - // Tests show that this is the case in some MinGW implementations. - - if (home.empty()) { - const char *home_drive = getenv("HOMEDRIVE"); - if (home_drive) { - home = home_drive; // copy *before* calling getenv() again, see above - const char *home_path = getenv("HOMEPATH"); - if (home_path) { - home.append(home_path); - } else { - home.clear(); // reset - } // home_path - } // home_drive - } // empty() - - if (home.empty()) { - const char *h = getenv("UserProfile"); - if (h) - home = h; - } - - if (home.empty()) { - const char *h = getenv("HOME"); - if (h) - home = h; - } - if (home.empty()) { - home = "~/"; // last resort - } - // Make path canonical. - for (char& c : home) { - if (c == '\\') - c = '/'; - } -#if (DEBUG_HOME_DIRECTORY_NAME) - printf("home_directory_name() returns \"%s\"\n", home.c_str()); - fflush(stdout); -#endif - return home.c_str(); -} - -void Fl_WinAPI_System_Driver::gettime(time_t *sec, int *usec) { - struct _timeb t; - _ftime(&t); - *sec = t.time; - *usec = t.millitm * 1000; -} - -// -// Code for lock support -// - -// These pointers are in Fl_win32.cxx: -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); - -// The main thread's ID -static DWORD main_thread; - -// Microsoft's version of a MUTEX... -static CRITICAL_SECTION cs; -static CRITICAL_SECTION *cs_ring; - -void Fl_WinAPI_System_Driver::unlock_ring() { - LeaveCriticalSection(cs_ring); -} - -void Fl_WinAPI_System_Driver::lock_ring() { - if (!cs_ring) { - cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION)); - InitializeCriticalSection(cs_ring); - } - EnterCriticalSection(cs_ring); -} - -// -// 'unlock_function()' - Release the lock. -// - -static void unlock_function() { - LeaveCriticalSection(&cs); -} - -// -// 'lock_function()' - Get the lock. -// - -static void lock_function() { - EnterCriticalSection(&cs); -} - -int Fl_WinAPI_System_Driver::lock() { - if (!main_thread) InitializeCriticalSection(&cs); - - lock_function(); - - if (!main_thread) { - fl_lock_function = lock_function; - fl_unlock_function = unlock_function; - main_thread = GetCurrentThreadId(); - } - return 0; -} - -void Fl_WinAPI_System_Driver::unlock() { - unlock_function(); -} - -void Fl_WinAPI_System_Driver::awake(void* msg) { - PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0); -} - -int Fl_WinAPI_System_Driver::close_fd(int fd) { - return _close(fd); -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H deleted file mode 100644 index 3cf26b67c..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H +++ /dev/null @@ -1,131 +0,0 @@ -// -// Definition of Windows window driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_Window_Driver.H - \brief Definition of Windows window driver. - */ - -#ifndef FL_WINAPI_WINDOW_DRIVER_H -#define FL_WINAPI_WINDOW_DRIVER_H - -#include <FL/Fl_Plugin.H> -#include "../../Fl_Window_Driver.H" -#include <windows.h> - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - - ? where do we handle the interface between OpenGL/DirectX and Cocoa/Windows/Glx? - */ - - - -class Fl_WinAPI_Window_Driver : public Fl_Window_Driver -{ - struct icon_data { - const void *legacy_icon; - Fl_RGB_Image **icons; - int count; - HICON big_icon; - HICON small_icon; - }; - struct shape_data_type { - int lw_; ///< width of shape image - int lh_; ///< height of shape image - Fl_Image* shape_; ///< shape image - Fl_Bitmap *effective_bitmap_; ///< auxiliary bitmap image - } *shape_data_; -private: - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) FL_OVERRIDE; -public: - Fl_WinAPI_Window_Driver(Fl_Window*); - ~Fl_WinAPI_Window_Driver(); - static inline Fl_WinAPI_Window_Driver* driver(const Fl_Window *w) {return (Fl_WinAPI_Window_Driver*)Fl_Window_Driver::driver(w);} - HDC private_dc; // used for OpenGL - RECT border_width_title_bar_height(int &bx, int &by, int &bt); - - struct icon_data *icon_; - HCURSOR cursor; - int custom_cursor; - void set_minmax(LPMINMAXINFO minmax); - int fake_X_wm(int &X, int &Y, int &bt, int &bx, int &by, DWORD style = 0, DWORD styleEx = 0); - void make_fullscreen(int X, int Y, int W, int H); - // --- window data - int decorated_w() FL_OVERRIDE; - int decorated_h() FL_OVERRIDE; - const Fl_Image* shape() FL_OVERRIDE; - - // --- window management - void makeWindow() FL_OVERRIDE; - void size_range() FL_OVERRIDE { - // currently nothing to do - } - void flush_double() FL_OVERRIDE; - void flush_overlay() FL_OVERRIDE; - void draw_begin() FL_OVERRIDE; - void make_current() FL_OVERRIDE; - void show() FL_OVERRIDE; - void label(const char *name,const char *iname) FL_OVERRIDE; - void resize(int X,int Y,int W,int H) FL_OVERRIDE; - void hide() FL_OVERRIDE; - void map() FL_OVERRIDE; - void unmap() FL_OVERRIDE; - void fullscreen_on() FL_OVERRIDE; - void fullscreen_off(int X, int Y, int W, int H) FL_OVERRIDE; - void maximize() FL_OVERRIDE; - void un_maximize() FL_OVERRIDE; - bool maximize_needs_hide() FL_OVERRIDE { return true; } - void iconize() FL_OVERRIDE; - void decoration_sizes(int *top, int *left, int *right, int *bottom) FL_OVERRIDE; - // --- window cursor stuff - int set_cursor(Fl_Cursor) FL_OVERRIDE; - int set_cursor(const Fl_RGB_Image*, int, int) FL_OVERRIDE; - - void shape(const Fl_Image* img) FL_OVERRIDE; - void icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - const void *icon() const FL_OVERRIDE; - void icon(const void * ic) FL_OVERRIDE; - void free_icons() FL_OVERRIDE; - void set_icons(); // driver-internal support function - // this one is implemented in Fl_win32.cxx - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) FL_OVERRIDE; - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) FL_OVERRIDE; -}; - - -class Fl_WinAPI_Plugin : public Fl_Plugin { -public: - Fl_WinAPI_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "winapi.fltk.org"; } - virtual const char *name() = 0; - virtual void invalidate(Fl_Window*) = 0; -}; - - -#endif // FL_WINAPI_WINDOW_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx deleted file mode 100644 index 4b27753bf..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx +++ /dev/null @@ -1,731 +0,0 @@ -// -// Definition of Windows window driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Image.H> -#include <FL/Fl_Bitmap.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_Overlay_Window.H> -#include <FL/platform.H> -#include "Fl_WinAPI_Window_Driver.H" -#include "Fl_WinAPI_Screen_Driver.H" -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include <windows.h> -#include <ole2.h> -#include <math.h> // for ceil() - -#if USE_COLORMAP -extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx -#endif - - -Fl_WinAPI_Window_Driver::Fl_WinAPI_Window_Driver(Fl_Window *win) -: Fl_Window_Driver(win) -{ - icon_ = new icon_data; - shape_data_ = NULL; - memset(icon_, 0, sizeof(icon_data)); - cursor = NULL; - screen_num_ = -1; -} - - -Fl_WinAPI_Window_Driver::~Fl_WinAPI_Window_Driver() -{ - if (shape_data_) { - delete shape_data_->effective_bitmap_; - delete shape_data_; - } - delete icon_; -} - - -//FILE*LOG=fopen("log.log","w"); - - -RECT // frame of the decorated window in screen coordinates - Fl_WinAPI_Window_Driver::border_width_title_bar_height( - int &bx, // left and right border width - int &by, // bottom border height (=bx) - int &bt // height of window title bar - ) -{ - Fl_Window *win = pWindow; - RECT r = {0,0,0,0}; - bx = by = bt = 0; - if (win->shown() && !win->parent() && win->border() && win->visible()) { - static HMODULE dwmapi_dll = LoadLibrary("dwmapi.dll"); - typedef HRESULT (WINAPI* DwmGetWindowAttribute_type)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); - static DwmGetWindowAttribute_type DwmGetWindowAttribute = dwmapi_dll ? - (DwmGetWindowAttribute_type)GetProcAddress(dwmapi_dll, "DwmGetWindowAttribute") : NULL; - int need_r = 1; - if (DwmGetWindowAttribute) { - const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9; - if ( DwmGetWindowAttribute(fl_xid(win), DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK ) { - need_r = 0; - } - } - if (need_r) { - GetWindowRect(fl_xid(win), &r); - } - int width, height; - RECT rc; - GetClientRect(fl_xid(win), &rc); - width = rc.right; - height = rc.bottom; - bx = (r.right - r.left - width)/2; - if (bx < 1) bx = 1; - by = bx; - bt = r.bottom - r.top - height - 2 * by; - } - return r; -} - - -// --- window data - -int Fl_WinAPI_Window_Driver::decorated_w() -{ - int bt, bx, by; - float s = Fl::screen_driver()->scale(screen_num()); - border_width_title_bar_height(bx, by, bt); - int mini_bx = int(bx/s); if (mini_bx < 1) mini_bx = 1; - return w() + 2 * mini_bx; -} - -int Fl_WinAPI_Window_Driver::decorated_h() -{ - int bt, bx, by; - border_width_title_bar_height(bx, by, bt); - float s = Fl::screen_driver()->scale(screen_num()); - int mini_by = int(by / s); if (mini_by < 1) mini_by = 1; - return h() + int((bt + by) / s) + mini_by; -} - - -// --- window management - - - -void Fl_WinAPI_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->shape_ = b; -} - -void Fl_WinAPI_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, j, d = img->d(), w = img->w(), h = img->h(), bytesperrow = (w+7)/8; - unsigned u; - uchar byte, onebit; - // build an Fl_Bitmap covering the non-fully transparent/black part of the image - const uchar* bits = new uchar[h*bytesperrow]; // to store the bitmap - const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of rgba pixels - for (i = 0; i < h; i++) { - uchar *p = (uchar*)bits + i * bytesperrow; - byte = 0; - onebit = 1; - for (j = 0; j < w; j++) { - if (d == 3) { - u = *alpha; - u += *(alpha+1); - u += *(alpha+2); - } - else u = *alpha; - if (u > 0) { // if the pixel is not fully transparent/black - byte |= onebit; // turn on the corresponding bit of the bitmap - } - onebit = onebit << 1; // move the single set bit one position to the left - if (onebit == 0 || j == w-1) { - onebit = 1; - *p++ = byte; // store in bitmap one pack of bits - byte = 0; - } - alpha += d; // point to alpha value of next pixel - } - } - Fl_Bitmap* bitmap = new Fl_Bitmap(bits, w, h); - bitmap->alloc_array = 1; - shape_bitmap_(bitmap); - shape_data_->effective_bitmap_ = bitmap; - shape_data_->shape_ = img; -} - -void Fl_WinAPI_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->effective_bitmap_) { delete shape_data_->effective_bitmap_; } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - pWindow->border(false); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); -} - - -static inline BYTE bit(int x) { return (BYTE)(1 << (x%8)); } - -static HRGN bitmap2region(Fl_Image* image) { - HRGN hRgn = 0; - /* Does this need to be dynamically determined, perhaps? */ - const int ALLOC_UNIT = 100; - DWORD maxRects = ALLOC_UNIT; - - RGNDATA* pData = (RGNDATA*)malloc(sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRects)); - pData->rdh.dwSize = sizeof(RGNDATAHEADER); - pData->rdh.iType = RDH_RECTANGLES; - pData->rdh.nCount = pData->rdh.nRgnSize = 0; - SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); - - const int bytesPerLine = (image->w() + 7)/8; - BYTE* p, *data = (BYTE*)*image->data(); - for (int y = 0; y < image->h(); y++) { - // each row, left to right - for (int x = 0; x < image->w(); x++) { - int x0 = x; - while (x < image->w()) { - p = data + x / 8; - if (!((*p) & bit(x))) break; // transparent pixel - x++; - } - if (x > x0) { - RECT *pr; - /* Add the pixels (x0, y) to (x, y+1) as a new rectangle - * in the region - */ - if (pData->rdh.nCount >= maxRects) { - maxRects += ALLOC_UNIT; - pData = (RGNDATA*)realloc(pData, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects)); - } - pr = (RECT*)&pData->Buffer; - SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1); - if (x0 < pData->rdh.rcBound.left) - pData->rdh.rcBound.left = x0; - if (y < pData->rdh.rcBound.top) - pData->rdh.rcBound.top = y; - if (x > pData->rdh.rcBound.right) - pData->rdh.rcBound.right = x; - if (y+1 > pData->rdh.rcBound.bottom) - pData->rdh.rcBound.bottom = y+1; - pData->rdh.nCount++; - /* On Windows98, ExtCreateRegion() may fail if the - * number of rectangles is too large (ie: > - * 4000). Therefore, we have to create the region by - * multiple steps. - */ - if (pData->rdh.nCount == 2000) { - HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects), pData); - if (hRgn) { - CombineRgn(hRgn, hRgn, h, RGN_OR); - DeleteObject(h); - } else - hRgn = h; - pData->rdh.nCount = 0; - SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); - } - } - } - /* Go to next row */ - data += bytesPerLine; - } - /* Create or extend the region with the remaining rectangles*/ - HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects), pData); - if (hRgn) { - CombineRgn(hRgn, hRgn, h, RGN_OR); - DeleteObject(h); - } else hRgn = h; - free(pData); // I've created the region so I can free this now, right? - return hRgn; -} - - -void Fl_WinAPI_Window_Driver::draw_begin() -{ - if (shape_data_) { - float s = Fl::screen_driver()->scale(screen_num()); - if ((shape_data_->lw_ != s*w() || shape_data_->lh_ != s*h()) && shape_data_->shape_) { - // size of window has changed since last time - shape_data_->lw_ = int(s * w()); - shape_data_->lh_ = int(s * h()); - Fl_Image* temp = shape_data_->effective_bitmap_ ? shape_data_->effective_bitmap_ : shape_data_->shape_; - temp = temp->copy(shape_data_->lw_, shape_data_->lh_); - HRGN region = bitmap2region(temp); - SetWindowRgn(fl_xid(pWindow), region, TRUE); // the system deletes the region when it's no longer needed - delete temp; - } - } -} - - -void Fl_WinAPI_Window_Driver::flush_double() -{ - if (!shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - Fl_X *i = Fl_X::flx(pWindow); - if (!i) return; // window not yet created - - if (!other_xid) { - other_xid = new Fl_Image_Surface(w(), h(), 1); - pWindow->clear_damage(FL_DAMAGE_ALL); - } - if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { - fl_clip_region(i->region); i->region = 0; -#if 0 /* Short form that transiently changes the current Fl_Surface_Device */ - Fl_Surface_Device::push_current(other_xid); - fl_graphics_driver->clip_region( 0 ); - draw(); - Fl_Surface_Device::pop_current(); -#else - /* Alternative form that avoids changing the current Fl_Surface_Device. - The code run in the window draw() method can call Fl_Surface_Device::surface() - and conclude that it's drawing to the display, which is ultimately true - for an Fl_Double_Window. - */ - HDC sgc = fl_gc; - fl_gc = fl_makeDC((HBITMAP)other_xid->offscreen()); - int savedc = SaveDC(fl_gc); - fl_graphics_driver->gc(fl_gc); - fl_graphics_driver->restore_clip(); // duplicate clip region into new gc -# if defined(FLTK_HAVE_CAIROEXT) - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -# endif - draw(); - RestoreDC(fl_gc, savedc); - DeleteDC(fl_gc); - fl_graphics_driver->gc(sgc); -#endif - } - int X = 0, Y = 0, W = 0, H = 0; - fl_clip_box(0, 0, w(), h(), X, Y, W, H); - if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid->offscreen(), X, Y); -} - - -void Fl_WinAPI_Window_Driver::flush_overlay() -{ - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - - if (!shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - Fl_X *i = Fl_X::flx(pWindow); - if (!i) return; // window not yet created - - int eraseoverlay = (pWindow->damage()&FL_DAMAGE_OVERLAY); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - - if (!other_xid) { - other_xid = new Fl_Image_Surface(w(), h(), 1); - pWindow->clear_damage(FL_DAMAGE_ALL); - } - if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { - fl_clip_region(i->region); i->region = 0; - Fl_Surface_Device::push_current(other_xid); - fl_graphics_driver->clip_region(0); - draw(); - Fl_Surface_Device::pop_current(); - } - - if (eraseoverlay) fl_clip_region(0); - int X, Y, W, H; fl_clip_box(0, 0, w(), h(), X, Y, W, H); - if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid->offscreen(), X, Y); - - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -void Fl_WinAPI_Window_Driver::icons(const Fl_RGB_Image *icons[], int count) { - free_icons(); - - if (count > 0) { - icon_->icons = new Fl_RGB_Image*[count]; - icon_->count = count; - // FIXME: Fl_RGB_Image lacks const modifiers on methods - for (int i = 0;i < count;i++) { - icon_->icons[i] = (Fl_RGB_Image*)((Fl_RGB_Image*)icons[i])->copy(); - icon_->icons[i]->normalize(); - } - } - - if (Fl_X::flx(pWindow)) - set_icons(); -} - -const void *Fl_WinAPI_Window_Driver::icon() const { - return icon_->legacy_icon; -} - -void Fl_WinAPI_Window_Driver::icon(const void * ic) { - free_icons(); - icon_->legacy_icon = ic; -} - -void Fl_WinAPI_Window_Driver::free_icons() { - int i; - icon_->legacy_icon = 0L; - if (icon_->icons) { - for (i = 0;i < icon_->count;i++) - delete icon_->icons[i]; - delete [] icon_->icons; - icon_->icons = 0L; - } - icon_->count = 0; - if (icon_->big_icon) - DestroyIcon(icon_->big_icon); - if (icon_->small_icon) - DestroyIcon(icon_->small_icon); - icon_->big_icon = NULL; - icon_->small_icon = NULL; -} - - -void Fl_WinAPI_Window_Driver::make_current() { - fl_GetDC(fl_xid(pWindow)); - -#if USE_COLORMAP - // Windows maintains a hardware and software color palette; the - // SelectPalette() call updates the current soft->hard mapping - // for all drawing calls, so we must select it here before any - // code does any drawing... - fl_select_palette(); -#endif // USE_COLORMAP - - fl_graphics_driver->clip_region(0); - ((Fl_GDI_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num())); -#if defined(FLTK_HAVE_CAIROEXT) - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -#endif -} - -void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) { - if (shown() && !parent()) { - if (!name) name = ""; - size_t l = strlen(name); - // WCHAR *lab = (WCHAR*) malloc((l + 1) * sizeof(short)); - // l = fl_utf2unicode((unsigned char*)name, l, (wchar_t*)lab); - unsigned wlen = fl_utf8toUtf16(name, (unsigned) l, NULL, 0); // Pass NULL to query length - wlen++; - unsigned short * lab = (unsigned short*)malloc(sizeof(unsigned short)*wlen); - wlen = fl_utf8toUtf16(name, (unsigned) l, lab, wlen); - lab[wlen] = 0; - SetWindowTextW(fl_xid(pWindow), (WCHAR *)lab); - free(lab); - } -} - - -extern void fl_clipboard_notify_retarget(HWND wnd); -extern void fl_update_clipboard(void); -extern char fl_i_own_selection[2]; - -void Fl_WinAPI_Window_Driver::hide() { - Fl_X* ip = Fl_X::flx(pWindow); - // STR#3079: if there remains a window and a non-modal window, and the window is deleted, - // the app remains running without any apparent window. - // Bug mechanism: hiding an owner window unmaps the owned (non-modal) window(s) - // but does not delete it(them) in FLTK. - // Fix for it: - // when hiding a window, build list of windows it owns, and do hide/show on them. - int count = 0; - Fl_Window *win, **doit = NULL; - for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { - if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == (HWND)ip->xid) { - count++; - } - } - if (count) { - doit = new Fl_Window*[count]; - count = 0; - for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { - if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == (HWND)ip->xid) { - doit[count++] = win; - } - } - } - - if (hide_common()) { - delete[] doit; // note: `count` and `doit` may be NULL (see PR #241) - return; - } - - // Issue #569: undo RegisterDragDrop() - RevokeDragDrop((HWND)ip->xid); - - fl_i_own_selection[1] = 0; // issue #1233 - - // make sure any custom icons get freed - // icons(NULL, 0); // free_icons() is called by the Fl_Window destructor - // this little trick keeps the current clipboard alive, even if we are about - // to destroy the window that owns the selection. - if (GetClipboardOwner() == (HWND)ip->xid) - fl_update_clipboard(); - // Make sure we unlink this window from the clipboard chain - fl_clipboard_notify_retarget((HWND)ip->xid); - // Send a message to myself so that I'll get out of the event loop... - PostMessage((HWND)ip->xid, WM_APP, 0, 0); - if (private_dc) fl_release_dc((HWND)ip->xid, private_dc); - if ((HWND)ip->xid == fl_window && fl_graphics_driver->gc()) { - fl_release_dc(fl_window, (HDC)fl_graphics_driver->gc()); - fl_window = (HWND)-1; - fl_graphics_driver->gc(0); -# ifdef FLTK_HAVE_CAIROEXT - if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); -# endif - } - - if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - - // this little trickery seems to avoid the popup window stacking problem - HWND p = GetForegroundWindow(); - if (p==GetParent((HWND)ip->xid)) { - ShowWindow((HWND)ip->xid, SW_HIDE); - ShowWindow(p, SW_SHOWNA); - } - DestroyWindow((HWND)ip->xid); - // end of fix for STR#3079 - if (count) { - int ii; - for (ii = 0; ii < count; ii++) doit[ii]->hide(); - for (ii = 0; ii < count; ii++) { - if (ii != 0) doit[0]->show(); // Fix for STR#3165 - doit[ii]->show(); - } - } - delete[] doit; // note: `count` and `doit` may be NULL (see PR #241) - - // Try to stop the annoying "raise another program" behavior - if (pWindow->non_modal() && Fl::first_window() && Fl::first_window()->shown()) - Fl::first_window()->show(); - delete ip; - screen_num_ = -1; -} - - -void Fl_WinAPI_Window_Driver::map() { - ShowWindow(fl_xid(pWindow), SW_RESTORE); // extra map calls are harmless -} - - -void Fl_WinAPI_Window_Driver::unmap() { - ShowWindow(fl_xid(pWindow), SW_HIDE); -} - -#if !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning - -void Fl_WinAPI_Window_Driver::make_fullscreen(int X, int Y, int W, int H) { - HWND xid = fl_xid(pWindow); - int top, bottom, left, right; - int sx, sy, sw, sh; - - top = fullscreen_screen_top(); - bottom = fullscreen_screen_bottom(); - left = fullscreen_screen_left(); - right = fullscreen_screen_right(); - - if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { - top = screen_num(); - bottom = top; - left = top; - right = top; - } - - Fl_WinAPI_Screen_Driver *scr_dr = (Fl_WinAPI_Screen_Driver*)Fl::screen_driver(); - scr_dr->screen_xywh_unscaled(sx, Y, sw, sh, top); - scr_dr->screen_xywh_unscaled(sx, sy, sw, sh, bottom); - H = sy + sh - Y; - scr_dr->screen_xywh_unscaled(X, sy, sw, sh, left); - scr_dr->screen_xywh_unscaled(sx, sy, sw, sh, right); - W = sx + sw - X; - - DWORD flags = GetWindowLong(xid, GWL_STYLE); - flags = flags & ~(WS_THICKFRAME|WS_CAPTION); - SetWindowLong(xid, GWL_STYLE, flags); - - // SWP_NOSENDCHANGING is so that we can override size limits - SetWindowPos(xid, HWND_TOP, X, Y, W, H, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); -} - -#endif // !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning - - -void Fl_WinAPI_Window_Driver::fullscreen_on() { - pWindow->_set_fullscreen(); - make_fullscreen(x(), y(), w(), h()); - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_WinAPI_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { - pWindow->_clear_fullscreen(); - DWORD style = GetWindowLong(fl_xid(pWindow), GWL_STYLE); - if (pWindow->border()) style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION; - // Remove the xid temporarily so that Fl_WinAPI_Window_Driver::fake_X_wm() behaves like it - // does in Fl_WinAPI_Window_Driver::makeWindow(). - HWND xid = fl_xid(pWindow); - Fl_X::flx(pWindow)->xid = 0; - int wx, wy, bt, bx, by; - switch (fake_X_wm(wx, wy, bt, bx, by, style)) { - case 0: - break; - case 1: - style |= WS_CAPTION; - break; - case 2: - /*if (border()) { - style |= WS_THICKFRAME | WS_CAPTION; - }*/ - break; - } - Fl_X::flx(pWindow)->xid = (fl_uintptr_t)xid; - SetWindowLong(fl_xid(pWindow), GWL_STYLE, style); - if (!pWindow->maximize_active()) { - // compute window position and size in scaled units - float s = Fl::screen_driver()->scale(screen_num()); - int scaledX = int(ceil(X*s)), scaledY= int(ceil(Y*s)), scaledW = int(ceil(W*s)), scaledH = int(ceil(H*s)); - // Adjust for decorations (but not if that puts the decorations - // outside the screen) - if ((X != x()) || (Y != y())) { - scaledX -= bx; - scaledY -= by+bt; - } - scaledW += bx*2; - scaledH += by*2+bt; - SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); - } else { - int WX, WY, WW, WH; - ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->screen_xywh_unscaled(WX, WY, WW, WH, screen_num()); - SetWindowPos(fl_xid(pWindow), 0, WX, WY, WW, WH, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_WinAPI_Window_Driver::maximize() { - if (!border()) return Fl_Window_Driver::maximize(); - ShowWindow(fl_xid(pWindow), SW_SHOWMAXIMIZED); -} - -void Fl_WinAPI_Window_Driver::un_maximize() { - if (!border()) return Fl_Window_Driver::un_maximize(); - ShowWindow(fl_xid(pWindow), SW_SHOWNORMAL); -} - - -void Fl_WinAPI_Window_Driver::iconize() { - ShowWindow(fl_xid(pWindow), SW_SHOWMINNOACTIVE); -} - - -void Fl_WinAPI_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) { - int minw, minh, maxw, maxh, set; - set = pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (set && (maxw != minw || maxh != minh)) { - *left = *right = GetSystemMetrics(SM_CXSIZEFRAME); - *top = *bottom = GetSystemMetrics(SM_CYSIZEFRAME); - } else { - *left = *right = GetSystemMetrics(SM_CXFIXEDFRAME); - *top = *bottom = GetSystemMetrics(SM_CYFIXEDFRAME); - } - *top += GetSystemMetrics(SM_CYCAPTION); -} - -int Fl_WinAPI_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) -{ - typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT); - static fl_GetRandomRgn_func fl_GetRandomRgn = 0L; - static char first_time = 1; - // We will have to do some Region magic now, so let's see if the - // required function is available (and it should be starting w/Win95) - if (first_time) { - HMODULE hMod = GetModuleHandle("GDI32.DLL"); - if (hMod) { - fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn"); - } - first_time = 0; - } - float s = Fl::screen_driver()->scale(screen_num()); - src_x = int(src_x * s); src_y = int(src_y * s); - src_w = int(src_w * s); src_h = int(src_h * s); - dest_x = int(dest_x * s); dest_y = int(dest_y * s); - // Now check if the source scrolling area is fully visible. - // If it is, we will do a quick scroll and just update the - // newly exposed area. If it is not, we go the safe route and - // re-render the full area instead. - // Note 1: we could go and find the areas that are actually - // obscured and recursively call fl_scroll for the newly found - // rectangles. However, this practice would rely on the - // elements of the undocumented Rgn structure. - // Note 2: although this method should take care of most - // multi-screen solutions, it will not solve issues scrolling - // from a different resolution screen onto another. - // Note 3: this has been tested with image maps, too. - HDC gc = (HDC)fl_graphics_driver->gc(); - if (fl_GetRandomRgn) { - // get the DC region minus all overlapping windows - HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0); - fl_GetRandomRgn(gc, sys_rgn, 4); - // now get the source scrolling rectangle - HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h); - POINT offset = { 0, 0 }; - if (GetDCOrgEx(gc, &offset)) { - OffsetRgn(src_rgn, offset.x, offset.y); - } - // see if all source pixels are available in the system region - // Note: we could be a bit more merciful and subtract the - // scroll destination region as well. - HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0); - int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF); - DeleteObject(dst_rgn); - DeleteObject(src_rgn); - DeleteObject(sys_rgn); - if (r != NULLREGION) { - return 1; - } - } - // Great, we can do an accelerated scroll instead of re-rendering - BitBlt(gc, dest_x, dest_y, src_w, src_h, gc, src_x, src_y,SRCCOPY); - return 0; -} - - -const Fl_Image* Fl_WinAPI_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - - -HWND fl_win32_xid(const Fl_Window *win) { - return (HWND)Fl_Window_Driver::xid(win); -} - - -Fl_Window *fl_win32_find(HWND xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} diff --git a/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx b/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx deleted file mode 100644 index b5ffe2449..000000000 --- a/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx +++ /dev/null @@ -1,85 +0,0 @@ -// -// Windows-specific code to initialize Windows support. -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "../GDI/Fl_GDI_Copy_Surface_Driver.H" -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include "Fl_WinAPI_Screen_Driver.H" -#include "Fl_WinAPI_System_Driver.H" -#include "Fl_WinAPI_Window_Driver.H" -#include "../GDI/Fl_GDI_Image_Surface_Driver.H" -#include "../Base/Fl_Base_Pen_Events.H" - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) -{ - return new Fl_GDI_Copy_Surface_Driver(w, h); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() -{ -#if USE_GDIPLUS - // Initialize GDI+. - static Gdiplus::GdiplusStartupInput gdiplusStartupInput; - if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_CLOSED) { - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_STARTUP; - Gdiplus::Status ret = GdiplusStartup(&Fl_GDIplus_Graphics_Driver::gdiplus_token_, &gdiplusStartupInput, NULL); - if (ret == 0) { // 0 is same as Gdiplus::Status::Ok, but old mingw64 barks at that - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_OPEN; - } else { - Fl::warning("GdiplusStartup failed with error code %d.", ret); - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_CLOSED; - return new Fl_GDI_Graphics_Driver(); - } - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_OPEN) { -// Fl::warning("GdiplusStartup() called, but driver is already open."); - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_SHUTDOWN) { -// Fl::warning("GdiplusStartup() called while driver is shutting down."); - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_STARTUP) { -// Fl::warning("GdiplusStartup() called recursively."); - } - Fl_Graphics_Driver *driver = new Fl_GDIplus_Graphics_Driver(); - return driver; -#else - return new Fl_GDI_Graphics_Driver(); -#endif -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() -{ - return new Fl_WinAPI_Screen_Driver(); -} - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() -{ - return new Fl_WinAPI_System_Driver(); -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ - return new Fl_WinAPI_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ - return new Fl_GDI_Image_Surface_Driver(w, h, high_res, off); -} - diff --git a/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx index 7282528ca..822acc826 100644 --- a/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx @@ -40,12 +40,10 @@ public: } }; -#ifndef FLTK_USE_WAYLAND Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) { return new Fl_X11_Gl_Window_Driver(w); } -#endif void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { draw_string_legacy_get_list(str, n); diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H index fa3c0ee90..3904fa19e 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H @@ -20,7 +20,7 @@ #include <FL/Fl_Copy_Surface.H> #include <FL/platform.H> #if FLTK_USE_CAIRO -# include <cairo/cairo.h> +# include <cairo.h> #endif // FLTK_USE_CAIRO class Fl_Image_Surface; diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index f60f748f5..281a6590e 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -24,7 +24,7 @@ #if FLTK_USE_CAIRO # include <cairo-xlib.h> # include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H" -# include <cairo/cairo.h> +# include <cairo.h> #else # include "Fl_Xlib_Graphics_Driver.H" #endif // FLTK_USE_CAIRO diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H index 382daf886..f90f2cc79 100644 --- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H @@ -19,7 +19,7 @@ #include <FL/Fl_Image_Surface.H> #if FLTK_USE_CAIRO -# include <cairo/cairo.h> +# include <cairo.h> #endif // FLTK_USE_CAIRO class Fl_Xlib_Image_Surface_Driver : public Fl_Image_Surface_Driver { diff --git a/src/fl_call_main.c b/src/fl_call_main.c deleted file mode 100644 index 31cd86c31..000000000 --- a/src/fl_call_main.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 1998-2023 by Bill Spitzak and others. - * - * fl_call_main() calls main() for you Windows people. Needs to be done in C - * because Borland C++ won't let you call main() from C++. - * - * This library is free software. Distribution and use rights are outlined in - * the file "COPYING" which should have been included with this file. If this - * file is missing or damaged, see the license at: - * - * https://www.fltk.org/COPYING.php - * - * Please see the following page on how to report bugs and issues: - * - * https://www.fltk.org/bugs.php - */ - -/* - * This WinMain() function can be overridden by an application and - * is provided for compatibility with programs written for other - * operating systems that conform to the ANSI standard entry point - * "main()". This will allow you to build a Windows Application - * without any special settings. - * - * You cannot have this WinMain() function in a DLL because it would have - * to call \c main() outside the DLL. Thus, this nifty feature is only - * available if you link to the static library. - * - * However, it is possible to build this module separately so you can - * use it in progams that link to the shared library. - * - * Currently the debug version of this library will create a console window - * for your application so you can put printf() statements for debugging or - * informational purposes. Ultimately we want to update this to always use - * the parent's console, but at present we have not identified a function - * or API in Microsoft(r) Windows(r) that allows for it. - */ - -/* - * Notes for FLTK developers: - * - * 1) Since FLTK 1.4.0 this file is compiled only on Windows, hence we don't - * need to test the _WIN32 macro. - * 2) This file must not call any FLTK library functions because this would - * not work with /both/ the DLL /and/ the static library (linkage stuff). - * 3) Converting the commandline arguments to UTF-8 is therefore implemented - * here *and* in the library but this seems to be an acceptable compromise. - * 4) (Unless someone finds a better solution, of course. Albrecht) - * 5) The condition "!defined(FL_DLL)" prevents building this in the shared - * library, i.e. "WinMain()" will not be defined in the shared lib (DLL). - * 6) The condition "!defined (__GNUC__)" prevents compilation of this - * module with MinGW, MSYS, and Cygwin which don't use WinMain(). - * 7) It is unclear if there are other build systems on Windows that need a - * WinMain() entry point. Earlier comments and code seem to indicate that - * Borland C++ would require it. -*/ - -#if !defined(FL_DLL) && !defined (__GNUC__) - -#include <windows.h> -#include <stdio.h> -#include <stdlib.h> -#include <shellapi.h> - -extern int main(int, char *[]); - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) { - int rc; - int i; - int argc = 0; - char** argv = NULL; - - /* - * If we are compiling in debug mode, open a console window so - * we can see any printf's, etc... - * - * While we can detect if the program was run from the command-line - - * look at the CMDLINE environment variable, it will be "WIN" for - * programs started from the GUI - the shell seems to run all Windows - * applications in the background anyways... - */ - -#ifdef _DEBUG - AllocConsole(); - freopen("conin$", "r", stdin); - freopen("conout$", "w", stdout); - freopen("conout$", "w", stderr); -#endif /* _DEBUG */ - - /* Get the command line arguments as Windows Wide Character strings */ - LPWSTR *wideArgv = CommandLineToArgvW(GetCommandLineW(), &argc); - - /* Allocate an array of 'argc + 1' string pointers */ - argv = (char **)malloc((argc + 1) * sizeof(char *)); - - /* Convert the command line arguments to UTF-8 */ - for (i = 0; i < argc; i++) { - /* find the required size of the buffer */ - int u8size = WideCharToMultiByte(CP_UTF8, /* CodePage */ - 0, /* dwFlags */ - wideArgv[i], /* lpWideCharStr */ - -1, /* cchWideChar */ - NULL, /* lpMultiByteStr */ - 0, /* cbMultiByte */ - NULL, /* lpDefaultChar */ - NULL); /* lpUsedDefaultChar */ - if (u8size > 0) { - char *strbuf = (char *)malloc(u8size); - int ret = WideCharToMultiByte(CP_UTF8, /* CodePage */ - 0, /* dwFlags */ - wideArgv[i], /* lpWideCharStr */ - -1, /* cchWideChar */ - strbuf, /* lpMultiByteStr */ - u8size, /* cbMultiByte */ - NULL, /* lpDefaultChar */ - NULL); /* lpUsedDefaultChar */ - if (ret) { - argv[i] = strbuf; - } else { - argv[i] = _strdup(""); - free(strbuf); - } - } else { - argv[i] = _strdup(""); - } - } - argv[argc] = NULL; /* required by C standard at end of list */ - - /* Free the wide character string array */ - LocalFree(wideArgv); - - /* Call the program's entry point main() */ - rc = main(argc, argv); - - /* Cleanup allocated memory for argv */ - for (int i = 0; i < argc; ++i) { - free((void *)argv[i]); - } - free((void *)argv); - - /* Close the console in debug mode */ - -#ifdef _DEBUG - fclose(stdin); - fclose(stdout); - fclose(stderr); -#endif /* _DEBUG */ - - return rc; -} - -#else - -/* STR# 2973: solves "empty translation unit" error */ -typedef int dummy; - -#endif /* !defined(FL_DLL) && !defined (__GNUC__) */ diff --git a/src/fl_dnd_win32.cxx b/src/fl_dnd_win32.cxx deleted file mode 100644 index abaa588cc..000000000 --- a/src/fl_dnd_win32.cxx +++ /dev/null @@ -1,559 +0,0 @@ -// -// Drag & Drop code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: this file contains platform specific code and will therefore -// not be processed by doxygen (see Doxyfile.in). - -// This file contains Windows-specific code for FLTK which is always linked -// in. Search other files for "_WIN32" or filenames ending in _win32.cxx -// for other system-specific code. - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/Fl_Window.H> -#include "Fl_Window_Driver.H" -#include <FL/fl_utf8.h> -#include "drivers/WinAPI/Fl_WinAPI_Screen_Driver.H" -#include "flstring.h" -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <objidl.h> -#include <time.h> -#if defined(__CYGWIN__) -#include <sys/time.h> -#include <unistd.h> -#endif - -extern char *fl_selection_buffer[2]; -extern int fl_selection_length[2]; -extern int fl_selection_buffer_length[2]; -extern char fl_i_own_selection[2]; -extern char *fl_locale2utf8(const char *s, UINT codepage = 0); -extern unsigned int fl_codepage; - -Fl_Window *fl_dnd_target_window = 0; - -#include <ole2.h> -#include <shellapi.h> -#include <shlobj.h> - - -/** - subclass the IDropTarget to receive data from DnD operations - */ -class FLDropTarget : public IDropTarget -{ - DWORD m_cRefCount; // for "statistics" only (issue #569) - DWORD lastEffect; - int px, py; -public: - FLDropTarget() : m_cRefCount(0) { } // initialize - virtual ~FLDropTarget() { } - HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) FL_OVERRIDE { - if (IID_IUnknown==riid || IID_IDropTarget==riid) - { - *ppvObject=this; - ((LPUNKNOWN)*ppvObject)->AddRef(); - return S_OK; - } - *ppvObject = NULL; - return E_NOINTERFACE; - } - ULONG STDMETHODCALLTYPE AddRef() FL_OVERRIDE { return ++m_cRefCount; } - ULONG STDMETHODCALLTYPE Release() FL_OVERRIDE { - long nTemp; - nTemp = --m_cRefCount; - // this is a static object, do not 'delete this' (issue #569) - return nTemp; - } - HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) FL_OVERRIDE { - if( !pDataObj ) return E_INVALIDARG; - // set e_modifiers here from grfKeyState, set e_x and e_root_x - // check if FLTK handles this drag and return if it can't (i.e. BMP drag without filename) - POINT ppt; - Fl::e_x_root = ppt.x = pt.x; - Fl::e_y_root = ppt.y = pt.y; - HWND hWnd = WindowFromPoint( ppt ); - Fl_Window *target = fl_find( hWnd ); - if (target) { - float s = Fl::screen_driver()->scale(Fl_Window_Driver::driver(target)->screen_num()); - Fl::e_x_root = int(Fl::e_x_root / s); - Fl::e_y_root = int(Fl::e_y_root / s); - Fl::e_x = Fl::e_x_root-target->x(); - Fl::e_y = Fl::e_y_root-target->y(); - } - fl_dnd_target_window = target; - px = pt.x; py = pt.y; - if (fillCurrentDragData(pDataObj)) { - // FLTK has no mechanism yet for the different drop effects, so we allow move and copy - if ( target && Fl::handle( FL_DND_ENTER, target ) ) - *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; - else - *pdwEffect = DROPEFFECT_NONE; - } else { - *pdwEffect = DROPEFFECT_NONE; - } - lastEffect = *pdwEffect; - return S_OK; - } - HRESULT STDMETHODCALLTYPE DragOver( DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) FL_OVERRIDE { - if ( px==pt.x && py==pt.y ) - { - *pdwEffect = lastEffect; - return S_OK; - } - if ( !fl_dnd_target_window ) - { - *pdwEffect = lastEffect = DROPEFFECT_NONE; - return S_OK; - } - // set e_modifiers here from grfKeyState, set e_x and e_root_x - Fl::e_x_root = pt.x; - Fl::e_y_root = pt.y; - if (fl_dnd_target_window) { - float s = Fl::screen_driver()->scale(Fl_Window_Driver::driver(fl_dnd_target_window)->screen_num()); - Fl::e_x_root = int(Fl::e_x_root /s); - Fl::e_y_root = int(Fl::e_y_root /s); - Fl::e_x = Fl::e_x_root-fl_dnd_target_window->x(); - Fl::e_y = Fl::e_y_root-fl_dnd_target_window->y(); - } - if (fillCurrentDragData(0)) { - // Fl_Group will change DND_DRAG into DND_ENTER and DND_LEAVE if needed - if ( Fl::handle( FL_DND_DRAG, fl_dnd_target_window ) ) - *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; - else - *pdwEffect = DROPEFFECT_NONE; - } else { - *pdwEffect = DROPEFFECT_NONE; - } - px = pt.x; py = pt.y; - lastEffect = *pdwEffect; - // show insert position if dnd'ing in the same window/process (STR #3209) - Fl::flush(); - return S_OK; - } - HRESULT STDMETHODCALLTYPE DragLeave() FL_OVERRIDE { - if ( fl_dnd_target_window && fillCurrentDragData(0)) - { - Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); - fl_dnd_target_window = 0; - clearCurrentDragData(); - } - return S_OK; - } - HRESULT STDMETHODCALLTYPE Drop( IDataObject *data, DWORD /*grfKeyState*/, POINTL pt, DWORD* /*pdwEffect*/) FL_OVERRIDE { - if ( !fl_dnd_target_window ) - return S_OK; - Fl_Window *target = fl_dnd_target_window; - fl_dnd_target_window = 0; - Fl::e_x_root = pt.x; - Fl::e_y_root = pt.y; - float s = Fl::screen_driver()->scale(Fl_Window_Driver::driver(target)->screen_num()); - Fl::e_x_root = int(Fl::e_x_root / s); - Fl::e_y_root = int(Fl::e_y_root / s); - if (target) { - Fl::e_x = Fl::e_x_root-target->x(); - Fl::e_y = Fl::e_y_root-target->y(); - } - // tell FLTK that the user released an object on this widget - if ( !Fl::handle( FL_DND_RELEASE, target ) ) - return S_OK; - - Fl_Widget *w = target; - while (w->parent()) w = w->window(); - HWND hwnd = fl_xid( (Fl_Window*)w ); - if (fillCurrentDragData(data)) { - int old_event = Fl::e_number; - char *a, *b; - a = b = currDragData; - while (*a) { // strip the CRLF pairs - if (*a == '\r' && a[1] == '\n') a++; - else *b++ = *a++; - } - *b = 0; - Fl::e_text = currDragData; - Fl::e_length = (int) (b - currDragData); - Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); // e_text will be invalid after this call - Fl::e_number = old_event; - SetForegroundWindow( hwnd ); - clearCurrentDragData(); - return S_OK; - } - return S_OK; - } -private: - - static IDataObject *currDragRef; - static char *currDragData; - static int currDragSize; - static char currDragResult; - - static void clearCurrentDragData() { - currDragRef = 0; - if (currDragData) free(currDragData); - currDragData = 0; - currDragSize = 0; - currDragResult = 0; - } - static char fillCurrentDragData(IDataObject *data) { - // shortcut through this whole procedure if there is no fresh data - if (!data) - return currDragResult; - // shortcut through this whole procedure if this is still the same drag event - // (* this is safe, because 'currDragRef' is cleared on Leave and Drop events) - if (data==currDragRef) - return currDragResult; - - // clear currDrag* for a new drag event - clearCurrentDragData(); - - currDragRef = data; - // fill currDrag* with UTF-8 data, if available - FORMATETC fmt = { 0 }; - STGMEDIUM medium = { 0 }; - fmt.tymed = TYMED_HGLOBAL; - fmt.dwAspect = DVASPECT_CONTENT; - fmt.lindex = -1; - fmt.cfFormat = CF_UNICODETEXT; - // if it is UNICODE text, return a UTF-8-converted copy of it - if ( data->GetData( &fmt, &medium )==S_OK ) - { - void *stuff = GlobalLock( medium.hGlobal ); - unsigned srclen = 0; - const wchar_t *wstuff = (const wchar_t *)stuff; - while (*wstuff++) srclen++; - wstuff = (const wchar_t *)stuff; - unsigned utf8len = fl_utf8fromwc(NULL, 0, wstuff, srclen); - currDragSize = utf8len; - currDragData = (char*)malloc(utf8len + 1); - fl_utf8fromwc(currDragData, currDragSize+1, wstuff, srclen+1); // include null-byte - GlobalUnlock( medium.hGlobal ); - ReleaseStgMedium( &medium ); - currDragResult = 1; - return currDragResult; - } - fmt.cfFormat = CF_TEXT; - // if it is CP1252 text, return a UTF-8-converted copy of it - if ( data->GetData( &fmt, &medium )==S_OK ) - { - int len; - char *p, *q, *last; - unsigned u; - void *stuff = GlobalLock( medium.hGlobal ); - currDragData = (char*)malloc(3 * strlen((char*)stuff) + 10); - p = (char*)stuff; - last = p + strlen(p); - q = currDragData; - while (p < last) { - u = fl_utf8decode(p, last, &len); - p += len; - len = fl_utf8encode(u, q); - q += len; - } - *q = 0; - currDragSize = (int) (q - currDragData); - currDragData = (char*)realloc(currDragData, currDragSize + 1); - GlobalUnlock( medium.hGlobal ); - ReleaseStgMedium( &medium ); - currDragResult = 1; - return currDragResult; - } - // else fill currDrag* with filenames, if possible - memset(&fmt, 0, sizeof(fmt)); - fmt.tymed = TYMED_HGLOBAL; - fmt.dwAspect = DVASPECT_CONTENT; - fmt.lindex = -1; - fmt.cfFormat = CF_HDROP; - // if it is a pathname list, send an FL_PASTE with a \n separated list of filepaths - if ( data->GetData( &fmt, &medium )==S_OK ) - { - HDROP hdrop = (HDROP)medium.hGlobal; - int i, n, nn = 0, nf = DragQueryFileW( hdrop, (UINT)-1, 0, 0 ); - for ( i=0; i<nf; i++ ) nn += DragQueryFileW( hdrop, i, 0, 0 ); - nn += nf; - wchar_t *dst = (wchar_t *)malloc(nn * sizeof(wchar_t)); - wchar_t *bu = dst; - for ( i=0; i<nf; i++ ) { - n = DragQueryFileW( hdrop, i, (WCHAR*)dst, nn ); - dst += n; - if ( i<nf-1 ) { - *dst++ = L'\n'; - } - } - *dst=0; - - currDragData = (char*) malloc(nn * 5 + 1); -// Fl::e_length = fl_unicode2utf(bu, nn, Fl::e_text); - currDragSize = fl_utf8fromwc(currDragData, (nn*5+1), bu, nn); - currDragData[currDragSize] = 0; - free(bu); - -// Fl::belowmouse()->handle(FL_DROP); -// free( Fl::e_text ); - ReleaseStgMedium( &medium ); - currDragResult = 1; - return currDragResult; - } - currDragResult = 0; - return currDragResult; - } -} flDropTarget; - -IDropTarget *flIDropTarget = &flDropTarget; - -IDataObject *FLDropTarget::currDragRef = 0; -char *FLDropTarget::currDragData = 0; -int FLDropTarget::currDragSize = 0; -char FLDropTarget::currDragResult = 0; - -/** - this class is needed to allow FLTK apps to be a DnD source - */ -class FLDropSource : public IDropSource -{ - DWORD m_cRefCount; -public: - FLDropSource() { m_cRefCount = 0; } - virtual ~FLDropSource() { } - HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) FL_OVERRIDE { - if (IID_IUnknown==riid || IID_IDropSource==riid) - { - *ppvObject=this; - ((LPUNKNOWN)*ppvObject)->AddRef(); - return S_OK; - } - *ppvObject = NULL; - return E_NOINTERFACE; - } - ULONG STDMETHODCALLTYPE AddRef() FL_OVERRIDE { return ++m_cRefCount; } - ULONG STDMETHODCALLTYPE Release() FL_OVERRIDE { - long nTemp; - nTemp = --m_cRefCount; - if(nTemp==0) - delete this; - return nTemp; - } - STDMETHODIMP GiveFeedback( DWORD ) FL_OVERRIDE { return DRAGDROP_S_USEDEFAULTCURSORS; } - STDMETHODIMP QueryContinueDrag( BOOL esc, DWORD keyState ) FL_OVERRIDE { - if ( esc ) - return DRAGDROP_S_CANCEL; - if ( !(keyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) ) - return DRAGDROP_S_DROP; - return S_OK; - } -}; -class FLEnum : public IEnumFORMATETC -{ -public: - int n; - LONG m_lRefCount; - - ULONG __stdcall AddRef(void) FL_OVERRIDE { - return InterlockedIncrement(&m_lRefCount); - } - - ULONG __stdcall Release(void) FL_OVERRIDE { - LONG count = InterlockedDecrement(&m_lRefCount); - if(count == 0) { - delete this; - return 0; - } else { - return count; - } - } - - - HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject) FL_OVERRIDE { - if(iid == IID_IEnumFORMATETC || iid == IID_IUnknown) { - AddRef(); - *ppvObject = this; - return S_OK; - } else { - *ppvObject = 0; - return E_NOINTERFACE; - } - } - - HRESULT __stdcall Next(ULONG celt, FORMATETC * rgelt, ULONG *pceltFetched) FL_OVERRIDE { - if (n > 0) return S_FALSE; - for (ULONG i = 0; i < celt; i++) { - n++; - rgelt->cfFormat = CF_HDROP; - rgelt->dwAspect = DVASPECT_CONTENT; - rgelt->lindex = -1; - rgelt->ptd = NULL; - rgelt->tymed = TYMED_HGLOBAL; - } - if (pceltFetched) *pceltFetched = celt; - return S_OK; - } - - HRESULT __stdcall Skip(ULONG celt) FL_OVERRIDE { - n += celt; - return (n == 0) ? S_OK : S_FALSE; - } - - HRESULT __stdcall Reset(void) FL_OVERRIDE { - n = 0; - return S_OK; - } - - HRESULT __stdcall Clone(IEnumFORMATETC **ppenum) FL_OVERRIDE { - *ppenum = new FLEnum(); - return S_OK; - } - - FLEnum(void) { - m_lRefCount = 1; - n = 0; - } - - virtual ~FLEnum(void) { - n = 0; - } -}; - - -/** - This is the actual object that FLTK can drop somewhere. - - The implementation is minimal, but it should work with all decent Win32 drop targets -*/ -class FLDataObject : public IDataObject -{ - DWORD m_cRefCount; - //FLEnum *m_EnumF; -public: - FLDataObject() { m_cRefCount = 1; }// m_EnumF = new FLEnum();} - virtual ~FLDataObject() { } - HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) FL_OVERRIDE { - if (IID_IUnknown==riid || IID_IDataObject==riid) - { - *ppvObject=this; - ((LPUNKNOWN)*ppvObject)->AddRef(); - return S_OK; - } - *ppvObject = NULL; - return E_NOINTERFACE; - } - ULONG STDMETHODCALLTYPE AddRef() FL_OVERRIDE { return ++m_cRefCount; } - ULONG STDMETHODCALLTYPE Release() FL_OVERRIDE { - long nTemp; - nTemp = --m_cRefCount; - if(nTemp==0) - delete this; - return nTemp; - } - // GetData currently allows UNICODE text through Global Memory only - HRESULT STDMETHODCALLTYPE GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium ) FL_OVERRIDE { - if ((pformatetcIn->dwAspect & DVASPECT_CONTENT) && - (pformatetcIn->tymed & TYMED_HGLOBAL) && - (pformatetcIn->cfFormat == CF_UNICODETEXT)) - { - int utf16_len = fl_utf8toUtf16(fl_selection_buffer[0], fl_selection_length[0], 0, 0); - HGLOBAL gh = GlobalAlloc( GHND, utf16_len * 2 + 2 ); - char *pMem = (char*)GlobalLock( gh ); - fl_utf8toUtf16(fl_selection_buffer[0], fl_selection_length[0], (unsigned short*)pMem, utf16_len + 1); -// HGLOBAL gh = GlobalAlloc( GHND| GMEM_SHARE, -// (fl_selection_length[0]+4) * sizeof(short) -// + sizeof(DROPFILES)); -// unsigned char *pMem = (unsigned char*)GlobalLock( gh ); -// if (!pMem) { -// GlobalFree(gh); -// return DV_E_FORMATETC; -// } -// DROPFILES *df =(DROPFILES*) pMem; -// int l; -// df->pFiles = sizeof(DROPFILES); -// df->pt.x = 0; -// df->pt.y = 0; -// df->fNC = FALSE; -// for (int i = 0; i < fl_selection_length[0]; i++) { -// if (fl_selection_buffer[0][i] == '\n') { -// fl_selection_buffer[0][i] = '\0'; -// } -// } -// -// df->fWide = TRUE; -// l = fl_utf2unicode((unsigned char*)fl_selection_buffer[0], -// fl_selection_length[0], (wchar_t*)(((char*)pMem) -// + sizeof(DROPFILES))); -// -// pMem[l * sizeof(WCHAR) + sizeof(DROPFILES)] = 0; -// pMem[l * sizeof(WCHAR) + 1 + sizeof(DROPFILES)] = 0; -// pMem[l * sizeof(WCHAR) + 2 + sizeof(DROPFILES)] = 0; -// pMem[l * sizeof(WCHAR) + 3 + sizeof(DROPFILES)] = 0; - pmedium->tymed = TYMED_HGLOBAL; - pmedium->hGlobal = gh; - pmedium->pUnkForRelease = NULL; - GlobalUnlock( gh ); - return S_OK; - } - return DV_E_FORMATETC; - } - HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pformatetc ) FL_OVERRIDE - { - if ((pformatetc->dwAspect & DVASPECT_CONTENT) && - (pformatetc->tymed & TYMED_HGLOBAL) && - (pformatetc->cfFormat == CF_UNICODETEXT)) - return S_OK; - return DV_E_FORMATETC; - } -// HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dir, IEnumFORMATETC** ppenumFormatEtc) { -// *ppenumFormatEtc = m_EnumF; -// return S_OK; -// } - - // all the following methods are not really needed for a DnD object - HRESULT STDMETHODCALLTYPE GetDataHere( FORMATETC* /*pformatetcIn*/, STGMEDIUM* /*pmedium*/) FL_OVERRIDE { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( FORMATETC* /*in*/, FORMATETC* /*out*/) FL_OVERRIDE { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE SetData( FORMATETC* /*pformatetc*/, STGMEDIUM* /*pmedium*/, BOOL /*fRelease*/) FL_OVERRIDE { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD /*dir*/, IEnumFORMATETC** /*ppenumFormatEtc*/) FL_OVERRIDE { return E_NOTIMPL; } -// HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dir, IEnumFORMATETC** ppenumFormatEtc) FL_OVERRIDE {*ppenumFormatEtc = m_EnumF; return S_OK;} - HRESULT STDMETHODCALLTYPE DAdvise( FORMATETC* /*pformatetc*/, DWORD /*advf*/, - IAdviseSink* /*pAdvSink*/, DWORD* /*pdwConnection*/) FL_OVERRIDE { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE DUnadvise( DWORD /*dwConnection*/) FL_OVERRIDE { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE EnumDAdvise( IEnumSTATDATA** /*ppenumAdvise*/) FL_OVERRIDE { return E_NOTIMPL; } -}; - - -int Fl_WinAPI_Screen_Driver::dnd(int unused) -{ - DWORD dropEffect; - ReleaseCapture(); - - FLDataObject *fdo = new FLDataObject; - fdo->AddRef(); - FLDropSource *fds = new FLDropSource; - fds->AddRef(); - - HRESULT ret = DoDragDrop( fdo, fds, DROPEFFECT_MOVE|DROPEFFECT_LINK|DROPEFFECT_COPY, &dropEffect ); - - fdo->Release(); - fds->Release(); - - Fl_Widget *w = Fl::pushed(); - if ( w ) - { - int old_event = Fl::e_number; - w->handle(Fl::e_number = FL_RELEASE); - Fl::e_number = old_event; - Fl::pushed( 0 ); - } - if ( ret==DRAGDROP_S_DROP ) return 1; // or DD_S_CANCEL - return 0; -} diff --git a/src/fl_encoding_latin1.cxx b/src/fl_encoding_latin1.cxx index 23bd889d7..7ec86f14a 100644 --- a/src/fl_encoding_latin1.cxx +++ b/src/fl_encoding_latin1.cxx @@ -70,3 +70,16 @@ const char *fl_local_to_latin1(const char *t, int n) { return Fl::system_driver()->local_to_latin1(t, n); } + +// Stub implementations for mac_roman encoding functions. +// On X11/Unix, these are no-ops since mac_roman encoding is not used. + +const char *Fl_System_Driver::mac_roman_to_local(const char *t, int) +{ + return t; +} + +const char *Fl_System_Driver::local_to_mac_roman(const char *t, int) +{ + return t; +} diff --git a/src/fl_encoding_mac_roman.cxx b/src/fl_encoding_mac_roman.cxx deleted file mode 100644 index 75439a3ee..000000000 --- a/src/fl_encoding_mac_roman.cxx +++ /dev/null @@ -1,117 +0,0 @@ -// -// Convert Mac Roman encoded text to the local encoding. -// -// Copyright 1998-2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include <FL/fl_draw.H> -#include "Fl_System_Driver.H" -#include <FL/Fl.H> -#include <FL/Enumerations.H> -#include <stdlib.h> -#include "flstring.h" - -/** - \cond DriverDev - \addtogroup DriverDeveloper - \{ - */ - -// These function assume a western code page. -// -// Windows and X11 render text in ISO or Latin-1 for western settings. The -// lookup tables below will convert all common character codes and replace -// unknown characters with an upsidedown question mark. - -// This table converts Windows-1252/Latin 1 into MacRoman encoding -static uchar latin2roman[128] = { -0xdb, 0xc0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xc0, 0xdc, 0xce, 0xc0, 0xc0, 0xc0, -0xc0, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xc0, 0xdd, 0xcf, 0xc0, 0xc0, 0xd9, -0xca, 0xc1, 0xa2, 0xa3, 0xc0, 0xb4, 0xc0, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xc0, 0xa8, 0xf8, -0xa1, 0xb1, 0xc0, 0xc0, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc0, 0xbc, 0xc8, 0xc0, 0xc0, 0xc0, 0xc0, -0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, -0xc0, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xc0, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xc0, 0xc0, 0xa7, -0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, -0xc0, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xc0, 0xc0, 0xd8 -}; - -// This table converts MacRoman into Windows-1252/Latin 1 -static uchar roman2latin[128] = { -0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, -0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, -0x86, 0xb0, 0xa2, 0xa3, 0xa7, 0x95, 0xb6, 0xdf, 0xae, 0xa9, 0x99, 0xb4, 0xa8, 0xbf, 0xc6, 0xd8, -0xbf, 0xb1, 0xbf, 0xbf, 0xa5, 0xb5, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xaa, 0xba, 0xbf, 0xe6, 0xf8, -0xbf, 0xa1, 0xac, 0xbf, 0x83, 0xbf, 0xbf, 0xab, 0xbb, 0x85, 0xa0, 0xc0, 0xc3, 0xd5, 0x8c, 0x9c, -0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xf7, 0xbf, 0xff, 0x9f, 0xbf, 0x80, 0x8b, 0x9b, 0xbf, 0xbf, -0x87, 0xb7, 0x82, 0x84, 0x89, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, -0xbf, 0xd2, 0xda, 0xdb, 0xd9, 0xbf, 0x88, 0x98, 0xaf, 0xbf, 0xbf, 0xbf, 0xb8, 0xbf, 0xbf, 0xbf -}; - -static char *buf = 0; -static int n_buf = 0; - -const char *Fl_System_Driver::local_to_mac_roman(const char *t, int n) -{ - if (n==-1) n = (int) strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src; - if (c>127) - *dst = latin2roman[c-128]; - else - *dst = c; - } - //*dst = 0; // this would be wrong! - return buf; -} - -const char *Fl_System_Driver::mac_roman_to_local(const char *t, int n) -{ - if (n==-1) n = (int) strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src++; - if (c>127) - *dst++ = roman2latin[c-128]; - else - *dst++ = c; - } - //*dst = 0; // this would be wrong - return buf; -} - -/** - \} - \endcond - */ - -const char *fl_local_to_mac_roman(const char *t, int n) { - return Fl::system_driver()->local_to_mac_roman(t, n); -} - -const char *fl_mac_roman_to_local(const char *t, int n) { - return Fl::system_driver()->mac_roman_to_local(t, n); -} diff --git a/src/flstring.h b/src/flstring.h index 04199d13e..5cedf1711 100644 --- a/src/flstring.h +++ b/src/flstring.h @@ -53,11 +53,6 @@ * Some of these functions are also defined in ISO C99... */ -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define strcasecmp(s,t) _stricmp((s), (t)) -# define strncasecmp(s,t,n) _strnicmp((s), (t), (n)) -# endif /* _WIN32 && ... */ - # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ diff --git a/src/forms_fselect.cxx b/src/forms_fselect.cxx index fd16b4d16..82e397ec4 100644 --- a/src/forms_fselect.cxx +++ b/src/forms_fselect.cxx @@ -29,11 +29,8 @@ char* fl_show_file_selector(const char *message,const char *dir, if (pat && pat[0]) fl_pattern = pat; if (fname && fname[0]) strlcpy(fl_filename,fname,sizeof(fl_filename)); char *p = fl_directory+strlen(fl_directory); - if (p > fl_directory && *(p-1)!='/' -#ifdef _WIN32 - && *(p-1)!='\\' && *(p-1)!=':' -#endif - ) *p++ = '/'; + if (p > fl_directory && *(p-1)!='/') + *p++ = '/'; strlcpy(p,fl_filename,sizeof(fl_directory) - (p - fl_directory)); const char *q = fl_file_chooser(message,fl_pattern,fl_directory); if (!q) return 0; diff --git a/src/scandir_win32.c b/src/scandir_win32.c deleted file mode 100644 index 4c9fc4fc9..000000000 --- a/src/scandir_win32.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Windows scandir function for the Fast Light Tool Kit (FLTK). - * - * Copyright 1998-2023 by Bill Spitzak and others. - * - * This library is free software. Distribution and use rights are outlined in - * the file "COPYING" which should have been included with this file. If this - * file is missing or damaged, see the license at: - * - * https://www.fltk.org/COPYING.php - * - * Please see the following page on how to report bugs and issues: - * - * https://www.fltk.org/bugs.php - */ - -#ifndef __CYGWIN__ -/* Emulation of POSIX scandir() call with error messages */ -#include <FL/platform_types.h> -#include <FL/fl_utf8.h> -#include "flstring.h" -#include <windows.h> -#include <stdlib.h> - -/* Get error message string for last failed WIN32 operation - * in 'errmsg' (if non-NULL), string size limited to errmsg_sz. - * - * NOTE: Copied from: fluid/ExternalCodeEditor_WIN32.cxx - * - * TODO: Verify works in different languages, with utf8 strings. - * TODO: This should be made available globally to the FLTK internals, in case - * other parts of FLTK need OS error messages.. - */ -static void get_ms_errmsg(char *errmsg, int errmsg_sz) { - DWORD lastErr = GetLastError(); - DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM; - DWORD langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); - LPWSTR mbuf = 0; - DWORD msize = 0; - - /* Early exit if parent doesn't want an errmsg */ - if (!errmsg || errmsg_sz <= 0 ) return; - /* Get error message from Windows */ - msize = FormatMessageW(flags, 0, lastErr, langid, (LPWSTR)&mbuf, 0, NULL); - if ( msize == 0 ) { - fl_snprintf(errmsg, errmsg_sz, "Error #%lu", (unsigned long)lastErr); - } else { - char *src; - char *dst; - /* convert message to UTF-8 */ - fl_utf8fromwc(errmsg, errmsg_sz, mbuf, msize); - /* Remove '\r's -- they screw up fl_alert()) */ - src = dst = errmsg; - for ( ; 1; src++ ) { - if ( *src == '\0' ) { *dst = '\0'; break; } - if ( *src != '\r' ) { *dst++ = *src; } - } - LocalFree(mbuf); /* Free the buffer allocated by the system */ - } -} - -/* - * This could use some docs. - * - * Returns -1 on error, errmsg returns error string (if non-NULL) - */ -int fl_scandir(const char *dirname, struct dirent ***namelist, - int (*select)(struct dirent *), - int (*compar)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_sz) { - int len; - char *findIn, *d, is_dir = 0; - WIN32_FIND_DATAW findw; - HANDLE h; - int nDir = 0, NDir = 0; - struct dirent **dir = 0, *selectDir; - unsigned long ret; - - if (errmsg && errmsg_sz>0) errmsg[0] = '\0'; - len = (int) strlen(dirname); - findIn = (char *)malloc((size_t)(len+10)); - if (!findIn) { - /* win32 malloc() docs: "malloc sets errno to ENOMEM if allocation fails" */ - if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno)); - return -1; - } - strcpy(findIn, dirname); - - for (d = findIn; *d; d++) if (*d == '/') *d = '\\'; - if (len == 0) { strcpy(findIn, ".\\*"); } - if ((len == 2) && (findIn[1] == ':') && isalpha(findIn[0])) { *d++ = '\\'; *d = 0; } - if ((len == 1) && (d[-1] == '.')) { strcpy(findIn, ".\\*"); is_dir = 1; } - if ((len > 0) && (d[-1] == '\\')) { *d++ = '*'; *d = 0; is_dir = 1; } - if ((len > 1) && (d[-1] == '.') && (d[-2] == '\\')) { d[-1] = '*'; is_dir = 1; } - { /* Create a block to limit the scope while we find the initial "wide" filename */ - unsigned short *wbuf = NULL; - unsigned wlen = fl_utf8toUtf16(findIn, (unsigned) strlen(findIn), NULL, 0); /* Pass NULL to query length */ - wlen++; /* add a little extra for termination etc. */ - wbuf = (unsigned short*)malloc(sizeof(unsigned short)*(wlen+2)); - wlen = fl_utf8toUtf16(findIn, (unsigned) strlen(findIn), wbuf, wlen); /* actually convert the filename */ - wbuf[wlen] = 0; /* NULL terminate the resultant string */ - if (!is_dir) { /* this file may still be a directory that we need to list */ - DWORD attr = GetFileAttributesW(wbuf); - if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) ) { - wbuf[wlen] = '\\'; wbuf[wlen+1] = '*'; wbuf[wlen+2] = 0; - } - } - h = FindFirstFileW(wbuf, &findw); /* get a handle to the first filename in the search */ - free(wbuf); /* release the "wide" buffer before the pointer goes out of scope */ - } - - if (h == INVALID_HANDLE_VALUE) { - free(findIn); - ret = GetLastError(); - if (ret != ERROR_NO_MORE_FILES) { - nDir = -1; - get_ms_errmsg(errmsg, errmsg_sz); /* return OS error msg */ - } - *namelist = dir; - return nDir; - } - do { - int l = (int) wcslen(findw.cFileName); - int dstlen = l * 5 + 1; - selectDir=(struct dirent*)malloc(sizeof(struct dirent)+dstlen); - - l = fl_utf8fromwc(selectDir->d_name, dstlen, findw.cFileName, l); - - selectDir->d_name[l] = 0; - if (findw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - /* Append a trailing slash to directory names... */ - strcat(selectDir->d_name, "/"); - } - if (!select || (*select)(selectDir)) { - if (nDir==NDir) { - struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), (size_t)(NDir+33)); - if (NDir) memcpy(tempDir, dir, sizeof(struct dirent*)*NDir); - if (dir) free(dir); - dir = tempDir; - NDir += 32; - } - dir[nDir] = selectDir; - nDir++; - dir[nDir] = 0; - } else { - free(selectDir); - } - } while (FindNextFileW(h, &findw)); - ret = GetLastError(); - if (ret != ERROR_NO_MORE_FILES) { - /* don't return an error code, because the dir list may still be valid - up to this point */ - } - FindClose(h); - free (findIn); - if (compar) qsort(dir, (size_t)nDir, sizeof(*dir), - (int(*)(const void*, const void*))compar); - *namelist = dir; - return nDir; -} - -#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index f3f5a45ca..000000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,375 +0,0 @@ -# -# CMakeLists.txt used to build test and demo apps by the CMake build system -# -# Copyright 2004-2025 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# -####################################################################### - -include(../CMake/FLTK-Functions.cmake) -include(../CMake/fl_create_example.cmake) - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin/test) -set(TESTFILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../data) - -# create data and binary directory to copy scripts and data files - -file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) -file(MAKE_DIRECTORY ${TESTFILE_PATH}) - -####################################################################### -# -# Define additional example programs for testing, for instance: -# set(extra_tests issue-276 str-1895) -# Use the source file test/'name'.cxx for each additional program. -# These test programs will be built with image and GL libraries. Leave -# 'extra_tests' empty (default) to disable extra test programs. -# Instead of adding the tests to the variable in the 'set' command you -# can also add it with `list(APPEND extra_tests test1 test2)` etc.. -# See commented example at the end of this paragraph. - -set(extra_tests) - -# Uncomment the following statement to set the C++ standard for your -# extra test(s), or add more such lines, using "TEST_cxx_standard" as -# variable names (replace 'TEST' with your program name), and set the -# variable to one of { 14, 17, 20, 23 } for C++14, C++17, ... resp.. -# The default is not to change the C++ standard, i.e. compile with -# C++11 or whatever the user chose to build the FLTK library. - -# set(TEST_cxx_standard 20) - -# Example code (do not uncomment these examples): -#------------------------------------------------ -# set(extra_tests test1 test2 test3) -# set(test2_cxx_standard 17) -# set(test3_cxx_standard 20) -#------------------------------------------------ -# This would build test1(.cxx) with default settings, test2 with C++17, -# and test3 with C++20. -# -####################################################################### -# audio libs for test apps -if(WIN32) - set(AUDIOLIBS winmm) -elseif(APPLE) - set(AUDIOLIBS "-framework CoreAudio") -elseif(HAVE_ALSA_ASOUNDLIB_H) - find_library(LIB_asound asound) - if(LIB_asound) - set(AUDIOLIBS ${LIB_asound}) - endif(LIB_asound) - mark_as_advanced (LIB_asound) -endif(WIN32) - -####################################################################### -# Define standard libraries for those OpenGL demos that can be built -# w/o OpenGL as well. These demos show an alternate GUI or a warning -# when built w/o OpenGL. -# -# For building with Visual Studio (MSVC) we also include the special -# object library 'call_main' when linking with the shared libraries. -# Setting the correct library variants as CMake variables may appear -# confusing but simplifies the build instructions below (makes them -# platform independent). -# -# Note that all CMake variables for libraries can be "CMake lists" -# and must therefore be quoted when used in fl_create_example(). -####################################################################### - -if(OPENGL_FOUND) - set(GLDEMO_LIBS fltk::gl) - if(MSVC) - set(GLDEMO_SHARED "call_main;fltk::fltk-shared") - else() - set(GLDEMO_SHARED fltk::gl-shared) - endif() -else() - # build w/o OpenGL libraries - set(GLDEMO_LIBS fltk::fltk) - if(MSVC) - set(GLDEMO_SHARED "call_main;fltk::fltk-shared") - else() - set(GLDEMO_SHARED "fltk::fltk-shared") - endif() -endif() - -# set FLTK_SHARED and IMAGES_SHARED depending on the platform (MSVC or ...) - -if(MSVC) - set(FLTK_SHARED "call_main;fltk::fltk-shared") - set(IMAGES_SHARED "${FLTK_SHARED}") -else() - set(FLTK_SHARED "fltk::fltk-shared") - set(IMAGES_SHARED "fltk::images-shared") -endif() - -# similar for the 'forms' demo (shared lib not supported) - -if(FLTK_BUILD_FORMS) - set(FORMS_LIBS fltk::forms) -else() - set(FORMS_LIBS fltk::fltk) -endif() - -####################################################################### - -fl_create_example(adjuster adjuster.cxx fltk::fltk) -fl_create_example(arc arc.cxx fltk::fltk) -fl_create_example(animated animated.cxx fltk::fltk) -fl_create_example(ask ask.cxx fltk::fltk) -fl_create_example(bitmap bitmap.cxx fltk::fltk) -fl_create_example(boxtype boxtype.cxx fltk::fltk) -fl_create_example(browser browser.cxx fltk::fltk) -fl_create_example(button button.cxx fltk::fltk) -fl_create_example(buttons buttons.cxx fltk::fltk) -# Cairo demo, built with and w/o Cairo (libcairo is linked implicitly - or not at all) -fl_create_example(cairo_test cairo_test.cxx fltk::fltk) -fl_create_example(clipboard clipboard.cxx fltk::images) -fl_create_example(clock clock.cxx fltk::fltk) -fl_create_example(colbrowser colbrowser.cxx fltk::fltk) -fl_create_example(color_chooser color_chooser.cxx fltk::fltk) -fl_create_example(contrast contrast.cxx fltk::fltk) -fl_create_example(coordinates coordinates.cxx fltk::fltk) -fl_create_example(cursor cursor.cxx fltk::fltk) -fl_create_example(curve curve.cxx fltk::fltk) -fl_create_example(demo demo.cxx fltk::fltk) -fl_create_example(device device.cxx fltk::images) -fl_create_example(doublebuffer doublebuffer.cxx fltk::fltk) -fl_create_example(editor "editor.cxx;editor.plist" fltk::fltk) -fl_create_example(fast_slow fast_slow.fl fltk::fltk) -fl_create_example(file_chooser file_chooser.cxx fltk::images) -fl_create_example(flex_demo flex_demo.cxx fltk::fltk) -fl_create_example(flex_login flex_login.cxx fltk::fltk) -fl_create_example(fltk-versions fltk-versions.cxx fltk::fltk) -fl_create_example(fonts fonts.cxx fltk::fltk) -fl_create_example(forms forms.cxx "${FORMS_LIBS}") -fl_create_example(fullscreen fullscreen.cxx "${GLDEMO_LIBS}") -fl_create_example(grid_alignment grid_alignment.cxx fltk::fltk) -fl_create_example(grid_buttons grid_buttons.cxx fltk::fltk) -fl_create_example(grid_dialog grid_dialog.cxx fltk::fltk) -fl_create_example(grid_login grid_login.cxx fltk::fltk) -fl_create_example(group group.cxx fltk::fltk) -fl_create_example(handle_events handle_events.cxx "${GLDEMO_LIBS}") -fl_create_example(handle_keys handle_keys.cxx fltk::fltk) -fl_create_example(hello hello.cxx fltk::fltk) -fl_create_example(help_dialog help_dialog.cxx fltk::images) -fl_create_example(icon icon.cxx fltk::fltk) -fl_create_example(iconize iconize.cxx fltk::fltk) -fl_create_example(image image.cxx fltk::fltk) -fl_create_example(inactive inactive.fl fltk::fltk) -fl_create_example(input input.cxx fltk::fltk) -fl_create_example(input_choice input_choice.cxx fltk::fltk) -fl_create_example(keyboard "keyboard.cxx;keyboard_ui.fl" fltk::fltk) -fl_create_example(label label.cxx fltk::fltk) -fl_create_example(line_style line_style.cxx fltk::fltk) -fl_create_example(line_style_docs line_style_docs.cxx fltk::fltk) -fl_create_example(list_visuals list_visuals.cxx fltk::fltk) -fl_create_example(mandelbrot "mandelbrot_ui.fl;mandelbrot.cxx" fltk::fltk) -fl_create_example(menubar menubar.cxx fltk::fltk) -fl_create_example(message message.cxx fltk::fltk) -fl_create_example(minimum minimum.cxx fltk::fltk) -fl_create_example(native-filechooser native-filechooser.cxx fltk::images) -fl_create_example(navigation navigation.cxx fltk::fltk) -fl_create_example(output output.cxx fltk::fltk) -fl_create_example(overlay overlay.cxx fltk::fltk) -fl_create_example(pack pack.cxx fltk::fltk) - -if(FLTK_HAVE_PEN_SUPPORT) - fl_create_example(penpal penpal.cxx fltk::fltk) -endif() - -fl_create_example(pixmap pixmap.cxx fltk::images) -fl_create_example(pixmap_browser pixmap_browser.cxx fltk::images) -fl_create_example(preferences preferences.fl fltk::fltk) -fl_create_example(offscreen offscreen.cxx fltk::fltk) -fl_create_example(radio radio.fl fltk::fltk) -fl_create_example(resize resize.fl fltk::fltk) -fl_create_example(resizebox resizebox.cxx fltk::fltk) -fl_create_example(resize-example1 "resize-example1.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example2 "resize-example2.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example3a "resize-example3a.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example3b "resize-example3b.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example3c "resize-example3c.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example4a "resize-example4a.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example4b "resize-example4b.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example5a "resize-example5a.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example5b "resize-example5b.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(resize-example5c "resize-example5c.cxx;resize-arrows.cxx" fltk::fltk) -fl_create_example(rotated_text rotated_text.cxx fltk::fltk) -fl_create_example(scroll scroll.cxx fltk::fltk) -fl_create_example(subwindow subwindow.cxx fltk::fltk) -fl_create_example(symbols symbols.cxx fltk::fltk) -fl_create_example(tabs tabs.fl fltk::fltk) -fl_create_example(table table.cxx fltk::fltk) -fl_create_example(terminal terminal.fl fltk::fltk) -fl_create_example(threads threads.cxx fltk::fltk) -fl_create_example(tile tile.cxx fltk::fltk) -fl_create_example(tiled_image tiled_image.cxx fltk::fltk) -fl_create_example(tree tree.fl fltk::fltk) -fl_create_example(twowin twowin.cxx fltk::fltk) -fl_create_example(utf8 utf8.cxx fltk::fltk) -fl_create_example(valuators valuators.fl fltk::fltk) -fl_create_example(windowfocus windowfocus.cxx fltk::fltk) -fl_create_example(wizard wizard.cxx fltk::fltk) - -# games w/o shared libs - -if(NOT FLTK_BUILD_SHARED_LIBS) - fl_create_example(blocks "blocks.cxx;blocks.plist;blocks.icns" "fltk::fltk;${AUDIOLIBS}") - fl_create_example(checkers "checkers.cxx;checkers.plist;checkers_pieces.fl;checkers.icns" fltk::images) - fl_create_example(sudoku "sudoku.cxx;sudoku.plist;sudoku.icns;sudoku.rc" "fltk::images;${AUDIOLIBS}") -endif() - -# unittests uses multiple source files and can be built with or w/o OpenGL and "shared" - -SET (UNITTEST_SRCS - unittests.cxx - unittests.h - unittest_about.cxx - unittest_points.cxx - unittest_core.cxx - unittest_complex_shapes.cxx - unittest_fast_shapes.cxx - unittest_circles.cxx - unittest_text.cxx - unittest_unicode.cxx - unittest_symbol.cxx - unittest_images.cxx - unittest_viewport.cxx - unittest_scrollbarsize.cxx - unittest_schemes.cxx - unittest_terminal.cxx -) -fl_create_example(unittests "${UNITTEST_SRCS}" "${GLDEMO_LIBS}") - -# Additional test programs used by developers for testing (see above) - -if(extra_tests) - foreach(name ${extra_tests}) - fl_create_example(${name} ${name}.cxx "fltk::images;${GLDEMO_LIBS}") - if(DEFINED ${name}_cxx_standard) - set_target_properties(${name} PROPERTIES CXX_STANDARD ${${name}_cxx_standard}) - endif() - endforeach() -endif() - -# OpenGL demos. These programs can't be built w/o OpenGL - -if(OPENGL_FOUND) - fl_create_example(CubeView "CubeMain.cxx;CubeView.cxx;CubeViewUI.fl" "${GLDEMO_LIBS}") - fl_create_example(cube cube.cxx "${GLDEMO_LIBS}") - fl_create_example(fractals "fractals.cxx;fracviewer.cxx" "${GLDEMO_LIBS}") - fl_create_example(glut_test glut_test.cxx "${GLDEMO_LIBS}") - if(NOT FLTK_BUILD_SHARED_LIBS) - fl_create_example(glpuzzle glpuzzle.cxx "${GLDEMO_LIBS}") - endif() - fl_create_example(gl_overlay gl_overlay.cxx "${GLDEMO_LIBS}") - fl_create_example(shape shape.cxx "${GLDEMO_LIBS}") -endif(OPENGL_FOUND) - -# Test FLTK headers for variable shadowing [-Wshadow] (STR 2728) -# -# The following test program is added only for GNU or Clang compilers which -# are known to support the '-Wshadow' compiler flag. We could also implement -# a compile test but using GNU and Clang appears to be sufficient. -# -# Note 1: usage of `file(GLOB ...)` is discouraged by CMake documentation because -# it doesn't trigger rebuilding when new header files are added. However, this -# is better than nothing. -# -# Note 2: a better way to generate the header file might be with a custom command -# to be able to generate proper dependencies but this is left for later... -# -# Note 3: this test program is only included in CMake builds and was inspired -# by STR 2728: "Add test program to test for shadowed variables (-Wshadow)". -# Its sole purpose is to issue compilation warnings during build time if -# variables are shadowed in public headers. - -set(_compilers GNU Clang AppleClang) -if(CMAKE_CXX_COMPILER_ID IN_LIST _compilers) - - set(include_all "${CMAKE_CURRENT_BINARY_DIR}/include_all.h") - file(WRITE ${include_all} "/* DO NOT EDIT - this file is created by CMake */\n") - - file(GLOB all_headers "${FLTK_SOURCE_DIR}/FL/*.[hH]") - foreach(hd ${all_headers}) - get_filename_component(hd "${hd}" NAME) - # skip headers that must not be included directly and fl_config.h if it exists - string(REGEX MATCH "^(mac|win32|x11|wayland|fl_config|gl[a-z_0-9]*)\.[hH]$" skip "${hd}") - if(skip STREQUAL "") - file(APPEND ${include_all} "#include <FL/${hd}>\n") - endif() - endforeach() - if(FLTK_USE_GL) - file(GLOB all_headers "${FLTK_SOURCE_DIR}/FL/gl*.[hH]") - foreach(hd ${all_headers}) - get_filename_component(hd "${hd}" NAME) - file(APPEND ${include_all} "#include <FL/${hd}>\n") - endforeach() - endif(FLTK_USE_GL) - file(APPEND ${include_all} "/* End of generated file */\n") - - # now add the 'shadow_variables' target and set the compiler flag - - fl_create_example(shadow_variables shadow_variables.cxx fltk::fltk) - set_target_properties(shadow_variables PROPERTIES COMPILE_FLAGS -Wshadow) - -endif() # GNU or Clang (-Wshadow test) -unset(_compilers) - -######################################################################### -# Build some of the demo programs linked against the shared FLTK lib(s) -######################################################################### - -if(FLTK_BUILD_SHARED_LIBS) - - fl_create_example(cairo_test-shared cairo_test.cxx "${FLTK_SHARED}") - fl_create_example(hello-shared hello.cxx "${FLTK_SHARED}") - fl_create_example(pixmap_browser-shared pixmap_browser.cxx "${IMAGES_SHARED}") - fl_create_example(unittests-shared "${UNITTEST_SRCS}" "${GLDEMO_SHARED}") - - # Games - fl_create_example(blocks-shared "blocks.cxx;blocks.plist;blocks.icns" "${FLTK_SHARED};${AUDIOLIBS}") - fl_create_example(checkers-shared "checkers.cxx;checkers.plist;checkers_pieces.fl;checkers.icns" "${IMAGES_SHARED}") - fl_create_example(sudoku-shared "sudoku.cxx;sudoku.plist;sudoku.icns;sudoku.rc" "${IMAGES_SHARED};${AUDIOLIBS}") - - # demo programs that can't be built w/o OpenGL - if(OPENGL_FOUND) - fl_create_example(glpuzzle-shared glpuzzle.cxx "${GLDEMO_SHARED}") - fl_create_example(shape-shared shape.cxx "${GLDEMO_SHARED}") - endif(OPENGL_FOUND) - -endif(FLTK_BUILD_SHARED_LIBS) - -##################################################### -# We need some support files for the demo programs -##################################################### - -# copy the required test files - -file(COPY - demo.menu rgb.txt browser.cxx editor.cxx valuators.fl - help_dialog.html - DESTINATION ${TESTFILE_PATH} -) - -# copy the image directory for help_dialog.html - -file(COPY - ${CMAKE_CURRENT_SOURCE_DIR}/images - DESTINATION ${TESTFILE_PATH} -) - -# The main test program 'demo' needs additional hints and configurations. -# Note: CMake defines "CMAKE_INTDIR" which is the build type folder (e.g. "Debug") -# for multi config builds (MSVC, Xcode) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt deleted file mode 100644 index 0e140a263..000000000 --- a/util/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# -# CMakeLists.txt to build utilities for the FLTK project using CMake (www.cmake.org) -# -# Copyright 1998-2026 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# Build utilities for FLTK development - -# Note: utilities are only built internally during the build process -# and not installed. They are tools used to generate source files or -# assist in building documentation. - -####################################################################### -# cmap - colormap generation program -####################################################################### - -# This program produces the contents of "src/fl_cmap.h". -# It can be used to modify the built-in colormap in src/fl_cmap.h. -# This utility must be built and executed manually. See instructions -# in util/cmap.cxx . - -add_executable(cmap cmap.cxx) - -# cmap doesn't need to link against FLTK libraries - it's a standalone tool, -# but it requires libm on Unix/Linux - link against libm, but only if found. - -if(LIB_m) - target_link_libraries(cmap PRIVATE m) -endif() - -# Set properties -set_target_properties(cmap PROPERTIES - OUTPUT_NAME cmap - EXCLUDE_FROM_ALL TRUE -) - -####################################################################### -# PDF documentation tool to generate a png image from a -# Doxygen `@code` segment with international characters -####################################################################### - -if(FLTK_BUILD_PDF_DOCS) - - # PDF documentation helper tool - add_executable(code_snapshot - code_snapshot.cxx - ../fluid/widgets/Code_Viewer.cxx - ../fluid/widgets/Code_Editor.cxx - ../fluid/widgets/Style_Parser.cxx - ) - - target_link_libraries(code_snapshot PRIVATE fltk::images) - - set_target_properties(code_snapshot PROPERTIES - OUTPUT_NAME code_snapshot - EXCLUDE_FROM_ALL FALSE - ) - - target_include_directories(code_snapshot PRIVATE - ../fluid - ) - - message(STATUS "PDF code snapshot tools will be built (FLTK_BUILD_PDF_DOCS=ON)") - -endif(FLTK_BUILD_PDF_DOCS) - -####################################################################### -# Install rules (if any tools need to be installed) -####################################################################### - -# Currently no utilities are installed as they are build-time tools only. -# If you need to install any utilities, add install() commands here. diff --git a/zlib/CMakeLists.txt b/zlib/CMakeLists.txt deleted file mode 100644 index 241804a3e..000000000 --- a/zlib/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# -# ZLIB library CMake configuration for the Fast Light Toolkit (FLTK). -# -# Copyright 1998-2024 by Bill Spitzak and others. -# -# This library is free software. Distribution and use rights are outlined in -# the file "COPYING" which should have been included with this file. If this -# file is missing or damaged, see the license at: -# -# https://www.fltk.org/COPYING.php -# -# Please see the following page on how to report bugs and issues: -# -# https://www.fltk.org/bugs.php -# - -# source files for zlib - -set(ZLIB_SRCS - adler32.c - compress.c - crc32.c - deflate.c - gzclose.c - gzlib.c - gzread.c - gzwrite.c - inflate.c - infback.c - inftrees.c - inffast.c - trees.c - uncompr.c - zutil.c -) - -####################################################################### - -# Suppress some Visual Studio compiler warnings - -set(msvc_warnings /wd4267 /wd4996) - -####################################################################### -# Build the static library -####################################################################### - -fl_add_library(fltk_z STATIC "${ZLIB_SRCS}") - -if(MSVC) - target_compile_options(fltk_z PRIVATE ${msvc_warnings}) -endif(MSVC) - -####################################################################### -# Build the shared library (optional) -####################################################################### - -if(FLTK_BUILD_SHARED_LIBS) - - # ensure to export all symbols for Windows DLL's - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) - - fl_add_library(fltk_z SHARED "${ZLIB_SRCS}") - - if(MSVC) - target_compile_options(fltk_z-shared PRIVATE ${msvc_warnings}) - endif(MSVC) - -endif(FLTK_BUILD_SHARED_LIBS) - -set(FLTK_LIBRARIES ${FLTK_LIBRARIES} PARENT_SCOPE) -set(FLTK_LIBRARIES_SHARED ${FLTK_LIBRARIES_SHARED} PARENT_SCOPE) - -####################################################################### -# Install the library headers -####################################################################### - -install(FILES zconf.h zlib.h zutil.h - DESTINATION ${FLTK_INCLUDEDIR}/FL/images -) |
