summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1071
-rw-r--r--src/Fl.cxx67
-rw-r--r--src/Fl_Cairo.cxx138
-rw-r--r--src/Fl_MacOS_Sys_Menu_Bar.mm785
-rw-r--r--src/Fl_Native_File_Chooser_MAC.mm825
-rw-r--r--src/Fl_Native_File_Chooser_WIN32.cxx1061
-rw-r--r--src/Fl_cocoa.mm4793
-rw-r--r--src/Fl_get_key_mac.cxx102
-rw-r--r--src/Fl_get_key_win32.cxx127
-rw-r--r--src/Fl_win32.cxx2976
-rw-r--r--src/Fl_x.cxx2
-rw-r--r--src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H2
-rw-r--r--src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx2
-rw-r--r--src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx2
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H60
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm527
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm439
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm455
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H114
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx434
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H168
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx294
-rw-r--r--src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H51
-rw-r--r--src/drivers/Darwin/Fl_Darwin_System_Driver.H85
-rw-r--r--src/drivers/Darwin/Fl_Darwin_System_Driver.cxx339
-rw-r--r--src/drivers/Darwin/fl_macOS_platform_init.cxx59
-rw-r--r--src/drivers/GDI/Fl_Font.H43
-rw-r--r--src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H35
-rw-r--r--src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx95
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver.H230
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx322
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx89
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx259
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx678
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx826
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx111
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx320
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx231
-rw-r--r--src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H44
-rw-r--r--src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx169
-rw-r--r--src/drivers/PostScript/Fl_PostScript.cxx8
-rw-r--r--src/drivers/PostScript/Fl_PostScript_image.cxx2
-rw-r--r--src/drivers/Quartz/Fl_Font.H42
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H39
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx71
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H149
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx133
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx65
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx70
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx561
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx284
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx83
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx310
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx98
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H38
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx167
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H34
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx60
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H62
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx486
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H72
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx310
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H40
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx185
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.H193
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx2204
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.H185
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx2191
-rw-r--r--src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx741
-rw-r--r--src/drivers/Wayland/fl_wayland_platform_init.cxx157
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H62
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx472
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx518
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx518
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H104
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx493
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_System_Driver.H124
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx1134
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H131
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx731
-rw-r--r--src/drivers/WinAPI/fl_WinAPI_platform_init.cxx85
-rw-r--r--src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx2
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H2
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx2
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H2
-rw-r--r--src/fl_call_main.c158
-rw-r--r--src/fl_dnd_win32.cxx559
-rw-r--r--src/fl_encoding_latin1.cxx13
-rw-r--r--src/fl_encoding_mac_roman.cxx117
-rw-r--r--src/flstring.h5
-rw-r--r--src/forms_fselect.cxx7
-rw-r--r--src/scandir_win32.c164
92 files changed, 39 insertions, 32834 deletions
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 = &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 = &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,
- &gtk_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, &registry_listener, &pair);
- struct wl_callback *registry_cb = wl_display_sync(wl_display);
- wl_callback_add_listener(registry_cb, &sync_listener, &registry_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, &current_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, &current_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