diff options
Diffstat (limited to 'src/drivers')
74 files changed, 11 insertions, 19892 deletions
diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index eee10900d..ca0cf5095 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H @@ -23,7 +23,7 @@ #include <FL/Fl_Graphics_Driver.H> #include "../../Fl_Scalable_Graphics_Driver.H" // Fl_Font_Descriptor -#include <cairo/cairo.h> +#include <cairo.h> typedef struct _PangoLayout PangoLayout; typedef struct _PangoContext PangoContext; diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index 236a677b1..bf2e2d361 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx @@ -26,7 +26,7 @@ #include <FL/platform.H> #include <FL/fl_draw.H> #include <FL/fl_utf8.h> -#include <cairo/cairo.h> +#include <cairo.h> #include <pango/pangocairo.h> #if ! PANGO_VERSION_CHECK(1,16,0) # error "Requires Pango 1.16 or higher" diff --git a/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx index ed04d1167..a400460d8 100644 --- a/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_X11_Cairo_Graphics_Driver.cxx @@ -20,7 +20,7 @@ #include "Fl_X11_Cairo_Graphics_Driver.H" #include <FL/platform.H> -#include <cairo/cairo.h> +#include <cairo.h> #include <pango/pangocairo.h> #include <stdlib.h> diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H deleted file mode 100644 index d5ba9c21c..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H +++ /dev/null @@ -1,60 +0,0 @@ -// -// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Gl_Window_Driver.H" - -class Fl_Gl_Choice; -#ifdef __OBJC__ - @class NSOpenGLContext; -#else - class NSOpenGLContext; -#endif - -class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { - NSOpenGLContext *gl1ctxt; // GL1 context in addition to GL3 context - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win); - float pixels_per_unit() FL_OVERRIDE; - void before_show(int& need_after) FL_OVERRIDE; - void after_show() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void make_current_before() FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void resize(int is_a_resize, int w, int h) FL_OVERRIDE; - char swap_type() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void gl_start() FL_OVERRIDE; - char *alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) FL_OVERRIDE; - Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h) FL_OVERRIDE; - bool need_scissor() FL_OVERRIDE { return true; } - void* GetProcAddress(const char *procName) FL_OVERRIDE; - void apply_scissor(); - void switch_to_GL1() FL_OVERRIDE; - void switch_back() FL_OVERRIDE; -}; - - -#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm deleted file mode 100644 index 561aa2ce5..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm +++ /dev/null @@ -1,527 +0,0 @@ -// -// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include <FL/gl.h> -#include "../../Fl_Gl_Choice.H" -#include "../../Fl_Screen_Driver.H" -#include "Fl_Cocoa_Window_Driver.H" -#include "Fl_Cocoa_Gl_Window_Driver.H" -#include <FL/Fl_Graphics_Driver.H> -#include <OpenGL/OpenGL.h> -#include <FL/Fl_Image_Surface.H> -#include <dlfcn.h> - -#import <Cocoa/Cocoa.h> - -/* macOS offers only core contexts when using GL3. This forbids to draw - FLTK widgets in a GL3-using NSOpenGLContext because these widgets are drawn - with the GL1-based Fl_OpenGL_Graphics_Driver. The solution implemented here - is to create an additional NSView and an associated additional NSOpenGLContext - (gl1ctxt) placed above and sized as the GL3-based window, to set the new - NSOpenGLContext non opaque and GL1-based, and to draw the FLTK widgets in the - new view/GL1 context. - */ - -// Describes crap needed to create a GLContext. -class Fl_Cocoa_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_Cocoa_Gl_Window_Driver; -private: - NSOpenGLPixelFormat* pixelformat; -public: - Fl_Cocoa_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - pixelformat = NULL; - } -}; - - -Fl_Cocoa_Gl_Window_Driver::Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : - Fl_Gl_Window_Driver(win) { - gl1ctxt = NULL; -} - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_Cocoa_Gl_Window_Driver(w); -} - - -static NSOpenGLPixelFormat* mode_to_NSOpenGLPixelFormat(int m, const int *alistp) -{ - NSOpenGLPixelFormatAttribute attribs[32]; - int n = 0; - // AGL-style code remains commented out for comparison - if (!alistp) { - if (m & FL_INDEX) { - //list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; - } else { - //list[n++] = AGL_RGBA; - //list[n++] = AGL_GREEN_SIZE; - //list[n++] = (m & FL_RGB8) ? 8 : 1; - attribs[n++] = NSOpenGLPFAColorSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 32 : 1); - if (m & FL_ALPHA) { - //list[n++] = AGL_ALPHA_SIZE; - attribs[n++] = NSOpenGLPFAAlphaSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 8 : 1); - } - if (m & FL_ACCUM) { - //list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAAccumSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - if (m & FL_ALPHA) { - //list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; - } - } - } - if (m & FL_DOUBLE) { - //list[n++] = AGL_DOUBLEBUFFER; - attribs[n++] = NSOpenGLPFADoubleBuffer; - } - if (m & FL_DEPTH32) { - //list[n++] = AGL_DEPTH_SIZE; list[n++] = 32; - attribs[n++] = NSOpenGLPFADepthSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)32; - } else if (m & FL_DEPTH) { - //list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; - attribs[n++] = NSOpenGLPFADepthSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)24; - } - if (m & FL_STENCIL) { - //list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAStencilSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - } - if (m & FL_STEREO) { - //list[n++] = AGL_STEREO; - attribs[n++] = 6/*NSOpenGLPFAStereo*/; - } - if (m & FL_MULTISAMPLE) { - attribs[n++] = NSOpenGLPFAMultisample; // 10.4 - attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - attribs[n++] = NSOpenGLPFASamples; attribs[n++] = (NSOpenGLPixelFormatAttribute)4; - } - attribs[n++] = NSOpenGLPFAOpenGLProfile; - attribs[n++] = (m & FL_OPENGL3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy; - } else { - while (alistp[n] && n < 30) { - attribs[n] = (NSOpenGLPixelFormatAttribute)alistp[n]; - n++; - } - } - attribs[n] = (NSOpenGLPixelFormatAttribute)0; - NSOpenGLPixelFormat *pixform = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - /*GLint color,alpha,accum,depth; - [pixform getValues:&color forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0]; - [pixform getValues:&alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0]; - [pixform getValues:&accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:0]; - [pixform getValues:&depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0]; - NSLog(@"color=%d alpha=%d accum=%d depth=%d",color,alpha,accum,depth);*/ - return pixform; -} - - -Fl_Gl_Choice *Fl_Cocoa_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl::screen_driver()->open_display(); // useful when called through gl_start() - Fl_Cocoa_Gl_Choice *g = (Fl_Cocoa_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - NSOpenGLPixelFormat* fmt = mode_to_NSOpenGLPixelFormat(m, alistp); - if (!fmt) return 0; - g = new Fl_Cocoa_Gl_Choice(m, alistp, first); - first = g; - g->pixelformat = fmt; - return g; -} - - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -# define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity -#endif - -static void remove_gl_context_opacity(NSOpenGLContext *ctx) { - GLint gl_opacity; - [ctx getValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - if (gl_opacity != 0) { - gl_opacity = 0; - [ctx setValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - } -} - - -static NSOpenGLContext *create_GLcontext_for_window( - NSOpenGLPixelFormat *pixelformat, - NSOpenGLContext *shared_ctx, Fl_Window *window) -{ - NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:shared_ctx]; - if (shared_ctx && !context) context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:nil]; - if (context) { - NSView *view = [fl_xid(window) contentView]; - [view setWantsBestResolutionOpenGLSurface:(Fl::use_high_res_GL() != 0)]; - [context setView:view]; - if (Fl_Cocoa_Window_Driver::driver(window)->subRect()) { - remove_gl_context_opacity(context); - } - } - return context; -} - -GLContext Fl_Cocoa_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) { - GLContext context, shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - // resets the pile of string textures used to draw strings - // necessary before the first context is created - if (!shared_ctx) gl_texture_reset(); - context = create_GLcontext_for_window(((Fl_Cocoa_Gl_Choice*)g)->pixelformat, (NSOpenGLContext*)shared_ctx, window); - if (!context) return 0; - add_context(context); - [(NSOpenGLContext*)context makeCurrentContext]; - glClearColor(0., 0., 0., 1.); - apply_scissor(); - return (context); -} - -void Fl_Cocoa_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - if (context != current_context || w != cached_window) { - cached_window = w; - [(NSOpenGLContext*)context makeCurrentContext]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::delete_gl_context(GLContext context) { - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - if (current_context == context) { - cached_window = 0; - [current_context clearDrawable]; - } - [(NSOpenGLContext*)context release]; - del_context(context); - if (gl1ctxt) { - [[gl1ctxt view] release]; - [gl1ctxt release]; - gl1ctxt = 0; - } -} - -void Fl_Cocoa_Gl_Window_Driver::make_overlay_current() { - // this is not very useful, but unfortunately, Apple decided - // that front buffer drawing can no longer (OS X 10.4) be supported on their platforms. - if (pWindow->shown()) pWindow->make_current(); -} - -void Fl_Cocoa_Gl_Window_Driver::redraw_overlay() { - pWindow->redraw(); -} - -void Fl_Cocoa_Gl_Window_Driver::before_show(int& need_after) { - need_after = 1; -} - -void Fl_Cocoa_Gl_Window_Driver::after_show() { - // Makes sure the GL context is created to avoid drawing twice the window when first shown - pWindow->make_current(); - if ((mode() & FL_OPENGL3) && !gl1ctxt) { - // Create transparent GL1 scene above the GL3 scene to hold child widgets and/or text - NSView *view = [fl_mac_xid(pWindow) contentView]; - NSView *gl1view = [[NSView alloc] initWithFrame:[view frame]]; - [gl1view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - static NSOpenGLContext *shared_gl1_ctxt = nil; - static NSOpenGLPixelFormat *gl1pixelformat = mode_to_NSOpenGLPixelFormat( - FL_RGB8 | FL_ALPHA | FL_SINGLE, NULL); - gl1ctxt = [[NSOpenGLContext alloc] initWithFormat:gl1pixelformat shareContext:shared_gl1_ctxt]; - if (!shared_gl1_ctxt) { - shared_gl1_ctxt = gl1ctxt; - [shared_gl1_ctxt retain]; - } - [view addSubview:gl1view]; - if (Fl::use_high_res_GL()) { - [gl1view setWantsBestResolutionOpenGLSurface:YES]; - } - [gl1ctxt setView:gl1view]; - remove_gl_context_opacity(gl1ctxt); - } -} - -float Fl_Cocoa_Gl_Window_Driver::pixels_per_unit() -{ - int retina = (Fl::use_high_res_GL() && Fl_X::flx(pWindow) && - Fl_Cocoa_Window_Driver::driver(pWindow)->mapped_to_retina()) ? 2 : 1; - return retina * Fl_Graphics_Driver::default_driver().scale(); -} - -int Fl_Cocoa_Gl_Window_Driver::mode_(int m, const int *a) { - if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, - // the FL_DOUBLE flag must be set in the mode_ member variable - const int *aa = a; - while (*aa) { - if (*(aa++) == - kCGLPFADoubleBuffer - ) { m |= FL_DOUBLE; break; } - } - } - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - pWindow->redraw(); - } else { - g(0); - } - return 1; -} - -void Fl_Cocoa_Gl_Window_Driver::make_current_before() { - // detect if the window was moved between low and high resolution displays - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(pWindow); - if (d->changed_resolution()){ - d->changed_resolution(false); - pWindow->invalidate(); - [(NSOpenGLContext*)pWindow->context() update]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::swap_buffers() { - if (overlay() != NULL) { - // STR# 2944 [1] - // Save matrixmode/proj/modelview/rasterpos before doing overlay. - // - int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); - GLint matrixmode; - GLfloat pos[4]; - glGetIntegerv(GL_MATRIX_MODE, &matrixmode); - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos - glMatrixMode(GL_PROJECTION); // save proj/model matrices - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(2.0f/wo, 2.0f/ho, 1.0f); - glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window - glRasterPos2i(0,0); // set glRasterPos to bottom left corner - { - // Emulate overlay by doing copypixels - glReadBuffer(GL_BACK); - glDrawBuffer(GL_FRONT); - glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT - } - glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(matrixmode); - glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos - } else { - [(NSOpenGLContext*)pWindow->context() flushBuffer]; - } -} - -char Fl_Cocoa_Gl_Window_Driver::swap_type() {return copy;} - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -# define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval -#endif - -void Fl_Cocoa_Gl_Window_Driver::swap_interval(int n) { - GLint interval = (GLint)n; - NSOpenGLContext* ctx = (NSOpenGLContext*)pWindow->context(); - if (ctx) - [ctx setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; -} - -int Fl_Cocoa_Gl_Window_Driver::swap_interval() const { - GLint interval = (GLint)-1; - NSOpenGLContext* ctx = (NSOpenGLContext*)pWindow->context(); - if (ctx) - [ctx getValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; - return interval; -} - -void Fl_Cocoa_Gl_Window_Driver::resize(int is_a_resize, int w, int h) { - if (pWindow->shown()) apply_scissor(); - [(NSOpenGLContext*)pWindow->context() update]; - if (gl1ctxt) { - [gl1ctxt update]; - } -} - -void Fl_Cocoa_Gl_Window_Driver::apply_scissor() { - if (glIsEnabled(GL_SCISSOR_TEST)) glDisable(GL_SCISSOR_TEST); - CGRect *extents = Fl_Cocoa_Window_Driver::driver(pWindow)->subRect(); - if (extents) { - remove_gl_context_opacity((NSOpenGLContext*)pWindow->context()); - GLdouble vals[4]; - glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(vals[0], vals[1], vals[2], vals[3]); - float s = pWindow->pixels_per_unit(); - glScissor(s*extents->origin.x, s*extents->origin.y, s*extents->size.width, s*extents->size.height); -//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - glEnable(GL_SCISSOR_TEST); - } -} - - -/* Some old Apple hardware doesn't implement the GL_EXT_texture_rectangle extension. - For it, draw_string_legacy_glut() is used to draw text. */ - -char *Fl_Cocoa_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) -{ - // write str to a bitmap just big enough - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Font f=fl_font(); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); - fl_font(f, fs); - fl_draw(str, n, 0, fl_height() - fl_descent()); - // get the alpha channel only of the bitmap - char *alpha_buf = new char[w*h], *r = alpha_buf, *q; - q = (char*)CGBitmapContextGetData((CGContextRef)surf->offscreen()); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - *r++ = *(q+3); - q += 4; - } - } - Fl_Surface_Device::pop_current(); - delete surf; - return alpha_buf; -} - -void Fl_Cocoa_Gl_Window_Driver::gl_start() { - [(NSOpenGLContext*)gl_start_context update]; -} - -// convert BGRA to RGB and also exchange top and bottom -static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) -{ - uchar *newimg = new uchar[3*w*h]; - uchar *to = newimg; - for (int i = h-1; i >= 0; i--) { - uchar *from = baseAddress + i * mByteWidth; - for (int j = 0; j < w; j++, from += 4) { -#if defined(__ppc__) && __ppc__ - memcpy(to, from + 1, 3); - to += 3; -#else - *(to++) = *(from+2); - *(to++) = *(from+1); - *(to++) = *from; -#endif - } - } - delete[] baseAddress; - return newimg; -} - - -static Fl_RGB_Image *cgimage_to_rgb4(CGImageRef img) { - int w = (int)CGImageGetWidth(img); - int h = (int)CGImageGetHeight(img); - CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - uchar *rgba = new uchar[4 * w * h]; - CGContextRef auxgc = CGBitmapContextCreate(rgba, w, h, 8, 4 * w, cspace, - kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(cspace); - CGContextDrawImage(auxgc, CGRectMake(0, 0, w, h), img); - CGContextRelease(auxgc); - Fl_RGB_Image *rgb = new Fl_RGB_Image(rgba, w, h, 4); - rgb->alloc_array = 1; - return rgb; -} - - -Fl_RGB_Image* Fl_Cocoa_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) -{ - Fl_Gl_Window* glw = pWindow; - float factor = glw->pixels_per_unit(); - if (factor != 1) { - w *= factor; h *= factor; x *= factor; y *= factor; - } - NSWindow *nswin = (NSWindow*)fl_mac_xid(pWindow); - CGImageRef img_full = Fl_Cocoa_Window_Driver::capture_decorated_window_10_5(nswin); - int bt = [nswin frame].size.height - [[nswin contentView] frame].size.height; - bt *= (factor / Fl_Graphics_Driver::default_driver().scale()); - CGRect cgr = CGRectMake(x, y + bt, w, h); // add vertical offset to bypass titlebar - CGImageRef cgimg = CGImageCreateWithImageInRect(img_full, cgr); // 10.4 - CGImageRelease(img_full); - Fl_RGB_Image *rgb = cgimage_to_rgb4(cgimg); - CGImageRelease(cgimg); - return rgb; - [(NSOpenGLContext*)glw->context() makeCurrentContext]; - // to capture also the overlay and for directGL demo - [(NSOpenGLContext*)glw->context() flushBuffer]; - // Read OpenGL context pixels directly. - // For extra safety, save & restore OpenGL states that are changed - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ - glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - // Read a block of pixels from the frame buffer - int mByteWidth = w * 4; - mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes - uchar *baseAddress = new uchar[mByteWidth * h]; - glReadPixels(x, glw->pixel_h() - (y+h), w, h, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); - glPopClientAttrib(); - baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); - Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); - img->alloc_array = 1; - [(NSOpenGLContext*)glw->context() flushBuffer]; - return img; -} - - -void* Fl_Cocoa_Gl_Window_Driver::GetProcAddress(const char *procName) { - return dlsym(RTLD_DEFAULT, procName); -} - - -FL_EXPORT NSOpenGLContext *fl_mac_glcontext(GLContext rc) { - return (NSOpenGLContext*)rc; -} - - -void Fl_Cocoa_Gl_Window_Driver::switch_to_GL1() { - [gl1ctxt makeCurrentContext]; - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); -} - - -void Fl_Cocoa_Gl_Window_Driver::switch_back() { - glFlush(); - [(NSOpenGLContext*)pWindow->context() makeCurrentContext]; -} - - -class Fl_Gl_Cocoa_Plugin : public Fl_Cocoa_Plugin { -public: - Fl_Gl_Cocoa_Plugin() : Fl_Cocoa_Plugin(name()) { } - const char *name() FL_OVERRIDE { return "gl.cocoa.fltk.org"; } - void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) FL_OVERRIDE { - glw->Fl_Gl_Window::resize(x, y, w, h); - } -}; - -static Fl_Gl_Cocoa_Plugin Gl_Cocoa_Plugin; - -#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm b/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm deleted file mode 100644 index 9c75c7ff2..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Pen_Events.mm +++ /dev/null @@ -1,439 +0,0 @@ -// -// Definition of macOS Cocoa Pen/Tablet event driver. -// -// Copyright 2025-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "src/drivers/Base/Fl_Base_Pen_Events.H" - -#include <FL/platform.H> -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include "../../Fl_Screen_Driver.H" - -#import <Cocoa/Cocoa.h> - - -extern Fl_Window *fl_xmousewin; - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 - -typedef short NSEventSubtype; -#define NSPointingDeviceTypePen NSPenPointingDevice -#define NSEventTypeMouseEntered NSMouseEntered -#define NSEventTypeMouseExited NSMouseExited -#define NSEventTypeTabletProximity NSTabletProximity -#define NSEventTypeTabletPoint NSTabletPoint -#define NSEventSubtypeTabletProximity NSTabletProximityEventSubtype -#define NSEventSubtypeTabletPoint NSTabletPointEventSubtype -#define NSEventSubtypeMouseEvent NSMouseEventSubtype -#define NSEventTypeLeftMouseDown NSLeftMouseDown -#define NSEventTypeLeftMouseUp NSLeftMouseUp -#define NSEventTypeLeftMouseDragged NSLeftMouseDragged -#define NSEventTypeMouseMoved NSMouseMoved -#define NSEventTypeRightMouseDown NSRightMouseDown -#define NSEventTypeRightMouseUp NSRightMouseUp -#define NSEventTypeRightMouseDragged NSRightMouseDragged -#define NSEventTypeOtherMouseUp NSOtherMouseUp -#define NSEventTypeOtherMouseDown NSOtherMouseDown -#define NSEventTypeOtherMouseDragged NSOtherMouseDragged -#define NSPointingDeviceTypeEraser NSEraserPointingDevice - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 - -static NSPointingDeviceType device_type_ { NSPointingDeviceTypePen }; - -// The trait list keeps track of traits for every pen ID that appears while -// handling events. -// AppKit does not tell us what traits are available per pen or tablet, so -// we use the first 5 motion events to discover event values that are not -// the default value, and enter that knowledge into the traits database. -typedef std::map<int, Fl::Pen::Trait> TraitList; -static TraitList trait_list_; -static int trait_countdown_ { 5 }; -static int current_pen_id_ { -1 }; -static Fl::Pen::Trait current_pen_trait_ { Fl::Pen::Trait::DRIVER_AVAILABLE }; -static Fl::Pen::Trait driver_traits_ { - Fl::Pen::Trait::DRIVER_AVAILABLE | Fl::Pen::Trait::PEN_ID | - Fl::Pen::Trait::ERASER | Fl::Pen::Trait::PRESSURE | - Fl::Pen::Trait::BARREL_PRESSURE | Fl::Pen::Trait::TILT_X | - Fl::Pen::Trait::TILT_Y | Fl::Pen::Trait::TWIST - // Notably missing: PROXIMITY -}; - -// Temporary storage of event data for the driver; -static Fl::Pen::EventData ev; - - -namespace Fl { - -namespace Private { - -// Global mouse position at mouse down event -extern int e_x_down; -extern int e_y_down; - -}; // namespace Private - -namespace Pen { - -class Cocoa_Driver : public Driver { -public: - Cocoa_Driver() = default; - //virtual void subscribe(Fl_Widget* widget) override; - //virtual void unsubscribe(Fl_Widget* widget) override; - //virtual void release() override; - virtual Trait traits() override { return driver_traits_; } - virtual Trait pen_traits(int pen_id) override { - auto it = trait_list_.find(pen_id); - if (pen_id == 0) - return current_pen_trait_; - if (it == trait_list_.end()) { - return Trait::DRIVER_AVAILABLE; - } else { - return it->second; - } - } -}; - -Cocoa_Driver cocoa_driver; -Driver& driver = cocoa_driver; - -} // namespace Pen - -} // namespace Fl - - -using namespace Fl::Pen; - - -/* - Copy the event state. - */ -static void copy_state() { - Fl::Pen::State tr = (Fl::Pen::State)((uint32_t)Fl::Pen::e.state ^ (uint32_t)ev.state); - Fl::Pen::e = ev; - Fl::Pen::e.trigger = tr; - Fl::e_x = (int)ev.x; - Fl::e_y = (int)ev.y; - Fl::e_x_root = (int)ev.rx; - Fl::e_y_root = (int)ev.ry; -} - -/* - Offset coordinates for subwindows and subsubwindows. - */ -static void offset_subwindow_event(Fl_Widget *w, double &x, double &y) { - Fl_Widget *p = w, *q; - while (p) { - q = p->parent(); - if (p->as_window() && q) { - x -= p->x(); - y -= p->y(); - } - p = q; - }; -} - -/* - Check if coordinates are within the widget box. - Coordinates are in top_window space. We iterate up the hierarchy to ensure - that we handle subwindows correctly. - */ -static bool event_inside(Fl_Widget *w, double x, double y) { - offset_subwindow_event(w, x, y); - if (w->as_window()) { - return ((x >= 0) && (y >= 0) && (x < w->w()) && (y < w->h())); - } else { - return ((x >= w->x()) && (y >= w->y()) && (x < w->x() + w->w()) && (y < w->y() + w->h())); - } -} - -/* - Find the widget under the pen event. - Search the subscriber list for widgets that are inside the same top window, - are visible, and are within the give coordinates. Subwindow aware. - */ -static Fl_Widget *find_below_pen(Fl_Window *win, double x, double y) { - for (auto &sub: subscriber_list_) { - Fl_Widget *candidate = sub.second->widget(); - if (candidate && (candidate->top_window() == win)) { - if (candidate->visible() && event_inside(candidate, x, y)) { - return candidate; - } - } - } - return nullptr; -} - -/* - Send the current event and event data to a widget. - Note: we will get the wrong coordinates if the widget is not a child of - the current event window (LEAVE events between windows). - */ -static int pen_send(Fl_Widget *w, int event, State trigger, bool &copied) { - // Copy most event data only once - if (!copied) { - copy_state(); - copied = true; - } - // Copy the top_window coordinates again as they may change when w changes - e.x = ev.x; - e.y = ev.y; - offset_subwindow_event(w, e.x, e.y); - Fl::e_x = e.x; - Fl::e_y = e.y; - // Send the event. - e.trigger = trigger; - return w->handle(event); -} - -/* - Send an event to all subscribers. - */ -static int pen_send_all(int event, State trigger) { - bool copied = false; - // use local value because handler may still change ev values - for (auto &it: subscriber_list_) { - auto w = it.second->widget(); - if (w) - pen_send(w, event, trigger, copied); - } - return 1; -} - -/* - Convert the NSEvent button number to Fl::Pen::State, - */ -static State button_to_trigger(NSInteger button, bool down) { - switch (button) { - case 0: - if ( (ev.state & (State::ERASER_DOWN | State::ERASER_HOVERS)) != State::NONE ) { - return down ? State::ERASER_DOWN : State::ERASER_HOVERS; - } else { - return down ? State::TIP_DOWN : State::TIP_HOVERS; - } - case 1: return State::BUTTON0; - case 2: return State::BUTTON1; - case 3: return State::BUTTON2; - case 4: return State::BUTTON3; - default: return State::NONE; - } -} - -/* - Handle events coming from Cocoa. - `capabilityMask` is useless, because it is vendor defined - If a modal window is open, AppKit will send window specific events only there. - */ -bool fl_cocoa_tablet_handler(NSEvent *event, Fl_Window *eventWindow) { - // Quick access to the main type. - auto type = [event type]; - - // There seems nothing useful here. Ignore for now. - if ((type == NSEventTypeMouseEntered) || (type == NSEventTypeMouseExited)) { - return false; - } - - // Sort out tablet-only events and mouse plus tablet events. - bool is_mouse = ((type != NSEventTypeTabletPoint) && (type != NSEventTypeTabletProximity)); - - // Set the subtype if one is available. Only NSEventSubtypeTabletPoint and - // NSEventSubtypeTabletProximity matter in this context - NSEventSubtype subtype = is_mouse ? [event subtype] : NSEventSubtypeMouseEvent; - - // Is this a change in proximity event? - bool is_proximity = ((type == NSEventTypeTabletProximity) || (subtype == NSEventSubtypeTabletProximity)); - - // Is this a pen pointer event? - bool is_point = ((type == NSEventTypeTabletPoint) || (subtype == NSEventSubtypeTabletPoint)); - - // Check if any of the pen down, move, drag, or up events was triggered. - bool is_down = ((type == NSEventTypeLeftMouseDown) || (type == NSEventTypeRightMouseDown) || (type == NSEventTypeOtherMouseDown)); - bool is_up = ((type == NSEventTypeLeftMouseUp) || (type == NSEventTypeRightMouseUp) || (type == NSEventTypeOtherMouseUp)); - bool is_drag = ((type == NSEventTypeLeftMouseDragged) || (type == NSEventTypeRightMouseDragged) || (type == NSEventTypeOtherMouseDragged)); - bool is_motion = is_drag || (type == NSEventTypeMouseMoved); - - // Find out if we can get the pen position - bool has_position = (eventWindow != nullptr) && (is_up || is_down || is_motion || is_proximity || is_point); - - // Event has extended pen data set: - if (has_position) { - // Get the position data. - auto pt = [event locationInWindow]; - double s = Fl::screen_driver()->scale(0); - ev.x = pt.x/s; - ev.y = eventWindow->h() - pt.y/s; - ev.rx = ev.x + eventWindow->x(); - ev.ry = ev.y + eventWindow->y(); - if (!is_proximity) { - // Get the pressure data. - ev.pressure = [event pressure]; - ev.barrel_pressure = [event tangentialPressure]; - // Get the tilt - auto tilt = [event tilt]; - ev.tilt_x = -tilt.x; - ev.tilt_y = tilt.y; - // Other stuff - ev.twist = [event rotation]; // TODO: untested - // ev.proximity = [event proximity]; // not supported in AppKit - } - if (device_type_ == NSPointingDeviceTypeEraser) { - if ([event buttonMask] & 1) - ev.state = State::ERASER_DOWN; - else - ev.state = State::ERASER_HOVERS; - } else { - if ([event buttonMask] & 1) - ev.state = State::TIP_DOWN; - else - ev.state = State::TIP_HOVERS; - } - if ([event buttonMask] & 0x0002) ev.state |= State::BUTTON0; - if ([event buttonMask] & 0x0004) ev.state |= State::BUTTON1; - if ([event buttonMask] & 0x0008) ev.state |= State::BUTTON2; - if ([event buttonMask] & 0x0010) ev.state |= State::BUTTON3; - // printf("0x%08x\n", [event buttonMask]); - } - if (is_proximity) { - ev.pen_id = (int)[event vendorID]; - device_type_ = [event pointingDeviceType]; - } - if (type == NSEventTypeTabletProximity) { - if ([event isEnteringProximity]) { - // Check if this is the first time we see this pen, or if the pen changed - if (current_pen_id_ != ev.pen_id) { - current_pen_id_ = ev.pen_id; - auto it = trait_list_.find(current_pen_id_); - if (it == trait_list_.end()) { // not found, create a new entry - trait_list_[current_pen_id_] = Trait::DRIVER_AVAILABLE; - trait_countdown_ = 5; - pen_send_all(Fl::Pen::DETECTED, State::NONE); - // printf("IN RANGE, NEW PEN\n"); - } else { - pen_send_all(Fl::Pen::CHANGED, State::NONE); - // printf("IN RANGE, CHANGED PEN\n"); - } - trait_list_[0] = trait_list_[current_pen_id_]; // set current pen traits - } else { - pen_send_all(Fl::Pen::IN_RANGE, State::NONE); - // printf("IN RANGE\n"); - } - } else { - pen_send_all(Fl::Pen::OUT_OF_RANGE, State::NONE); - // printf("OUT OF RANGE\n"); - } - } - - Fl_Widget *receiver = nullptr; - bool pushed = false; - bool event_data_copied = false; - - if (has_position) { - if (trait_countdown_) { - trait_countdown_--; - if (ev.tilt_x != 0.0) current_pen_trait_ |= Trait::TILT_X; - if (ev.tilt_y != 0.0) current_pen_trait_ |= Trait::TILT_Y; - if (ev.pressure != 1.0) current_pen_trait_ |= Trait::PRESSURE; - if (ev.barrel_pressure != 0.0) current_pen_trait_ |= Trait::BARREL_PRESSURE; - if (ev.pen_id != 0) current_pen_trait_ |= Trait::PEN_ID; - if (ev.twist != 0.0) current_pen_trait_ |= Trait::TWIST; - //if (ev.proximity != 0) current_pen_trait_ |= Trait::PROXIMITY; - trait_list_[current_pen_id_] = current_pen_trait_; - } - fl_xmousewin = eventWindow; - if (pushed_ && pushed_->widget() && (Fl::pushed() == pushed_->widget())) { - receiver = pushed_->widget(); - if (Fl::grab() && (Fl::grab() != receiver->top_window())) - return 0; - if (Fl::modal() && (Fl::modal() != receiver->top_window())) - return 0; - pushed = true; - } else { - if (Fl::grab() && (Fl::grab() != eventWindow)) - return 0; - if (Fl::modal() && (Fl::modal() != eventWindow)) - return 0; - auto bpen = below_pen_ ? below_pen_->widget() : nullptr; - auto bmouse = Fl::belowmouse(); - auto bpen_old = bmouse && (bmouse == bpen) ? bpen : nullptr; - auto bpen_now = find_below_pen(eventWindow, ev.x, ev.y); - - if (bpen_now != bpen_old) { - if (bpen_old) { - pen_send(bpen_old, Fl::Pen::LEAVE, State::NONE, event_data_copied); - } - below_pen_ = nullptr; - if (bpen_now) { - State state = (device_type_ == NSPointingDeviceTypeEraser) ? State::ERASER_HOVERS : State::TIP_HOVERS; - if (pen_send(bpen_now, Fl::Pen::ENTER, state, event_data_copied)) { - below_pen_ = subscriber_list_[bpen_now]; - Fl::belowmouse(bpen_now); - } - } - } - - receiver = below_pen_ ? below_pen_->widget() : nullptr; - if (!receiver) - return 0; - } - } else { - // Proximity events were handled earlier. - } - - if (!receiver) - return 0; - - if (is_down) { - if (!pushed) { - pushed_ = subscriber_list_[receiver]; - Fl::pushed(receiver); - } - State trigger = button_to_trigger([event buttonNumber], true); - if ([event buttonNumber] == 0) { - Fl::e_is_click = 1; - Fl::Private::e_x_down = (int)ev.x; - Fl::Private::e_y_down = (int)ev.y; - if ([event clickCount] > 1) - Fl::e_clicks++; - else - Fl::e_clicks = 0; - pen_send(receiver, Fl::Pen::TOUCH, trigger, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::BUTTON_PUSH, trigger, event_data_copied); - } - } else if (is_up) { - if ( (ev.state & State::ANY_DOWN) == State::NONE ) { - Fl::pushed(nullptr); - pushed_ = nullptr; - } - State trigger = button_to_trigger([event buttonNumber], true); - if ([event buttonNumber] == 0) - pen_send(receiver, Fl::Pen::LIFT, trigger, event_data_copied); - else - pen_send(receiver, Fl::Pen::BUTTON_RELEASE, trigger, event_data_copied); - } else if (is_motion) { - if ( Fl::e_is_click && - ( (fabs((int)ev.x - Fl::Private::e_x_down) > 5) || - (fabs((int)ev.y - Fl::Private::e_y_down) > 5) ) ) - Fl::e_is_click = 0; - if (pushed) { - pen_send(receiver, Fl::Pen::DRAW, State::NONE, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::HOVER, State::NONE, event_data_copied); - } - } - // Always return 1 because at this point, we capture pen events and don't - // want mouse events anymore! - return 1; -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm b/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm deleted file mode 100644 index a40f1feb4..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm +++ /dev/null @@ -1,455 +0,0 @@ -// -// Mac OS X-specific printing support (objective-c++) for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/Fl_Paged_Device.H> -#include <FL/Fl_Printer.H> -#include "../../Fl_Window_Driver.H" -#include "../../Fl_Screen_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include <FL/Fl_PDF_File_Surface.H> -#include "Fl_Cocoa_Window_Driver.H" - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_ask.H> -#include <FL/fl_draw.H> -#include <FL/fl_string_functions.h> -#import <Cocoa/Cocoa.h> - -typedef OSStatus (*PMSessionSetDocumentFormatGeneration_type)( - PMPrintSession printSession, - CFStringRef docFormat, - CFArrayRef graphicsContextTypes, - CFTypeRef options); -typedef OSStatus (*PMSessionBeginDocumentNoDialog_type)( - PMPrintSession printSession, - PMPrintSettings printSettings, - PMPageFormat pageFormat); -typedef OSStatus -(*PMSessionGetGraphicsContext_type)( - PMPrintSession printSession, - CFStringRef graphicsContextType, - void ** graphicsContext); - - -/** Support for printing on the Apple OS X platform */ -class Fl_Cocoa_Printer_Driver : public Fl_Paged_Device { - friend class Fl_Printer; -protected: - float scale_x; - float scale_y; - float angle; // rotation angle in radians - PMPrintSession printSession; - PMPageFormat pageFormat; - PMPrintSettings printSettings; - Fl_Cocoa_Printer_Driver(void); - int begin_job(int pagecount = 0, int *frompage = NULL, int *topage = NULL, char **perr_message = NULL) FL_OVERRIDE; - int begin_page (void) FL_OVERRIDE; - int printable_rect(int *w, int *h) FL_OVERRIDE; - void margins(int *left, int *top, int *right, int *bottom) FL_OVERRIDE; - void origin(int *x, int *y) FL_OVERRIDE; - void origin(int x, int y) FL_OVERRIDE; - void scale (float scale_x, float scale_y = 0.) FL_OVERRIDE; - void rotate(float angle) FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate(void) FL_OVERRIDE; - int end_page (void) FL_OVERRIDE; - void end_job (void) FL_OVERRIDE; - ~Fl_Cocoa_Printer_Driver(void); -}; - - -Fl_Cocoa_Printer_Driver::Fl_Cocoa_Printer_Driver(void) -{ - x_offset = 0; - y_offset = 0; - scale_x = scale_y = 1.; - driver(new Fl_Quartz_Printer_Graphics_Driver); -} - -Fl_Paged_Device* Fl_Printer::newPrinterDriver(void) -{ - return new Fl_Cocoa_Printer_Driver(); -} - -Fl_Cocoa_Printer_Driver::~Fl_Cocoa_Printer_Driver(void) { - delete driver(); -} - -@interface print_panel_delegate : NSObject -- (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(NSInteger)returnCode contextInfo:(NSInteger *)contextInfo; -@end -@implementation print_panel_delegate -- (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(NSInteger)returnCode contextInfo:(NSInteger *)contextInfo -{ - *contextInfo = returnCode; -} -@end - -int Fl_Cocoa_Printer_Driver::begin_job (int pagecount, int *frompage, int *topage, char **perr_message) -//printing using a Quartz graphics context -//returns 0 iff OK -{ - OSStatus status = 0; - fl_open_display(); - Fl_Cocoa_Window_Driver::q_release_context(); - NSPrintInfo *info = [NSPrintInfo sharedPrintInfo]; - NSPrintPanel *panel = [NSPrintPanel printPanel]; - //from 10.5 - [panel setOptions:NSPrintPanelShowsCopies | NSPrintPanelShowsPageRange | - NSPrintPanelShowsPageSetupAccessory | NSPrintPanelShowsOrientation | NSPrintPanelShowsPaperSize]; - NSInteger retval = -1; - Fl_Window *top = Fl::first_window(); - NSWindow *main = (top ? (NSWindow*)fl_xid(top->top_window()) : nil); - if (main) { - [panel beginSheetWithPrintInfo:info - modalForWindow:main - delegate:[[[print_panel_delegate alloc] init] autorelease] - didEndSelector:@selector(printPanelDidEnd:returnCode:contextInfo:) - contextInfo:&retval]; - while (retval < 0) Fl::wait(100); - [main makeKeyAndOrderFront:nil]; - } else { - retval = [panel runModalWithPrintInfo:info]; //from 10.5 - } -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 - const NSInteger NSModalResponseOK = NSOKButton; -#endif - if (retval != NSModalResponseOK) return 1; - printSession = (PMPrintSession)[info PMPrintSession]; //from 10.5 - pageFormat = (PMPageFormat)[info PMPageFormat]; //from 10.5 - printSettings = (PMPrintSettings)[info PMPrintSettings];//from 10.5 - UInt32 from32, to32; - PMGetFirstPage(printSettings, &from32); - if (frompage) *frompage = (int)from32; - PMGetLastPage(printSettings, &to32); - if (topage) { - *topage = (int)to32; - if (*topage > pagecount && pagecount > 0) *topage = pagecount; - } - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 - - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - return 2; - } - y_offset = x_offset = 0; - return 0; -} - -void Fl_Cocoa_Printer_Driver::margins(int *left, int *top, int *right, int *bottom) -{ - PMPaper paper; - PMGetPageFormatPaper(pageFormat, &paper); - PMOrientation orientation; - PMGetOrientation(pageFormat, &orientation); - PMPaperMargins margins; - PMPaperGetMargins(paper, &margins); - if(orientation == kPMPortrait) { - if (left) *left = (int)(margins.left / scale_x + 0.5); - if (top) *top = (int)(margins.top / scale_y + 0.5); - if (right) *right = (int)(margins.right / scale_x + 0.5); - if (bottom) *bottom = (int)(margins.bottom / scale_y + 0.5); - } else { - if (left) *left = (int)(margins.top / scale_x + 0.5); - if (top) *top = (int)(margins.left / scale_y + 0.5); - if (right) *right = (int)(margins.bottom / scale_x + 0.5); - if (bottom) *bottom = (int)(margins.right / scale_y + 0.5); - } -} - -int Fl_Cocoa_Printer_Driver::printable_rect(int *w, int *h) -//returns 0 iff OK -{ - OSStatus status; - PMRect pmRect; - int x, y; - - status = PMGetAdjustedPageRect(pageFormat, &pmRect); - if (status != noErr) return 1; - - x = (int)pmRect.left; - y = (int)pmRect.top; - *w = int((int)(pmRect.right - x) / scale_x + 1); - *h = int((int)(pmRect.bottom - y) / scale_y + 1); - return 0; -} - -void Fl_Cocoa_Printer_Driver::origin(int x, int y) -{ - x_offset = x; - y_offset = y; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextTranslateCTM(gc, x, y); - CGContextRotateCTM(gc, angle); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::scale (float s_x, float s_y) -{ - if (s_y == 0.) s_y = s_x; - scale_x = s_x; - scale_y = s_y; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextRotateCTM(gc, angle); - x_offset = y_offset = 0; - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::rotate (float rot_angle) -{ - angle = - rot_angle * M_PI / 180.; - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextScaleCTM(gc, scale_x, scale_y); - CGContextTranslateCTM(gc, x_offset, y_offset); - CGContextRotateCTM(gc, angle); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::translate(int x, int y) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, x, y ); - CGContextSaveGState(gc); -} - -void Fl_Cocoa_Printer_Driver::untranslate(void) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); -} - -int Fl_Cocoa_Printer_Driver::begin_page (void) -{ - OSStatus status = PMSessionBeginPageNoDialog(printSession, pageFormat, NULL); - CGContextRef gc; - status = PMSessionGetCGGraphicsContext(printSession, &gc); // 10.4 - driver()->gc(gc); - Fl_Surface_Device::push_current(this); - PMRect pmRect; - float win_scale_x, win_scale_y; - - PMPaper paper; - PMGetPageFormatPaper(pageFormat, &paper); - PMPaperMargins margins; - PMPaperGetMargins(paper, &margins); - PMOrientation orientation; - PMGetOrientation(pageFormat, &orientation); - - status = PMGetAdjustedPageRect(pageFormat, &pmRect); - double h = pmRect.bottom - pmRect.top; - x_offset = 0; - y_offset = 0; - angle = 0; - scale_x = scale_y = 1; - win_scale_x = win_scale_y = 1; - if(orientation == kPMPortrait) - CGContextTranslateCTM(gc, margins.left, margins.bottom + h); - else - CGContextTranslateCTM(gc, margins.top, margins.right + h); - CGContextScaleCTM(gc, win_scale_x, - win_scale_y); - ((Fl_Quartz_Graphics_Driver*)driver())->quartz_restore_line_style(); - CGContextSetShouldAntialias(gc, false); - CGContextSaveGState(gc); - CGContextSaveGState(gc); - fl_line_style(FL_SOLID); - fl_window = (FLWindow*)1; // TODO: something better - fl_clip_region(0); - return status != noErr; -} - -int Fl_Cocoa_Printer_Driver::end_page (void) -{ - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextFlush(gc); - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - OSStatus status = PMSessionEndPageNoDialog(printSession); - gc = NULL; - Fl_Surface_Device::pop_current(); - return status != noErr; -} - -void Fl_Cocoa_Printer_Driver::end_job (void) -{ - OSStatus status; - - status = PMSessionError(printSession); - if (status != noErr) { - fl_alert ("PM Session error %d", (int)status); - } - PMSessionEndDocumentNoDialog(printSession); - Fl_Window *w = Fl::first_window(); - if (w) w->show(); -} - -void Fl_Cocoa_Printer_Driver::origin(int *x, int *y) -{ - Fl_Paged_Device::origin(x, y); -} - - -class Fl_PDF_Cocoa_File_Surface : public Fl_Cocoa_Printer_Driver -{ -public: - char *doc_fname; - Fl_PDF_Cocoa_File_Surface(); - ~Fl_PDF_Cocoa_File_Surface() { if (doc_fname) free(doc_fname); } - int begin_job(const char *defaultname, - char **perr_message = NULL); - int begin_job(int, int*, int *, char **) FL_OVERRIDE {return 1;} // don't use - int begin_document(const char* outname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message); -}; - - -Fl_PDF_Cocoa_File_Surface::Fl_PDF_Cocoa_File_Surface() { - driver(new Fl_Quartz_Graphics_Driver()); - doc_fname = NULL; -} - - -int Fl_PDF_Cocoa_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - OSStatus status = 0; - if (fl_mac_os_version < 100900) return 1; - Fl_Window *top = Fl::first_window(); - NSWindow *main = (top ? (NSWindow*)fl_xid(top->top_window()) : nil); - if (!main) return 1; - Fl_Cocoa_Window_Driver::q_release_context(); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 && defined(__BLOCKS__) - NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9 - NSPDFPanel *pdf_panel = [NSPDFPanel panel]; // 10.9 - char buf[FL_PATH_MAX]; - strcpy(buf, defaultfilename); - fl_filename_setext(buf, sizeof(buf), NULL); - [pdf_panel setDefaultFileName:[NSString stringWithUTF8String:buf]]; - [pdf_panel setOptions: NSPrintPanelShowsOrientation | NSPrintPanelShowsPaperSize]; - NSInteger retval = -1; - __block NSInteger complete = -1; - [pdf_panel beginSheetWithPDFInfo:pdf_info - modalForWindow:main - completionHandler:^(NSInteger returnCode) { - // this block runs after OK or Cancel was triggered in file dialog - complete = returnCode; - } - ]; - while (complete == -1) Fl::wait(100); // loop until end of file dialog - retval = complete; - [main makeKeyAndOrderFront:nil]; - if (retval != NSModalResponseOK) return 1; - NSURL *url = [pdf_info URL]; - doc_fname = fl_strdup([url fileSystemRepresentation]); - NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo]; - [pr_info takeSettingsFromPDFInfo:pdf_info]; - [pdf_info release]; - printSession = (PMPrintSession)[pr_info PMPrintSession]; - printSettings = (PMPrintSettings)[pr_info PMPrintSettings]; - pageFormat = (PMPageFormat)[pr_info PMPageFormat]; - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 -#endif - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - free(doc_fname); - doc_fname = NULL; - return 2; - } - y_offset = x_offset = 0; - return 0; -} - - -int Fl_PDF_Cocoa_File_Surface::begin_document(const char* outfname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - OSStatus status = 0; - fl_open_display(); - if (fl_mac_os_version < 100900) return 1; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 - NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9 - doc_fname = fl_strdup(outfname); - NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:doc_fname]]; - [pdf_info setURL:url]; - NSSize psize = {(CGFloat)Fl_Paged_Device::page_formats[format].width, (CGFloat)Fl_Paged_Device::page_formats[format].height}; - [pdf_info setPaperSize:psize]; - [pdf_info setOrientation:(layout == PORTRAIT ? NSPaperOrientationPortrait : NSPaperOrientationLandscape)]; - NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo]; - [pr_info takeSettingsFromPDFInfo:pdf_info]; - [pdf_info release]; - printSession = (PMPrintSession)[pr_info PMPrintSession]; - printSettings = (PMPrintSettings)[pr_info PMPrintSettings]; - pageFormat = (PMPageFormat)[pr_info PMPageFormat]; - status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4 -#endif - if (status != noErr) { - if (perr_message) { - NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil]; - NSString *s = [nserr localizedDescription]; - if (s) *perr_message = fl_strdup([s UTF8String]); - } - free(doc_fname); - doc_fname = NULL; - return 2; - } - y_offset = x_offset = 0; - return 0; -} - - -Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { - Fl_PDF_Cocoa_File_Surface *surf = new Fl_PDF_Cocoa_File_Surface(); - *pfname = (const char**)&surf->doc_fname; - return surf; -} - - -int Fl_PDF_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - return ((Fl_PDF_Cocoa_File_Surface*)platform_surface_)->begin_job(defaultfilename, perr_message); -} - - -int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - return ((Fl_PDF_Cocoa_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message); -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H deleted file mode 100644 index 9e3d2386a..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ /dev/null @@ -1,114 +0,0 @@ -// -// Definition of Apple Cocoa Screen interface -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Cocoa_Screen_Driver.H - \brief Definition of Apple Cocoa Screen interface. - */ - -#ifndef FL_COCOA_SCREEN_DRIVER_H -#define FL_COCOA_SCREEN_DRIVER_H - -#include "../../Fl_Screen_Driver.H" - -/* - Move everything here that manages the native screen interface. - - There is exactly one screen driver in the system. - - - screen configuration and sizes - - multiple screens - - native dialog boxes -*/ - - -class Fl_Window; -class Fl_Input; -class Fl_RGB_Image; -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif - -class Fl_Cocoa_Screen_Driver : public Fl_Screen_Driver -{ -protected: - struct XRectangle {int x, y, width, height;}; - XRectangle screens[MAX_SCREENS]; - float dpi_h[MAX_SCREENS]; - float dpi_v[MAX_SCREENS]; - static int insertion_point_x; - static int insertion_point_y; - static int insertion_point_height; - static bool insertion_point_location_is_valid; -public: - NSImage *default_icon; - Fl_Cocoa_Screen_Driver(); - static int next_marked_length; // next length of marked text after current marked text will have been replaced - static void breakMacEventLoop(); - // --- display management - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - // implemented in Fl_cocoa.mm because uses Objective-c - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - int has_marked_text() const FL_OVERRIDE; - static void reset_marked_text(); - static void insertion_point_location(int x, int y, int height); - static int insertion_point_location(int *px, int *py, int *pheight); - int dnd(int use_selection) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - int input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input) FL_OVERRIDE; - int get_mouse(int &x, int &y) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - // --- compute dimensions of an Fl_Offscreen - void offscreen_size(Fl_Offscreen o, int &width, int &height) FL_OVERRIDE; - - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { return SYSTEMWIDE_APP_SCALING; } - float scale(int /*nscreen*/) FL_OVERRIDE {return scale_;} - void scale(int /*nscreen*/, float f) FL_OVERRIDE { scale_ = f;} - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - void default_icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - int clipboard_contains(const char *type) FL_OVERRIDE; - void set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) FL_OVERRIDE; - void reset_spot() FL_OVERRIDE; - int need_menu_handle_part2() FL_OVERRIDE {return 1;} - // these 2 are in Fl_get_key_mac.cxx - int event_key(int) FL_OVERRIDE; - int get_key(int) FL_OVERRIDE; -private: - float scale_; -}; - - -#endif // FL_COCOA_SCREEN_DRIVER_H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx deleted file mode 100644 index 7eb98b291..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ /dev/null @@ -1,434 +0,0 @@ -// -// Definition of Apple Cocoa Screen interface. -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_Cocoa_Screen_Driver.H" -#include "Fl_Cocoa_Window_Driver.H" -#include "../Quartz/Fl_Font.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> -#include <FL/Fl_Input.H> -#include <FL/fl_ask.H> -#include <FL/Fl_Image_Surface.H> -#include <stdio.h> - - -extern "C" void NSBeep(void); -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); - -int Fl_Cocoa_Screen_Driver::next_marked_length = 0; - - -// This key table is used for the Darwin system driver. It is defined here -// "static" and assigned in the constructor to avoid static initialization -// race conditions. It is used in fl_shortcut.cxx. -// -// This table must be in numeric order by fltk (X) keysym number: - -Fl_Screen_Driver::Keyname darwin_key_table[] = { - // v - this column may contain UTF-8 characters - {' ', "Space"}, - {FL_BackSpace, "⌫"/*"\xe2\x8c\xab"*/}, // U+232B : erase to the left - {FL_Tab, "⇥"/*"\xe2\x87\xa5"*/}, // U+21E5 rightwards arrow to bar - {FL_Enter, "↩"/*"\xe2\x86\xa9"*/}, // U+21A9 leftwards arrow with hook - {FL_Pause, "Pause"}, - {FL_Scroll_Lock, "Scroll_Lock"}, - {FL_Escape, "⎋"/*"\xe2\x8e\x8b"*/}, // U+238B : broken circle with northwest arrow - {FL_Home, "↖"/*"\xe2\x86\x96"*/}, // U+2196 north west arrow - {FL_Left, "←"/*"\xe2\x86\x90"*/}, // U+2190 leftwards arrow - {FL_Up, "↑"/*"\xe2\x86\x91"*/}, // U+2191 upwards arrow - {FL_Right, "→"/*"\xe2\x86\x92"*/}, // U+2192 rightwards arrow - {FL_Down, "↓"/*"\xe2\x86\x93"*/}, // U+2193 downwards arrow - {FL_Page_Up, "⇞"/*"\xe2\x87\x9e"*/}, // U+21DE upwards arrow with double stroke - {FL_Page_Down, "⇟"/*"\xe2\x87\x9f"*/}, // U+21DF downwards arrow with double stroke - {FL_End, "↘"/*"\xe2\x86\x98"*/}, // U+2198 south east arrow - {FL_Print, "Print"}, - {FL_Insert, "Insert"}, - {FL_Menu, "Menu"}, - {FL_Num_Lock, "Num_Lock"}, - {FL_KP_Enter, "⌤"/*"\xe2\x8c\xa4"*/}, // U+2324 up arrow head between two horizontal bars - {FL_Shift_L, "Shift_L"}, - {FL_Shift_R, "Shift_R"}, - {FL_Control_L, "Control_L"}, - {FL_Control_R, "Control_R"}, - {FL_Caps_Lock, "⇪"/*"\xe2\x87\xaa"*/}, // U+21EA upwards white arrow from bar - {FL_Meta_L, "Meta_L"}, - {FL_Meta_R, "Meta_R"}, - {FL_Alt_L, "Alt_L"}, - {FL_Alt_R, "Alt_R"}, - {FL_Delete, "⌦"/*"\xe2\x8c\xa6"*/} // U+2326 : erase to the right -}; - - -static Fl_Text_Editor::Key_Binding extra_bindings[] = { - // Define CMD+key accelerators... - { 'z', FL_COMMAND, Fl_Text_Editor::kf_undo ,0}, - { 'z', FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_redo ,0}, - { 'x', FL_COMMAND, Fl_Text_Editor::kf_cut ,0}, - { 'c', FL_COMMAND, Fl_Text_Editor::kf_copy ,0}, - { 'v', FL_COMMAND, Fl_Text_Editor::kf_paste ,0}, - { 'a', FL_COMMAND, Fl_Text_Editor::kf_select_all ,0}, - { FL_Left, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Right, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Up, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Down, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0}, - { FL_Left, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Right, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Up, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { FL_Down, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0}, - { 0, 0, 0 ,0} -}; - - -Fl_Cocoa_Screen_Driver::Fl_Cocoa_Screen_Driver() { - text_editor_extra_key_bindings = extra_bindings; - scale_ = 1.; - default_icon = nil; - // initialize key table - key_table = darwin_key_table; - key_table_size = sizeof(darwin_key_table)/sizeof(*darwin_key_table); -} - - -void Fl_Cocoa_Screen_Driver::init() -{ - open_display(); - CGDirectDisplayID displays[MAX_SCREENS]; - CGDisplayCount count, i; - CGRect r; - CGGetActiveDisplayList(MAX_SCREENS, displays, &count); - for( i = 0; i < count; i++) { - r = CGDisplayBounds(displays[i]); - screens[i].x = int(r.origin.x); - screens[i].y = int(r.origin.y); - screens[i].width = int(r.size.width); - screens[i].height = int(r.size.height); - //fprintf(stderr,"screen %d %dx%dx%dx%d\n",i,screens[i].x,screens[i].y,screens[i].width,screens[i].height); - if (&CGDisplayScreenSize != NULL) { - CGSize s = CGDisplayScreenSize(displays[i]); // from 10.3 - dpi_h[i] = screens[i].width / (s.width/25.4); - dpi_v[i] = screens[i].height / (s.height/25.4); - } else { - dpi_h[i] = dpi_v[i] = 75.; - } - } - num_screens = count; -} - - -void Fl_Cocoa_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - float s = scale(0); - X = screens[n].x/s; - Y = screens[n].y/s; - W = screens[n].width/s; - H = screens[n].height/s; -} - - -void Fl_Cocoa_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - - if (n >= 0 && n < num_screens) { - h = dpi_h[n]; - v = dpi_v[n]; - } -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_Cocoa_Screen_Driver::beep(int type) { - switch (type) { - case FL_BEEP_DEFAULT : - case FL_BEEP_ERROR : - NSBeep(); - break; - default : - break; - } -} - - -extern void fl_fix_focus(); // in Fl.cxx - -extern void *fl_capture; - - -void Fl_Cocoa_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab_) { - fl_capture = (FLWindow*)(Fl_X::flx(Fl::first_window())->xid); - Fl_Cocoa_Window_Driver::driver(Fl::first_window())->set_key_window(); - } - Fl::grab_ = win; - } else { - if (Fl::grab_) { - fl_capture = 0; - Fl::grab_ = 0; - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -// MacOS X currently supports two color schemes - Blue and Graphite. -// Since we aren't emulating the Aqua interface (even if Apple would -// let us), we use some defaults that are similar to both. The -// Fl::scheme("plastic") color/box scheme provides a usable Aqua-like -// look-n-feel... -void Fl_Cocoa_Screen_Driver::get_system_colors() -{ - open_display(); - - Fl_Screen_Driver::get_system_colors(); - - if (!bg2_set) Fl::background2(0xff, 0xff, 0xff); - if (!fg_set) Fl::foreground(0, 0, 0); - if (!bg_set) Fl::background(0xd8, 0xd8, 0xd8); - -#if 0 - // this would be the correct code, but it does not run on all versions - // of OS X. Also, setting a bright selection color would require - // some updates in Fl_Adjuster and Fl_Help_Browser - OSStatus err; - RGBColor c; - err = GetThemeBrushAsColor(kThemeBrushPrimaryHighlightColor, 24, true, &c); - if (err) - set_selection_color(0x00, 0x00, 0x80); - else - set_selection_color(c.red, c.green, c.blue); -#else - set_selection_color(0x00, 0x00, 0x80); -#endif -} - - -int Fl_Cocoa_Screen_Driver::has_marked_text() const { - return 1; -} - - -int Fl_Cocoa_Screen_Driver::insertion_point_x = 0; -int Fl_Cocoa_Screen_Driver::insertion_point_y = 0; -int Fl_Cocoa_Screen_Driver::insertion_point_height = 0; -bool Fl_Cocoa_Screen_Driver::insertion_point_location_is_valid = false; - -void Fl_Cocoa_Screen_Driver::reset_marked_text() { - Fl::compose_state = 0; - next_marked_length = 0; - insertion_point_location_is_valid = false; -} - -// computes window coordinates & height of insertion point -int Fl_Cocoa_Screen_Driver::insertion_point_location(int *px, int *py, int *pheight) -// return true if the current coordinates of the insertion point are available -{ - if ( ! insertion_point_location_is_valid ) return false; - *px = insertion_point_x; - *py = insertion_point_y; - *pheight = insertion_point_height; - return true; -} - -void Fl_Cocoa_Screen_Driver::insertion_point_location(int x, int y, int height) { - insertion_point_location_is_valid = true; - insertion_point_x = x; - insertion_point_y = y; - insertion_point_height = height; -} - -int Fl_Cocoa_Screen_Driver::compose(int &del) { - int condition; - int has_text_key = Fl::compose_state || Fl::e_keysym <= '~' || Fl::e_keysym == FL_Iso_Key || - Fl::e_keysym == FL_JIS_Underscore || Fl::e_keysym == FL_Yen || - (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last && Fl::e_keysym != FL_KP_Enter); - condition = Fl::e_state&(FL_META | FL_CTRL) || - (Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || // called from flagsChanged - !has_text_key ; - if (condition) { del = 0; return 0;} // this stuff is to be treated as a function key - del = Fl::compose_state; - Fl::compose_state = next_marked_length; - return 1; -} - - -int Fl_Cocoa_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input) -{ - switch (key) { - case FL_Delete: { - if (mods==0) return input->kf_delete_char_right(); // Delete (OSX-HIG,TE,SA,WOX) - if (mods==FL_CTRL) return input->kf_delete_char_right(); // Ctrl-Delete (??? TE,!SA,!WOX) - if (mods==FL_ALT) return input->kf_delete_word_right(); // Alt-Delete (OSX-HIG,TE,SA) - return 0; // ignore other combos, pass to parent - } - - case FL_Left: - if (mods==0) return input->kf_move_char_left(); // Left (OSX-HIG) - if (mods==FL_ALT) return input->kf_move_word_left(); // Alt-Left (OSX-HIG) - if (mods==FL_META) return input->kf_move_sol(); // Meta-Left (OSX-HIG) - if (mods==FL_CTRL) return input->kf_move_sol(); // Ctrl-Left (TE/SA) - return 0; // ignore other combos, pass to parent - - case FL_Right: - if (mods==0) return input->kf_move_char_right(); // Right (OSX-HIG) - if (mods==FL_ALT) return input->kf_move_word_right(); // Alt-Right (OSX-HIG) - if (mods==FL_META) return input->kf_move_eol(); // Meta-Right (OSX-HIG) - if (mods==FL_CTRL) return input->kf_move_eol(); // Ctrl-Right (TE/SA) - return 0; // ignore other combos, pass to parent - - case FL_Up: - if (mods==0) return input->kf_lines_up(1); // Up (OSX-HIG) - if (mods==FL_CTRL) return input->kf_page_up(); // Ctrl-Up (TE !HIG) - if (mods==FL_ALT) return input->kf_move_up_and_sol(); // Alt-Up (OSX-HIG) - if (mods==FL_META) return input->kf_top(); // Meta-Up (OSX-HIG) - return 0; // ignore other combos, pass to parent - - case FL_Down: - if (mods==0) return input->kf_lines_down(1); // Dn (OSX-HIG) - if (mods==FL_CTRL) return input->kf_page_down(); // Ctrl-Dn (TE !HIG) - if (mods==FL_ALT) return input->kf_move_down_and_eol(); // Alt-Dn (OSX-HIG) - if (mods==FL_META) return input->kf_bottom(); // Meta-Dn (OSX-HIG) - return 0; // ignore other combos, pass to parent - - case FL_Page_Up: - // Fl_Input has no scroll control, so instead we move the cursor by one page - // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. - if (mods==0) return input->kf_page_up(); // PgUp (OSX-HIG) - if (mods==FL_ALT) return input->kf_page_up(); // Alt-PageUp (OSX-HIG) - if (mods==FL_META) return input->kf_top(); // Meta-PageUp (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - - case FL_Page_Down: - // Fl_Input has no scroll control, so instead we move the cursor by one page - // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. - if (mods==0) return input->kf_page_down(); // PgDn (OSX-HIG) - if (mods==FL_ALT) return input->kf_page_down(); // Alt-PageDn (OSX-HIG) - if (mods==FL_META) return input->kf_bottom(); // Meta-PageDn (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - - case FL_Home: - if (mods==0) return input->kf_top(); // Home (OSX-HIG) - if (mods==FL_ALT) return input->kf_top(); // Alt-Home (???) - return 0; // ignore other combos, pass to parent - - case FL_End: - if (mods==0) return input->kf_bottom(); // End (OSX-HIG) - if (mods==FL_ALT) return input->kf_bottom(); // Alt-End (???) - return 0; // ignore other combos, pass to parent - - case FL_BackSpace: - if (mods==0) return input->kf_delete_char_left(); // Backspace (OSX-HIG) - if (mods==FL_CTRL) return input->kf_delete_char_left(); // Ctrl-Backspace (TE/SA) - if (mods==FL_ALT) return input->kf_delete_word_left(); // Alt-Backspace (OSX-HIG) - if (mods==FL_META) return input->kf_delete_sol(); // Meta-Backspace (OSX-HIG,!TE) - return 0; // ignore other combos, pass to parent - } - return -1; -} - -void Fl_Cocoa_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) -{ - width = (int)CGBitmapContextGetWidth((CGContextRef)off); - height = (int)CGBitmapContextGetHeight((CGContextRef)off); -} - -Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window, - bool may_capture_subwins, bool *did_capture_subwins) -{ - int bpp, bpr; - uchar *base, *p; - if (!window) { // read from offscreen buffer - float s = 1; - CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context - base = (uchar *)CGBitmapContextGetData(src); // get data - if(!base) return NULL; - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - if( (sw - X < w) || (sh - Y < h) ) return NULL; - bpr = (int)CGBitmapContextGetBytesPerRow(src); - bpp = (int)CGBitmapContextGetBitsPerPixel(src)/8; - Fl_Image_Surface *imgs = (Fl_Image_Surface*)Fl_Surface_Device::surface(); - int fltk_w, fltk_h; - imgs->printable_rect(&fltk_w, &fltk_h); - s = sw / float(fltk_w); - X *= s; Y *= s; w *= s; h *= s; - if (X + w > sw) w = sw - X; - if (Y + h > sh) h = sh - Y; - // Copy the image from the off-screen buffer to the memory buffer. - int idx, idy; // Current X & Y in image - uchar *pdst, *psrc; - p = new uchar[w * h * 4]; - for (idy = Y, pdst = p; idy < h + Y; idy ++) { - for (idx = 0, psrc = base + idy * bpr + X * bpp; idx < w; idx ++, psrc += bpp, pdst += 4) { - pdst[0] = psrc[0]; // R - pdst[1] = psrc[1]; // G - pdst[2] = psrc[2]; // B - } - } - bpr = 0; - } else { // read from window - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, may_capture_subwins); - if (did_capture_subwins) *did_capture_subwins = may_capture_subwins; - if (!cgimg) { - return NULL; - } - w = (int)CGImageGetWidth(cgimg); - h = (int)CGImageGetHeight(cgimg); - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Surface_Device::push_current(surf); - ((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(cgimg, 0, 0, w, h, 0, 0, w, h); - CGContextRef gc = (CGContextRef)fl_graphics_driver->gc(); - w = (int)CGBitmapContextGetWidth(gc); - h = (int)CGBitmapContextGetHeight(gc); - bpr = (int)CGBitmapContextGetBytesPerRow(gc); - bpp = (int)CGBitmapContextGetBitsPerPixel(gc)/8; - base = (uchar*)CGBitmapContextGetData(gc); - p = new uchar[bpr * h]; - memcpy(p, base, bpr * h); - Fl_Surface_Device::pop_current(); - delete surf; - CFRelease(cgimg); - } - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, 4, bpr); - rgb->alloc_array = 1; - return rgb; -} - -void Fl_Cocoa_Screen_Driver::set_spot(int /*font*/, int size, int X, int Y, int /*W*/, int /*H*/, Fl_Window* /*win*/) { - Fl_Cocoa_Screen_Driver::insertion_point_location(X, Y, size); -} - -void Fl_Cocoa_Screen_Driver::reset_spot() { - Fl_Cocoa_Screen_Driver::reset_marked_text(); -} diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H deleted file mode 100644 index 358523dbd..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ /dev/null @@ -1,168 +0,0 @@ -// -// Definition of Apple Cocoa window driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Cocoa_Window_Driver.H - \brief Definition of Apple Cocoa window driver. - */ - -#ifndef FL_COCOA_WINDOW_DRIVER_H -#define FL_COCOA_WINDOW_DRIVER_H - -#include "../../Fl_Window_Driver.H" -#include <FL/Fl_Plugin.H> -#include <ApplicationServices/ApplicationServices.h> - -class Fl_Image; -class Fl_Window; -#ifdef __OBJC__ -@class CALayer; -@class NSCursor; -@class NSImage; -@class FLWindow; -@class NSOpenGLContext; -@class NSOpenGLPixelFormat; -@class NSView; -@class NSWindow; -#else -class CALayer; -class NSCursor; -class NSImage; -class FLWindow; -class NSOpenGLContext; -class NSOpenGLPixelFormat; -class NSView; -class NSWindow; -#endif // __OBJC__ - -/** - \cond DriverDev - \addtogroup DriverDeveloper - \{ - */ - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - - ? where do we handle the interface between OpenGL/DirectX and Cocoa/Windows/Glx? - */ - -/** - \} - \endcond - */ - - -class Fl_Cocoa_Window_Driver : public Fl_Window_Driver -{ -private: - struct shape_data_type { - Fl_Image* shape_; ///< shape image - CGImageRef mask; - } *shape_data_; - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) FL_OVERRIDE; - CGRect* subRect_; // makes sure subwindow remains inside its parent window - // stores 3 binary flags: whether window is mapped to retina display; whether resolution just changed; - // whether window's view received the [FLView view_did_resize] message - unsigned window_flags_; -public: - Fl_Cocoa_Window_Driver(Fl_Window*); - ~Fl_Cocoa_Window_Driver(); - static inline Fl_Cocoa_Window_Driver* driver(const Fl_Window *w) {return (Fl_Cocoa_Window_Driver*)Fl_Window_Driver::driver(w);} - CGContextRef gc; // graphics context - NSCursor *cursor; - static void q_release_context(Fl_Cocoa_Window_Driver *x = 0); // free all resources associated with gc - static CGImageRef capture_decorated_window_10_5(NSWindow *nswin); - void set_key_window(); - bool mapped_to_retina(); // is window mapped to retina display? - void mapped_to_retina(bool); // sets whether window is mapped to retina display - bool changed_resolution(); // did window just moved to display with another resolution? - void changed_resolution(bool);// sets whether window just moved to display with another resolution - bool view_resized(); // did window's view receive [FLView view_did_resize] message? - void view_resized(bool b); // sets whether window's view received [FLView view_did_resize] message - bool through_resize(); // did Fl_Window::resize() run already - void through_resize(bool b); // set whether Fl_Window::resize() run already - CGRect* subRect() { return subRect_; } // getter - void subRect(CGRect *r) { subRect_ = r; } // setter - static void destroy(FLWindow*); - CGImageRef CGImage_from_window_rect(int x, int y, int w, int h, bool capture_subwins = true); - - // --- window data - int decorated_w() FL_OVERRIDE; - int decorated_h() FL_OVERRIDE; - const Fl_Image* shape() FL_OVERRIDE; - - // --- window management - void makeWindow() FL_OVERRIDE; - void take_focus() FL_OVERRIDE; - void flush() FL_OVERRIDE; - void flush_overlay() FL_OVERRIDE; - void draw_begin() FL_OVERRIDE; - void draw_end() FL_OVERRIDE; - void make_current() FL_OVERRIDE; - void label(const char *name, const char *mininame) FL_OVERRIDE; - void show() FL_OVERRIDE; - void resize(int X,int Y,int W,int H) FL_OVERRIDE; - void hide() FL_OVERRIDE; - void map() FL_OVERRIDE; - void unmap() FL_OVERRIDE; - void fullscreen_on() FL_OVERRIDE; - void fullscreen_off(int X, int Y, int W, int H) FL_OVERRIDE; - void fullscreen_screens(bool on_off) FL_OVERRIDE; - void maximize() FL_OVERRIDE; - void un_maximize() FL_OVERRIDE; - void use_border() FL_OVERRIDE; - void size_range() FL_OVERRIDE; - void iconize() FL_OVERRIDE; - void decoration_sizes(int *top, int *left, int *right, int *bottom) FL_OVERRIDE; - // --- window cursor stuff - int set_cursor(Fl_Cursor) FL_OVERRIDE; - int set_cursor(const Fl_RGB_Image*, int, int) FL_OVERRIDE; - - void shape(const Fl_Image* img) FL_OVERRIDE; - // next 4 are in Fl_cocoa.mm because they use Objective-c - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) FL_OVERRIDE; - void wait_for_expose() FL_OVERRIDE; - void draw_titlebar_to_context(CGContextRef gc, int w, int h); - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data) FL_OVERRIDE; - - //icons - void icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - NSImage *icon_image; - - fl_uintptr_t os_id() FL_OVERRIDE; -}; - -class Fl_Cocoa_Plugin : public Fl_Plugin { -public: - Fl_Cocoa_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "fltk:cocoa"; } - virtual const char *name() = 0; - virtual void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) = 0; -}; - -#endif // FL_COCOA_WINDOW_DRIVER_H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx deleted file mode 100644 index 55d1bea32..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx +++ /dev/null @@ -1,294 +0,0 @@ -// -// Definition of Apple Cocoa window driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_Cocoa_Window_Driver.H" -#include "../../Fl_Screen_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include <FL/Fl_Double_Window.H> -#include <FL/Fl_Overlay_Window.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/fl_draw.H> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <math.h> - - -Fl_Cocoa_Window_Driver::Fl_Cocoa_Window_Driver(Fl_Window *win) -: Fl_Window_Driver(win) -{ - cursor = nil; - window_flags_ = 0; - icon_image = NULL; - screen_num_ = 0; - shape_data_ = NULL; -} - - -void Fl_Cocoa_Window_Driver::take_focus() -{ - set_key_window(); -} - - -void Fl_Cocoa_Window_Driver::flush_overlay() -{ - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - int erase_overlay = (pWindow->damage()&FL_DAMAGE_OVERLAY) | (overlay() == oWindow); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - - if (!oWindow->shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - if (!other_xid) { - other_xid = new Fl_Image_Surface(oWindow->w(), oWindow->h(), 1); - oWindow->clear_damage(FL_DAMAGE_ALL); - } - if (oWindow->damage() & ~FL_DAMAGE_EXPOSE) { - Fl_X *myi = Fl_X::flx(pWindow); - fl_clip_region(myi->region); myi->region = 0; - Fl_Surface_Device::push_current(other_xid); - draw(); - Fl_Surface_Device::pop_current(); - } - if (erase_overlay) fl_clip_region(0); - fl_copy_offscreen(0, 0, oWindow->w(), oWindow->h(), other_xid->offscreen(), 0, 0); - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -void Fl_Cocoa_Window_Driver::draw_begin() -{ - if (!Fl_Surface_Device::surface()->driver()->has_feature(Fl_Graphics_Driver::NATIVE)) return; - CGContextRef my_gc = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); - if (shape_data_) { - if (shape_data_->mask) { - CGContextClipToMask(my_gc, CGRectMake(0,0,w(),h()), shape_data_->mask); // requires Mac OS 10.4 - } - CGContextSaveGState(my_gc); - } -} - - -void Fl_Cocoa_Window_Driver::draw_end() -{ - if (Fl_Surface_Device::surface()->driver()->has_feature(Fl_Graphics_Driver::NATIVE)) { - CGContextRef my_gc = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); - if (shape_data_) CGContextRestoreGState(my_gc); - } -} - - - -static void MyProviderReleaseData (void *info, const void *data, size_t size) { - delete[] (uchar*)data; -} - -// bitwise inversion of all 4-bit quantities -static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; - -static inline uchar swap_byte(const uchar b) { - // reverse the order of bits of byte b: 1->8 becomes 8->1 - return (swapped[b & 0xF] << 4) | swapped[b >> 4]; -} - - -void Fl_Cocoa_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->shape_ = b; - if (b) { - // complement mask bits and perform bitwise inversion of all bytes and also reverse top and bottom - int bytes_per_row = (b->w() + 7)/8; - uchar *from = new uchar[bytes_per_row * b->h()]; - for (int i = 0; i < b->h(); i++) { - uchar *p = (uchar*)(*b->data()) + bytes_per_row * i; - uchar *last = p + bytes_per_row; - uchar *q = from + (b->h() - 1 - i) * bytes_per_row; - while (p < last) { - *q++ = swap_byte(~*p++); - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, bytes_per_row * b->h(), MyProviderReleaseData); - shape_data_->mask = CGImageMaskCreate(b->w(), b->h(), 1, 1, bytes_per_row, provider, NULL, false); - CFRelease(provider); - } -} - - -void Fl_Cocoa_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, d = img->d(), w = img->w(), h = img->h(); - shape_data_->shape_ = img; - if (shape_data_->shape_) { - // reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits - int bytes_per_row = w * d; - uchar *from = new uchar[w * h]; - for ( i = 0; i < h; i++) { - uchar *p = (uchar*)(*img->data()) + bytes_per_row * i + offset; - uchar *last = p + bytes_per_row; - uchar *q = from + (h - 1 - i) * w; - while (p < last) { - if (d == 3) { - unsigned u = *p++; - u += *p++; - u += *p++; - *q++ = ~(u/3); - } - else { - *q++ = ~(*p); - p += d; - } - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, w * h, MyProviderReleaseData); - shape_data_->mask = CGImageMaskCreate(w, h, 8, 8, w, provider, NULL, false); - CFRelease(provider); - } -} - - -void Fl_Cocoa_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->mask) { CGImageRelease(shape_data_->mask); } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); - pWindow->border(false); -} - - -void Fl_Cocoa_Window_Driver::hide() { - Fl_X* ip = Fl_X::flx(pWindow); - // MacOS X manages a single pointer per application. Make sure that hiding - // a toplevel window will not leave us with some random pointer shape, or - // worst case, an invisible pointer - if (ip && !parent()) pWindow->cursor(FL_CURSOR_DEFAULT); - if ( hide_common() ) return; - q_release_context(this); - if ( ip->xid == (fl_uintptr_t)fl_window ) - fl_window = 0; - if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - destroy((FLWindow*)ip->xid); - delete subRect(); - delete ip; -} - - -int Fl_Cocoa_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data) -{ - if ( (src_x < 0) || (src_y < 0) ) - return 1; - if ( (src_x+src_w > pWindow->w()) || (src_y+src_h > pWindow->h()) ) - return 1; - CGImageRef img = CGImage_from_window_rect(src_x, src_y, src_w, src_h); - if (!img) - return 1; - // the current surface is generally the display, but is an Fl_Image_Surface when scrolling an Fl_Overlay_Window - Fl_Quartz_Graphics_Driver *qgd = (Fl_Quartz_Graphics_Driver*)Fl_Surface_Device::surface()->driver(); - float s = qgd->scale(); - qgd->draw_CGImage(img, dest_x, dest_y, (int)lround(s*src_w), (int)lround(s*src_h), 0, 0, src_w, src_h); - CFRelease(img); - return 0; -} - -static const unsigned mapped_mask = 1; -static const unsigned changed_mask = 2; -static const unsigned view_resized_mask = 4; -static const unsigned through_resize_mask = 8; - -bool Fl_Cocoa_Window_Driver::mapped_to_retina() { - return window_flags_ & mapped_mask; -} - -void Fl_Cocoa_Window_Driver::mapped_to_retina(bool b) { - if (b) window_flags_ |= mapped_mask; - else window_flags_ &= ~mapped_mask; -} - -bool Fl_Cocoa_Window_Driver::changed_resolution() { - return window_flags_ & changed_mask; -} - -void Fl_Cocoa_Window_Driver::changed_resolution(bool b) { - if (b) window_flags_ |= changed_mask; - else window_flags_ &= ~changed_mask; -} - -bool Fl_Cocoa_Window_Driver::view_resized() { - return window_flags_ & view_resized_mask; -} - -void Fl_Cocoa_Window_Driver::view_resized(bool b) { - if (b) window_flags_ |= view_resized_mask; - else window_flags_ &= ~view_resized_mask; -} - -bool Fl_Cocoa_Window_Driver::through_resize() { - return window_flags_ & through_resize_mask; -} - -void Fl_Cocoa_Window_Driver::through_resize(bool b) { - if (b) window_flags_ |= through_resize_mask; - else window_flags_ &= ~through_resize_mask; -} - -const Fl_Image* Fl_Cocoa_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - -/* Returns images of the capture of the window title-bar. - On the Mac OS platform, left, bottom and right are returned NULL; top is returned with depth 4. - */ -void Fl_Cocoa_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) -{ - top = left = bottom = right = NULL; - int htop, hleft, hright, hbottom; - Fl_Cocoa_Window_Driver::decoration_sizes(&htop, &hleft, &hright, &hbottom); - if (htop == 0) return; // when window is fullscreen - CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - float s = Fl::screen_driver()->scale(screen_num()); - int scaled_w = int(w() * s); - const int factor = (mapped_to_retina() ? 2 : 1); - int data_w = factor * scaled_w, data_h = factor * htop; - uchar *rgba = new uchar[4 * data_w * data_h]; - CGContextRef auxgc = CGBitmapContextCreate(rgba, data_w, data_h, 8, 4 * data_w, cspace, kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(cspace); - CGContextClearRect(auxgc, CGRectMake(0,0,data_w,data_h)); - CGContextScaleCTM(auxgc, factor, factor); - draw_titlebar_to_context(auxgc, scaled_w, htop); - top = new Fl_RGB_Image(rgba, data_w, data_h, 4); - top->alloc_array = 1; - top->scale(w(),htop, s <1 ? 0 : 1, 1); - CGContextRelease(auxgc); -} - - -FLWindow *fl_mac_xid(const Fl_Window *win) { - return (FLWindow*)Fl_Window_Driver::xid(win); -} - - -Fl_Window *fl_mac_find(FLWindow *xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} diff --git a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H b/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H deleted file mode 100644 index 2de8bde64..000000000 --- a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H +++ /dev/null @@ -1,51 +0,0 @@ -// -// Definition of class Fl_MacOS_Sys_Menu_Bar_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2017 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef Fl_MacOS_Sys_Menu_Bar_Driver_H -#define Fl_MacOS_Sys_Menu_Bar_Driver_H - -#include "../../Fl_Sys_Menu_Bar_Driver.H" - -class Fl_MacOS_Sys_Menu_Bar_Driver : public Fl_Sys_Menu_Bar_Driver { -public: - Fl_Menu_Item *window_menu_items; - int first_window_menu_item; - Fl_MacOS_Sys_Menu_Bar_Driver(); - virtual ~Fl_MacOS_Sys_Menu_Bar_Driver(); - void update() FL_OVERRIDE; - void draw() FL_OVERRIDE; - void about(Fl_Callback *cb, void *data) FL_OVERRIDE; - int add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) FL_OVERRIDE; - int add(const char* str) FL_OVERRIDE; - int insert(int index, const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags) FL_OVERRIDE; - void menu(const Fl_Menu_Item *m) FL_OVERRIDE; - void shortcut (int i, int s) FL_OVERRIDE; - void setonly (Fl_Menu_Item *item) FL_OVERRIDE; - void clear() FL_OVERRIDE; - int clear_submenu(int index) FL_OVERRIDE; - void remove(int index) FL_OVERRIDE; - void replace(int index, const char *name) FL_OVERRIDE; - void mode(int i, int fl) FL_OVERRIDE; - void create_window_menu() FL_OVERRIDE; - void new_window(Fl_Window *win); - void remove_window(Fl_Window *win); - void rename_window(Fl_Window *win); - static Fl_MacOS_Sys_Menu_Bar_Driver* driver(); - void play_menu(const Fl_Menu_Item *) FL_OVERRIDE; -}; - - -#endif /* Fl_MacOS_Sys_Menu_Bar_Driver_H */ diff --git a/src/drivers/Darwin/Fl_Darwin_System_Driver.H b/src/drivers/Darwin/Fl_Darwin_System_Driver.H deleted file mode 100644 index 7dd0ae6da..000000000 --- a/src/drivers/Darwin/Fl_Darwin_System_Driver.H +++ /dev/null @@ -1,85 +0,0 @@ -// -// Definition of Apple Darwin system driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2021 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Darwin_System_Driver.H - \brief Definition of Apple Darwin system driver. - */ - -#ifndef FL_DARWIN_SYSTEM_DRIVER_H -#define FL_DARWIN_SYSTEM_DRIVER_H - -#include "../Posix/Fl_Posix_System_Driver.H" -#include <stdlib.h> -#include <unistd.h> - -/* - Move everything here that manages the system interface. - - There is exactly one system driver. - - - filename and pathname management - - directory and file access - - system time and system timer - - multithreading - */ - -class Fl_Darwin_System_Driver : public Fl_Posix_System_Driver -{ -public: - Fl_Darwin_System_Driver(); - int single_arg(const char *arg) FL_OVERRIDE; - int arg_and_value(const char *name, const char *value) FL_OVERRIDE; - int clocale_vprintf(FILE *output, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsscanf(const char *input, const char *format, va_list args) FL_OVERRIDE; - static void *get_carbon_function(const char *name); - static int calc_mac_os_version(); // computes the fl_mac_os_version global variable - static unsigned short *compute_macKeyLookUp(); - - int filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - int open_uri(const char *uri, char *msg, int msglen) FL_OVERRIDE; - int need_test_shortcut_extra() FL_OVERRIDE {return 1;} - int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) FL_OVERRIDE; - void newUUID(char *uuidBuffer) FL_OVERRIDE; - char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor, - const char *application) FL_OVERRIDE; - const char *local_to_latin1(const char *t, int n) FL_OVERRIDE; - const char *latin1_to_local(const char *t, int n) FL_OVERRIDE; - const char *local_to_mac_roman(const char *t, int n) FL_OVERRIDE; - const char *mac_roman_to_local(const char *t, int n) FL_OVERRIDE; - void tree_draw_expando_button(int x, int y, bool state, bool active) FL_OVERRIDE; - int tree_connector_style() FL_OVERRIDE; - const char *filename_name(const char *buf) FL_OVERRIDE; - void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void add_fd(int fd, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void remove_fd(int, int when) FL_OVERRIDE; - void remove_fd(int) FL_OVERRIDE; - void open_callback(void (*)(const char *)) FL_OVERRIDE; - const char *shift_name() FL_OVERRIDE; - const char *meta_name() FL_OVERRIDE; - const char *alt_name() FL_OVERRIDE; - const char *control_name() FL_OVERRIDE; - Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() FL_OVERRIDE; - double wait(double time_to_wait) FL_OVERRIDE; - int ready() FL_OVERRIDE; - int filename_relative(char *to, int tolen, const char *dest_dir, const char *base_dir) FL_OVERRIDE; -}; - -#endif // FL_DARWIN_SYSTEM_DRIVER_H diff --git a/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx b/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx deleted file mode 100644 index c11a95f94..000000000 --- a/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx +++ /dev/null @@ -1,339 +0,0 @@ -// -// Definition of Apple Darwin system driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H" -#include <FL/Fl.H> -#include <FL/Fl_File_Browser.H> -#include <FL/Fl_Tree_Prefs.H> -#include <FL/Fl_Pixmap.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "../../flstring.h" -#include <string.h> -#include <xlocale.h> // 10.4 -#include <locale.h> -#include <stdio.h> -#include <dlfcn.h> -#include <pwd.h> -#include <sys/param.h> -#include <sys/ucred.h> -#include <sys/mount.h> -#include <sys/stat.h> - - -const char *Fl_Darwin_System_Driver::shift_name() { - return "⇧\\"; // "\xe2\x87\xa7\\"; // U+21E7 (upwards white arrow) -} -const char *Fl_Darwin_System_Driver::meta_name() { - return "⌘\\"; // "\xe2\x8c\x98\\"; // U+2318 (place of interest sign) -} -const char *Fl_Darwin_System_Driver::alt_name() { - return "⌥\\"; // "\xe2\x8c\xa5\\"; // U+2325 (option key) -} -const char *Fl_Darwin_System_Driver::control_name() { - return "⌃\\"; // "\xe2\x8c\x83\\"; // U+2303 (up arrowhead) -} - -Fl_Darwin_System_Driver::Fl_Darwin_System_Driver() : Fl_Posix_System_Driver() { - if (fl_mac_os_version == 0) fl_mac_os_version = calc_mac_os_version(); - command_key = FL_META; - control_key = FL_CTRL; -} - -int Fl_Darwin_System_Driver::single_arg(const char *arg) { - // The Finder application in MacOS X passes the "-psn_N_NNNNN" option to all apps. - return (strncmp(arg, "psn_", 4) == 0); -} - -int Fl_Darwin_System_Driver::arg_and_value(const char *name, const char *value) { - // Xcode in MacOS X may pass "-NSDocumentRevisionsDebugMode YES" - return strcmp(name, "NSDocumentRevisionsDebugMode") == 0; -} - -static locale_t postscript_locale = NULL; - -int Fl_Darwin_System_Driver::clocale_vprintf(FILE *output, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vfprintf_l(output, postscript_locale, format, args); // 10.4 -} - -int Fl_Darwin_System_Driver::clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vsnprintf_l(output, output_size, postscript_locale, format, args); // 10.4 -} - -int Fl_Darwin_System_Driver::clocale_vsscanf(const char *input, const char *format, va_list args) { - if (!postscript_locale) - postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - return vsscanf_l(input, postscript_locale, format, args); // 10.4 -} - - -// Returns the address of a Carbon function after dynamically loading the Carbon library if needed. -void *Fl_Darwin_System_Driver::get_carbon_function(const char *function_name) { - static void *carbon = ::dlopen("/System/Library/Frameworks/Carbon.framework/Carbon", RTLD_LAZY); - return (carbon ? dlsym(carbon, function_name) : NULL); -} - -int Fl_Darwin_System_Driver::filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_sz) { - int dirlen; - char *dirloc; - // Assume that locale encoding is no less dense than UTF-8 - dirlen = (int)strlen(d); - dirloc = (char *)d; -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - int n = scandir(dirloc, list, 0, (int(*)(const struct dirent**,const struct dirent**))sort); -# else - int n = scandir(dirloc, list, 0, (int(*)(const void*,const void*))sort); -# endif - if (n==-1) { - if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno)); - return -1; - } - // convert every filename to UTF-8, and append a '/' to all - // filenames that are directories - int i; - char *fullname = (char*)malloc(dirlen+FL_PATH_MAX+3); // Add enough extra for two /'s and a nul - // Use memcpy for speed since we already know the length of the string... - memcpy(fullname, d, dirlen+1); - char *name = fullname + dirlen; - if (name!=fullname && name[-1]!='/') *name++ = '/'; - for (i=0; i<n; i++) { - int newlen; - dirent *de = (*list)[i]; - int len = (int)strlen(de->d_name); - newlen = len; - dirent *newde = (dirent*)malloc(de->d_name - (char*)de + newlen + 2); // Add space for a / and a nul - // Conversion to UTF-8 - memcpy(newde, de, de->d_name - (char*)de); - strcpy(newde->d_name, de->d_name); - // Check if dir (checks done on "old" name as we need to interact with - // the underlying OS) - if (de->d_name[len-1]!='/' && len<=FL_PATH_MAX) { - // Use memcpy for speed since we already know the length of the string... - memcpy(name, de->d_name, len+1); - if (fl_filename_isdir(fullname)) { - char *dst = newde->d_name + newlen; - *dst++ = '/'; - *dst = 0; - } - } - free(de); - (*list)[i] = newde; - } - free(fullname); - return n; -} - - -int Fl_Darwin_System_Driver::open_uri(const char *uri, char *msg, int msglen) -{ - char *argv[3]; // Command-line arguments - argv[0] = (char*)"open"; - argv[1] = (char*)uri; - argv[2] = (char*)0; - if (msg) snprintf(msg, msglen, "open %s", uri); - return run_program("/usr/bin/open", argv, msg, msglen) != 0; -} - -int Fl_Darwin_System_Driver::file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) -{ - // MacOS X and Darwin use getfsstat() system call... - int numfs; // Number of file systems - struct statfs *fs; // Buffer for file system info - int num_files = 0; - - // We always have the root filesystem. - browser->add("/", icon); - - // Get the mounted filesystems... - numfs = getfsstat(NULL, 0, MNT_NOWAIT); - if (numfs > 0) { - // We have file systems, get them... - fs = new struct statfs[numfs]; - getfsstat(fs, sizeof(struct statfs) * numfs, MNT_NOWAIT); - - // Add filesystems to the list... - for (int i = 0; i < numfs; i ++) { - // Ignore "/", "/dev", and "/.vol"... - if (fs[i].f_mntonname[1] && strcmp(fs[i].f_mntonname, "/dev") && - strcmp(fs[i].f_mntonname, "/.vol")) { - snprintf(filename, lname, "%s/", fs[i].f_mntonname); - browser->add(filename, icon); - } - num_files ++; - } - - // Free the memory used for the file system info array... - delete[] fs; - } - return num_files; -} - -void Fl_Darwin_System_Driver::newUUID(char *uuidBuffer) -{ - CFUUIDRef theUUID = CFUUIDCreate(NULL); - CFUUIDBytes b = CFUUIDGetUUIDBytes(theUUID); - snprintf(uuidBuffer, 36+1, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - b.byte0, b.byte1, b.byte2, b.byte3, b.byte4, b.byte5, b.byte6, b.byte7, - b.byte8, b.byte9, b.byte10, b.byte11, b.byte12, b.byte13, b.byte14, b.byte15); - CFRelease(theUUID); -} - -/* - * returns pointer to the filename, or null if name ends with ':' - */ -const char *Fl_Darwin_System_Driver::filename_name( const char *name ) -{ - const char *p, *q; - if (!name) return (0); - for ( p = q = name ; *p ; ) { - if ( ( p[0] == ':' ) && ( p[1] == ':' ) ) { - q = p+2; - p++; - } - else if (p[0] == '/') { - q = p + 1; - } - p++; - } - return q; -} - -// These function assume a western code page. If you need to support -// scripts that are not part of this code page, you might want to -// take a look at FLTK2, which uses utf8 for text encoding. -// -// By keeping these conversion tables in their own module, they will not -// be statically linked (by a smart linker) unless actually used. -// -// On MS-Windows, nothing need to be converted. We simply return the -// original pointer. -// -// Most X11 implementations seem to default to Latin-1 as a code since it -// is a superset of ISO 8859-1, the original Western codepage on X11. -// -// Apple's OS X however renders text in MacRoman for western settings. The -// lookup tables below will convert all common character codes and replace -// unknown characters with an upside-down question mark. - -// This table converts Windows-1252/Latin 1 into MacRoman encoding -static uchar latin2roman[128] = { -0xdb, 0xc0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xc0, 0xdc, 0xce, 0xc0, 0xc0, 0xc0, -0xc0, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xc0, 0xdd, 0xcf, 0xc0, 0xc0, 0xd9, -0xca, 0xc1, 0xa2, 0xa3, 0xc0, 0xb4, 0xc0, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xc0, 0xa8, 0xf8, -0xa1, 0xb1, 0xc0, 0xc0, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc0, 0xbc, 0xc8, 0xc0, 0xc0, 0xc0, 0xc0, -0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, -0xc0, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xc0, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xc0, 0xc0, 0xa7, -0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, -0xc0, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xc0, 0xc0, 0xd8 -}; - -// This table converts MacRoman into Windows-1252/Latin 1 -static uchar roman2latin[128] = { -0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, -0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, -0x86, 0xb0, 0xa2, 0xa3, 0xa7, 0x95, 0xb6, 0xdf, 0xae, 0xa9, 0x99, 0xb4, 0xa8, 0xbf, 0xc6, 0xd8, -0xbf, 0xb1, 0xbf, 0xbf, 0xa5, 0xb5, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xaa, 0xba, 0xbf, 0xe6, 0xf8, -0xbf, 0xa1, 0xac, 0xbf, 0x83, 0xbf, 0xbf, 0xab, 0xbb, 0x85, 0xa0, 0xc0, 0xc3, 0xd5, 0x8c, 0x9c, -0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xf7, 0xbf, 0xff, 0x9f, 0xbf, 0x80, 0x8b, 0x9b, 0xbf, 0xbf, -0x87, 0xb7, 0x82, 0x84, 0x89, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, -0xbf, 0xd2, 0xda, 0xdb, 0xd9, 0xbf, 0x88, 0x98, 0xaf, 0xbf, 0xbf, 0xbf, 0xb8, 0xbf, 0xbf, 0xbf -}; - -static char *buf = 0; -static int n_buf = 0; - -const char *Fl_Darwin_System_Driver::latin1_to_local(const char *t, int n) -{ - if (n==-1) n = (int)strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src++; - if (c>127) - *dst = latin2roman[c-128]; - else - *dst = c; - } - //*dst = 0; // this would be wrong! - return buf; -} - -const char *Fl_Darwin_System_Driver::local_to_latin1(const char *t, int n) -{ - if (n==-1) n = (int)strlen(t); - if (n<=n_buf) { - n_buf = (n + 257) & 0x7fffff00; - if (buf) free(buf); - buf = (char*)malloc(n_buf); - } - const uchar *src = (const uchar*)t; - uchar *dst = (uchar*)buf; - for ( ; n>0; n--) { - uchar c = *src++; - if (c>127) - *dst++ = roman2latin[c-128]; - else - *dst++ = c; - } - //*dst = 0; // this would be wrong - return buf; -} - -// On Mac OS X, nothing need to be converted. We simply return the -// original pointer. -const char *Fl_Darwin_System_Driver::mac_roman_to_local(const char *t, int) -{ - return t; -} - -// On Mac OS X, nothing need to be converted. We simply return the -// original pointer. -const char *Fl_Darwin_System_Driver::local_to_mac_roman(const char *t, int) -{ - return t; -} - -Fl_Sys_Menu_Bar_Driver *Fl_Darwin_System_Driver::sys_menu_bar_driver() -{ - return Fl_MacOS_Sys_Menu_Bar_Driver::driver(); -} - -// Draw Mac-specific Fl_Tree open/close icons -void Fl_Darwin_System_Driver::tree_draw_expando_button(int x, int y, bool state, bool active) { - fl_color(active ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR); - if(state) fl_polygon(x + 3, y, x + 3, y + 11, x + 8, y + 5); // right arrow: ▶ - else fl_polygon(x, y + 3, x + 11, y + 3, x + 5, y + 8); // down arrow: ▼ -} -int Fl_Darwin_System_Driver::tree_connector_style() { - return FL_TREE_CONNECTOR_NONE; -} - - -int Fl_Darwin_System_Driver::filename_relative(char *to, int tolen, const char *dest_dir, const char *base_dir) { - return Fl_System_Driver::filename_relative_(to, tolen, dest_dir, base_dir, false); -} diff --git a/src/drivers/Darwin/fl_macOS_platform_init.cxx b/src/drivers/Darwin/fl_macOS_platform_init.cxx deleted file mode 100644 index fc18e90db..000000000 --- a/src/drivers/Darwin/fl_macOS_platform_init.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// -// macOS-specific code to initialize macOS support. -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "../Quartz/Fl_Quartz_Copy_Surface_Driver.H" -#include "../Quartz/Fl_Quartz_Graphics_Driver.H" -#include "../Cocoa/Fl_Cocoa_Screen_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" -#include "../Quartz/Fl_Quartz_Image_Surface_Driver.H" - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) -{ - return new Fl_Quartz_Copy_Surface_Driver(w, h); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() -{ - return new Fl_Quartz_Graphics_Driver(); -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() -{ - return new Fl_Cocoa_Screen_Driver(); -} - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() -{ - return new Fl_Darwin_System_Driver(); -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ - return new Fl_Cocoa_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ - return new Fl_Quartz_Image_Surface_Driver(w, h, high_res, off); -} diff --git a/src/drivers/GDI/Fl_Font.H b/src/drivers/GDI/Fl_Font.H deleted file mode 100644 index 3e8b1296f..000000000 --- a/src/drivers/GDI/Fl_Font.H +++ /dev/null @@ -1,43 +0,0 @@ -// -// Font definitions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Two internal fltk data structures: -// -// Fl_Fontdesc: an entry into the fl_font() table. There is one of these -// for each fltk font number. -// -#ifndef FL_FONT_ -#define FL_FONT_ - -#include <config.h> -#include "../../Fl_Scalable_Graphics_Driver.H" - -class Fl_GDI_Font_Descriptor : public Fl_Font_Descriptor { -public: - HFONT fid; - int *width[64]; - TEXTMETRIC metr; - int angle; - FL_EXPORT Fl_GDI_Font_Descriptor(const char* fontname, Fl_Fontsize size); -# if HAVE_GL - char glok[64]; -# endif // HAVE_GL - virtual FL_EXPORT ~Fl_GDI_Font_Descriptor(); -}; - -extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H deleted file mode 100644 index 7eae4c2bc..000000000 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.H +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_GDI_COPY_SURFACE_DRIVER_H -#define FL_GDI_COPY_SURFACE_DRIVER_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> - -class Fl_GDI_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; -protected: - HDC oldgc; - HDC gc; - Fl_GDI_Copy_Surface_Driver(int w, int h); - ~Fl_GDI_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif // FL_GDI_COPY_SURFACE_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx deleted file mode 100644 index c44c0a77b..000000000 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_GDI_Copy_Surface_Driver.H" -#include <FL/platform.H> -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_Screen_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include <windows.h> - - -Fl_GDI_Copy_Surface_Driver::Fl_GDI_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - driver(Fl_Graphics_Driver::newMainGraphicsDriver()); - oldgc = (HDC)Fl_Surface_Device::surface()->driver()->gc(); - // exact computation of factor from screen units to EnhMetaFile units (0.01 mm) - HDC hdc = GetDC(NULL); - int hmm = GetDeviceCaps(hdc, HORZSIZE); - int hdots = GetDeviceCaps(hdc, HORZRES); - int vmm = GetDeviceCaps(hdc, VERTSIZE); - int vdots = GetDeviceCaps(hdc, VERTRES); - ReleaseDC(NULL, hdc); - float factorw = (100.f * hmm) / hdots; - float factorh = (100.f * vmm) / vdots; - // Global display scaling factor: 1, 1.25, 1.5, 1.75, etc... - float scaling = Fl_Graphics_Driver::default_driver().scale(); - driver()->scale(scaling); - RECT rect; rect.left = 0; rect.top = 0; rect.right = (LONG)((w*scaling) * factorw); rect.bottom = (LONG)((h*scaling) * factorh); - gc = CreateEnhMetaFile (NULL, NULL, &rect, NULL); - if (gc != NULL) { - SetTextAlign(gc, TA_BASELINE|TA_LEFT); - SetBkMode(gc, TRANSPARENT); - } -} - - -Fl_GDI_Copy_Surface_Driver::~Fl_GDI_Copy_Surface_Driver() { - if (oldgc == (HDC)Fl_Surface_Device::surface()->driver()->gc()) oldgc = NULL; - HENHMETAFILE hmf = CloseEnhMetaFile (gc); - if ( hmf != NULL ) { - if ( OpenClipboard (NULL) ){ - EmptyClipboard (); - // put first the vectorial form of the graphics in the clipboard - SetClipboardData (CF_ENHMETAFILE, hmf); - // then put a BITMAP version of the graphics in the clipboard - float scaling = driver()->scale(); - int W = Fl_Scalable_Graphics_Driver::floor(width, scaling), H = Fl_Scalable_Graphics_Driver::floor(height, scaling); - RECT rect = {0, 0, W, H}; - Fl_Image_Surface *surf = new Fl_Image_Surface(W, H); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); // draw white background - fl_rectf(0, 0, W, H); - PlayEnhMetaFile((HDC)surf->driver()->gc(), hmf, &rect); // draw metafile to offscreen buffer - SetClipboardData(CF_BITMAP, (HBITMAP)surf->offscreen()); - Fl_Surface_Device::pop_current(); - delete surf; - - CloseClipboard (); - } - DeleteEnhMetaFile(hmf); - } - DeleteDC(gc); - Fl_Surface_Device::surface()->driver()->gc(oldgc); - delete driver(); -} - - -void Fl_GDI_Copy_Surface_Driver::set_current() { - driver()->gc(gc); - fl_window = (HWND)1; - Fl_Surface_Device::set_current(); -} - - -void Fl_GDI_Copy_Surface_Driver::translate(int x, int y) { - ((Fl_GDI_Graphics_Driver*)driver())->translate_all(x, y); -} - - -void Fl_GDI_Copy_Surface_Driver::untranslate() { - ((Fl_GDI_Graphics_Driver*)driver())->untranslate_all(); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H deleted file mode 100644 index 336fa1ebc..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ /dev/null @@ -1,230 +0,0 @@ -// -// Definition of classes Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver.H - \brief Definition of Windows GDI graphics driver. - */ - -#ifndef FL_GDI_GRAPHICS_DRIVER_H -#define FL_GDI_GRAPHICS_DRIVER_H - -#include "../../Fl_Scalable_Graphics_Driver.H" -#include <windows.h> -#include <stdlib.h> -#include <config.h> - -#if USE_GDIPLUS -# if defined(_MSC_VER) -# include <objidl.h> -# else -# include <wtypes.h> // for PROPID needed with gcc 4.9.0 but not with 4.9.3 -# endif -# include <gdiplus.h> -#endif - -/** - \brief The Windows-specific graphics driver class. - - This class is implemented only on the Windows platform. -*/ -class Fl_GDI_Graphics_Driver : public Fl_Scalable_Graphics_Driver { -private: - BOOL alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch); - int depth; // to support translation - POINT *origins; // to support translation - void set_current_() FL_OVERRIDE; - void draw_fixed(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_fixed(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void make_unused_color_(unsigned char &r, unsigned char &g, unsigned char &b, int color_count, void **data) FL_OVERRIDE; -protected: - void draw_fixed(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void cache(Fl_RGB_Image *rgb) FL_OVERRIDE; - HDC gc_; - int numcount; - int counts[20]; - uchar *mask_bitmap_; - uchar **mask_bitmap() FL_OVERRIDE {return &mask_bitmap_;} - POINT *long_point; - int style_; -public: - Fl_GDI_Graphics_Driver(); - ~Fl_GDI_Graphics_Driver() FL_OVERRIDE; - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & NATIVE; } - char can_do_alpha_blending() FL_OVERRIDE; - void gc(void *ctxt) FL_OVERRIDE { gc_ = (HDC)ctxt; global_gc(); } - void *gc() FL_OVERRIDE {return gc_;} - - // --- bitmap stuff - static HBITMAP create_bitmask(int w, int h, const uchar *array); // NOT virtual - static HBITMAP calc_HBITMAP_mask(Fl_RGB_Image *mask); - void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE; - HBITMAP create_alphamask(int w, int h, int d, int ld, const uchar *array); - void draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE; - void draw_unscaled(int angle, const char *str, int n, int x, int y) FL_OVERRIDE; - void rtl_draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE; - void font_unscaled(Fl_Font face, Fl_Fontsize size) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) FL_OVERRIDE; - void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) FL_OVERRIDE; - void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) FL_OVERRIDE; - void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) FL_OVERRIDE; - void cache(Fl_Pixmap *img) FL_OVERRIDE; - void uncache_pixmap(fl_uintptr_t p) FL_OVERRIDE; - void cache(Fl_Bitmap *img) FL_OVERRIDE; - void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) FL_OVERRIDE; - double width_unscaled(const char *str, int n) FL_OVERRIDE; - double width_unscaled(unsigned int c) FL_OVERRIDE; - void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h) FL_OVERRIDE; - int height_unscaled() FL_OVERRIDE; - int descent_unscaled() FL_OVERRIDE; - Fl_Fontsize size_unscaled() FL_OVERRIDE; -#if ! defined(FL_DOXYGEN) - void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy); -#endif - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) FL_OVERRIDE; - void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h) FL_OVERRIDE; - Fl_Region XRectangleRegion(int x, int y, int w, int h) FL_OVERRIDE; - void XDestroyRegion(Fl_Region r) FL_OVERRIDE; - void translate_all(int x, int y); - void untranslate_all(void); - static HRGN scale_region(HRGN r, float f, Fl_GDI_Graphics_Driver *dr); - void scale(float f) FL_OVERRIDE; - float scale() {return Fl_Graphics_Driver::scale();} -protected: - void transformed_vertex0(float x, float y) FL_OVERRIDE; - void fixloop() FL_OVERRIDE; - void point(int x, int y) FL_OVERRIDE; - void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; - void rect_unscaled(int x, int y, int w, int h) FL_OVERRIDE; - void rectf_unscaled(int x, int y, int w, int h) FL_OVERRIDE; -#if USE_COLORMAP - void colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) FL_OVERRIDE; -#endif - void line_unscaled(int x, int y, int x1, int y1) FL_OVERRIDE; - void line_unscaled(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void xyline_unscaled(int x, int y, int x1) FL_OVERRIDE; - void yxline_unscaled(int x, int y, int y1) FL_OVERRIDE; - void loop_unscaled(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop_unscaled(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon_unscaled(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon_unscaled(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - // --- clipping - void push_clip(int x, int y, int w, int h) FL_OVERRIDE; - int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) FL_OVERRIDE; - int not_clipped(int x, int y, int w, int h) FL_OVERRIDE; - void restore_clip() FL_OVERRIDE; - Fl_Region scale_clip(float f) FL_OVERRIDE; - // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx - void begin_complex_polygon() FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_loop() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void gap() FL_OVERRIDE; - void ellipse_unscaled(double xt, double yt, double rx, double ry) FL_OVERRIDE; - void arc_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void line_style_unscaled(int style, int width, char* dashes) FL_OVERRIDE; - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void set_color(Fl_Color i, unsigned int c) FL_OVERRIDE; - void free_color(Fl_Color i, int overlay) FL_OVERRIDE; - Fl_Font set_fonts(const char *name) FL_OVERRIDE; - int get_font_sizes(Fl_Font fnum, int*& sizep) FL_OVERRIDE; - const char* get_font_name(Fl_Font fnum, int* ap) FL_OVERRIDE; - const char *font_name(int num) FL_OVERRIDE; - void font_name(int num, const char *name) FL_OVERRIDE; - void global_gc() FL_OVERRIDE; - void overlay_rect(int x, int y, int w , int h) FL_OVERRIDE; - void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE; - void* change_pen_width(int width) FL_OVERRIDE; - void reset_pen_width(void *data) FL_OVERRIDE; -}; - - -/** - The graphics driver used when printing on Windows. - - This class is implemented only on the Windows platform. - It is extremely similar to Fl_GDI_Graphics_Driver. -*/ -class Fl_GDI_Printer_Graphics_Driver : public Fl_GDI_Graphics_Driver { -private: - typedef BOOL (WINAPI* transparent_f_type) (HDC,int,int,int,int,HDC,int,int,int,int,UINT); - transparent_f_type TransparentBlt(); -public: - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & (NATIVE | PRINTER); } - void draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) FL_OVERRIDE; -}; - -#if USE_GDIPLUS - -class Fl_GDIplus_Graphics_Driver : public Fl_GDI_Graphics_Driver { - friend class Fl_Graphics_Driver; -private: - Gdiplus::Color gdiplus_color_; - Gdiplus::Pen *pen_; - Gdiplus::SolidBrush *brush_; - // The code below ensures that a connection to GDIplus is only made once, and that the - // matching connection shutdown is also done exactly once. - enum { - STATE_CLOSED = 0, // no connection, token is invalid - STATE_STARTUP, // attempt to start up, avoid recursions for whatever reason - STATE_OPEN, // connection was successful and the token is valid - STATE_SHUTDOWN // shutting down the gdi connection, avoid possible recursion - }; - static int gdiplus_state_; // reflect the state of the GDIplus driver connection - static ULONG_PTR gdiplus_token_; // the token that GDIplus gives to us -public: - Fl_GDIplus_Graphics_Driver(); - virtual ~Fl_GDIplus_Graphics_Driver(); - bool active; - static void shutdown(void); - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void line(int x, int y, int x1, int y1) FL_OVERRIDE; - void line(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void line_style(int style, int width, char* dashes) FL_OVERRIDE; - void arc_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie_unscaled(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void draw_circle(int x, int y, int d, Fl_Color c) FL_OVERRIDE; - void transformed_vertex(double xf, double yf) FL_OVERRIDE; - void vertex(double x,double y) FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_loop() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void circle(double x, double y, double r) FL_OVERRIDE; - void antialias(int state) FL_OVERRIDE; - int antialias() FL_OVERRIDE; -}; - -#endif // USE_GDIPLUS - -#endif // FL_GDI_GRAPHICS_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx deleted file mode 100644 index 97b3244d1..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx +++ /dev/null @@ -1,322 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_GDI_Graphics_Driver.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "../../Fl_Screen_Driver.H" -#include "Fl_Font.H" - -#if USE_GDIPLUS - -Fl_GDIplus_Graphics_Driver::Fl_GDIplus_Graphics_Driver() : Fl_GDI_Graphics_Driver() { - if (!fl_current_xmap) color(FL_BLACK); - pen_ = new Gdiplus::Pen(gdiplus_color_, 1); - pen_->SetLineJoin(Gdiplus::LineJoinRound); - pen_->SetStartCap(Gdiplus::LineCapFlat); - pen_->SetEndCap(Gdiplus::LineCapFlat); - brush_ = new Gdiplus::SolidBrush(gdiplus_color_); - active = true; -} - -Fl_GDIplus_Graphics_Driver::~Fl_GDIplus_Graphics_Driver() { - delete pen_; - delete brush_; -} - -void Fl_GDIplus_Graphics_Driver::antialias(int state) { - active = state; -} - -int Fl_GDIplus_Graphics_Driver::antialias() { - return active; -} - -void Fl_GDIplus_Graphics_Driver::draw_circle(int x, int y, int d, Fl_Color c) { - Fl_Graphics_Driver::draw_circle(x, y, d, c); -} - -int Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_CLOSED; -ULONG_PTR Fl_GDIplus_Graphics_Driver::gdiplus_token_ = 0; - -void Fl_GDIplus_Graphics_Driver::shutdown() { - if (gdiplus_state_ == STATE_OPEN) { - gdiplus_state_ = STATE_SHUTDOWN; - Gdiplus::GdiplusShutdown(Fl_GDIplus_Graphics_Driver::gdiplus_token_); - gdiplus_token_ = 0; - gdiplus_state_ = STATE_CLOSED; - } else if (gdiplus_state_ == STATE_CLOSED) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called, but driver is closed."); - } else if (gdiplus_state_ == STATE_SHUTDOWN) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called recursively."); - } else if (gdiplus_state_ == STATE_STARTUP) { -// Fl::warning("Fl_GDIplus_Graphics_Driver::shutdown() called while driver is starting up."); - } -} -#endif - -// Code used to switch output to an off-screen window. See macros in -// win32.H which save the old state in local variables. - -typedef struct { BYTE a; BYTE b; BYTE c; BYTE d; } FL_BLENDFUNCTION; -typedef BOOL (WINAPI* fl_alpha_blend_func) -(HDC,int,int,int,int,HDC,int,int,int,int,FL_BLENDFUNCTION); -static fl_alpha_blend_func fl_alpha_blend = NULL; -static FL_BLENDFUNCTION blendfunc = { 0, 0, 255, 1}; - -/* Reference to the current device context - For back-compatibility only. The preferred procedure to get this reference is - Fl_Surface_Device::surface()->driver()->gc(). - */ -HDC fl_gc = 0; - - -HDC fl_win32_gc() { return fl_gc; } - - -Fl_GDI_Graphics_Driver::Fl_GDI_Graphics_Driver() { - mask_bitmap_ = NULL; - gc_ = NULL; - long_point = NULL; - depth = -1; - origins = NULL; - style_ = FL_SOLID; -} - -Fl_GDI_Graphics_Driver::~Fl_GDI_Graphics_Driver() { - if (long_point) free(long_point); - delete[] origins; -} - -void Fl_GDI_Graphics_Driver::global_gc() -{ - fl_gc = (HDC)gc(); -} - -/* - * This function checks if the version of Windows that we - * curently run on supports alpha blending for bitmap transfers - * and finds the required function if so. - */ -char Fl_GDI_Graphics_Driver::can_do_alpha_blending() { - static char been_here = 0; - static char can_do = 0; - // do this test only once - if (been_here) return can_do; - been_here = 1; - // load the library that implements alpha blending - HMODULE hMod = LoadLibrary("MSIMG32.DLL"); - // give up if that doesn't exist (Win95?) - if (!hMod) return 0; - // now find the blending function inside that dll - fl_alpha_blend = (fl_alpha_blend_func)GetProcAddress(hMod, "AlphaBlend"); - // give up if we can't find it (Win95) - if (!fl_alpha_blend) return 0; - // we have the call, but does our display support alpha blending? - // get the desktop's device context - HDC dc = GetDC(0L); - if (!dc) return 0; - // check the device capabilities flags. However GetDeviceCaps - // does not return anything useful, so we have to do it manually: - - HBITMAP bm = CreateCompatibleBitmap(dc, 1, 1); - HDC new_gc = CreateCompatibleDC(dc); - int save = SaveDC(new_gc); - SelectObject(new_gc, bm); - /*COLORREF set = */ SetPixel(new_gc, 0, 0, 0x01010101); - BOOL alpha_ok = fl_alpha_blend(dc, 0, 0, 1, 1, new_gc, 0, 0, 1, 1, blendfunc); - RestoreDC(new_gc, save); - DeleteDC(new_gc); - DeleteObject(bm); - ReleaseDC(0L, dc); - - if (alpha_ok) can_do = 1; - return can_do; -} - -HDC fl_makeDC(HBITMAP bitmap) { - HDC new_gc = CreateCompatibleDC((HDC)Fl_Graphics_Driver::default_driver().gc()); - SetTextAlign(new_gc, TA_BASELINE|TA_LEFT); - SetBkMode(new_gc, TRANSPARENT); -#if USE_COLORMAP - if (fl_palette) SelectPalette(new_gc, fl_palette, FALSE); -#endif - SelectObject(new_gc, bitmap); - return new_gc; -} - -void Fl_GDI_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) { - x = int(x * scale()); y = int(y * scale()); w = int(w * scale()); h = int(h * scale()); - srcx = int(srcx * scale()); srcy = int(srcy * scale()); - if (srcx < 0) {w += srcx; x -= srcx; srcx = 0;} - if (srcy < 0) {h += srcy; y -= srcy; srcy = 0;} - int off_width, off_height; - Fl::screen_driver()->offscreen_size(bitmap, off_width, off_height); - if (srcx + w >= off_width) {w = off_width - srcx;} - if (srcy + h >= off_height) {h = off_height - srcy;} - if (w <= 0 || h <= 0) return; - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (HBITMAP)bitmap); - BitBlt(gc_, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); - RestoreDC(new_gc, save); - DeleteDC(new_gc); -} - -void Fl_GDI_Printer_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen bitmap, int srcx, int srcy) { - Fl_Graphics_Driver::copy_offscreen(x, y, w, h, bitmap, srcx, srcy); -} - -BOOL Fl_GDI_Graphics_Driver::alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch) { - return fl_alpha_blend(gc_, x, y, w, h, src_gc, srcx, srcy, srcw, srch, blendfunc); -} - -#if ! defined(FL_DOXYGEN) -void Fl_GDI_Graphics_Driver::copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, bitmap); - BOOL alpha_ok = 0; - // first try to alpha blend - if ( fl_can_do_alpha_blending() ) { - alpha_ok = alpha_blend_(x, y, w, h, new_gc, srcx, srcy, w, h); - } - // if that failed (it shouldn't), still copy the bitmap over, but now alpha is 1 - if (!alpha_ok) { - BitBlt(gc_, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); - } - RestoreDC(new_gc, save); - DeleteDC(new_gc); -} - -void Fl_GDI_Graphics_Driver::translate_all(int x, int y) { - const int stack_height = 10; - if (depth == -1) { - origins = new POINT[stack_height]; - depth = 0; - } - if (depth >= stack_height) { - Fl::warning("Fl_Copy/Image_Surface: translate stack overflow!"); - depth = stack_height - 1; - } - GetWindowOrgEx((HDC)gc(), origins+depth); - SetWindowOrgEx((HDC)gc(), int(origins[depth].x - x*scale()), int(origins[depth].y - y*scale()), NULL); - depth++; -} - -void Fl_GDI_Graphics_Driver::untranslate_all() { - if (depth > 0) depth--; - SetWindowOrgEx((HDC)gc(), origins[depth].x, origins[depth].y, NULL); -} -#endif - -void Fl_GDI_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H) { - HRGN R = (HRGN)XRectangleRegion(X, Y, W, H); - CombineRgn((HRGN)r, (HRGN)r, R, RGN_OR); - XDestroyRegion(R); -} - -void Fl_GDI_Graphics_Driver::transformed_vertex0(float x, float y) { - if (!n || x != long_point[n-1].x || y != long_point[n-1].y) { - if (n >= p_size) { - p_size = long_point ? 2*p_size : 16; - long_point = (POINT*)realloc((void*)long_point, p_size*sizeof(*long_point)); - } - long_point[n].x = LONG(x); - long_point[n].y = LONG(y); - n++; - } -} - -void Fl_GDI_Graphics_Driver::fixloop() { // remove equal points from closed path - while (n>2 && long_point[n-1].x == long_point[0].x && long_point[n-1].y == long_point[0].y) n--; -} - -Fl_Region Fl_GDI_Graphics_Driver::XRectangleRegion(int x, int y, int w, int h) { - if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) return CreateRectRgn(x,y,x+w,y+h); - // because rotation may apply, the rectangle becomes a polygon in device coords - POINT pt[4] = { {x, y}, {x + w, y}, {x + w, y + h}, {x, y + h} }; - LPtoDP((HDC)fl_graphics_driver->gc(), pt, 4); - return CreatePolygonRgn(pt, 4, ALTERNATE); -} - -void Fl_GDI_Graphics_Driver::XDestroyRegion(Fl_Region r) { - DeleteObject((HRGN)r); -} - - -void Fl_GDI_Graphics_Driver::scale(float f) { - if (f != scale()) { - size_ = 0; - Fl_Graphics_Driver::scale(f); - color(FL_BLACK); - line_style(FL_SOLID); // scale also default line width - } -} - - -/* Rescale region r with factor f and returns the scaled region. - Region r is returned unchanged if r is null or f is 1. - */ -HRGN Fl_GDI_Graphics_Driver::scale_region(HRGN r, float f, Fl_GDI_Graphics_Driver *dr) { - if (r && f != 1) { - DWORD size = GetRegionData(r, 0, NULL); - RGNDATA *pdata = (RGNDATA*)malloc(size); - GetRegionData(r, size, pdata); - POINT pt = {0, 0}; - if (dr && dr->depth >= 1) { // account for translation - GetWindowOrgEx((HDC)dr->gc(), &pt); - pt.x = int(pt.x * (f - 1)); - pt.y = int(pt.y * (f - 1)); - } - RECT *rects = (RECT*)&(pdata->Buffer); - for (DWORD i = 0; i < pdata->rdh.nCount; i++) { - int x = Fl_Scalable_Graphics_Driver::floor(rects[i].left, f) + pt.x; - int y = Fl_Scalable_Graphics_Driver::floor(rects[i].top, f) + pt.y; - RECT R2; - R2.left = x; - R2.top = y; - R2.right = Fl_Scalable_Graphics_Driver::floor(rects[i].right, f) + pt.x - x + R2.left; - R2.bottom = Fl_Scalable_Graphics_Driver::floor(rects[i].bottom, f) + pt.y - y + R2.top; - rects[i] = R2; - } - r = ExtCreateRegion(NULL, size, pdata); - free(pdata); - } - return r; -} - - -Fl_Region Fl_GDI_Graphics_Driver::scale_clip(float f) { - HRGN r = (HRGN)rstack[rstackptr]; - HRGN r2 = scale_region(r, f, this); - return (r == r2 ? NULL : (rstack[rstackptr] = r2, r)); -} - -void Fl_GDI_Graphics_Driver::set_current_() { - restore_clip(); -} - -void Fl_GDI_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) -{ - float s = scale(); - width = (s == int(s) ? width * int(s) : floor(width+1)); - height = (s == int(s) ? height * int(s) : floor(height+1)); - cache_size_finalize(img, width, height); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx deleted file mode 100644 index 0c1e90064..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx +++ /dev/null @@ -1,89 +0,0 @@ -// -// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_arci.cxx - \brief Utility functions for drawing circles using integers -*/ - -// "integer" circle drawing functions. These draw the limited -// circle types provided by X and NT graphics. The advantage of -// these is that small ones draw quite nicely (probably due to stored -// hand-drawn bitmaps of small circles!) and may be implemented by -// hardware and thus are fast. - -#include "Fl_GDI_Graphics_Driver.H" - -#include <FL/math.h> -#include <FL/platform.H> - -void Fl_GDI_Graphics_Driver::arc_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - w++; h++; - int xa = int( x+w/2+int(w*cos(a1/180.0*M_PI)) ); - int ya = int( y+h/2-int(h*sin(a1/180.0*M_PI)) ); - int xb = int( x+w/2+int(w*cos(a2/180.0*M_PI)) ); - int yb = int( y+h/2-int(h*sin(a2/180.0*M_PI)) ); - if (fabs(a1 - a2) < 90) { - if (xa == xb && ya == yb) SetPixel(gc_, xa, ya, fl_RGB()); - else Arc(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); - } else Arc(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); -} - -void Fl_GDI_Graphics_Driver::pie_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (a1 == a2) return; - x++; y++; w--; h--; - if (scale() >= 3) {x++; y++; w-=2; h-=2;} - int xa = int( x+w/2+int(w*cos(a1/180.0*M_PI)) ); - int ya = int( y+h/2-int(h*sin(a1/180.0*M_PI)) ); - int xb = int( x+w/2+int(w*cos(a2/180.0*M_PI)) ); - int yb = int( y+h/2-int(h*sin(a2/180.0*M_PI)) ); - SelectObject(gc_, fl_brush()); - if (fabs(a1 - a2) < 90) { - if (xa == xb && ya == yb) { - MoveToEx(gc_, int(x+w/2), int(y+h/2), 0L); - LineTo(gc_, xa, ya); - SetPixel(gc_, xa, ya, fl_RGB()); - } else Pie(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); - } else Pie(gc_, int(x), int(y), int(x+w), int(y+h), xa, ya, xb, yb); -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::arc_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (!active) return Fl_GDI_Graphics_Driver::arc_unscaled(x, y, w, h, a1, a2); - Gdiplus::Graphics graphics_(gc_); - pen_->SetColor(gdiplus_color_); - Gdiplus::REAL oldw = pen_->GetWidth(); - Gdiplus::REAL new_w = (line_width_ <= scale() ? 1 : line_width_) * scale(); - pen_->SetWidth(new_w); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawArc(pen_, x, y, w, h, Gdiplus::REAL(-a1), Gdiplus::REAL(a1-a2)); - pen_->SetWidth(oldw); -} - -void Fl_GDIplus_Graphics_Driver::pie_unscaled(int x, int y, int w, int h, double a1, double a2) { - if (w <= 0 || h <= 0) return; - if (!active) return Fl_GDI_Graphics_Driver::pie_unscaled(x, y, w, h, a1, a2); - Gdiplus::Graphics graphics_(gc_); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPie(brush_, x, y, w, h, Gdiplus::REAL(-a1), Gdiplus::REAL(a1-a2)); -} - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx deleted file mode 100644 index c05a255d0..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_color.cxx +++ /dev/null @@ -1,259 +0,0 @@ -// -// MSWidnows' GDI color functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// The fltk "colormap". This allows ui colors to be stored in 8-bit -// locations, and provides a level of indirection so that global color -// changes can be made. Not to be confused with the X colormap, which -// I try to hide completely. - -#include "Fl_GDI_Graphics_Driver.H" - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -// FIXME: all the global functions in this file should probably be protected -// members of the driver class. Starting with 1.4 we will allow multiple drivers -// to co-exist, creating conflicts with multipe mapping. - -// FIXME: maybe we can forget about color mapping and assume RGB? -// FIXME: ... but for now we still have it ... -extern unsigned fl_cmap[256]; // defined in fl_color.cxx - -// Translations to win32 data structures: -Fl_XMap fl_xmap[256]; - -Fl_XMap* fl_current_xmap; - -HPALETTE fl_palette; -static HGDIOBJ tmppen=0; -static HPEN savepen=0; - -void fl_cleanup_pens(void) { - for (int i=0; i<256; i++) { - if (fl_xmap[i].pen) DeleteObject(fl_xmap[i].pen); - } -} - -void fl_save_pen(void) { - if(!tmppen) tmppen = CreatePen(PS_SOLID, 1, 0); - savepen = (HPEN)SelectObject((HDC)fl_graphics_driver->gc(), tmppen); -} - -void fl_restore_pen(void) { - if (savepen) SelectObject((HDC)fl_graphics_driver->gc(), savepen); - DeleteObject(tmppen); - tmppen = 0; - savepen = 0; -} - -static void clear_xmap(Fl_XMap& xmap) { - if (xmap.pen) { - HDC gc = (HDC)fl_graphics_driver->gc(); - HGDIOBJ tmppen = GetStockObject(BLACK_PEN); - HGDIOBJ oldpen = SelectObject(gc, tmppen); // Push out the current pen of the gc - if(oldpen != xmap.pen) SelectObject(gc, oldpen); // Put it back if it is not the one we are about to delete - DeleteObject((HGDIOBJ)(xmap.pen)); - xmap.pen = 0; - xmap.brush = -1; - } -} - -static void set_xmap(Fl_XMap& xmap, COLORREF c, int lw) { - xmap.rgb = c; - if (xmap.pen) { - HDC gc = (HDC)fl_graphics_driver->gc(); - HGDIOBJ oldpen = SelectObject(gc,GetStockObject(BLACK_PEN)); // replace current pen with safe one - if (oldpen != xmap.pen)SelectObject(gc,oldpen); // if old one not xmap.pen, need to put it back - DeleteObject(xmap.pen); // delete pen - } -// xmap.pen = CreatePen(PS_SOLID, 1, xmap.rgb); // get a pen into xmap.pen - LOGBRUSH penbrush = {BS_SOLID, xmap.rgb, 0}; - xmap.pen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_ROUND, lw, &penbrush, 0, 0); - xmap.pwidth = lw; - xmap.brush = -1; -} - -void Fl_GDI_Graphics_Driver::color(Fl_Color i) { - if (i & 0xffffff00) { - unsigned rgb = (unsigned)i; - color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); - } else { - Fl_Graphics_Driver::color(i); - Fl_XMap &xmap = fl_xmap[i]; - int tw = line_width_ ? line_width_ : int(scale()); if (!tw) tw = 1; - if (!xmap.pen || xmap.pwidth != tw) { -#if USE_COLORMAP - if (fl_palette) { - set_xmap(xmap, PALETTEINDEX(i), tw); - } else { -#endif - unsigned c = fl_cmap[i]; - set_xmap(xmap, RGB(uchar(c>>24), uchar(c>>16), uchar(c>>8)), tw); -#if USE_COLORMAP - } -#endif - } - fl_current_xmap = ⟼ - SelectObject(gc_, (HGDIOBJ)(xmap.pen)); - } -} - -void Fl_GDI_Graphics_Driver::color(uchar r, uchar g, uchar b) { - static Fl_XMap xmap; - COLORREF c = RGB(r,g,b); - Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); - int tw = line_width_ ? line_width_ : int(scale()); if (!tw) tw = 1; - if (!xmap.pen || c != xmap.rgb || tw != xmap.pwidth) { - clear_xmap(xmap); - set_xmap(xmap, c, tw); - } - fl_current_xmap = ⟼ - SelectObject(gc_, (HGDIOBJ)(xmap.pen)); -} - -HBRUSH fl_brush() { - return fl_brush_action(0); -} - -HBRUSH fl_brush_action(int action) { - Fl_XMap *xmap = fl_current_xmap; - HDC gc = (HDC)fl_graphics_driver->gc(); - // Wonko: we use some statistics to cache only a limited number - // of brushes: -#define FL_N_BRUSH 16 - static struct Fl_Brush { - HBRUSH brush; - unsigned short usage; - Fl_XMap* backref; - } brushes[FL_N_BRUSH]; - - if (action) { - SelectObject(gc, GetStockObject(BLACK_BRUSH)); // Load stock object - for (int i=0; i<FL_N_BRUSH; i++) { - if (brushes[i].brush) - DeleteObject(brushes[i].brush); // delete all brushes in array - } - return NULL; - } - - int i = xmap->brush; // find the associated brush - if (i != -1) { // if the brush was allready allocated - if (brushes[i].brush == NULL) goto CREATE_BRUSH; - if ( (++brushes[i].usage) > 32000 ) { // keep a usage statistic - for (int j=0; j<FL_N_BRUSH; j++) { - if (brushes[j].usage>16000) - brushes[j].usage -= 16000; - else - brushes[j].usage = 0; - } - } - return brushes[i].brush; - } else { - int umin = 32000, imin = 0; - for (i=0; i<FL_N_BRUSH; i++) { - if (brushes[i].brush == NULL) goto CREATE_BRUSH; - if (brushes[i].usage<umin) { - umin = brushes[i].usage; - imin = i; - } - } - i = imin; - HGDIOBJ tmpbrush = GetStockObject(BLACK_BRUSH); // get a stock brush - HGDIOBJ oldbrush = SelectObject(gc,tmpbrush); // load in into current context - if (oldbrush != brushes[i].brush) SelectObject(gc,oldbrush); // reload old one - DeleteObject(brushes[i].brush); // delete the one in list - brushes[i].brush = NULL; - brushes[i].backref->brush = -1; - } -CREATE_BRUSH: - brushes[i].brush = CreateSolidBrush(xmap->rgb); - brushes[i].usage = 0; - brushes[i].backref = xmap; - xmap->brush = i; - return brushes[i].brush; -} - -void Fl_GDI_Graphics_Driver::free_color(Fl_Color i, int overlay) { - if (overlay) return; // do something about GL overlay? - clear_xmap(fl_xmap[i]); -} - -void Fl_GDI_Graphics_Driver::set_color(Fl_Color i, unsigned c) { - if (fl_cmap[i] != c) { - clear_xmap(fl_xmap[i]); - fl_cmap[i] = c; - } -} - -#if USE_COLORMAP - -// 'fl_select_palette()' - Make a color palette for 8-bit displays if necessary -// Thanks to Michael Sweet @ Easy Software Products for this - -HPALETTE -fl_select_palette(void) -{ - static char beenhere; - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!beenhere) { - beenhere = 1; - - int nColors = GetDeviceCaps(gc, SIZEPALETTE); - if (nColors <= 0 || nColors > 256) return NULL; - // this will try to work on < 256 color screens, but will probably - // come out quite badly. - - // I lamely try to get this variable-sized object allocated on stack: - ulong foo[(sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY))/sizeof(ulong)+1]; - LOGPALETTE *pPal = (LOGPALETTE*)foo; - - pPal->palVersion = 0x300; - pPal->palNumEntries = nColors; - - // Build 256 colors from the standard FLTK colormap... - - for (int i = 0; i < nColors; i ++) { - pPal->palPalEntry[i].peRed = (fl_cmap[i] >> 24) & 255; - pPal->palPalEntry[i].peGreen = (fl_cmap[i] >> 16) & 255; - pPal->palPalEntry[i].peBlue = (fl_cmap[i] >> 8) & 255; - pPal->palPalEntry[i].peFlags = 0; - }; - - // Create the palette: - fl_palette = CreatePalette(pPal); - } - if (fl_palette) { - SelectPalette(gc, fl_palette, FALSE); - RealizePalette(gc); - } - return fl_palette; -} - -#endif - -#if USE_GDIPLUS -void Fl_GDIplus_Graphics_Driver::color(uchar r, uchar g, uchar b) { - Fl_GDI_Graphics_Driver::color(r, g, b); - gdiplus_color_.SetFromCOLORREF(fl_RGB()); -} - -void Fl_GDIplus_Graphics_Driver::color(Fl_Color i) { - Fl_GDI_Graphics_Driver::color(i); - gdiplus_color_.SetFromCOLORREF(fl_RGB()); -} -#endif // USE_GDIPLUS diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx deleted file mode 100644 index 49111f10e..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx +++ /dev/null @@ -1,678 +0,0 @@ -// -// Windows font utilities for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> - -#ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif -/* We require Windows 2000 features such as GetGlyphIndices */ -#if !defined(WINVER) || (WINVER < 0x0500) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0500 -#endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0500 -#endif - -// Select fonts from the FLTK font table. -#include "Fl_GDI_Graphics_Driver.H" -#include "../../flstring.h" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include "Fl_Font.H" - -#include <stdio.h> -#include <stdlib.h> -#include <FL/fl_string_functions.h> - -// This function fills in the FLTK font table with all the fonts that -// are found on the X server. It tries to place the fonts into families -// and to sort them so the first 4 in a family are normal, bold, italic, -// and bold italic. -#include <FL/fl_utf8.h> -#ifdef __CYGWIN__ -# include <wchar.h> -#endif - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 - -// turn a stored font name into a pretty name: -const char* Fl_GDI_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) { - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - const char* p = f->name; - if (!p || !*p) {if (ap) *ap = 0; return "";} - int type; - switch (*p) { - case 'B': type = FL_BOLD; break; - case 'I': type = FL_ITALIC; break; - case 'P': type = FL_BOLD | FL_ITALIC; break; - default: type = 0; break; - } - strlcpy(f->fontname, p+1, ENDOFBUFFER); - if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); - if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - -static int fl_free_font = FL_FREE_FONT; - -// helper function for `enumcbw()` to avoid code repetition -// input: -// ft: font "type", i.e. ' ', 'B', 'I', or 'P' -// fn: font name whose first byte is overwritten and then stored - -static void set_font_name(const char ft, char *fn) { - fn[0] = ft; - Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(fn)); -} - -// Callback for EnumFontFamiliesW(): -// return 1 to continue, 0 to stop enumeration - -static int CALLBACK -enumcbw(CONST LOGFONTW *lpelf, - CONST TEXTMETRICW * /* lpntm */, - DWORD /* FontType */, - LPARAM p) { - if (!p && lpelf->lfCharSet != ANSI_CHARSET) return 1; - char *fn = nullptr; // FLTK font name - unsigned lw = (unsigned)wcslen(lpelf->lfFaceName); - unsigned dstlen = fl_utf8fromwc(fn, 0, (wchar_t*)lpelf->lfFaceName, lw); // measure the string - fn = (char*)malloc((size_t)dstlen + 2); // "?" + name + NUL - if (!fn) return 1; - fn[0] = ' '; - dstlen = fl_utf8fromwc(fn+1, dstlen+1, (wchar_t*)lpelf->lfFaceName, lw); // convert the string - fn[dstlen + 1] = 0; - // skip if it is one of our built-in fonts - for (int i = 0; i < FL_FREE_FONT; i++) { - if (!strcmp(Fl::get_font_name((Fl_Font)i), fn+1)) { - free(fn); - return 1; - } - } - set_font_name(' ', fn); - if (lpelf->lfWeight <= 400) - set_font_name('B', fn); - set_font_name('I', fn); - if (lpelf->lfWeight <= 400) - set_font_name('P', fn); - free(fn); - return 1; -} /* enumcbw */ - -Fl_Font Fl_GDI_Graphics_Driver::set_fonts(const char* xstarname) { - HDC gc = (HDC)fl_graphics_driver->gc(); - if (fl_free_font == FL_FREE_FONT) {// if not already been called - if (!gc) gc = fl_GetDC(0); - - EnumFontFamiliesW(gc, NULL, (FONTENUMPROCW)enumcbw, xstarname != 0); - - } - return (Fl_Font)fl_free_font; -} - - -static int nbSize; -static int cyPerInch; -static int sizes[128]; -static int CALLBACK - -EnumSizeCbW(CONST LOGFONTW * /*lpelf*/, - CONST TEXTMETRICW *lpntm, - DWORD fontType, - LPARAM /*p*/) { - if ((fontType & RASTER_FONTTYPE) == 0) { - sizes[0] = 0; - nbSize = 1; - - // Scalable font - return 0; - } - - int add = lpntm->tmHeight - lpntm->tmInternalLeading; - add = MulDiv(add, 72, cyPerInch); - - int start = 0; - while ((start < nbSize) && (sizes[start] < add)) { - start++; - } - - if ((start < nbSize) && (sizes[start] == add)) { - return 1; - } - - for (int i=nbSize; i>start; i--) sizes[i] = sizes[i - 1]; - - sizes[start] = add; - nbSize++; - - // Stop enum if buffer overflow - return nbSize < 128; -} - - -int Fl_GDI_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { - nbSize = 0; - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!gc) gc = fl_GetDC(0); - cyPerInch = GetDeviceCaps(gc, LOGPIXELSY); - if (cyPerInch < 1) cyPerInch = 1; - -// int l = fl_utf_nb_char((unsigned char*)s->name+1, strlen(s->name+1)); -// unsigned short *b = (unsigned short*) malloc((l + 1) * sizeof(short)); -// fl_utf2unicode((unsigned char*)s->name+1, l, (wchar_t*)b); - const char *nm = (const char*)s->name+1; - size_t len = strlen(s->name+1); - unsigned l = fl_utf8toUtf16(nm, (unsigned) len, NULL, 0); // Pass NULL to query length required - unsigned short *b = (unsigned short*) malloc((l + 1) * sizeof(short)); - l = fl_utf8toUtf16(nm, (unsigned) len, b, (l+1)); // Now do the conversion - b[l] = 0; - EnumFontFamiliesW(gc, (WCHAR*)b, (FONTENUMPROCW)EnumSizeCbW, 0); - free(b); - - sizep = sizes; - return nbSize; -} - -const char *Fl_GDI_Graphics_Driver::font_name(int num) { - return fl_fonts[num].name; -} - -void Fl_GDI_Graphics_Driver::font_name(int num, const char *name) { - Fl_Fontdesc *s = fl_fonts + num; - if (s->name) { - if (!strcmp(s->name, name)) {s->name = name; return;} - for (Fl_Font_Descriptor* f = s->first; f;) { - Fl_Font_Descriptor* n = f->next; delete f; f = n; - } - s->first = 0; - } - s->name = name; - s->fontname[0] = 0; - s->first = 0; -} - - -static int fl_angle_ = 0; -// Unicode string buffer -static unsigned short *wstr = NULL; -static int wstr_len = 0; - -#ifndef FL_DOXYGEN -Fl_GDI_Font_Descriptor::Fl_GDI_Font_Descriptor(const char* name, Fl_Fontsize fsize) : Fl_Font_Descriptor(name,fsize) { - int weight = FW_NORMAL; - int italic = 0; - switch (*name++) { - case 'I': italic = 1; break; - case 'P': italic = 1; - case 'B': weight = FW_BOLD; break; - case ' ': break; - default: name--; - } - int wn = fl_utf8toUtf16(name, (unsigned int)strlen(name), wstr, wstr_len); - if (wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(name, (unsigned int)strlen(name), wstr, wstr_len); - } - - fid = CreateFontW( - -fsize, // negative makes it use "char size" - 0, // logical average character width - fl_angle_*10, // angle of escapement - fl_angle_*10, // base-line orientation angle - weight, - italic, - FALSE, // underline attribute flag - FALSE, // strikeout attribute flag - DEFAULT_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS,// clipping precision - DEFAULT_QUALITY, // output quality - DEFAULT_PITCH, // pitch and family - (LPCWSTR)wstr // pointer to typeface name string - ); - angle = fl_angle_; - HDC gc = (HDC)fl_graphics_driver->gc(); - if (!gc) gc = fl_GetDC(0); - SelectObject(gc, fid); - GetTextMetrics(gc, &metr); -// BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar); -// ...would be the right call, but is not implemented into Window95! (WinNT?) - //GetCharWidth(fl_gc, 0, 255, width); - int i; - memset(width, 0, 64 * sizeof(int*)); -#if HAVE_GL - for (i = 0; i < 64; i++) glok[i] = 0; -#endif - size = fsize; -} - -Fl_GDI_Font_Descriptor::~Fl_GDI_Font_Descriptor() { -#if HAVE_GL -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -#endif - if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); - DeleteObject(fid); - for (int i = 0; i < 64; i++) { - if ( width[i] ) free(width[i]); - } -} - -//////////////////////////////////////////////////////////////// - -// WARNING: if you add to this table, you must redefine FL_FREE_FONT -// in Enumerations.H & recompile!! -static Fl_Fontdesc built_in_table[] = { - {" Microsoft Sans Serif"}, - {"BMicrosoft Sans Serif"}, - {"IMicrosoft Sans Serif"}, - {"PMicrosoft Sans Serif"}, -{" Courier New"}, -{"BCourier New"}, -{"ICourier New"}, -{"PCourier New"}, -{" Times New Roman"}, -{"BTimes New Roman"}, -{"ITimes New Roman"}, -{"PTimes New Roman"}, -{" Symbol"}, -{" Terminal"}, -{"BTerminal"}, -{" Wingdings"}, -}; - -Fl_Fontdesc* fl_fonts = built_in_table; - -static Fl_GDI_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size, int angle) { - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_GDI_Font_Descriptor* f; - for (f = (Fl_GDI_Font_Descriptor*)s->first; f; f = (Fl_GDI_Font_Descriptor*)f->next) - if (f->size == size && f->angle == angle) return f; - f = new Fl_GDI_Font_Descriptor(s->name, size); - f->next = s->first; - s->first = f; - return f; -} - -//////////////////////////////////////////////////////////////// -// Public interface: - -static void fl_font(Fl_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) { - if (fnum==-1) { // just make sure that we will load a new font next time - fl_angle_ = 0; - driver->Fl_Graphics_Driver::font(0, 0); - return; - } - if (fnum == driver->Fl_Graphics_Driver::font() && size == ((Fl_GDI_Graphics_Driver*)driver)->size_unscaled() && angle == fl_angle_) return; - fl_angle_ = angle; - driver->Fl_Graphics_Driver::font(fnum, size); - driver->font_descriptor( find(fnum, size, angle) ); -} - -void Fl_GDI_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { - fl_font(this, fnum, size, 0); -} - -int Fl_GDI_Graphics_Driver::height_unscaled() { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent); - else return -1; -} - -int Fl_GDI_Graphics_Driver::descent_unscaled() { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (fl_fontsize) return fl_fontsize->metr.tmDescent; - else return -1; -} - -Fl_Fontsize Fl_GDI_Graphics_Driver::size_unscaled() { - if (font_descriptor()) return size_; - return -1; -} - -double Fl_GDI_Graphics_Driver::width_unscaled(const char* c, int n) { - if (n == 0) return 0; - int len1 = fl_utf8len1(*c); - if (n > len1 && len1 > 0) { // a text with several codepoints: compute its typographical width - int wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - if (wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - } - HDC gc2 = gc_; - HWND hWnd; - if (!gc2) { - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - SelectObject(gc2, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - SIZE s; - GetTextExtentPoint32W(gc2, (WCHAR*)wstr, wn, &s); - if (gc2 && gc2 != gc_) ReleaseDC(hWnd, gc2); - return (double)s.cx; - } - int i = 0; - if (!font_descriptor()) return -1.0; - double w = 0.0; - char *end = (char *)&c[n]; - while (i < n) { - unsigned int ucs; - int l; - ucs = fl_utf8decode((const char*)(c + i), end, &l); -// if (l < 1) l = 1; - i += l; - if (!fl_nonspacing(ucs)) { - w += width_unscaled(ucs); - } - } - return w; -} - -double Fl_GDI_Graphics_Driver::width_unscaled(unsigned int c) { - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - unsigned int r; - SIZE s; - // Special Case Handling of Unicode points over U+FFFF. - // The logic (below) computes a lookup table for char widths - // on-the-fly, but the table only covers codepoints up to - // U+FFFF, which covers the basic multilingual plane, but - // not any higher plane, or glyphs that require surrogate-pairs - // to encode them in WinXX, which is UTF16. - // This code assumes that these glyphs are rarely used and simply - // measures them explicitly if they occur - This will be slow... - if(c > 0x0000FFFF) { // UTF16 surrogate pair is needed - if (!gc_) { // We have no valid gc, so nothing to measure - bail out - return 0.0; - } - int cc; // cell count - unsigned short u16[4]; // Array for UTF16 representation of c - // Creates a UTF16 string from a UCS code point. - cc = fl_ucs_to_Utf16(c, u16, 4); - // Make sure the current font is selected before we make the measurement - SelectObject(gc_, fl_fontsize->fid); - // measure the glyph width - GetTextExtentPoint32W(gc_, (WCHAR*)u16, cc, &s); - return (double)s.cx; - } - // else - this falls through to the lookup-table for glyph widths - // in the basic multilingual plane - r = (c & 0xFC00) >> 10; - if (!fl_fontsize->width[r]) { - fl_fontsize->width[r] = (int*) malloc(sizeof(int) * 0x0400); - for (int i = 0; i < 0x0400; i++) fl_fontsize->width[r][i] = -1; - } else { - if ( fl_fontsize->width[r][c&0x03FF] >= 0 ) { // already cached - return (double) fl_fontsize->width[r][c & 0x03FF]; - } - } - unsigned short ii = r * 0x400; - // The following code makes a best effort attempt to obtain a valid fl_gc. - // If no fl_gc is available at the time we call fl_width(), then we first - // try to obtain a gc from the first fltk window. - // If that is null then we attempt to obtain the gc from the current screen - // using (GetDC(NULL)). - // This should resolve STR #2086 - HDC gc2 = gc_; - HWND hWnd = 0; - if (!gc2) { // We have no valid gc, try and obtain one - // Use our first fltk window, or fallback to using the screen via GetDC(NULL) - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - if (!gc2) Fl::fatal("Invalid graphic context: fl_width() failed because no valid HDC was found!"); - SelectObject(gc2, fl_fontsize->fid); - ii += c &0x03FF; - GetTextExtentPoint32W(gc2, (WCHAR*)&ii, 1, &s); - fl_fontsize->width[r][c&0x03FF] = s.cx; - if (gc2 && gc2 != gc_) ReleaseDC(hWnd, gc2); - return (double) fl_fontsize->width[r][c & 0x03FF]; -} - -/* Add function pointer to allow us to access GetGlyphIndicesW on systems that have it, - * without crashing on systems that do not. */ -/* DWORD WINAPI GetGlyphIndicesW(HDC,LPCWSTR,int,LPWORD,DWORD) */ -typedef DWORD (WINAPI* fl_GetGlyphIndices_func)(HDC,LPCWSTR,int,LPWORD,DWORD); - -static fl_GetGlyphIndices_func fl_GetGlyphIndices = NULL; // used to hold a proc pointer for GetGlyphIndicesW -static int have_loaded_GetGlyphIndices = 0; // Set this non-zero once we have tried to load GetGlyphIndices - -// Function that tries to dynamically load GetGlyphIndicesW at runtime -static void GetGlyphIndices_init() { - // Since not all versions of Windows include GetGlyphIndicesW support, - // we do a run-time check for the required function. - HMODULE hMod = GetModuleHandle("GDI32.DLL"); - if (hMod) { - // check that GetGlyphIndicesW is available - fl_GetGlyphIndices = (fl_GetGlyphIndices_func)GetProcAddress(hMod, "GetGlyphIndicesW"); - } - have_loaded_GetGlyphIndices = -1; // set this non-zero when we have attempted to load GetGlyphIndicesW -} // GetGlyphIndices_init function - -static void on_printer_extents_update(int &dx, int &dy, int &w, int &h, HDC gc) -// converts text extents from device coords to logical coords -{ - POINT pt[3] = { {0, 0}, {dx, dy}, {dx+w, dy+h} }; - DPtoLP(gc, pt, 3); - w = pt[2].x - pt[1].x; - h = pt[2].y - pt[1].y; - dx = pt[1].x - pt[0].x; - dy = pt[1].y - pt[0].y; -} - -// if printer context, extents shd be converted to logical coords -#define EXTENTS_UPDATE(x,y,w,h,gc) \ - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { \ - on_printer_extents_update(x,y,w,h,gc); \ - } - -// Function to determine the extent of the "inked" area of the glyphs in a string -void Fl_GDI_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) { - - Fl_GDI_Font_Descriptor *fl_fontsize = (Fl_GDI_Font_Descriptor*)font_descriptor(); - if (!fl_fontsize) { // no valid font, nothing to measure - w = 0; h = 0; - dx = dy = 0; - return; - } - - static unsigned short *ext_buff = NULL; // UTF-16 converted version of input UTF-8 string - static WORD *w_buff = NULL; // glyph indices array - static unsigned wc_len = 0; // current string buffer dimensions - static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; // identity mat for GetGlyphOutlineW - GLYPHMETRICS metrics; - int maxw = 0, maxh = 0, dh; - int minx = 0, miny = -999999; - unsigned len = 0, idx = 0; - HWND hWnd = 0; - HDC gc2 = gc_; // local copy of current gc - make a copy in case we change it... - int has_surrogates; // will be set if the string contains surrogate pairs - - // Have we loaded the GetGlyphIndicesW function yet? - if (have_loaded_GetGlyphIndices == 0) { - GetGlyphIndices_init(); - } - // Do we have a usable GetGlyphIndices function? - if(!fl_GetGlyphIndices) goto exit_error; // No GetGlyphIndices function, use fallback mechanism instead - - // The following code makes a best effort attempt to obtain a valid fl_gc. - // See description in fl_width() above for an explanation. - if (!gc2) { // We have no valid gc, try and obtain one - // Use our first fltk window, or fallback to using the screen via GetDC(NULL) - hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; - gc2 = GetDC(hWnd); - } - if (!gc2) goto exit_error; // no valid gc, attempt to use fallback measure - - // now convert the string to WCHAR and measure it - len = fl_utf8toUtf16(c, n, ext_buff, wc_len); - if(len >= wc_len) { - if(ext_buff) {delete [] ext_buff;} - if(w_buff) {delete [] w_buff;} - wc_len = len + 64; - ext_buff = new unsigned short[wc_len]; - w_buff = new WORD[wc_len]; - len = fl_utf8toUtf16(c, n, ext_buff, wc_len); - } - SelectObject(gc2, fl_fontsize->fid); - - // Are there surrogate-pairs in this string? If so GetGlyphIndicesW will fail - // since it can only handle the BMP range. - // We ideally want to use GetGlyphIndicesW, as it is the Right Thing, but it - // only works for the BMP, so we leverage GetCharacterPlacementW instead, which - // is not ideal, but works adequately well, and does handle surrogate pairs. - has_surrogates = 0; - for(unsigned ll = 0; ll < len; ll++) { - if((ext_buff[ll] >= 0xD800) && (ext_buff[ll] < 0xE000)) { - has_surrogates = -1; - break; - } - } - if (has_surrogates) { - // GetGlyphIndices will not work - use GetCharacterPlacementW() instead - GCP_RESULTSW gcp_res; - memset(w_buff, 0, (sizeof(WORD) * wc_len)); - memset(&gcp_res, 0, sizeof(GCP_RESULTSW)); - gcp_res.lpGlyphs = (LPWSTR)w_buff; - gcp_res.nGlyphs = wc_len; - gcp_res.lStructSize = sizeof(gcp_res); - - DWORD dr = GetCharacterPlacementW(gc2, (WCHAR*)ext_buff, len, 0, &gcp_res, GCP_GLYPHSHAPE); - if(dr) { - len = gcp_res.nGlyphs; - } else goto exit_error; - } else { - if (fl_GetGlyphIndices(gc_, (WCHAR*)ext_buff, len, w_buff, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) { - // some error occurred here - just return fl_measure values - goto exit_error; - } - } - - // now we have the glyph array we measure each glyph in turn... - for(idx = 0; idx < len; idx++){ - if (GetGlyphOutlineW (gc2, w_buff[idx], GGO_METRICS | GGO_GLYPH_INDEX, - &metrics, 0, NULL, &matrix) == GDI_ERROR) { - goto exit_error; - } - maxw += metrics.gmCellIncX; - if(idx == 0) minx = metrics.gmptGlyphOrigin.x; - dh = metrics.gmBlackBoxY - metrics.gmptGlyphOrigin.y; - if(dh > maxh) maxh = dh; - if(miny < metrics.gmptGlyphOrigin.y) miny = metrics.gmptGlyphOrigin.y; - } - // for the last cell, we only want the bounding X-extent, not the glyphs increment step - maxw = maxw - metrics.gmCellIncX + metrics.gmBlackBoxX + metrics.gmptGlyphOrigin.x; - w = maxw - minx; - h = maxh + miny; - dx = minx; - dy = -miny; - EXTENTS_UPDATE(dx, dy, w, h, gc_); - return; // normal exit - -exit_error: - // some error here - just return fl_measure values - w = (int)width(c, n); - h = height_unscaled(); - dx = 0; - dy = descent_unscaled() - h; - EXTENTS_UPDATE(dx, dy, w, h, gc_); - return; -} // fl_text_extents - -void Fl_GDI_Graphics_Driver::draw_unscaled(const char* str, int n, int x, int y) { - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - // avoid crash if no font has been set yet - if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - int wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - if(wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - } - TextOutW(gc_, x, y, (WCHAR*)wstr, wn); - SetTextColor(gc_, oldColor); // restore initial state -} - -void Fl_GDI_Graphics_Driver::draw_unscaled(int angle, const char* str, int n, int x, int y) { - fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), angle); - int wn = 0; // count of UTF16 cells to render full string - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); - if(wn >= wstr_len) { // Array too small - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(str, n, wstr, wstr_len); // respin the translation - } - TextOutW(gc_, x, y, (WCHAR*)wstr, wn); - SetTextColor(gc_, oldColor); - fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), 0); -} - -void Fl_GDI_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) { - int wn; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - if(wn >= wstr_len) { - wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); - wstr_len = wn + 1; - wn = fl_utf8toUtf16(c, n, wstr, wstr_len); - } - - COLORREF oldColor = SetTextColor(gc_, fl_RGB()); - SelectObject(gc_, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); -#ifdef RTL_CHAR_BY_CHAR - int i = 0; - int lx = 0; - while (i < wn) { // output char by char is very bad for Arabic but coherent with fl_width() - lx = (int) width(wstr[i]); - x -= lx; - TextOutW(gc_, x, y, (WCHAR*)wstr + i, 1); - if (fl_nonspacing(wstr[i])) { - x += lx; - } - i++; - } -#else - UINT old_align = SetTextAlign(gc_, TA_RIGHT | TA_RTLREADING); - TextOutW(gc_, x, y - height_unscaled() + descent_unscaled(), (WCHAR*)wstr, wn); - SetTextAlign(gc_, old_align); -#endif - SetTextColor(gc_, oldColor); -} -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx deleted file mode 100644 index 3a8e70689..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ /dev/null @@ -1,826 +0,0 @@ -// -// Windows image drawing code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// I hope a simple and portable method of drawing color and monochrome -// images. To keep this simple, only a single storage type is -// supported: 8 bit unsigned data, byte order RGB, and pixels are -// stored packed into rows with the origin at the top-left. It is -// possible to alter the size of pixels with the "delta" argument, to -// add alpha or other information per pixel. It is also possible to -// change the origin and direction of the image data by messing with -// the "delta" and "linedelta", making them negative, though this may -// defeat some of the shortcuts in translating the image for X. - -// Unbelievably (since it conflicts with how most PC software works) -// Micro$oft picked a bottom-up and BGR storage format for their -// DIB images. I'm pretty certain there is a way around this, but -// I can't find any other than the brute-force method of drawing -// each line as a separate image. This may also need to be done -// if the delta is any amount other than 1, 3, or 4. - -//////////////////////////////////////////////////////////////// - -#include <config.h> -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_System_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> - -#define MAXBUFFER 0x40000 // 256k - -void fl_release_dc(HWND, HDC); // from Fl_win32.cxx - -#if USE_COLORMAP - -// error-diffusion dither into the FLTK colormap -static void dither(uchar* to, const uchar* from, int w, int delta) { - static int ri, gi, bi, dir; - int r=ri, g=gi, b=bi; - int d, td; - if (dir) { - dir = 0; - from = from+(w-1)*delta; - to = to+(w-1); - d = -delta; - td = -1; - } else { - dir = 1; - d = delta; - td = 1; - } - for (; w--; from += d, to += td) { - r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; - int rr = r*FL_NUM_RED/256; - r -= rr*255/(FL_NUM_RED-1); - g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; - int gg = g*FL_NUM_GREEN/256; - g -= gg*255/(FL_NUM_GREEN-1); - b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; - int bb = b*FL_NUM_BLUE/256; - b -= bb*255/(FL_NUM_BLUE-1); - *to = uchar(FL_COLOR_CUBE+(bb*FL_NUM_RED+rr)*FL_NUM_GREEN+gg); - } - ri = r; gi = g; bi = b; -} - -// error-diffusion dither into the FLTK colormap -static void monodither(uchar* to, const uchar* from, int w, int delta) { - static int ri,dir; - int r=ri; - int d, td; - if (dir) { - dir = 0; - from = from+(w-1)*delta; - to = to+(w-1); - d = -delta; - td = -1; - } else { - dir = 1; - d = delta; - td = 1; - } - for (; w--; from += d, to += td) { - r += *from; if (r < 0) r = 0; else if (r>255) r = 255; - int rr = r*FL_NUM_GRAY/256; - r -= rr*255/(FL_NUM_GRAY-1); - *to = uchar(FL_GRAY_RAMP+rr); - } - ri = r; -} - -#endif // USE_COLORMAP - -static int fl_abs(int v) { return v<0 ? -v : v; } - -static void innards(const uchar *buf, int X, int Y, int W, int H, - int delta, int linedelta, int depth, - Fl_Draw_Image_Cb cb, void* userdata, HDC gc) -{ - char indexed = 0; - -#if USE_COLORMAP - indexed = (fl_palette != 0); -#endif - - if (depth==0) depth = 3; - if (indexed || !fl_can_do_alpha_blending()) - depth = (depth-1)|1; - - if (!linedelta) linedelta = W*fl_abs(delta); - - int x = 0, y = 0, w = 0, h = 0; - fl_clip_box(X, Y, W, H, x, y, w, h); - if (w<=0 || h<=0) return; - if (buf) buf += (x-X)*delta + (y-Y)*linedelta; - - // bmibuffer: BITMAPINFOHEADER + 256 colors (RGBQUAD) + 1 (rounding effects ?) - static U32 bmibuffer[sizeof(BITMAPINFOHEADER)/4 + 257]; - BITMAPINFO *bmi = (BITMAPINFO*)bmibuffer; - if (!bmi->bmiHeader.biSize) { - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biCompression = BI_RGB; - bmi->bmiHeader.biXPelsPerMeter = 0; - bmi->bmiHeader.biYPelsPerMeter = 0; - bmi->bmiHeader.biClrUsed = 0; - bmi->bmiHeader.biClrImportant = 0; - } -#if USE_COLORMAP - if (indexed) { - for (short i=0; i<256; i++) { - *((short*)(bmi->bmiColors)+i) = i; - } - } else -#endif - if (depth<3) { - RGBQUAD *bmi_colors = &(bmi->bmiColors[0]); // use pointer to suppress warning (STR #3199) - for (int i=0; i<256; i++) { - bmi_colors[i].rgbBlue = (uchar)i; // = bmi->bmiColors[i] - bmi_colors[i].rgbGreen = (uchar)i; - bmi_colors[i].rgbRed = (uchar)i; - bmi_colors[i].rgbReserved = (uchar)0; // must be zero - } - } - bmi->bmiHeader.biWidth = w; -#if USE_COLORMAP - bmi->bmiHeader.biBitCount = indexed ? 8 : depth*8; - int pixelsize = indexed ? 1 : depth; -#else - bmi->bmiHeader.biBitCount = depth*8; - int pixelsize = depth; -#endif - if (depth==2) { // special case: gray with alpha - bmi->bmiHeader.biBitCount = 32; - pixelsize = 4; - } - int linesize = (pixelsize*w+3)&~3; - - static U32* buffer; - static long buffer_size; - int blocking = h; - { - int size = linesize * h; - // when printing, don't limit buffer size not to get a crash in StretchDIBits - if (size > MAXBUFFER && !fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { - size = MAXBUFFER; - blocking = MAXBUFFER / linesize; - } - if (size > buffer_size) { - delete[] buffer; - buffer_size = size; - buffer = new U32[(size + 3) / 4]; - } - } - bmi->bmiHeader.biHeight = blocking; - static U32* line_buffer; - if (!buf) { - int size = W*delta; - static int line_buf_size; - if (size > line_buf_size) { - delete[] line_buffer; - line_buf_size = size; - line_buffer = new U32[(size+3)/4]; - } - } - for (int j=0; j<h; ) { - int k; - for (k = 0; j<h && k<blocking; k++, j++) { - const uchar* from; - if (!buf) { // run the converter: - cb(userdata, x-X, y-Y+j, w, (uchar*)line_buffer); - from = (uchar*)line_buffer; - } else { - from = buf; - buf += linedelta; - } - uchar *to = (uchar*)buffer+(blocking-k-1)*linesize; -#if USE_COLORMAP - if (indexed) { - if (depth<3) - monodither(to, from, w, delta); - else - dither(to, from, w, delta); - } else -#endif - { - int i; - switch (depth) { - case 1: - for (i=w; i--; from += delta) *to++ = *from; - break; - case 2: - for (i=w; i--; from += delta, to += 4) { - uchar a = from[1]; - uchar gray = (from[0]*a)>>8; - to[0] = gray; - to[1] = gray; - to[2] = gray; - to[3] = a; - } - break; - case 3: - for (i=w; i--; from += delta, to += 3) { - uchar r = from[0]; - to[0] = from[2]; - to[1] = from[1]; - to[2] = r; - } - break; - case 4: - for (i=w; i--; from += delta, to += 4) { - uchar a = from[3]; - uchar r = from[0]; - to[0] = (from[2]*a)>>8; - to[1] = (from[1]*a)>>8; - to[2] = (r*a)>>8; - to[3] = from[3]; - } - break; - } - } - } // for (k = 0; j<h && k<blocking ...) - - if (fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { - // if print context, device and logical units are not equal, so SetDIBitsToDevice - // does not do the expected job, whereas StretchDIBits does it. - StretchDIBits(gc, x, y+j-k, w, k, 0, 0, w, k, - (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - bmi, -#if USE_COLORMAP - indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS -#else - DIB_RGB_COLORS -#endif - , SRCCOPY ); - delete[] buffer; - buffer = NULL; - buffer_size = 0; - } - else { - SetDIBitsToDevice(gc, x, y+j-k, w, k, 0, 0, 0, k, - (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - bmi, -#if USE_COLORMAP - indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS -#else - DIB_RGB_COLORS -#endif - ); - } - } // for (int j=0; j<h; ) -} - -void Fl_GDI_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,fl_abs(d),0,0, gc_); - } else { - innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data, gc_); - } else { - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,1,0,0, gc_); - } else { - innards(buf,x,y,w,h,d,l,1,0,0, gc_); - } -} - -void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { - d ^= FL_IMAGE_WITH_ALPHA; - innards(0,x,y,w,h,d,0,1,cb,data, gc_); - } else { - innards(0,x,y,w,h,d,0,1,cb,data, gc_); - } -} - -#if USE_COLORMAP -void Fl_GDI_Graphics_Driver::colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { - // use the error diffusion dithering code to produce a much nicer block: - if (fl_palette) { - uchar c[3]; - c[0] = r; c[1] = g; c[2] = b; - innards(c, floor(x), floor(y), floor(x + w) - floor(x), floor(y + h) - floor(y), - 0,0,0,0,0, (HDC)gc()); - return; - } - Fl_Graphics_Driver::colored_rectf(x, y, w, h, r, g, b); -} -#endif - -// Create an N-bit bitmap for masking... -HBITMAP Fl_GDI_Graphics_Driver::create_bitmask(int w, int h, const uchar *data) { - // this won't work when the user changes display mode during run or - // has two screens with different depths - HBITMAP bm; - static uchar hiNibble[16] = - { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 }; - static uchar loNibble[16] = - { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, - 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f }; - HDC current_gc = (HDC)Fl_Surface_Device::surface()->driver()->gc(); - int np = GetDeviceCaps(current_gc, PLANES); //: was always one on sample machines - int bpp = GetDeviceCaps(current_gc, BITSPIXEL);//: 1,4,8,16,24,32 and more odd stuff? - int Bpr = (bpp*w+7)/8; //: bytes per row - int pad = Bpr&1, w1 = (w+7)/8, shr = ((w-1)&7)+1; - if (bpp==4) shr = (shr+1)/2; - uchar *newarray = new uchar[(Bpr+pad)*h]; - uchar *dst = newarray; - const uchar *src = data; - - for (int i=0; i<h; i++) { - // This is slooow, but we do it only once per pixmap - for (int j=w1; j>0; j--) { - uchar b = *src++; - if (bpp==1) { - *dst++ = (uchar)( hiNibble[b&15] ) | ( loNibble[(b>>4)&15] ); - } else if (bpp==4) { - for (int k=(j==1)?shr:4; k>0; k--) { - *dst++ = (uchar)("\377\360\017\000"[b&3]); - b = b >> 2; - } - } else { - for (int k=(j==1)?shr:8; k>0; k--) { - if (b&1) { - *dst++=0; - if (bpp>8) *dst++=0; - if (bpp>16) *dst++=0; - if (bpp>24) *dst++=0; - } else { - *dst++=0xff; - if (bpp>8) *dst++=0xff; - if (bpp>16) *dst++=0xff; - if (bpp>24) *dst++=0xff; - } - - b = b >> 1; - } - } - } - - dst += pad; - } - - bm = CreateBitmap(w, h, np, bpp, newarray); - delete[] newarray; - - return bm; -} - -void Fl_GDI_Graphics_Driver::delete_bitmask(fl_uintptr_t bm) { - DeleteObject((HGDIOBJ)bm); -} - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(bm, W, H); - cx = this->floor(cx); cy = this->floor(cy); - - HDC tempdc = CreateCompatibleDC(gc_); - int save = SaveDC(tempdc); - SelectObject(tempdc, (HGDIOBJ)*Fl_Graphics_Driver::id(bm)); - SelectObject(gc_, fl_brush()); - // secret bitblt code found in old Windows reference manual: - BitBlt(gc_, X, Y, W, H, tempdc, cx, cy, 0xE20746L); - RestoreDC(tempdc, save); - DeleteDC(tempdc); -} - -Fl_GDI_Printer_Graphics_Driver::transparent_f_type Fl_GDI_Printer_Graphics_Driver::TransparentBlt() { - HMODULE hMod; - static transparent_f_type fpter = ( (hMod = LoadLibrary("MSIMG32.DLL")) ? - (transparent_f_type)GetProcAddress(hMod, "TransparentBlt") : NULL - ); - return fpter; -} - -void Fl_GDI_Printer_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (Fl_Graphics_Driver::start_image(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - transparent_f_type fl_TransparentBlt = TransparentBlt(); - if (!fl_TransparentBlt) { - Fl_Graphics_Driver::draw_bitmap(bm, X, Y, W, H, cx, cy); - return; - } - bool recache = false; - if (*id(bm)) { - int *pw, *ph; - cache_w_h(bm, pw, ph); - recache = (*pw != bm->data_w() || *ph != bm->data_h()); - } - if (recache || !*id(bm)) { - bm->uncache(); - cache(bm); - } - HDC tempdc; - int save; - // algorithm for bitmap output to Fl_GDI_Printer - Fl_Color save_c = fl_color(); // save bitmap's desired color - uchar r, g, b; - Fl::get_color(save_c, r, g, b); - r = 255-r; - g = 255-g; - b = 255-b; - Fl_Color background = fl_rgb_color(r, g, b); // a color very different from the bitmap's - Fl_Image_Surface *img_surf = new Fl_Image_Surface(bm->data_w(), bm->data_h()); - Fl_Surface_Device::push_current(img_surf); - fl_color(background); - fl_rectf(0,0, bm->data_w(), bm->data_h()); // use this color as offscreen background - fl_color(save_c); // back to bitmap's color - HDC off_gc = (HDC)fl_graphics_driver->gc(); - tempdc = CreateCompatibleDC(off_gc); - save = SaveDC(tempdc); - SelectObject(tempdc, (HGDIOBJ)*Fl_Graphics_Driver::id(bm)); - SelectObject(off_gc, fl_brush()); // use bitmap's desired color - BitBlt(off_gc, 0, 0, bm->data_w(), bm->data_h(), tempdc, 0, 0, 0xE20746L); // draw bitmap to offscreen - Fl_Surface_Device::pop_current(); - SelectObject(tempdc, (HGDIOBJ)img_surf->offscreen()); // use offscreen data - // draw it to printer context with background color as transparent - float scaleW = bm->data_w()/float(bm->w()); - float scaleH = bm->data_h()/float(bm->h()); - fl_TransparentBlt(gc_, X, Y, W, H, tempdc, - int(cx * scaleW), int(cy * scaleH), int(W * scaleW), int(H * scaleH), RGB(r, g, b) ); - delete img_surf; - RestoreDC(tempdc, save); - DeleteDC(tempdc); - if (recache) bm->uncache(); -} - - -// Create a 1-bit mask used for alpha blending -HBITMAP Fl_GDI_Graphics_Driver::create_alphamask(int w, int h, int d, int ld, const uchar *array) { - HBITMAP bm; - int bmw = (w + 7) / 8; - uchar *bitmap = new uchar[bmw * h]; - uchar *bitptr, bit; - const uchar *dataptr; - int x, y; - static uchar dither[16][16] = { // Simple 16x16 Floyd dither - { 0, 128, 32, 160, 8, 136, 40, 168, - 2, 130, 34, 162, 10, 138, 42, 170 }, - { 192, 64, 224, 96, 200, 72, 232, 104, - 194, 66, 226, 98, 202, 74, 234, 106 }, - { 48, 176, 16, 144, 56, 184, 24, 152, - 50, 178, 18, 146, 58, 186, 26, 154 }, - { 240, 112, 208, 80, 248, 120, 216, 88, - 242, 114, 210, 82, 250, 122, 218, 90 }, - { 12, 140, 44, 172, 4, 132, 36, 164, - 14, 142, 46, 174, 6, 134, 38, 166 }, - { 204, 76, 236, 108, 196, 68, 228, 100, - 206, 78, 238, 110, 198, 70, 230, 102 }, - { 60, 188, 28, 156, 52, 180, 20, 148, - 62, 190, 30, 158, 54, 182, 22, 150 }, - { 252, 124, 220, 92, 244, 116, 212, 84, - 254, 126, 222, 94, 246, 118, 214, 86 }, - { 3, 131, 35, 163, 11, 139, 43, 171, - 1, 129, 33, 161, 9, 137, 41, 169 }, - { 195, 67, 227, 99, 203, 75, 235, 107, - 193, 65, 225, 97, 201, 73, 233, 105 }, - { 51, 179, 19, 147, 59, 187, 27, 155, - 49, 177, 17, 145, 57, 185, 25, 153 }, - { 243, 115, 211, 83, 251, 123, 219, 91, - 241, 113, 209, 81, 249, 121, 217, 89 }, - { 15, 143, 47, 175, 7, 135, 39, 167, - 13, 141, 45, 173, 5, 133, 37, 165 }, - { 207, 79, 239, 111, 199, 71, 231, 103, - 205, 77, 237, 109, 197, 69, 229, 101 }, - { 63, 191, 31, 159, 55, 183, 23, 151, - 61, 189, 29, 157, 53, 181, 21, 149 }, - { 254, 127, 223, 95, 247, 119, 215, 87, - 253, 125, 221, 93, 245, 117, 213, 85 } - }; - - // Generate a 1-bit "screen door" alpha mask; not always pretty, but - // definitely fast... In the future we may be able to support things - // like the RENDER extension in XFree86, when available, to provide - // true RGBA-blended rendering. See: - // - // http://www.xfree86.org/~keithp/render/protocol.html - // - // for more info on XRender... - // - memset(bitmap, 0, bmw * h); - - for (dataptr = array + d - 1, y = 0; y < h; y ++, dataptr += ld) - for (bitptr = bitmap + y * bmw, bit = 1, x = 0; x < w; x ++, dataptr += d) { - if (*dataptr > dither[x & 15][y & 15]) - *bitptr |= bit; - if (bit < 128) bit <<= 1; - else { - bit = 1; - bitptr ++; - } - } - - bm = create_bitmask(w, h, bitmap); - delete[] bitmap; - - return bm; -} - - -void Fl_GDI_Graphics_Driver::cache(Fl_RGB_Image *img) -{ - Fl_Image_Surface *surface = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surface); - if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { - fl_draw_image(img->array, 0, 0, img->data_w(), img->data_h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); - } else { - fl_draw_image(img->array, 0, 0, img->data_w(), img->data_h(), img->d(), img->ld()); - if (img->d() == 2 || img->d() == 4) { - *Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)create_alphamask(img->data_w(), img->data_h(), img->d(), img->ld(), img->array); - } - } - Fl_Surface_Device::pop_current(); - Fl_Offscreen offs = Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surface); - int *pw, *ph; - cache_w_h(img, pw, ph); - *pw = img->data_w(); - *ph = img->data_h(); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)offs; -} - - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(img, W, H); - cx = this->floor(cx); cy = this->floor(cy); - if (W + cx > img->data_w()) W = img->data_w() - cx; - if (H + cy > img->data_h()) H = img->data_h() - cy; - if (!*Fl_Graphics_Driver::id(img)) { - cache(img); - } - if (*Fl_Graphics_Driver::mask(img)) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::mask(img)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(img)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else if (img->d()==2 || img->d()==4) { - copy_offscreen_with_alpha(X, Y, W, H, (HBITMAP)*Fl_Graphics_Driver::id(img), cx, cy); - } else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(img), cx, cy); - } -} - - -void Fl_GDI_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) { - if (Fl_Graphics_Driver::start_image(rgb, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { - return; - } - if ((rgb->d() % 2) == 0 && !fl_can_do_alpha_blending()) { - Fl_Graphics_Driver::draw_rgb(rgb, XP, YP, WP, HP, cx, cy); - return; - } - if (!*Fl_Graphics_Driver::id(rgb)) { - cache(rgb); - } - push_clip(XP, YP, WP, HP); - XP -= cx; YP -= cy; - WP = rgb->w(); HP = rgb->h(); - cache_size(rgb, WP, HP); - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); - if ( (rgb->d() % 2) == 0 ) { - alpha_blend_(this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h()); - } else { - SetStretchBltMode(gc_, (Fl_Image::scaling_algorithm() == FL_RGB_SCALING_BILINEAR ? HALFTONE : BLACKONWHITE)); - StretchBlt(gc_, this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h(), SRCCOPY); - } - RestoreDC(new_gc, save); - DeleteDC(new_gc); - pop_clip(); -} - - -void Fl_GDI_Printer_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int HP, int cx, int cy) { - if (Fl_Graphics_Driver::start_image(rgb, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { - return; - } - XFORM old_tr, tr; - GetWorldTransform(gc_, &old_tr); // storing old transform - tr.eM11 = float(rgb->w())/float(rgb->data_w()); - tr.eM22 = float(rgb->h())/float(rgb->data_h()); - tr.eM12 = tr.eM21 = 0; - tr.eDx = float(XP); - tr.eDy = float(YP); - ModifyWorldTransform(gc_, &tr, MWT_LEFTMULTIPLY); - if (*id(rgb)) { - int *pw, *ph; - cache_w_h(rgb, pw, ph); - if ( *pw != rgb->data_w() || *ph != rgb->data_h()) rgb->uncache(); - } - if (!*id(rgb)) cache(rgb); - draw_fixed(rgb, 0, 0, int(WP / tr.eM11), int(HP / tr.eM22), int(cx / tr.eM11), int(cy / tr.eM22)); - SetWorldTransform(gc_, &old_tr); -} - - -void Fl_GDI_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) -{ - if (id_) { - DeleteObject((HBITMAP)id_); - id_ = 0; - } - - if (mask_) { - delete_bitmask(mask_); - mask_ = 0; - } -} - -// 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing... -static HBITMAP fl_create_bitmap(int w, int h, const uchar *data) { - // we need to pad the lines out to words & swap the bits - // in each byte. - int w1 = (w + 7) / 8; - int w2 = ((w + 15) / 16) * 2; - uchar* newarray = new uchar[w2*h]; - const uchar* src = data; - uchar* dest = newarray; - HBITMAP bm; - static uchar reverse[16] = /* Bit reversal lookup table */ - { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, - 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; - - for (int y = 0; y < h; y++) { - for (int n = 0; n < w1; n++, src++) - *dest++ = (uchar)((reverse[*src & 0x0f] & 0xf0) | - (reverse[(*src >> 4) & 0x0f] & 0x0f)); - dest += w2 - w1; - } - - bm = CreateBitmap(w, h, 1, 1, newarray); - - delete[] newarray; - - return bm; -} - -void Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm) { - int *pw, *ph; - cache_w_h(bm, pw, ph); - *pw = bm->data_w(); - *ph = bm->data_h(); - *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)fl_create_bitmap(bm->data_w(), bm->data_h(), bm->array); -} - -void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) { - X = this->floor(X); - Y = this->floor(Y); - cache_size(pxm, W, H); - cx = this->floor(cx); cy = this->floor(cy); - Fl_Region r2 = scale_clip(scale()); - if (*Fl_Graphics_Driver::mask(pxm)) { - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::mask(pxm)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(pxm)); - BitBlt(gc_, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else { - float s = scale(); Fl_Graphics_Driver::scale(1); - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy); - Fl_Graphics_Driver::scale(s); - } - unscale_clip(r2); -} - -/* ===== Implementation note about how Fl_Pixmap objects get printed under Windows ===== - Fl_Pixmap objects are printed with the print-specific Fl_GDI_Printer_Graphics_Driver - which uses the TransparentBlt() system function that can scale the image and treat one - of its colors as transparent. - Fl_GDI_Printer_Graphics_Driver::draw_pixmap(Fl_Pixmap *,...) sets need_pixmap_bg_color, - a static class variable, to 1 and recaches the image. This calls fl_convert_pixmap() - that checks the value of need_pixmap_bg_color. When this value is not 0, fl_convert_pixmap - runs in a way that memorizes the list of all colors in the pixmap, computes - a color absent from this list, uses it for the transparent pixels of the pixmap and puts - this color value in need_pixmap_bg_color. As a result, the transparent areas of the image - are correcty handled by the printing operation. Variable need_pixmap_bg_color is ultimately - reset to 0. - Fl_GDI_Graphics_Driver::make_unused_color_() which does the color computation mentioned - above is implemented in file src/fl_draw_pixmap.cxx - */ -void Fl_GDI_Printer_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; - transparent_f_type fl_TransparentBlt = TransparentBlt(); - if (fl_TransparentBlt) { - need_pixmap_bg_color = 1; - pxm->uncache(); - cache(pxm); - HDC new_gc = CreateCompatibleDC(gc_); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)*Fl_Graphics_Driver::id(pxm)); - // print all of offscreen but its parts in background color - float scaleW = pxm->data_w()/float(pxm->w()); - float scaleH = pxm->data_h()/float(pxm->h()); - fl_TransparentBlt(gc_, X, Y, W, H, new_gc, - int(cx * scaleW), int(cy * scaleH), int(W * scaleW), int(H * scaleH), need_pixmap_bg_color ); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - need_pixmap_bg_color = 0; - } - else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy); - } -} - -// Makes an RGB triplet different from all the colors used in the pixmap -// and computes Fl_Graphics_Driver::need_pixmap_bg_color from this triplet -void Fl_GDI_Graphics_Driver::make_unused_color_(uchar &r, uchar &g, uchar &b, int color_count, void **data) { - typedef struct { uchar r; uchar g; uchar b; } UsedColor; - UsedColor *used_colors = *(UsedColor**)data; - int i; - r = 2; g = 3; b = 4; - while (1) { - for ( i=0; i<color_count; i++ ) - if ( used_colors[i].r == r && - used_colors[i].g == g && - used_colors[i].b == b ) - break; - if (i >= color_count) { - free((void*)used_colors); - *(UsedColor**)data = NULL; - need_pixmap_bg_color = RGB(r, g, b); - return; - } - if (r < 255) { - r++; - } else { - r = 0; - if (g < 255) { - g++; - } else { - g = 0; - b++; - } - } - } -} - -void Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img) { - Fl_Image_Surface *surf = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surf); - uchar **pbitmap = surf->driver()->mask_bitmap(); - *pbitmap = (uchar*)1;// will instruct fl_draw_pixmap() to compute the image's mask - fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); - uchar *bitmap = *pbitmap; - if (bitmap) { - *Fl_Graphics_Driver::mask(img) = - (fl_uintptr_t)create_bitmask(img->data_w(), img->data_h(), bitmap); - delete[] bitmap; - } - *pbitmap = 0; - Fl_Surface_Device::pop_current(); - Fl_Offscreen id = Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surf); - int *pw, *ph; - cache_w_h(img, pw, ph); - *pw = img->data_w(); - *ph = img->data_h(); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)id; -} - -void Fl_GDI_Graphics_Driver::uncache_pixmap(fl_uintptr_t offscreen) { - DeleteObject((HBITMAP)offscreen); -} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx deleted file mode 100644 index 9d086f353..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx +++ /dev/null @@ -1,111 +0,0 @@ -// -// Line style code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_line_style.cxx - - \brief Line style drawing utility for Windows (GDI) platform. -*/ - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -#include "Fl_GDI_Graphics_Driver.H" - - -void Fl_GDI_Graphics_Driver::line_style_unscaled(int style, int width, char* dashes) { - - // According to Bill, the "default" cap and join should be the - // "fastest" mode supported for the platform. I don't know why - // they should be different (same graphics cards, etc., right?) MRS - - static const DWORD Cap[4] = {PS_ENDCAP_FLAT, PS_ENDCAP_FLAT, PS_ENDCAP_ROUND, PS_ENDCAP_SQUARE}; - static const DWORD Join[4] = {PS_JOIN_ROUND, PS_JOIN_MITER, PS_JOIN_ROUND, PS_JOIN_BEVEL}; - - int s1 = PS_GEOMETRIC | Cap[(style>>8)&3] | Join[(style>>12)&3]; - DWORD a[16]; - int n = 0; - if (dashes && dashes[0]) { - s1 |= PS_USERSTYLE; - for (n = 0; n < 16 && *dashes; n++) a[n] = *dashes++; - } else { - s1 |= style & 0xff; // allow them to pass any low 8 bits for style - } - if ((style || n) && !width) width = int(scale()); // fix cards that do nothing for 0? - if (!width) width = 1; - if (!fl_current_xmap) color(FL_BLACK); - LOGBRUSH penbrush = {BS_SOLID,fl_RGB(),0}; // can this be fl_brush()? - HPEN newpen = ExtCreatePen(s1, width, &penbrush, n, n ? a : 0); - if (!newpen) { - Fl::error("fl_line_style(): Could not create GDI pen object."); - return; - } - HPEN oldpen = (HPEN)SelectObject(gc_, newpen); - DeleteObject(oldpen); - DeleteObject(fl_current_xmap->pen); - fl_current_xmap->pen = newpen; - style_ = style; -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::line_style(int style, int width, char* dashes) { - if (!active) return Fl_Scalable_Graphics_Driver::line_style(style, width, dashes); - int gdi_width = (width ? width : 1); - pen_->SetWidth(Gdiplus::REAL(gdi_width)); - int standard_dash = style & 0x7; - if (standard_dash == FL_DASH ) - pen_->SetDashStyle(Gdiplus::DashStyleDash); - else if (standard_dash == FL_DOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDot); - else if (standard_dash == FL_DASHDOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDashDot); - else if (standard_dash == FL_DASHDOTDOT ) - pen_->SetDashStyle(Gdiplus::DashStyleDashDotDot); - else if(!dashes || !*dashes) - pen_->SetDashStyle(Gdiplus::DashStyleSolid); - - if (style & FL_CAP_ROUND ) { - pen_->SetStartCap(Gdiplus::LineCapRound); - pen_->SetEndCap(Gdiplus::LineCapRound); - } else if (style & FL_CAP_SQUARE ) { - pen_->SetStartCap(Gdiplus::LineCapSquare); - pen_->SetEndCap(Gdiplus::LineCapSquare); - } else { - pen_->SetStartCap(Gdiplus::LineCapFlat); - pen_->SetEndCap(Gdiplus::LineCapFlat); - } - - if (style & FL_JOIN_MITER ) { - pen_->SetLineJoin(Gdiplus::LineJoinMiter); - } else if (style & FL_JOIN_BEVEL ) { - pen_->SetLineJoin(Gdiplus::LineJoinBevel); - } else { - pen_->SetLineJoin(Gdiplus::LineJoinRound); - } - - if (dashes && *dashes) { - int n = 0; while (dashes[n]) n++; - Gdiplus::REAL *gdi_dashes = new Gdiplus::REAL[n]; - for (int i = 0; i < n; i++) gdi_dashes[i] = dashes[i]/float(gdi_width); - pen_->SetDashPattern(gdi_dashes, n); - delete[] gdi_dashes; - } - Fl_Scalable_Graphics_Driver::line_style(style, width, dashes); -} - -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx deleted file mode 100644 index a86242e12..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx +++ /dev/null @@ -1,320 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -/** - \file Fl_GDI_Graphics_Driver_rect.cxx - \brief Windows GDI specific line and polygon drawing with integer coordinates. - */ - -#include <config.h> -#include <FL/Fl.H> -#include <FL/Fl_Widget.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> - -#include "Fl_GDI_Graphics_Driver.H" - - -// --- line and polygon drawing with integer coordinates - -void Fl_GDI_Graphics_Driver::point(int x, int y) { - rectf(x, y, 1, 1); -} - -void Fl_GDI_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { - // make pen have a one-pixel width - line_style_unscaled( (color()==FL_WHITE?FL_SOLID:FL_DOT), 1, NULL); - int right = this->floor(x+w-1), bottom = this->floor(y+h-1); - x = this->floor(x); y = this->floor(y); - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, right, y); - LineTo(gc_, right, bottom); - LineTo(gc_, x, bottom); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) { - // Windows 95/98/ME do not implement the dotted line style, so draw - // every other pixel around the focus area... - w = floor(x+w-1) - floor(x) + 1; - h = floor(y+h-1) - floor(y) + 1; - x = floor(x); y = floor(y); - int i=1, xx, yy; - COLORREF c = fl_RGB(); - for (xx = 0; xx < w; xx++, i++) if (i & 1) SetPixel(gc_, x+xx, y, c); - for (yy = 0; yy < h; yy++, i++) if (i & 1) SetPixel(gc_, x+w, y+yy, c); - for (xx = w; xx > 0; xx--, i++) if (i & 1) SetPixel(gc_, x+xx, y+h, c); - for (yy = h; yy > 0; yy--, i++) if (i & 1) SetPixel(gc_, x, y+yy, c); -} - -void Fl_GDI_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) { - if (is_solid_ && line_width_ > 1) { - line_style_unscaled(FL_CAP_SQUARE, line_width_, 0); // see issue #1052 - } - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x+w, y); - if (is_solid_ && line_width_ <= 1) LineTo(gc_, x+w, y+h+1); // see issue #1052 - LineTo(gc_, x+w, y+h); - LineTo(gc_, x, y+h); - LineTo(gc_, x, y); - if (is_solid_ && line_width_ > 1) { - line_style_unscaled(style_, line_width_, 0); - } -} - -void Fl_GDI_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) { - RECT rect; - rect.left = x; rect.top = y; - rect.right = (x + w); rect.bottom = (y + h); - FillRect(gc_, &rect, fl_brush()); -} - -void Fl_GDI_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - SetPixel(gc_, x1, y1, fl_RGB()); -} - -void Fl_GDI_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - SetPixel(gc_, x2, y2, fl_RGB()); -} - -void* Fl_GDI_Graphics_Driver::change_pen_width(int width) { // set the width of the pen, return previous pen - LOGBRUSH penbrush = {BS_SOLID, fl_RGB(), 0}; - HPEN newpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_ROUND, width, &penbrush, 0, 0); - return SelectObject(gc_, newpen); -} - -void Fl_GDI_Graphics_Driver::reset_pen_width(void *data) { - DeleteObject(SelectObject(gc_, (HPEN)data)); -} - -void Fl_GDI_Graphics_Driver::xyline_unscaled(int x, int y, int x1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1+1 , y); -} - -void Fl_GDI_Graphics_Driver::yxline_unscaled(int x, int y, int y1) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x, y1+1); -} - -void Fl_GDI_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - MoveToEx(gc_, x, y, 0L); - LineTo(gc_, x1, y1); - LineTo(gc_, x2, y2); - LineTo(gc_, x3, y3); - LineTo(gc_, x, y); -} - -void Fl_GDI_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - POINT p[3]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - SelectObject(gc_, fl_brush()); - Polygon(gc_, p, 3); -} - -void Fl_GDI_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - POINT p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; - SelectObject(gc_, fl_brush()); - Polygon(gc_, p, 4); -} - -// --- clipping - -void Fl_GDI_Graphics_Driver::push_clip(int x, int y, int w, int h) { - HRGN r; - if (w > 0 && h > 0) { - r = (HRGN)XRectangleRegion(x,y,w,h); - HRGN current = (HRGN)rstack[rstackptr]; - if (current) { - CombineRgn(r,r,current,RGN_AND); - } - } else { // make empty clip region: - r = CreateRectRgn(0,0,0,0); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_GDI_Graphics_Driver::push_clip: clip stack overflow!\n"); - fl_restore_clip(); -} - -int Fl_GDI_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - HRGN r = (HRGN)rstack[rstackptr]; - if (!r) return 0; - // The win32 API makes no distinction between partial and complete - // intersection, so we have to check for partial intersection ourselves. - // However, given that the regions may be composite, we have to do - // some voodoo stuff... - HRGN rr = (HRGN)XRectangleRegion(x,y,w,h); - HRGN temp = CreateRectRgn(0,0,0,0); - int ret; - if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint - W = H = 0; - ret = 2; - } else if (EqualRgn(temp, rr)) { // complete - ret = 0; - } else { // partial intersection - RECT rect; - GetRgnBox(temp, &rect); - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // if print context, convert coords from device to logical - POINT pt[2] = { {rect.left, rect.top}, {rect.right, rect.bottom} }; - DPtoLP(gc_, pt, 2); - X = pt[0].x; Y = pt[0].y; W = pt[1].x - X; H = pt[1].y - Y; - } - else { - X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y; - } - ret = 1; - } - DeleteObject(temp); - DeleteObject(rr); - return ret; -} - -int Fl_GDI_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - HRGN r = (HRGN)rstack[rstackptr]; - if (!r) return 1; - RECT rect; - if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // in case of print context, convert coords from logical to device - POINT pt[2] = { {x, y}, {x + w, y + h} }; - LPtoDP(gc_, pt, 2); - rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y; - } else { - rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; - } - return RectInRegion(r,&rect); -} - -void Fl_GDI_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - if (gc_) { - HRGN r = NULL; - if (rstack[rstackptr]) r = (HRGN)scale_clip(scale()); - SelectClipRgn(gc_, (HRGN)rstack[rstackptr]); // if region is NULL, clip is automatically cleared - if (r) unscale_clip(r); - } -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::line(int x, int y, int x1, int y1) { - if (!active) return Fl_Scalable_Graphics_Driver::line(x, y, x1, y1); - bool AA = !(x == x1 || y == y1); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - if (AA) graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawLine(pen_, x, y, x1, y1); -} - -void Fl_GDIplus_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::line(x, y, x1, y1, x2, y2); - line(x, y, x1, y1); - line(x1, y1, x2, y2); -} - -void Fl_GDIplus_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2); - Gdiplus::GraphicsPath path; - Gdiplus::Point gdi2_p[3] = {Gdiplus::Point(x0, y0), Gdiplus::Point(x1, y1), Gdiplus::Point(x2, y2)}; - path.AddLines(gdi2_p, 3); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawPath(pen_, &path); -} - -#define fl_min(a,b) (a < b ? a : b) -#define fl_max(a,b) (a > b ? a : b) -void Fl_GDIplus_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - if ( (x0 == x3 && x1 == x2 && y0 == y1 && y3 == y2) || - (x0 == x1 && y1 == y2 && x2 == x3 && y3 == y0) ) { // rectangular loop - int left = fl_min(x0, fl_min(x1, fl_min(x2, x3))); - int right = fl_max(x0, fl_max(x1, fl_max(x2, x3))); - int top = fl_min(y0, fl_min(y1, fl_min(y2, y3))); - int bottom = fl_max(y0, fl_max(y1, fl_max(y2, y3))); - rect(left, top, right-left+1, bottom-top+1); - } else { - if (!active) return Fl_Scalable_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2, x3, y3); - Gdiplus::GraphicsPath path; - Gdiplus::PointF gdi2_p[4] = {Gdiplus::PointF(x0+1-line_width_/2.f, y0+1-line_width_/2.f), Gdiplus::PointF(x1+1-line_width_/2.f, y1+1-line_width_/2.f), Gdiplus::PointF(x2+1-line_width_/2.f, y2+1-line_width_/2.f), Gdiplus::PointF(x3+1-line_width_/2.f, y3+1-line_width_/2.f)}; - path.AddLines(gdi2_p, 4); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - pen_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { - if (!active) return Fl_Scalable_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2); - Gdiplus::GraphicsPath path; - path.AddLine(x0, y0, x1, y1); - path.AddLine(x1, y1, x2, y2); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPath(brush_, &path); -} - -void Fl_GDIplus_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - if ( (x0 == x3 && x1 == x2 && y0 == y1 && y3 == y2) || - (x0 == x1 && y1 == y2 && x2 == x3 && y3 == y0) ) { - int left = fl_min(x0, fl_min(x1, fl_min(x2, x3))); - int right = fl_max(x0, fl_max(x1, fl_max(x2, x3))); - int top = fl_min(y0, fl_min(y1, fl_min(y2, y3))); - int bottom = fl_max(y0, fl_max(y1, fl_max(y2, y3))); - rectf(left, top, right-left, bottom-top); - } else { - if (!active) return Fl_Scalable_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2, x3, y3); - Gdiplus::GraphicsPath path; - path.AddLine(x0, y0, x1, y1); - path.AddLine(x1, y1, x2, y2); - path.AddLine(x2, y2, x3, y3); - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - brush_->SetColor(gdiplus_color_); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - graphics_.FillPath(brush_, &path); - } -} -#endif diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx deleted file mode 100644 index e469bb11b..000000000 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx +++ /dev/null @@ -1,231 +0,0 @@ -// -// Portable drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_GDI_Graphics_Driver_vertex.cxx - - \brief Portable drawing code for drawing arbitrary shapes with - simple 2D transformations, implemented for Windows GDI. -*/ - -#include "Fl_GDI_Graphics_Driver.H" - -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/math.h> - - -void Fl_GDI_Graphics_Driver::end_points() { - for (int i=0; i<n; i++) SetPixel(gc_, long_point[i].x, long_point[i].y, fl_RGB()); -} - -void Fl_GDI_Graphics_Driver::end_line() { - if (n < 2) { - end_points(); - return; - } - if (n>1) Polyline(gc_, long_point, n); -} - -void Fl_GDI_Graphics_Driver::end_loop() { - fixloop(); - if (n>2) transformed_vertex0(float(long_point[0].x), float(long_point[0].y)); - end_line(); -} - -void Fl_GDI_Graphics_Driver::end_polygon() { - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - SelectObject(gc_, fl_brush()); - Polygon(gc_, long_point, n); - } -} - -void Fl_GDI_Graphics_Driver::begin_complex_polygon() { - Fl_Graphics_Driver::begin_complex_polygon(); - numcount = 0; -} - -void Fl_GDI_Graphics_Driver::gap() { - while (n>gap_+2 && long_point[n-1].x == long_point[gap_].x && long_point[n-1].y == long_point[gap_].y) n--; - if (n > gap_+2) { - transformed_vertex0(float(long_point[gap_].x), float(long_point[gap_].y)); - counts[numcount++] = n-gap_; - gap_ = n; - } else { - n = gap_; - } -} - -void Fl_GDI_Graphics_Driver::end_complex_polygon() { - gap(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - SelectObject(gc_, fl_brush()); - PolyPolygon(gc_, long_point, counts, numcount); - } -} - -void Fl_GDI_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) { - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - - if (what==POLYGON) { - SelectObject(gc_, fl_brush()); - Pie(gc_, llx, lly, llx+w, lly+h, 0,0, 0,0); - } else - Arc(gc_, llx, lly, llx+w, lly+h, 0,0, 0,0); -} - -#if USE_GDIPLUS - -void Fl_GDIplus_Graphics_Driver::transformed_vertex(double xf, double yf) { - if (!active) return Fl_Scalable_Graphics_Driver::transformed_vertex(xf, yf); - transformed_vertex0(float(xf) , float(yf) ); -} - -void Fl_GDIplus_Graphics_Driver::vertex(double x,double y) { - if (!active) return Fl_Scalable_Graphics_Driver::vertex(x, y); - transformed_vertex0(float(x*m.a + y*m.c + m.x) , float(x*m.b + y*m.d + m.y) ); -} - -void Fl_GDIplus_Graphics_Driver::end_points() { - if (!active) return Fl_GDI_Graphics_Driver::end_points(); - for (int i = 0; i < n; i++) point(long_point[i].x, long_point[i].y); -} - -void Fl_GDIplus_Graphics_Driver::end_line() { - if (!active) return Fl_GDI_Graphics_Driver::end_line(); - if (n < 2) { - end_points(); - return; - } - if (n>1) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddLines(gdi2_p, n); - delete[] gdi2_p; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - pen_->SetColor(gdiplus_color_); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_loop() { - if (!active) return Fl_GDI_Graphics_Driver::end_loop(); - fixloop(); - if (n >= 2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddLines(gdi2_p, n); - path.CloseFigure(); - delete[] gdi2_p; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - pen_->SetColor(gdiplus_color_); - graphics_.DrawPath(pen_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_polygon() { - if (!active) return Fl_GDI_Graphics_Driver::end_polygon(); - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddPolygon(gdi2_p, n); - delete[] gdi2_p; - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - brush_->SetColor(gdiplus_color_); - graphics_.FillPath(brush_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::end_complex_polygon() { - if (!active) return Fl_GDI_Graphics_Driver::end_complex_polygon(); - gap(); - if (n < 3) { - end_line(); - return; - } - if (n>2) { - Gdiplus::GraphicsPath path; - Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; - for (int i = 0; i < n; i++) { - gdi2_p[i] = Gdiplus::Point(long_point[i].x, long_point[i].y); - } - path.AddPolygon(gdi2_p, n); - delete[] gdi2_p; - path.CloseFigure(); - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - brush_->SetColor(gdiplus_color_); - graphics_.FillPath(brush_, &path); - } -} - -void Fl_GDIplus_Graphics_Driver::circle(double x, double y, double r) { - if (!active) return Fl_Scalable_Graphics_Driver::circle(x, y, r); - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - Gdiplus::Graphics graphics_(gc_); - graphics_.ScaleTransform(scale(), scale()); - graphics_.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - if (what==POLYGON) { - brush_->SetColor(gdiplus_color_); - graphics_.FillPie(brush_, llx, lly, w, h, 0, 360); - } else { - pen_->SetColor(gdiplus_color_); - graphics_.DrawArc(pen_, llx, lly, w, h, 0, 360); - } -} -#endif - diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H deleted file mode 100644 index 129a4ecbc..000000000 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.H +++ /dev/null @@ -1,44 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_GDI_IMAGE_SURFACE_DRIVER_H -#define FL_GDI_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_RGB_Image.H> -#include <FL/platform.H> - -class Fl_GDI_Image_Surface_Driver : public Fl_Image_Surface_Driver { - void end_current() FL_OVERRIDE; -public: - HWND pre_window; - int _savedc; - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - struct shape_data_type { - HBITMAP background; - uchar *vBits; - Fl_RGB_Image* mask; - } *shape_data_; - Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_GDI_Image_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; - POINT origin; -}; - -#endif // FL_GDI_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx deleted file mode 100644 index a14524ee2..000000000 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "Fl_GDI_Graphics_Driver.H" -#include "../WinAPI/Fl_WinAPI_Screen_Driver.H" -#include "Fl_GDI_Image_Surface_Driver.H" -#include <FL/platform.H> -#include <FL/Fl_Bitmap.H> -#include <windows.h> - - -Fl_GDI_Image_Surface_Driver::Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - Fl_Display_Device::display_device(); // make sure fl_graphics_driver was initialized - float d = fl_graphics_driver->scale(); - if (!off && d != 1 && high_res) { - w = int(w*d); - h = int(h*d); - } - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - offscreen = off ? off : (Fl_Offscreen)CreateCompatibleBitmap( (gc ? gc : fl_GetDC(0) ) , w, h); - if (!offscreen) offscreen = (Fl_Offscreen)CreateCompatibleBitmap(fl_GetDC(0), w, h); - driver(Fl_Graphics_Driver::newMainGraphicsDriver()); - if (d != 1 && high_res) ((Fl_GDI_Graphics_Driver*)driver())->scale(d); - origin.x = origin.y = 0; - shape_data_ = NULL; -} - - -Fl_GDI_Image_Surface_Driver::~Fl_GDI_Image_Surface_Driver() { - if (shape_data_ && shape_data_->background) { - DeleteObject(shape_data_->background); - delete shape_data_->mask; - free(shape_data_); - } - if (offscreen && !external_offscreen) DeleteObject((HBITMAP)offscreen); - delete driver(); -} - - -void Fl_GDI_Image_Surface_Driver::set_current() { - HDC gc = fl_makeDC((HBITMAP)offscreen); - driver()->gc(gc); - SetWindowOrgEx(gc, origin.x, origin.y, NULL); - Fl_Surface_Device::set_current(); - pre_window = fl_window; - _savedc = SaveDC(gc); - fl_window=(HWND)offscreen; -} - - -void Fl_GDI_Image_Surface_Driver::translate(int x, int y) { - ((Fl_GDI_Graphics_Driver*)driver())->translate_all(x, y); -} - - -void Fl_GDI_Image_Surface_Driver::untranslate() { - ((Fl_GDI_Graphics_Driver*)driver())->untranslate_all(); -} - - -Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image() -{ - if (shape_data_ && shape_data_->background) { - // get the offscreen size in pixels - HDC gc = fl_makeDC((HBITMAP)offscreen); - BITMAPINFO bmi; - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 0; - bmi.bmiHeader.biSizeImage = 0; - GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS); - int W = bmi.bmiHeader.biWidth; - int H = bmi.bmiHeader.biHeight; - int line_size = ((3*W+3)/4) * 4; - - // read bits of main offscreen - uchar *dib_src = new uchar[line_size * H]; - bmi.bmiHeader.biWidth = W; - bmi.bmiHeader.biHeight = H; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 24; - GetDIBits(gc, (HBITMAP)offscreen, 0, H, - dib_src, &bmi, DIB_RGB_COLORS); - - // draw above the secondary offscreen the main offscreen masked by shape_data_->mask - GdiFlush(); - Fl_Image_Surface_Driver::copy_with_mask(shape_data_->mask, shape_data_->vBits, dib_src, ((3*W+3)/4) * 4, true); - delete shape_data_->mask; - delete[] dib_src; - - // write bits of main offscreen - SetDIBits(gc, (HBITMAP)offscreen, 0, H, shape_data_->vBits, &bmi, DIB_RGB_COLORS); - DeleteDC(gc); - DeleteObject(shape_data_->background); - shape_data_->background = NULL; - free(shape_data_); - shape_data_ = NULL; - } - Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height, 0); - return image; -} - - -void Fl_GDI_Image_Surface_Driver::end_current() -{ - HDC gc = (HDC)driver()->gc(); - GetWindowOrgEx(gc, &origin); - RestoreDC(gc, _savedc); - DeleteDC(gc); - fl_window = pre_window; - Fl_Surface_Device::end_current(); -} - - -void Fl_GDI_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) { - shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type)); - // get the offscreen size in pixels - HDC gc = fl_makeDC((HBITMAP)offscreen); - BITMAPINFO bmi; - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 0; - bmi.bmiHeader.biSizeImage = 0; - - GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS); - int W = bmi.bmiHeader.biWidth; - int H = bmi.bmiHeader.biHeight; - - shape_data_->mask = Fl_Image_Surface_Driver::RGB3_to_RGB1(mask, W, H); - - // duplicate current offscreen content to new offscreen - int line_size = ((3*W+3)/4) * 4; - uchar *dib = new uchar[line_size * H]; // create temporary buffer to read DIB - bmi.bmiHeader.biWidth = W; - bmi.bmiHeader.biHeight = H; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 24; - - GetDIBits(gc, (HBITMAP)offscreen, 0, H, dib, &bmi, DIB_RGB_COLORS); - - HDC background_gc = CreateCompatibleDC(gc); - shape_data_->background = - CreateDIBSection(background_gc, &bmi, DIB_RGB_COLORS, - (void**)&shape_data_->vBits, NULL, 0); - if (!shape_data_->background) { - Fl::error("CreateDIBSection error=%lu", GetLastError()); - } - memcpy(shape_data_->vBits, dib, H * line_size); - delete[] dib; - DeleteDC(background_gc); - DeleteDC(gc); -} - diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx index 324d1c6f9..9cece371d 100644 --- a/src/drivers/PostScript/Fl_PostScript.cxx +++ b/src/drivers/PostScript/Fl_PostScript.cxx @@ -38,8 +38,8 @@ #if USE_PANGO #include <FL/math.h> // for M_PI #include <pango/pangocairo.h> -#include <cairo/cairo-ps.h> -#include <cairo/cairo-pdf.h> +#include <cairo-ps.h> +#include <cairo-pdf.h> #include <FL/Fl_Preferences.H> # if ! PANGO_VERSION_CHECK(1,10,0) # error "Requires Pango 1.10 or higher" @@ -1470,7 +1470,7 @@ void Fl_PostScript_Graphics_Driver::ps_untranslate(void) fprintf(output, "GR GR\n"); } -#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) +#if defined(FLTK_USE_X11) Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { *pfname = NULL; @@ -1492,7 +1492,7 @@ int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, return begin_job(NULL, perr_message); } -#endif // defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) +#endif // defined(FLTK_USE_X11) # else // USE_PANGO diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx index 9b5fe1668..ebb91cf03 100644 --- a/src/drivers/PostScript/Fl_PostScript_image.cxx +++ b/src/drivers/PostScript/Fl_PostScript_image.cxx @@ -26,7 +26,7 @@ #include <string.h> // memcpy() #if USE_PANGO -# include <cairo/cairo.h> +# include <cairo.h> #else # include <stdio.h> // fprintf() #endif diff --git a/src/drivers/Quartz/Fl_Font.H b/src/drivers/Quartz/Fl_Font.H deleted file mode 100644 index f1a710eea..000000000 --- a/src/drivers/Quartz/Fl_Font.H +++ /dev/null @@ -1,42 +0,0 @@ -// -// Font definitions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Two internal fltk data structures: -// -// Fl_Fontdesc: an entry into the fl_font() table. There is one of these -// for each fltk font number. -// -#ifndef FL_FONT_ -#define FL_FONT_ - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include "../../Fl_Scalable_Graphics_Driver.H" // Fl_Font_Descriptor -#include <ApplicationServices/ApplicationServices.h> - -class Fl_Quartz_Font_Descriptor : public Fl_Font_Descriptor { -public: - Fl_Quartz_Font_Descriptor(const char* fontname, Fl_Fontsize size); - virtual FL_EXPORT ~Fl_Quartz_Font_Descriptor(); - CTFontRef fontref; - // the unicode span is divided in 512 blocks of 128 characters - float *width[512]; // array of arrays of character widths - short q_width; -}; - -extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table - -#endif diff --git a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H deleted file mode 100644 index 8ef586624..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H +++ /dev/null @@ -1,39 +0,0 @@ -// -// Definition of Apple Quartz graphics driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2016 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#ifndef Fl_Quartz_Copy_Surface_Driver_H -#define Fl_Quartz_Copy_Surface_Driver_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> - -class Fl_Quartz_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; -protected: - CFMutableDataRef pdfdata; - CGContextRef gc; - static size_t MyPutBytes(void* info, const void* buffer, size_t count); - Fl_Quartz_Copy_Surface_Driver(int w, int h); - // implemented in Fl_cocoa.mm because uses Objective-c - ~Fl_Quartz_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif /* Fl_Quartz_Copy_Surface_Driver_H */ diff --git a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx deleted file mode 100644 index 77ecdaa0a..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2019 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/Fl_Copy_Surface.H> -#include <FL/platform.H> -#include "Fl_Quartz_Graphics_Driver.H" -#include "Fl_Quartz_Copy_Surface_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" - - -Fl_Quartz_Copy_Surface_Driver::Fl_Quartz_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - driver(new Fl_Quartz_Printer_Graphics_Driver); - pdfdata = CFDataCreateMutable(NULL, 0); - CGDataConsumerRef myconsumer; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 - if (&CGDataConsumerCreateWithCFData != NULL) { - myconsumer = CGDataConsumerCreateWithCFData(pdfdata); // 10.4 - } - else -#endif - { - static CGDataConsumerCallbacks callbacks = { Fl_Quartz_Copy_Surface_Driver::MyPutBytes, NULL }; - myconsumer = CGDataConsumerCreate((void*) pdfdata, &callbacks); - } - float d = fl_graphics_driver->scale(); - CGRect bounds = CGRectMake(0, 0, w * d, h * d); - gc = CGPDFContextCreate(myconsumer, &bounds, NULL); - CGDataConsumerRelease(myconsumer); - if (gc) { - CGContextBeginPage(gc, &bounds); - CGContextScaleCTM(gc, d, -d); - CGContextTranslateCTM(gc, 0.5, -h + 0.5); - CGContextSaveGState(gc); - } -} - -void Fl_Quartz_Copy_Surface_Driver::set_current() { - driver()->gc(gc); - fl_window = (FLWindow*)1; - Fl_Surface_Device::set_current(); -} - -size_t Fl_Quartz_Copy_Surface_Driver::MyPutBytes(void* info, const void* buffer, size_t count) -{ - CFDataAppendBytes ((CFMutableDataRef) info, (const UInt8 *)buffer, count); - return count; -} - -void Fl_Quartz_Copy_Surface_Driver::translate(int x, int y) { - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, x, y); - CGContextSaveGState(gc); -} - -void Fl_Quartz_Copy_Surface_Driver::untranslate() { - CGContextRestoreGState(gc); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H deleted file mode 100644 index 0afc7369e..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H +++ /dev/null @@ -1,149 +0,0 @@ -// -// Definition of Apple Quartz graphics driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Quartz_Graphics_Driver.H - \brief Definition of Apple Quartz graphics driver. - */ - -#ifndef FL_QUARTZ_GRAPHICS_DRIVER_H -#define FL_QUARTZ_GRAPHICS_DRIVER_H - -#include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> -#include <ApplicationServices/ApplicationServices.h> - -struct Fl_Fontdesc; -class Fl_Quartz_Font_Descriptor; - -/** - \brief The Mac OS X-specific graphics class. - - This class is implemented only on the Mac OS X platform. - */ -class Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { - friend class Fl_Cocoa_Printer_Driver; - friend class Fl_Quartz_Font_Descriptor; -protected: - CGContextRef gc_; - bool high_resolution_; - float quartz_line_width_; - CGLineCap quartz_line_cap_; - CGLineJoin quartz_line_join_; - CGFloat *quartz_line_pattern; - int quartz_line_pattern_size; - void cache_size(Fl_Image* img, int &width, int &height) FL_OVERRIDE; -public: - Fl_Quartz_Graphics_Driver(); - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & NATIVE; } - void gc(void *ctxt) FL_OVERRIDE { gc_ = (CGContextRef)ctxt; global_gc(); } - void *gc() FL_OVERRIDE {return gc_;} - char can_do_alpha_blending() FL_OVERRIDE; - - // --- bitmap stuff - static CGImageRef create_bitmask(int w, int h, const uchar *array); // NOT virtual - void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE; - void draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_bitmap(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) FL_OVERRIDE; - void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) FL_OVERRIDE; - void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) FL_OVERRIDE; - void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) FL_OVERRIDE; - void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) FL_OVERRIDE; - void cache(Fl_Pixmap *img) FL_OVERRIDE; - void cache(Fl_Bitmap *img) FL_OVERRIDE; - void cache(Fl_RGB_Image *img) FL_OVERRIDE; - void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) FL_OVERRIDE; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) FL_OVERRIDE; - void draw_CGImage(CGImageRef cgimg, int x, int y, int w, int h, int srcx, int srcy, int sw, int sh); - static CGRect fl_cgrectmake_cocoa(int x, int y, int w, int h); - void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h) FL_OVERRIDE; - Fl_Region XRectangleRegion(int x, int y, int w, int h) FL_OVERRIDE; - void XDestroyRegion(Fl_Region r) FL_OVERRIDE; - void high_resolution(bool b) { high_resolution_ = b; } -protected: - void point(int x, int y) FL_OVERRIDE; - void rect(int x, int y, int w, int h) FL_OVERRIDE; - void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; - void rectf(int x, int y, int w, int h) FL_OVERRIDE; - void line(int x, int y, int x1, int y1) FL_OVERRIDE; - void line(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void xyline(int x, int y, int x1) FL_OVERRIDE; - void xyline(int x, int y, int x1, int y2) FL_OVERRIDE; - void xyline(int x, int y, int x1, int y2, int x3) FL_OVERRIDE; - void yxline(int x, int y, int y1) FL_OVERRIDE; - void yxline(int x, int y, int y1, int x2) FL_OVERRIDE; - void yxline(int x, int y, int y1, int x2, int y3) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2) FL_OVERRIDE; - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) FL_OVERRIDE; - // --- clipping - void push_clip(int x, int y, int w, int h) FL_OVERRIDE; - int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) FL_OVERRIDE; - int not_clipped(int x, int y, int w, int h) FL_OVERRIDE; - void restore_clip() FL_OVERRIDE; - void end_points() FL_OVERRIDE; - void end_line() FL_OVERRIDE; - void end_polygon() FL_OVERRIDE; - void end_complex_polygon() FL_OVERRIDE; - void circle(double x, double y, double r) FL_OVERRIDE; - void arc(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void pie(int x, int y, int w, int h, double a1, double a2) FL_OVERRIDE; - void line_style(int style, int width=0, char* dashes=0) FL_OVERRIDE; - void color(Fl_Color c) FL_OVERRIDE; - Fl_Color color() FL_OVERRIDE { return color_; } - void color(uchar r, uchar g, uchar b) FL_OVERRIDE; - void draw(const char *str, int n, int x, int y) FL_OVERRIDE; - void draw(const char *str, int n, float x, float y) FL_OVERRIDE; - void draw(int angle, const char *str, int n, int x, int y) FL_OVERRIDE; - double width(const UniChar* txt, int n); - void rtl_draw(const char *str, int n, int x, int y) FL_OVERRIDE; - void font(Fl_Font face, Fl_Fontsize fsize) FL_OVERRIDE; - double width(const char *str, int n) FL_OVERRIDE; - double width(unsigned int c) FL_OVERRIDE; - int height() FL_OVERRIDE; - int descent() FL_OVERRIDE; - virtual bool high_resolution() { return high_resolution_; } - void global_gc() FL_OVERRIDE; - void quartz_restore_line_style(); - inline Fl_Quartz_Font_Descriptor *valid_font_descriptor(); - const char* get_font_name(Fl_Font fnum, int* ap) FL_OVERRIDE; - int get_font_sizes(Fl_Font fnum, int*& sizep) FL_OVERRIDE; - const char *font_name(int num) FL_OVERRIDE; - void font_name(int num, const char *name) FL_OVERRIDE; - Fl_Fontdesc* calc_fl_fonts(void) FL_OVERRIDE; - - void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h) FL_OVERRIDE; - Fl_Font set_fonts(const char* xstarname) FL_OVERRIDE; - void set_fontname_in_fontdesc(Fl_Fontdesc *f); - void uncache_pixmap(fl_uintptr_t p) FL_OVERRIDE; - - void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Quartz_Font_Descriptor *d); - void overlay_rect(int x, int y, int w , int h) FL_OVERRIDE; - float override_scale() FL_OVERRIDE; - void restore_scale(float) FL_OVERRIDE; - void antialias(int state) FL_OVERRIDE; - int antialias() FL_OVERRIDE; -}; - -class Fl_Quartz_Printer_Graphics_Driver : public Fl_Quartz_Graphics_Driver { -public: - int has_feature(driver_feature mask) FL_OVERRIDE { return mask & (NATIVE | PRINTER); } -}; - -#endif // FL_QUARTZ_GRAPHICS_DRIVER_H diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx deleted file mode 100644 index 21c5eda4c..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx +++ /dev/null @@ -1,133 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include "../Darwin/Fl_Darwin_System_Driver.H" -#include "../Cocoa/Fl_Cocoa_Screen_Driver.H" -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include <FL/Fl_Image_Surface.H> - - -void Fl_Quartz_Graphics_Driver::antialias(int state) { -} - -int Fl_Quartz_Graphics_Driver::antialias() { - return 1; -} - -Fl_Quartz_Graphics_Driver::Fl_Quartz_Graphics_Driver() : Fl_Graphics_Driver(), gc_(NULL) { - quartz_line_width_ = 1.f; - quartz_line_cap_ = kCGLineCapButt; - quartz_line_join_ = kCGLineJoinMiter; - quartz_line_pattern = 0; - quartz_line_pattern_size = 0; - high_resolution_ = false; -} - -char Fl_Quartz_Graphics_Driver::can_do_alpha_blending() { - return 1; -} - -static void bmProviderRelease (void *src, const void *data, size_t size) { - CFIndex count = CFGetRetainCount(src); - CFRelease(src); - if(count == 1) free((void*)data); -} - -/* Reference to the current CGContext - For back-compatibility only. The preferred procedure to get this reference is - Fl_Surface_Device::surface()->driver()->gc(). - */ -CGContextRef fl_gc = 0; - -void Fl_Quartz_Graphics_Driver::global_gc() -{ - fl_gc = (CGContextRef)gc(); -} - - -CGContextRef fl_mac_gc() { return fl_gc; } - - -void Fl_Quartz_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface - CGContextRef src = (CGContextRef)osrc; - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - CGImageRef img; - img = CGBitmapContextCreateImage(src); // requires 10.4 - CGAffineTransform at = CGContextGetCTM(src); - float s = at.a; - draw_CGImage(img, x, y, w, h, srcx, srcy, sw/s, sh/s); - CGImageRelease(img); -} - -// so a CGRect matches exactly what is denoted x,y,w,h for clipping purposes -CGRect Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(int x, int y, int w, int h) { - return CGRectMake(x - 0.5, y - 0.5, w, h); -} - -void Fl_Quartz_Graphics_Driver::add_rectangle_to_region(Fl_Region r_, int X, int Y, int W, int H) { - struct flCocoaRegion *r = (struct flCocoaRegion*)r_; - CGRect arg = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(X, Y, W, H); - int j; // don't add a rectangle totally inside the Fl_Region - for(j = 0; j < r->count; j++) { - if(CGRectContainsRect(r->rects[j], arg)) break; - } - if( j >= r->count) { - r->rects = (CGRect*)realloc(r->rects, (++(r->count)) * sizeof(CGRect)); - r->rects[r->count - 1] = arg; - } -} - -Fl_Region Fl_Quartz_Graphics_Driver::XRectangleRegion(int x, int y, int w, int h) { - struct flCocoaRegion* R = (struct flCocoaRegion*)malloc(sizeof(struct flCocoaRegion)); - R->count = 1; - R->rects = (CGRect *)malloc(sizeof(CGRect)); - *(R->rects) = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(x, y, w, h); - return R; -} - -void Fl_Quartz_Graphics_Driver::XDestroyRegion(Fl_Region r_) { - if (r_) { - struct flCocoaRegion *r = (struct flCocoaRegion*)r_; - free(r->rects); - free(r); - } -} - -void Fl_Quartz_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) { - width *= 2 * scale(); - height *= 2 * scale(); -} - -float Fl_Quartz_Graphics_Driver::override_scale() { - float s = scale(); - if (s != 1.f && Fl_Display_Device::display_device()->is_current()) { - CGContextScaleCTM(gc_, 1./s, 1./s); - Fl_Graphics_Driver::scale(1); - } - return s; -} - -void Fl_Quartz_Graphics_Driver::restore_scale(float s) { - if (s != 1.f && Fl_Display_Device::display_device()->is_current()) { - CGContextScaleCTM(gc_, s, s); - Fl_Graphics_Driver::scale(s); - } -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx deleted file mode 100644 index 4163de685..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// -// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Quartz_Graphics_Driver.H" -#include <FL/platform.H> - -/** - \file quartz_arci.cxx - \brief Utility functions for drawing circles using integers -*/ - -void Fl_Quartz_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; - float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; - CGContextSetShouldAntialias(gc_, true); - if (w!=h) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, cx, cy); - CGContextScaleCTM(gc_, w-1.0f, h-1.0f); - CGContextAddArc(gc_, 0, 0, 0.5, a1, a2, 1); - CGContextRestoreGState(gc_); - } else { - float r = (w+h)*0.25f-0.5f; - CGContextAddArc(gc_, cx, cy, r, a1, a2, 1); - } - CGContextStrokePath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; - float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; - CGContextSetShouldAntialias(gc_, true); - if (w!=h) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, cx, cy); - CGContextScaleCTM(gc_, w, h); - CGContextAddArc(gc_, 0, 0, 0.5, a1, a2, 1); - CGContextAddLineToPoint(gc_, 0, 0); - CGContextClosePath(gc_); - CGContextRestoreGState(gc_); - } else { - float r = (w+h)*0.25f; - CGContextAddArc(gc_, cx, cy, r, a1, a2, 1); - CGContextAddLineToPoint(gc_, cx, cy); - CGContextClosePath(gc_); - } - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx deleted file mode 100644 index 9d31f8573..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx +++ /dev/null @@ -1,70 +0,0 @@ -// -// MacOS color functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// The fltk "colormap". This allows ui colors to be stored in 8-bit -// locations, and provides a level of indirection so that global color -// changes can be made. Not to be confused with the X colormap, which -// I try to hide completely. - -// matt: Neither Quartz nor Quickdraw support colormaps in this implementation -// matt: Quartz support done - -#include "Fl_Quartz_Graphics_Driver.H" - -#include <config.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_draw.H> - -extern unsigned fl_cmap[256]; // defined in fl_color.cxx - -void Fl_Quartz_Graphics_Driver::color(Fl_Color i) { - Fl_Graphics_Driver::color(i); - uchar r, g, b; - float fa = 1.0f; - if (i & 0xFFFFFF00) { - // translate rgb colors into color index - r = i>>24; - g = i>>16; - b = i>> 8; - } else { - // translate index into rgb: - unsigned c = fl_cmap[i]; - c = c ^ 0x000000ff; // trick to restore the color's correct alpha value - r = c>>24; - g = c>>16; - b = c>> 8; - uchar a = c & 0xff; - //printf("i=%d rgb=%u,%u,%u a=%u\n",i,r,g,b,a); - fa = a/255.0f; - } - if (!gc_) return; // no context yet? We will assign the color later. - float fr = r/255.0f; - float fg = g/255.0f; - float fb = b/255.0f; - CGContextSetRGBFillColor(gc_, fr, fg, fb, fa); - CGContextSetRGBStrokeColor(gc_, fr, fg, fb, fa); -} - -void Fl_Quartz_Graphics_Driver::color(uchar r, uchar g, uchar b) { - Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); - float fr = r/255.0f; - float fg = g/255.0f; - float fb = b/255.0f; - if (!gc_) return; // no context yet? We will assign the color later. - CGContextSetRGBFillColor(gc_, fr, fg, fb, 1.0f); - CGContextSetRGBStrokeColor(gc_, fr, fg, fb, 1.0f); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx deleted file mode 100644 index d373c1768..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx +++ /dev/null @@ -1,561 +0,0 @@ -// -// MacOS font selection routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Quartz_Graphics_Driver.H" -#include "Fl_Font.H" -#include <math.h> -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/fl_utf8.h> // for fl_utf8toUtf16() -#include <FL/fl_string_functions.h> // fl_strdup() - -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 -const NSUInteger kCTFontOrientationHorizontal = kCTFontHorizontalOrientation; -#endif - -Fl_Fontdesc* fl_fonts = NULL; - -static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; - -static int fl_free_font = FL_FREE_FONT; - - -static CFMutableDictionaryRef attributes = NULL; - -static Fl_Fontdesc built_in_table_PS[] = { // PostScript font names preferred when Mac OS ≥ 10.5 - {"ArialMT"}, - {"Arial-BoldMT"}, - {"Arial-ItalicMT"}, - {"Arial-BoldItalicMT"}, - {"Courier"}, - {"Courier-Bold"}, - {"Courier-Oblique"}, - {"Courier-BoldOblique"}, - {"TimesNewRomanPSMT"}, - {"TimesNewRomanPS-BoldMT"}, - {"TimesNewRomanPS-ItalicMT"}, - {"TimesNewRomanPS-BoldItalicMT"}, - {"Symbol"}, - {"Monaco"}, - {"AndaleMono"}, // there is no bold Monaco font on standard Mac - {"ZapfDingbatsITC"} -}; - - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER sizeof(fl_fonts->fontname)-1 - -// turn a stored font name into a pretty name: -const char* Fl_Quartz_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) { - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - this->set_fontname_in_fontdesc(f); - const char* thisFont = f->name; - if (!thisFont || !*thisFont) {if (ap) *ap = 0; return "";} - int type = 0; - if (strstr(f->name, "Bold")) type |= FL_BOLD; - if (strstr(f->name, "Italic") || strstr(f->name, "Oblique")) type |= FL_ITALIC; - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - - -int Fl_Quartz_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { - static int array[128]; - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - int cnt = 0; - - // ATS supports all font size - array[0] = 0; - sizep = array; - cnt = 1; - - return cnt; -} - -Fl_Quartz_Font_Descriptor::Fl_Quartz_Font_Descriptor(const char* name, Fl_Fontsize Size) : Fl_Font_Descriptor(name, Size) { - fontref = NULL; - Fl_Quartz_Graphics_Driver *driver = (Fl_Quartz_Graphics_Driver*)&Fl_Graphics_Driver::default_driver(); - driver->descriptor_init(name, size, this); -} - - -Fl_Quartz_Font_Descriptor::~Fl_Quartz_Font_Descriptor() { -/* -#if HAVE_GL - // ++ todo: remove OpenGL font allocations -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -#endif - */ - if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); - if (fontref) { - CFRelease(fontref); - for (unsigned i = 0; i < sizeof(width)/sizeof(float*); i++) { - if (width[i]) free(width[i]); - } - } -} - - -static UniChar *utfWbuf = 0; -static unsigned utfWlen = 0; - -static UniChar *mac_Utf8_to_Utf16(const char *txt, int len, int *new_len) -{ - unsigned wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); - if (wlen >= utfWlen) - { - utfWlen = wlen + 100; - if (utfWbuf) free(utfWbuf); - utfWbuf = (UniChar*)malloc((utfWlen)*sizeof(UniChar)); - wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); - } - *new_len = wlen; - return utfWbuf; -} - - -static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { - if (!fl_fonts) fl_fonts = Fl_Graphics_Driver::default_driver().calc_fl_fonts(); - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_Font_Descriptor* f; - for (f = s->first; f; f = f->next) - if (f->size == size) return f; - f = new Fl_Quartz_Font_Descriptor(s->name, size); - f->next = s->first; - s->first = f; - return f; -} - - -void Fl_Quartz_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { - if (fnum == -1) { - Fl_Graphics_Driver::font(0, 0); - return; - } - Fl_Graphics_Driver::font(fnum, size); - font_descriptor( find(fnum, size) ); -} - -Fl_Quartz_Font_Descriptor *Fl_Quartz_Graphics_Driver::valid_font_descriptor() { - // avoid a crash if no font has been selected by user yet - if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); - return (Fl_Quartz_Font_Descriptor*)font_descriptor(); -} - -int Fl_Quartz_Graphics_Driver::height() { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - return fl_fontsize->ascent + fl_fontsize->descent; -} - -int Fl_Quartz_Graphics_Driver::descent() { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - return fl_fontsize->descent + 1; -} - -void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) { - draw(str, n, (float)x, y+0.5f); -} - -void Fl_Quartz_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { - CGContextSaveGState(gc_); - CGContextTranslateCTM(gc_, x, y); - CGContextRotateCTM(gc_, - angle*(M_PI/180) ); - draw(str, n, 0, 0); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { - int dx, dy, w, h; - text_extents(c, n, dx, dy, w, h); - draw(c, n, x - w - dx, y); -} - -double Fl_Quartz_Graphics_Driver::width(const char* txt, int n) { - if (n == 0) return 0; - int len1 = fl_utf8len1(*txt); - if (len1 > 0 && n > len1) { // a text with several codepoints: compute its typographical width - CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n, kCFStringEncodingUTF8, false); - if (str) { - CFDictionarySetValue(attributes, kCTFontAttributeName, valid_font_descriptor()->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str, attributes); - CFRelease(str); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - double d = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL); - CFRelease(ctline); - return d; - } - } - int wc_len = n; - UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len); - return width(uniStr, wc_len); -} - -double Fl_Quartz_Graphics_Driver::width(unsigned int wc) { - UniChar utf16[3]; - int l = 1; - if (wc <= 0xFFFF) { - *utf16 = wc; - } - else { - l = (int)fl_ucs_to_Utf16(wc, utf16, 3); - } - return width(utf16, l); -} - -void Fl_Quartz_Graphics_Driver::set_fontname_in_fontdesc(Fl_Fontdesc *f) { - CFStringRef cfname = CFStringCreateWithCString(NULL, f->name, kCFStringEncodingUTF8); - CTFontRef ctfont = cfname ? CTFontCreateWithName(cfname, 0, NULL) : NULL; - if (cfname) { CFRelease(cfname); cfname = NULL; } - if (ctfont) { - cfname = CTFontCopyFullName(ctfont); - CFRelease(ctfont); - if (cfname) { - CFStringGetCString(cfname, f->fontname, ENDOFBUFFER, kCFStringEncodingUTF8); - CFRelease(cfname); - } - } - if (!cfname) strlcpy(f->fontname, f->name, ENDOFBUFFER); -} - -const char *Fl_Quartz_Graphics_Driver::font_name(int num) { - if (!fl_fonts) fl_fonts = calc_fl_fonts(); - return fl_fonts[num].name; -} - -void Fl_Quartz_Graphics_Driver::font_name(int num, const char *name) { - Fl_Fontdesc *s = fl_fonts + num; - if (s->name) { - if (!strcmp(s->name, name)) {s->name = name; return;} - for (Fl_Font_Descriptor* f = s->first; f;) { - Fl_Font_Descriptor* n = f->next; delete f; f = n; - } - s->first = 0; - } - s->name = name; - s->fontname[0] = 0; - s->first = 0; -} - - -Fl_Fontdesc* Fl_Quartz_Graphics_Driver::calc_fl_fonts(void) -{ - return built_in_table_PS; -} - - -void Fl_Quartz_Graphics_Driver::descriptor_init(const char* name, - Fl_Fontsize size, Fl_Quartz_Font_Descriptor *d) -{ - CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); - d->fontref = CTFontCreateWithName(str, size, NULL); - CGGlyph glyph[2]; - const UniChar A[2]={'W','.'}; - CTFontGetGlyphsForCharacters(d->fontref, A, glyph, 2); - CGSize advances[2]; - double w; - CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, advances, 2); - w = advances[0].width; - if ( fabs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font - // slightly rescale fixed-width fonts so the character width has an integral value - CFRelease(d->fontref); - CGFloat fsize = size / ( w/floor(w + 0.5) ); - d->fontref = CTFontCreateWithName(str, fsize, NULL); - w = CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, NULL, 1); - } - CFRelease(str); - d->ascent = (short)(CTFontGetAscent(d->fontref) + 0.5); - d->descent = (short)(CTFontGetDescent(d->fontref) + 0.5); - d->q_width = w + 0.5; - for (unsigned i = 0; i < sizeof(d->width)/sizeof(float*); i++) d->width[i] = NULL; - if (!attributes) { - static CFNumberRef zero_ref; - float zero = 0.; - zero_ref = CFNumberCreate(NULL, kCFNumberFloat32Type, &zero); - // deactivate kerning for all fonts, so that string width = sum of character widths - // which allows fast fl_width() implementation. - attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 3, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue (attributes, kCTKernAttributeName, zero_ref); - } - if (d->ascent == 0) { // this may happen with some third party fonts - CFDictionarySetValue (attributes, kCTFontAttributeName, d->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("Wj"), attributes); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGFloat fascent, fdescent; - CTLineGetTypographicBounds(ctline, &fascent, &fdescent, NULL); - CFRelease(ctline); - d->ascent = (short)(fascent + 0.5); - d->descent = (short)(fdescent + 0.5); - } -} - -// returns width of a pair of UniChar's in the surrogate range -static CGFloat surrogate_width(const UniChar *txt, Fl_Quartz_Font_Descriptor *fl_fontsize) -{ - CTFontRef font2 = fl_fontsize->fontref; - bool must_release = false; - CGGlyph glyphs[2]; - bool b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); - CGSize a; - if(!b) { // the current font doesn't contain this char - CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, txt, 2, kCFAllocatorNull); - // find a font that contains it - font2 = CTFontCreateForString(font2, str, CFRangeMake(0,2)); - must_release = true; - CFRelease(str); - b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); - } - if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, glyphs, &a, 1); - else a.width = fl_fontsize->q_width; - if(must_release) CFRelease(font2); - return a.width; -} - -static CGFloat variation_selector_width(CFStringRef str16, Fl_Quartz_Font_Descriptor *fl_fontsize) -{ - CGFloat retval; - CFDictionarySetValue(attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - retval = CTLineGetOffsetForStringIndex(ctline, 2, NULL); - CFRelease(ctline); - return retval; -} - -double Fl_Quartz_Graphics_Driver::width(const UniChar* txt, int n) -{ - double retval = 0; - UniChar uni; - int i; - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - for (i = 0; i < n; i++) { // loop over txt - uni = txt[i]; - if (uni >= 0xD800 && uni <= 0xDBFF) { // handles the surrogate range - retval += surrogate_width(&txt[i], fl_fontsize); - i++; // because a pair of UniChar's represent a single character - continue; - } - if (i+1 < n && txt[i+1] >= 0xFE00 && txt[i+1] <= 0xFE0F) { // handles variation selectors - CFStringRef substr = CFStringCreateWithCharacters(NULL, txt + i, 2); - retval += variation_selector_width(substr, fl_fontsize); - CFRelease(substr); - i++; - continue; - } - const int block = 0x10000 / (sizeof(fl_fontsize->width)/sizeof(float*)); // block size - // r: index of the character block containing uni - unsigned int r = uni >> 7; // change 7 if sizeof(width) is changed - if (!fl_fontsize->width[r]) { // this character block has not been hit yet - //fprintf(stderr,"r=%d size=%d name=%s\n",r,fl_fontsize->size,fl_fonts[fl_font()].name); - // allocate memory to hold width of each character in the block - fl_fontsize->width[r] = (float*) malloc(sizeof(float) * block); - UniChar ii = r * block; - CGSize advance_size; - CGGlyph glyph; - for (int j = 0; j < block; j++) { // loop over the block - // ii spans all characters of this block - bool b = CTFontGetGlyphsForCharacters(fl_fontsize->fontref, &ii, &glyph, 1); - if (b) - CTFontGetAdvancesForGlyphs(fl_fontsize->fontref, kCTFontOrientationHorizontal, &glyph, &advance_size, 1); - else - advance_size.width = -1e9; // calculate this later - // the width of one character of this block of characters - fl_fontsize->width[r][j] = advance_size.width; - ii++; - } - } - // sum the widths of all characters of txt - double wdt = fl_fontsize->width[r][uni & (block-1)]; - if (wdt == -1e9) { - CGSize advance_size; - CGGlyph glyph; - CTFontRef font2 = fl_fontsize->fontref; - bool must_release = false; - bool b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); - if (!b) { // the current font doesn't contain this char - CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, &uni, 1, kCFAllocatorNull); - // find a font that contains it - font2 = CTFontCreateForString(font2, str, CFRangeMake(0,1)); - must_release = true; - CFRelease(str); - b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); - } - if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, &glyph, &advance_size, 1); - else advance_size.width = 0.; - // the width of the 'uni' character - wdt = fl_fontsize->width[r][uni & (block-1)] = advance_size.width; - if (must_release) CFRelease(font2); - } - retval += wdt; - } - return retval; -} - - -// text extent calculation -void Fl_Quartz_Graphics_Driver::text_extents(const char *str8, int n, - int &dx, int &dy, int &w, int &h) { - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n); - CFStringRef str16 = CFStringCreateWithCharactersNoCopy(NULL, txt, n, kCFAllocatorNull); - CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CFRelease(str16); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGContextSetTextPosition(gc_, 0, 0); - CGContextSetShouldAntialias(gc_, true); - CGRect rect = CTLineGetImageBounds(ctline, gc_); - CGContextSetShouldAntialias(gc_, false); - CFRelease(ctline); - dx = floor(rect.origin.x + 0.5); - dy = floor(- rect.origin.y - rect.size.height + 0.5); - w = rect.size.width + 0.5; - h = rect.size.height + 0.5; -} - - -static CGColorRef flcolortocgcolor(Fl_Color i) -{ - uchar r, g, b; - Fl::get_color(i, r, g, b); - CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.}; - static CGColorSpaceRef cspace = NULL; - if (cspace == NULL) { - cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - } - return CGColorCreate(cspace, components); -} - -void Fl_Quartz_Graphics_Driver::draw(const char *str, int n, float x, float y) -{ - Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor(); - // convert to UTF-16 first - UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n); - CGContextRef gc = (CGContextRef)this->gc(); - CFMutableStringRef str16 = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, uniStr, n, n, kCFAllocatorNull); - if (str16 == NULL) return; // shd not happen - CGColorRef color = flcolortocgcolor(this->color()); - CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref); - CFDictionarySetValue (attributes, kCTForegroundColorAttributeName, color); - CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); - CFRelease(str16); - CFRelease(color); - CTLineRef ctline = CTLineCreateWithAttributedString(mastr); - CFRelease(mastr); - CGContextSetTextMatrix(gc, font_mx); - CGContextSetTextPosition(gc, x, y); - CGContextSetShouldAntialias(gc, true); - CTLineDraw(ctline, gc); - CGContextSetShouldAntialias(gc, false); - CFRelease(ctline); -} - -// Skip over bold/italic/oblique qualifiers part of PostScript font names -// Example: -// input: '-Regular_Light-Condensed' -// return: '_Light-Condensed' -// -static char *skip(char *p, int& derived) -{ - // 0 5 10 - // | | | - if (strncmp(p, "-BoldItalic", 11) == 0) { p += 11; derived = 3; } - else if (strncmp(p, "-BoldOblique", 12) == 0) { p += 12; derived = 3; } - else if (strncmp(p, "-Bold", 5) == 0) { p += 5; derived = 1; } - else if (strncmp(p, "-Italic", 7) == 0) { p += 7; derived = 2; } - else if (strncmp(p, "-Oblique", 8) == 0) { p += 8; derived = 2; } - else if (strncmp(p, "-Regular", 8) == 0) { p += 8; } - else if (strncmp(p, "-Roman", 6) == 0) { p += 6; } - return p; -} - -static int name_compare(const void *a, const void *b) -{ - /* Compare PostScript font names. - First compare font family names ignoring bold, italic and oblique qualifiers. - When families are identical, order them according to regular, bold, italic, bolditalic. - */ - char *n1 = *(char**)a; - char *n2 = *(char**)b; - int derived1 = 0; - int derived2 = 0; - while (true) { - if (*n1 == '-') n1 = skip(n1, derived1); - if (*n2 == '-') n2 = skip(n2, derived2); - if (*n1 < *n2) return -1; - if (*n1 > *n2) return +1; - if (*n1 == 0) { - return derived1 - derived2; - } - n1++; n2++; - } -} - -Fl_Font Fl_Quartz_Graphics_Driver::set_fonts(const char* xstarname) -{ -#pragma unused ( xstarname ) - if (fl_free_font > FL_FREE_FONT) return (Fl_Font)fl_free_font; // if already called - - int value[1] = {1}; - CFDictionaryRef dict = CFDictionaryCreate(NULL, - (const void **)kCTFontCollectionRemoveDuplicatesOption, - (const void **)&value, 1, NULL, NULL); - CTFontCollectionRef fcref = CTFontCollectionCreateFromAvailableFonts(dict); - CFRelease(dict); - CFArrayRef arrayref = CTFontCollectionCreateMatchingFontDescriptors(fcref); - CFRelease(fcref); - CFIndex count = CFArrayGetCount(arrayref); - CFIndex i; - char **tabfontnames = new char*[count]; - for (i = 0; i < count; i++) { - CTFontDescriptorRef fdesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arrayref, i); - CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, 0., NULL); - CFStringRef cfname = CTFontCopyPostScriptName(font); - CFRelease(font); - CFDataRef cfdata = CFStringCreateExternalRepresentation(NULL, cfname, kCFStringEncodingUTF8, '?'); - CFIndex l = CFDataGetLength(cfdata); - tabfontnames[i] = (char*)malloc(l+1); // never free'ed - memcpy(tabfontnames[i], CFDataGetBytePtr(cfdata), l); - tabfontnames[i][l] = 0; - CFRelease(cfdata); - CFRelease(cfname); - } - CFRelease(arrayref); - qsort(tabfontnames, count, sizeof(char*), name_compare); - for (i = 0; i < count; i++) { - Fl::set_font((Fl_Font)(fl_free_font++), tabfontnames[i]); - } - delete[] tabfontnames; - return (Fl_Font)fl_free_font; -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx deleted file mode 100644 index 932ef7d82..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx +++ /dev/null @@ -1,284 +0,0 @@ -// -// MacOS image drawing code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include "Fl_Quartz_Graphics_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> - -#define MAXBUFFER 0x40000 // 256k - -static void dataReleaseCB(void *info, const void *data, size_t size) -{ - delete[] (uchar *)data; -} - -/* - draw an image based on the input parameters - - buf: image source data - X, Y: position (in buffer?!) - W, H: size of picture (in pixel?) - delta: distance from pixel to pixel in buf in bytes - linedelta: distance from line to line in buf in bytes - mono: if set, pixel is one byte - if zero, pixel is 3 byte - cb: callback to copy image data into (RGB?) buffer - buf: pointer to first byte in image source - x, y: position in buffer - w: width (in bytes?) - dst: destination buffer - userdata: ? - */ -static void innards(const uchar *buf, int X, int Y, int W, int H, - int delta, int linedelta, int mono, - Fl_Draw_Image_Cb cb, void* userdata, CGContextRef gc, Fl_Quartz_Graphics_Driver *driver) -{ - if (!linedelta) linedelta = W*abs(delta); - - uchar *tmpBuf = 0; - if (!cb) { - if (delta < 0) buf -= (W-1)*(-delta); - if (linedelta < 0) buf -= (H-1)*abs(linedelta); - } - const void *array = buf; - if (cb || driver->has_feature(Fl_Quartz_Graphics_Driver::PRINTER)) { - tmpBuf = new uchar[ H*W*abs(delta) ]; - if (cb) { - for (int i=0; i<H; i++) { - cb(userdata, 0, i, W, tmpBuf+i*W*abs(delta)); - } - } else { - uchar *p = tmpBuf; - for (int i=0; i<H; i++) { - memcpy(p, buf+i*abs(linedelta), W*abs(delta)); - p += W*abs(delta); - } - } - array = (void*)tmpBuf; - linedelta = W*abs(delta); - } - // create an image context - CGColorSpaceRef lut = 0; - if (abs(delta)<=2) - lut = CGColorSpaceCreateDeviceGray(); - else - lut = CGColorSpaceCreateDeviceRGB(); - // a release callback is necessary when the gc is a print context because the image data - // must be kept until the page is closed. Thus tmpBuf can't be deleted here. It's too early. - CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, abs(linedelta)*H, - tmpBuf ? dataReleaseCB : NULL - ); - CGImageRef img = CGImageCreate( W, H, 8, 8*abs(delta), abs(linedelta), - lut, abs(delta)&1?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(lut); - CGDataProviderRelease(src); - // draw the image into the destination context - if (img) { - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, X, Y); - if (linedelta < 0) { - CGContextTranslateCTM(gc, 0, H-1); - CGContextScaleCTM(gc, 1, -1); - } - if (delta < 0) { - CGContextTranslateCTM(gc, W-1, 0); - CGContextScaleCTM(gc, -1, 1); - } - driver->draw_CGImage(img, 0,0,W,H, 0,0,W,H); - CGImageRelease(img); - CGContextRestoreGState(gc); - } -} - -void Fl_Quartz_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ - d &= ~FL_IMAGE_WITH_ALPHA; - innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ - innards(buf,x,y,w,h,d,l,1,0,0,gc_,this); -} -void Fl_Quartz_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, - int x, int y, int w, int h,int d) { - innards(0,x,y,w,h,d,0,1,cb,data,gc_,this); -} - - -void Fl_Quartz_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (!bm->array) { - draw_empty(bm, XP, YP); - return; - } - if (start_image(bm, XP,YP,WP,HP,cx,cy,X,Y,W,H)) return; - if (!*id(bm)) - cache(bm); - - if (*Fl_Graphics_Driver::id(bm) && gc_) { - draw_CGImage((CGImageRef)*Fl_Graphics_Driver::id(bm), X,Y,W,H, cx, cy, bm->w(), bm->h()); - } -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_RGB_Image *rgb) { - CGColorSpaceRef lut = rgb->d()<=2 ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); - int ld = rgb->ld(); - if (!ld) ld = rgb->data_w() * rgb->d(); - CGDataProviderRef src; - if ( has_feature(PRINTER) ) { - // When printing or copying to clipboard, the data at rgb->array are used when - // the PDF page is completed, that is, after return from this function. - // At that stage, the rgb object has possibly been deleted. It is therefore necessary - // to use a copy of rgb->array. The mask_ member of rgb - // is used to avoid repeating the copy operation if rgb is drawn again. - // The CGImage data provider deletes the copy at the latest of these two events: - // deletion of rgb, and completion of the PDF page where rgb was drawn. - size_t total = ld * rgb->data_h(); - uchar *copy = new uchar[total]; - memcpy(copy, rgb->array, total); - src = CGDataProviderCreateWithData(NULL, copy, total, dataReleaseCB); - *Fl_Graphics_Driver::mask(rgb) = 1; - } else { - // the CGImage data provider must not release the image data. - src = CGDataProviderCreateWithData(NULL, rgb->array, ld * rgb->data_h(), NULL); - } - CGImageRef cgimg = CGImageCreate(rgb->data_w(), rgb->data_h(), 8, rgb->d()*8, ld, - lut, (rgb->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, false, kCGRenderingIntentDefault); - *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)cgimg; - CGColorSpaceRelease(lut); - CGDataProviderRelease(src); -} - -void Fl_Quartz_Graphics_Driver::draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!img->d() || !img->array) { - Fl_Graphics_Driver::draw_empty(img, XP, YP); - return; - } - if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - CGImageRef cgimg = (CGImageRef)*Fl_Graphics_Driver::id(img); - if (cgimg && has_feature(PRINTER) && !*Fl_Graphics_Driver::mask(img)) { - CGImageRelease(cgimg); - *Fl_Graphics_Driver::id(img) = 0; - cgimg = NULL; - } - if (!cgimg) { - cache(img); - cgimg = (CGImageRef)*Fl_Graphics_Driver::id(img); - } - if (cgimg && gc_) { - draw_CGImage(cgimg, X,Y,W,H, cx,cy, img->w(), img->h()); - } -} - -void Fl_Quartz_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (!pxm->data() || !pxm->w()) { - draw_empty(pxm, XP, YP); - return; - } - if ( start_image(pxm, XP,YP,WP,HP,cx,cy,X,Y,W,H) ) return; - if (!*id(pxm)) { - cache(pxm); - } - - CGImageRef cgimg = (CGImageRef)*Fl_Graphics_Driver::id(pxm); - draw_CGImage(cgimg, X,Y,W,H, cx,cy, pxm->w(), pxm->h()); -} - -CGImageRef Fl_Quartz_Graphics_Driver::create_bitmask(int w, int h, const uchar *array) { - static uchar reverse[16] = /* Bit reversal lookup table */ - { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, - 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; - int rowBytes = (w+7)>>3 ; - uchar *bmask = new uchar[rowBytes*h]; - uchar *dst = bmask; - const uchar *src = array; - for ( int i=rowBytes*h; i>0; i--,src++ ) { - *dst++ = ((reverse[*src & 0x0f] & 0xf0) | (reverse[(*src >> 4) & 0x0f] & 0x0f))^0xff; - } - CGDataProviderRef srcp = CGDataProviderCreateWithData( NULL, bmask, rowBytes*h, dataReleaseCB); - CGImageRef id_ = CGImageMaskCreate( w, h, 1, 1, rowBytes, srcp, 0L, false); - CGDataProviderRelease(srcp); - return id_; -} - -void Fl_Quartz_Graphics_Driver::delete_bitmask(fl_uintptr_t bm) { - if (bm) CGImageRelease((CGImageRef)bm); -} - -void Fl_Quartz_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) { - if (id_) { - CGImageRelease((CGImageRef)id_); - id_ = 0; - mask_ = 0; - } -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_Bitmap *bm) { - *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)create_bitmask(bm->data_w(), bm->data_h(), bm->array); -} - - -static void pmProviderRelease (void *ctxt, const void *data, size_t size) { - CFRelease(ctxt); -} - -void Fl_Quartz_Graphics_Driver::cache(Fl_Pixmap *img) { - Fl_Image_Surface *surf = new Fl_Image_Surface(img->data_w(), img->data_h()); - Fl_Surface_Device::push_current(surf); - fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); - Fl_Surface_Device::pop_current(); - CGContextRef src = (CGContextRef)Fl_Graphics_Driver::get_offscreen_and_delete_image_surface(surf); - void *cgdata = CGBitmapContextGetData(src); - int sw = (int)CGBitmapContextGetWidth(src); - int sh = (int)CGBitmapContextGetHeight(src); - CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(src); - CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef src_bytes = CGDataProviderCreateWithData(src, cgdata, sw*sh*4, pmProviderRelease); - CGImageRef cgimg = CGImageCreate( sw, sh, 8, 4*8, 4*sw, lut, alpha, - src_bytes, 0L, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(lut); - CGDataProviderRelease(src_bytes); - *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)cgimg; -} - -void Fl_Quartz_Graphics_Driver::draw_CGImage(CGImageRef cgimg, int x, int y, int w, int h, int srcx, int srcy, int sw, int sh) -{ - CGRect rect = CGRectMake(x, y, w, h); - CGContextSaveGState(gc_); - CGContextClipToRect(gc_, CGRectOffset(rect, -0.5, -0.5 )); - // move graphics context to origin of vertically reversed image - // The 0.5 here cancels the 0.5 offset present in Quartz graphics contexts. - // Thus, image and surface pixels are in phase. - CGContextTranslateCTM(gc_, rect.origin.x - srcx - 0.5, rect.origin.y - srcy + sh - 0.5); - CGContextScaleCTM(gc_, 1, -1); - CGContextDrawImage(gc_, CGRectMake(0, 0, sw, sh), cgimg); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::uncache_pixmap(fl_uintptr_t pixmap_ref) { - CGImageRelease((CGImageRef)pixmap_ref); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx deleted file mode 100644 index 6a63ae483..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx +++ /dev/null @@ -1,83 +0,0 @@ -// -// Line style code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/fl_draw.H> -#include <FL/platform.H> - - -/** - \file quartz_line_style.cxx - \brief Line style drawing utility hiding different platforms. -*/ - -#include "Fl_Quartz_Graphics_Driver.H" - -void Fl_Quartz_Graphics_Driver::quartz_restore_line_style() { - CGContextSetLineWidth(gc_, quartz_line_width_); - CGContextSetLineCap(gc_, quartz_line_cap_); - CGContextSetLineJoin(gc_, quartz_line_join_); - CGContextSetLineDash(gc_, 0, quartz_line_pattern, quartz_line_pattern_size); -} - -void Fl_Quartz_Graphics_Driver::line_style(int style, int width, char* dashes) { - - static CGLineCap Cap[4] = { kCGLineCapButt, kCGLineCapButt, - kCGLineCapRound, kCGLineCapSquare }; - static CGLineJoin Join[4] = { kCGLineJoinMiter, kCGLineJoinMiter, - kCGLineJoinRound, kCGLineJoinBevel }; - if (width<1) width = 1; - quartz_line_width_ = (float)width; - quartz_line_cap_ = Cap[(style>>8)&3]; - // when printing kCGLineCapSquare seems better for solid lines - if ( Fl_Surface_Device::surface() != Fl_Display_Device::display_device() - && style == FL_SOLID && dashes == NULL ) - { - quartz_line_cap_ = kCGLineCapSquare; - } - quartz_line_join_ = Join[(style>>12)&3]; - char *d = dashes; - static CGFloat pattern[16]; - if (d && *d) { - CGFloat *pDst = pattern; - while (*d) { *pDst++ = (float)*d++; } - quartz_line_pattern = pattern; - quartz_line_pattern_size = (int)(d-dashes); - } else if (style & 0xff) { - char dash, dot, gap; - // adjust lengths to account for cap: - if (style & 0x200) { - dash = char(2*width); - dot = 1; - gap = char(2*width-1); - } else { - dash = char(3*width); - dot = gap = char(width); - } - CGFloat *pDst = pattern; - switch (style & 0xff) { - case FL_DASH: *pDst++ = dash; *pDst++ = gap; break; - case FL_DOT: *pDst++ = dot; *pDst++ = gap; break; - case FL_DASHDOT: *pDst++ = dash; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; break; - case FL_DASHDOTDOT: *pDst++ = dash; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; *pDst++ = dot; *pDst++ = gap; break; - } - quartz_line_pattern_size = (int)(pDst-pattern); - quartz_line_pattern = pattern; - } else { - quartz_line_pattern = 0; - quartz_line_pattern_size = 0; - } - quartz_restore_line_style(); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx deleted file mode 100644 index 234853ad6..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx +++ /dev/null @@ -1,310 +0,0 @@ -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <FL/Fl.H> -#include <FL/platform.H> -#include <math.h> - - -/** - \file quartz_rect.cxx - \brief Apple Quartz specific line and polygon drawing with integer coordinates. -*/ - - -#include "Fl_Quartz_Graphics_Driver.H" - - -// --- line and polygon drawing with integer coordinates - -void Fl_Quartz_Graphics_Driver::point(int x, int y) { - CGContextFillRect(gc_, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); -} - -void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - double offset = (quartz_line_width_ >= 2 ? quartz_line_width_/4 : 0); - CGRect rect = CGRectMake(x - offset, y - offset, w-1, h-1); - CGContextStrokeRect(gc_, rect); -} - -void Fl_Quartz_Graphics_Driver::focus_rect(int x, int y, int w, int h) -{ - CGContextSaveGState(gc_); - float s = scale(); - CGContextScaleCTM(gc_, 1/s, 1/s); - CGFloat lw = (s >= 1 ? floor(s) : 1); - CGContextSetLineWidth(gc_, lw); - CGFloat dots[2] = {lw, lw}; - CGContextSetLineDash(gc_, 0, dots, 2); - CGContextStrokeRect(gc_, CGRectMake(x*s, y*s, (w-1)*s, (h-1)*s)); - CGContextRestoreGState(gc_); -} - -void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); - CGContextFillRect(gc_, rect); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit - (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles - of size one unit by line-width. - */ - CGContextFillRect(gc_, CGRectMake(x-0.5 , y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x1-0.5 , y - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextAddLineToPoint(gc_, x1, y2); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x1 - quartz_line_width_/2, y2-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y); - CGContextAddLineToPoint(gc_, x1, y2); - CGContextAddLineToPoint(gc_, x3, y2); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); - CGContextFillRect(gc_, CGRectMake(x3-0.5, y2 - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y1-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextAddLineToPoint(gc_, x2, y1); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x2-0.5, y1 - quartz_line_width_/2, 1 , quartz_line_width_)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x, y1); - CGContextAddLineToPoint(gc_, x2, y1); - CGContextAddLineToPoint(gc_, x2, y3); - CGContextStrokePath(gc_); - if (high_resolution() || scale()>=2) { - CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); - CGContextFillRect(gc_, CGRectMake(x2 - quartz_line_width_/2, y3-0.5, quartz_line_width_, 1)); - } - if (has_feature(PRINTER) || quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextAddLineToPoint(gc_, x3, y3); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { - float s = scale(); if (s < 2) s = 0; - CGContextSetLineWidth(gc_, 0.05); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x+w-1 +s/8, y); - CGContextAddLineToPoint(gc_, x+w-1 +s/8, y+h-1 -s/8); - CGContextAddLineToPoint(gc_, x, y+h-1 -s/8); - CGContextClosePath(gc_); - CGContextStrokePath(gc_); - CGContextSetLineWidth(gc_, quartz_line_width_); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, x, y); - CGContextAddLineToPoint(gc_, x1, y1); - CGContextAddLineToPoint(gc_, x2, y2); - CGContextAddLineToPoint(gc_, x3, y3); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -// --- clipping - -// intersects current and x,y,w,h rectangle and returns result as a new Fl_Region -static Fl_Region intersect_region_and_rect(Fl_Region current_, int x,int y,int w, int h) -{ - if (current_ == NULL) return Fl_Graphics_Driver::default_driver().XRectangleRegion(x,y,w,h); - struct flCocoaRegion* current = (struct flCocoaRegion*)current_; - CGRect r = Fl_Quartz_Graphics_Driver::fl_cgrectmake_cocoa(x, y, w, h); - struct flCocoaRegion* outr = (struct flCocoaRegion*)malloc(sizeof(struct flCocoaRegion)); - outr->count = current->count; - outr->rects =(CGRect*)malloc(outr->count * sizeof(CGRect)); - int j = 0; - for(int i = 0; i < current->count; i++) { - CGRect test = CGRectIntersection(current->rects[i], r); - if (!CGRectIsEmpty(test)) outr->rects[j++] = test; - } - if (j) { - outr->count = j; - outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect)); - } - else { - Fl_Graphics_Driver::default_driver().XDestroyRegion(outr); - outr = (struct flCocoaRegion*)Fl_Graphics_Driver::default_driver().XRectangleRegion(0,0,0,0); - } - return outr; -} - - -void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { - Fl_Region r; - if (w > 0 && h > 0) { - r = XRectangleRegion(x,y,w,h); - Fl_Region current = rstack[rstackptr]; - if (current) { - XDestroyRegion(r); - r = intersect_region_and_rect(current, x,y,w,h); - } - } else { // make empty clip region: - r = XRectangleRegion(0,0,0,0); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); - restore_clip(); -} - -int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if (!r) return 0; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - CGRect u = CGRectMake(0,0,0,0); - CGRect test; - for (int i = 0; i < r->count; i++) { - test = CGRectIntersection(r->rects[i], arg); - if ( !CGRectIsEmpty(test) ) { - if(CGRectIsEmpty(u)) u = test; - else u = CGRectUnion(u, test); - } - } - X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() - Y = int(u.origin.y + 0.5); - W = int(u.size.width + 0.5); // round to nearest integer - H = int(u.size.height + 0.5); - if (CGRectIsEmpty(u)) W = H = 0; - return !CGRectEqualToRect(arg, u); -} - -int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if (!r) return 1; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - for (int i = 0; i < r->count; i++) { - CGRect test = CGRectIntersection(r->rects[i], arg); - if (!CGRectIsEmpty(test)) return 1; - } - return 0; -} - -void Fl_Quartz_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - struct flCocoaRegion* r = (struct flCocoaRegion*)rstack[rstackptr]; - if ( fl_window || gc_ ) { // clipping for a true window or an offscreen buffer - if (gc_) { - CGContextRestoreGState(gc_); - CGContextSaveGState(gc_); - } - color(color()); - quartz_restore_line_style(); - if (r) { //apply program clip - CGContextClipToRects(gc_, r->rects, r->count); - } - } -} diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx deleted file mode 100644 index 16c6c6c29..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx +++ /dev/null @@ -1,98 +0,0 @@ -// -// Portable drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file quartz_vertex.cxx - \brief Portable drawing code for drawing arbitrary shapes with - simple 2D transformations, implemented for OS X Quartz. -*/ - -#include "Fl_Quartz_Graphics_Driver.H" - -#include <FL/fl_draw.H> -#include <FL/platform.H> -#include <FL/math.h> - - -void Fl_Quartz_Graphics_Driver::end_points() { - for (int i = 0; i < n; i++) { - point(xpoint[i].x, xpoint[i].y); - } -} - -void Fl_Quartz_Graphics_Driver::end_line() { - if (n < 2) { - end_points(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextStrokePath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::end_polygon() { - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::end_complex_polygon() { - gap(); - if (n < 3) { - end_line(); - return; - } - if (n<=1) return; - CGContextSetShouldAntialias(gc_, true); - CGContextMoveToPoint(gc_, xpoint[0].x, xpoint[0].y); - for (int i=1; i<n; i++) - CGContextAddLineToPoint(gc_, xpoint[i].x, xpoint[i].y); - CGContextClosePath(gc_); - CGContextFillPath(gc_); - CGContextSetShouldAntialias(gc_, false); -} - -void Fl_Quartz_Graphics_Driver::circle(double x, double y,double r) { - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - - // Quartz warning: circle won't scale to current matrix! - // Last argument must be 0 (counter-clockwise) or it draws nothing under __LP64__ !!!! - CGContextSetShouldAntialias(gc_, true); - CGContextAddArc(gc_, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 0); - (what == POLYGON ? CGContextFillPath : CGContextStrokePath)(gc_); - CGContextSetShouldAntialias(gc_, false); -} diff --git a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H deleted file mode 100644 index 3849ea4df..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.H +++ /dev/null @@ -1,38 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_QUARTZ_IMAGE_SURFACE_DRIVER_H -#define FL_QUARTZ_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> -#include <FL/platform.H> - -class Fl_Quartz_Image_Surface_Driver : public Fl_Image_Surface_Driver { -private: - CGImageRef mask_; - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - void end_current() FL_OVERRIDE; -public: - FLWindow *pre_window; - Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_Quartz_Image_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; -}; - -#endif // FL_QUARTZ_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx deleted file mode 100644 index 4615ba475..000000000 --- a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx +++ /dev/null @@ -1,167 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include <FL/fl_draw.H> -#include "Fl_Quartz_Image_Surface_Driver.H" -#include "Fl_Quartz_Graphics_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" -#include <ApplicationServices/ApplicationServices.h> - - -Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - mask_ = NULL; - int W = w, H = h; - float s = 1; - if (high_res) { - s = Fl_Graphics_Driver::default_driver().scale(); - Fl_Window *cw = Fl::first_window(); - Fl_Cocoa_Window_Driver *dr = cw ? Fl_Cocoa_Window_Driver::driver(cw) : NULL; - if (dr && dr->mapped_to_retina()) s *= 2; - W *= s; H *= s; - } - CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); - offscreen = off ? off : (Fl_Offscreen)CGBitmapContextCreate(calloc(W*H,4), W, H, 8, W*4, lut, kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(lut); - driver(new Fl_Quartz_Graphics_Driver); - CGContextTranslateCTM((CGContextRef)offscreen, 0.5*s, -0.5*s); // as when drawing to a window - if (high_res) { - CGContextScaleCTM((CGContextRef)offscreen, s, s); - driver()->scale(s); - } - CGContextSetShouldAntialias((CGContextRef)offscreen, false); - CGContextTranslateCTM((CGContextRef)offscreen, 0, height); - CGContextScaleCTM((CGContextRef)offscreen, 1.0f, -1.0f); - CGContextSaveGState((CGContextRef)offscreen); - CGContextSetRGBFillColor((CGContextRef)offscreen, 1, 1, 1, 0); - CGContextFillRect((CGContextRef)offscreen, CGRectMake(0,0,w,h)); -} - -Fl_Quartz_Image_Surface_Driver::~Fl_Quartz_Image_Surface_Driver() { - if (mask_) { - CGImageRelease(mask_); - } - if (offscreen) CGContextRestoreGState((CGContextRef)offscreen); - if (offscreen && !external_offscreen) { - void *data = CGBitmapContextGetData((CGContextRef)offscreen); - free(data); - CGContextRelease((CGContextRef)offscreen); - } - delete driver(); -} - - -void Fl_Quartz_Image_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - pre_window = fl_window; - driver()->gc((CGContextRef)offscreen); - fl_window = 0; - ((Fl_Quartz_Graphics_Driver*)driver())->high_resolution( CGBitmapContextGetWidth((CGContextRef)offscreen) > (size_t)width ); - if (mask_) { - int W, H; - printable_rect(&W, &H); - CGContextSaveGState((CGContextRef)offscreen); - CGContextClipToMask((CGContextRef)offscreen, CGRectMake(0,0,W,H), mask_); // 10.4 - CGContextSaveGState((CGContextRef)offscreen); - } -} - -void Fl_Quartz_Image_Surface_Driver::translate(int x, int y) { - CGContextRestoreGState((CGContextRef)offscreen); - CGContextSaveGState((CGContextRef)offscreen); - CGContextTranslateCTM((CGContextRef)offscreen, x, y); - CGContextSaveGState((CGContextRef)offscreen); -} - -void Fl_Quartz_Image_Surface_Driver::untranslate() { - CGContextRestoreGState((CGContextRef)offscreen); -} - -Fl_RGB_Image* Fl_Quartz_Image_Surface_Driver::image() -{ - CGContextFlush((CGContextRef)offscreen); - if (mask_) { - CGContextRestoreGState((CGContextRef)offscreen); - CGImageRelease(mask_); - mask_ = NULL; - } - int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen); - int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen); - int bpr = (int)CGBitmapContextGetBytesPerRow((CGContextRef)offscreen); - int bpp = (int)CGBitmapContextGetBitsPerPixel((CGContextRef)offscreen)/8; - uchar *base = (uchar*)CGBitmapContextGetData((CGContextRef)offscreen); - int idx, idy; - uchar *pdst, *psrc; - unsigned char *data = new uchar[W * H * 3]; - for (idy = 0, pdst = data; idy < H; idy ++) { - for (idx = 0, psrc = base + idy * bpr; idx < W; idx ++, psrc += bpp, pdst += 3) { - pdst[0] = psrc[0]; // R - pdst[1] = psrc[1]; // G - pdst[2] = psrc[2]; // B - } - } - Fl_RGB_Image *image = new Fl_RGB_Image(data, W, H); - image->alloc_array = 1; - return image; -} - -void Fl_Quartz_Image_Surface_Driver::end_current() -{ - if (mask_) { - CGContextRestoreGState((CGContextRef)offscreen); - CGContextRestoreGState((CGContextRef)offscreen); - } - fl_window = pre_window; - Fl_Surface_Device::end_current(); -} - - -static void MyProviderReleaseData (void *info, const void *data, size_t size) { - delete[] (uchar*)data; -} - - -void Fl_Quartz_Image_Surface_Driver::mask(const Fl_RGB_Image *img) { - if (!&CGContextClipToMask) return; - int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen); - int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen); - bool using_copy = false; - if (W != img->data_w() || H != img->data_h()) { - Fl_RGB_Image *copy = (Fl_RGB_Image*)img->copy(W, H); - img = copy; - using_copy = true; - } - - int i, d = img->d(), w = img->data_w(), h = img->data_h(); - // reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits - int bytes_per_row = (img->ld() ? img->ld() : w * d); - uchar *from = new uchar[w * h]; - for ( i = 0; i < h; i++) { - const uchar *p = img->array + bytes_per_row * i; - const uchar *last = p + bytes_per_row; - uchar *q = from + (h - 1 - i) * w; - while (p < last) { - unsigned u = *p++; - u += *p++; - u += *p++; - *q++ = ~(u/3); - } - } - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, w * h, MyProviderReleaseData); - mask_ = CGImageMaskCreate(w, h, 8, 8, w, provider, NULL, false); - CFRelease(provider); - if (using_copy) delete img; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H deleted file mode 100644 index e10a801ce..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_COPY_SURFACE_DRIVER_H -#define FL_WAYLAND_COPY_SURFACE_DRIVER_H - -#include <FL/Fl_Copy_Surface.H> -#include <FL/Fl_Image_Surface.H> - -class Fl_Wayland_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { - friend class Fl_Copy_Surface_Driver; - Fl_Image_Surface *img_surf; -protected: - Fl_Wayland_Copy_Surface_Driver(int w, int h); - ~Fl_Wayland_Copy_Surface_Driver(); - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; -}; - -#endif // FL_WAYLAND_COPY_SURFACE_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx deleted file mode 100644 index 043114781..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Copy_Surface_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" - - -Fl_Wayland_Copy_Surface_Driver::Fl_Wayland_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { - float os_scale = Fl_Graphics_Driver::default_driver().scale(); - int d = 1; - if (Fl::first_window()) { - d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale(); - } - img_surf = new Fl_Image_Surface(int(w * os_scale) * d, int(h * os_scale) * d); - driver(img_surf->driver()); - driver()->scale(d * os_scale); -} - - -Fl_Wayland_Copy_Surface_Driver::~Fl_Wayland_Copy_Surface_Driver() { - Fl_RGB_Image *rgb = img_surf->image(); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - scr_driver->copy_image(rgb->array, rgb->data_w(), rgb->data_h()); - delete rgb; - delete img_surf; - driver(NULL); -} - - -void Fl_Wayland_Copy_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver(); - if (!dr->cr()) dr->set_cairo((cairo_t*)img_surf->offscreen()); -} - - -void Fl_Wayland_Copy_Surface_Driver::translate(int x, int y) { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y); -} - - -void Fl_Wayland_Copy_Surface_Driver::untranslate() { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate(); -} diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H deleted file mode 100644 index ad67c01bf..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H +++ /dev/null @@ -1,62 +0,0 @@ -// -// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_GL_WINDOW_DRIVER_H -#define FL_WAYLAND_GL_WINDOW_DRIVER_H - -#include <config.h> -#if HAVE_GL -#include "../../Fl_Gl_Window_Driver.H" -#include <wayland-egl.h> -#include <EGL/egl.h> -#include <FL/gl.h> - - -class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - friend class Fl_Wayland_Gl_Plugin; -private: - static EGLDisplay egl_display; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; - bool need_swap; - Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win); - float pixels_per_unit() FL_OVERRIDE; - void make_current_before() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void resize(int is_a_resize, int w, int h) FL_OVERRIDE; - char swap_type() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void gl_start() FL_OVERRIDE; - void gl_visual(Fl_Gl_Choice *c) FL_OVERRIDE; - void init(); - void* GetProcAddress(const char *procName) FL_OVERRIDE; -public: - static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time); - //virtual bool need_scissor() { return true; } // CONTROL_LEAKING_SUB_GL_WINDOWS - //void apply_scissor(); // CONTROL_LEAKING_SUB_GL_WINDOWS -}; - -#endif // HAVE_GL -#endif // FL_WAYLAND_GL_WINDOW_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx deleted file mode 100644 index d20b941b7..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx +++ /dev/null @@ -1,486 +0,0 @@ -// -// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> -#include "../../Fl_Gl_Choice.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Gl_Window_Driver.H" -#include "../Posix/Fl_Posix_System_Driver.H" -#ifdef FLTK_USE_X11 -# include "../X11/Fl_X11_Gl_Window_Driver.H" -#endif -#include <wayland-egl.h> -#include <EGL/egl.h> -#include <FL/gl.h> - -/* Implementation notes about OpenGL drawing on the Wayland platform - -* After eglCreateWindowSurface() with attributes {EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER, EGL_NONE}, -eglQueryContext() reports that EGL_RENDER_BUFFER equals EGL_BACK_BUFFER. -This experiment suggests that the platform only supports double-buffer drawing. -Consequently, FL_DOUBLE is enforced in all Fl_Gl_Window::mode_ values under Wayland. - -* Commented out code marked with CONTROL_LEAKING_SUB_GL_WINDOWS aims to prevent - sub GL windows from leaking out from their parent by making leaking parts fully transparent. - This code is commented out because it requires the FL_ALPHA flag to be on - which not all client applications do. -*/ - -// Describes crap needed to create a GLContext. -class Fl_Wayland_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_Wayland_Gl_Window_Driver; -private: - EGLConfig egl_conf; -public: - Fl_Wayland_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - egl_conf = 0; - } -}; - - -struct gl_start_support { // to support use of gl_start / gl_finish - struct wl_surface *surface; - struct wl_subsurface *subsurface; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; -}; - - -static EGLConfig wld_egl_conf = NULL; -static EGLint swap_interval_ = 1; -static EGLint max_swap_interval = 1000; -static EGLint min_swap_interval = 0; - - -EGLDisplay Fl_Wayland_Gl_Window_Driver::egl_display = EGL_NO_DISPLAY; - - -Fl_Wayland_Gl_Window_Driver::Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win) : - Fl_Gl_Window_Driver(win) { - if (egl_display == EGL_NO_DISPLAY) init(); - egl_window = NULL; - egl_surface = NULL; - need_swap = false; -} - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ -#ifdef FLTK_USE_X11 - if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_X11_Gl_Window_Driver(w); -#endif - return new Fl_Wayland_Gl_Window_Driver(w); -} - - -void Fl_Wayland_Gl_Window_Driver::init() { - EGLint major, minor; - - if (!fl_wl_display()) fl_open_display(); - egl_display = eglGetDisplay((EGLNativeDisplayType) fl_wl_display()); - if (egl_display == EGL_NO_DISPLAY) { - Fl::fatal("Can't create egl display\n"); - } - - if (eglInitialize(egl_display, &major, &minor) != EGL_TRUE) { - Fl::fatal("Can't initialise egl display\n"); - } - //printf("EGL major: %d, minor %d\n", major, minor); - //eglGetConfigs(egl_display, NULL, 0, &configs_count); - //printf("EGL has %d configs\n", configs_count); - eglBindAPI(EGL_OPENGL_API); -} - - -Fl_Gl_Choice *Fl_Wayland_Gl_Window_Driver::find(int m, const int *alistp) -{ - m |= FL_DOUBLE; - //if (pWindow->parent()) m |= FL_ALPHA; // CONTROL_LEAKING_SUB_GL_WINDOWS - Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)Fl_Gl_Window_Driver::find_begin( - m, alistp); - if (g) return g; - - EGLint n; - EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_DEPTH_SIZE, 0, // set at 11 - EGL_SAMPLE_BUFFERS, 0, // set at 13 - EGL_STENCIL_SIZE, 0, // set at 15 - EGL_ALPHA_SIZE, 0, // set at 17 - EGL_NONE - }; - - if (m & FL_DEPTH32) - config_attribs[11] = 32; // request at least 32 bits - else if (m & FL_DEPTH) - config_attribs[11] = 1; // accept any size - - if (m & FL_MULTISAMPLE) config_attribs[13] = 1; - if (m & FL_STENCIL) config_attribs[15] = 1; - if (m & FL_ALPHA) config_attribs[17] = (m & FL_RGB8) ? 8 : 1; - - g = new Fl_Wayland_Gl_Choice(m, alistp, first); - eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n); - if (n == 0 && (m & FL_MULTISAMPLE)) { - config_attribs[13] = 0; - eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n); - } - if (n == 0) { - Fl::fatal("failed to choose an EGL config\n"); - } - - eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MAX_SWAP_INTERVAL, &max_swap_interval); - eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MIN_SWAP_INTERVAL, &min_swap_interval); - - first = g; - return g; -} - - -GLContext Fl_Wayland_Gl_Window_Driver::create_gl_context(Fl_Window* window, - const Fl_Gl_Choice* g) { - GLContext shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - - static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - GLContext ctx = (GLContext)eglCreateContext(egl_display, - ((Fl_Wayland_Gl_Choice*)g)->egl_conf, - (shared_ctx ? (EGLContext)shared_ctx : EGL_NO_CONTEXT), - context_attribs); -//fprintf(stderr, "eglCreateContext=%p shared_ctx=%p\n", ctx, shared_ctx); - if (ctx) { - add_context(ctx); - /* CONTROL_LEAKING_SUB_GL_WINDOWS - if (egl_surface) { - eglMakeCurrent(egl_display, egl_surface, egl_surface, (EGLContext)ctx); - glClearColor(0., 0., 0., 1.); // set opaque black as starting background color - apply_scissor(); - }*/ - } - return ctx; -} - - -void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - struct wld_window *win = fl_wl_xid(w); - if (!win) return; - Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(w); - EGLSurface target_egl_surface = NULL; - if (egl_surface) target_egl_surface = egl_surface; - else if (dr->gl_start_support_) target_egl_surface = dr->gl_start_support_->egl_surface; - if (!target_egl_surface) { // useful for gl_start() - dr->gl_start_support_ = new struct gl_start_support; - float s = Fl::screen_scale(w->screen_num()); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - // the GL scene will be a transparent subsurface above the cairo-drawn surface - dr->gl_start_support_->surface = - wl_compositor_create_surface(scr_driver->wl_compositor); - dr->gl_start_support_->subsurface = wl_subcompositor_get_subsurface( - scr_driver->wl_subcompositor, dr->gl_start_support_->surface, win->wl_surface); - wl_subsurface_set_position(dr->gl_start_support_->subsurface, w->x() * s, w->y() * s); - wl_subsurface_place_above(dr->gl_start_support_->subsurface, win->wl_surface); - dr->gl_start_support_->egl_window = wl_egl_window_create( - dr->gl_start_support_->surface, w->w() * s, w->h() * s); - target_egl_surface = dr->gl_start_support_->egl_surface = eglCreateWindowSurface( - egl_display, wld_egl_conf, dr->gl_start_support_->egl_window, NULL); - } - GLContext current_context = eglGetCurrentContext(); - if (context != current_context || w != cached_window) { - cached_window = w; - if (eglMakeCurrent(egl_display, target_egl_surface, target_egl_surface, - (EGLContext)context)) { -//fprintf(stderr, "EGLContext %p made current\n", context); - } else { - Fl::error("eglMakeCurrent() failed\n"); - } - } - if (!(mode() & FL_ALPHA)) { // useful at least for Linux on MacBook hardware - GLfloat vals[4]; - glGetFloatv(GL_COLOR_CLEAR_VALUE, vals); - if (vals[3] == 0.) glClearColor(vals[0], vals[1], vals[2], 1.); - } -} - -/* CONTROL_LEAKING_SUB_GL_WINDOWS -void Fl_Wayland_Gl_Window_Driver::apply_scissor() { - cairo_rectangle_int_t *extents = Fl_Wayland_Window_Driver::driver(pWindow)->subRect(); - if (extents) { - glDisable(GL_SCISSOR_TEST); - GLdouble vals[4]; - glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(vals[0], vals[1], vals[2], vals[3]); - float s = pWindow->pixels_per_unit(); - glScissor(s*extents->x, s*extents->y, s*extents->width, s*extents->height); -//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - glEnable(GL_SCISSOR_TEST); - } -}*/ - - -void Fl_Wayland_Gl_Window_Driver::delete_gl_context(GLContext context) { - GLContext current_context = eglGetCurrentContext(); - if (current_context == context) { - cached_window = 0; - } - if (current_context == (EGLContext)context) { - eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - eglDestroyContext(egl_display, (EGLContext)context); - eglDestroySurface(egl_display, egl_surface); - egl_surface = NULL; - wl_egl_window_destroy(egl_window); - egl_window = NULL; - del_context(context); -} - - -void Fl_Wayland_Gl_Window_Driver::make_overlay_current() { - glDrawBuffer(GL_FRONT); -} - - -void Fl_Wayland_Gl_Window_Driver::redraw_overlay() { - pWindow->redraw(); -} - - -void Fl_Wayland_Gl_Window_Driver::make_current_before() { - if (!egl_window) { - struct wld_window *win = fl_wl_xid(pWindow); - struct wl_surface *surface = win->wl_surface; - int W = pWindow->pixel_w(); - int H = pWindow->pixel_h(); - int scale = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale(); - egl_window = wl_egl_window_create(surface, (W/scale)*scale, (H/scale)*scale); - if (egl_window == EGL_NO_SURFACE) { - Fl::fatal("Can't create egl window with wl_egl_window_create()\n"); - } - Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)this->g(); - egl_surface = eglCreateWindowSurface(egl_display, g->egl_conf, egl_window, NULL); - wl_surface_set_buffer_scale(surface, scale); - if (mode() & FL_ALPHA) wl_surface_set_opaque_region(surface, NULL); - // Tested apps: shape, glpuzzle, cube, fractals, gl_overlay, fullscreen, unittests, - // OpenGL3-glut-test, OpenGL3test. - // Tested wayland compositors: mutter, kde-plasma, weston, sway on FreeBSD. - if (pWindow->parent()) win = fl_wl_xid(pWindow->top_window()); - while (wl_list_empty(&win->outputs)) wl_display_dispatch(fl_wl_display()); - } -} - - -float Fl_Wayland_Gl_Window_Driver::pixels_per_unit() -{ - int ns = pWindow->screen_num(); - int wld_scale = (pWindow->shown() ? - Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale() : 1); - return wld_scale * Fl::screen_driver()->scale(ns); -} - - -int Fl_Wayland_Gl_Window_Driver::mode_(int m, const int *a) { - mode(m | FL_DOUBLE); - return 1; -} - - -void Fl_Wayland_Gl_Window_Driver::surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - Fl_Wayland_Gl_Window_Driver *gl_dr = (Fl_Wayland_Gl_Window_Driver *)data; - wl_callback_destroy(cb); - struct wld_window *window = fl_wl_xid(gl_dr->pWindow); - window->frame_cb = NULL; - if (gl_dr->need_swap) { - eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, gl_dr->egl_surface); - gl_dr->need_swap = false; - } -} - - -static const struct wl_callback_listener surface_frame_listener = { - .done = Fl_Wayland_Gl_Window_Driver::surface_frame_done, -}; - - -void Fl_Wayland_Gl_Window_Driver::swap_buffers() { - if (overlay()) { - static bool overlay_buffer = true; - int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); - GLint matrixmode; - GLfloat pos[4]; - glGetIntegerv(GL_MATRIX_MODE, &matrixmode); - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos - glMatrixMode(GL_PROJECTION); // save proj/model matrices - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(2.0f/wo, 2.0f/ho, 1.0f); - glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of window - glRasterPos2i(0,0); // set glRasterPos to bottom left corner - { - // Emulate overlay by doing copypixels - glReadBuffer(overlay_buffer?GL_BACK:GL_FRONT); - glDrawBuffer(overlay_buffer?GL_FRONT:GL_BACK); - overlay_buffer = ! overlay_buffer; - glCopyPixels(0, 0, wo, ho, GL_COLOR); - } - glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(matrixmode); - glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos - if (!overlay_buffer) return; // don't call eglSwapBuffers until overlay has been drawn - } - - if (egl_surface) { - Fl_Window *parent = pWindow->parent() ? pWindow->window() : NULL; - struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL; - if (parent_xid) { // issue #967 - struct wld_window *xid = fl_wl_xid(pWindow); - if (xid->frame_cb) { - need_swap = true; - return; - } - if (!parent_xid->frame_cb) { - xid->frame_cb = wl_surface_frame(xid->wl_surface); - wl_callback_add_listener(xid->frame_cb, &surface_frame_listener, this); - } - } - eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, egl_surface); - need_swap = false; - } -} - - -class Fl_Wayland_Gl_Plugin : public Fl_Wayland_Plugin { -public: - Fl_Wayland_Gl_Plugin() : Fl_Wayland_Plugin(name()) { } - const char *name() FL_OVERRIDE { return "gl.wayland.fltk.org"; } - void do_swap(Fl_Window *w) FL_OVERRIDE { - Fl_Gl_Window_Driver *gldr = Fl_Gl_Window_Driver::driver(w->as_gl_window()); - if (gldr->overlay() == w) gldr->swap_buffers(); - } - void invalidate(Fl_Window *w) FL_OVERRIDE { - w->as_gl_window()->valid(0); - } - void terminate() FL_OVERRIDE { - if (Fl_Wayland_Gl_Window_Driver::egl_display != EGL_NO_DISPLAY) { - eglTerminate(Fl_Wayland_Gl_Window_Driver::egl_display); - } - } - void destroy(struct gl_start_support *gl_start_support_) FL_OVERRIDE { - eglDestroySurface(Fl_Wayland_Gl_Window_Driver::egl_display, - gl_start_support_->egl_surface); - wl_egl_window_destroy(gl_start_support_->egl_window); - wl_subsurface_destroy(gl_start_support_->subsurface); - wl_surface_destroy(gl_start_support_->surface); - delete gl_start_support_; - } -}; - - -static Fl_Wayland_Gl_Plugin Gl_Overlay_Plugin; - - -/* CONTROL_LEAKING_SUB_GL_WINDOWS -static void delayed_scissor(Fl_Wayland_Gl_Window_Driver *dr) { - dr->apply_scissor(); -}*/ - - -void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { - if (!egl_window) return; - float f = Fl::screen_scale(pWindow->screen_num()); - int s = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale(); - W = int(W * f) * s; // W, H must be multiples of int s - H = int(H * f) * s; - int W2, H2; - wl_egl_window_get_attached_size(egl_window, &W2, &H2); - if (W2 != W || H2 != H) { - struct wld_window *xid = fl_wl_xid(pWindow); - if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && !xid->frame_cb) { - xid->frame_cb = wl_surface_frame(xid->wl_surface); - wl_callback_add_listener(xid->frame_cb, - Fl_Wayland_Graphics_Driver::p_surface_frame_listener, xid); - } - wl_egl_window_resize(egl_window, W, H, 0, 0); - wl_surface_set_buffer_scale(xid->wl_surface, s); - } - /* CONTROL_LEAKING_SUB_GL_WINDOWS - if (Fl_Wayland_Window_Driver::driver(pWindow)->subRect()) { - pWindow->redraw(); - Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_scissor, this); - }*/ -} - - -char Fl_Wayland_Gl_Window_Driver::swap_type() { - return copy; -} - - -void Fl_Wayland_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) { - Fl_Gl_Window_Driver::gl_visual(c); - wld_egl_conf = ((Fl_Wayland_Gl_Choice*)c)->egl_conf; -} - - -void Fl_Wayland_Gl_Window_Driver::gl_start() { - float f = Fl::screen_scale(Fl_Window::current()->screen_num()); - int W = Fl_Window::current()->w() * f; - int H = Fl_Window::current()->h() * f; - int W2, H2; - Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(Fl_Window::current()); - wl_egl_window_get_attached_size(dr->gl_start_support_->egl_window, &W2, &H2); - if (W2 != W || H2 != H) { - wl_egl_window_resize(dr->gl_start_support_->egl_window, W, H, 0, 0); - } - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); -} - -void Fl_Wayland_Gl_Window_Driver::swap_interval(int interval) { - if (interval < min_swap_interval) interval = min_swap_interval; - if (interval > max_swap_interval) interval = max_swap_interval; - if (egl_display && eglSwapInterval(egl_display, interval)) - swap_interval_ = interval; - // printf("swap_interval_=%d\n",swap_interval_); -} - - -int Fl_Wayland_Gl_Window_Driver::swap_interval() const { - return swap_interval_; -} - - -void* Fl_Wayland_Gl_Window_Driver::GetProcAddress(const char *procName) { - return Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, procName); -} - - -FL_EXPORT EGLContext fl_wl_glcontext(GLContext rc) { return (EGLContext)rc; } - -#endif // HAVE_GL diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H deleted file mode 100644 index ac8786a47..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ /dev/null @@ -1,72 +0,0 @@ -// -// Definition of class Fl_Wayland_Graphics_Driver. -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Graphics_Driver.H - \brief Definition of Wayland graphics driver. - */ - -#ifndef FL_WAYLAND_GRAPHICS_DRIVER_H -#define FL_WAYLAND_GRAPHICS_DRIVER_H - -#include "../Cairo/Fl_Cairo_Graphics_Driver.H" -#include <stdint.h> // for uint32_t -#include <wayland-client.h> // for wl_list - - -class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver { -public: - struct draw_buffer { - unsigned char *buffer; - cairo_t *cairo_; - size_t data_size; // of wl_buffer and buffer - int stride; - int width; - }; - struct wld_buffer { - struct draw_buffer draw_buffer; - struct wl_list link; // links all buffers from the same wl_shm_pool - struct wl_buffer *wl_buffer; - void *data; - struct wl_shm_pool *shm_pool; - bool draw_buffer_needs_commit; - bool in_use; // true while being committed - bool released; // true after buffer_release() was called - }; - struct wld_shm_pool_data { // one record attached to each wl_shm_pool object - char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool - size_t pool_size; // size of encapsulated memory - struct wl_list buffers; // to list of fl_wld_buffer's from this pool - }; - static const uint32_t wld_format; - static struct wl_shm_pool *current_pool; - static FL_EXPORT const struct wl_callback_listener *p_surface_frame_listener; - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, - int srcx, int srcy) FL_OVERRIDE; - void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE; - static struct wld_buffer *create_wld_buffer(int width, int height, bool with_shm = true); - static void create_shm_buffer(wld_buffer *buffer); - static void buffer_release(struct wld_window *window); - static void buffer_commit(struct wld_window *window, cairo_region_t *r = NULL); - static void cairo_init(struct draw_buffer *buffer, int width, int height, int stride, - cairo_format_t format); - // used by class Fl_Wayland_Gl_Window_Driver - static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen); - static const cairo_user_data_key_t key; - static Fl_Image_Surface *custom_offscreen(int w, int h, struct wld_buffer **buffer); -}; - -#endif // FL_WAYLAND_GRAPHICS_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx deleted file mode 100644 index 5c9539a8c..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ /dev/null @@ -1,310 +0,0 @@ -// -// Implementation of the Wayland graphics driver. -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include <sys/mman.h> -#include <unistd.h> // for close() -#include <errno.h> -#include <string.h> // for strerror() -#include <cairo/cairo.h> - -extern "C" { -# include "../../../libdecor/src/os-compatibility.h" // for libdecor_os_create_anonymous_file() -} - -// used by create_shm_buffer and do_buffer_release -struct wl_shm_pool *Fl_Wayland_Graphics_Driver::current_pool = NULL; - - -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *); - - -static void buffer_release_listener(void *user_data, struct wl_buffer *wl_buffer) -{ - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = - (struct Fl_Wayland_Graphics_Driver::wld_buffer*)user_data; - buffer->in_use = false; - if (buffer->released) do_buffer_release(buffer); -} - - -static const struct wl_buffer_listener buffer_listener = { - buffer_release_listener -}; - - -void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - int width = buffer->draw_buffer.width; - int stride = buffer->draw_buffer.stride; - int height = buffer->draw_buffer.data_size / stride; - const size_t default_pool_size = 10000000; // larger pools are possible if needed - int chunk_offset = 0; // offset to start of available memory in pool - struct wld_shm_pool_data *pool_data = current_pool ? // data record attached to current pool - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(current_pool) : NULL; - size_t pool_size = current_pool ? pool_data->pool_size : default_pool_size; // current pool size - if (current_pool && !wl_list_empty(&pool_data->buffers)) { - // last wld_buffer created from current pool - struct wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); - chunk_offset = ((char*)record->data - pool_data->pool_memory) + - record->draw_buffer.data_size; - } - if (!current_pool || chunk_offset + buffer->draw_buffer.data_size > pool_size) { - // if true, a new pool is needed - if (current_pool && wl_list_empty(&pool_data->buffers)) { - wl_shm_pool_destroy(current_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); -// printf("create_shm_buffer munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - chunk_offset = 0; - pool_size = default_pool_size; - if (buffer->draw_buffer.data_size > pool_size) - pool_size = 2 * buffer->draw_buffer.data_size; // a larger pool is needed - int fd = libdecor_os_create_anonymous_file(pool_size); - if (fd < 0) { - Fl::fatal("libdecor_os_create_anonymous_file failed: %s\n", strerror(errno)); - } - pool_data = (struct wld_shm_pool_data*)calloc(1, sizeof(struct wld_shm_pool_data)); - pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (pool_data->pool_memory == MAP_FAILED) { - close(fd); - Fl::fatal("mmap failed: %s\n", strerror(errno)); - } - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - current_pool = wl_shm_create_pool(scr_driver->wl_shm, fd, (int32_t)pool_size); - close(fd); // does not prevent the mmap'ed memory from being used - //printf("wl_shm_create_pool %p size=%lu\n",pool_data->pool_memory , pool_size); - pool_data->pool_size = pool_size; - wl_list_init(&pool_data->buffers); - wl_shm_pool_set_user_data(current_pool, pool_data); - } - buffer->wl_buffer = wl_shm_pool_create_buffer(current_pool, chunk_offset, - width, height, stride, wld_format); - wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); - // add this buffer to head of list of current pool's buffers - wl_list_insert(&pool_data->buffers, &buffer->link); - buffer->shm_pool = current_pool; - buffer->data = (void*)(pool_data->pool_memory + chunk_offset); -//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset); -//fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size); -} - - -struct Fl_Wayland_Graphics_Driver::wld_buffer * - Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm) { - struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer)); - int stride = cairo_format_stride_for_width(cairo_format, width); - cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format); - buffer->draw_buffer_needs_commit = true; - if (with_shm) create_shm_buffer(buffer); - return buffer; -} - - -// used to support both normal and progressive drawing and for top-level GL windows -static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - struct wld_window *window = (struct wld_window *)data; - wl_callback_destroy(cb); - window->frame_cb = NULL; - if (window->buffer && window->buffer->draw_buffer_needs_commit) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } -} - - -static const struct wl_callback_listener surface_frame_listener = { - .done = surface_frame_done, -}; - - -const struct wl_callback_listener *Fl_Wayland_Graphics_Driver::p_surface_frame_listener = - &surface_frame_listener; - - -// copy pixels in region r from the Cairo surface to the Wayland buffer -static void copy_region(struct wld_window *window, cairo_region_t *r) { - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer; - float f = Fl::screen_scale(window->fl_win->screen_num()); - int d = Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); - int count = cairo_region_num_rectangles(r); - cairo_rectangle_int_t rect; - for (int i = 0; i < count; i++) { - cairo_region_get_rectangle(r, i, &rect); - int left = d * int(rect.x * f); - int top = d * int(rect.y * f); - int right = d * ceil((rect.x + rect.width) * f); - if (right > d * int(window->fl_win->w() * f)) right = d * int(window->fl_win->w() * f); - int width = right - left; - int bottom = d * ceil((rect.y + rect.height) * f); - if (bottom > d * int(window->fl_win->h() * f)) bottom = d * int(window->fl_win->h() * f); - int height = bottom - top; - int offset = top * buffer->draw_buffer.stride + 4 * left; - int W4 = 4 * width; - for (int l = 0; l < height; l++) { - if (offset + W4 >= (int)buffer->draw_buffer.data_size) { - W4 = buffer->draw_buffer.data_size - offset; - if (W4 <= 0) break; - } - memcpy((uchar*)buffer->data + offset, buffer->draw_buffer.buffer + offset, W4); - offset += buffer->draw_buffer.stride; - } - wl_surface_damage_buffer(window->wl_surface, left, top, width, height); - } -} - - -void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r) -{ - if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer); - cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_); - cairo_surface_flush(surf); - if (r) copy_region(window, r); - else { - memcpy(window->buffer->data, window->buffer->draw_buffer.buffer, - window->buffer->draw_buffer.data_size); - wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000); - } - window->buffer->in_use = true; - wl_surface_attach(window->wl_surface, window->buffer->wl_buffer, 0, 0); - wl_surface_set_buffer_scale( window->wl_surface, - Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale() ); - if (!window->covered) { // see issue #878 - window->frame_cb = wl_surface_frame(window->wl_surface); - wl_callback_add_listener(window->frame_cb, p_surface_frame_listener, window); - } - wl_surface_commit(window->wl_surface); - window->buffer->draw_buffer_needs_commit = false; -} - - -void Fl_Wayland_Graphics_Driver::cairo_init(struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer, - int width, int height, int stride, - cairo_format_t format) { - buffer->data_size = stride * height; - buffer->stride = stride; - buffer->buffer = new uchar[buffer->data_size]; - buffer->width = width; - cairo_surface_t *surf = cairo_image_surface_create_for_data(buffer->buffer, format, - width, height, stride); - if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Can't create Cairo surface with cairo_image_surface_create_for_data()\n"); - return; - } - buffer->cairo_ = cairo_create(surf); - cairo_status_t err; - if ((err = cairo_status(buffer->cairo_)) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Cairo error during cairo_create() %s\n", cairo_status_to_string(err)); - return; - } - cairo_surface_destroy(surf); - memset(buffer->buffer, 0, buffer->data_size); // useful for transparent windows - cairo_set_source_rgba(buffer->cairo_, .0, .0, .0, 1.0); // Black default color - cairo_save(buffer->cairo_); -} - - -// runs when buffer->in_use is false and buffer->released is true -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - struct wl_shm_pool *my_pool = buffer->shm_pool; - if (buffer->wl_buffer) { - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data = - (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*) - wl_shm_pool_get_user_data(my_pool); - wl_buffer_destroy(buffer->wl_buffer); - // remove wld_buffer from list of pool's buffers - wl_list_remove(&buffer->link); - if (wl_list_empty(&pool_data->buffers) && my_pool != Fl_Wayland_Graphics_Driver::current_pool) { - // all buffers from pool are gone - wl_shm_pool_destroy(my_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); - //printf("do_buffer_release munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - } - free(buffer); -} - - -void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) -{ - if (window->buffer && !window->buffer->released) { - window->buffer->released = true; - if (window->frame_cb) { wl_callback_destroy(window->frame_cb); window->frame_cb = NULL; } - delete[] window->buffer->draw_buffer.buffer; - window->buffer->draw_buffer.buffer = NULL; - cairo_destroy(window->buffer->draw_buffer.cairo_); - if (!window->buffer->in_use) do_buffer_release(window->buffer); - window->buffer = NULL; - } -} - - -// this refers to the same memory layout for pixel data as does CAIRO_FORMAT_ARGB32 -const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888; - - -void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, - Fl_Offscreen src, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of - // the graphics driver's surface - cairo_matrix_t matrix; - cairo_get_matrix(cairo_, &matrix); - double s = matrix.xx; - cairo_save(cairo_); - cairo_rectangle(cairo_, x - 0.5, y - 0.5, w, h); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); - cairo_clip(cairo_); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT); - cairo_surface_t *surf = cairo_get_target((cairo_t *)src); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - cairo_set_source(cairo_, pat); - cairo_matrix_init_scale(&matrix, s, s); - cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy)); - cairo_pattern_set_matrix(pat, &matrix); - cairo_paint(cairo_); - cairo_pattern_destroy(pat); - cairo_restore(cairo_); - surface_needs_commit(); -} - - -const cairo_user_data_key_t Fl_Wayland_Graphics_Driver::key = {}; - - -struct Fl_Wayland_Graphics_Driver::draw_buffer* -Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen offscreen) { - return (struct draw_buffer*)cairo_get_user_data((cairo_t*)offscreen, &key); -} - - -Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h, - struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) { - struct wld_buffer *off = create_wld_buffer(w, h); - *p_off = off; - cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL); - return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_); -} - - -void Fl_Wayland_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) { - Fl_Graphics_Driver::cache_size(img, width, height); - width *= wld_scale; - height *= wld_scale; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H deleted file mode 100644 index ae32ac3df..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H +++ /dev/null @@ -1,40 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WAYLAND_IMAGE_SURFACE_DRIVER_H -#define FL_WAYLAND_IMAGE_SURFACE_DRIVER_H - -#include <FL/Fl_Image_Surface.H> - -class Fl_Wayland_Image_Surface_Driver : public Fl_Image_Surface_Driver { - void end_current() FL_OVERRIDE; - struct wld_window *pre_window; -public: - Fl_Wayland_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); - ~Fl_Wayland_Image_Surface_Driver(); - void mask(const Fl_RGB_Image *) FL_OVERRIDE; - struct shape_data_type { - double scale; - cairo_pattern_t *mask_pattern_; - cairo_t *bg_cr; - } *shape_data_; - void set_current() FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate() FL_OVERRIDE; - Fl_RGB_Image *image() FL_OVERRIDE; -}; - -#endif // FL_WAYLAND_IMAGE_SURFACE_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx deleted file mode 100644 index ec9c56cb7..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx +++ /dev/null @@ -1,185 +0,0 @@ -// -// Draw-to-image code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Image_Surface_Driver.H" - - -Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h, - int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { - shape_data_ = NULL; - float s = 1; - int d = 1; - if (!off) { - fl_open_display(); - if (Fl::first_window()) { - d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale(); - } - s = Fl_Graphics_Driver::default_driver().scale(); - if (d*s != 1 && high_res) { - w = int(w * s) * d; - h = int(h * s) * d; - } - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1, - sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer)); - Fl_Wayland_Graphics_Driver::cairo_init(off_, w, h, - cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w), CAIRO_FORMAT_RGB24); - offscreen = (Fl_Offscreen)off_->cairo_; - cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL); - if (d*s != 1 && high_res) cairo_scale((cairo_t*)offscreen, d*s, d*s); - } - driver(new Fl_Wayland_Graphics_Driver()); - if (d*s != 1 && high_res) driver()->scale(d*s); -} - - -Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() { - if (shape_data_) { - cairo_surface_t *surf; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf); - unsigned char *bits = cairo_image_surface_get_data(surf); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] bits; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr); - delete[] off_->buffer; - free(off_); - cairo_destroy(shape_data_->bg_cr); - free(shape_data_); - } - if (offscreen && !external_offscreen) { - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - cairo_destroy((cairo_t *)offscreen); - delete[] buffer->buffer; - free(buffer); - } - delete driver(); -} - - -void Fl_Wayland_Image_Surface_Driver::set_current() { - Fl_Surface_Device::set_current(); - Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver(); - if (!dr->cr()) dr->set_cairo((cairo_t*)offscreen); - pre_window = Fl_Wayland_Window_Driver::wld_window; - Fl_Wayland_Window_Driver::wld_window = NULL; - fl_window = 0; -} - - -void Fl_Wayland_Image_Surface_Driver::end_current() { - cairo_surface_t *surf = cairo_get_target((cairo_t*)offscreen); - cairo_surface_flush(surf); - Fl_Wayland_Window_Driver::wld_window = pre_window; - fl_window = (Window)pre_window; - Fl_Surface_Device::end_current(); -} - - -void Fl_Wayland_Image_Surface_Driver::translate(int x, int y) { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y); -} - - -void Fl_Wayland_Image_Surface_Driver::untranslate() { - ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate(); -} - - -Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() { - if (shape_data_ && shape_data_->mask_pattern_) { - // draw above the secondary offscreen the main offscreen masked by mask_pattern_ - cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr(); - cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c)); - cairo_set_source(shape_data_->bg_cr, paint_pattern); - cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_); - cairo_pattern_destroy(paint_pattern); - // copy secondary offscreen to the main offscreen - cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr)); - cairo_scale(c, shape_data_->scale, shape_data_->scale); - cairo_set_source(c, pat), - cairo_paint(c); - cairo_pattern_destroy(pat); - // delete secondary offscreen - cairo_surface_t *surf; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf); - unsigned char *bits = cairo_image_surface_get_data(surf); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] bits; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr); - delete[] off_->buffer; - free(off_); - cairo_destroy(shape_data_->bg_cr); - free(shape_data_); - shape_data_ = NULL; - } - - // Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - int height = int(off_buf->data_size / off_buf->stride); - uchar *rgb = new uchar[off_buf->width * height * 3]; - uchar *p = rgb; - uchar *q; - for (int j = 0; j < height; j++) { - q = off_buf->buffer + j*off_buf->stride; - for (int i = 0; i < off_buf->width; i++) { // exchange R and B colors, transmit G - *p = *(q+2); - *(p+1) = *(q+1); - *(p+2) = *q; - p += 3; q += 4; - } - } - Fl_RGB_Image *image = new Fl_RGB_Image(rgb, off_buf->width, height, 3); - image->alloc_array = 1; - return image; -} - - -void Fl_Wayland_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) { - bool using_copy = false; - shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type)); - int W, H; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf = - Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen); - W = off_buf->width; - H = (int)(off_buf->data_size / off_buf->stride); - if (W != mask->data_w() || H != mask->data_h()) { - Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H); - mask = copy; - using_copy = true; - } - shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask); - //duplicate current offscreen content to new cairo_t* shape_data_->bg_cr - int width, height; - printable_rect(&width, &height); - struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ = - (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1, - sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer)); - Fl_Wayland_Graphics_Driver::cairo_init(off_, W, H, - cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, W), - CAIRO_FORMAT_RGB24); - cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL); - shape_data_->bg_cr = off_->cairo_; - memcpy(off_->buffer, off_buf->buffer, off_buf->data_size); - shape_data_->scale = double(width) / W; - if (using_copy) delete mask; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H deleted file mode 100644 index 83efd79a3..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H +++ /dev/null @@ -1,193 +0,0 @@ -// -// Definition of the Wayland Screen interface -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Screen_Driver.H - \brief Definition of Wayland Screen interface - */ - -#ifndef FL_WAYLAND_SCREEN_DRIVER_H -#define FL_WAYLAND_SCREEN_DRIVER_H - -#include <config.h> -#include "../Unix/Fl_Unix_Screen_Driver.H" -#include <wayland-client.h> - -class Fl_Window; - -class Fl_Wayland_Screen_Driver : public Fl_Unix_Screen_Driver -{ -private: - static int insertion_point_x; - static int insertion_point_y; - static int insertion_point_width; - static int insertion_point_height; - static bool insertion_point_location_is_valid; -public: -// type definitions - typedef enum {unspecified, MUTTER, WESTON, KWIN, OWL, WAYFIRE} compositor_name; - struct seat { - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - struct wl_keyboard *wl_keyboard; - uint32_t keyboard_enter_serial; - struct wl_surface *keyboard_surface; - struct wl_list pointer_outputs; - struct wl_cursor_theme *cursor_theme; - struct wl_cursor *default_cursor; - struct wl_surface *cursor_surface; - struct wl_surface *pointer_focus; - int pointer_scale; - uint32_t serial; - uint32_t pointer_enter_serial; - struct wl_data_device_manager *data_device_manager; - struct wl_data_device *data_device; - struct wl_data_source *data_source; - struct xkb_state *xkb_state; - struct xkb_context *xkb_context; - struct xkb_keymap *xkb_keymap; - struct xkb_compose_state *xkb_compose_state; - char *name; - struct zwp_text_input_v3 *text_input; - struct gtk_shell1 *gtk_shell; - }; - struct output { // one record for each screen - uint32_t id; - int x, y; // logical position of screen - int pixel_width; // in pixels - int pixel_height; // in pixels - int width; // in pixels, account for fractional scaling - int height; // in pixels, account for fractional scaling - float dpi; - struct wl_output *wl_output; - int wld_scale; // Wayland scale factor - float gui_scale; // FLTK scale factor - bool done; - struct wl_list link; - }; - enum cursor_shapes {arrow = 0, wait, insert, hand, help, cross, move, - north, south, west, east, north_south, west_east, south_west, south_east, north_east, north_west, nesw, nwse}; - static const int cursor_count = nwse + 1; // nber of elements of 'enum cursor_shapes' - -// static member variables - static FL_EXPORT struct wl_display *wl_display; - static const struct wl_data_device_listener *p_data_device_listener; - // next length of marked text after current marked text will have been replaced - static int next_marked_length; - static compositor_name compositor; // identifies the used Wayland compositor - -// static member functions - static void insertion_point_location(int x, int y, int height); - static bool insertion_point_location(int *px, int *py, int *pwidth, int *pheight); - static bool own_output(struct wl_output *output); - static void do_set_cursor(struct Fl_Wayland_Screen_Driver::seat *, - struct wl_cursor *wl_cursor = NULL, Fl_Cursor c = FL_CURSOR_NONE); -// member variables - struct wl_cursor *xc_cursor[cursor_count]; // one for each element of enum cursor_shapes - struct wl_registry *wl_registry; - struct wl_compositor *wl_compositor; - struct wl_subcompositor *wl_subcompositor; - struct wl_shm *wl_shm; - struct seat *seat; - struct wl_list outputs; // linked list of struct output records for all screens in system - struct libdecor *libdecor_context; - struct xdg_wm_base *xdg_wm_base; - struct zwp_text_input_manager_v3 *text_input_base; -#if HAVE_XDG_DIALOG - struct xdg_wm_dialog_v1 *xdg_wm_dialog; -#endif -#if HAVE_CURSOR_SHAPE - struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager; - struct wp_cursor_shape_device_v1 *wp_cursor_shape_device; -#endif - -// constructor - Fl_Wayland_Screen_Driver(); - -// overridden functions from parent class Fl_Screen_Driver - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { return PER_SCREEN_APP_SCALING; } - float scale(int n) FL_OVERRIDE; - void scale(int n, float f) FL_OVERRIDE; - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void flush() FL_OVERRIDE; - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - int dnd(int unused) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - void compose_reset() FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, - bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - int get_mouse(int &x, int &y) FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - void close_display() FL_OVERRIDE; - void display(const char *d) FL_OVERRIDE; - // --- compute dimensions of an Fl_Offscreen - void offscreen_size(Fl_Offscreen o, int &width, int &height) FL_OVERRIDE; - int has_marked_text() const FL_OVERRIDE; - // --- clipboard operations - // this one is in fl_wayland_clipboard_dnd.cxx - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - // this one is in fl_wayland_clipboard_dnd.cxx - int clipboard_contains(const char *type) FL_OVERRIDE; - void set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) FL_OVERRIDE; - void reset_spot() FL_OVERRIDE; - void *control_maximize_button(void *data) FL_OVERRIDE; - int event_key(int k) FL_OVERRIDE; - int get_key(int k) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - bool screen_boundaries_known() FL_OVERRIDE { return false; } - float base_scale(int numscreen) FL_OVERRIDE; - - // overridden functions from parent class Fl_Unix_Screen_Driver - int poll_or_select_with_delay(double time_to_wait) FL_OVERRIDE; - int poll_or_select() FL_OVERRIDE; - -// Wayland-specific member functions - void screen_count_set(int count) {num_screens = count;} - int screen_count_get() {return num_screens;} - void reset_cursor(); - // this one is in fl_wayland_clipboard_dnd.cxx - void copy_image(const unsigned char* data, int W, int H); - void init_workarea(); - void set_cursor(); - struct wl_cursor *default_cursor(); - void default_cursor(struct wl_cursor *cursor); - struct wl_cursor *cache_cursor(const char *cursor_name); - uint32_t get_serial(); - struct wl_seat *get_wl_seat(); - char *get_seat_name(); - struct xkb_keymap *get_xkb_keymap(); -}; - - -#endif // FL_WAYLAND_SCREEN_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx deleted file mode 100644 index 9199f3a5f..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx +++ /dev/null @@ -1,2204 +0,0 @@ -// -// Implementation of Wayland Screen interface -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "../../Fl_Scalable_Graphics_Driver.H" -#include <wayland-cursor.h> -#include "../../../libdecor/build/fl_libdecor.h" -#include "xdg-shell-client-protocol.h" -#include "../Posix/Fl_Posix_System_Driver.H" -#include <FL/Fl.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/platform.H> -#include <FL/fl_ask.H> -#include <FL/filename.H> -#include <vector> -#include "../../print_button.h" -#include <dlfcn.h> -#include <linux/input.h> -#include <stdlib.h> -#include <xkbcommon/xkbcommon.h> -#include <xkbcommon/xkbcommon-compose.h> -#include "text-input-client-protocol.h" -#include "gtk-shell-client-protocol.h" -#if HAVE_XDG_DIALOG -# include "xdg-dialog-client-protocol.h" -#endif -#if HAVE_CURSOR_SHAPE -# include "cursor-shape-client-protocol.h" -#endif -#include <assert.h> -#include <sys/mman.h> -#include <poll.h> -#include <errno.h> -#include <string.h> // for strerror() -#include <map> -extern "C" { - bool libdecor_get_cursor_settings(char **theme, int *size); - bool fl_is_surface_from_GTK_titlebar (struct wl_surface *surface, struct libdecor_frame *frame, - bool *using_GTK); -} - -// set this to 1 for keyboard debug output, 0 for no debug output -#define DEBUG_KEYBOARD 0 - -#define fl_max(a,b) ((a) > (b) ? (a) : (b)) -#define fl_min(a,b) ((a) < (b) ? (a) : (b)) - -struct pointer_output { - Fl_Wayland_Screen_Driver::output* output; - struct wl_list link; -}; - -/* Implementation note: - -- About CSD and SSD : - * Mutter and Weston use CSD (client-side decoration) which means that libdecor.so draws all window - titlebars and responds to resize, minimization and maximization events. - * KWin uses SSD (server-side decoration) which means the OS draws titlebars according to its own rules - and triggers resize, minimization and maximization events. - -- Function registry_handle_global() runs within fl_open_display() and sets public static variable - Fl_Wayland_Screen_Driver::compositor to either Fl_Wayland_Screen_Driver::MUTTER, ::WESTON, or ::KWIN. - -- Specific operations for WESTON: - * When a libdecor-framed window is minimized under Weston, the frame remains on display. To avoid - that, function libdecor_frame_set_minimized() is modified so it turns off the frame's visibility, with - function libdecor_frame_set_visibility(), when the window is minimized. That's implemented in file - libdecor/build/fl_libdecor.c. The modified libdecor_frame_set_minimized() function, part of libdecor.so, - needs access to variable Fl_Wayland_Screen_Driver::compositor, part of libfltk.a. This is achieved - calling FLTK function fl_libdecor_using_weston() which returns whether the running compositor - is Weston. This Weston bug has been corrected in Weston version 10. Thus, this special processing - is not performed when Weston version is ≥ 10. - -- Support of Fl_Window::border(int) : - FLTK uses libdecor_frame_set_visibility() to show or hide a toplevel window's frame. This doesn't work - with KWin which uses Server-Side Decoration. In that case, FLTK hides and re-shows the window to toggle - between presence and absence of a window's frame. -*/ - - -static std::vector<int> key_vector; // used by Fl_Wayland_Screen_Driver::event_key() -static struct wl_surface *gtk_shell_surface = NULL; - -Fl_Wayland_Screen_Driver::compositor_name Fl_Wayland_Screen_Driver::compositor = - Fl_Wayland_Screen_Driver::unspecified; - - -extern "C" { - bool fl_libdecor_using_weston(void) { - return Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON; - } -} - - -static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) -{ - xdg_wm_base_pong(xdg_wm_base, serial); -} - - -static const struct xdg_wm_base_listener xdg_wm_base_listener = { - .ping = xdg_wm_base_ping, -}; - - -// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx -extern const char *fl_fg; -extern const char *fl_bg; -extern const char *fl_bg2; -// end of extern additions workaround - - -void Fl_Wayland_Screen_Driver::do_set_cursor( - struct Fl_Wayland_Screen_Driver::seat *seat, struct wl_cursor *wl_cursor, Fl_Cursor cursor) { - /* - wl_cursor: when non-NULL means a custom cursor; - when NULL: - - with "Cursor shape" protocol, cursor is meaningful if != FL_CURSOR_NONE; - - with old-school cursors, seat->default_cursor gives the desired cursor. - cursor: used with "Cursor shape" protocol for enumerated cursor shape, otherwise equal to FL_CURSOR_NONE - */ - struct wl_cursor_image *image; - struct wl_buffer *buffer; - const int scale = seat->pointer_scale; - -#if HAVE_CURSOR_SHAPE - static std::map<int, int> cursor_shape_map = { - {FL_CURSOR_DEFAULT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT }, - {FL_CURSOR_ARROW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT }, - {FL_CURSOR_CROSS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR }, - {FL_CURSOR_WAIT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT }, - {FL_CURSOR_INSERT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT }, - {FL_CURSOR_HAND, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB }, - {FL_CURSOR_HELP, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP }, - {FL_CURSOR_MOVE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE }, - {FL_CURSOR_N, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE }, - {FL_CURSOR_E, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE }, - {FL_CURSOR_W, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE }, - {FL_CURSOR_S, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE }, - {FL_CURSOR_NS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE }, - {FL_CURSOR_WE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE }, - {FL_CURSOR_SW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE }, - {FL_CURSOR_SE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE }, - {FL_CURSOR_NE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE }, - {FL_CURSOR_NW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE }, - {FL_CURSOR_NESW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE }, - {FL_CURSOR_NWSE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE } - }; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->wp_cursor_shape_device && !wl_cursor) { - if (cursor != FL_CURSOR_NONE) wp_cursor_shape_device_v1_set_shape( - scr_driver->wp_cursor_shape_device, seat->pointer_enter_serial, cursor_shape_map[cursor]); - return; - } -#endif - - if ((!seat->cursor_theme && !wl_cursor) || !seat->wl_pointer) - return; - - if (!wl_cursor) wl_cursor = seat->default_cursor; - image = wl_cursor->images[0]; - buffer = wl_cursor_image_get_buffer(image); - wl_pointer_set_cursor(seat->wl_pointer, seat->pointer_enter_serial, - seat->cursor_surface, - image->hotspot_x / scale, - image->hotspot_y / scale); - wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width, image->height); - wl_surface_commit(seat->cursor_surface); -} - - -static uint32_t ptime; -static uint32_t wld_event_time; -static int px, py; - - -static void set_event_xy(Fl_Window *win) { - // turn off is_click if enough time or mouse movement has passed: - if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 || - wld_event_time >= ptime+1000) { - Fl::e_is_click = 0; -//fprintf(stderr, "Fl::e_is_click = 0\n"); - } -} - - -// if this is same event as last && is_click, increment click count: -static inline void checkdouble() { - if (Fl::e_is_click == Fl::e_keysym) { - Fl::e_clicks++; -//fprintf(stderr, "Fl::e_clicks = %d\n", Fl::e_clicks); - } else { - Fl::e_clicks = 0; - Fl::e_is_click = Fl::e_keysym; -//fprintf(stderr, "Fl::e_is_click = %d\n", Fl::e_is_click); - } - px = Fl::e_x_root; - py = Fl::e_y_root; - ptime = wld_event_time; -} - - -struct wl_display *Fl_Wayland_Screen_Driver::wl_display = NULL; - - -static Fl_Window *event_coords_from_surface(struct wl_surface *surface, - wl_fixed_t surface_x, wl_fixed_t surface_y) { - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (!win) return NULL; - int delta_x = 0, delta_y = 0; - while (win->parent()) { - delta_x += win->x(); - delta_y += win->y(); - win = win->window(); - } - float f = Fl::screen_scale(win->screen_num()); - Fl::e_x = wl_fixed_to_int(surface_x) / f + delta_x; - Fl::e_x_root = Fl::e_x + win->x(); - Fl::e_y = wl_fixed_to_int(surface_y) / f + delta_y; - int *poffset = Fl_Window_Driver::menu_offset_y(win); - if (poffset) Fl::e_y -= *poffset; - Fl::e_y_root = Fl::e_y + win->y(); - return win; -} - -static Fl_Window *need_leave = NULL; - -static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, - struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y); - static bool using_GTK = seat->gtk_shell && - (gtk_shell1_get_version(seat->gtk_shell) >= GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION); - if (!win && using_GTK) { - // check whether surface is the headerbar of a GTK-decorated window - Fl_X *xp = Fl_X::first; - while (xp && using_GTK) { // all mapped windows - struct wld_window *xid = (struct wld_window*)xp->xid; - if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && - fl_is_surface_from_GTK_titlebar(surface, xid->frame, &using_GTK)) { - gtk_shell_surface = surface; - break; - } - xp = xp->next; - } - } - if (!win) return; - //fprintf(stderr, "pointer_enter window=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface)); - seat->pointer_focus = surface; - // use custom cursor if present - struct wl_cursor *cursor = - fl_wl_xid(win)->custom_cursor ? fl_wl_xid(win)->custom_cursor->wl_cursor : NULL; - seat->serial = serial; - seat->pointer_enter_serial = serial; - Fl_Wayland_Screen_Driver::do_set_cursor(seat, cursor, Fl_Wayland_Window_Driver::driver(win)->standard_cursor()); - set_event_xy(win); - need_leave = NULL; - win = Fl_Wayland_Window_Driver::surface_to_window(surface); - // Caution: with an Fl_Tooltip this call can hide the window being entered (#1317) - if (!win->parent()) Fl::handle(FL_ENTER, win); -} - - -static void pointer_leave(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - if (seat->pointer_focus == surface) seat->pointer_focus = NULL; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - gtk_shell_surface = NULL; - if (win) { - //fprintf(stderr, "pointer_leave window=%p [%s]\n", win, (win->parent()?"sub":"top")); - set_event_xy(win); - need_leave = win->top_window(); // we leave a sub or toplevel window - wl_display_roundtrip(fl_wl_display()); // pointer_enter to other win, if applicable, will run - if (need_leave) { // we really left the sub-or-top win and did not enter another - extern Fl_Window *fl_xmousewin; - fl_xmousewin = 0; - Fl::handle(FL_LEAVE, need_leave); - } - } -} - - -static void pointer_motion(void *data, struct wl_pointer *wl_pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = event_coords_from_surface(seat->pointer_focus, surface_x, surface_y); - if (!win) return; - if (Fl::grab() && !Fl::grab()->menu_window() && Fl::grab() != win) { - // If there's an active, non-menu grab() and the pointer is in a window other than - // the grab(), make e_x_root too large to be in any window - Fl::e_x_root = 1000000; - } - else if (Fl_Window_Driver::menu_parent(NULL) && // any kind of menu is active now, and - !win->menu_window() && // we enter a non-menu window - win != Fl_Window_Driver::menu_parent(NULL) // that's not the window below the menu - ) { - Fl::e_x_root = 1000000; // make it too large to be in any window - } -//fprintf(stderr, "FL_MOVE on win=%p to x:%dx%d root:%dx%d\n", win, Fl::e_x, Fl::e_y, Fl::e_x_root, Fl::e_y_root); - wld_event_time = time; - set_event_xy(win); - Fl::handle(FL_MOVE, win); -} - - -//#include <FL/names.h> -static void pointer_button(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - if (gtk_shell_surface && state == WL_POINTER_BUTTON_STATE_PRESSED && - button == BTN_MIDDLE) { - struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(seat->gtk_shell,gtk_shell_surface); - gtk_surface1_titlebar_gesture(gtk_surface, serial, seat->wl_seat, - GTK_SURFACE1_GESTURE_MIDDLE_CLICK); - gtk_surface1_release(gtk_surface); // very necessary - return; - } - seat->serial = serial; - int event = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return; - win = win->top_window(); - wld_event_time = time; - int b = 0; - // Fl::e_state &= ~FL_BUTTONS; // DO NOT reset the mouse button state! - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; } - else if (button == BTN_BACK) { Fl::e_state |= FL_BUTTON4; b = 4; } // ? - else if (button == BTN_SIDE) { Fl::e_state |= FL_BUTTON4; b = 4; } // OK: Debian 12 - else if (button == BTN_FORWARD) { Fl::e_state |= FL_BUTTON5; b = 5; } // ? - else if (button == BTN_EXTRA) { Fl::e_state |= FL_BUTTON5; b = 5; } // OK: Debian 12 - } else { // must be WL_POINTER_BUTTON_STATE_RELEASED - if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; } - else if (button == BTN_BACK) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // ? - else if (button == BTN_SIDE) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // OK: Debian 12 - else if (button == BTN_FORWARD) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // ? - else if (button == BTN_EXTRA) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // OK: Debian 12 - } - Fl::e_keysym = FL_Button + b; - Fl::e_dx = Fl::e_dy = 0; - - set_event_xy(win); - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - event = FL_PUSH; - checkdouble(); - } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) { - event = FL_RELEASE; - } - // fprintf(stderr, "%s %s\n", fl_eventnames[event], win->label() ? win->label():"[]"); - Fl::handle(event, win); -} - - -static void pointer_axis(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return; - wld_event_time = time; - int delta = wl_fixed_to_int(value); - if (abs(delta) >= 10) delta /= 10; - // fprintf(stderr, "FL_MOUSEWHEEL: %c delta=%d\n", axis==WL_POINTER_AXIS_HORIZONTAL_SCROLL?'H':'V', delta); - // allow both horizontal and vertical movements to be processed by the widget - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - if (Fl::event_shift()) { // shift key pressed: send vertical mousewheel event - Fl::e_dx = 0; - Fl::e_dy = delta; - } else { // shift key not pressed (normal behavior): send horizontal mousewheel event - Fl::e_dx = delta; - Fl::e_dy = 0; - } - Fl::handle(FL_MOUSEWHEEL, win->top_window()); - } - if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - if (Fl::event_shift()) { // shift key pressed: send horizontal mousewheel event - Fl::e_dx = delta; - Fl::e_dy = 0; - } else {// shift key not pressed (normal behavior): send vertical mousewheel event - Fl::e_dx = 0; - Fl::e_dy = delta; - } - Fl::handle(FL_MOUSEWHEEL, win->top_window()); - } -} - - -static struct wl_pointer_listener pointer_listener = { - pointer_enter, - pointer_leave, - pointer_motion, - pointer_button, - pointer_axis -}; - - -static const char *proxy_tag = "FLTK for Wayland"; - - -bool Fl_Wayland_Screen_Driver::own_output(struct wl_output *output) -{ - return wl_proxy_get_tag((struct wl_proxy *)output) == &proxy_tag; -} - - -static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat); - - -static void try_update_cursor(struct Fl_Wayland_Screen_Driver::seat *seat) { - if (wl_list_empty(&seat->pointer_outputs)) return; - struct pointer_output *pointer_output; - int scale = 1; - - wl_list_for_each(pointer_output, &seat->pointer_outputs, link) { - scale = fl_max(scale, pointer_output->output->wld_scale); - } - - if (scale != seat->pointer_scale) { - seat->pointer_scale = scale; - init_cursors(seat); - Fl_Wayland_Screen_Driver::do_set_cursor(seat); - } -} - - -static void output_scale(void *data, struct wl_output *wl_output, int32_t factor); - - -static void cursor_surface_enter(void *data, - struct wl_surface *wl_surface, struct wl_output *wl_output) { - // Runs when the seat's cursor_surface enters a display - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - struct pointer_output *pointer_output; - - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - - pointer_output = (struct pointer_output *)calloc(1, sizeof(struct pointer_output)); - pointer_output->output = - (Fl_Wayland_Screen_Driver::output *)wl_output_get_user_data(wl_output); -//fprintf(stderr, "cursor_surface_enter: wl_output_get_user_data(%p)=%p\n", wl_output, pointer_output->output); - wl_list_insert(&seat->pointer_outputs, &pointer_output->link); - try_update_cursor(seat); - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - output_scale(output, wl_output, output->wld_scale); // rescale custom cursors - // maintain custom or standard window cursor - Fl_Window *win = Fl::first_window(); - if (win) { - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win); - struct wld_window *xid = fl_wl_xid(win); - if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor); - else if (driver->cursor_default()) driver->set_cursor(driver->cursor_default()); - else win->cursor(driver->standard_cursor()); - } -} - - -static void cursor_surface_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - struct pointer_output *pointer_output, *tmp; - wl_list_for_each_safe(pointer_output, tmp, &seat->pointer_outputs, link) { - if (pointer_output->output->wl_output == wl_output) { - wl_list_remove(&pointer_output->link); - free(pointer_output); - } - } - try_update_cursor(seat); - // maintain custom window cursor - Fl_Window *win = Fl::first_window(); - if (win) { - struct wld_window *xid = fl_wl_xid(win); - if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor); - } -} - - -static struct wl_surface_listener cursor_surface_listener = { - cursor_surface_enter, - cursor_surface_leave, -}; - - -static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (!seat->cursor_surface) { - seat->cursor_surface = wl_compositor_create_surface(scr_driver->wl_compositor); - wl_surface_add_listener(seat->cursor_surface, &cursor_surface_listener, seat); - } -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_manager) return; -#endif - - char *name; - int size; - struct wl_cursor_theme *theme; - - if (!libdecor_get_cursor_settings(&name, &size)) { - name = NULL; - size = 24; - } - size *= seat->pointer_scale; - theme = wl_cursor_theme_load(name, size, scr_driver->wl_shm); - free(name); - if (theme != NULL) { - if (seat->cursor_theme) { - // caution to destroy theme because Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor) caches used cursors - scr_driver->reset_cursor(); - wl_cursor_theme_destroy(seat->cursor_theme); - } - seat->cursor_theme = theme; - } - if (seat->cursor_theme) { - seat->default_cursor = scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow] = - wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr"); - } -} - - -static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, - uint32_t format, int32_t fd, uint32_t size) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - - char *map_shm = (char*)mmap(NULL, size, PROT_READ, - wl_keyboard_get_version(wl_keyboard) >= 7 ? MAP_PRIVATE : MAP_SHARED, fd, 0); - assert(map_shm != MAP_FAILED); - - struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(seat->xkb_context, map_shm, - XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - munmap(map_shm, size); - close(fd); - if (xkb_keymap) { - struct xkb_state *xkb_state = xkb_state_new(xkb_keymap); - xkb_keymap_unref(seat->xkb_keymap); - if (seat->xkb_state) xkb_state_unref(seat->xkb_state); - seat->xkb_keymap = xkb_keymap; - seat->xkb_state = xkb_state; - } -} - - -static int search_int_vector(std::vector<int>& v, int val) { - for (unsigned pos = 0; pos < v.size(); pos++) { - if (v[pos] == val) return pos; - } - return -1; -} - - -static void remove_int_vector(std::vector<int>& v, int val) { - int pos = search_int_vector(v, val); - if (pos < 0) return; - v.erase(v.begin()+pos); -} - - -static int process_wld_key(struct xkb_state *xkb_state, uint32_t key, - uint32_t *p_keycode, xkb_keysym_t *p_sym) { - uint32_t keycode = key + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, keycode); - if (sym == 0xfe20) sym = FL_Tab; - if (sym == 0xffeb) sym = FL_Meta_L; // repair value libxkb gives for FL_Meta_L - if (sym == 0xffec) sym = FL_Meta_R; // repair value libxkb gives for FL_Meta_R - if (sym >= 'A' && sym <= 'Z') sym += 32; // replace uppercase by lowercase letter - int for_key_vector = sym; // for support of Fl::event_key(int) - // special processing for number keys == keycodes 10-19 : - if (keycode >= 10 && keycode <= 18) { - for_key_vector = '1' + (keycode - 10); - } else if (keycode == 19) { - for_key_vector = '0'; - } - if (p_keycode) *p_keycode = keycode; - if (p_sym) *p_sym = sym; - return for_key_vector; -} - - -static uint32_t last_keydown_serial = 0; // serial of last keydown event - - -static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; -//fprintf(stderr, "keyboard enter fl_win=%p; keys pressed are: ", Fl_Wayland_Window_Driver::surface_to_window(surface)); - key_vector.clear(); - // Replace wl_array_for_each(p, keys) rejected by C++ - for (uint32_t *p = (uint32_t *)(keys)->data; - (const char *) p < ((const char *) (keys)->data + (keys)->size); - (p)++) { - int for_key_vector = process_wld_key(seat->xkb_state, *p, NULL, NULL); -//fprintf(stderr, "%d ", for_key_vector); - if (search_int_vector(key_vector, for_key_vector) < 0) { - key_vector.push_back(for_key_vector); - } - } -//fprintf(stderr, "\n"); - seat->keyboard_surface = surface; - seat->keyboard_enter_serial = serial; - last_keydown_serial = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (win) { - Fl::handle(FL_FOCUS, win); - fl_wl_find(fl_wl_xid(win)); - } -} - - -struct key_repeat_data_t { - uint32_t serial; - Fl_Window *window; -}; - -#define KEY_REPEAT_DELAY 0.5 // sec -#define KEY_REPEAT_INTERVAL 0.05 // sec - - -static void key_repeat_timer_cb(key_repeat_data_t *key_repeat_data) { - if (last_keydown_serial == key_repeat_data->serial) { - Fl::handle(FL_KEYDOWN, key_repeat_data->window); - Fl::add_timeout(KEY_REPEAT_INTERVAL, (Fl_Timeout_Handler)key_repeat_timer_cb, key_repeat_data); - } - else delete key_repeat_data; -} - - -int Fl_Wayland_Screen_Driver::next_marked_length = 0; - - -int Fl_Wayland_Screen_Driver::has_marked_text() const { - return 1; -} - - -int Fl_Wayland_Screen_Driver::insertion_point_x = 0; -int Fl_Wayland_Screen_Driver::insertion_point_y = 0; -int Fl_Wayland_Screen_Driver::insertion_point_width = 0; -int Fl_Wayland_Screen_Driver::insertion_point_height = 0; -bool Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false; - -static int previous_cursor_x = 0, previous_cursor_y = 0, previous_cursor_h = 0; -static uint32_t commit_serial = 0; -static char *current_pre_edit = NULL; -static char *pending_pre_edit = NULL; -static char *pending_commit = NULL; - - -static void send_commit(struct zwp_text_input_v3 *zwp_text_input_v3) { - zwp_text_input_v3_commit(zwp_text_input_v3); - commit_serial++; -} - - -// inform TIM about location of the insertion point, and memorize this info. -void Fl_Wayland_Screen_Driver::insertion_point_location(int x, int y, int height) { -//printf("insertion_point_location %dx%d\n",x,y); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->seat->text_input /*&& !current_pre_edit*/ && - (x != previous_cursor_x || y != previous_cursor_y || height != previous_cursor_h)) { - previous_cursor_x = x; - previous_cursor_y = y; - previous_cursor_h = height; - if (Fl::focus()) { - Fl_Widget *focuswin = Fl::focus()->window(); - while (focuswin && focuswin->parent()) { - x += focuswin->x(); y += focuswin->y(); - focuswin = focuswin->window(); - } - } - float s = fl_graphics_driver->scale(); - insertion_point_location_is_valid = true; - insertion_point_x = s*x; - insertion_point_y = s*(y-height); - insertion_point_width = s*5; - insertion_point_height = s*height; - if (zwp_text_input_v3_get_user_data(scr_driver->seat->text_input) ) { - zwp_text_input_v3_set_cursor_rectangle(scr_driver->seat->text_input, - insertion_point_x, insertion_point_y, - insertion_point_width, insertion_point_height); - send_commit(scr_driver->seat->text_input); - } - } -} - - -// computes window coordinates & size of insertion point -bool Fl_Wayland_Screen_Driver::insertion_point_location(int *px, int *py, - int *pwidth, int *pheight) { - // return true if the current coordinates and size of the insertion point are available - if ( ! insertion_point_location_is_valid ) return false; - *px = insertion_point_x; - *py = insertion_point_y; - *pwidth = insertion_point_width; - *pheight = insertion_point_height; - return true; -} - - -int Fl_Wayland_Screen_Driver::compose(int& del) { - unsigned char ascii = (unsigned char)Fl::e_text[0]; - // letter+modifier key - int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && ascii < 128 ; - // pressing modifier key - // FL_Shift_L, FL_Shift_R, FL_Control_L, FL_Control_R, FL_Caps_Lock - // FL_Meta_L, FL_Meta_R, FL_Alt_L, FL_Alt_R - condition |= ((Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || - Fl::e_keysym == FL_Alt_Gr); - // FL_Home FL_Left FL_Up FL_Right FL_Down FL_Page_Up FL_Page_Down FL_End - // FL_Print FL_Insert FL_Menu FL_Help and more - condition |= (Fl::e_keysym >= FL_Home && Fl::e_keysym <= FL_Num_Lock); - condition |= (Fl::e_keysym >= FL_F && Fl::e_keysym <= FL_F_Last); - condition |= Fl::e_keysym == FL_Tab || Fl::e_keysym == FL_Scroll_Lock || Fl::e_keysym == FL_Pause; -//fprintf(stderr, "compose: condition=%d e_state=%x ascii=%d\n", condition, Fl::e_state, ascii); - if (condition) { del = 0; return 0;} -//fprintf(stderr, "compose: del=%d compose_state=%d next_marked_length=%d \n", del, Fl::compose_state, next_marked_length); - del = Fl::compose_state; - Fl::compose_state = next_marked_length; - // no-underlined-text && (ascii non-printable || ascii == delete) - if (ascii && (!Fl::compose_state) && (ascii <= 31 || ascii == 127)) { del = 0; return 0; } - return 1; -} - - -void Fl_Wayland_Screen_Driver::compose_reset() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl::compose_state = 0; - next_marked_length = 0; - if (seat->xkb_compose_state) xkb_compose_state_reset(seat->xkb_compose_state); -} - - -struct dead_key_struct { - xkb_keysym_t keysym; // the keysym obtained when hitting a dead key - const char *marked_text; // the temporary text to display for that dead key -}; - - -static dead_key_struct dead_keys[] = { - {XKB_KEY_dead_grave, "`"}, - {XKB_KEY_dead_acute, "´"}, - {XKB_KEY_dead_circumflex, "^"}, - {XKB_KEY_dead_tilde, "~"}, - {XKB_KEY_dead_macron, "¯"}, - {XKB_KEY_dead_breve, "˘"}, - {XKB_KEY_dead_abovedot, "˙"}, - {XKB_KEY_dead_diaeresis, "¨"}, - {XKB_KEY_dead_abovering, "˚"}, - {XKB_KEY_dead_doubleacute, "˝"}, - {XKB_KEY_dead_caron, "ˇ"}, - {XKB_KEY_dead_cedilla, "¸"}, - {XKB_KEY_dead_ogonek, "˛"}, - {XKB_KEY_dead_iota, "ι"}, - {XKB_KEY_dead_doublegrave, " ̏"}, -}; - - -const int dead_key_count = sizeof(dead_keys)/sizeof(struct dead_key_struct); - -static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - seat->serial = serial; - static char buf[128]; - uint32_t keycode; - xkb_keysym_t sym; - int for_key_vector = process_wld_key(seat->xkb_state, key, &keycode, &sym); -#if (DEBUG_KEYBOARD) - xkb_keysym_get_name(sym, buf, sizeof(buf)); - const char *action = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release"); - fprintf(stderr, "wl_keyboard_key: key %s: sym: %-12s(%d) code:%u fl_win=%p, ", - action, buf, sym, keycode, - Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface)); -#endif - xkb_state_key_get_utf8(seat->xkb_state, keycode, buf, sizeof(buf)); -#if (DEBUG_KEYBOARD) - fprintf(stderr, "utf8: '%s' e_length=%d [%d]\n", buf, (int)strlen(buf), *buf); -#endif - Fl::e_keysym = Fl::e_original_keysym = for_key_vector; - if (!(Fl::e_state & FL_NUM_LOCK) && sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete) { - // compute e_keysym and e_original_keysym for keypad number keys and '.|,' when NumLock is off - static const int table[11] = {FL_Home /* 7 */, FL_Left /* 4 */, FL_Up /* 8 */, - FL_Right /* 6 */, FL_Down /* 2 */, FL_Page_Up /* 9 */, - FL_Page_Down /* 3 */, FL_End /* 1 */, 0xff0b /* 5 */, - FL_Insert /* 0 */, FL_Delete /* .|, */}; - static const int table_original[11] = {0xffb7 /* 7 */, 0xffb4 /* 4 */, 0xffb8 /* 8 */, - 0xffb6 /* 6 */, 0xffb2 /* 2 */, 0xffb9 /* 9 */, - 0xffb3 /* 3 */, 0xffb1 /* 1 */, 0xffb5 /* 5 */, - 0xffb0 /* 0 */, 0xffac /* .|, */}; - Fl::e_keysym = table[sym - XKB_KEY_KP_Home]; - Fl::e_original_keysym = table_original[sym - XKB_KEY_KP_Home]; - for_key_vector = Fl::e_original_keysym; - } -#if (DEBUG_KEYBOARD) - fprintf(stderr, "wl_keyboard_key: e_keysym=%x e_original_keysym=%x\n", Fl::e_keysym, Fl::e_original_keysym); -#endif - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - if (search_int_vector(key_vector, for_key_vector) < 0) { - key_vector.push_back(for_key_vector); - } - } else { - last_keydown_serial = 0; - remove_int_vector(key_vector, for_key_vector); - } - Fl::e_text = buf; - Fl::e_length = (int)strlen(buf); - // Process dead keys and compose sequences : - enum xkb_compose_status status = XKB_COMPOSE_NOTHING; - // This part is useful only if the compositor doesn't support protocol text-input-unstable-v3 - if (seat->xkb_compose_state && state == WL_KEYBOARD_KEY_STATE_PRESSED && - !(sym >= FL_Shift_L && sym <= FL_Alt_R) && sym != XKB_KEY_ISO_Level3_Shift) { - xkb_compose_state_feed(seat->xkb_compose_state, sym); - status = xkb_compose_state_get_status(seat->xkb_compose_state); - if (status == XKB_COMPOSE_COMPOSING) { - if (Fl::e_length == 0) { // dead keys produce e_length = 0 - int i; - for (i = 0; i < dead_key_count; i++) { - if (dead_keys[i].keysym == sym) break; - } - if (i < dead_key_count) strcpy(buf, dead_keys[i].marked_text); - else buf[0] = 0; - Fl::e_length = (int)strlen(buf); - Fl::compose_state = 0; - } - Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length; - } else if (status == XKB_COMPOSE_COMPOSED) { - Fl::e_length = xkb_compose_state_get_utf8(seat->xkb_compose_state, buf, sizeof(buf)); - Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - } else if (status == XKB_COMPOSE_CANCELLED) { - Fl::e_length = 0; - Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - } -//fprintf(stderr, "xkb_compose_status=%d ctxt=%p state=%p l=%d[%s]\n", status, seat->xkb_context, seat->xkb_compose_state, Fl::e_length, buf); - } - // end of part used only without text-input-unstable-v3 - - wld_event_time = time; - int event = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? FL_KEYDOWN : FL_KEYUP); - // Send event to focus-containing top window as defined by FLTK, - // otherwise send it to Wayland-defined focus window - Fl_Window *win = ( Fl::focus() ? Fl::focus()->top_window() : - Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface) ); - if (win) { - set_event_xy(win); - Fl::e_is_click = 0; - Fl::handle(event, win); - } - if (event == FL_KEYDOWN && status == XKB_COMPOSE_NOTHING && - !(sym >= FL_Shift_L && sym <= FL_Alt_R)) { - // Handling of key repeats : - // Use serial argument rather than time to detect repeated keys because - // serial value changes at each key up or down in all tested OS and compositors, - // whereas time value changes in Ubuntu24.04 KDE/Plasma 5.27.11 and Ubuntu22.04 KDE/Plasma 5.24.7 - // but not in Debian-testing KDE/Plasma 5.27.10. - // Unexplained difference in behaviors of KDE/Plasma compositor: - // Consider KDE settings -> input -> keyboard -> when a key is held: repeat/do nothing. - // This setting (repeat) has key-down wayland events repeated when key is held under Debian/KDE - // but not under Ubuntu/KDE ! - key_repeat_data_t *key_repeat_data = new key_repeat_data_t; - key_repeat_data->serial = serial; - key_repeat_data->window = win; - last_keydown_serial = serial; - Fl::add_timeout(KEY_REPEAT_DELAY, (Fl_Timeout_Handler)key_repeat_timer_cb, - key_repeat_data); - } -} - - -static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; -//fprintf(stderr, "keyboard leave fl_win=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface)); - seat->keyboard_surface = NULL; - last_keydown_serial = 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); - if (!win && Fl::focus()) win = Fl::focus()->top_window(); - if (win) Fl::handle(FL_UNFOCUS, win); - key_vector.clear(); -} - - -static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t mods_depressed, - uint32_t mods_latched, uint32_t mods_locked, - uint32_t group) { - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched, mods_locked, - 0, 0, group); - Fl::e_state &= ~(FL_SHIFT+FL_CTRL+FL_ALT+FL_META+FL_CAPS_LOCK+FL_NUM_LOCK); - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_SHIFT, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_SHIFT; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_CTRL; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_ALT, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_ALT; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_LOGO, - XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_META; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CAPS, - XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_CAPS_LOCK; - if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_NUM, - XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_NUM_LOCK; -//fprintf(stderr, "mods_depressed=%u Fl::e_state=%X\n", mods_depressed, Fl::e_state); -} - - -static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) -{ - // wl_keyboard is version 3 under Debian, but that event isn't sent until version 4 -} - - -static const struct wl_keyboard_listener wl_keyboard_listener = { - .keymap = wl_keyboard_keymap, - .enter = wl_keyboard_enter, - .leave = wl_keyboard_leave, - .key = wl_keyboard_key, - .modifiers = wl_keyboard_modifiers, - .repeat_info = wl_keyboard_repeat_info, -}; - - -void text_input_enter(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - struct wl_surface *surface) { -//puts("text_input_enter"); - zwp_text_input_v3_set_user_data(zwp_text_input_v3, surface); - zwp_text_input_v3_enable(zwp_text_input_v3); - zwp_text_input_v3_set_content_type(zwp_text_input_v3, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL); - int x, y, width, height; - if (Fl_Wayland_Screen_Driver::insertion_point_location(&x, &y, &width, &height)) { - zwp_text_input_v3_set_cursor_rectangle(zwp_text_input_v3, x, y, width, height); - } - send_commit(zwp_text_input_v3); -} - - -void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - struct wl_surface *surface) { -//puts("text_input_leave"); - zwp_text_input_v3_disable(zwp_text_input_v3); - zwp_text_input_v3_set_user_data(zwp_text_input_v3, NULL); - send_commit(zwp_text_input_v3); - free(pending_pre_edit); pending_pre_edit = NULL; - free(current_pre_edit); current_pre_edit = NULL; - free(pending_commit); pending_commit = NULL; -} - - -static void send_text_to_fltk(const char *text, bool is_marked, struct wl_surface *current_surface) { -//printf("send_text_to_fltk(%s, %d)\n",text,is_marked); - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(current_surface); - Fl::e_text = text ? (char*)text : (char*)""; - Fl::e_length = text ? (int)strlen(text) : 0; - Fl::e_keysym = 'a'; // fake a simple key - set_event_xy(win); - Fl::e_is_click = 0; - if (is_marked) { // goes to widget as marked text - Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length; - Fl::handle(FL_KEYDOWN, win); - } else if (text) { - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl::handle(FL_KEYDOWN, win); - Fl::compose_state = 0; - } else { - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl::handle(FL_KEYDOWN, win); - } -} - - -void text_input_preedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - const char *text, int32_t cursor_begin, int32_t cursor_end) { -//printf("text_input_preedit_string %s cursor_begin=%d cursor_end=%d\n",text, cursor_begin, cursor_end); - free(pending_pre_edit); - pending_pre_edit = text ? strdup(text) : NULL; -} - - -void text_input_commit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - const char *text) { -//printf("text_input_commit_string %s\n",text); - free(pending_commit); - pending_commit = (text ? strdup(text) : NULL); -} - - -void text_input_delete_surrounding_text(void *data, - struct zwp_text_input_v3 *zwp_text_input_v3, - uint32_t before_length, uint32_t after_length) { - fprintf(stderr, "delete_surrounding_text before=%d adfter=%d\n", - before_length,after_length); -} - - -void text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, - uint32_t serial) { -//puts("text_input_done"); - struct wl_surface *current_surface = (struct wl_surface*)data; - const bool bad_event = (serial != commit_serial); - if ((pending_pre_edit == NULL && current_pre_edit == NULL) || - (pending_pre_edit && current_pre_edit && strcmp(pending_pre_edit, current_pre_edit) == 0)) { - free(pending_pre_edit); pending_pre_edit = NULL; - } else { - free(current_pre_edit); - current_pre_edit = pending_pre_edit; - pending_pre_edit = NULL; - if (current_pre_edit) { - send_text_to_fltk(current_pre_edit, !bad_event, current_surface); - } else { - send_text_to_fltk(NULL, false, current_surface); - } - } - if (pending_commit) { - send_text_to_fltk(pending_commit, false, current_surface); - free(pending_commit); pending_commit = NULL; - } -} - - -static const struct zwp_text_input_v3_listener text_input_listener = { - .enter = text_input_enter, - .leave = text_input_leave, - .preedit_string = text_input_preedit_string, - .commit_string = text_input_commit_string, - .delete_surrounding_text = text_input_delete_surrounding_text, - .done = text_input_done, -}; - - -void Fl_Wayland_Screen_Driver::enable_im() { - if (text_input_base && !seat->text_input) { - seat->text_input = zwp_text_input_manager_v3_get_text_input(text_input_base, - seat->wl_seat); - //printf("seat->text_input=%p\n",seat->text_input); - zwp_text_input_v3_add_listener(seat->text_input, &text_input_listener, NULL); - } -} - - -void Fl_Wayland_Screen_Driver::disable_im() { - if (seat->text_input) { - zwp_text_input_v3_disable(seat->text_input); - zwp_text_input_v3_commit(seat->text_input); - zwp_text_input_v3_destroy(seat->text_input); - seat->text_input = NULL; - free(pending_pre_edit); pending_pre_edit = NULL; - free(current_pre_edit); current_pre_edit = NULL; - free(pending_commit); pending_commit = NULL; - } -} - - -static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) -{ - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct Fl_Wayland_Screen_Driver::seat *seat = - (struct Fl_Wayland_Screen_Driver::seat*)data; - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); - seat->pointer_scale = 1; -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_manager) { - scr_driver->wp_cursor_shape_device = - wp_cursor_shape_manager_v1_get_pointer(scr_driver->wp_cursor_shape_manager, seat->wl_pointer); - } -#endif // HAVE_CURSOR_SHAPE - init_cursors(seat); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) { - wl_pointer_release(seat->wl_pointer); - seat->wl_pointer = NULL; - } - - bool have_keyboard = seat->xkb_context && (capabilities & WL_SEAT_CAPABILITY_KEYBOARD); - if (have_keyboard && seat->wl_keyboard == NULL) { - seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(seat->wl_keyboard, - &wl_keyboard_listener, seat); -//fprintf(stderr, "wl_keyboard version=%d\n", wl_keyboard_get_version(seat->wl_keyboard)); - - } else if (!have_keyboard && seat->wl_keyboard != NULL) { - wl_keyboard_release(seat->wl_keyboard); - seat->wl_keyboard = NULL; - } - scr_driver->enable_im(); -} - - -static void seat_name(void *data, struct wl_seat *wl_seat, const char *name) { - struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; - seat->name = strdup(name); -} - - -static struct wl_seat_listener seat_listener = { - seat_capabilities, - seat_name -}; - - -static void output_geometry(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform) -{ - //fprintf(stderr, "output_geometry: x=%d y=%d physical=%dx%d\n",x,y,physical_width,physical_height); - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->x = int(x); - output->y = int(y); - output->dpi = 96; // to elaborate -} - - -static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags, - int32_t width, int32_t height, int32_t refresh) -{ - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->pixel_width = int(width); - output->pixel_height = int(height); - output->width = output->pixel_width; // until further notice - output->height = output->pixel_height; -//fprintf(stderr, "output_mode: [%p]=%dx%d\n",output->wl_output,width,height); -} - - -static void output_done(void *data, struct wl_output *wl_output) -{ - // Runs at startup and when desktop scale factor is changed or screen added - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; -//fprintf(stderr, "output_done output=%p\n",output); - Fl_X *xp = Fl_X::first; - while (xp) { // all mapped windows - struct wld_window *win = (struct wld_window*)xp->xid; - Fl_Window *W = win->fl_win; - if (win->buffer || W->as_gl_window()) { - if (W->as_gl_window()) { - wl_surface_set_buffer_scale(win->wl_surface, output->wld_scale); - Fl_Window_Driver::driver(W)->is_a_rescale(true); - W->resize(W->x(), W->y(), W->w(), W->h()); - Fl_Window_Driver::driver(W)->is_a_rescale(false); - } else { - Fl_Wayland_Graphics_Driver::buffer_release(win); - } - W->redraw(); - Fl_Window_Driver::driver(W)->flush(); - } - xp = xp->next; - } - output->done = true; - - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->screen_count_get() > 0) { // true when output_done runs after initial screen dectection - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - scr_driver->init_workarea(); - } -} - - -static void output_scale(void *data, struct wl_output *wl_output, int32_t factor) { - Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data; - output->wld_scale = factor; -//fprintf(stderr,"output_scale: wl_output=%p factor=%d\n",wl_output, factor); - // rescale cursors of windows that map here and have a custom cursor - Fl_Window *win = Fl::first_window(); - while (win) { - struct wld_window *xid = fl_wl_xid(win); - struct Fl_Wayland_Window_Driver::surface_output *s_output; - // get 1st screen where window appears - s_output = wl_container_of(xid->outputs.next, s_output, link); - if (xid->custom_cursor && output == s_output->output) { - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win); - driver->set_cursor_4args(xid->custom_cursor->rgb, - xid->custom_cursor->hotx, xid->custom_cursor->hoty, false); - }; - win = Fl::next_window(win); - } -} - - -static struct wl_output_listener output_listener = { - output_geometry, - output_mode, - output_done, - output_scale -}; - - -struct pair_bool { - bool found_gtk_shell; - bool found_wf_shell; -}; - - -// Notice: adding use of unstable protocol "XDG output" would allow FLTK to be notified -// in real time of changes to the relative location of multiple displays; -// with the present code, that information is received at startup only. -static void registry_handle_global(void *user_data, struct wl_registry *wl_registry, - uint32_t id, const char *interface, uint32_t version) { -//fprintf(stderr, "interface=%s version=%u\n", interface, version); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (strcmp(interface, "wl_compositor") == 0) { - if (version < 4) { - Fl::fatal("wl_compositor version >= 4 required"); - } - scr_driver->wl_compositor = (struct wl_compositor*)wl_registry_bind(wl_registry, - id, &wl_compositor_interface, 4); - - } else if (strcmp(interface, "wl_subcompositor") == 0) { - scr_driver->wl_subcompositor = (struct wl_subcompositor*)wl_registry_bind(wl_registry, - id, &wl_subcompositor_interface, 1); - - } else if (strcmp(interface, "wl_shm") == 0) { - scr_driver->wl_shm = (struct wl_shm*)wl_registry_bind(wl_registry, - id, &wl_shm_interface, 1); - - } else if (strcmp(interface, "wl_seat") == 0) { - if (version < 3) { - Fl::fatal("%s version 3 required but only version %i is available\n", - interface, version); - } - if (!scr_driver->seat) scr_driver->seat = - (struct Fl_Wayland_Screen_Driver::seat*)calloc(1, - sizeof(struct Fl_Wayland_Screen_Driver::seat)); -//fprintf(stderr, "registry_handle_global: seat=%p\n", scr_driver->seat); - wl_list_init(&scr_driver->seat->pointer_outputs); - scr_driver->seat->wl_seat = (wl_seat*)wl_registry_bind(wl_registry, id, - &wl_seat_interface, 3); - scr_driver->seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (scr_driver->seat->xkb_context) { - const char *locale = getenv("LC_ALL"); - if (!locale || !*locale) - locale = getenv("LC_CTYPE"); - if (!locale || !*locale) - locale = getenv("LANG"); - if (!locale || !*locale) - locale = "C"; - struct xkb_compose_table *table = - xkb_compose_table_new_from_locale(scr_driver->seat->xkb_context, locale, - XKB_COMPOSE_COMPILE_NO_FLAGS); - if (table) { - scr_driver->seat->xkb_compose_state = - xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS); - } - } - wl_seat_add_listener(scr_driver->seat->wl_seat, &seat_listener, scr_driver->seat); - if (scr_driver->seat->data_device_manager) { - scr_driver->seat->data_device = - wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager, - scr_driver->seat->wl_seat); - wl_data_device_add_listener(scr_driver->seat->data_device, - Fl_Wayland_Screen_Driver::p_data_device_listener, NULL); - } - - } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { - if (!scr_driver->seat) scr_driver->seat = - (struct Fl_Wayland_Screen_Driver::seat*)calloc(1, - sizeof(struct Fl_Wayland_Screen_Driver::seat)); - scr_driver->seat->data_device_manager = - (struct wl_data_device_manager*)wl_registry_bind(wl_registry, id, - &wl_data_device_manager_interface, - fl_min(version, 3)); - if (scr_driver->seat->wl_seat) { - scr_driver->seat->data_device = - wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager, - scr_driver->seat->wl_seat); - wl_data_device_add_listener(scr_driver->seat->data_device, - Fl_Wayland_Screen_Driver::p_data_device_listener, NULL); - } -//fprintf(stderr, "registry_handle_global: %s\n", interface); - - } else if (strcmp(interface, "wl_output") == 0) { - if (version < 2) { - Fl::fatal("%s version 2 required but only version %i is available\n", - interface, version); - } - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output); - output->id = id; - output->wld_scale = 1; -#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION - const int used_version = WL_OUTPUT_RELEASE_SINCE_VERSION; -#else - const int used_version = 2; -#endif - output->wl_output = (struct wl_output*)wl_registry_bind(wl_registry, - id, &wl_output_interface, fl_min(used_version, version)); - output->gui_scale = 1.f; - wl_proxy_set_tag((struct wl_proxy *) output->wl_output, &proxy_tag); - wl_output_add_listener(output->wl_output, &output_listener, output); - // Put new screen in list of screens, but make sure it's not in list already - // which may occur after having removed a screen. - bool found = false; - Fl_Wayland_Screen_Driver::output *elt; - wl_list_for_each(elt, &scr_driver->outputs, link) { - if (elt == output) found = true; - } - if (!found) { // add to end of the linked list of displays - struct wl_list *e = &scr_driver->outputs; - while (e->next != &scr_driver->outputs) e = e->next; // move e to end of linked list - wl_list_insert(e, &output->link); - } -//fprintf(stderr, "wl_output: id=%d wl_output=%p \n", id, output->wl_output); - - } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { -//fprintf(stderr, "registry_handle_global interface=%s\n", interface); - scr_driver->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, id, - &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(scr_driver->xdg_wm_base, &xdg_wm_base_listener, NULL); - } else if (strstr(interface, "wf_shell_manager")) { - ((pair_bool*)user_data)->found_wf_shell = true; - } else if (strcmp(interface, "gtk_shell1") == 0) { - ((pair_bool*)user_data)->found_gtk_shell = true; - //fprintf(stderr, "Running the Mutter compositor\n"); - scr_driver->seat->gtk_shell = (struct gtk_shell1*)wl_registry_bind(wl_registry, id, - >k_shell1_interface, version); - } else if (strcmp(interface, "weston_desktop_shell") == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::WESTON; - //fprintf(stderr, "Running the Weston compositor\n"); - } else if (strcmp(interface, "org_kde_plasma_shell") == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::KWIN; - //fprintf(stderr, "Running the KWin compositor\n"); - } else if (strncmp(interface, "zowl_mach_ipc", 13) == 0) { - Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::OWL; - //fprintf(stderr, "Running the Owl compositor\n"); - if (wl_list_length(&scr_driver->outputs) == 0) { - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output); - output->id = 1; - output->wld_scale = 1; - output->gui_scale = 1.f; - output->width = 1440; output->height = 900; - output->pixel_width = 1440; output->pixel_height = 900; - output->done = true; - wl_list_insert(&(scr_driver->outputs), &output->link); - scr_driver->screen_count_set(1); - } - } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { - scr_driver->text_input_base = (struct zwp_text_input_manager_v3 *) - wl_registry_bind(wl_registry, id, &zwp_text_input_manager_v3_interface, 1); -//printf("scr_driver->text_input_base=%p version=%d\n",scr_driver->text_input_base,version); -#if HAVE_XDG_DIALOG - } else if (strcmp(interface, xdg_wm_dialog_v1_interface.name) == 0) { - scr_driver->xdg_wm_dialog = (struct xdg_wm_dialog_v1 *) - wl_registry_bind(wl_registry, id, &xdg_wm_dialog_v1_interface, 1); -#endif // HAVE_XDG_DIALOG -#if HAVE_CURSOR_SHAPE - } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { - scr_driver->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *) - wl_registry_bind(wl_registry, id, &wp_cursor_shape_manager_v1_interface, 1); -#endif // HAVE_CURSOR_SHAPE - } -} - - -static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { - Fl_Wayland_Screen_Driver::output *output; -//fprintf(stderr, "registry_handle_global_remove data=%p id=%u\n", data, name); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - bool has_removed_screen = false; - wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens - if (output->id == name) { // the screen being removed - wl_list_remove(&output->link); - wl_output_destroy(output->wl_output); - free(output); - has_removed_screen = true; - break; - } - } - if (has_removed_screen) { - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - scr_driver->init_workarea(); - } -} - - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - - -static void wayland_socket_callback(int fd, struct wl_display *display) -{ - if (wl_display_prepare_read(display) == -1) { - wl_display_dispatch_pending(display); - return; - } - wl_display_flush(display); - struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 }; - if (poll(&fds, 1, 0) <= 0) { - wl_display_cancel_read(display); - return; - } - if (fds.revents & (POLLERR | POLLHUP)) { - wl_display_cancel_read(display); - goto fatal; - } - if (wl_display_read_events(display) == -1) - goto fatal; - if (wl_display_dispatch_pending(display) == -1) - goto fatal; - return; -fatal: - if (wl_display_get_error(display) == EPROTO) { - const struct wl_interface *interface; - int code = wl_display_get_protocol_error(display, &interface, NULL); - Fl::fatal("Fatal error %d in Wayland protocol: %s", - code, (interface ? interface->name : "unknown") ); - } else { - Fl::fatal("Fatal error while communicating with Wayland server: %s", - strerror(errno)); - } -} - - -Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() { - libdecor_context = NULL; - seat = NULL; - text_input_base = NULL; - reset_cursor(); - wl_registry = NULL; -#if HAVE_XDG_DIALOG - xdg_wm_dialog = NULL; -#endif -#if HAVE_CURSOR_SHAPE - wp_cursor_shape_manager = NULL; - wp_cursor_shape_device = NULL; -#endif -} - - -static void sync_done(void *data, struct wl_callback *cb, uint32_t time) { - // runs after all calls to registry_handle_global() - *(struct wl_callback **)data = NULL; - wl_callback_destroy(cb); - // keep processing until output_done() has run for each screen - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &scr_driver->outputs, link) { // each screen of the system - while (!output->done) wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - // Now all screens have been initialized - scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) ); - struct pair_bool *pair = (struct pair_bool*)wl_registry_get_user_data(scr_driver->wl_registry); - if (pair->found_gtk_shell || pair->found_wf_shell) { - Fl_Wayland_Screen_Driver::compositor = (pair->found_wf_shell ? - Fl_Wayland_Screen_Driver::WAYFIRE : Fl_Wayland_Screen_Driver::MUTTER); - } - if (scr_driver->seat) { -#if HAVE_CURSOR_SHAPE - if (!scr_driver->wp_cursor_shape_manager) -#endif - try_update_cursor(scr_driver->seat); - } - if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::OWL) scr_driver->init_workarea(); -} - - -static const struct wl_callback_listener sync_listener = { - sync_done -}; - - -static void do_atexit() { - if (Fl_Wayland_Screen_Driver::wl_display) { - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } -} - - -void Fl_Wayland_Screen_Driver::open_display_platform() { - static bool beenHereDoneThat = false; - if (beenHereDoneThat) - return; - - beenHereDoneThat = true; - - if (!wl_display) { - wl_display = wl_display_connect(NULL); - if (!wl_display) { - Fl::fatal("No Wayland connection\n"); - } - } - //puts("Using Wayland backend"); - wl_list_init(&outputs); - - wl_registry = wl_display_get_registry(wl_display); - struct pair_bool pair = {false, false}; - wl_registry_add_listener(wl_registry, ®istry_listener, &pair); - struct wl_callback *registry_cb = wl_display_sync(wl_display); - wl_callback_add_listener(registry_cb, &sync_listener, ®istry_cb); - while (registry_cb) wl_display_dispatch(wl_display); - Fl::add_fd(wl_display_get_fd(wl_display), FL_READ, (Fl_FD_Handler)wayland_socket_callback, - wl_display); - fl_create_print_window(); - /* This is useful to avoid crash of the Wayland compositor after - FLTK apps terminate in certain situations: - - gnome-shell version < 44 (e.g. version 42.9) - - focus set to "follow-mouse" - See issue #821 for details. - */ - atexit(do_atexit); -} - - -void Fl_Wayland_Screen_Driver::close_display() { - if (!Fl_Wayland_Screen_Driver::wl_display) return; - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (text_input_base) { - disable_im(); - zwp_text_input_manager_v3_destroy(text_input_base); - text_input_base = NULL; - } - while (wl_list_length(&outputs) > 0) { - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - wl_list_remove(&output->link); - screen_count_set( wl_list_length(&outputs) ); - if (output->wl_output) { -#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION - if (wl_output_get_version(output->wl_output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) - wl_output_release(output->wl_output); - else -#endif - wl_output_destroy(output->wl_output); - } - free(output); - break; - } - } - wl_subcompositor_destroy(wl_subcompositor); wl_subcompositor = NULL; - wl_surface_destroy(seat->cursor_surface); seat->cursor_surface = NULL; - if (seat->cursor_theme) { - wl_cursor_theme_destroy(seat->cursor_theme); - seat->cursor_theme = NULL; - } - wl_compositor_destroy(wl_compositor); wl_compositor = NULL; - // wl_shm-related data - if (Fl_Wayland_Graphics_Driver::current_pool) { - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data = - (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*) - wl_shm_pool_get_user_data(Fl_Wayland_Graphics_Driver::current_pool); - wl_shm_pool_destroy(Fl_Wayland_Graphics_Driver::current_pool); - Fl_Wayland_Graphics_Driver::current_pool = NULL; - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); - //printf("close_display munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - wl_shm_destroy(wl_shm); wl_shm = NULL; - if (seat->wl_keyboard) { - if (seat->xkb_state) { - xkb_state_unref(seat->xkb_state); - seat->xkb_state = NULL; - } - if (seat->xkb_keymap) { - xkb_keymap_unref(seat->xkb_keymap); - seat->xkb_keymap = NULL; - } - wl_keyboard_destroy(seat->wl_keyboard); - seat->wl_keyboard = NULL; - } - wl_pointer_destroy(seat->wl_pointer); seat->wl_pointer = NULL; - if (seat->xkb_compose_state) { - xkb_compose_state_unref(seat->xkb_compose_state); - seat->xkb_compose_state = NULL; - } - if (seat->xkb_context) { - xkb_context_unref(seat->xkb_context); - seat->xkb_context = NULL; - } - if (seat->data_source) { - wl_data_source_destroy(seat->data_source); - seat->data_source = NULL; - } - wl_data_device_destroy(seat->data_device); seat->data_device = NULL; - wl_data_device_manager_destroy(seat->data_device_manager); - seat->data_device_manager = NULL; - wl_seat_destroy(seat->wl_seat); seat->wl_seat = NULL; - if (seat->name) free(seat->name); - free(seat); seat = NULL; - if (libdecor_context) { - libdecor_unref(libdecor_context); - libdecor_context = NULL; - } - xdg_wm_base_destroy(xdg_wm_base); xdg_wm_base = NULL; - Fl_Wayland_Plugin *plugin = Fl_Wayland_Window_Driver::gl_plugin(); - if (plugin) plugin->terminate(); -#if HAVE_XDG_DIALOG - if (xdg_wm_dialog) { - xdg_wm_dialog_v1_destroy(xdg_wm_dialog); - xdg_wm_dialog = NULL; - } -#endif // HAVE_XDG_DIALOG -#if HAVE_CURSOR_SHAPE - if (wp_cursor_shape_device ) { - wp_cursor_shape_device_v1_destroy(wp_cursor_shape_device); - wp_cursor_shape_device = NULL; - } - if (wp_cursor_shape_manager ) { - wp_cursor_shape_manager_v1_destroy(wp_cursor_shape_manager); - wp_cursor_shape_manager = NULL; - } -#endif // HAVE_CURSOR_SHAPE - - Fl::remove_fd(wl_display_get_fd(Fl_Wayland_Screen_Driver::wl_display)); - wl_registry_destroy(wl_registry); wl_registry = NULL; - wl_display_disconnect(Fl_Wayland_Screen_Driver::wl_display); - Fl_Wayland_Screen_Driver::wl_display = NULL; - delete Fl_Display_Device::display_device()->driver(); - delete Fl_Display_Device::display_device(); - delete Fl::system_driver(); - delete this; -} - - -struct configure_s { int W, H; uint32_t state; }; - -static void xdg_toplevel_configure(void *v, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - struct configure_s *data = (struct configure_s*)v; - data->W = width; - data->H = height; - data->state = (width && height && states ? *(uint32_t *)(states->data) : 0); -} - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure, -}; - - -static bool compute_full_and_maximized_areas(Fl_Wayland_Screen_Driver::output *output, - int& Wfullscreen, int& Hfullscreen, - int& Wworkarea, int& Hworkarea) { - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::unspecified) { - Wfullscreen = 0; - return false; - } - bool found_workarea = false; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wl_surface *wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor); - wl_surface_set_opaque_region(wl_surface, NULL); - struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface); - struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); - struct configure_s data = {0, 0, 0}; - xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, &data); - xdg_toplevel_set_fullscreen(xdg_toplevel, output->wl_output); - wl_surface_commit(wl_surface); // necessary under KWin - while (data.state != XDG_TOPLEVEL_STATE_FULLSCREEN) - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - Wfullscreen = data.W; - Hfullscreen = data.H; - if (Wfullscreen && Hfullscreen && wl_list_length(&scr_driver->outputs) == 1) { - struct wl_surface *wl_surface2 = wl_compositor_create_surface(scr_driver->wl_compositor); - struct xdg_surface *xdg_surface2 = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface2); - struct xdg_toplevel *xdg_toplevel2 = xdg_surface_get_toplevel(xdg_surface2); - struct configure_s data2 = {0, 0, 0}; - xdg_toplevel_add_listener(xdg_toplevel2, &xdg_toplevel_listener, &data2); - xdg_toplevel_set_parent(xdg_toplevel2, xdg_toplevel); - xdg_toplevel_set_maximized(xdg_toplevel2); - wl_surface_commit(wl_surface2); // necessary under KWin - while (data2.state != XDG_TOPLEVEL_STATE_MAXIMIZED) - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - Wworkarea = data2.W; - Hworkarea = data2.H; - xdg_toplevel_destroy(xdg_toplevel2); - xdg_surface_destroy(xdg_surface2); - wl_surface_destroy(wl_surface2); - if (Wworkarea == Wfullscreen && Hworkarea < Hfullscreen && Hworkarea > Hfullscreen - 80) - found_workarea = true; - if (Hworkarea == Hfullscreen && Wworkarea < Wfullscreen && Wworkarea > Wfullscreen - 80) - found_workarea = true; - } else { - Wworkarea = Wfullscreen; - Hworkarea = Hfullscreen; - } - xdg_toplevel_destroy(xdg_toplevel); - xdg_surface_destroy(xdg_surface); - wl_surface_destroy(wl_surface); - /*int fractional_scale = int(100 * (output->pixel_width / float(Wfullscreen))); - printf("fullscreen=%dx%d workarea=%dx%d fractional_scale=%d%% wld_s=%d\n", - Wfullscreen,Hfullscreen,Wworkarea,Hworkarea,fractional_scale,output->wld_scale);*/ - return found_workarea; -} - -static int workarea_xywh[4] = { -1, -1, -1, -1 }; - - -/* Implementation note about computing work area and about handling fractional scaling. - - FLTK computes 2 pairs of (WxH) values for each display: - 1) (pixel_width x pixel_height) gives the size in pixel of a display. It's unchanged by - any scaling applied by the compositor; it's assigned by function output_mode(). - 2) (width x height) gives the size in pixels of a buffer that would fully cover the display. - When the active scaling is non-fractional, these equations hold: - pixel_width = width = wld_scale * configured-width-of-fullscreen-window - pixel_height = height = wld_scale * configured-height-of-fullscreen-window - - When fractional scaling is active, buffers received from client are scaled down - by the compositor and mapped to screen. These equations hold: - pixel_width < width = wld_scale * configured-width-of-fullscreen-window - pixel_height < height = wld_scale * configured-height-of-fullscreen-window - - One way for a client to discover that fractional scaling is active on a given display - is to ask for a fullscreen window on that display, get its configured size and compare - it to that display's pixel size. That's what function compute_full_and_maximized_areas() does. - - One way for a client to discover the work area size of a display is to get the configured size - of a maximized window on that display. FLTK didn't find a way to control in general - on what display the compositor puts a maximized window. Therefore, FLTK computes an exact - work area size only when the system contains a single display. We create first a fullscreen - window on the display and then we create a maximized window made a child of the - fullscreen one and record its configured size. That's also done by function - compute_full_and_maximized_areas(). - */ - -void Fl_Wayland_Screen_Driver::init_workarea() -{ - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); // important after screen removal - bool need_init_workarea = true; - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - int Wfullscreen, Hfullscreen, Wworkarea, Hworkarea; - bool found_workarea = compute_full_and_maximized_areas(output, Wfullscreen, Hfullscreen, Wworkarea, Hworkarea); - if (Wfullscreen && Hfullscreen) { // skip sway which puts 0 there - output->width = Wfullscreen * output->wld_scale; // pixels - output->height = Hfullscreen * output->wld_scale; // pixels - if (found_workarea) { - workarea_xywh[0] = output->x; // pixels - workarea_xywh[1] = output->y; // pixels - workarea_xywh[2] = Wworkarea * output->wld_scale; // pixels - workarea_xywh[3] = Hworkarea * output->wld_scale; // pixels - need_init_workarea = false; - } - } - } - if (need_init_workarea) { - screen_xywh(workarea_xywh[0], workarea_xywh[1], workarea_xywh[2], workarea_xywh[3], 0); - } - Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); -} - - -int Fl_Wayland_Screen_Driver::x() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[0] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::y() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[1] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::w() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[2] / (output->gui_scale * output->wld_scale); -} - - -int Fl_Wayland_Screen_Driver::h() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &outputs, link) { - break; - } - return workarea_xywh[3] / (output->gui_scale * output->wld_scale); -} - - -void Fl_Wayland_Screen_Driver::init() { - if (!Fl_Wayland_Screen_Driver::wl_registry) open_display(); -} - - -void Fl_Wayland_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - if (n == 0) { // for the main screen, these return the work area - X = Fl::x(); - Y = Fl::y(); - W = Fl::w(); - H = Fl::h(); - } else { // for other screens, work area is full screen, - screen_xywh(X, Y, W, H, n); - } -} - - -void Fl_Wayland_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - if (num_screens > 0) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { // n'th screen of the system - float s = output->gui_scale * output->wld_scale; - X = output->x / s; - Y = output->y / s; - W = output->width / s; - H = output->height / s; - break; - } - } - } -} - - -void Fl_Wayland_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - - if (n >= 0 && n < num_screens) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { // n'th screen of the system - h = output->dpi; - v = output->dpi; - break; - } - } - } -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_Wayland_Screen_Driver::beep(int type) -{ - fprintf(stderr, "\007"); -} - - -void Fl_Wayland_Screen_Driver::flush() -{ - if (Fl_Wayland_Screen_Driver::wl_display) { - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - } -} - - -extern void fl_fix_focus(); // in Fl.cxx - - -void Fl_Wayland_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab()) { - } - Fl::grab_ = win; // FIXME: Fl::grab_ "should be private", but we need - // a way to *set* the variable from the driver! - } else { - if (Fl::grab()) { - // We must keep the grab in the non-EWMH fullscreen case - Fl::grab_ = 0; // FIXME: Fl::grab_ "should be private", but we need - // a way to *set* the variable from the driver! - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -static void getsyscolor(const char *key1, const char* key2, const char *arg, - const char *defarg, void (*func)(uchar,uchar,uchar)) { - uchar r, g, b; - if (!arg) arg = defarg; - if (!Fl::screen_driver()->parse_color(arg, r, g, b)) - Fl::error("Unknown color: %s", arg); - else - func(r, g, b); -} - - -void Fl_Wayland_Screen_Driver::get_system_colors() -{ - open_display(); - const char* key1 = 0; - if (Fl::first_window()) key1 = Fl::first_window()->xclass(); - if (!key1) key1 = "fltk"; - if (!bg2_set) - getsyscolor("Text","background", fl_bg2, "#ffffff", Fl::background2); - if (!fg_set) - getsyscolor(key1, "foreground", fl_fg, "#000000", Fl::foreground); - if (!bg_set) - getsyscolor(key1, "background", fl_bg, "#c0c0c0", Fl::background); - getsyscolor("Text", "selectBackground", 0, "#000080", set_selection_color); -} - - -Fl_RGB_Image *Fl_Wayland_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, - Fl_Window *win, - bool ignore, bool *p_ignore) { - struct wld_window* xid = win ? fl_wl_xid(win) : NULL; - if (win && (!xid || !xid->buffer)) return NULL; - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer; - if (win) buffer = &xid->buffer->draw_buffer; - else { - Fl_Image_Surface_Driver *dr = (Fl_Image_Surface_Driver*)Fl_Surface_Device::surface(); - buffer = Fl_Wayland_Graphics_Driver::offscreen_buffer( - dr->image_surface()->offscreen()); - } - float s = win ? - Fl_Wayland_Window_Driver::driver(win)->wld_scale() * scale(win->screen_num()) : - Fl_Surface_Device::surface()->driver()->scale(); - int Xs, Ys, ws, hs; - if (s == 1) { - Xs = X; Ys = Y; ws = w; hs = h; - } else { - Xs = Fl_Scalable_Graphics_Driver::floor(X, s); - Ys = Fl_Scalable_Graphics_Driver::floor(Y, s); - ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Xs; - hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Ys; - } - if (ws == 0 || hs == 0) return NULL; - uchar *data = new uchar[ws * hs * 3]; - uchar *p = data, *q; - for (int j = 0; j < hs; j++) { - q = buffer->buffer + (j+Ys) * buffer->stride + 4 * Xs; - for (int i = 0; i < ws; i++) { - *p++ = *(q+2); // R - *p++ = *(q+1); // G - *p++ = *q; // B - q += 4; - } - } - Fl_RGB_Image *rgb = new Fl_RGB_Image(data, ws, hs, 3); - rgb->alloc_array = 1; - return rgb; -} - - -void Fl_Wayland_Screen_Driver::offscreen_size(Fl_Offscreen off_, int &width, int &height) -{ - struct Fl_Wayland_Graphics_Driver::draw_buffer *off = Fl_Wayland_Graphics_Driver::offscreen_buffer(off_); - width = off->width; - height = off->data_size / off->stride; -} - - -float Fl_Wayland_Screen_Driver::scale(int n) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) break; - } - return output->gui_scale; -} - - -void Fl_Wayland_Screen_Driver::scale(int n, float f) { - Fl_Wayland_Screen_Driver::output *output; - int i = 0; - wl_list_for_each(output, &outputs, link) { - if (i++ == n) { - output->gui_scale = f; - return; - } - } -} - - -void Fl_Wayland_Screen_Driver::set_cursor() { - do_set_cursor(seat); -} - - -struct wl_cursor *Fl_Wayland_Screen_Driver::default_cursor() { - return seat->default_cursor; -} - - -void Fl_Wayland_Screen_Driver::default_cursor(struct wl_cursor *cursor) { - seat->default_cursor = cursor; - do_set_cursor(seat); -} - - -struct wl_cursor *Fl_Wayland_Screen_Driver::cache_cursor(const char *cursor_name) { - return wl_cursor_theme_get_cursor(seat->cursor_theme, cursor_name); -} - - -void Fl_Wayland_Screen_Driver::reset_cursor() { - for (int i = 0; i < cursor_count; i++) xc_cursor[i] = NULL; -} - - -uint32_t Fl_Wayland_Screen_Driver::get_serial() { - return seat->serial; -} - - -struct wl_seat*Fl_Wayland_Screen_Driver::get_wl_seat() { - return seat->wl_seat; -} - - -char *Fl_Wayland_Screen_Driver::get_seat_name() { - return seat->name; -} - - -struct xkb_keymap *Fl_Wayland_Screen_Driver::get_xkb_keymap() { - return seat->xkb_keymap; -} - - -int Fl_Wayland_Screen_Driver::get_mouse(int &xx, int &yy) { - open_display(); - xx = Fl::e_x_root; yy = Fl::e_y_root; - if (!seat->pointer_focus) return 0; - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus); - if (!win) return 0; - int snum = Fl_Window_Driver::driver(win)->screen_num(); -//printf("get_mouse(%dx%d)->%d\n", xx, yy, snum); - return snum; -} - - -void Fl_Wayland_Screen_Driver::set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) { - Fl_Wayland_Screen_Driver::insertion_point_location(x, y, height); -} - - -void Fl_Wayland_Screen_Driver::reset_spot() { - Fl::compose_state = 0; - Fl_Wayland_Screen_Driver::next_marked_length = 0; - Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false; -} - - -void Fl_Wayland_Screen_Driver::display(const char *d) -{ - if (d && !wl_registry) { // if display was opened, it's too late - if (wl_display) { - // only the wl_display_connect() call was done, redo it because the target - // Wayland compositor may be different - wl_display_disconnect(wl_display); - } - wl_display = wl_display_connect(d); - if (!wl_display) { - fprintf(stderr, "Error: '%s' is not an active Wayland socket\n", d); - exit(1); - } - } -} - - -void *Fl_Wayland_Screen_Driver::control_maximize_button(void *data) { - // The code below aims at removing the calling window's fullscreen button - // while dialog runs. Unfortunately, it doesn't work with some X11 window managers - // (e.g., KDE, xfce) because the button goes away but doesn't come back, - // so we move this code to a virtual member function. - // Noticeably, this code works OK under Wayland. - struct win_dims { - Fl_Widget_Tracker *tracker; - int minw, minh, maxw, maxh; - struct win_dims *next; - }; - - if (!data) { // this call turns each decorated window's maximize button off - struct win_dims *first_dim = NULL; - // consider all bordered, top-level FLTK windows - Fl_Window *win = Fl::first_window(); - while (win) { - if (!win->parent() && win->border() && - !( ((struct wld_window*)Fl_X::flx(win)->xid)->state & - LIBDECOR_WINDOW_STATE_MAXIMIZED) ) { - win_dims *dim = new win_dims; - dim->tracker = new Fl_Widget_Tracker(win); - win->get_size_range(&dim->minw, &dim->minh, &dim->maxw, &dim->maxh, NULL, NULL, NULL); - //make win un-resizable - win->size_range(win->w(), win->h(), win->w(), win->h()); - dim->next = first_dim; - first_dim = dim; - } - win = Fl::next_window(win); - } - return first_dim; - } else { // this call returns each decorated window's maximize button to its previous state - win_dims *first_dim = (win_dims *)data; - while (first_dim) { - win_dims *dim = first_dim; - //give back win its resizing parameters - if (dim->tracker->exists()) { - Fl_Window *win = (Fl_Window*)dim->tracker->widget(); - win->size_range(dim->minw, dim->minh, dim->maxw, dim->maxh); - } - first_dim = dim->next; - delete dim->tracker; - delete dim; - } - return NULL; - } -} - - -int Fl_Wayland_Screen_Driver::poll_or_select_with_delay(double time_to_wait) { - if (wl_display_dispatch_pending(wl_display) > 0) return 1; - return Fl_Unix_Screen_Driver::poll_or_select_with_delay(time_to_wait); -} - - -// like Fl_Wayland_Screen_Driver::poll_or_select_with_delay(0.0) except no callbacks are done: -int Fl_Wayland_Screen_Driver::poll_or_select() { - int ret = wl_display_prepare_read(wl_display); - if (ret == 0) wl_display_cancel_read(wl_display); - else return 1; - return Fl_Unix_Screen_Driver::poll_or_select(); -} - - -int Fl_Wayland_Screen_Driver::event_key(int k) { - if (k >= 'A' && k <= 'Z') k += 32; - return (search_int_vector(key_vector, k) >= 0); -} - - -int Fl_Wayland_Screen_Driver::get_key(int k) { - return event_key(k); -} - - -float Fl_Wayland_Screen_Driver::base_scale(int numscreen) { - const char *p; - float factor = 1; - if ((p = fl_getenv("FLTK_SCALING_FACTOR"))) { - sscanf(p, "%f", &factor); - } - return factor; -} - - -struct wl_display *fl_wl_display() { - return Fl_Wayland_Screen_Driver::wl_display; -} diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H deleted file mode 100644 index c5c1bee50..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H +++ /dev/null @@ -1,185 +0,0 @@ -// -// Definition of Wayland window driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_Wayland_Window_Driver.H - \brief Definition of Wayland window driver. - */ - -#ifndef FL_WAYLAND_WINDOW_DRIVER_H -#define FL_WAYLAND_WINDOW_DRIVER_H - -#include <config.h> -#include "../../Fl_Window_Driver.H" -#include <FL/Fl_Plugin.H> -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" - - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - */ - -typedef struct _cairo_pattern cairo_pattern_t; -typedef struct _cairo_rectangle_int cairo_rectangle_int_t; -class Fl_Wayland_Plugin; - - -class Fl_Wayland_Window_Driver : public Fl_Window_Driver -{ - friend class Fl_Wayland_Gl_Window_Driver; -private: - struct shape_data_type { - int lw_; ///< width of shape image - int lh_; ///< height of shape image - Fl_Image* shape_; ///< shape image - cairo_pattern_t *mask_pattern_; - } *shape_data_; - bool can_expand_outside_parent_; // specially to allow window docking (#987) - cairo_rectangle_int_t *subRect_; // makes sure subwindow remains inside its parent window - static bool in_flush_; // useful for progressive window drawing - Fl_Cursor standard_cursor_; // window's standard custom kind - struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish - bool is_popup_window_; -public: - inline Fl_Cursor standard_cursor() { return standard_cursor_; } - bool in_handle_configure; // distinguish OS and user window resize - - struct surface_output { // for linked list of displays where a surface maps - struct Fl_Wayland_Screen_Driver::output *output; - struct wl_list link; - }; - struct custom_cursor { - struct wl_cursor *wl_cursor; - const Fl_RGB_Image *rgb; - int hotx, hoty; - }; - static void delete_cursor(struct custom_cursor *custom, bool delete_rgb = true); - void decorated_win_size(int &w, int &h); - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) override; - FL_EXPORT int wld_scale(); // used by class Fl_Wayland_Gl_Window_Driver - cairo_rectangle_int_t *subRect() { return subRect_; } // getter - void subRect(cairo_rectangle_int_t *r); // setter - void checkSubwindowFrame(); - enum kind {DECORATED, SUBWINDOW, POPUP, UNFRAMED}; - struct xdg_toplevel *xdg_toplevel(); - Fl_Wayland_Window_Driver(Fl_Window*); - virtual ~Fl_Wayland_Window_Driver(); - static struct wld_window *wld_window; - static Fl_Window *surface_to_window(struct wl_surface *); - - static inline Fl_Wayland_Window_Driver* driver(const Fl_Window *w) { - return (Fl_Wayland_Window_Driver*)Fl_Window_Driver::driver(w); - } - static Fl_Wayland_Plugin *gl_plugin(); - - // --- window data - int decorated_w() override; - int decorated_h() override; - const Fl_Image* shape() override; - - // --- window management - void makeWindow() override; - void take_focus() override; - void flush() override; - void flush_overlay() override; - void draw_end() override; - void make_current() override; - void show() override; - void resize(int X,int Y,int W,int H) override; - void label(const char *name, const char *mininame) override; - void hide() override; - void map() override; - void unmap() override; - void fullscreen_on() override; - void fullscreen_off(int X, int Y, int W, int H) override; - void maximize() override; - void un_maximize() override; - void use_border() override; - void size_range() override; - void iconize() override; - void decoration_sizes(int *top, int *left, int *right, int *bottom) override; - // --- window cursor stuff - int set_cursor(Fl_Cursor) override; - int set_cursor(const Fl_RGB_Image*, int, int) override; - int set_cursor_4args(const Fl_RGB_Image*, int, int, bool); - - void shape(const Fl_Image* img) override; - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, - Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) override; - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) override; - void wait_for_expose() override; - // menu-related stuff - void reposition_menu_window(int x, int y) override; - void menu_window_area(int &X, int &Y, int &W, int &H, int nscreen = -1) override; - static bool new_popup; // to support tall menu buttons - bool process_menu_or_tooltip(struct wld_window *); - static Fl_Window *previous_floatingtitle; // to support floating menuwindow w/ title - void allow_expand_outside_parent() override { can_expand_outside_parent_ = true; } -}; - - -struct wld_window { - Fl_Window *fl_win; - struct wl_list outputs; // linked list of displays where part or whole of window maps - struct wl_surface *wl_surface; - struct wl_callback *frame_cb; - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer; - struct xdg_surface *xdg_surface; - union { // for each value of kind - struct libdecor_frame *frame; - struct wl_subsurface *subsurface; - struct xdg_popup *xdg_popup; - struct xdg_toplevel *xdg_toplevel; - }; - // non-null when using custom cursor - struct Fl_Wayland_Window_Driver::custom_cursor *custom_cursor; -#if HAVE_XDG_DIALOG - struct xdg_dialog_v1 *xdg_dialog; -#endif - enum Fl_Wayland_Window_Driver::kind kind; - int configured_width; - int configured_height; - int floating_width; - int floating_height; - int state; - bool covered; // specially for Mutter and issue #878 -}; - - -class Fl_Wayland_Plugin : public Fl_Plugin { -public: - Fl_Wayland_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "wayland.fltk.org"; } - virtual const char *name() = 0; - virtual void do_swap(Fl_Window*) = 0; - virtual void invalidate(Fl_Window*) = 0; - virtual void terminate() = 0; - virtual void destroy(struct gl_start_support *) = 0; -}; - -#endif // FL_WAYLAND_WINDOW_DRIVER_H diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx deleted file mode 100644 index 0495fb7bc..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ /dev/null @@ -1,2191 +0,0 @@ -// -// Implementation of the Wayland window driver. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/platform.H> -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include <FL/filename.H> -#include <wayland-cursor.h> -#include "../../../libdecor/build/fl_libdecor.h" -#include "xdg-shell-client-protocol.h" -#include "gtk-shell-client-protocol.h" -#if HAVE_XDG_DIALOG -# include "xdg-dialog-client-protocol.h" -#endif -#include <pango/pangocairo.h> -#include <FL/Fl_Overlay_Window.H> -#include <FL/Fl_Tooltip.H> -#include <FL/fl_draw.H> -#include <FL/fl_ask.H> -#include <FL/Fl.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_Menu_Button.H> -#include <string.h> -#include <math.h> // for ceil() -#include <sys/types.h> // for pid_t -#include <unistd.h> // for getpid() - -struct cursor_image { // as in wayland-cursor.c of the Wayland project source code - struct wl_cursor_image image; - struct wl_cursor_theme *theme; - struct wl_buffer *buffer; - int offset; /* data offset of this image in the shm pool */ -}; - -extern "C" { -# include "../../../libdecor/src/libdecor-plugin.h" - uchar *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame, int *w, int *h, int *stride); -} - -#define fl_max(a,b) ((a) > (b) ? (a) : (b)) -#define fl_min(a,b) ((a) < (b) ? (a) : (b)) - -#if !defined(FLTK_USE_X11) -Window fl_window = 0; -#endif - - -struct wld_window *Fl_Wayland_Window_Driver::wld_window = NULL; -bool Fl_Wayland_Window_Driver::new_popup = false; // to support tall menu buttons -// A menutitle to be mapped later as the child of a menuwindow -Fl_Window *Fl_Wayland_Window_Driver::previous_floatingtitle = NULL; - - -Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_Driver(win) -{ - shape_data_ = NULL; - standard_cursor_ = FL_CURSOR_DEFAULT; - in_handle_configure = false; - screen_num_ = -1; - gl_start_support_ = NULL; - subRect_ = NULL; - is_popup_window_ = false; - can_expand_outside_parent_ = false; -} - - -void Fl_Wayland_Window_Driver::delete_cursor( - struct Fl_Wayland_Window_Driver::custom_cursor *custom, bool delete_rgb) { - struct wl_cursor *wl_cursor = custom->wl_cursor; - struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0]; - struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen = - (struct Fl_Wayland_Graphics_Driver::wld_buffer *) - wl_buffer_get_user_data(new_image->buffer); - struct wld_window fake_xid; - memset(&fake_xid, 0, sizeof(fake_xid)); - fake_xid.buffer = offscreen; - Fl_Wayland_Graphics_Driver::buffer_release(&fake_xid); - free(new_image); - free(wl_cursor->images); - free(wl_cursor->name); - free(wl_cursor); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->default_cursor() == wl_cursor) { - scr_driver->default_cursor(scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow]); - } - if (delete_rgb) delete custom->rgb; - delete custom; -} - - -Fl_Wayland_Window_Driver::~Fl_Wayland_Window_Driver() -{ - if (shape_data_) { - cairo_surface_t *surface; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface); - uchar *data = cairo_image_surface_get_data(surface); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] data; - delete shape_data_; - } - if (subRect_) delete subRect_; - if (gl_start_support_) { // occurs only if gl_start/gl_finish was used - gl_plugin()->destroy(gl_start_support_); - } -} - - -void Fl_Wayland_Window_Driver::decorated_win_size(int &w, int &h) -{ - Fl_Window *win = pWindow; - w = win->w(); - h = win->h(); - if (!win->shown() || win->parent() || !win->border() || !win->visible()) return; - int X, titlebar_height; - libdecor_frame_translate_coordinate(fl_wl_xid(win)->frame, 0, 0, &X, &titlebar_height); -//printf("titlebar_height=%d\n",titlebar_height); - h = win->h() + ceil(titlebar_height / Fl::screen_scale(win->screen_num())); -} - - -int Fl_Wayland_Window_Driver::decorated_h() -{ - int w, h; - decorated_win_size(w, h); - return h; -} - - -int Fl_Wayland_Window_Driver::decorated_w() -{ - int w, h; - decorated_win_size(w, h); - return w; -} - - -struct xdg_toplevel *Fl_Wayland_Window_Driver::xdg_toplevel() { - struct wld_window * w = fl_wl_xid(pWindow); - struct xdg_toplevel *top = NULL; - if (w->kind == DECORATED) top = libdecor_frame_get_xdg_toplevel(w->frame); - else if (w->kind == UNFRAMED) top = w->xdg_toplevel; - return top; -} - - -void Fl_Wayland_Window_Driver::take_focus() -{ - struct wld_window *w = fl_wl_xid(pWindow); - if (w) { - Fl_Window *old_first = Fl::first_window(); - struct wld_window *first_xid = (old_first ? fl_wl_xid(old_first->top_window()) : NULL); - if (first_xid && first_xid != w && xdg_toplevel()) { - // this will move the target window to the front - Fl_Wayland_Window_Driver *top_dr = - Fl_Wayland_Window_Driver::driver(old_first->top_window()); - xdg_toplevel_set_parent(xdg_toplevel(), top_dr->xdg_toplevel()); - // this will remove the parent-child relationship - xdg_toplevel_set_parent(xdg_toplevel(), NULL); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } - // this sets the first window - fl_wl_find(w); - } -} - - -void Fl_Wayland_Window_Driver::flush_overlay() -{ - if (!shown()) return; - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - int erase_overlay = (pWindow->damage()&FL_DAMAGE_OVERLAY) | (overlay() == oWindow); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - pWindow->make_current(); - if (!other_xid) { - other_xid = new Fl_Image_Surface(oWindow->w(), oWindow->h(), 1); - oWindow->clear_damage(FL_DAMAGE_ALL); - } - if (oWindow->damage() & ~FL_DAMAGE_EXPOSE) { - Fl_X *myi = Fl_X::flx(pWindow); - fl_clip_region(myi->region); myi->region = 0; - Fl_Surface_Device::push_current(other_xid); - draw(); - Fl_Surface_Device::pop_current(); - } - if (erase_overlay) fl_clip_region(0); - if (other_xid) { - struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer = - Fl_Wayland_Graphics_Driver::offscreen_buffer(other_xid->offscreen()); - struct wld_window *xid = fl_wl_xid(pWindow); - struct Fl_Wayland_Graphics_Driver::wld_buffer *wbuffer = xid->buffer; - if (wbuffer->draw_buffer.data_size != buffer->data_size) { - fl_copy_offscreen(0, 0, oWindow->w(), oWindow->h(), other_xid->offscreen(), 0, 0); - } else { - memcpy(wbuffer->draw_buffer.buffer, buffer->buffer, wbuffer->draw_buffer.data_size); - } - } - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -const Fl_Image* Fl_Wayland_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - - -void Fl_Wayland_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::bitmap_to_pattern( - (Fl_Bitmap*)b, true, NULL); - shape_data_->shape_ = b; - shape_data_->lw_ = b->data_w(); - shape_data_->lh_ = b->data_h(); -} - - -void Fl_Wayland_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, j, d = img->d(), w = img->data_w(), h = img->data_h(); - int bytesperrow = cairo_format_stride_for_width(CAIRO_FORMAT_A1, w); - unsigned u; - uchar byte, onebit; - // build a CAIRO_FORMAT_A1 surface covering the non-fully transparent/black part of the image - uchar* bits = new uchar[h*bytesperrow]; // to store the surface data - const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of pixels - for (i = 0; i < h; i++) { - uchar *p = (uchar*)bits + i * bytesperrow; - byte = 0; - onebit = 1; - for (j = 0; j < w; j++) { - if (d == 3) { - u = *alpha; - u += *(alpha+1); - u += *(alpha+2); - } - else u = *alpha; - if (u > 0) { // if the pixel is not fully transparent/black - byte |= onebit; // turn on the corresponding bit of the bitmap - } - onebit = onebit << 1; // move the single set bit one position to the left - if (onebit == 0 || j == w-1) { - onebit = 1; - *p++ = ~byte; // store in bitmap one pack of bits, complemented - byte = 0; - } - alpha += d; // point to alpha value of next img pixel - } - } - cairo_surface_t *mask_surf = cairo_image_surface_create_for_data(bits, CAIRO_FORMAT_A1, - w, h, bytesperrow); - shape_data_->mask_pattern_ = cairo_pattern_create_for_surface(mask_surf); - cairo_surface_destroy(mask_surf); - shape_data_->shape_ = img; - shape_data_->lw_ = w; - shape_data_->lh_ = h; -} - - -void Fl_Wayland_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->mask_pattern_) { - cairo_surface_t *surface; - cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface); - uchar *data = cairo_image_surface_get_data(surface); - cairo_pattern_destroy(shape_data_->mask_pattern_); - delete[] data; - } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - pWindow->border(false); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); -} - - -void Fl_Wayland_Window_Driver::draw_end() -{ - if (shape_data_ && shape_data_->mask_pattern_) { - Fl_Wayland_Graphics_Driver *gr_dr = (Fl_Wayland_Graphics_Driver*)fl_graphics_driver; - cairo_t *cr = gr_dr->cr(); - cairo_matrix_t matrix; - cairo_matrix_init_scale(&matrix, double(shape_data_->lw_) / (pWindow->w() + 1), - double(shape_data_->lh_) / (pWindow->h() + 1) ); - cairo_matrix_translate(&matrix, 1, 1); - cairo_pattern_set_matrix(shape_data_->mask_pattern_, &matrix); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_mask(cr, shape_data_->mask_pattern_); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - } -} - - -/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders - (or NULL if a particular border is absent). - Returned images can be deleted after use. Their depth and size may be platform-dependent. - The top and bottom images extend from left of the left border to right of the right border. - */ -void Fl_Wayland_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, - Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) -{ - top = left = bottom = right = NULL; - if (pWindow->decorated_h() == h()) return; - int htop = pWindow->decorated_h() - pWindow->h(); - struct wld_window *wwin = fl_wl_xid(pWindow); - int width, height, stride; - uchar *cairo_data = fl_libdecor_titlebar_buffer(wwin->frame, &width, &height, &stride); - if (!cairo_data) return; - uchar *data = new uchar[width * height * 4]; - uchar *p = data; - for (int j = 0; j < height; j++) { - uchar *q = cairo_data + j * stride; - for (int i = 0; i < width; i++) { - *p++ = *(q+2); // R - *p++ = *(q+1); // G - *p++ = *q; // B - *p++ = *(q+3); // A - q += 4; - } - } - top = new Fl_RGB_Image(data, width, height, 4); - top->alloc_array = 1; - top->scale(pWindow->w(), htop); -} - - -// make drawing go into this window (called by subclass flush() impl.) -void Fl_Wayland_Window_Driver::make_current() { - if (!shown()) { - static const char err_message[] = "Fl_Window::make_current(), but window is not shown()."; - fl_alert(err_message); - Fl::fatal(err_message); - } - - struct wld_window *window = fl_wl_xid(pWindow); - if (window->buffer) { - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( - &window->buffer->draw_buffer_needs_commit); - } - - // to support progressive drawing - if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->frame_cb) && - (!wait_for_expose_value) ) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } - - Fl_Wayland_Window_Driver::wld_window = window; - fl_window = (Window)window; - float f = Fl::screen_scale(pWindow->screen_num()); - int wld_s = wld_scale(); - if (!window->buffer) { - window->buffer = Fl_Wayland_Graphics_Driver::create_wld_buffer( - int(pWindow->w() * f) * wld_s, int(pWindow->h() * f) * wld_s, false); - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( - &window->buffer->draw_buffer_needs_commit); - } - ((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_cairo( - window->buffer->draw_buffer.cairo_, f * wld_s); - ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->wld_scale = wld_s; - int *poffset = Fl_Window_Driver::menu_offset_y(pWindow); - if (poffset) { // for tall menu windows under KWIN to offset drawing inside window - cairo_translate(window->buffer->draw_buffer.cairo_, 0, *poffset); - } - cairo_rectangle_int_t *extents = subRect(); - if (extents) { // make damage-to-buffer not to leak outside parent - Fl_Region clip_region = fl_graphics_driver->XRectangleRegion(extents->x, extents->y, - extents->width, extents->height); -//printf("make_current: %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - Fl_X::flx(pWindow)->region = clip_region; - } - else fl_graphics_driver->clip_region(0); - -#ifdef FLTK_HAVE_CAIROEXT - // update the cairo_t context - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -#endif -} - - -void Fl_Wayland_Window_Driver::flush() { - if (!pWindow->damage()) return; - if (pWindow->as_gl_window()) { - int W = pWindow->w(); - int H = pWindow->h(); - float scale = fl_graphics_driver->scale(); - Fl_Wayland_Window_Driver::in_flush_ = true; - Fl_Window_Driver::flush(); - Fl_Wayland_Window_Driver::in_flush_ = false; - gl_plugin()->do_swap(pWindow); // useful only for GL win with overlay - if (scale != fl_graphics_driver->scale() || W != pWindow->w() || H != pWindow->h()) { - gl_plugin()->invalidate(pWindow); - } - return; - } - struct wld_window *window = fl_wl_xid(pWindow); - if (!window || !window->configured_width) return; - - Fl_X *ip = Fl_X::flx(pWindow); - cairo_region_t* r = (cairo_region_t*)ip->region; - if (!window->buffer || pWindow->as_overlay_window()) r = NULL; - - Fl_Wayland_Window_Driver::in_flush_ = true; - Fl_Window_Driver::flush(); - Fl_Wayland_Window_Driver::in_flush_ = false; - if (!window->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(window, r); -} - - -void Fl_Wayland_Window_Driver::show() { - if (!shown()) { - fl_open_display(); - makeWindow(); - } else { - // Wayland itself gives no way to programmatically unminimize a minimized window - Fl::handle(FL_SHOW, pWindow); - } -} - - -static void popup_done(void *data, struct xdg_popup *xdg_popup); - - -static void destroy_surface_caution_pointer_focus(struct wl_surface *surface, - struct Fl_Wayland_Screen_Driver::seat *seat) { - if (seat->pointer_focus == surface) seat->pointer_focus = NULL; - if (seat->keyboard_surface == surface) seat->keyboard_surface = NULL; - wl_surface_destroy(surface); -} - - -void Fl_Wayland_Window_Driver::hide() { - if (pWindow == Fl_Screen_Driver::transient_scale_parent) { - // Delete also the running transient scale window - // because the transient is a popup and MUST be deleted - // before its parent. - Fl::remove_timeout(Fl_Screen_Driver::del_transient_window); - Fl_Screen_Driver::del_transient_window(NULL); - } - Fl_X* ip = Fl_X::flx(pWindow); - if (hide_common()) return; - if (ip->region) { - Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - ip->region = 0; - } - screen_num_ = -1; - struct wld_window *wld_win = (struct wld_window*)ip->xid; - if (wld_win) { // this test makes sure ip->xid has not been destroyed already - Fl_Wayland_Graphics_Driver::buffer_release(wld_win); - if (wld_win->kind == SUBWINDOW && wld_win->subsurface) { - wl_subsurface_destroy(wld_win->subsurface); - wld_win->subsurface = NULL; - } -#if HAVE_XDG_DIALOG - if (wld_win->xdg_dialog) { - xdg_dialog_v1_destroy(wld_win->xdg_dialog); - wld_win->xdg_dialog = NULL; - } -#endif - if (wld_win->kind == DECORATED) { - libdecor_frame_unref(wld_win->frame); - wld_win->frame = NULL; - wld_win->xdg_surface = NULL; - } else { - if (wld_win->kind == POPUP && wld_win->xdg_popup) { - popup_done(xdg_popup_get_user_data(wld_win->xdg_popup), wld_win->xdg_popup); - wld_win->xdg_popup = NULL; - } - if (wld_win->kind == UNFRAMED && wld_win->xdg_toplevel) { - xdg_toplevel_destroy(wld_win->xdg_toplevel); - wld_win->xdg_toplevel = NULL; - } - if (wld_win->xdg_surface) { - xdg_surface_destroy(wld_win->xdg_surface); - wld_win->xdg_surface = NULL; - } - } - if (wld_win->custom_cursor) delete_cursor(wld_win->custom_cursor); - if (wld_win->wl_surface) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - destroy_surface_caution_pointer_focus(wld_win->wl_surface, scr_driver->seat); - wld_win->wl_surface = NULL; - } - while (!wl_list_empty(&wld_win->outputs)) { // remove from screens where it belongs - struct surface_output *s_output; - s_output = wl_container_of(wld_win->outputs.next, s_output, link); - wl_list_remove(&s_output->link); - free(s_output); - } - if (Fl_Wayland_Window_Driver::wld_window == wld_win) { - Fl_Wayland_Window_Driver::wld_window = NULL; - } - if (wld_win->frame_cb) wl_callback_destroy(wld_win->frame_cb); // useful for GL subwins - free(wld_win); - } - delete ip; -} - - -void Fl_Wayland_Window_Driver::map() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == SUBWINDOW && !wl_win->subsurface) { - struct wld_window *parent = fl_wl_xid(pWindow->window()); - if (parent) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - wl_win->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor, - wl_win->wl_surface, parent->wl_surface); - float f = Fl::screen_scale(pWindow->top_window()->screen_num()); - wl_subsurface_set_position(wl_win->subsurface, pWindow->x() * f, pWindow->y() * f); - wl_subsurface_set_desync(wl_win->subsurface); // important - wl_subsurface_place_above(wl_win->subsurface, parent->wl_surface); - wl_win->configured_width = pWindow->w(); - wl_win->configured_height = pWindow->h(); - wait_for_expose_value = 0; - pWindow->redraw(); - } - } -} - - -void Fl_Wayland_Window_Driver::unmap() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == SUBWINDOW && wl_win->wl_surface) { - wl_surface_attach(wl_win->wl_surface, NULL, 0, 0); - Fl_Wayland_Graphics_Driver::buffer_release(wl_win); - wl_subsurface_destroy(wl_win->subsurface); - wl_win->subsurface = NULL; - } -} - - -void Fl_Wayland_Window_Driver::size_range() { - if (shown()) { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - float f = Fl::screen_scale(pWindow->screen_num()); - int minw, minh, maxw, maxh; - pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (wl_win->kind == DECORATED && wl_win->frame) { - int X,Y,W,H; - Fl::screen_work_area(X,Y,W,H, Fl::screen_num(x(),y(),w(),h())); - if (maxw && maxw < W && maxh && maxh < H) { - libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN); - } else { - libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN); - } - if (maxw && maxh && (minw >= maxw || minh >= maxh)) { - libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE); - } else { - libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE); - } - libdecor_frame_set_min_content_size(wl_win->frame, minw*f, minh*f); - libdecor_frame_set_max_content_size(wl_win->frame, maxw*f, maxh*f); - if (xdg_toplevel()) { - struct libdecor_state *state = libdecor_state_new(int(w() * f), int(h() * f)); - libdecor_frame_commit(wl_win->frame, state, NULL); - libdecor_state_free(state); - } - } else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) { - xdg_toplevel_set_min_size(wl_win->xdg_toplevel, minw*f, minh*f); - if (maxw && maxh) - xdg_toplevel_set_max_size(wl_win->xdg_toplevel, maxw*f, maxh*f); - } - } -} - - -void Fl_Wayland_Window_Driver::iconize() { - Fl_X* ip = Fl_X::flx(pWindow); - struct wld_window *wl_win = (struct wld_window*)ip->xid; - if (wl_win->kind == DECORATED) { - libdecor_frame_set_minimized(wl_win->frame); - if (xdg_toplevel_get_version(xdg_toplevel()) < 6) { - Fl::handle(FL_HIDE, pWindow); - } - } - else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) xdg_toplevel_set_minimized(wl_win->xdg_toplevel); -} - - -void Fl_Wayland_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) -{ - struct wld_window *xid = (struct wld_window*)fl_xid(pWindow); - if (xid && xid->kind == DECORATED) { - libdecor_frame_translate_coordinate(xid->frame, 0, 0, left, top); - *right = *left; - *bottom = 0; - } else { - Fl_Window_Driver::decoration_sizes(top, left, right, bottom); - } -} - - -int Fl_Wayland_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, - int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) -{ - struct wld_window * xid = fl_wl_xid(pWindow); - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = xid->buffer; - float s = wld_scale() * fl_graphics_driver->scale(); - if (s != 1) { - src_x = src_x * s; - src_y = src_y * s; - src_w = src_w * s; - src_h = src_h * s; - dest_x = dest_x * s; - dest_y = dest_y * s; - } - if (src_x == dest_x) { // vertical scroll - int i, to, step; - if (src_y > dest_y) { - i = 0; to = src_h; step = 1; - } else { - i = src_h - 1; to = -1; step = -1; - } - while (i != to) { - memcpy( - buffer->draw_buffer.buffer + (dest_y + i) * buffer->draw_buffer.stride + 4 * dest_x, - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x, - 4 * src_w); - i += step; - } - } else { // horizontal scroll - int i, to, step; - if (src_x > dest_x) { - i = 0; to = src_h; step = 1; - } else { - i = src_h - 1; to = -1; step = -1; - } - while (i != to) { - memmove( - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * dest_x, - buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x, - 4 * src_w); - i += step; - } - } - return 0; -} - - -static void handle_error(struct libdecor *libdecor_context, enum libdecor_error error, const char *message) -{ - Fl::fatal("Caught error (%d): %s\n", error, message); -} - - -static struct libdecor_interface libdecor_iface = { - .error = handle_error, -}; - - - -static void delayed_rescale(Fl_Window *win) { - Fl_Window_Driver::driver(win)->is_a_rescale(true); - win->size(win->w(), win->h()); - Fl_Window_Driver::driver(win)->is_a_rescale(false); -} - - -void change_scale(Fl_Wayland_Screen_Driver::output *output, struct wld_window *window, - float pre_scale) { - Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - if (!window->fl_win->parent()) { - // for top-level, set its screen number when the 1st screen for this surface changes - Fl_Wayland_Screen_Driver::output *running_output; - Fl_Wayland_Screen_Driver *scr_dr = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - int i = 0; - wl_list_for_each(running_output, &scr_dr->outputs, link) { // each screen of the system - if (running_output == output) { // we've found our screen of the system - win_driver->screen_num(i); - break; - } - i++; - } - } - float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; -//printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); - if (post_scale != pre_scale) { - if (window->kind == Fl_Wayland_Window_Driver::POPUP) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - window->fl_win->redraw(); - } else { - // delaying the rescaling is necessary to set first the window's size_range according to the new screen - Fl::add_timeout(0, (Fl_Timeout_Handler)delayed_rescale, window->fl_win); - } - } -} - - -static void surface_enter(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - struct wld_window *window = (struct wld_window*)data; - - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - if (output == NULL) - return; - - bool list_was_empty = wl_list_empty(&window->outputs); - struct Fl_Wayland_Window_Driver::surface_output *surface_output = - (struct Fl_Wayland_Window_Driver::surface_output*)malloc( - sizeof(struct Fl_Wayland_Window_Driver::surface_output)); - surface_output->output = output; - // add to end of the linked list of displays of this surface - struct wl_list *e = &window->outputs; - while (e->next != &window->outputs) e = e->next; // move e to end of linked list - wl_list_insert(e, &surface_output->link); -//printf("window %p enters screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs)); - if (list_was_empty && !window->fl_win->parent()) { - change_scale(output, window, 0); - } -} - - -static void surface_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) { - if (!Fl_Wayland_Screen_Driver::own_output(wl_output)) - return; - struct wld_window *window = (struct wld_window*)data; - Fl_Wayland_Screen_Driver::output *output = - (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output); - Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale(); - struct Fl_Wayland_Window_Driver::surface_output *s_output; - int count = 0; - wl_list_for_each(s_output, &window->outputs, link) { - count++; - if (s_output->output == output) { - wl_list_remove(&s_output->link); - free(s_output); -//printf("window %p leaves screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs)); - break; - } - } - if (count == 1 && !wl_list_empty(&window->outputs) && !window->fl_win->parent()) { - s_output = wl_container_of(window->outputs.next, s_output, link); - change_scale(s_output->output, window, pre_scale); - } -} - - -static struct wl_surface_listener surface_listener = { - surface_enter, - surface_leave, -}; - - -Fl_Window *Fl_Wayland_Window_Driver::surface_to_window(struct wl_surface *surface) { - if (surface) { - if (wl_proxy_get_listener((struct wl_proxy *)surface) == &surface_listener) { - return ((struct wld_window *)wl_surface_get_user_data(surface))->fl_win; - } - } - return NULL; -} - - -static struct Fl_Wayland_Screen_Driver::output *screen_num_to_output(int num_screen) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - int i = 0; - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens of the system - if (i++ == num_screen) return output; - } - return NULL; -} - - -#define LIBDECOR_MR131 1 // this means libdecor does not include MR!131 yet - -#ifdef LIBDECOR_MR131 -/* === Beginning of hack that would become un-needed if libdecor accepted MR!131 === */ - -// true while the GUI is interactively resizing a decorated window -static bool in_decorated_window_resizing = false; - - -// libdecor's configure cb function for xdg_toplevel objects -static void (*decor_xdg_toplevel_configure)(void*, struct xdg_toplevel *, int32_t, - int32_t, struct wl_array *); - - -static void fltk_xdg_toplevel_configure(void *user_data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, - struct wl_array *states) { - uint32_t *p; - in_decorated_window_resizing = false; - // Replace wl_array_for_each(p, states) rejected by C++ - for (p = (uint32_t *)(states)->data; - (const char *) p < ((const char *) (states)->data + (states)->size); - (p)++) { - if (*p == XDG_TOPLEVEL_STATE_RESIZING) { - in_decorated_window_resizing = true; - break; - } - } - decor_xdg_toplevel_configure(user_data, xdg_toplevel, width, height, states); -} - - -struct wl_object { // copied from wayland-private.h - const struct wl_interface *interface; - const void *implementation; - uint32_t id; -}; - - -// replace libdecor's toplevel configure cb by FLTK's -static void use_FLTK_toplevel_configure_cb(struct libdecor_frame *frame) { - struct wl_object *object = (struct wl_object *)libdecor_frame_get_xdg_toplevel(frame); - static struct xdg_toplevel_listener *fltk_listener = NULL; - if (!fltk_listener) { - struct xdg_toplevel_listener *decor_listener = (struct xdg_toplevel_listener*) - object->implementation; - fltk_listener = (struct xdg_toplevel_listener*) - malloc(sizeof(struct xdg_toplevel_listener)); - // initialize FLTK's listener with libdecor's values - *fltk_listener = *decor_listener; - // memorize libdecor's toplevel configure cb - decor_xdg_toplevel_configure = decor_listener->configure; - // replace libdecor's toplevel configure cb by FLTK's - fltk_listener->configure = fltk_xdg_toplevel_configure; - } - // replace the toplevel listener by a copy whose configure member is FLTK's - object->implementation = fltk_listener; -} - -/* === End of hack that would become un-needed if libdecor accepted MR!131 === */ -#endif // LIBDECOR_MR131 - - -// does win entirely cover its parent ? -static void does_window_cover_parent(Fl_Window *win) { - Fl_Window *parent = win->window(); - fl_wl_xid(parent)->covered = (win->x() <= 0 && win->y() <= 0 && - win->w() >= parent->w() && win->h() >= parent->h()); -} - - -// recursively explore all shown subwindows in a window and call f for each -static void scan_subwindows(Fl_Group *g, void (*f)(Fl_Window *)) { - for (int i = 0; i < g->children(); i++) { - Fl_Widget *o = g->child(i); - if (o->as_window()) { - if (!o->as_window()->shown()) continue; - f(o->as_window()); - } - if (o->as_group()) scan_subwindows(o->as_group(), f); - } -} - -// Generate FL_APP_ACTIVATE and FL_APP_DEACTIVATE events -static bool app_has_active_window = false; - -// If a window is deactivated, check after a short delay if any other window has -// become active. If not, send an FL_APP_DEACTIVATE event. -static void deferred_check_app_deactivate(void*) { - if (!app_has_active_window) return; - app_has_active_window = false; - // Check all FLTK windows to see if any are still active - for (Fl_Window *w = Fl::first_window(); w; w = Fl::next_window(w)) { - if (w->visible_r()) { - struct wld_window* xid = fl_wl_xid(w); - if (xid && (xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - app_has_active_window = true; - break; - } - } - } - if (!app_has_active_window) Fl::handle(FL_APP_DEACTIVATE, nullptr); -} - -static void handle_configure(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, void *user_data) -{ - struct wld_window *window = (struct wld_window*)user_data; - if (!window->wl_surface) return; - int width, height; - enum libdecor_window_state window_state; - struct libdecor_state *state; - Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(window->fl_win); - // true exactly for the 1st run of handle_configure() for this window - bool is_1st_run = (window->xdg_surface == 0); - // true exactly for the 2nd run of handle_configure() for this window - bool is_2nd_run = (window->xdg_surface != 0 && driver->wait_for_expose_value); - float f = Fl::screen_scale(window->fl_win->screen_num()); - - if (!window->xdg_surface) window->xdg_surface = libdecor_frame_get_xdg_surface(frame); - -#ifdef LIBDECOR_MR131 - if (is_1st_run) use_FLTK_toplevel_configure_cb(frame); -#endif - struct wl_output *wl_output = NULL; - if (window->fl_win->fullscreen_active()) { - if (!(window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN)) { - if (Fl_Window_Driver::driver(window->fl_win)->force_position()) { - struct Fl_Wayland_Screen_Driver::output *output = - screen_num_to_output(window->fl_win->screen_num()); - if (output) wl_output = output->wl_output; - } - libdecor_frame_set_fullscreen(window->frame, wl_output); - } - } else if (driver->show_iconic()) { - libdecor_frame_set_minimized(window->frame); - driver->show_iconic(0); - } - if (!libdecor_configuration_get_window_state(configuration, &window_state)) - window_state = LIBDECOR_WINDOW_STATE_NONE; - if ((window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) && - !(window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) && !window->fl_win->border()) { - // necessary so Mutter correctly positions borderless window back from fullscreen - window->fl_win->redraw(); - } - window->state = window_state; - - // Weston, KWin, and some old versions of Mutter, on purpose, don't set the - // window width x height when xdg_toplevel_configure runs twice - // during resizable window creation - // (see https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/6). - // Consequently, libdecor_configuration_get_content_size() may return false twice. - // Weston and KWin, at least, don't change the window size asked by the client application - // which is available here in floating_{width,height}. - if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) { - if (is_2nd_run) { - width = window->floating_width; - height = window->floating_height; - if (!driver->is_resizable()) { - libdecor_frame_set_min_content_size(frame, width, height); - libdecor_frame_set_max_content_size(frame, width, height); - } - } else { width = height = 0; } - } - if (is_2nd_run && Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER) { - scan_subwindows(window->fl_win, does_window_cover_parent); // issue #878 - } - - if (window->fl_win->fullscreen_active() && - Fl_Window_Driver::driver(window->fl_win)->force_position()) { - int X, Y, W, H; - Fl::screen_xywh(X, Y, W, H, window->fl_win->screen_num()); - width = W * f; height = H * f; - } - - if (width == 0) { - width = window->floating_width; - height = window->floating_height; - //fprintf(stderr,"handle_configure: using floating %dx%d\n",width,height); - } - -#ifndef LIBDECOR_MR131 - bool in_decorated_window_resizing = (window->state & LIBDECOR_WINDOW_STATE_RESIZING); -#endif - bool condition = in_decorated_window_resizing; - if (condition) { // see issue #878 - condition = (window->covered ? (window->buffer && window->buffer->in_use) : (window->frame_cb != NULL)); - } - if (condition) { - // Skip resizing & redrawing. The last resize request won't be skipped because - // LIBDECOR_WINDOW_STATE_RESIZING will be off or cb will be NULL then. - return; - } - - driver->in_handle_configure = true; - window->fl_win->resize(0, 0, ceil(width / f), ceil(height / f)); - driver->in_handle_configure = false; - if (wl_output) window->fl_win->redraw(); - window->configured_width = ceil(width / f); - window->configured_height = ceil(height / f); - if (is_2nd_run) driver->wait_for_expose_value = 0; -//fprintf(stderr, "handle_configure fl_win=%p size:%dx%d state=%x wait_for_expose_value=%d is_2nd_run=%d\n", window->fl_win, width,height,window_state,driver->wait_for_expose_value, is_2nd_run); - - // When no window is active, and one window gets activated, generate an FL_APP_ACTIVATE event - if (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) { - if (!app_has_active_window) { - app_has_active_window = true; - Fl::handle(FL_APP_ACTIVATE, nullptr); - } - - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON) { - // After click on titlebar, weston calls wl_keyboard_enter() for a - // titlebar-related surface that FLTK can't identify, so we send FL_FOCUS here. - Fl::handle(FL_FOCUS, window->fl_win); - } - if (!window->fl_win->border()) libdecor_frame_set_visibility(window->frame, false); - else if (!libdecor_frame_is_visible(window->frame)) { - libdecor_frame_set_visibility(window->frame, true); - } else if (!window->fl_win->visible()) { - Fl::handle(FL_SHOW, window->fl_win); // useful when un-minimizing - } - } else if (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) { // window is minimized - Fl::handle(FL_HIDE, window->fl_win); - } - - // When a window gets deactivated and there are no other active windows, - // generate an FL_APP_DEACTIVATE event - if ( ((window_state & LIBDECOR_WINDOW_STATE_ACTIVE) == 0) && app_has_active_window) { - Fl::add_timeout(0.1, deferred_check_app_deactivate, nullptr); - } - - if (window->fl_win->border()) - driver->is_maximized(window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED); - if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) state = libdecor_state_new(width, - height); - else state = libdecor_state_new(int(ceil(width/f)*f), int(ceil(height/f)*f)); - libdecor_frame_commit(frame, state, configuration); - if (libdecor_frame_is_floating(frame)) { // store floating dimensions - window->floating_width = int(ceil(width/f)*f); - window->floating_height = int(ceil(height/f)*f); - //fprintf(stderr,"set floating_width+height %dx%d\n",width,height); - } - libdecor_state_free(state); - - driver->flush(); - if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::WESTON || !is_1st_run) { - window->fl_win->clear_damage(); - } -} - - -void Fl_Wayland_Window_Driver::wait_for_expose() -{ - Fl_Window_Driver::wait_for_expose(); - struct wld_window * xid = fl_wl_xid(pWindow); - if (!xid) return; - if (pWindow->fullscreen_active()) { - if (xid->kind == DECORATED) { - while (!(xid->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) || - !(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - } else if (xid->kind == UNFRAMED) { - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - } - } else if (xid->kind == DECORATED) { - // necessary for the windowfocus demo program with recent Wayland versions - if (!(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) { - wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display); - } - } -} - - -static void delayed_close(Fl_Window *win) { - Fl::remove_check((Fl_Timeout_Handler)delayed_close, win); - Fl::handle(FL_CLOSE, win); -} - - -static void handle_close(struct libdecor_frame *frame, void *user_data) -{ // runs when the close button of a window titlebar is pushed - // or after "Quit" of the application menu - // or after the Kill command of Sway - Fl_Window* win = ((struct wld_window*)user_data)->fl_win; - int X, Y; - libdecor_frame_translate_coordinate(frame, 0, 0, &X, &Y); - if (Y == 0) Fl::handle(FL_CLOSE, win); - else { - // the close window attempt is delayed because libdecor - // uses the frame after return from this function - Fl::add_check((Fl_Timeout_Handler)delayed_close, win); - } -} - - -static void handle_commit(struct libdecor_frame *frame, void *user_data) -{ - struct wld_window* wl_win = (struct wld_window*)user_data; - if (wl_win->wl_surface) wl_surface_commit(wl_win->wl_surface); -} - - -static void handle_dismiss_popup(struct libdecor_frame *frame, const char *seat_name, void *user_data) -{ -} - - -static struct libdecor_frame_interface libdecor_frame_iface = { - handle_configure, - handle_close, - handle_commit, - handle_dismiss_popup, -}; - - -static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) -{ - // runs for borderless windows and popup (menu,tooltip) windows - struct wld_window *window = (struct wld_window*)data; - xdg_surface_ack_configure(xdg_surface, serial); -//fprintf(stderr, "xdg_surface_configure: surface=%p\n", window->wl_surface); - - if (window->fl_win->w() != window->configured_width || - window->fl_win->h() != window->configured_height) { - if (window->buffer) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - } - } - window->configured_width = window->fl_win->w(); - window->configured_height = window->fl_win->h(); - Fl_Window_Driver::driver(window->fl_win)->flush(); - window->fl_win->clear_damage(); -} - - -static const struct xdg_surface_listener xdg_surface_listener = { - .configure = xdg_surface_configure, -}; - - -static bool parse_states_fullscreen(struct wl_array *states) -{ - uint32_t *p; - // Replace wl_array_for_each(p, states) rejected by C++ - for (p = (uint32_t *)(states)->data; - (const char *) p < ((const char *) (states)->data + (states)->size); - (p)++) { - if (*p == XDG_TOPLEVEL_STATE_FULLSCREEN) return true; - } - return false; -} - - -static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - // runs for borderless top-level windows - // under Weston: width & height are 0 during both calls, except if fullscreen - struct wld_window *window = (struct wld_window*)data; -//fprintf(stderr, "xdg_toplevel_configure: surface=%p size: %dx%d\n", window->wl_surface, width, height); - if (window->fl_win->fullscreen_active() && !parse_states_fullscreen(states)) { - struct wl_output *wl_output = NULL; - if (Fl_Window_Driver::driver(window->fl_win)->force_position()) { - struct Fl_Wayland_Screen_Driver::output *output = - screen_num_to_output(window->fl_win->screen_num()); - if (output) wl_output = output->wl_output; - } - xdg_toplevel_set_fullscreen(xdg_toplevel, wl_output); - if (wl_output) { - int X, Y; - Fl::screen_xywh(X, Y, width, height, window->fl_win->screen_num()); - } - } - if (window->configured_width) { - Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0; - } - float f = Fl::screen_scale(window->fl_win->screen_num()); - if (width == 0 || height == 0) { - width = window->fl_win->w() * f; - height = window->fl_win->h() * f; - } - window->fl_win->size(ceil(width / f), ceil(height / f)); - if (window->buffer && (ceil(width / f) != window->configured_width || - ceil(height / f) != window->configured_height)) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - } - window->configured_width = ceil(width / f); - window->configured_height = ceil(height / f); -} - - -static void xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel) -{ -} - - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure, - .close = xdg_toplevel_close, -}; - - -struct win_positioner { - struct wld_window *window; - int x, y; - Fl_Window *child_popup; -}; - - -static void popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, - int32_t width, int32_t height) { - struct win_positioner *win_pos = (struct win_positioner *)data; - struct wld_window *window = win_pos->window; -//printf("popup_configure %p asked:%dx%d got:%dx%d\n",window->fl_win, win_pos->x,win_pos->y, x,y); - Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0; - int HH; - Fl_Window_Driver::menu_parent(&HH); - if (window->fl_win->h() > HH && y != win_pos->y) { // A menu taller than the display - // Under KWin, height is set to the display height or less: we ignore that. - window->state = (y - win_pos->y); - // make selected item visible, if there's one - Fl_Window_Driver::scroll_to_selected_item(window->fl_win); - } - if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(window->fl_win)) { - int X, Y; - Fl_Window_Driver::current_menu_button->top_window_offset(X, Y); - if (y < Y) { - Fl_Window *win = window->fl_win; - win->Fl_Widget::resize(win->x(), Y - win->h(), win->w(), win->h()); - } - } -} - - -static struct xdg_popup *mem_grabbing_popup = NULL; - - -static void popup_done(void *data, struct xdg_popup *xdg_popup) { - struct win_positioner *win_pos = (struct win_positioner *)data; - struct wld_window *window = win_pos->window; -//fprintf(stderr, "popup_done: popup=%p data=%p xid=%p fl_win=%p\n", xdg_popup, data, window, window->fl_win); - if (win_pos->child_popup) win_pos->child_popup->hide(); - xdg_popup_destroy(xdg_popup); - delete win_pos; - // The sway compositor calls popup_done directly and hides the menu - // when the app looses focus. - // Thus, we hide the window so FLTK and Wayland are in matching states. - window->xdg_popup = NULL; - window->fl_win->hide(); - if (mem_grabbing_popup == xdg_popup) { - mem_grabbing_popup = NULL; - } -} - - -static const struct xdg_popup_listener popup_listener = { - .configure = popup_configure, - .popup_done = popup_done, -}; - - -bool Fl_Wayland_Window_Driver::in_flush_ = false; - - -static const char *get_prog_name() { - pid_t pid = getpid(); - char fname[100]; - snprintf(fname, 100, "/proc/%u/cmdline", pid); - FILE *in = fopen(fname, "r"); - if (in) { - static char line[200]; - const char *p = fgets(line, sizeof(line), in); - fclose(in); - p = strrchr(line, '/'); if (!p) p = line; else p++; - return p; - } - return "unknown"; -} - - -/* Implementation note about menu windows under Wayland. - Wayland offers a way to position popup windows such as menu windows using constraints. - Each popup is located relatively to a parent window which can be a popup itself and - MUST overlap or at least touch this parent. - Constraints determine how a popup is positioned relatively to a defined area (called - the anchor rectangle) of its parent popup/window and what happens when this position - would place the popup all or partly outside the display. - In contrast, FLTK computes the adequate positions of menu windows in the display using - knowledge about the display size and the location of the window in the display, and then - maps them at these positions. - These 2 logics are quite different because Wayland hides the position of windows inside the - display, whereas FLTK uses the location of windows inside the display to position popups. - Let's call "source window" the non-popup window above which all popups are mapped. - The approach implemented here is two-fold. - 1) If a menu window is not taller than the display, use Wayland constraints to position it. - Wayland imposes that the first constructed popup must overlap or touch the source window. - Other popups can be placed below, above, at right, or at left of a previous popup which - allows them to expand outside the source window, while constraints can ensure they won't - extend outside the display. - 2) A menu window taller than the display is initially mapped with the constraint to - begin at the top border of the display. This allows FLTK to know the distance between - the source window and the display top. FLTK can later reposition the same tall popup, - without the constraint not to go beyond the display top, at the exact position so that - the desired series of menu items appear in the visible part of the tall popup. - - In case 1) above, the values that represent the display bounds are given very - large values. That's done by member function Fl_Wayland_Window_Driver::menu_window_area(). - Consequently, FLTK computes an initial layout of future popups relatively to - the source window as if it was mapped on an infinitely large display. Then, the location - of the first popup to be mapped is modified if necessary so it overlaps or touches the - source window. Finally, other popups are located using Wayland logic below, above or to the - right of previous popups. Wayland constraints mechanism also allows a popup tentatively - placed below a previous one to be flipped above it if that prevents the popup from expanding - beyond display limits. This is used to unfold menu bar menus below or above the menu bar. - After each popup is created and scheduled for being mapped on display by function - process_menu_or_tooltip(), makeWindow() calls Fl_Window::wait_for_expose() so its constrained - position is known before computing the position of the next popup. This ensures each - popup is correctly placed relatively to its parent. - - Groups of popups containing a menutitle, the associated menuwindow, and optionally - a submenu window and that don't belong to an Fl_Menu_Bar are mapped in a different order: - the menuwindow is mapped first, and the menutitle is mapped second above it as a child popup. - Fl_Window_Driver::is_floating_title() detects when such a menutitle is created, - static member variable previous_floatingtitle is assigned the value of this menutitle, and - the menutitle is mapped only after the menuwindow has been mapped, as a child of it. - This positions better the popup group in the display relatively to where the popup - was created. - - In case 2) above, a tall popup is mapped with XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y - which puts its top at the display top border. The Wayland system then calls the - popup_configure() callback function with the x,y coordinates of the top left corner - where the popup is mapped relatively to an anchor point in the source window. - The difference between the asked window position and the effective position is stored - in the state member variable of the tall popup's struct wld_window. This information - allows FLTK to compute the distance between the source window top and the display top border. - Function Fl_Wayland_Window_Driver::menu_window_area() sets the top of the display to - a value such that function Fl_Wayland_Window_Driver::reposition_menu_window(), called by - menuwindow::autoscroll(int n), ensures that menu item #n is visible. Static boolean member - variable Fl_Wayland_Window_Driver::new_popup is useful to position tall menuwindows created - by an Fl_Menu_Button or Fl_Choice. It is set to true when any menu popup is created. - It is used each time menu_window_area() runs for a particular Fl_Menu_Button or Fl_Choice, - and is reset to false after its first use. This allows menu_window_area() to give the top of - the display an adequate value the first time and to keep this value next times it runs. - Fl_Window_Driver::scroll_to_selected_item() scrolls the tall popup so its selected - item, when there's one, is visible immediately after the tall popup is mapped on display. - */ - - -bool Fl_Wayland_Window_Driver::process_menu_or_tooltip(struct wld_window *new_window) { - // a menu window or tooltip - new_window->kind = Fl_Wayland_Window_Driver::POPUP; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (Fl_Window_Driver::is_floating_title(pWindow)) { - previous_floatingtitle = pWindow; - return true; - } - new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, - new_window->wl_surface); - xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window); - Fl_Wayland_Window_Driver::new_popup = true; - Fl_Window *menu_origin = NULL; - if (pWindow->menu_window()) { - menu_origin = Fl_Window_Driver::menu_leftorigin(pWindow); - if (!menu_origin && !previous_floatingtitle) menu_origin = - Fl_Window_Driver::menu_title(pWindow); - } - Fl_Widget *target = (pWindow->tooltip_window() ? Fl_Tooltip::current() : NULL); - if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display && - Fl_Screen_Driver::transient_scale_parent) { - target = Fl_Screen_Driver::transient_scale_parent; - } - if (!target) target = Fl_Window_Driver::menu_parent(); - if (!target) target = Fl::belowmouse(); - if (!target) target = Fl::first_window(); - Fl_Window *parent_win = target->top_window(); - while (parent_win && parent_win->menu_window() && driver(parent_win)->popup_window()) { - parent_win = Fl::next_window(parent_win); - } - Fl_Window *origin_win = (menu_origin ? menu_origin : parent_win); - struct wld_window * parent_xid = fl_wl_xid(origin_win); - struct xdg_surface *parent_xdg = parent_xid->xdg_surface; - float f = Fl::screen_scale(parent_win->screen_num()); - //fprintf(stderr, "menu parent_win=%p pos:%dx%d size:%dx%d\n", parent_win, pWindow->x(), pWindow->y(), pWindow->w(), pWindow->h()); -//printf("window=%p menutitle=%p bartitle=%d leftorigin=%p y=%d\n", pWindow, Fl_Window_Driver::menu_title(pWindow), Fl_Window_Driver::menu_bartitle(pWindow), Fl_Window_Driver::menu_leftorigin(pWindow), pWindow->y()); - struct xdg_positioner *positioner = xdg_wm_base_create_positioner(scr_driver->xdg_wm_base); - //xdg_positioner_get_version(positioner) <== gives 1 under Debian and Sway - int popup_x, popup_y; - if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(pWindow)) { - int X, Y; - Fl_Window_Driver::current_menu_button->top_window_offset(X, Y); - xdg_positioner_set_anchor_rect(positioner, X * f, Y * f, - Fl_Window_Driver::current_menu_button->w() * f, - Fl_Window_Driver::current_menu_button->h() * f); - popup_x = X * f; - popup_y = 0; - if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active()) - libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y, - &popup_x, &popup_y); - } else if (Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow)) { - xdg_positioner_set_anchor_rect(positioner, 0, 0, - Fl_Window_Driver::menu_title(pWindow)->w() * f, - Fl_Window_Driver::menu_title(pWindow)->h() * f); - popup_x = 0; - popup_y = Fl_Window_Driver::menu_title(pWindow)->h() * f; - } else { - popup_x = pWindow->x() * f; popup_y = pWindow->y() * f; - if (popup_x + pWindow->w() * f < 0) popup_x = - pWindow->w() * f; - if (menu_origin) { - popup_x -= menu_origin->x() * f; - popup_y -= menu_origin->y() * f; - } - if (popup_x >= origin_win->w() * f) popup_x = origin_win->w() * f - 1; - if (!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_bartitle(pWindow) && - !Fl_Window_Driver::menu_leftorigin(pWindow)) { - // prevent first popup from going above the permissible source window - popup_y = fl_max(popup_y, - pWindow->h() * f); - } - if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active()) - libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y, - &popup_x, &popup_y); - xdg_positioner_set_anchor_rect(positioner, popup_x, 0, 1, 1); - popup_y++; - } - int positioner_H = pWindow->h(); - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::KWIN) { - // Under KWIN, limiting the height of the positioner to the work area height - // results in tall popup windows starting at the top of the screen, what we want. - // Unfortunately, we know the work area height exactly only for single-screen systems, - // otherwise FLTK returns work area height == screen height. In that case we estimate - // work area height ≈ screen height - 44. - int V, work_area_H, screen_H; - Fl::screen_work_area(V, V, V, work_area_H, origin_win->screen_num()); - Fl::screen_xywh(V, V, V, screen_H, origin_win->screen_num()); - if (work_area_H == screen_H) work_area_H -= 44; - if (positioner_H > work_area_H) positioner_H = work_area_H; - } - xdg_positioner_set_size(positioner, pWindow->w() * f , positioner_H * f ); - xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); - xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); - // prevent menuwindow from expanding beyond display limits - int constraint = 0; - int top_menubar = pWindow->y() - - (Fl_Window_Driver::menu_bartitle(pWindow) && Fl_Window_Driver::menu_title(pWindow) ? - Fl_Window_Driver::menu_title(pWindow)->h() : 0); - if ( !(parent_win->fullscreen_active() && - Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER && - ((!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) || - Fl_Window_Driver::menu_bartitle(pWindow)) && top_menubar < 10 && - !Fl_Window_Driver::current_menu_button) - ) { - // Condition above is only to bypass Mutter bug for fullscreen windows (see #1061) - constraint |= (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - if ((Fl_Window_Driver::current_menu_button || Fl_Window_Driver::menu_bartitle(pWindow)) && - !Fl_Window_Driver::menu_leftorigin(pWindow)) { - constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; - } - xdg_positioner_set_constraint_adjustment(positioner, constraint); - } - if (!(Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow))) { - xdg_positioner_set_offset(positioner, 0, popup_y); - } - new_window->xdg_popup = xdg_surface_get_popup(new_window->xdg_surface, - parent_xdg, positioner); - struct win_positioner *win_pos = new struct win_positioner; - win_pos->window = new_window; - win_pos->x = popup_x; - win_pos->y = popup_y; - win_pos->child_popup = NULL; -//printf("create xdg_popup=%p data=%p xid=%p fl_win=%p\n",new_window->xdg_popup,win_pos,new_window,new_window->fl_win); - xdg_positioner_destroy(positioner); - xdg_popup_add_listener(new_window->xdg_popup, &popup_listener, win_pos); - if (!mem_grabbing_popup) { - mem_grabbing_popup = new_window->xdg_popup; - //xdg_popup_grab(new_window->xdg_popup, scr_driver->get_wl_seat(), scr_driver->get_serial()); - //libdecor_frame_popup_grab(parent_xid->frame, scr_driver->get_seat_name()); - } - wl_surface_commit(new_window->wl_surface); - // put it on same screen as parent_win - this->screen_num(parent_win->screen_num()); - return false; -} - - -void Fl_Wayland_Window_Driver::makeWindow() -{ - Fl_Group::current(0); // get rid of very common user bug: forgot end() - struct wld_window *new_window; - bool is_floatingtitle = false; - wait_for_expose_value = 1; - - if (pWindow->parent() && !pWindow->window()) return; - if (pWindow->parent() && !pWindow->window()->shown()) return; - - if (!pWindow->parent() && !popup_window()) { - x(0); y(0); // toplevel, non-popup windows must have origin at 0,0 - } - new_window = (struct wld_window *)calloc(1, sizeof *new_window); - new_window->fl_win = pWindow; - wl_list_init(&new_window->outputs); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - - new_window->wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor); -//printf("makeWindow:%p %s %s\n", pWindow, pWindow->parent()?"SUB":"", pWindow->as_gl_window()?"GL":""); - wl_surface_add_listener(new_window->wl_surface, &surface_listener, new_window); - - if (!shape()) { // rectangular FLTK windows are opaque - struct wl_region *opaque = wl_compositor_create_region(scr_driver->wl_compositor); - wl_region_add(opaque, 0, 0, 1000000, 1000000); - wl_surface_set_opaque_region(new_window->wl_surface, opaque); - wl_region_destroy(opaque); - } - - if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display && - Fl::first_window()) { - // put transient scale win at center of top window by making it a tooltip of top - Fl_Screen_Driver::transient_scale_parent = Fl::first_window(); - pWindow->set_tooltip_window(); - set_popup_window(); - pWindow->position( - (Fl_Screen_Driver::transient_scale_parent->w() - pWindow->w())/2 , - (Fl_Screen_Driver::transient_scale_parent->h() - pWindow->h())/2); - } - - if (popup_window()) { // a menu window or tooltip - is_floatingtitle = process_menu_or_tooltip(new_window); - - } else if (pWindow->border() && !pWindow->parent() ) { // a decorated window - new_window->kind = DECORATED; - if (!scr_driver->libdecor_context) - scr_driver->libdecor_context = libdecor_new(Fl_Wayland_Screen_Driver::wl_display, - &libdecor_iface); - new_window->frame = libdecor_decorate(scr_driver->libdecor_context, new_window->wl_surface, - &libdecor_frame_iface, new_window); - // appears in the Gnome desktop menu bar - libdecor_frame_set_app_id(new_window->frame, get_prog_name()); - libdecor_frame_set_title(new_window->frame, pWindow->label()?pWindow->label():""); - if (!is_resizable()) { - libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_RESIZE); - libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_FULLSCREEN); - } - libdecor_frame_map(new_window->frame); - float f = Fl::screen_scale(pWindow->screen_num()); - new_window->floating_width = pWindow->w() * f; - new_window->floating_height = pWindow->h() * f; - - } else if (pWindow->parent()) { // for subwindows (GL or non-GL) - new_window->kind = SUBWINDOW; - struct wld_window *parent = fl_wl_xid(pWindow->window()); - new_window->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor, - new_window->wl_surface, - parent->wl_surface); -//fprintf(stderr, "makeWindow: subsurface=%p\n", new_window->subsurface); - float f = Fl::screen_scale(pWindow->top_window()->screen_num()); - wl_subsurface_set_position(new_window->subsurface, pWindow->x() * f, pWindow->y() * f); - wl_subsurface_set_desync(new_window->subsurface); // important - // Next 5 statements ensure the subsurface will be mapped because: - // "The effect of adding a sub-surface becomes visible on the next time - // the state of the parent surface is applied." - new_window->configured_width = pWindow->w(); - new_window->configured_height = pWindow->h(); - if (!pWindow->as_gl_window()) { - parent->fl_win->wait_for_expose(); - wl_surface_commit(parent->wl_surface); - } - wait_for_expose_value = 0; - pWindow->border(0); - checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent - - } else { // a window without decoration - new_window->kind = UNFRAMED; - new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, - new_window->wl_surface); -//fprintf(stderr, "makeWindow: xdg_wm_base_get_xdg_surface=%p\n", new_window->xdg_surface); - xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window); - new_window->xdg_toplevel = xdg_surface_get_toplevel(new_window->xdg_surface); - xdg_toplevel_add_listener(new_window->xdg_toplevel, &xdg_toplevel_listener, new_window); - if (pWindow->label()) xdg_toplevel_set_title(new_window->xdg_toplevel, pWindow->label()); - wl_surface_commit(new_window->wl_surface); - pWindow->border(0); - } - - Fl_Window *old_first = Fl::first_window(); - struct wld_window * first_xid = (old_first ? fl_wl_xid(old_first) : NULL); - Fl_X *xp = new Fl_X; - xp->xid = (fl_uintptr_t)new_window; - other_xid = 0; - xp->w = pWindow; - flx(xp); - xp->region = 0; - if (!pWindow->parent()) { - xp->next = Fl_X::first; - Fl_X::first = xp; - } else if (Fl_X::first) { - xp->next = Fl_X::first->next; - Fl_X::first->next = xp; - } else { - xp->next = NULL; - Fl_X::first = xp; - } - - if (pWindow->modal() || pWindow->non_modal()) { - if (pWindow->modal()) Fl::modal_ = pWindow; - if (new_window->kind == DECORATED && first_xid && first_xid->kind == DECORATED) { - if (first_xid->frame) libdecor_frame_set_parent(new_window->frame, first_xid->frame); - } else if (new_window->kind == UNFRAMED && new_window->xdg_toplevel && first_xid) { - Fl_Wayland_Window_Driver *top_dr = Fl_Wayland_Window_Driver::driver(first_xid->fl_win); - if (top_dr->xdg_toplevel()) xdg_toplevel_set_parent(new_window->xdg_toplevel, - top_dr->xdg_toplevel()); - } - if (new_window->kind == DECORATED || new_window->kind == UNFRAMED) { -#if HAVE_XDG_DIALOG - if (scr_driver->xdg_wm_dialog) { - new_window->xdg_dialog = xdg_wm_dialog_v1_get_xdg_dialog(scr_driver->xdg_wm_dialog, xdg_toplevel()); - if (pWindow->modal()) xdg_dialog_v1_set_modal(new_window->xdg_dialog); - } else -#endif - if (scr_driver->seat->gtk_shell && pWindow->modal()) { - // Useful to position modal windows above their parent with "gnome-shell --version" ≤ 45.2, - // useless but harmless with "gnome-shell --version" ≥ 46.0. - struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(scr_driver->seat->gtk_shell, - new_window->wl_surface); - gtk_surface1_set_modal(gtk_surface); - if (gtk_surface1_get_version(gtk_surface) >= GTK_SURFACE1_RELEASE_SINCE_VERSION) - gtk_surface1_release(gtk_surface); // very necessary - else - gtk_surface1_destroy(gtk_surface); - } - } - } - - size_range(); - pWindow->set_visible(); - int old_event = Fl::e_number; - pWindow->redraw(); - pWindow->handle(Fl::e_number = FL_SHOW); // get child windows to appear - Fl::e_number = old_event; - if (pWindow->menu_window() && popup_window() && !is_floatingtitle) { - // make sure each menu window is mapped with its constraints before mapping next popup - pWindow->wait_for_expose(); - if (previous_floatingtitle) { // a menuwindow with a menutitle - //puts("previous_floatingtitle"); - int HH; - Fl_Window_Driver::menu_parent(&HH); - if (pWindow->h() > HH) { - // a tall menuwindow with a menutitle: don't create the menutitle at all - // and undo what has been created/allocated before - struct wld_window *xid = fl_wl_xid(previous_floatingtitle); - destroy_surface_caution_pointer_focus(xid->wl_surface, scr_driver->seat); - free(xid); - Fl_Window_Driver::driver(previous_floatingtitle)->hide_common(); - previous_floatingtitle = NULL; - return; - } - // map the menutitle popup now as child of pWindow - struct wld_window *xid = fl_wl_xid(previous_floatingtitle); - xid->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, xid->wl_surface); - xdg_surface_add_listener(xid->xdg_surface, &xdg_surface_listener, xid); - struct xdg_positioner *positioner = - xdg_wm_base_create_positioner(scr_driver->xdg_wm_base); - xdg_positioner_set_anchor_rect(positioner, 0, 0, 1, 1); - int snum = Fl_Window_Driver::menu_parent()->screen_num(); - float f = Fl::screen_scale(snum); - // put it on same screen as parent menu - Fl_Window_Driver::driver(previous_floatingtitle)->screen_num(snum); - xdg_positioner_set_size(positioner, previous_floatingtitle->w() * f , - previous_floatingtitle->h() * f ); - xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); - xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_TOP_RIGHT); - xid->xdg_popup = xdg_surface_get_popup(xid->xdg_surface, new_window->xdg_surface, - positioner); - xdg_positioner_destroy(positioner); - struct win_positioner *win_pos = new struct win_positioner; - win_pos->window = xid; - win_pos->x = 0; - win_pos->y = 0; - win_pos->child_popup = NULL; - xdg_popup_add_listener(xid->xdg_popup, &popup_listener, win_pos); - wl_surface_commit(xid->wl_surface); - struct win_positioner *parent_win_pos = - (struct win_positioner*)xdg_popup_get_user_data(new_window->xdg_popup); - parent_win_pos->child_popup = previous_floatingtitle; - previous_floatingtitle = NULL; - } - } - if (pWindow->fullscreen_active()) Fl::handle(FL_FULLSCREEN, pWindow); -} - - -int Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor c) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); -#if HAVE_CURSOR_SHAPE - if (scr_driver->wp_cursor_shape_device) { - if (xid->custom_cursor) { - delete_cursor(xid->custom_cursor); - xid->custom_cursor = NULL; - } - if (c == FL_CURSOR_NONE) return 0; - standard_cursor_ = c; - Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, NULL, c); - return 1; - } -#endif // HAVE_CURSOR_SHAPE - if (!scr_driver->seat->cursor_theme) return 1; - // Cursor names are the files of directory /usr/share/icons/XXXX/cursors/ - // where XXXX is the name of the current 'cursor theme'. - static struct cursor_file_struct { - Fl_Cursor c; - const char *fname; - Fl_Wayland_Screen_Driver::cursor_shapes wld_c; - } cursor_file_array[] = { - {FL_CURSOR_ARROW, "left_ptr", Fl_Wayland_Screen_Driver::arrow }, - {FL_CURSOR_CROSS, "cross", Fl_Wayland_Screen_Driver::cross }, - {FL_CURSOR_WAIT, "watch", Fl_Wayland_Screen_Driver::wait }, - {FL_CURSOR_INSERT, "xterm", Fl_Wayland_Screen_Driver::insert }, - {FL_CURSOR_HAND, "hand1", Fl_Wayland_Screen_Driver::hand }, - {FL_CURSOR_HELP, "help", Fl_Wayland_Screen_Driver::help }, - {FL_CURSOR_MOVE, "move", Fl_Wayland_Screen_Driver::move }, - {FL_CURSOR_N, "top_side", Fl_Wayland_Screen_Driver::north }, - {FL_CURSOR_E, "right_side", Fl_Wayland_Screen_Driver::east }, - {FL_CURSOR_W, "left_side", Fl_Wayland_Screen_Driver::west }, - {FL_CURSOR_S, "bottom_side", Fl_Wayland_Screen_Driver::south }, - {FL_CURSOR_NS, "sb_v_double_arrow", Fl_Wayland_Screen_Driver::north_south }, - {FL_CURSOR_WE, "sb_h_double_arrow", Fl_Wayland_Screen_Driver::west_east }, - {FL_CURSOR_SW, "bottom_left_corner", Fl_Wayland_Screen_Driver::south_west }, - {FL_CURSOR_SE, "bottom_right_corner", Fl_Wayland_Screen_Driver::south_east }, - {FL_CURSOR_NE, "top_right_corner", Fl_Wayland_Screen_Driver::north_east }, - {FL_CURSOR_NW, "top_left_corner", Fl_Wayland_Screen_Driver::north_west }, - {FL_CURSOR_NESW, "fd_double_arrow", Fl_Wayland_Screen_Driver::nesw }, - {FL_CURSOR_NWSE, "bd_double_arrow", Fl_Wayland_Screen_Driver::nwse } - }; - - int found = -1; - for (unsigned i = 0; i < sizeof(cursor_file_array) / sizeof(struct cursor_file_struct); i++) { - if (cursor_file_array[i].c == c) { - found = cursor_file_array[i].wld_c; - if (!scr_driver->xc_cursor[found]) scr_driver->xc_cursor[found] = - scr_driver->cache_cursor(cursor_file_array[i].fname); - if (scr_driver->xc_cursor[found]) { - scr_driver->default_cursor(scr_driver->xc_cursor[found]); - } - break; - } - } - if (found < 0 || !scr_driver->xc_cursor[found]) return 0; - - if (xid->custom_cursor) { - delete_cursor(xid->custom_cursor); - xid->custom_cursor = NULL; - } - standard_cursor_ = c; - scr_driver->set_cursor(); - return 1; -} - - -void Fl_Wayland_Window_Driver::use_border() { - if (!shown() || pWindow->parent()) return; - pWindow->wait_for_expose(); // useful for border(0) just after show() - struct libdecor_frame *frame = fl_wl_xid(pWindow)->frame; - if (frame && Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::KWIN) { - if (fl_wl_xid(pWindow)->kind == DECORATED) { - libdecor_frame_set_visibility(frame, pWindow->border()); - } else { - pWindow->hide(); - pWindow->show(); - } - pWindow->redraw(); - } else { - Fl_Window_Driver::use_border(); - } -} - - -/* Change an existing window to fullscreen */ -void Fl_Wayland_Window_Driver::fullscreen_on() { - int top, bottom, left, right; - - top = fullscreen_screen_top(); - bottom = fullscreen_screen_bottom(); - left = fullscreen_screen_left(); - right = fullscreen_screen_right(); - - if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { - top = screen_num(); - bottom = top; - left = top; - right = top; - } - pWindow->wait_for_expose(); // make sure ->xdg_toplevel is initialized - if (xdg_toplevel()) { - xdg_toplevel_set_fullscreen(xdg_toplevel(), NULL); - pWindow->_set_fullscreen(); - Fl::handle(FL_FULLSCREEN, pWindow); - } -} - - -void Fl_Wayland_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { - pWindow->hide(); - pWindow->_clear_fullscreen(); - // avoid being called with W=H=0 in suboptimal scenario of #1299 - if (!W) W = w(); - if (!H) H = h(); - pWindow->resize(X, Y, W, H); - pWindow->show(); - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_Wayland_Window_Driver::label(const char *name, const char *iname) { - if (shown() && !parent() && fl_wl_xid(pWindow)->kind == DECORATED) { - if (!name) name = ""; - if (!iname) iname = fl_filename_name(name); - libdecor_frame_set_title(fl_wl_xid(pWindow)->frame, name); - } -} - - -int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int hoty) { - int retval = set_cursor_4args(rgb, hotx, hoty, true); - if (retval) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); - Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, xid->custom_cursor->wl_cursor); - } - return retval; -} - - -int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx, int hoty, - bool keep_copy) { - if (keep_copy) { - if (rgb->as_svg_image()) { - int scale = wld_scale(); - Fl_RGB_Image *svg = (Fl_RGB_Image*)rgb->copy(rgb->w() * scale, rgb->h() * scale); - svg->normalize(); - svg->scale(rgb->w(), rgb->h(), 0, 1); - rgb = svg; - } else { - int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); - uchar *data = new uchar[ld * rgb->data_h()]; - memcpy(data, rgb->array, ld * rgb->data_h()); - Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld()); - rgb2->alloc_array = 1; - rgb2->scale(rgb->w(), rgb->h(), 0, 1); - rgb = rgb2; - } - } -// build a new wl_cursor and its image - struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow); - struct wl_cursor *new_cursor = (struct wl_cursor*)malloc(sizeof(struct wl_cursor)); - struct cursor_image *new_image = (struct cursor_image*)calloc(1, - sizeof(struct cursor_image)); - int scale = wld_scale(); - new_image->image.width = rgb->w() * scale; - new_image->image.height = rgb->h() * scale; - new_image->image.hotspot_x = hotx * scale; - new_image->image.hotspot_y = hoty * scale; - new_image->image.delay = 0; - new_image->offset = 0; - //create a Wayland buffer and have it used as an image of the new cursor - struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen; - Fl_Image_Surface *img_surf = Fl_Wayland_Graphics_Driver::custom_offscreen( - new_image->image.width, new_image->image.height, &offscreen); - new_image->buffer = offscreen->wl_buffer; - wl_buffer_set_user_data(new_image->buffer, offscreen); - new_cursor->image_count = 1; - new_cursor->images = (struct wl_cursor_image**)malloc(sizeof(struct wl_cursor_image*)); - new_cursor->images[0] = (struct wl_cursor_image*)new_image; - new_cursor->name = strdup("custom cursor"); - // draw the rgb image to the cursor's drawing buffer - Fl_Surface_Device::push_current(img_surf); - Fl_Wayland_Graphics_Driver *driver = (Fl_Wayland_Graphics_Driver*)img_surf->driver(); - cairo_scale(driver->cr(), scale, scale); - ((Fl_RGB_Image*)rgb)->draw(0, 0); - Fl_Surface_Device::pop_current(); - delete img_surf; - memcpy(offscreen->data, offscreen->draw_buffer.buffer, offscreen->draw_buffer.data_size); - // delete the previous custom cursor, if there was one, - // and keep its Fl_RGB_Image if appropriate - if (xid->custom_cursor) delete_cursor(xid->custom_cursor, keep_copy); - //have this new cursor used - xid->custom_cursor = new custom_cursor; - xid->custom_cursor->wl_cursor = new_cursor; - xid->custom_cursor->rgb = rgb; - xid->custom_cursor->hotx = hotx; - xid->custom_cursor->hoty = hoty; - return 1; -} - - -void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) { - static int depth = 0; - struct wld_window *fl_win = fl_wl_xid(pWindow); - if (fl_win && fl_win->kind == DECORATED && !xdg_toplevel()) { - pWindow->wait_for_expose(); - } - int is_a_move = (X != x() || Y != y()); - bool true_rescale = Fl_Window::is_a_rescale(); - float f = fl_win ? Fl::screen_scale(pWindow->screen_num()) : 1; - if (fl_win && fl_win->buffer) { - int scale = wld_scale(); - int stride = cairo_format_stride_for_width( - Fl_Cairo_Graphics_Driver::cairo_format, int(W * f) * scale ); - size_t bsize = stride * int(H * f) * scale; - true_rescale = (bsize != fl_win->buffer->draw_buffer.data_size); - } - int is_a_resize = (W != w() || H != h() || true_rescale); - if (is_a_move) force_position(1); - else if (!is_a_resize && !is_a_move) return; - depth++; - if (shown() && !(parent() || popup_window())) { - X = Y = 0; - } - Fl_Window *parent = this->parent() ? pWindow->window() : NULL; - struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL; -//printf("resize[%p] %dx%d is_a_resize=%d is_a_move=%d depth=%d parent_xid->frame_cb=%p\n", pWindow,W,H,is_a_resize,is_a_move,depth, (parent_xid?parent_xid->frame_cb:0) ); - if (depth == 1 && fl_win && parent_xid && parent_xid->frame_cb && can_expand_outside_parent_) { - // When moving or resizing a subwindow independently from its parent while the parent window - // is being redrawn, the processing depends on whether the moved/resize window - // is a draggable-subwindow. For a draggable subwindow having can_expand_outside_parent_ != 0, - // skip the X,Y,W,H tuple to process only tuples received when parent window is ready. - // This smoothes the movement of the draggable subwindow. - // Process regular subwindows normally. - depth--; - return; - } - if (is_a_resize) { - if (pWindow->parent()) { - if (W < 1) W = 1; - if (H < 1) H = 1; - } - pWindow->Fl_Group::resize(X,Y,W,H); - //fprintf(stderr, "resize: win=%p to %dx%d\n", pWindow, W, H); - if (shown()) {pWindow->redraw();} - } else { - x(X); y(Y); - //fprintf(stderr, "move win=%p to %dx%d\n", pWindow, X, Y); - } - if (!fl_win) { - depth--; - return; - } - - if (is_a_resize) { - if (pWindow->as_overlay_window() && other_xid) { - destroy_double_buffer(); - } - if (fl_win->kind == DECORATED) { // a decorated window - if (fl_win->buffer) { - Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - } - fl_win->configured_width = W; - fl_win->configured_height = H; - if (!in_handle_configure && xdg_toplevel()) { - if (Fl_Window::is_a_rescale()) size_range(); - struct libdecor_state *state = libdecor_state_new(int(W * f), int(H * f)); - // necessary only if resize is initiated by prog - libdecor_frame_commit(fl_win->frame, state, NULL); - libdecor_state_free(state); - if (libdecor_frame_is_floating(fl_win->frame)) { - fl_win->floating_width = int(W*f); - fl_win->floating_height = int(H*f); - } - } - } else if (fl_win->kind == SUBWINDOW && fl_win->subsurface) { // a subwindow - wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - fl_win->configured_width = W; - fl_win->configured_height = H; - } else if (fl_win->xdg_surface) { // a window without border - if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win); - fl_win->configured_width = W; - fl_win->configured_height = H; - W *= f; H *= f; - xdg_surface_set_window_geometry(fl_win->xdg_surface, 0, 0, W, H); - //printf("xdg_surface_set_window_geometry: %dx%d\n",W, H); - } - } else if (!in_handle_configure && xdg_toplevel() && Fl::e_state == FL_BUTTON1) { - // Wayland doesn't provide a way for the app to set the window position on screen. - // This is functional when the move is mouse-driven. - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - xdg_toplevel_move(xdg_toplevel(), scr_driver->seat->wl_seat, scr_driver->seat->serial); - Fl::pushed(NULL); - Fl::e_state = 0; - } - - if (parent_xid) { - if (depth > 1) { - if (fl_win->subsurface) { - wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - wl_surface_commit(parent_xid->wl_surface); - } - } else if (parent_xid->buffer && is_a_move) { - if (fl_win->subsurface) wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); - if (!parent_xid->buffer->wl_buffer || parent_xid->buffer->draw_buffer_needs_commit) { - if (!parent_xid->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(parent_xid); - else wl_surface_commit(parent_xid->wl_surface); - } else { - if (!parent_xid->frame_cb) { - // Use the frame callback mechanism applied to the object's parent window - parent_xid->frame_cb = wl_surface_frame(parent_xid->wl_surface); - wl_callback_add_listener(parent_xid->frame_cb, - Fl_Wayland_Graphics_Driver::p_surface_frame_listener, parent_xid); - } - wl_surface_commit(parent_xid->wl_surface); - } - } - checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent - } - depth--; -} - - -static void crect_intersect(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) { - int x = fl_max(to->x, with->x); - to->width = fl_min(to->x + to->width, with->x + with->width) - x; - if (to->width < 0) to->width = 0; - int y = fl_max(to->y, with->y); - to->height = fl_min(to->y + to->height, with->y + with->height) - y; - if (to->height < 0) to->height = 0; - to->x = x; - to->y = y; -} - - -static bool crect_equal(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) { - return (to->x == with->x && to->y == with->y && to->width == with->width && - to->height == with->height); -} - - -void Fl_Wayland_Window_Driver::checkSubwindowFrame() { - if (!pWindow->parent() || can_expand_outside_parent_) return; - // make sure this subwindow doesn't leak out of its parent window - Fl_Window *from = pWindow, *parent; - cairo_rectangle_int_t full = {0, 0, pWindow->w(), pWindow->h()}; // full subwindow area - cairo_rectangle_int_t srect = full; // will become new subwindow clip - int fromx = 0, fromy = 0; - while ((parent = from->window()) != NULL) { // loop over all parent windows - fromx -= from->x(); // parent origin in subwindow's coordinates - fromy -= from->y(); - cairo_rectangle_int_t prect = {fromx, fromy, parent->w(), parent->h()}; - crect_intersect(&srect, &prect); // area of subwindow inside its parent - from = parent; - } - cairo_rectangle_int_t *r = subRect(); - // current subwindow clip - cairo_rectangle_int_t current_clip = (r ? *r : full); - if (!crect_equal(&srect, ¤t_clip)) { // if new clip differs from current clip - if (crect_equal(&srect, &full)) r = NULL; - else { - r = &srect; - if (r->width == 0 || r->height == 0) { - r = NULL; - } - } - subRect(r); - } -} - - -void Fl_Wayland_Window_Driver::subRect(cairo_rectangle_int_t *r) { - if (subRect_) delete subRect_; - cairo_rectangle_int_t *r2 = NULL; - if (r) { - r2 = new cairo_rectangle_int_t; - *r2 = *r; - } - subRect_ = r2; -} - - -void Fl_Wayland_Window_Driver::reposition_menu_window(int x, int y) { - if (y == pWindow->y()) return; - // The top of the tall popup window was positioned at the top of the screen - // Instead of sliding up the popup window on the display, we slide up the - // drawing inside the fixed popup via member variable offset_y of the - // menuwindow class, and we redraw the popup content. - // It's also useful to make such tall popup window transparent. - *Fl_Window_Driver::menu_offset_y(pWindow) += (y - pWindow->y()); - struct wld_window *xid = fl_wl_xid(pWindow); - wl_surface_set_opaque_region(xid->wl_surface, NULL); - if (xid->buffer) memset(xid->buffer->draw_buffer.buffer, 0, - xid->buffer->draw_buffer.data_size); - //printf("offset_y=%d\n", *Fl_Window_Driver::menu_offset_y(pWindow)); - this->y(y); - pWindow->redraw(); -} - - -void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int nscreen) { - int HH; - Fl_Window *parent = Fl_Window_Driver::menu_parent(&HH); - if (parent) { - if (pWindow->menu_window() && popup_window() && pWindow->h() > HH) { - // tall menu: set top (Y) and bottom (Y+H) bounds relatively to reference window - int ih = Fl_Window_Driver::menu_itemheight(pWindow); - X = -50000; - W = 1000000; - H = HH - 2 * ih; - Fl_Window *origin = Fl_Window_Driver::menu_leftorigin(pWindow); - if (origin) { // has left parent - int selected = fl_max(Fl_Window_Driver::menu_selected(origin), 0); - Y = origin->y() + (selected + 0.5) * ih; - } else if (!Fl_Window_Driver::menu_bartitle(pWindow)) { // tall menu button - static int y_offset = 0; - if (new_popup) { - y_offset = pWindow->y()- ih; - new_popup = false; - } - Y = 1.5 * ih + y_offset; - } else { // has a menutitle - Y = 1.5 * ih; - } - } else { // position the menu window by wayland constraints - X = -50000; - Y = -50000; - W = 1000000; - H = 1000000; - } - //printf("menu_window_area: %dx%d - %dx%d\n",X,Y,W,H); - } else Fl_Window_Driver::menu_window_area(X, Y, W, H, nscreen); -} - - -int Fl_Wayland_Window_Driver::wld_scale() { - Fl_X *flx = Fl_X::flx(pWindow); - struct wld_window *xid = (flx ? (struct wld_window *)flx->xid : NULL); - if (!xid || wl_list_empty(&xid->outputs)) { - int scale = 1; - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - Fl_Wayland_Screen_Driver::output *output; - wl_list_for_each(output, &(scr_driver->outputs), link) { - scale = fl_max(scale, output->wld_scale); - } - return scale; - } - struct surface_output *s_output; - s_output = wl_container_of(xid->outputs.next, s_output, link); - return s_output->output->wld_scale; -} - - -FL_EXPORT struct wl_surface *fl_wl_surface(struct wld_window *xid) { - return xid->wl_surface; -} - - -cairo_t *fl_wl_gc() { - return ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->cr(); -} - - -Fl_Window *fl_wl_find(struct wld_window *xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} - - -struct wld_window *fl_wl_xid(const Fl_Window *win) { - return (struct wld_window *)Fl_Window_Driver::xid(win); -} - - -struct wl_compositor *fl_wl_compositor() { - Fl_Wayland_Screen_Driver *screen_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - return screen_driver->wl_compositor; -} - - -int fl_wl_buffer_scale(Fl_Window *window) { - return Fl_Wayland_Window_Driver::driver(window)->wld_scale(); -} - - -Fl_Wayland_Plugin *Fl_Wayland_Window_Driver::gl_plugin() { - static Fl_Wayland_Plugin *plugin = NULL; - if (!plugin) { - Fl_Plugin_Manager pm("wayland.fltk.org"); - plugin = (Fl_Wayland_Plugin*)pm.plugin("gl.wayland.fltk.org"); - } - return plugin; -} - - -void Fl_Wayland_Window_Driver::maximize() { - struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; - if (xid->kind == DECORATED) libdecor_frame_set_maximized(xid->frame); - else Fl_Window_Driver::maximize(); -} - - -void Fl_Wayland_Window_Driver::un_maximize() { - struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; - if (xid->kind == DECORATED) libdecor_frame_unset_maximized(xid->frame); - else Fl_Window_Driver::un_maximize(); -} diff --git a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx b/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx deleted file mode 100644 index 12c525c46..000000000 --- a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx +++ /dev/null @@ -1,741 +0,0 @@ -// -// Wayland-specific code for clipboard and drag-n-drop support. -// -// Copyright 1998-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#if !defined(FL_DOXYGEN) - -# include <FL/Fl.H> -# include <FL/platform.H> -# include <FL/Fl_Window.H> -# include <FL/Fl_Shared_Image.H> -# include <FL/Fl_Image_Surface.H> -# include "Fl_Wayland_Screen_Driver.H" -# include "Fl_Wayland_Window_Driver.H" -# include "../Unix/Fl_Unix_System_Driver.H" -# include "Fl_Wayland_Graphics_Driver.H" -# include "../../flstring.h" // includes <string.h> - -# include <errno.h> -# include <stdio.h> -# include <stdlib.h> -# include <map> - - -//////////////////////////////////////////////////////////////// -// Code used for copy and paste and DnD into the program: - -static char *fl_selection_buffer[2]; -static int fl_selection_length[2]; -static const char * fl_selection_type[2]; -static int fl_selection_buffer_length[2]; -static char fl_i_own_selection[2] = {0,0}; -static struct wl_data_offer *fl_selection_offer = NULL; -// The MIME type Wayland uses for text-containing clipboard: -static const char wld_plain_text_clipboard[] = "text/plain;charset=utf-8"; - - -int Fl_Wayland_Screen_Driver::clipboard_contains(const char *type) -{ - return fl_selection_type[1] == type; -} - - -struct data_source_write_struct { - size_t rest; - char *from; -}; - -void write_data_source_cb(FL_SOCKET fd, data_source_write_struct *data) { - while (data->rest) { - ssize_t n = write(fd, data->from, data->rest); - if (n == -1) { - if (errno == EAGAIN) return; - Fl::error("write_data_source_cb: error while writing clipboard data\n"); - break; - } - data->from += n; - data->rest -= n; - } - Fl::remove_fd(fd, FL_WRITE); - delete data; - close(fd); -} - - -static void data_source_handle_send(void *data, struct wl_data_source *source, - const char *mime_type, int fd) { - fl_intptr_t rank = (fl_intptr_t)data; -//fprintf(stderr, "data_source_handle_send: %s fd=%d l=%d\n", mime_type, fd, fl_selection_length[1]); - if (((!strcmp(mime_type, wld_plain_text_clipboard) || !strcmp(mime_type, "text/plain")) && - fl_selection_type[rank] == Fl::clipboard_plain_text) - || - (!strcmp(mime_type, "image/bmp") && fl_selection_type[rank] == Fl::clipboard_image) ) { - data_source_write_struct *write_data = new data_source_write_struct; - write_data->rest = fl_selection_length[rank]; - write_data->from = fl_selection_buffer[rank]; - Fl::add_fd(fd, FL_WRITE, (Fl_FD_Handler)write_data_source_cb, write_data); - } else { - //Fl::error("Destination client requested unsupported MIME type: %s\n", mime_type); - close(fd); - } -} - - -static Fl_Window *fl_dnd_target_window = 0; -static wl_surface *fl_dnd_target_surface = 0; -static bool doing_dnd = false; // true when DnD is in action -static wl_surface *dnd_icon = NULL; // non null when DnD uses text as cursor -static wl_cursor* save_cursor = NULL; // non null when DnD uses "dnd-copy" cursor - - -static void data_source_handle_cancelled(void *data, struct wl_data_source *source) { - // An application has replaced the clipboard contents or DnD finished - wl_data_source_destroy(source); - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - if (scr_driver->seat->data_source == source) scr_driver->seat->data_source = NULL; - doing_dnd = false; - if (dnd_icon) { - struct Fl_Wayland_Graphics_Driver::wld_buffer *off = - (struct Fl_Wayland_Graphics_Driver::wld_buffer *) - wl_surface_get_user_data(dnd_icon); - struct wld_window fake_window; - memset(&fake_window, 0, sizeof(fake_window)); - fake_window.buffer = off; - Fl_Wayland_Graphics_Driver::buffer_release(&fake_window); - wl_surface_destroy(dnd_icon); - dnd_icon = NULL; - } - fl_i_own_selection[1] = 0; - if (data == 0) { // at end of DnD - if (save_cursor) { - scr_driver->default_cursor(save_cursor); - scr_driver->set_cursor(); - save_cursor = NULL; - } - if (fl_dnd_target_window) { - Fl::handle(FL_RELEASE, fl_dnd_target_window); - fl_dnd_target_window = 0; - } - Fl::pushed(0); - } -} - - -static void data_source_handle_target(void *data, struct wl_data_source *source, const char *mime_type) { - if (!Fl::pushed()) { - data_source_handle_cancelled(data, source); - return; - } - if (mime_type != NULL) { - //printf("Destination would accept MIME type if dropped: %s\n", mime_type); - } else { - //printf("Destination would reject if dropped\n"); - } -} - - -static uint32_t last_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - - -static void data_source_handle_action(void *data, struct wl_data_source *source, - uint32_t dnd_action) { - last_dnd_action = dnd_action; - switch (dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("Destination would perform a copy action if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: - //printf("Destination would reject the drag if dropped\n"); - break; - } -} - - -static void data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *source) { - //printf("Drop performed\n"); -} - - -static void data_source_handle_dnd_finished(void *data, struct wl_data_source *source) { - switch (last_dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: - //printf("Destination has accepted the drop with a move action\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("Destination has accepted the drop with a copy action\n"); - break; - } -} - - -static const struct wl_data_source_listener data_source_listener = { - .target = data_source_handle_target, - .send = data_source_handle_send, - .cancelled = data_source_handle_cancelled, - .dnd_drop_performed = data_source_handle_dnd_drop_performed, - .dnd_finished = data_source_handle_dnd_finished, - .action = data_source_handle_action, -}; - - -static struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen_from_text(const char *text, - int scale) { - const char *p, *q; - int width = 0, height, w2, ltext = strlen(text); - fl_font(FL_HELVETICA, 10 * scale); - p = text; - int nl = 0; - while(nl < 20 && (q=strchr(p, '\n')) != NULL) { - nl++; - w2 = int(fl_width(p, q - p)); - if (w2 > width) width = w2; - p = q + 1; - } - if (nl < 20 && text[ ltext - 1] != '\n') { - nl++; - w2 = int(fl_width(p)); - if (w2 > width) width = w2; - } - if (width > 300*scale) width = 300*scale; - height = nl * fl_height() + 3; - width += 6; - width = ceil(width/float(scale)) * scale; // these must be multiples of scale - height = ceil(height/float(scale)) * scale; - struct Fl_Wayland_Graphics_Driver::wld_buffer *off; - Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen( - width, height, &off); - Fl_Surface_Device::push_current(surf); - p = text; - fl_font(FL_HELVETICA, 10 * scale); - int y = fl_height(); - while (nl > 0) { - q = strchr(p, '\n'); - if (q) { - fl_draw(p, q - p, 3, y); - } else { - fl_draw(p, 3, y); - break; - } - y += fl_height(); - p = q + 1; - nl--; - } - Fl_Surface_Device::pop_current(); - delete surf; - cairo_surface_flush( cairo_get_target(off->draw_buffer.cairo_) ); - memcpy(off->data, off->draw_buffer.buffer, off->draw_buffer.data_size); - return off; -} - - -int Fl_Wayland_Screen_Driver::dnd(int use_selection) { - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - - struct wl_data_source *source = - wl_data_device_manager_create_data_source(scr_driver->seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(source, &data_source_listener, (void*)0); - wl_data_source_offer(source, wld_plain_text_clipboard); - wl_data_source_set_actions(source, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); - struct Fl_Wayland_Graphics_Driver::wld_buffer *off = NULL; - int s = 1; - if (use_selection) { - // use the text as dragging icon - Fl_Widget *current = Fl::pushed() ? Fl::pushed() : Fl::first_window(); - s = Fl_Wayland_Window_Driver::driver(current->top_window())->wld_scale(); - off = (struct Fl_Wayland_Graphics_Driver::wld_buffer *)offscreen_from_text(fl_selection_buffer[0], s); - dnd_icon = wl_compositor_create_surface(scr_driver->wl_compositor); - } else dnd_icon = NULL; - doing_dnd = true; - wl_data_device_start_drag(scr_driver->seat->data_device, source, - scr_driver->seat->pointer_focus, dnd_icon, - scr_driver->seat->serial); - if (use_selection) { - wl_surface_attach(dnd_icon, off->wl_buffer, 0, 0); - wl_surface_set_buffer_scale(dnd_icon, s); - wl_surface_damage(dnd_icon, 0, 0, 10000, 10000); - wl_surface_commit(dnd_icon); - wl_surface_set_user_data(dnd_icon, off); - } else { - static struct wl_cursor *dnd_cursor = scr_driver->cache_cursor("dnd-copy"); - if (dnd_cursor) { - save_cursor = scr_driver->default_cursor(); - scr_driver->default_cursor(dnd_cursor); - scr_driver->set_cursor(); - } else save_cursor = NULL; - } - return 1; -} - - -struct compare_utf8 { // used as key_comp member of following map object - bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; } -}; - -// map: for each clipboard mime-type FLTK has interest in, give FLTK clipboard type and priority. -// A mime-type with higher priority for same FLTK clipboard type is preferred. -typedef struct { const char * const fltk_type; int priority; } type_prio_struct; -static std::map<const char * const, type_prio_struct, compare_utf8> clipboard_mimetypes_map { -// mime-type FLTK-clipboard-type priority - {"image/png", {Fl::clipboard_image, 1} }, - {"image/bmp", {Fl::clipboard_image, 2} }, - {"text/plain", {Fl::clipboard_plain_text, 1} }, - {"text/uri-list", {Fl::clipboard_plain_text, 2} }, - {"UTF8_STRING", {Fl::clipboard_plain_text, 3} }, - {wld_plain_text_clipboard, {Fl::clipboard_plain_text, 4} }, -}; - -// map: for each FLTK-clipboard-type, give current preferred mime-type and priority -typedef struct { const char *mime_type; int priority; } mime_prio_struct; -static std::map<const char * const, mime_prio_struct> clipboard_kinds_map { -// FLTK-clipboard-type current mime-type current highest priority - {Fl::clipboard_image, {NULL, 0} }, - {Fl::clipboard_plain_text, {NULL, 0} }, -}; - - -static void data_offer_handle_offer(void *data, struct wl_data_offer *offer, - const char *mime_type) { - // runs when app becomes active once for each offered clipboard type -//fprintf(stderr, "Clipboard offer=%p supports MIME type: %s\n", offer, mime_type); - std::map<const char*const, type_prio_struct, compare_utf8>::iterator iter_mime = - clipboard_mimetypes_map.find(mime_type); - if (iter_mime == clipboard_mimetypes_map.end()) return; // FLTK doesn't handle this mime_type - std::map<const char*const, mime_prio_struct>::iterator iter_kind = - clipboard_kinds_map.find(iter_mime->second.fltk_type); - if (iter_mime->second.priority > iter_kind->second.priority) { // found mime-type with higher priority - iter_kind->second.priority = iter_mime->second.priority; - iter_kind->second.mime_type = iter_mime->first; - fl_selection_type[1] = iter_kind->first; -//fprintf(stderr,"mime_type=%s priority=%d [%s]\n",iter_kind->second.mime_type, iter_kind->second.priority, fl_selection_type[1]); - } -} - - -static void data_offer_handle_source_actions(void *data, struct wl_data_offer *offer, - uint32_t actions) { - if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { - //printf("Drag supports the copy action\n"); - } -} - - -static void data_offer_handle_action(void *data, struct wl_data_offer *offer, - uint32_t dnd_action) { - switch (dnd_action) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: - //printf("A move action would be performed if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - //printf("A copy action would be performed if dropped\n"); - break; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: - //printf("The drag would be rejected if dropped\n"); - break; - } -} - - -static const struct wl_data_offer_listener data_offer_listener = { - .offer = data_offer_handle_offer, - .source_actions = data_offer_handle_source_actions, - .action = data_offer_handle_action, -}; - - -static void data_device_handle_data_offer(void *data, struct wl_data_device *data_device, - struct wl_data_offer *offer) { - // An application has created a new data source -//fprintf(stderr, "data_device_handle_data_offer offer=%p\n", offer); - fl_selection_type[1] = NULL; - wl_data_offer_add_listener(offer, &data_offer_listener, NULL); - // reset current best mime-type and priority - std::map<const char*const, mime_prio_struct>::iterator iter = clipboard_kinds_map.begin(); - while (iter != clipboard_kinds_map.end()) { - iter->second.mime_type = NULL; - iter->second.priority = 0; - iter++; - } -} - - -static void data_device_handle_selection(void *data, struct wl_data_device *data_device, - struct wl_data_offer *offer) { - // An application has set the clipboard contents. W -//fprintf(stderr, "data_device_handle_selection\n"); - if (fl_selection_offer) wl_data_offer_destroy(fl_selection_offer); - fl_selection_offer = offer; -//if (offer == NULL) fprintf(stderr, "Clipboard is empty\n"); -} - - -// Gets from the system the clipboard or dnd text and puts it in fl_selection_buffer[1] -// which is enlarged if necessary. -static void get_clipboard_or_dragged_text(struct wl_data_offer *offer) { - int fds[2]; - char *from; - if (pipe(fds)) return; - // preferred mime-type for the text clipboard type - const char *type = clipboard_kinds_map[Fl::clipboard_plain_text].mime_type; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - // read in fl_selection_buffer - char *to = fl_selection_buffer[1]; - ssize_t rest = fl_selection_buffer_length[1]; - while (rest) { - ssize_t n = read(fds[0], to, rest); - if (n <= 0) { - close(fds[0]); - fl_selection_length[1] = to - fl_selection_buffer[1]; - fl_selection_buffer[1][ fl_selection_length[1] ] = 0; - goto way_out; - } - n = Fl_Screen_Driver::convert_crlf(to, n); - to += n; - rest -= n; - } - // compute size of unread clipboard data - rest = fl_selection_buffer_length[1]; - while (true) { - char buf[1000]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) { - close(fds[0]); - break; - } - rest += n; - } -//fprintf(stderr, "get_clipboard_or_dragged_text: size=%ld\n", rest); - // read full clipboard data - if (pipe(fds)) goto way_out; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_flush(Fl_Wayland_Screen_Driver::wl_display); - if (rest+1 > fl_selection_buffer_length[1]) { - delete[] fl_selection_buffer[1]; - fl_selection_buffer[1] = new char[rest+1000+1]; - fl_selection_buffer_length[1] = rest+1000; - } - from = fl_selection_buffer[1]; - while (rest > 0) { - ssize_t n = read(fds[0], from, rest); - if (n <= 0) break; - n = Fl_Screen_Driver::convert_crlf(from, n); - from += n; - rest -= n; - } - close(fds[0]); - fl_selection_length[1] = from - fl_selection_buffer[1]; - fl_selection_buffer[1][fl_selection_length[1]] = 0; -way_out: - if (strcmp(type, "text/uri-list") == 0) { - fl_decode_uri(fl_selection_buffer[1]); // decode encoded bytes - char *p = fl_selection_buffer[1]; - while (*p) { // remove prefixes - if (strncmp(p, "file://", 7) == 0) { - memmove(p, p+7, strlen(p+7)+1); - } - p = strchr(p, '\n'); - if (!p) break; - if (*++p == 0) *(p-1) = 0; // remove last '\n' - } - fl_selection_length[1] = strlen(fl_selection_buffer[1]); - } - Fl::e_clipboard_type = Fl::clipboard_plain_text; -} - - -static struct wl_data_offer *current_drag_offer = NULL; -static uint32_t fl_dnd_serial; - - -static void data_device_handle_enter(void *data, struct wl_data_device *data_device, - uint32_t serial, struct wl_surface *surface, - wl_fixed_t x, wl_fixed_t y, - struct wl_data_offer *offer) { - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); -//printf("Drag entered our surface %p(win=%p) at %dx%d\n", surface, win, wl_fixed_to_int(x), wl_fixed_to_int(y)); - if (win) { - fl_dnd_target_surface = surface; - float f = Fl::screen_scale(win->screen_num()); - Fl::e_x = wl_fixed_to_int(x) / f; - Fl::e_y = wl_fixed_to_int(y) / f; - while (win->parent()) { - Fl::e_x += win->x(); - Fl::e_y += win->y(); - win = win->window(); - } - fl_dnd_target_window = win; - Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x(); - Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y(); - Fl::handle(FL_DND_ENTER, fl_dnd_target_window); - current_drag_offer = offer; - fl_dnd_serial = serial; - } else fl_dnd_target_window = NULL; // we enter a non-FLTK window (titlebar, shade) - uint32_t supported_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - uint32_t preferred_action = supported_actions; - wl_data_offer_set_actions(offer, supported_actions, preferred_action); -} - - -static void data_device_handle_motion(void *data, struct wl_data_device *data_device, - uint32_t time, wl_fixed_t x, wl_fixed_t y) { - if (!current_drag_offer) return; -//printf("data_device_handle_motion fl_dnd_target_window=%p\n", fl_dnd_target_window); - int ret = 0; - if (fl_dnd_target_window) { - float f = Fl::screen_scale(fl_dnd_target_window->screen_num()); - Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(fl_dnd_target_surface); - Fl::e_x = wl_fixed_to_int(x) / f; - Fl::e_y = wl_fixed_to_int(y) / f; - while (win->parent()) { - Fl::e_x += win->x(); - Fl::e_y += win->y(); - win = win->window(); - } - Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x(); - Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y(); - ret = Fl::handle(FL_DND_DRAG, fl_dnd_target_window); - if (Fl::belowmouse()) Fl::belowmouse()->take_focus(); - } - uint32_t supported_actions = ret && (Fl::pushed() || !doing_dnd) ? - WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY : WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - uint32_t preferred_action = supported_actions; - wl_data_offer_set_actions(current_drag_offer, supported_actions, preferred_action); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (ret && current_drag_offer) wl_data_offer_accept(current_drag_offer, fl_dnd_serial, "text/plain"); -} - - -static void data_device_handle_leave(void *data, struct wl_data_device *data_device) { - //printf("Drag left our surface\n"); - if (current_drag_offer) Fl::handle(FL_DND_LEAVE, fl_dnd_target_window); -} - - -static void data_device_handle_drop(void *data, struct wl_data_device *data_device) { - if (!current_drag_offer) return; - Fl::handle(FL_ENTER, fl_dnd_target_window); // useful to set the belowmouse widget - int ret = Fl::handle(FL_DND_RELEASE, fl_dnd_target_window); -//printf("data_device_handle_drop ret=%d doing_dnd=%d\n", ret, doing_dnd); - - if (!ret) { - wl_data_offer_destroy(current_drag_offer); - current_drag_offer = NULL; - return; - } - - if (doing_dnd) { - Fl::e_text = fl_selection_buffer[0]; - Fl::e_length = fl_selection_length[0]; - } else { - get_clipboard_or_dragged_text(current_drag_offer); - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - } - int old_event = Fl::e_number; - Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); - Fl::e_number = old_event; - - wl_data_offer_finish(current_drag_offer); - wl_data_offer_destroy(current_drag_offer); - current_drag_offer = NULL; -} - - -static const struct wl_data_device_listener data_device_listener = { - .data_offer = data_device_handle_data_offer, - .enter = data_device_handle_enter, - .leave = data_device_handle_leave, - .motion = data_device_handle_motion, - .drop = data_device_handle_drop, - .selection = data_device_handle_selection, -}; - - -const struct wl_data_device_listener *Fl_Wayland_Screen_Driver::p_data_device_listener = - &data_device_listener; - - -// Reads from the clipboard an image which can be in image/bmp or image/png MIME type. -// Returns 0 if OK, != 0 if error. -static int get_clipboard_image(struct wl_data_offer *offer) { - int fds[2]; - if (pipe(fds)) return 1; - // preferred mime-type for the image clipboard type - const char *type = clipboard_kinds_map[Fl::clipboard_image].mime_type; - wl_data_offer_receive(offer, type, fds[1]); - close(fds[1]); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); - if (strcmp(type, "image/png") == 0) { - char tmp_fname[21]; - Fl_Shared_Image *shared = 0; - strcpy(tmp_fname, "/tmp/clipboardXXXXXX"); - int fd = mkstemp(tmp_fname); - if (fd >= 0) { - while (true) { - char buf[10000]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) break; - n = write(fd, buf, n); - } - close(fd); - shared = Fl_Shared_Image::get(tmp_fname); - fl_unlink(tmp_fname); - } - close(fds[0]); - if (!shared) return 1; - int ld = shared->ld() ? shared->ld() : shared->w() * shared->d(); - uchar *rgb = new uchar[shared->w() * shared->h() * shared->d()]; - memcpy(rgb, shared->data()[0], ld * shared->h() ); - Fl_RGB_Image *image = new Fl_RGB_Image(rgb, shared->w(), shared->h(), shared->d(), - shared->ld()); - shared->release(); - image->alloc_array = 1; - Fl::e_clipboard_data = (void*)image; - } else { // process image/bmp - uchar buf[54]; - size_t rest = 1; - char *bmp = NULL; - ssize_t n = read(fds[0], buf, sizeof(buf)); // read size info of the BMP image - if (n == sizeof(buf)) { - int w, h; // size of the BMP image - Fl_Unix_System_Driver::read_int(buf + 18, w); - Fl_Unix_System_Driver::read_int(buf + 22, h); - // the number of bytes per row of BMP image, rounded up to multiple of 4 - int R = ((3*w+3)/4) * 4; - bmp = new char[R * h + 54]; - memcpy(bmp, buf, 54); - char *from = bmp + 54; - rest = R * h; - while (rest) { - ssize_t n = read(fds[0], from, rest); - if (n <= 0) break; - from += n; - rest -= n; - } -//fprintf(stderr, "get_clipboard_image: image/bmp %dx%d rest=%lu\n", w,h,rest); - } - close(fds[0]); - if (!rest) Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(bmp); - delete[] bmp; - if (rest) return 1; - } - Fl::e_clipboard_type = Fl::clipboard_image; - return 0; -} - - -void Fl_Wayland_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) { - if (clipboard != 1) return; - if (fl_i_own_selection[1]) { - // We already have it, do it quickly without compositor. - if (type == Fl::clipboard_plain_text && fl_selection_type[1] == type) { - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - if (!Fl::e_text) Fl::e_text = (char *)""; - } else if (type == Fl::clipboard_image && fl_selection_type[1] == type) { - Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(fl_selection_buffer[1]); - Fl::e_clipboard_type = Fl::clipboard_image; - } else return; - receiver.handle(FL_PASTE); - return; - } - // otherwise get the compositor to return it: - if (!fl_selection_offer) return; - if (type == Fl::clipboard_plain_text && clipboard_contains(Fl::clipboard_plain_text)) { - get_clipboard_or_dragged_text(fl_selection_offer); - Fl::e_text = fl_selection_buffer[1]; - Fl::e_length = fl_selection_length[1]; - receiver.handle(FL_PASTE); - } else if (type == Fl::clipboard_image && clipboard_contains(Fl::clipboard_image)) { - if (get_clipboard_image(fl_selection_offer)) return; - struct wld_window * xid = fl_wl_xid(receiver.top_window()); - if (xid) { - int s = Fl_Wayland_Window_Driver::driver(receiver.top_window())->wld_scale(); - if ( s > 1) { - Fl_RGB_Image *rgb = (Fl_RGB_Image*)Fl::e_clipboard_data; - rgb->scale(rgb->data_w() / s, rgb->data_h() / s); - } - } - int done = receiver.handle(FL_PASTE); - Fl::e_clipboard_type = ""; - if (done == 0) { - delete (Fl_RGB_Image*)Fl::e_clipboard_data; - Fl::e_clipboard_data = NULL; - } - } -} - - -void Fl_Wayland_Screen_Driver::copy(const char *stuff, int len, int clipboard, - const char *type) { - if (!stuff || len < 0) return; - - if (clipboard >= 2) - clipboard = 1; // Only on X11 do multiple clipboards make sense. - - if (len+1 > fl_selection_buffer_length[clipboard]) { - delete[] fl_selection_buffer[clipboard]; - fl_selection_buffer[clipboard] = new char[len+100]; - fl_selection_buffer_length[clipboard] = len+100; - } - memcpy(fl_selection_buffer[clipboard], stuff, len); - fl_selection_buffer[clipboard][len] = 0; // needed for direct paste - fl_selection_length[clipboard] = len; - fl_i_own_selection[clipboard] = 1; - fl_selection_type[clipboard] = Fl::clipboard_plain_text; - if (clipboard == 1) { - if (seat->data_source) wl_data_source_destroy(seat->data_source); - seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1); - wl_data_source_offer(seat->data_source, wld_plain_text_clipboard); - wl_data_device_set_selection(seat->data_device, - seat->data_source, - seat->keyboard_enter_serial); -//fprintf(stderr, "wl_data_device_set_selection len=%d to %d\n", len, clipboard); - } -} - - -// takes a raw RGB image and puts it in the copy/paste buffer -void Fl_Wayland_Screen_Driver::copy_image(const unsigned char *data, int W, int H){ - if (!data || W <= 0 || H <= 0) return; - delete[] fl_selection_buffer[1]; - fl_selection_buffer[1] = - (char *)Fl_Unix_System_Driver::create_bmp(data,W,H,&fl_selection_length[1]); - fl_selection_buffer_length[1] = fl_selection_length[1]; - fl_i_own_selection[1] = 1; - fl_selection_type[1] = Fl::clipboard_image; - if (seat->data_source) wl_data_source_destroy(seat->data_source); - seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager); - // we transmit the adequate value of index in fl_selection_buffer[index] - wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1); - wl_data_source_offer(seat->data_source, "image/bmp"); - wl_data_device_set_selection(seat->data_device, seat->data_source, - seat->keyboard_enter_serial); -//fprintf(stderr, "copy_image: len=%d\n", fl_selection_length[1]); -} - -//////////////////////////////////////////////////////////////// -// Code for tracking clipboard changes: - -// is that possible with Wayland ? - -//////////////////////////////////////////////////////////////// - -#endif // !defined(FL_DOXYGEN) diff --git a/src/drivers/Wayland/fl_wayland_platform_init.cxx b/src/drivers/Wayland/fl_wayland_platform_init.cxx deleted file mode 100644 index 4c4477740..000000000 --- a/src/drivers/Wayland/fl_wayland_platform_init.cxx +++ /dev/null @@ -1,157 +0,0 @@ -// -// Wayland-specific code to initialize wayland support. -// -// Copyright 2022-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <FL/fl_config.h> -#include "Fl_Wayland_Copy_Surface_Driver.H" -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "../Unix/Fl_Unix_System_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include "Fl_Wayland_Image_Surface_Driver.H" -#include "../Base/Fl_Base_Pen_Events.H" -#ifdef FLTK_USE_X11 -# include "../Xlib/Fl_Xlib_Copy_Surface_Driver.H" -# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H" -# include "../X11/Fl_X11_Screen_Driver.H" -# include "../X11/Fl_X11_Window_Driver.H" -# include "../Xlib/Fl_Xlib_Image_Surface_Driver.H" -#endif -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - - -#ifdef FLTK_USE_X11 - -static bool attempt_wayland() { - if (Fl_Wayland_Screen_Driver::wl_display) return true; - static bool first = true; - static bool disable_wl = false; - if (first) { // get the value if it exists and cache it - void *sym = Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, "fl_disable_wayland"); - if (sym) { - disable_wl = *(bool *)sym; - // printf("fl_disable_wayland = %s\n", disable_wl ? "true" : "false"); - } - first = false; - } - if (disable_wl) - return false; - const char *backend = ::getenv("FLTK_BACKEND"); - // fprintf(stderr, "FLTK_BACKEND='%s'\n", backend ? backend : ""); - if (backend && strcmp(backend, "x11") == 0) { - return false; - } - - if (backend && strcmp(backend, "wayland") == 0) { - Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL); - if (!Fl_Wayland_Screen_Driver::wl_display) { - fprintf(stderr, "Error: no Wayland connection available, FLTK_BACKEND='wayland'\n"); - exit(1); - } - return true; - } - - if (!backend) { - // env var XDG_RUNTIME_DIR is required for Wayland - const char *xdgrt = ::getenv("XDG_RUNTIME_DIR"); - if (xdgrt) { - // is a Wayland connection available ? - Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL); - if (Fl_Wayland_Screen_Driver::wl_display) { // Yes, use Wayland drivers - // puts("using wayland"); - return true; - } - } - // no Wayland connection or environment variable XDG_RUNTIME_DIR not set, - // falling back to X11 - return false; - } - - fprintf(stderr, "Error: unexpected value of FLTK_BACKEND: '%s'\n", backend); - exit(1); - return false; -} - -#endif // FLTK_USE_X11 - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() { - return new Fl_Unix_System_Driver(); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() { -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) return new Fl_X11_Cairo_Graphics_Driver(); -#endif - return new Fl_Wayland_Graphics_Driver(); -} - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) { -#ifdef FLTK_USE_X11 - if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_Xlib_Copy_Surface_Driver(w, h); -#endif - return new Fl_Wayland_Copy_Surface_Driver(w, h); -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() { - if (!Fl_Screen_Driver::system_driver) Fl::system_driver(); -#ifdef FLTK_USE_X11 - if (attempt_wayland()) { - return new Fl_Wayland_Screen_Driver(); - } - - Fl_X11_Screen_Driver *d = new Fl_X11_Screen_Driver(); - for (int i = 0; i < MAX_SCREENS; i++) d->screens[i].scale = 1; - d->current_xft_dpi = 0.; // means the value of the Xft.dpi resource is still unknown - return d; -#else - return new Fl_Wayland_Screen_Driver(); -#endif -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) return new Fl_X11_Window_Driver(w); -#endif - return new Fl_Wayland_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ -#ifdef FLTK_USE_X11 - if (!attempt_wayland()) - return new Fl_Xlib_Image_Surface_Driver(w, h, high_res, off); -#endif - return new Fl_Wayland_Image_Surface_Driver(w, h, high_res, off); -} - -#if defined(FLTK_HAVE_PEN_SUPPORT) - -namespace Fl { -namespace Pen { -Driver default_driver; -Driver& driver = default_driver; -} // namespace Pen -} // namespace Fl - -#endif // FLTK_HAVE_PEN_SUPPORT diff --git a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H deleted file mode 100644 index 2958fe6e5..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.H +++ /dev/null @@ -1,62 +0,0 @@ -// -// Class Fl_WinAPI_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2023 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_WINAPI_GL_WINDOW_DRIVER_H -#define FL_WINAPI_GL_WINDOW_DRIVER_H - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Gl_Window_Driver.H" -#include <FL/gl.h> - -class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); - Fl_WinAPI_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} - float pixels_per_unit() FL_OVERRIDE; - int mode_(int m, const int *a) FL_OVERRIDE; - void make_current_after() FL_OVERRIDE; - void swap_buffers() FL_OVERRIDE; - void swap_interval(int) FL_OVERRIDE; - int swap_interval() const FL_OVERRIDE; - void invalidate() FL_OVERRIDE {} - int flush_begin(char& valid_f) FL_OVERRIDE; - Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE; - GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE; - GLContext do_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, - int layer); - void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE; - void delete_gl_context(GLContext) FL_OVERRIDE; - void make_overlay_current() FL_OVERRIDE; - void redraw_overlay() FL_OVERRIDE; - void* GetProcAddress(const char *procName) FL_OVERRIDE; - void draw_string_legacy(const char* str, int n) FL_OVERRIDE; - void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) FL_OVERRIDE; - void get_list(Fl_Font_Descriptor *fd, int r) FL_OVERRIDE; - int genlistsize() FL_OVERRIDE; - void switch_to_GL1() FL_OVERRIDE; - void switch_back() FL_OVERRIDE; -#if HAVE_GL_OVERLAY - void gl_hide_before(void *& overlay) FL_OVERRIDE; - int can_do_overlay() FL_OVERRIDE; - int overlay_color(Fl_Color i) FL_OVERRIDE; - void make_overlay(void*&overlay) FL_OVERRIDE; -#endif -}; - -#endif // HAVE_GL - -#endif // FL_WINAPI_GL_WINDOW_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx deleted file mode 100644 index 8e199b09c..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx +++ /dev/null @@ -1,472 +0,0 @@ -// -// Class Fl_WinAPI_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#if HAVE_GL -#include <FL/platform.H> -#include "../../Fl_Screen_Driver.H" -#include <FL/gl.h> -#include "Fl_WinAPI_Gl_Window_Driver.H" -#include "../../Fl_Gl_Choice.H" -#include "Fl_WinAPI_Window_Driver.H" -#include "../GDI/Fl_Font.H" -extern void fl_save_dc(HWND, HDC); - -#ifndef GL_CURRENT_PROGRAM -# define GL_CURRENT_PROGRAM 0x8B8D // from glew.h -#endif - -// STR #3119: select pixel format with composition support -// ... and no more than 32 color bits (8 bits/color) -// Ref: PixelFormatDescriptor Object -// https://msdn.microsoft.com/en-us/library/cc231189.aspx -#if !defined(PFD_SUPPORT_COMPOSITION) -# define PFD_SUPPORT_COMPOSITION (0x8000) -#endif - -#define DEBUG_PFD (0) // 1 = PFD selection debug output, 0 = no debug output - - -// Describes crap needed to create a GLContext. -class Fl_WinAPI_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_WinAPI_Gl_Window_Driver; -private: - int pixelformat; // the visual to use - PIXELFORMATDESCRIPTOR pfd; // some wgl calls need this thing -public: - Fl_WinAPI_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - pixelformat = 0; - } -}; - - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_WinAPI_Gl_Window_Driver(w); -} - - -Fl_Gl_Choice *Fl_WinAPI_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl_WinAPI_Gl_Choice *g = (Fl_WinAPI_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - - // Replacement for ChoosePixelFormat() that finds one with an overlay if possible: - HDC gc = (HDC)(fl_graphics_driver ? fl_graphics_driver->gc() : 0); - if (!gc) gc = fl_GetDC(0); - int pixelformat = 0; - PIXELFORMATDESCRIPTOR chosen_pfd; - for (int i = 1; ; i++) { - PIXELFORMATDESCRIPTOR pfd; - if (!DescribePixelFormat(gc, i, sizeof(pfd), &pfd)) break; - // continue if it does not satisfy our requirements: - if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; - if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; - if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; - if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; - if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; - if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; - // Skipt his descriptor if we want a depth buffer, but this one has none - if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; - // Skipt his descriptor if we want a 32 bit depth buffer, but this one has less or none - if ((m & FL_DEPTH32) && pfd.cDepthBits < 32) continue; - if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; - -#if DEBUG_PFD - printf("pfd #%d supports composition: %s\n", i, (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - printf(" ... & PFD_GENERIC_FORMAT: %s\n", (pfd.dwFlags & PFD_GENERIC_FORMAT) ? "generic" : "accelerated"); - printf(" ... Overlay Planes : %d\n", pfd.bReserved & 15); - printf(" ... Color & Depth : %d, %d\n", pfd.cColorBits, pfd.cDepthBits); - if (pixelformat) - printf(" current pixelformat : %d\n", pixelformat); - fflush(stdout); -#endif // DEBUG_PFD - - // see if better than the one we have already: - if (pixelformat) { - // offering non-generic rendering is better (read: hardware acceleration) - if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && - (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; - // offering overlay is better: - else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} - // otherwise prefer a format that supports composition (STR #3119) - else if ((chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) && - !(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) continue; - // otherwise more bit planes is better, but no more than 32 (8 bits per channel): - else if (pfd.cColorBits > 32 || chosen_pfd.cColorBits > pfd.cColorBits) continue; - else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; - } - pixelformat = i; - chosen_pfd = pfd; - } - -#if DEBUG_PFD - static int bb = 0; - if (!bb) { - bb = 1; - printf("PFD_SUPPORT_COMPOSITION = 0x%x\n", PFD_SUPPORT_COMPOSITION); - } - printf("Chosen pixel format is %d\n", pixelformat); - printf("Color bits = %d, Depth bits = %d\n", chosen_pfd.cColorBits, chosen_pfd.cDepthBits); - printf("Pixel format supports composition: %s\n", (chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - fflush(stdout); -#endif // DEBUG_PFD - - if (!pixelformat) return 0; - - g = new Fl_WinAPI_Gl_Choice(m, alistp, first); - first = g; - - g->pixelformat = pixelformat; - g->pfd = chosen_pfd; - - return g; -} - - -GLContext Fl_WinAPI_Gl_Window_Driver::do_create_gl_context(Fl_Window* window, - const Fl_Gl_Choice* g, int layer) -{ - Fl_X* i = Fl_X::flx(window); - HDC hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc; - if (!hdc) { - hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc = GetDCEx((HWND)i->xid, 0, DCX_CACHE); - fl_save_dc((HWND)i->xid, hdc); - SetPixelFormat(hdc, ((Fl_WinAPI_Gl_Choice*)g)->pixelformat, (PIXELFORMATDESCRIPTOR*)(&((Fl_WinAPI_Gl_Choice*)g)->pfd)); -# if USE_COLORMAP - if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); -# endif - } - GLContext context = layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); - if (context) { - if (context_list && nContext) - wglShareLists((HGLRC)context_list[0], (HGLRC)context); - add_context(context); - } - return context; -} - - -GLContext Fl_WinAPI_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) -{ - return do_create_gl_context(window, g, 0); -} - -void Fl_WinAPI_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - GLContext current_context = wglGetCurrentContext(); - if (context != current_context || w != cached_window) { - cached_window = w; - wglMakeCurrent(Fl_WinAPI_Window_Driver::driver(w)->private_dc, (HGLRC)context); - } -} - -void Fl_WinAPI_Gl_Window_Driver::delete_gl_context(GLContext context) { - GLContext current_context = wglGetCurrentContext(); - if (current_context == context) { - cached_window = 0; - wglMakeCurrent(0, 0); - } - wglDeleteContext((HGLRC)context); - del_context(context); -} - - -void Fl_WinAPI_Gl_Window_Driver::make_overlay_current() { -#if HAVE_GL_OVERLAY - if (overlay() != this) { - set_gl_context(pWindow, (GLContext)overlay()); - // if (fl_overlay_depth) - // wglRealizeLayerPalette(Fl_X::flx(this)->private_dc, 1, TRUE); - } else -#endif - glDrawBuffer(GL_FRONT); -} - -void Fl_WinAPI_Gl_Window_Driver::redraw_overlay() { - pWindow->damage(FL_DAMAGE_OVERLAY); -} - -#if HAVE_GL_OVERLAY - -// Methods on Fl_Gl_Window_driver that create an overlay window. - -// Under win32 another GLX context is created to draw into the overlay -// and it is stored in the "overlay" pointer. - -// If overlay hardware is unavailable, the overlay is -// "faked" by drawing into the main layers. This is indicated by -// setting overlay == this. - -//static COLORREF *palette; -static int fl_overlay_depth = 0; - -void Fl_WinAPI_Gl_Window_Driver::gl_hide_before(void *& overlay) { - if (overlay && overlay != pWindow) { - delete_gl_context((GLContext)overlay); - overlay = 0; - } -} - -void Fl_WinAPI_Gl_Window_Driver::make_overlay(void*&overlay) { - if (overlay) return; - - GLContext context = do_create_gl_context(pWindow, g(), 1); - if (!context) {overlay = pWindow; return;} // fake the overlay - - HDC hdc = Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc; - overlay = context; - LAYERPLANEDESCRIPTOR pfd; - wglDescribeLayerPlane(hdc, g()->pixelformat, 1, sizeof(pfd), &pfd); - if (!pfd.iPixelType) { - ; // full-color overlay - } else { - fl_overlay_depth = pfd.cColorBits; // used by gl_color() - if (fl_overlay_depth > 8) fl_overlay_depth = 8; - COLORREF palette[256]; - int n = (1<<fl_overlay_depth)-1; - // copy all colors except #0 into the overlay palette: - for (int i = 0; i <= n; i++) { - uchar r,g,b; Fl::get_color((Fl_Color)i,r,g,b); - palette[i] = RGB(r,g,b); - } - // always provide black & white in the last 2 pixels: - if (fl_overlay_depth < 8) { - palette[n-1] = RGB(0,0,0); - palette[n] = RGB(255,255,255); - } - // and use it: - wglSetLayerPaletteEntries(hdc, 1, 1, n, palette+1); - wglRealizeLayerPalette(hdc, 1, TRUE); - } - pWindow->valid(0); - return; -} - -int Fl_WinAPI_Gl_Window_Driver::can_do_overlay() { - if (!g()) { - g( find(mode(), alist()) ); - if (!g()) return 0; - } - return (g()->pfd.bReserved & 15) != 0; -} - -int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) { - if (Fl_Xlib_Graphics_Driver::fl_overlay && fl_overlay_depth) { - if (fl_overlay_depth < 8) { - // only black & white produce the expected colors. This could - // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx - int size = 1<<fl_overlay_depth; - if (!i) glIndexi(size-2); - else if (i >= size-2) glIndexi(size-1); - else glIndexi(i); - } else { - glIndexi(i ? i : FL_GRAY_RAMP); - } - return 1; - } - return 0; -} - -#endif // HAVE_GL_OVERLAY - - -float Fl_WinAPI_Gl_Window_Driver::pixels_per_unit() -{ - int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); - return Fl::screen_driver()->scale(ns); -} - - -int Fl_WinAPI_Gl_Window_Driver::mode_(int m, const int *a) { - int oldmode = mode(); - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - if (!g() || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { - pWindow->hide(); - pWindow->show(); - } - } else { - g(0); - } - return 1; -} - -void Fl_WinAPI_Gl_Window_Driver::make_current_after() { -#if USE_COLORMAP - if (fl_palette) { - fl_GetDC(fl_xid(pWindow)); - SelectPalette((HDC)fl_graphics_driver->gc(), fl_palette, FALSE); - RealizePalette((HDC)fl_graphics_driver->gc()); - } -#endif // USE_COLORMAP -} - -//#define HAVE_GL_OVERLAY 1 //test only - -void Fl_WinAPI_Gl_Window_Driver::swap_buffers() { -# if HAVE_GL_OVERLAY - // Do not swap the overlay, to match GLX: - BOOL ret = wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_MAIN_PLANE); - DWORD err = GetLastError(); -# else - SwapBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc); -# endif -} - - -// Start of swap_interval implementation in the three possibel ways for X11 - -// -1 = not yet initialized, 0 = none found, 1 = GLX, 2 = MESA, 3 = SGI -static signed char swap_interval_type = -1; - -typedef const char *(WINAPI *WGL_Get_Extension_String_Proc)(); -typedef BOOL (WINAPI *WGL_Swap_Iterval_Proc)(int interval); -typedef int (WINAPI *WGL_Get_Swap_Iterval_Proc)(); - -static WGL_Swap_Iterval_Proc wglSwapIntervalEXT = NULL; -static WGL_Get_Swap_Iterval_Proc wglGetSwapIntervalEXT = NULL; - -static void init_swap_interval() { - if (swap_interval_type != -1) - return; - swap_interval_type = 0; - WGL_Get_Extension_String_Proc wglGetExtensionsStringEXT = NULL; - wglGetExtensionsStringEXT = (WGL_Get_Extension_String_Proc)wglGetProcAddress("wglGetExtensionsStringEXT"); - if (!wglGetExtensionsStringEXT) - return; - const char *extensions = wglGetExtensionsStringEXT(); - if (extensions && strstr(extensions, "WGL_EXT_swap_control")) { - wglSwapIntervalEXT = (WGL_Swap_Iterval_Proc)wglGetProcAddress("wglSwapIntervalEXT"); - wglGetSwapIntervalEXT = (WGL_Get_Swap_Iterval_Proc)wglGetProcAddress("wglGetSwapIntervalEXT"); - swap_interval_type = 1; - } -} - -void Fl_WinAPI_Gl_Window_Driver::swap_interval(int interval) { - if (swap_interval_type == -1) - init_swap_interval(); - if (swap_interval_type == 1) { - if (wglSwapIntervalEXT) - wglSwapIntervalEXT(interval); - } -} - -int Fl_WinAPI_Gl_Window_Driver::swap_interval() const { - if (swap_interval_type == -1) - init_swap_interval(); - int interval = -1; - if (swap_interval_type == 1) { - if (wglGetSwapIntervalEXT) - interval = wglGetSwapIntervalEXT(); - } - return interval; -} - -// end of swap_interval implementation - -#if HAVE_GL_OVERLAY -#endif - -int Fl_WinAPI_Gl_Window_Driver::flush_begin(char& valid_f_) { -#if HAVE_GL_OVERLAY - char save_valid_f = valid_f_; - // Draw into hardware overlay planes if they are damaged: - if (overlay() && overlay() != pWindow - && (pWindow->damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid_f & 1)) { - set_gl_context(pWindow, (GLContext)overlay()); - if (fl_overlay_depth) - wglRealizeLayerPalette(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, 1, TRUE); - glDisable(GL_SCISSOR_TEST); - glClear(GL_COLOR_BUFFER_BIT); - Fl_Xlib_Graphics_Driver::fl_overlay = 1; - draw_overlay(); - Fl_Xlib_Graphics_Driver::fl_overlay = 0; - valid_f_ = save_valid_f; - wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_OVERLAY1); - // if only the overlay was damaged we are done, leave main layer alone: - if (pWindow->damage() == FL_DAMAGE_OVERLAY) { - return 1; - } - } -#endif - return 0; -} - -void* Fl_WinAPI_Gl_Window_Driver::GetProcAddress(const char *procName) { - return (void*)wglGetProcAddress((LPCSTR)procName); -} - - -void Fl_WinAPI_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { - draw_string_legacy_get_list(str, n); -} - -int Fl_WinAPI_Gl_Window_Driver::genlistsize() { - return 0x10000; -} - -void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { - if (!fl_fontsize->listbase) { - fl_fontsize->listbase = glGenLists(genlistsize()); - } - glListBase(fl_fontsize->listbase); -} - -void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { - Fl_GDI_Font_Descriptor* gl_fd = (Fl_GDI_Font_Descriptor*)fd; - if (gl_fd->glok[r]) return; - gl_fd->glok[r] = 1; - unsigned int ii = r * 0x400; - HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid); - wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, 0x400, gl_fd->listbase+ii); - SelectObject((HDC)fl_graphics_driver->gc(), oldFid); -} - - -typedef void (WINAPI *glUseProgram_type)(GLint); -static glUseProgram_type glUseProgram_f = NULL; - -void Fl_WinAPI_Gl_Window_Driver::switch_to_GL1() { - if (!glUseProgram_f) { - glUseProgram_f = (glUseProgram_type)GetProcAddress("glUseProgram"); - } - glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_prog); - if (current_prog) glUseProgram_f(0); -} - -void Fl_WinAPI_Gl_Window_Driver::switch_back() { - if (current_prog) glUseProgram_f((GLuint)current_prog); -} - - -class Fl_WinAPI_Gl_Plugin : public Fl_WinAPI_Plugin { -public: - Fl_WinAPI_Gl_Plugin() : Fl_WinAPI_Plugin(name()) { } - const char *name() override { return "gl.winapi.fltk.org"; } - void invalidate(Fl_Window *w) override { - w->as_gl_window()->valid(0); - } -}; - - -static Fl_WinAPI_Gl_Plugin Gl_Invalidate_Plugin; - - -FL_EXPORT HGLRC fl_win32_glcontext(GLContext rc) { return (HGLRC)rc; } - -#endif // HAVE_GL diff --git a/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx deleted file mode 100644 index 06cc1e477..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Pen_Driver.cxx +++ /dev/null @@ -1,518 +0,0 @@ -// -// Definition of Windows Pen/Tablet event driver. -// -// Copyright 2025-2026 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Note: We require Windows 8 or later features for Pen/Tablet support. -// Defining WINVER and _WIN32_WINNT to 0x0602 *may* be required on some -// Windows build platforms. Must be done before all #include's. - -#if !defined(WINVER) || (WINVER < 0x0602) -# ifdef WINVER -# undef WINVER -# endif -# define WINVER 0x0602 -#endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602) -# ifdef _WIN32_WINNT -# undef _WIN32_WINNT -# endif -# define _WIN32_WINNT 0x0602 -#endif - -#include "src/drivers/Base/Fl_Base_Pen_Events.H" - -#include <FL/platform.H> -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include "../../Fl_Screen_Driver.H" -#include <math.h> -#include <windows.h> -#include <ole2.h> -#include <shellapi.h> -// Some versions of MinGW now require us to explicitly include winerror to get S_OK defined -#include <winerror.h> - -extern Fl_Window *fl_xmousewin; - -static constexpr uint8_t _FL_PEN = 0; // internal use -static constexpr uint8_t _FL_ERASER = 1; // internal use -static uint8_t device_type_ = _FL_PEN; - -static int _e_x_down = 0; -static int _e_y_down = 0; - -// Click counting state -static DWORD last_click_time_ = 0; -static int last_click_x_ = 0; -static int last_click_y_ = 0; -static Fl::Pen::State last_click_trigger_ = Fl::Pen::State::NONE; - -// The trait list keeps track of traits for every pen ID that appears while -// handling events. -// AppKit does not tell us what traits are available per pen or tablet, so -// we use the first 5 motion events to discover event values that are not -// the default value, and enter that knowledge into the traits database. -typedef std::map<int, Fl::Pen::Trait> TraitList; -static TraitList trait_list_; -static int trait_countdown_ { 5 }; -static int current_pen_id_ { -1 }; -static Fl::Pen::Trait current_pen_trait_ { Fl::Pen::Trait::DRIVER_AVAILABLE }; -static Fl::Pen::Trait driver_traits_ { - Fl::Pen::Trait::DRIVER_AVAILABLE | Fl::Pen::Trait::PEN_ID | - Fl::Pen::Trait::ERASER | Fl::Pen::Trait::PRESSURE | - Fl::Pen::Trait::TILT_X | - Fl::Pen::Trait::TILT_Y | Fl::Pen::Trait::TWIST - // Notably missing: PROXIMITY, BARREL_PRESSURE -}; - -// Temporary storage of event data for the driver; -static Fl::Pen::EventData ev; - - -namespace Fl { - -// namespace Private { - -// // Global mouse position at mouse down event -// extern int e_x_down; -// extern int e_y_down; - -// }; // namespace Private - -namespace Pen { - -class Windows_Driver : public Driver { -public: - Windows_Driver() = default; - //virtual void subscribe(Fl_Widget* widget) override; - //virtual void unsubscribe(Fl_Widget* widget) override; - //virtual void release() override; - virtual Trait traits() override { return driver_traits_; } - virtual Trait pen_traits(int pen_id) override { - auto it = trait_list_.find(pen_id); - if (pen_id == 0) - return current_pen_trait_; - if (it == trait_list_.end()) { - return Trait::DRIVER_AVAILABLE; - } else { - return it->second; - } - } -}; - -Windows_Driver windows_driver; -Driver& driver { windows_driver }; - -} // namespace Pen - -} // namespace Fl - - -using namespace Fl::Pen; - -/* - Copy the event state. - */ -static void copy_state() { - Fl::Pen::State tr = (Fl::Pen::State)((uint32_t)Fl::Pen::e.state ^ (uint32_t)ev.state); - Fl::Pen::e = ev; - Fl::Pen::e.trigger = tr; - Fl::e_x = (int)ev.x; - Fl::e_y = (int)ev.y; - Fl::e_x_root = (int)ev.rx; - Fl::e_y_root = (int)ev.ry; -} - -/* - Check if coordinates are within the widget box. - Coordinates are in top_window space. We iterate up the hierarchy to ensure - that we handle subwindows correctly. - */ -static bool event_inside(Fl_Widget *w, double x, double y) { - if (w->as_window()) { - return ((x >= 0) && (y >= 0) && (x < w->w()) && (y < w->h())); - } else { - return ((x >= w->x()) && (y >= w->y()) && (x < w->x() + w->w()) && (y < w->y() + w->h())); - } -} - -/* - Find the widget under the pen event. - Search the subscriber list for widgets that are inside the same window, - are visible, and are within the give coordinates. Subwindow aware. - */ -static Fl_Widget *find_below_pen(Fl_Window *win, double x, double y) { - for (auto &sub: subscriber_list_) { - Fl_Widget *candidate = sub.second->widget(); - if (candidate && ((candidate == win) || (!candidate->as_window() && candidate->window() == win))) { - if (candidate->visible() && event_inside(candidate, x, y)) { - return candidate; - } - } - } - return nullptr; -} - -/* - Send the current event and event data to a widget. - Note: we will get the wrong coordinates if the widget is not a child of - the current event window (LEAVE events between windows). - */ -static int pen_send(Fl_Widget *w, int event, State trigger, bool &copied) { - // Copy most event data only once - if (!copied) { - copy_state(); - copied = true; - } - // Copy the top_window coordinates again as they may change when w changes - Fl::e_x = e.x = ev.x; - Fl::e_y = e.y = ev.y; - // Send the event. - e.trigger = trigger; - return w->handle(event); -} - -/* - Send an event to all subscribers. - */ -static int pen_send_all(int event, State trigger) { - bool copied = false; - // use local value because handler may still change ev values - for (auto &it: subscriber_list_) { - auto w = it.second->widget(); - if (w) - pen_send(w, event, trigger, copied); - } - return 1; -} - -/* - Convert the NSEvent button number to Fl::Pen::State, - */ -static State button_to_trigger(POINTER_BUTTON_CHANGE_TYPE button, bool down) { - switch (button) { - case POINTER_CHANGE_FIRSTBUTTON_DOWN: - case POINTER_CHANGE_FIRSTBUTTON_UP: - if ( (ev.state & (State::ERASER_DOWN | State::ERASER_HOVERS)) != State::NONE ) { - return down ? State::ERASER_DOWN : State::ERASER_HOVERS; - } else { - return down ? State::TIP_DOWN : State::TIP_HOVERS; - } - case POINTER_CHANGE_SECONDBUTTON_DOWN: - case POINTER_CHANGE_SECONDBUTTON_UP: - return State::BUTTON0; - case POINTER_CHANGE_THIRDBUTTON_DOWN: - case POINTER_CHANGE_THIRDBUTTON_UP: - return State::BUTTON1; - case POINTER_CHANGE_FOURTHBUTTON_DOWN: - case POINTER_CHANGE_FOURTHBUTTON_UP: - return State::BUTTON2; - case POINTER_CHANGE_FIFTHBUTTON_DOWN: - case POINTER_CHANGE_FIFTHBUTTON_UP: - return State::BUTTON3; - default: return State::NONE; - } -} - -/* - Handle events coming from the Win32 API. - WM_TABLET (Windows 2000 and up) - WM_POINTER (Windows 8 and up) - https://learn.microsoft.com/en-us/windows/win32/inputmsg/messages-and-notifications-portal - #if(WINVER >= 0x0602) ... #endif - \return -1 if we did not handle the event and want the main event handler to call DefWindowProc() - \return any other value that will then be return from WndProc() directly. - */ -LRESULT fl_win32_tablet_handler(MSG& msg) { - auto message = msg.message; - if (message < WM_NCPOINTERUPDATE || message > WM_POINTERROUTEDRELEASED) { - return -1; - } - - Fl_Window *eventWindow = fl_find(msg.hwnd); // can be nullptr - bool is_proximity = false; - bool is_down = false; - bool is_up = false; - bool is_motion = false; - - switch (msg.message) { - case WM_NCPOINTERDOWN: // pen pushed over window decoration, don't care - case WM_NCPOINTERUP: // pen released over window decoration, don't care - case WM_NCPOINTERUPDATE: // pen moved over decoration, don't care - case WM_POINTERACTIVATE: // shall the pointer activate an inactive window? - return -1; // let the system handle this forwarding this to DefWindowProc - - case WM_POINTERENTER: // pointer moved into window area from top or sides - is_proximity = true; - break; - case WM_POINTERLEAVE: // left window area to top or sides - is_proximity = true; - break; - - - case WM_POINTERDOWN: - is_down = true; - break; - case WM_POINTERUP: - is_up = true; - break; - case WM_POINTERUPDATE: - is_motion = true; - break; - - case WM_POINTERCAPTURECHANGED: - case WM_TOUCHHITTESTING: - case WM_POINTERWHEEL: - case WM_POINTERHWHEEL: - case DM_POINTERHITTEST: - case WM_POINTERROUTEDTO: - case WM_POINTERROUTEDAWAY: - case WM_POINTERROUTEDRELEASED: - default: - // printf("Windows message: msg=0x%04X wParam=0x%08X lParam=0x%08X\n", - // msg.message, (unsigned)msg.wParam, (unsigned)msg.lParam); - return -1; - } - // printf(" msg=0x%04X wParam=0x%08X lParam=0x%08X\n", - // msg.message, (unsigned)msg.wParam, (unsigned)msg.lParam); - - POINTER_PEN_INFO info; - BOOL has_position = GetPointerPenInfo( - GET_POINTERID_WPARAM(msg.wParam), - &info - ); - // if (has_position && info.pointerInfo.ButtonChangeType!=0) { - // printf(" pointerFlags: %08x [", (unsigned)info.pointerInfo.pointerFlags); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIRSTBUTTON) printf(" 1ST"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_SECONDBUTTON) printf(" 2ND"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_THIRDBUTTON) printf(" 3RD"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FOURTHBUTTON) printf(" 4TH"); - // if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIFTHBUTTON) printf(" 5TH"); - // printf(" ]\n penFlags: %08x [", (unsigned)info.penFlags); - // if (info.penFlags & PEN_FLAG_BARREL) printf(" BARREL"); - // if (info.penFlags & PEN_FLAG_INVERTED) printf(" INVERTED"); - // if (info.penFlags & PEN_FLAG_ERASER) printf(" ERASER"); - // printf(" ]\n penMask: %08x ButtonChangeType: %d\n", - // (unsigned)info.penMask, info.pointerInfo.ButtonChangeType); - // } - - // Event has extended pen data set: - if (has_position) { - // Get the position data. - double s = Fl::screen_driver()->scale(0); - double ex = info.pointerInfo.ptPixelLocation.x/s; - double ey = info.pointerInfo.ptPixelLocation.y/s; - // Go from global coordinates to event window coordinates - Fl_Widget *p = eventWindow; - while (p) { - if (p->as_window()) { - ex -= p->x(); - ey -= p->y(); - } - p = p->parent(); - }; - ev.x = ex; - ev.y = ey; - ev.rx = info.pointerInfo.ptPixelLocation.x/s; - ev.ry = info.pointerInfo.ptPixelLocation.y/s; - if (!is_proximity) { - // Get the extended data. - if (info.penMask & PEN_MASK_PRESSURE) - ev.pressure = info.pressure / 1024.0; - if (info.penMask & PEN_MASK_TILT_X) - ev.tilt_x = -info.tiltX / 90.0; - if (info.penMask & PEN_MASK_TILT_Y) - ev.tilt_y = -info.tiltY / 90.0; - if (info.penMask & PEN_MASK_ROTATION) - ev.twist = info.rotation > 180 ? (info.rotation - 360) : info.rotation; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.proximity = 0.0; - else - ev.proximity = 1.0; - } - if (info.penFlags & PEN_FLAG_INVERTED) { - device_type_ = _FL_ERASER; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.state = State::ERASER_DOWN; - else - ev.state = State::ERASER_HOVERS; - } else { - device_type_ = _FL_PEN; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) - ev.state = State::TIP_DOWN; - else - ev.state = State::TIP_HOVERS; - } - // Add pen barrel button states - // Note: POINTER_FLAG_FIRSTBUTTON is the pen tip - // PEN_FLAG_BARREL and POINTER_FLAG_SECONDBUTTON both indicate the primary barrel button - if ((info.penFlags & PEN_FLAG_BARREL) || (info.pointerInfo.pointerFlags & POINTER_FLAG_SECONDBUTTON)) - ev.state |= State::BUTTON0; - // Note: the following code does not work very well with the Wayland driver - // More research is needed to find out how to get these button states reliably. - if (info.pointerInfo.pointerFlags & POINTER_FLAG_THIRDBUTTON) ev.state |= State::BUTTON1; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_FOURTHBUTTON) ev.state |= State::BUTTON2; - if (info.pointerInfo.pointerFlags & POINTER_FLAG_FIFTHBUTTON) ev.state |= State::BUTTON3; - } - // printf(" %08x\n", (unsigned)ev.state); - if (is_proximity) { - ev.pen_id = GET_POINTERID_WPARAM(msg.wParam); - } - if ((msg.message == WM_POINTERENTER) || (msg.message == WM_POINTERLEAVE)) { - if (msg.message == WM_POINTERENTER) { - // Check if this is the first time we see this pen, or if the pen changed - if (current_pen_id_ != ev.pen_id) { - current_pen_id_ = ev.pen_id; - auto it = trait_list_.find(current_pen_id_); - if (it == trait_list_.end()) { // not found, create a new entry - trait_list_[current_pen_id_] = Trait::DRIVER_AVAILABLE; - trait_countdown_ = 5; - pen_send_all(Fl::Pen::DETECTED, State::NONE); - // printf("IN RANGE, NEW PEN\n"); - } else { - pen_send_all(Fl::Pen::CHANGED, State::NONE); - // printf("IN RANGE, CHANGED PEN\n"); - } - trait_list_[0] = trait_list_[current_pen_id_]; // set current pen traits - } else { - pen_send_all(Fl::Pen::IN_RANGE, State::NONE); - // printf("IN RANGE\n"); - } - } else { - pen_send_all(Fl::Pen::OUT_OF_RANGE, State::NONE); - // printf("OUT OF RANGE\n"); - } - } - - Fl_Widget *receiver = nullptr; - bool pushed = false; - bool event_data_copied = false; - - if (has_position) { - if (trait_countdown_) { - trait_countdown_--; - if (ev.tilt_x != 0.0) current_pen_trait_ |= Trait::TILT_X; - if (ev.tilt_y != 0.0) current_pen_trait_ |= Trait::TILT_Y; - if (ev.pressure != 1.0) current_pen_trait_ |= Trait::PRESSURE; - if (ev.barrel_pressure != 0.0) current_pen_trait_ |= Trait::BARREL_PRESSURE; - if (ev.pen_id != 0) current_pen_trait_ |= Trait::PEN_ID; - if (ev.twist != 0.0) current_pen_trait_ |= Trait::TWIST; - //if (ev.proximity != 0) current_pen_trait_ |= Trait::PROXIMITY; - trait_list_[current_pen_id_] = current_pen_trait_; - } - fl_xmousewin = eventWindow; - if (pushed_ && pushed_->widget() && (Fl::pushed() == pushed_->widget())) { - receiver = pushed_->widget(); - if (Fl::grab() && (Fl::grab() != receiver->top_window())) - return -1; - if (Fl::modal() && (Fl::modal() != receiver->top_window())) - return -1; - pushed = true; - } else { - if (Fl::grab() && (Fl::grab() != eventWindow)) - return -1; - if (Fl::modal() && (Fl::modal() != eventWindow)) - return -1; - auto bpen = below_pen_ ? below_pen_->widget() : nullptr; - auto bmouse = Fl::belowmouse(); - auto bpen_old = bmouse && (bmouse == bpen) ? bpen : nullptr; - auto bpen_now = find_below_pen(eventWindow, ev.x, ev.y); - - if (bpen_now != bpen_old) { - if (bpen_old) { - pen_send(bpen_old, Fl::Pen::LEAVE, State::NONE, event_data_copied); - } - below_pen_ = nullptr; - if (bpen_now) { - State state = (device_type_ == _FL_ERASER) ? State::ERASER_HOVERS : State::TIP_HOVERS; - if (pen_send(bpen_now, Fl::Pen::ENTER, state, event_data_copied)) { - below_pen_ = subscriber_list_[bpen_now]; - Fl::belowmouse(bpen_now); - } - } - } - - receiver = below_pen_ ? below_pen_->widget() : nullptr; - if (!receiver) - return -1; - } - } else { - // Proximity events were handled earlier. - } - - if (!receiver) - return -1; - - if (is_down) { - if (!pushed) { - pushed_ = subscriber_list_[receiver]; - Fl::pushed(receiver); - } - State trigger = button_to_trigger(info.pointerInfo.ButtonChangeType, true); - if (msg.message == WM_POINTERDOWN) { - Fl::e_is_click = 1; - _e_x_down = (int)ev.x; - _e_y_down = (int)ev.y; - - // Implement click counting using Windows system metrics - DWORD current_time = GetMessageTime(); - DWORD double_click_time = GetDoubleClickTime(); - int double_click_dx = GetSystemMetrics(SM_CXDOUBLECLK) / 2; - int double_click_dy = GetSystemMetrics(SM_CYDOUBLECLK) / 2; - - // Check if this is a multi-click: same trigger, within time and distance thresholds - if (trigger == last_click_trigger_ && - (current_time - last_click_time_) < double_click_time && - abs((int)ev.rx - last_click_x_) < double_click_dx && - abs((int)ev.ry - last_click_y_) < double_click_dy) { - Fl::e_clicks++; - } else { - Fl::e_clicks = 0; - } - - last_click_time_ = current_time; - last_click_x_ = (int)ev.rx; - last_click_y_ = (int)ev.ry; - last_click_trigger_ = trigger; - - pen_send(receiver, Fl::Pen::TOUCH, trigger, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::BUTTON_PUSH, trigger, event_data_copied); - } - } else if (is_up) { - if ( (ev.state & State::ANY_DOWN) == State::NONE ) { - Fl::pushed(nullptr); - pushed_ = nullptr; - } - State trigger = button_to_trigger(info.pointerInfo.ButtonChangeType, true); - if (info.pointerInfo.ButtonChangeType == 0) - pen_send(receiver, Fl::Pen::LIFT, trigger, event_data_copied); - else - pen_send(receiver, Fl::Pen::BUTTON_RELEASE, trigger, event_data_copied); - } else if (is_motion) { - if ( Fl::e_is_click && - ( (fabs((int)ev.x - _e_x_down) > 5) || - (fabs((int)ev.y - _e_y_down) > 5) ) ) - Fl::e_is_click = 0; - if (pushed) { - pen_send(receiver, Fl::Pen::DRAW, State::NONE, event_data_copied); - } else { - pen_send(receiver, Fl::Pen::HOVER, State::NONE, event_data_copied); - } - } - // Always return 0 because at this point, we capture pen events and don't - // want mouse events anymore! - return 0; -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx deleted file mode 100644 index 4b74c76cb..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Printer_Driver.cxx +++ /dev/null @@ -1,518 +0,0 @@ -// -// Printing support for Windows for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2024 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include <FL/Fl_PDF_File_Surface.H> -#include <FL/Fl_Paged_Device.H> -#include <FL/Fl_Printer.H> -#include <FL/Fl_Native_File_Chooser.H> -#include <FL/fl_ask.H> -#include <FL/math.h> -#include <FL/fl_draw.H> -#include <FL/platform.H> // for fl_win32_xid() -#include <FL/fl_string_functions.h> // fl_strdup() -#include <commdlg.h> -#include <winspool.h> // DocumentProperties(), OpenPrinter(), ClosePrinter() - -extern HWND fl_window; - -/** Support for printing on the Windows platform */ -class Fl_WinAPI_Printer_Driver : public Fl_Paged_Device { - friend class Fl_Printer; -protected: - int abortPrint; - PRINTDLG pd; - HDC hPr; - int prerr; - int left_margin; - int top_margin; - void absolute_printable_rect(int *x, int *y, int *w, int *h); - Fl_WinAPI_Printer_Driver(void); - int begin_job(int pagecount = 0, int *frompage = NULL, int *topage = NULL, char **perr_message = NULL) FL_OVERRIDE; - int begin_page (void) FL_OVERRIDE; - int printable_rect(int *w, int *h) FL_OVERRIDE; - void margins(int *left, int *top, int *right, int *bottom) FL_OVERRIDE; - void origin(int *x, int *y) FL_OVERRIDE; - void origin(int x, int y) FL_OVERRIDE; - void scale (float scale_x, float scale_y = 0.) FL_OVERRIDE; - void rotate(float angle) FL_OVERRIDE; - void translate(int x, int y) FL_OVERRIDE; - void untranslate(void) FL_OVERRIDE; - int end_page (void) FL_OVERRIDE; - void end_job (void) FL_OVERRIDE; - ~Fl_WinAPI_Printer_Driver(void); -}; - -Fl_WinAPI_Printer_Driver::Fl_WinAPI_Printer_Driver(void) : Fl_Paged_Device() { - hPr = NULL; - driver(new Fl_GDI_Printer_Graphics_Driver); -} - -Fl_Paged_Device* Fl_Printer::newPrinterDriver(void) -{ - return new Fl_WinAPI_Printer_Driver(); -} - - -Fl_WinAPI_Printer_Driver::~Fl_WinAPI_Printer_Driver(void) { - if (hPr) end_job(); - delete driver(); -} - -static void WIN_SetupPrinterDeviceContext(HDC prHDC) -{ - if ( !prHDC ) return; - - fl_window = 0; - SetGraphicsMode(prHDC, GM_ADVANCED); // to allow for rotations - SetMapMode(prHDC, MM_ANISOTROPIC); - SetTextAlign(prHDC, TA_BASELINE|TA_LEFT); - SetBkMode(prHDC, TRANSPARENT); - // this matches 720 logical units to the number of device units in 10 inches of paper - // thus the logical unit is the point (= 1/72 inch) - SetWindowExtEx(prHDC, 720, 720, NULL); - SetViewportExtEx(prHDC, 10*GetDeviceCaps(prHDC, LOGPIXELSX), 10*GetDeviceCaps(prHDC, LOGPIXELSY), NULL); -} - - -class Fl_PDF_GDI_File_Surface : public Fl_WinAPI_Printer_Driver -{ -private: - static LPSTR pdf_printer_name_; -public: - char *doc_fname; - Fl_PDF_GDI_File_Surface(); - ~Fl_PDF_GDI_File_Surface() { if (doc_fname) free(doc_fname); } - int begin_job(const char *defaultname, - char **perr_message = NULL); - int begin_job(int, int*, int *, char **) FL_OVERRIDE {return 1;} // don't use - int begin_document(const char* outname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message); - void end_job() FL_OVERRIDE; -}; - -LPSTR Fl_PDF_GDI_File_Surface::pdf_printer_name_ = _strdup("Microsoft Print to PDF"); - -Fl_PDF_GDI_File_Surface::Fl_PDF_GDI_File_Surface() { - driver(new Fl_GDI_Graphics_Driver()); - doc_fname = NULL; -} - -Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) { - Fl_PDF_GDI_File_Surface *surf = new Fl_PDF_GDI_File_Surface(); - *pfname = (const char**)&surf->doc_fname; - return surf; -} - -int Fl_PDF_File_Surface::begin_job(const char* defaultfilename, - char **perr_message) { - return ((Fl_PDF_GDI_File_Surface*)platform_surface_)->begin_job(defaultfilename, perr_message); -} - -int Fl_PDF_File_Surface::begin_document(const char* defaultfilename, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - return ((Fl_PDF_GDI_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message); -} - - -int Fl_PDF_GDI_File_Surface::begin_job(const char *defaultfname, char **perr_message) { - int err = 0; - abortPrint = FALSE; - - HANDLE hPr2; - err = OpenPrinterA(pdf_printer_name_, &hPr2, NULL); - if (err == 0) { - if (perr_message) { - int l = 240; - *perr_message = new char[l]; - snprintf(*perr_message, l, - "Class Fl_PDF_File_Surface requires printer '%s' available in Windows 10+.", - pdf_printer_name_); - } - return 1; - } - HWND hwndOwner = fl_win32_xid(Fl::first_window()); - LONG count = DocumentPropertiesA(hwndOwner, hPr2, pdf_printer_name_, NULL, NULL, 0); - if (count <= 0) { ClosePrinter(hPr2); return 1; } - char *buffer = new char[count]; - DEVMODEA *pDevMode = (DEVMODEA*)buffer; - memset(buffer, 0, count); - pDevMode->dmSize = (WORD)count; - count = DocumentPropertiesA(hwndOwner, hPr2, pdf_printer_name_, pDevMode, NULL, DM_OUT_BUFFER | DM_IN_PROMPT); - ClosePrinter(hPr2); - if (count == IDCANCEL || count < 0) { delete[] buffer; return 1; } - - Fl_Native_File_Chooser fnfc; - fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); - fnfc.filter("PDF\t*.pdf\n"); - if (defaultfname && strlen(defaultfname) > 0) fnfc.preset_file(defaultfname); - fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); - if (fnfc.show() == 0) this->hPr = CreateDCA(NULL, pdf_printer_name_, NULL, pDevMode); - delete[] buffer; - if (!this->hPr) return 1; - DOCINFOW di; - wchar_t docName [256]; - wchar_t outName [256]; - fl_utf8towc("FLTK", 4, docName, 256); - fl_utf8towc(fnfc.filename(), (unsigned int)strlen(fnfc.filename()), outName, 256); - memset(&di, 0, sizeof(DOCINFOW)); - di.cbSize = sizeof(DOCINFOW); - di.lpszDocName = (LPCWSTR)docName; - di.lpszOutput = (LPCWSTR)outName; - err = StartDocW(this->hPr, &di); - if (err <= 0) { - DWORD dw = GetLastError(); - DeleteDC(this->hPr); - this->hPr = NULL; - if (dw != ERROR_CANCELLED) { - if (perr_message) { - int l = 40; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Error %lu in StartDoc() call", dw); - } - return 2; - } - return 1; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext(this->hPr); - driver()->gc(this->hPr); - doc_fname = fl_strdup(fnfc.filename()); - return 0; -} - - -int Fl_PDF_GDI_File_Surface::begin_document(const char* outfname, - enum Fl_Paged_Device::Page_Format format, - enum Fl_Paged_Device::Page_Layout layout, - char **perr_message) { - int err = 0; - abortPrint = FALSE; - - DEVMODEA inDevMode; - memset(&inDevMode, 0, sizeof(DEVMODEA)); inDevMode.dmSize = sizeof(DEVMODEA); - inDevMode.dmOrientation = (layout == PORTRAIT ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE); - inDevMode.dmPaperSize = (format == A4 ? DMPAPER_A4 : DMPAPER_LETTER); - inDevMode.dmFields = DM_ORIENTATION | DM_PAPERSIZE ; - - this->hPr = CreateDCA(NULL, pdf_printer_name_, NULL, &inDevMode); - if (!this->hPr) { - if (perr_message) { - int l = 150; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Class Fl_PDF_File_Surface requires printer '%s'.", - pdf_printer_name_); - } - return 2; - } - DOCINFOW di; - wchar_t docName[256]; - wchar_t outName[256]; - fl_utf8towc("FLTK", 4, docName, 256); - memset(&di, 0, sizeof(DOCINFOW)); - di.cbSize = sizeof(DOCINFOW); - di.lpszDocName = (LPCWSTR)docName; - di.lpszOutput = (LPCWSTR)outName; - fl_utf8towc(outfname, (unsigned int)strlen(outfname), outName, 256); - err = StartDocW(hPr, &di); - if (err <= 0) { - DWORD dw = GetLastError(); - DeleteDC(this->hPr); - this->hPr = NULL; - if (perr_message) { - int l = 50; - *perr_message = new char[l]; - snprintf(*perr_message, l, "Error %lu in StartDoc() call", dw); - } - return 2; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext(this->hPr); - driver()->gc(this->hPr); - doc_fname = fl_strdup(outfname); - return 0; -} - - -int Fl_WinAPI_Printer_Driver::begin_job (int pagecount, int *frompage, int *topage, char **perr_message) -// returns 0 iff OK -{ - if (pagecount == 0) pagecount = 10000; - DOCINFO di; - char docName [256]; - int err = 0; - - abortPrint = FALSE; - memset (&pd, 0, sizeof (PRINTDLG)); - pd.lStructSize = sizeof (PRINTDLG); - pd.hwndOwner = GetForegroundWindow(); - pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION; - pd.nMinPage = 1; - pd.nMaxPage = pagecount; - BOOL b = PrintDlg (&pd); - if (pd.hwndOwner) { // restore the correct state of mouse buttons and keyboard modifier keys (STR #3221) - WNDPROC windproc = (WNDPROC)GetWindowLongPtrW(pd.hwndOwner, GWLP_WNDPROC); - CallWindowProc(windproc, pd.hwndOwner, WM_ACTIVATEAPP, 1, 0); - } - if (b != 0) { - hPr = pd.hDC; - if (hPr != NULL) { - strcpy (docName, "FLTK"); - memset(&di, 0, sizeof(DOCINFO)); - di.cbSize = sizeof (DOCINFO); - di.lpszDocName = (LPCSTR) docName; - prerr = StartDoc (hPr, &di); - if (prerr < 1) { - abortPrint = TRUE; - DWORD dw = GetLastError(); - err = (dw == ERROR_CANCELLED ? 1 : 2); - if (perr_message && err == 2) { - wchar_t *lpMsgBuf; - DWORD retval = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR) &lpMsgBuf, - 0, NULL); - if (retval) { - unsigned srclen = lstrlenW(lpMsgBuf); - while (srclen > 0 && (lpMsgBuf[srclen-1] == '\n' || lpMsgBuf[srclen-1] == '\r')) srclen--; - unsigned l = fl_utf8fromwc(NULL, 0, lpMsgBuf, srclen); - *perr_message = new char[l+51]; - snprintf(*perr_message, l+51, "begin_job() failed with error %lu: ", dw); - fl_utf8fromwc(*perr_message + strlen(*perr_message), l+1, lpMsgBuf, srclen); - LocalFree(lpMsgBuf); - } - } - } - } - } else { - err = 1; - } - if(!err) { - if((pd.Flags & PD_PAGENUMS) != 0 ) { - if (frompage) *frompage = pd.nFromPage; - if (topage) *topage = pd.nToPage; - } - else { - if (frompage) *frompage = 1; - if (topage) *topage = pagecount; - } - x_offset = 0; - y_offset = 0; - WIN_SetupPrinterDeviceContext (hPr); - driver()->gc(hPr); - } - return err; -} - -void Fl_PDF_GDI_File_Surface::end_job(void) -{ - if (hPr != NULL) { - if (! abortPrint) { - if (EndDoc (hPr) <= 0) { - fl_message ("Error in EndDoc() call"); - } - DeleteDC (hPr); - } - hPr = NULL; - } -} - -void Fl_WinAPI_Printer_Driver::end_job (void) -{ - if (hPr != NULL) { - if (! abortPrint) { - prerr = EndDoc (hPr); - if (prerr < 0) { - fl_alert ("EndDoc error %d", prerr); - } - } - DeleteDC (hPr); - if (pd.hDevMode != NULL) { - GlobalFree (pd.hDevMode); - } - if (pd.hDevNames != NULL) { - GlobalFree (pd.hDevNames); - } - } - hPr = NULL; -} - -void Fl_WinAPI_Printer_Driver::absolute_printable_rect(int *x, int *y, int *w, int *h) -{ - POINT physPageSize; - POINT pixelsPerInch; - XFORM transform; - - if (hPr == NULL) return; - HDC gc = (HDC)driver()->gc(); - GetWorldTransform(gc, &transform); - ModifyWorldTransform(gc, NULL, MWT_IDENTITY); - SetWindowOrgEx(gc, 0, 0, NULL); - - physPageSize.x = GetDeviceCaps(hPr, HORZRES); - physPageSize.y = GetDeviceCaps(hPr, VERTRES); - DPtoLP(hPr, &physPageSize, 1); - *w = physPageSize.x + 1; - *h = physPageSize.y + 1; - pixelsPerInch.x = GetDeviceCaps(hPr, LOGPIXELSX); - pixelsPerInch.y = GetDeviceCaps(hPr, LOGPIXELSY); - DPtoLP(hPr, &pixelsPerInch, 1); - left_margin = (pixelsPerInch.x / 4); - *w -= (pixelsPerInch.x / 2); - top_margin = (pixelsPerInch.y / 4); - *h -= (pixelsPerInch.y / 2); - - *x = left_margin; - *y = top_margin; - origin(x_offset, y_offset); - SetWorldTransform(gc, &transform); -} - -void Fl_WinAPI_Printer_Driver::margins(int *left, int *top, int *right, int *bottom) -{ - int x = 0, y = 0, w = 0, h = 0; - absolute_printable_rect(&x, &y, &w, &h); - if (left) *left = x; - if (top) *top = y; - if (right) *right = x; - if (bottom) *bottom = y; -} - -int Fl_WinAPI_Printer_Driver::printable_rect(int *w, int *h) -{ - int x, y; - absolute_printable_rect(&x, &y, w, h); - return 0; -} - -int Fl_WinAPI_Printer_Driver::begin_page (void) -{ - int rsult, w, h; - - rsult = 0; - if (hPr != NULL) { - Fl_Surface_Device::push_current(this); - WIN_SetupPrinterDeviceContext (hPr); - prerr = StartPage (hPr); - if (prerr < 0) { - Fl_Surface_Device::pop_current(); - fl_alert ("StartPage error %d", prerr); - rsult = 1; - } - printable_rect(&w, &h); - origin(0, 0); - fl_clip_region(0); - } - return rsult; -} - -void Fl_WinAPI_Printer_Driver::origin (int deltax, int deltay) -{ - SetWindowOrgEx( (HDC)driver()->gc(), - left_margin - deltax, - top_margin - deltay, NULL); - x_offset = deltax; - y_offset = deltay; -} - -void Fl_WinAPI_Printer_Driver::scale (float scalex, float scaley) -{ - if (scaley == 0.) scaley = scalex; - int w, h; - SetWindowExtEx((HDC)driver()->gc(), (int)(720 / scalex + 0.5), (int)(720 / scaley + 0.5), NULL); - printable_rect(&w, &h); - origin(0, 0); -} - -void Fl_WinAPI_Printer_Driver::rotate (float rot_angle) -{ - XFORM mat; - float angle; - angle = (float) - (rot_angle * M_PI / 180.); - mat.eM11 = (float)cos(angle); - mat.eM12 = (float)sin(angle); - mat.eM21 = - mat.eM12; - mat.eM22 = mat.eM11; - mat.eDx = mat.eDy = 0; - SetWorldTransform((HDC)driver()->gc(), &mat); -} - -int Fl_WinAPI_Printer_Driver::end_page (void) -{ - int rsult; - - rsult = 0; - if (hPr != NULL) { - Fl_Surface_Device::pop_current(); - prerr = EndPage (hPr); - if (prerr < 0) { - abortPrint = TRUE; - fl_alert ("EndPage error %d", prerr); - rsult = 1; - } - else { // make sure rotation is not transferred to next page - ModifyWorldTransform(hPr, NULL, MWT_IDENTITY); - } - } - return rsult; -} - -static int translate_stack_depth = 0; -const int translate_stack_max = 5; -static int translate_stack_x[translate_stack_max]; -static int translate_stack_y[translate_stack_max]; - -static void do_translate(int x, int y, HDC gc) -{ - XFORM tr; - tr.eM11 = tr.eM22 = 1; - tr.eM12 = tr.eM21 = 0; - tr.eDx = (FLOAT) x; - tr.eDy = (FLOAT) y; - ModifyWorldTransform(gc, &tr, MWT_LEFTMULTIPLY); -} - -void Fl_WinAPI_Printer_Driver::translate (int x, int y) -{ - do_translate(x, y, (HDC)driver()->gc()); - if (translate_stack_depth < translate_stack_max) { - translate_stack_x[translate_stack_depth] = x; - translate_stack_y[translate_stack_depth] = y; - translate_stack_depth++; - } -} - -void Fl_WinAPI_Printer_Driver::untranslate (void) -{ - if (translate_stack_depth > 0) { - translate_stack_depth--; - do_translate( - translate_stack_x[translate_stack_depth], - translate_stack_y[translate_stack_depth], (HDC)driver()->gc() ); - } -} - -void Fl_WinAPI_Printer_Driver::origin(int *x, int *y) -{ - Fl_Paged_Device::origin(x, y); -} - - diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H deleted file mode 100644 index b038fc5f1..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ /dev/null @@ -1,104 +0,0 @@ -// -// Windows screen interface for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_Screen_Driver.H - \brief Definition of Windows screen interface. - */ - -#ifndef FL_WINAPI_SCREEN_DRIVER_H -#define FL_WINAPI_SCREEN_DRIVER_H - -#include "../../Fl_Screen_Driver.H" -#include <windows.h> - -class Fl_Window; - - -class Fl_WinAPI_Screen_Driver : public Fl_Screen_Driver -{ -protected: - RECT screens[MAX_SCREENS]; - RECT work_area[MAX_SCREENS]; - float scale_of_screen[MAX_SCREENS]; - - static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM); - BOOL screen_cb(HMONITOR mon, HDC, LPRECT r); - int get_mouse_unscaled(int &mx, int &my); - -public: - float dpi[MAX_SCREENS][2]; - enum APP_SCALING_CAPABILITY scaling_capability; - void update_scaling_capability(); - Fl_WinAPI_Screen_Driver(); - // --- display management - int visual(int flags) FL_OVERRIDE; - // --- screen configuration - void init() FL_OVERRIDE; - int x() FL_OVERRIDE; - int y() FL_OVERRIDE; - int w() FL_OVERRIDE; - int h() FL_OVERRIDE; - void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - void screen_xywh_unscaled(int &X, int &Y, int &W, int &H, int n); - void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE; - int screen_num_unscaled(int x, int y); - void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE; - // --- audible output - void beep(int type) FL_OVERRIDE; - // --- global events - void flush() FL_OVERRIDE; - void grab(Fl_Window* win) FL_OVERRIDE; - // --- global colors - void get_system_colors() FL_OVERRIDE; - int dnd(int unused) FL_OVERRIDE; - int compose(int &del) FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE; - Fl_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win); - int get_mouse(int &x, int &y) FL_OVERRIDE; - void enable_im() FL_OVERRIDE; - void disable_im() FL_OVERRIDE; - void open_display_platform() FL_OVERRIDE; - void offscreen_size(Fl_Offscreen off, int &width, int &height) FL_OVERRIDE; - APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { - return scaling_capability; - } - float scale(int n) FL_OVERRIDE { - return scale_of_screen[n]; - } - void scale(int n, float f) FL_OVERRIDE { - scale_of_screen[n] = f; - } - void desktop_scale_factor() FL_OVERRIDE; - void default_icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - int clipboard_contains(const char *type) FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void clipboard_notify_change() FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) FL_OVERRIDE; - // these two are implemented in Fl_get_key_win32.cxx - int event_key(int) FL_OVERRIDE; - int get_key(int) FL_OVERRIDE; - float base_scale(int numscreen) FL_OVERRIDE; -}; - - -#endif // FL_WINAPI_SCREEN_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx deleted file mode 100644 index b1ddc9f91..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ /dev/null @@ -1,493 +0,0 @@ -// -// Windows screen interface for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_WinAPI_Screen_Driver.H" -#include "../GDI/Fl_Font.H" -#include <FL/Fl.H> -#include <FL/platform.H> -#include <FL/Fl_RGB_Image.H> -#include <FL/fl_ask.H> -#include <stdio.h> - - -// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx -extern const char *fl_fg; -extern const char *fl_bg; -extern const char *fl_bg2; -// end of extern additions workaround - - -#if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500) -# define COMPILE_MULTIMON_STUBS -# include <multimon.h> -#endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500 - -static Fl_Text_Editor::Key_Binding extra_bindings[] = { - // Define Windows specific accelerators... - { 'y', FL_CTRL, Fl_Text_Editor::kf_redo ,0}, - { 0, 0, 0 ,0} -}; - - -Fl_WinAPI_Screen_Driver::Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { - text_editor_extra_key_bindings = extra_bindings; - for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1; - scaling_capability = SYSTEMWIDE_APP_SCALING; -} - -int Fl_WinAPI_Screen_Driver::visual(int flags) -{ - fl_GetDC(0); - if (flags & FL_DOUBLE) return 0; - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - if (!(flags & FL_INDEX) && - GetDeviceCaps(gc,BITSPIXEL) <= 8) return 0; - if ((flags & FL_RGB8) && GetDeviceCaps(gc,BITSPIXEL)<24) return 0; - return 1; -} - - -// We go the much more difficult route of individually picking some multi-screen -// functions from the USER32.DLL . If these functions are not available, we -// will gracefully fall back to single monitor support. -// -// If we were to insist on the existence of "EnumDisplayMonitors" and -// "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000 -// before SP2 or earlier. - -// BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM) -typedef BOOL(WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); -// BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO) -typedef BOOL(WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO); - -static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC hdc, LPRECT r, LPARAM d) -{ - Fl_WinAPI_Screen_Driver *drv = (Fl_WinAPI_Screen_Driver*)d; - return drv->screen_cb(mon, hdc, r); -} - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r) -{ - if (num_screens >= MAX_SCREENS) return TRUE; - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - - // GetMonitorInfo(mon, &mi); - // (but we use our self-acquired function pointer instead) - if (fl_gmi(mon, &mi)) { - screens[num_screens] = mi.rcMonitor; - // If we also want to record the work area, we would also store mi.rcWork at this point - work_area[num_screens] = mi.rcWork; - num_screens++; - } - return TRUE; -} - - -void Fl_WinAPI_Screen_Driver::init() -{ - open_display(); - // Since not all versions of Windows include multiple monitor support, - // we do a run-time check for the required functions... - HMODULE hMod = GetModuleHandle("USER32.DLL"); - - if (hMod) { - // check that EnumDisplayMonitors is available - fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors"); - - if (fl_edm) { - // we have EnumDisplayMonitors - do we also have GetMonitorInfoA ? - fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA"); - if (fl_gmi) { - // We have GetMonitorInfoA, enumerate all the screens... - // EnumDisplayMonitors(0,0,screen_cb,0); - // (but we use our self-acquired function pointer instead) - // NOTE: num_screens is incremented in screen_cb so we must first reset it here... - num_screens = 0; - fl_edm(0, 0, screen_cb, (LPARAM)this); - return; - } - } - } - - // If we get here, assume we have 1 monitor... - num_screens = 1; - screens[0].top = 0; - screens[0].left = 0; - screens[0].right = GetSystemMetrics(SM_CXSCREEN); - screens[0].bottom = GetSystemMetrics(SM_CYSCREEN); - work_area[0] = screens[0]; -} - - -void Fl_WinAPI_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - X = int(work_area[n].left/scale_of_screen[n]); - Y = int(work_area[n].top/scale_of_screen[n]); - W = int((work_area[n].right - work_area[n].left)/scale_of_screen[n]); - H = int((work_area[n].bottom - work_area[n].top)/scale_of_screen[n]); -} - - -void Fl_WinAPI_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - if (num_screens > 0) { - X = int(screens[n].left/scale_of_screen[n]); - Y = int(screens[n].top/scale_of_screen[n]); - W = int((screens[n].right - screens[n].left)/scale_of_screen[n]); - H = int((screens[n].bottom - screens[n].top)/scale_of_screen[n]); - } else { - /* Fallback if something is broken... */ - X = 0; - Y = 0; - W = GetSystemMetrics(SM_CXSCREEN); - H = GetSystemMetrics(SM_CYSCREEN); - } -} - - -void Fl_WinAPI_Screen_Driver::screen_xywh_unscaled(int &X, int &Y, int &W, int &H, int n) { - if (num_screens < 0) init(); - if ((n < 0) || (n >= num_screens)) n = 0; - X = screens[n].left; - Y = screens[n].top; - W = screens[n].right - screens[n].left; - H = screens[n].bottom - screens[n].top; -}; - - -void Fl_WinAPI_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - if (n >= 0 && n < num_screens) { - h = float(dpi[n][0]); - v = float(dpi[n][1]); - } -} - - -int Fl_WinAPI_Screen_Driver::x() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.left;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return X; -} - - -int Fl_WinAPI_Screen_Driver::y() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.top;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return Y; -} - - -int Fl_WinAPI_Screen_Driver::h() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.bottom - r.top;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return H; -} - - -int Fl_WinAPI_Screen_Driver::w() -{ - /*RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.right - r.left;*/ - int X, Y, W, H; - screen_work_area(X, Y, W, H, 0); - return W; -} - - -// Implements fl_beep(). See documentation in src/fl_ask.cxx. -void Fl_WinAPI_Screen_Driver::beep(int type) -{ - switch (type) { - case FL_BEEP_QUESTION : - case FL_BEEP_PASSWORD : - MessageBeep(MB_ICONQUESTION); - break; - case FL_BEEP_MESSAGE : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_NOTIFICATION : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_ERROR : - MessageBeep(MB_ICONERROR); - break; - default : - MessageBeep(0xFFFFFFFF); - break; - } -} - - -void Fl_WinAPI_Screen_Driver::flush() -{ - GdiFlush(); -} - - -extern void fl_fix_focus(); // in Fl.cxx - -// We have to keep track of whether we have captured the mouse, since -// Windows shows little respect for this... Grep for fl_capture to -// see where and how this is used. -extern HWND fl_capture; - - -void Fl_WinAPI_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab_) { - SetActiveWindow(fl_capture = fl_xid(Fl::first_window())); - SetCapture(fl_capture); - } - Fl::grab_ = win; - } else { - if (Fl::grab_) { - fl_capture = 0; - ReleaseCapture(); - Fl::grab_ = 0; - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -static void getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar)) -{ - if (arg) { - uchar r,g,b; - if (!fl_parse_color(arg, r,g,b)) - Fl::error("Unknown color: %s", arg); - else - func(r,g,b); - } else { - DWORD x = GetSysColor(what); - func(uchar(x&255), uchar(x>>8), uchar(x>>16)); - } -} - - -void Fl_WinAPI_Screen_Driver::get_system_colors() -{ - if (!bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2); - if (!fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground); - if (!bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background); - getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color); -} - - -int Fl_WinAPI_Screen_Driver::compose(int &del) { - unsigned char ascii = (unsigned char)Fl::e_text[0]; - /* WARNING: The [AltGr] key on international keyboards sets FL_CTRL. - 2nd line in condition below asks [AltGr] key (a.k.a. VK_RMENU) not to be down. - */ - int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && !(ascii & 128) && - !( (Fl::e_state & FL_CTRL) && (GetAsyncKeyState(VK_RMENU) >> 15) ); - if (condition) { // this stuff is to be treated as a function key - del = 0; - return 0; - } - del = Fl::compose_state; - Fl::compose_state = 0; - // Only insert non-control characters: - if ( (!Fl::compose_state) && ! (ascii & ~31 && ascii!=127)) { - return 0; - } - return 1; -} - - -Fl_RGB_Image * // O - image or NULL if failed -Fl_WinAPI_Screen_Driver::read_win_rectangle( - int X, // I - Left position - int Y, // I - Top position - int w, // I - Width of area to read - int h, // I - Height of area to read - Fl_Window *win, // I - window to capture from or NULL to capture from current offscreen - bool may_capture_subwins, bool *did_capture_subwins) -{ - float s = Fl_Surface_Device::surface()->driver()->scale(); - int ws, hs; - if (int(s) == s) { ws = w * int(s); hs = h * int(s);} - else { - ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Fl_Scalable_Graphics_Driver::floor(X, s), - hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Fl_Scalable_Graphics_Driver::floor(Y, s); - if (ws < 1) ws = 1; - if (hs < 1) hs = 1; - } - return read_win_rectangle_unscaled(Fl_Scalable_Graphics_Driver::floor(X, s), Fl_Scalable_Graphics_Driver::floor(Y, s), ws, hs, win); -} - -Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win) -{ - // Depth of image is always 3 here - - // Grab all of the pixels in the image... - - // Assure that we are not trying to read non-existing data. If it is so, the - // function should still work, but the out-of-bounds part of the image is - // untouched (initialized with the alpha value or 0 (black), resp.). - - int ww = w; // We need the original width for output data line size - - int shift_x = 0; // X target shift if X modified - int shift_y = 0; // Y target shift if X modified - - if (X < 0) { - shift_x = -X; - w += X; - X = 0; - } - if (Y < 0) { - shift_y = -Y; - h += Y; - Y = 0; - } - - if (h < 1 || w < 1) return 0; // nothing to copy - - // Allocate and initialize the image data array - size_t arraySize = ((size_t)w * h) * 3; - uchar *p = new uchar[arraySize]; - memset(p, 0, arraySize); - - int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes) - uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB - - // fill in bitmap info for GetDIBits - - BITMAPINFO bi; - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = w; - bi.bmiHeader.biHeight = -h; // negative => top-down DIB - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 24; // 24 bits RGB - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = 0; - bi.bmiHeader.biXPelsPerMeter = 0; - bi.bmiHeader.biYPelsPerMeter = 0; - bi.bmiHeader.biClrUsed = 0; - bi.bmiHeader.biClrImportant = 0; - - // copy bitmap from original DC (Window, Fl_Offscreen, ...) - if (win && Fl_Window::current() != win) win->make_current(); - HDC gc = (HDC)fl_graphics_driver->gc(); - HDC hdc = CreateCompatibleDC(gc); - HBITMAP hbm = CreateCompatibleBitmap(gc,w,h); - - int save_dc = SaveDC(hdc); // save context for cleanup - SelectObject(hdc,hbm); // select bitmap - BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB - - // copy RGB image data to the allocated DIB - - GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS); - - // finally copy the image data to the user buffer - - for (int j = 0; j<h; j++) { - const uchar *src = dib + j * line_size; // source line - uchar *tg = p + (j + shift_y) * 3 * ww + shift_x * 3; // target line - for (int i = 0; i<w; i++) { - uchar b = *src++; - uchar g = *src++; - *tg++ = *src++; // R - *tg++ = g; // G - *tg++ = b; // B - } - } - - // free used GDI and other structures - - RestoreDC(hdc,save_dc); // reset DC - DeleteDC(hdc); - DeleteObject(hbm); - delete[] dib; // delete DIB temporary buffer - - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, 3); - rgb->alloc_array = 1; - return rgb; -} - - -void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) -{ - BITMAP bitmap; - if ( GetObject((HBITMAP)off, sizeof(BITMAP), &bitmap) ) { - width = bitmap.bmWidth; - height = bitmap.bmHeight; - } -} - -//NOTICE: returns -1 if x,y is not in any screen -int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y) -{ - int screen = -1; - if (num_screens < 0) init(); - for (int i = 0; i < num_screens; i ++) { - if (x >= screens[i].left && x < screens[i].right && - y >= screens[i].top && y < screens[i].bottom) { - screen = i; - break; - } - } - return screen; -} - - -float Fl_WinAPI_Screen_Driver::base_scale(int numscreen) { - return float(dpi[numscreen][0] / 96.); -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H deleted file mode 100644 index 016cad9fa..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H +++ /dev/null @@ -1,124 +0,0 @@ -// -// Windows system driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_System_Driver.H - \brief Definition of Windows system driver. - */ - -#ifndef FL_WINAPI_SYSTEM_DRIVER_H -#define FL_WINAPI_SYSTEM_DRIVER_H - -#include "../../Fl_System_Driver.H" -#include <stdarg.h> -#include <string.h> // strdup - -/* - Move everything here that manages the system interface. - - There is exactly one system driver. - - - filename and pathname management - - directory and file access - - system time and system timer - - multithreading - - string management - */ - -class Fl_WinAPI_System_Driver : public Fl_System_Driver -{ -public: - void warning(const char *format, va_list args) FL_OVERRIDE; - void error(const char *format, va_list args) FL_OVERRIDE; - void fatal(const char *format, va_list args) FL_OVERRIDE; - char *utf2mbcs(const char *s) FL_OVERRIDE; - char *getenv(const char *var) FL_OVERRIDE; - int putenv(const char *var) FL_OVERRIDE; - int open(const char *fnam, int oflags, int pmode) FL_OVERRIDE; - int open_ext(const char *fnam, int binary, int oflags, int pmode) FL_OVERRIDE; - FILE *fopen(const char *fnam, const char *mode) FL_OVERRIDE; - int system(const char *cmd) FL_OVERRIDE; - int execvp(const char *file, char *const *argv) FL_OVERRIDE; - int chmod(const char *fnam, int mode) FL_OVERRIDE; - int access(const char *fnam, int mode) FL_OVERRIDE; - int flstat(const char *fnam, struct stat *b) FL_OVERRIDE; - char *getcwd(char *b, int l) FL_OVERRIDE; - int chdir(const char *path) FL_OVERRIDE; - int unlink(const char *fnam) FL_OVERRIDE; - int mkdir(const char *fnam, int mode) FL_OVERRIDE; - int rmdir(const char *fnam) FL_OVERRIDE; - int rename(const char *fnam, const char *newnam) FL_OVERRIDE; - // Windows commandline argument conversion to UTF-8 - int args_to_utf8(int argc, char ** &argv) FL_OVERRIDE; - // Windows specific UTF-8 conversions - unsigned utf8towc(const char *src, unsigned srclen, wchar_t* dst, unsigned dstlen) FL_OVERRIDE; - unsigned utf8fromwc(char *dst, unsigned dstlen, const wchar_t* src, unsigned srclen) FL_OVERRIDE; - int utf8locale() FL_OVERRIDE; - unsigned utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen) FL_OVERRIDE; - unsigned utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen) FL_OVERRIDE; - - int clocale_vprintf(FILE *output, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) FL_OVERRIDE; - int clocale_vsscanf(const char *input, const char *format, va_list args) FL_OVERRIDE; - int filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - int filename_expand(char *to,int tolen, const char *from) FL_OVERRIDE; - int filename_relative(char *to, int tolen, const char *from, const char *base) FL_OVERRIDE; - int filename_absolute(char *to, int tolen, const char *from, const char *base) FL_OVERRIDE; - int filename_isdir(const char *n) FL_OVERRIDE; - int filename_isdir_quick(const char *n) FL_OVERRIDE; - const char *filename_ext(const char *buf) FL_OVERRIDE; - int open_uri(const char *uri, char *msg, int msglen) FL_OVERRIDE; - int use_recent_tooltip_fix() FL_OVERRIDE {return 1;} - int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) FL_OVERRIDE; - int file_browser_load_directory(const char *directory, char *filename, size_t name_size, - dirent ***pfiles, Fl_File_Sort_F *sort, - char *errmsg=NULL, int errmsg_sz=0) FL_OVERRIDE; - void newUUID(char *uuidBuffer) FL_OVERRIDE; - char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor, - const char *application) FL_OVERRIDE; - void *load(const char *filename) FL_OVERRIDE; - void png_extra_rgba_processing(unsigned char *array, int w, int h) FL_OVERRIDE; - const char *next_dir_sep(const char *start) FL_OVERRIDE; - // these 3 are implemented in Fl_lock.cxx - void awake(void*) FL_OVERRIDE; - int lock() FL_OVERRIDE; - void unlock() FL_OVERRIDE; - // this one is implemented in Fl_win32.cxx - void* thread_message() FL_OVERRIDE; - int file_type(const char *filename) FL_OVERRIDE; - const char *home_directory_name() FL_OVERRIDE; - const char *filesystems_label() FL_OVERRIDE { return "My Computer"; } - int backslash_as_slash() FL_OVERRIDE {return 1;} - int colon_is_drive() FL_OVERRIDE {return 1;} - int case_insensitive_filenames() FL_OVERRIDE {return 1;} - // this one is implemented in Fl_win32.cxx - const char *filename_name(const char *buf) FL_OVERRIDE; - void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void add_fd(int fd, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; - void remove_fd(int, int when) FL_OVERRIDE; - void remove_fd(int) FL_OVERRIDE; - void gettime(time_t *sec, int *usec) FL_OVERRIDE; - char* strdup(const char *s) FL_OVERRIDE { return ::_strdup(s); } - void lock_ring() FL_OVERRIDE; - void unlock_ring() FL_OVERRIDE; - double wait(double time_to_wait) FL_OVERRIDE; - int ready() FL_OVERRIDE; - int close_fd(int fd) FL_OVERRIDE; -}; - -#endif // FL_WINAPI_SYSTEM_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx deleted file mode 100644 index 9eab455df..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx +++ /dev/null @@ -1,1134 +0,0 @@ -// -// Definition of Windows system driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include <config.h> -#include <FL/platform.H> -#include "Fl_WinAPI_System_Driver.H" -#include <FL/Fl.H> -#include <FL/fl_utf8.h> -#include <FL/filename.H> -#include <FL/Fl_File_Browser.H> -#include <FL/Fl_File_Icon.H> -#include "../../flstring.h" -#include <stdio.h> -#include <stdarg.h> -#include <windows.h> -#include <rpc.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/timeb.h> -#include <shellapi.h> -#include <wchar.h> -#include <process.h> -#include <locale.h> -#include <time.h> -#include <direct.h> -#include <io.h> -#include <fcntl.h> -#include <string> - -// We must define _WIN32_IE at least to 0x0500 before inclusion of 'shlobj.h' to enable -// the declaration of SHGFP_TYPE_CURRENT for some older versions of MinGW, notably -// header versions 5.3.0 and earlier, whereas 5.4.2 seems to define _WIN32_IE as needed. -#if !(defined _WIN32_IE) || (_WIN32_IE < 0x0500) -# undef _WIN32_IE -# define _WIN32_IE 0x0500 -#endif /* _WIN32_WINNT checks */ - -#include <shlobj.h> - -// function pointer for the UuidCreate Function -// RPC_STATUS RPC_ENTRY UuidCreate(UUID __RPC_FAR *Uuid); -typedef RPC_STATUS (WINAPI *uuid_func)(UUID __RPC_FAR *Uuid); - -// Apparently Borland C++ defines DIRECTORY in <direct.h>, which -// interferes with the Fl_File_Icon enumeration of the same name. -# ifdef DIRECTORY -# undef DIRECTORY -# endif // DIRECTORY - -#ifdef __CYGWIN__ -# include <mntent.h> -#endif - -// Optional helper function to debug Fl_WinAPI_System_Driver::home_directory_name() -#ifndef DEBUG_HOME_DIRECTORY_NAME -#define DEBUG_HOME_DIRECTORY_NAME 0 -#endif -#if DEBUG_HOME_DIRECTORY_NAME -static void print_env(const char *ev) { - const char *val = getenv(ev); - printf("%-30.30s = \"%s\"\n", ev, val ? val : "<null>"); - fflush(stdout); -} -#endif // DEBUG_HOME_DIRECTORY_NAME - -static inline int isdirsep(char c) { return c == '/' || c == '\\'; } - -static wchar_t *mbwbuf = NULL; -static wchar_t *wbuf = NULL; -static wchar_t *wbuf1 = NULL; - -extern "C" { - int fl_scandir(const char *dirname, struct dirent ***namelist, - int (*select)(struct dirent *), - int (*compar)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_len); -} - -/* - Convert UTF-8 string to Windows wide character encoding (UTF-16). - - This helper function is used throughout this file to convert UTF-8 - strings to Windows specific UTF-16 encoding for filenames, paths, or - other strings to be used by system functions. - - The input string can be a null-terminated string or its length can be - provided by the optional argument 'lg'. If 'lg' is omitted or less than 0 - (default = -1) the string length is determined with strlen(), otherwise - 'lg' takes precedence. Zero (0) is a valid string length (an empty string). - - The argument 'wbuf' must have been initialized with NULL or a previous - call to malloc() or realloc(). - - If the converted string doesn't fit into the allocated size of 'wbuf' or if - 'wbuf' is NULL a new buffer is allocated with realloc(). Hence the pointer - 'wbuf' can be shared among multiple calls to this function if it has been - initialized with NULL (or malloc or realloc) before the first call. - - The return value is either the old value of 'wbuf' (if the string fits) - or a pointer to the (re)allocated buffer. - - Pseudo doxygen docs (static function intentionally not documented): - - param[in] utf8 input string (UTF-8) - param[in,out] wbuf in: pointer to output string buffer or NULL - out: new string (the pointer may be changed) - param[in] lg optional: input string length (default = -1) - - returns pointer to string buffer -*/ -static wchar_t *utf8_to_wchar(const char *utf8, wchar_t *&wbuf, int lg = -1) { - unsigned len = (lg >= 0) ? (unsigned)lg : (unsigned)strlen(utf8); - unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 1; // Query length - wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * wn); - wn = fl_utf8toUtf16(utf8, len, (unsigned short *)wbuf, wn); // Convert string - wbuf[wn] = 0; - return wbuf; -} - -/* - Convert a Windows wide character (UTF-16) string to UTF-8 encoding. - - This helper function is used throughout this file to convert Windows - wide character strings as returned by system functions to UTF-8 - encoding for internal usage. - - The argument 'utf8' must have been initialized with NULL or a previous - call to malloc() or realloc(). - - If the converted string doesn't fit into the allocated size of 'utf8' or if - 'utf8' is NULL a new buffer is allocated with realloc(). Hence the pointer - 'utf8' can be shared among multiple calls to this function if it has been - initialized with NULL (or malloc or realloc) before the first call. - Ideally every call to this function has its own static pointer though. - - The return value is either the old value of 'utf8' (if the string fits) - or a pointer at the (re)allocated buffer. - - Pseudo doxygen docs (static function intentionally not documented): - - param[in] wstr input string (wide character, UTF-16) - param[in,out] utf8 in: pointer to output string buffer - out: new string (pointer may be changed) - - returns pointer to string buffer -*/ -static char *wchar_to_utf8(const wchar_t *wstr, char *&utf8) { - unsigned len = (unsigned)wcslen(wstr); - unsigned wn = fl_utf8fromwc(NULL, 0, wstr, len) + 1; // query length - utf8 = (char *)realloc(utf8, wn); - wn = fl_utf8fromwc(utf8, wn, wstr, len); // convert string - utf8[wn] = 0; - return utf8; -} - -void Fl_WinAPI_System_Driver::warning(const char *format, va_list args) { - // Show nothing for warnings under Windows... -} - -void Fl_WinAPI_System_Driver::error(const char *format, va_list args) { - char buf[1024]; - vsnprintf(buf, 1024, format, args); - MessageBox(0, buf, "Error", MB_ICONEXCLAMATION | MB_SYSTEMMODAL); -} - -void Fl_WinAPI_System_Driver::fatal(const char *format, va_list args) { - char buf[1024]; - vsnprintf(buf, 1024, format, args); - MessageBox(0, buf, "Error", MB_ICONSTOP | MB_SYSTEMMODAL); - ::exit(1); -} - -char *Fl_WinAPI_System_Driver::utf2mbcs(const char *utf8) { - static char *buf = NULL; - if (!utf8) return NULL; - - unsigned len = (unsigned)strlen(utf8); - - unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 7; // Query length - mbwbuf = (wchar_t *)realloc(mbwbuf, sizeof(wchar_t) * wn); - len = fl_utf8toUtf16(utf8, len, (unsigned short *)mbwbuf, wn); // Convert string - mbwbuf[len] = 0; - - buf = (char*)realloc(buf, len * 6 + 2); - len = (unsigned)wcstombs(buf, mbwbuf, len * 6); - buf[len] = 0; - buf[len+1] = 0; // in case the result is a UTF-16 string - return buf; -} - -char *Fl_WinAPI_System_Driver::getenv(const char *var) { - static char *buf = NULL; - wchar_t *ret = _wgetenv(utf8_to_wchar(var, wbuf)); - if (!ret) return NULL; - return wchar_to_utf8(ret, buf); -} - -int Fl_WinAPI_System_Driver::putenv(const char *var) { - unsigned len = (unsigned)strlen(var); - unsigned wn = fl_utf8toUtf16(var, len, NULL, 0) + 1; // Query length - wchar_t *wbuf = (wchar_t *)malloc(sizeof(wchar_t) * wn); - wn = fl_utf8toUtf16(var, len, (unsigned short *)wbuf, wn); - wbuf[wn] = 0; - int ret = _wputenv(wbuf); - free(wbuf); - return ret; -} - -int Fl_WinAPI_System_Driver::open(const char *fnam, int oflags, int pmode) { - utf8_to_wchar(fnam, wbuf); - if (pmode == -1) return _wopen(wbuf, oflags); - else return _wopen(wbuf, oflags, pmode); -} - -int Fl_WinAPI_System_Driver::open_ext(const char *fnam, int binary, int oflags, int pmode) { - if (oflags == 0) oflags = _O_RDONLY; - oflags |= (binary ? _O_BINARY : _O_TEXT); - return this->open(fnam, oflags, pmode); -} - -FILE *Fl_WinAPI_System_Driver::fopen(const char *fnam, const char *mode) { - utf8_to_wchar(fnam, wbuf); - utf8_to_wchar(mode, wbuf1); - return _wfopen(wbuf, wbuf1); -} - -int Fl_WinAPI_System_Driver::system(const char *cmd) { - return _wsystem(utf8_to_wchar(cmd, wbuf)); -} - -int Fl_WinAPI_System_Driver::execvp(const char *file, char *const *argv) { - int n = 0; - while (argv[n]) n++; // count args - wchar_t **ar = (wchar_t **)calloc(sizeof(wchar_t *), n + 1); - // convert arguments first; trailing NULL provided by calloc() - for (int i = 0; i < n; i++) - ar[i] = utf8_to_wchar(argv[i], ar[i]); // alloc and assign - // convert executable file and execute it ... - utf8_to_wchar(file, wbuf); - _wexecvp(wbuf, ar); // STR #3040 - // clean up (reached only if _wexecvp() failed) - for (int i = 0; i < n; i++) - free(ar[i]); - free(ar); - return -1; // STR #3040 -} - -int Fl_WinAPI_System_Driver::chmod(const char *fnam, int mode) { - return _wchmod(utf8_to_wchar(fnam, wbuf), mode); -} - -int Fl_WinAPI_System_Driver::access(const char *fnam, int mode) { - return _waccess(utf8_to_wchar(fnam, wbuf), mode); -} - -int Fl_WinAPI_System_Driver::flstat(const char *fnam, struct stat *b) { - - // remove trailing '/' or '\' - unsigned len = (unsigned)strlen(fnam); - if (len > 0 && (fnam[len-1] == '/' || fnam[len-1] == '\\')) - len--; - // convert filename and execute _wstat() - return _wstat(utf8_to_wchar(fnam, wbuf, len), (struct _stat *)b); -} - -char *Fl_WinAPI_System_Driver::getcwd(char *buf, int len) { - - static wchar_t *wbuf = NULL; - wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * (len + 1)); - wchar_t *ret = _wgetcwd(wbuf, len); - if (!ret) return NULL; - - unsigned dstlen = (unsigned)len; - len = (int)wcslen(wbuf); - dstlen = fl_utf8fromwc(buf, dstlen, wbuf, (unsigned)len); - buf[dstlen] = 0; - return buf; -} - -int Fl_WinAPI_System_Driver::chdir(const char *path) { - return _wchdir(utf8_to_wchar(path, wbuf)); -} - -int Fl_WinAPI_System_Driver::unlink(const char *fnam) { - return _wunlink(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::mkdir(const char *fnam, int mode) { - return _wmkdir(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::rmdir(const char *fnam) { - return _wrmdir(utf8_to_wchar(fnam, wbuf)); -} - -int Fl_WinAPI_System_Driver::rename(const char *fnam, const char *newnam) { - utf8_to_wchar(fnam, wbuf); - utf8_to_wchar(newnam, wbuf1); - return _wrename(wbuf, wbuf1); -} - -// See Fl::args_to_utf8() -int Fl_WinAPI_System_Driver::args_to_utf8(int argc, char ** &argv) { - int i; - - // Convert the command line arguments to UTF-8 - LPWSTR *wideArgv = CommandLineToArgvW(GetCommandLineW(), &argc); - argv = (char **)malloc((argc + 1) * sizeof(char *)); - for (i = 0; i < argc; i++) { - // find the required size of the buffer - int u8size = WideCharToMultiByte(CP_UTF8, // CodePage - 0, // dwFlags - wideArgv[i], // lpWideCharStr - -1, // cchWideChar - NULL, // lpMultiByteStr - 0, // cbMultiByte - NULL, // lpDefaultChar - NULL); // lpUsedDefaultChar - if (u8size > 0) { - char *strbuf = (char*)::malloc(u8size); - int ret = WideCharToMultiByte(CP_UTF8, // CodePage - 0, // dwFlags - wideArgv[i], // lpWideCharStr - -1, // cchWideChar - strbuf, // lpMultiByteStr - u8size, // cbMultiByte - NULL, // lpDefaultChar - NULL); // lpUsedDefaultChar - - if (ret) { - argv[i] = strbuf; - } else { - argv[i] = _strdup(""); - ::free(strbuf); - } - } else { - argv[i] = _strdup(""); - } - } - argv[argc] = NULL; // required NULL pointer at end of list - - // Free the wide character string array - LocalFree(wideArgv); - - // Note: the allocated memory or argv[] will not be free'd by the system - // on exit. This does not constitute a memory leak. - - return argc; -} - - -// Two Windows-specific functions fl_utf8_to_locale() and fl_locale_to_utf8() -// from file fl_utf8.cxx are put here for API compatibility - -static char *buf = NULL; -static int buf_len = 0; -static unsigned short *wbufa = NULL; -unsigned int fl_codepage = 0; - - -// FIXME: This should *maybe* return 'const char *' instead of 'char *' -char *fl_utf8_to_locale(const char *s, int len, UINT codepage) -{ - if (!s) return (char *)""; - int l = 0; - unsigned wn = fl_utf8toUtf16(s, len, NULL, 0); // Query length - wn = wn * 2 + 1; - if (wn >= (unsigned)buf_len) { - buf_len = wn; - buf = (char*) realloc(buf, buf_len); - wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short)); - } - if (codepage < 1) codepage = fl_codepage; - l = fl_utf8toUtf16(s, len, wbufa, wn); // Convert string - wbufa[l] = 0; - buf[l] = 0; - l = WideCharToMultiByte(codepage, 0, (WCHAR*)wbufa, l, buf, buf_len, NULL, NULL); - if (l < 0) l = 0; - buf[l] = 0; - return buf; -} - -// FIXME: This should maybe return 'const char *' instead of 'char *' -char *fl_locale_to_utf8(const char *s, int len, UINT codepage) -{ - if (!s) return (char *)""; - int l = 0; - if (buf_len < len * 5 + 1) { - buf_len = len * 5 + 1; - buf = (char*) realloc(buf, buf_len); - wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short)); - } - if (codepage < 1) codepage = fl_codepage; - buf[l] = 0; - - l = MultiByteToWideChar(codepage, 0, s, len, (WCHAR*)wbufa, buf_len); - if (l < 0) l = 0; - wbufa[l] = 0; - l = fl_utf8fromwc(buf, buf_len, (wchar_t*)wbufa, l); - buf[l] = 0; - return buf; -} - -/////////////////////////////////// - -unsigned Fl_WinAPI_System_Driver::utf8towc(const char *src, unsigned srclen, wchar_t *dst, unsigned dstlen) { - return fl_utf8toUtf16(src, srclen, (unsigned short*)dst, dstlen); -} - -unsigned Fl_WinAPI_System_Driver::utf8fromwc(char *dst, unsigned dstlen, const wchar_t *src, unsigned srclen) { - unsigned i = 0; - unsigned count = 0; - if (dstlen) for (;;) { - unsigned ucs; - if (i >= srclen) { - dst[count] = 0; - return count; - } - ucs = src[i++]; - if (ucs < 0x80U) { - dst[count++] = ucs; - if (count >= dstlen) {dst[count-1] = 0; break;} - } else if (ucs < 0x800U) { /* 2 bytes */ - if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;} - dst[count++] = 0xc0 | (ucs >> 6); - dst[count++] = 0x80 | (ucs & 0x3F); - } else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen && - src[i] >= 0xdc00 && src[i] <= 0xdfff) { - /* surrogate pair */ - unsigned ucs2 = src[i++]; - ucs = 0x10000U + ((ucs&0x3ff)<<10) + (ucs2&0x3ff); - /* all surrogate pairs turn into 4-byte UTF-8 */ - if (count+4 >= dstlen) {dst[count] = 0; count += 4; break;} - dst[count++] = 0xf0 | (ucs >> 18); - dst[count++] = 0x80 | ((ucs >> 12) & 0x3F); - dst[count++] = 0x80 | ((ucs >> 6) & 0x3F); - dst[count++] = 0x80 | (ucs & 0x3F); - } else { - /* all others are 3 bytes: */ - if (count+3 >= dstlen) {dst[count] = 0; count += 3; break;} - dst[count++] = 0xe0 | (ucs >> 12); - dst[count++] = 0x80 | ((ucs >> 6) & 0x3F); - dst[count++] = 0x80 | (ucs & 0x3F); - } - } - /* we filled dst, measure the rest: */ - while (i < srclen) { - unsigned ucs = src[i++]; - if (ucs < 0x80U) { - count++; - } else if (ucs < 0x800U) { /* 2 bytes */ - count += 2; - } else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen-1 && - src[i+1] >= 0xdc00 && src[i+1] <= 0xdfff) { - /* surrogate pair */ - ++i; - count += 4; - } else { - count += 3; - } - } - return count; -} - -int Fl_WinAPI_System_Driver::utf8locale() -{ - static int ret = (GetACP() == CP_UTF8); - return ret; -} - -unsigned Fl_WinAPI_System_Driver::utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen) { - wchar_t lbuf[1024]; - wchar_t *buf = lbuf; - unsigned length = fl_utf8towc(src, srclen, buf, 1024); - unsigned ret; - if (length >= 1024) { - buf = (wchar_t*)(malloc((length+1)*sizeof(wchar_t))); - fl_utf8towc(src, srclen, buf, length+1); - } - if (dstlen) { - // apparently this does not null-terminate, even though msdn documentation claims it does: - ret = - WideCharToMultiByte(GetACP(), 0, buf, length, dst, dstlen, 0, 0); - dst[ret] = 0; - } - // if it overflows or measuring length, get the actual length: - if (dstlen==0 || ret >= dstlen-1) - ret = WideCharToMultiByte(GetACP(), 0, buf, length, 0, 0, 0, 0); - if (buf != lbuf) free(buf); - return ret; -} - -unsigned Fl_WinAPI_System_Driver::utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen) { - wchar_t lbuf[1024]; - wchar_t *buf = lbuf; - unsigned length; - unsigned ret; - length = MultiByteToWideChar(GetACP(), 0, src, srclen, buf, 1024); - if ((length == 0)&&(GetLastError()==ERROR_INSUFFICIENT_BUFFER)) { - length = MultiByteToWideChar(GetACP(), 0, src, srclen, 0, 0); - buf = (wchar_t*)(malloc(length*sizeof(wchar_t))); - MultiByteToWideChar(GetACP(), 0, src, srclen, buf, length); - } - ret = fl_utf8fromwc(dst, dstlen, buf, length); - if (buf != lbuf) free((void*)buf); - return ret; -} - -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) -static _locale_t c_locale = NULL; -#endif - -int Fl_WinAPI_System_Driver::clocale_vprintf(FILE *output, const char *format, va_list args) { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) - if (!c_locale) - c_locale = _create_locale(LC_NUMERIC, "C"); - int retval = _vfprintf_l(output, format, c_locale, args); -#else - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vfprintf(output, format, args); - setlocale(LC_NUMERIC, saved_locale); -#endif - return retval; -} - -int Fl_WinAPI_System_Driver::clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/) - if (!c_locale) - c_locale = _create_locale(LC_NUMERIC, "C"); - int retval = _vsnprintf_l(output, output_size, format, c_locale, args); -#else - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vsnprintf(output, output_size, format, args); - setlocale(LC_NUMERIC, saved_locale); -#endif - return retval; -} - -int Fl_WinAPI_System_Driver::clocale_vsscanf(const char *input, const char *format, va_list args) { - char *saved_locale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - int retval = vsscanf(input, format, args); - setlocale(LC_NUMERIC, saved_locale); - return retval; -} - - -int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list, - int (*sort)(struct dirent **, struct dirent **), - char *errmsg, int errmsg_sz) { - // For Windows we have a special scandir implementation that uses - // the Win32 "wide" functions for lookup, avoiding the code page mess - // entirely. It also fixes up the trailing '/'. - return fl_scandir(d, list, 0, sort, errmsg, errmsg_sz); -} - -int Fl_WinAPI_System_Driver::filename_expand(char *to, int tolen, const char *from) { - char *temp = new char[tolen]; - strlcpy(temp,from, tolen); - char *start = temp; - char *end = temp+strlen(temp); - int ret = 0; - for (char *a=temp; a<end; ) { // for each slash component - char *e; for (e=a; e<end && !isdirsep(*e); e++) {/*empty*/} // find next slash - const char *value = 0; // this will point at substitute value - switch (*a) { - case '~': // a home directory name - if (e <= a+1) { // current user's directory - value = home_directory_name(); - } - break; - case '$': /* an environment variable */ - {char t = *e; *(char *)e = 0; value = getenv(a+1); *(char *)e = t;} - break; - } - if (value) { - // substitutions that start with slash delete everything before them: - if (isdirsep(value[0])) start = a; - // also if it starts with "A:" - if (value[0] && value[1]==':') start = a; - int t = (int) strlen(value); if (isdirsep(value[t-1])) t--; - if ((end+1-e+t) >= tolen) end += tolen - (end+1-e+t); - memmove(a+t, e, end+1-e); - end = a+t+(end-e); - *end = '\0'; - memcpy(a, value, t); - ret++; - } else { - a = e+1; - if (*e == '\\') {*e = '/'; ret++;} // ha ha! - } - } - strlcpy(to, start, tolen); - delete[] temp; - return ret; -} - -int // O - 0 if no change, 1 if changed -Fl_WinAPI_System_Driver::filename_relative(char *to, // O - Relative filename - int tolen, // I - Size of "to" buffer - const char *dest_dir, // I - Absolute filename - const char *base_dir) // I - Find path relative to this path -{ - // Find the relative path from base_dir to dest_dir. - // Both paths must be absolute and well formed (contain no /../ and /./ segments). - - // return if any of the pointers is NULL - if (!to || !dest_dir || !base_dir) { - return 0; - } - - // if there is a drive letter, make sure both paths use the same drive - if ( (unsigned)base_dir[0] < 128 && isalpha(base_dir[0]) && base_dir[1] == ':' - && (unsigned)dest_dir[0] < 128 && isalpha(dest_dir[0]) && dest_dir[1] == ':') { - if (tolower(base_dir[0]) != tolower(dest_dir[0])) { - strlcpy(to, dest_dir, tolen); - return 0; - } - // same drive, so skip to the start of the path - base_dir += 2; - dest_dir += 2; - } - - // return if `base_dir` or `dest_dir` is not an absolute path - if (!isdirsep(*base_dir) || !isdirsep(*dest_dir)) { - strlcpy(to, dest_dir, tolen); - return 0; - } - - const char *base_i = base_dir; // iterator through the base directory string - const char *base_s = base_dir; // pointer to the last dir separator found - const char *dest_i = dest_dir; // iterator through the destination directory - const char *dest_s = dest_dir; // pointer to the last dir separator found - - // compare both path names until we find a difference - for (;;) { -#if 0 // case sensitive - base_i++; - dest_i++; - char b = *base_i, d = *dest_i; -#else // case insensitive - base_i += fl_utf8len1(*base_i); - int b = fl_tolower(fl_utf8decode(base_i, NULL, NULL)); - dest_i += fl_utf8len1(*dest_i); - int d = fl_tolower(fl_utf8decode(dest_i, NULL, NULL)); -#endif - int b0 = (b == 0) || (isdirsep(b)); - int d0 = (d == 0) || (isdirsep(d)); - if (b0 && d0) { - base_s = base_i; - dest_s = dest_i; - } - if (b == 0 || d == 0) - break; - if (b != d) - break; - } - // base_s and dest_s point at the last separator we found - // base_i and dest_i point at the first character that differs - - // test for the exact same string and return "." if so - if ( (base_i[0] == 0 || (isdirsep(base_i[0]) && base_i[1] == 0)) - && (dest_i[0] == 0 || (isdirsep(dest_i[0]) && dest_i[1] == 0))) { - strlcpy(to, ".", tolen); - return 0; - } - - // prepare the destination buffer - to[0] = '\0'; - to[tolen - 1] = '\0'; - - // count the directory segments remaining in `base_dir` - int n_up = 0; - for (;;) { - char b = *base_s++; - if (b == 0) - break; - if (isdirsep(b) && *base_s) - n_up++; - } - - // now add a "previous dir" sequence for every following slash in the cwd - if (n_up > 0) - strlcat(to, "..", tolen); - for (; n_up > 1; --n_up) - strlcat(to, "/..", tolen); - - // finally add the differing path from "from" - if (*dest_s) { - if (n_up) - strlcat(to, "/", tolen); - strlcat(to, dest_s + 1, tolen); - } - - return 1; -} - -int Fl_WinAPI_System_Driver::filename_absolute(char *to, int tolen, const char *from, const char *base) { - if (isdirsep(*from) || *from == '|' || from[1]==':' || !base) { - strlcpy(to, from, tolen); - return 0; - } - char *a; - char *temp = new char[tolen]; - const char *start = from; - strlcpy(temp, base, tolen); - for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha - /* remove trailing '/' in current working directory */ - if (isdirsep(*(a-1))) a--; - /* remove intermediate . and .. names: */ - while (*start == '.') { - if (start[1]=='.' && (isdirsep(start[2]) || start[2]==0) ) { - // found "..", remove the last directory segment form cwd - char *b; - for (b = a-1; b >= temp && !isdirsep(*b); b--) {/*empty*/} - if (b < temp) break; - a = b; - if (start[2] == 0) - start += 2; - else - start += 3; - } else if (isdirsep(start[1])) { - // found "./" in path, just skip it - start += 2; - } else if (!start[1]) { - // found "." at end of path, just skip it - start ++; - break; - } else - break; - } - *a++ = '/'; - strlcpy(a,start,tolen - (a - temp)); - strlcpy(to, temp, tolen); - delete[] temp; - return 1; -} - -int Fl_WinAPI_System_Driver::filename_isdir(const char *n) { - char fn[4]; // used for drive letter only: "X:/" - int length = (int)strlen(n); - // Strip trailing slash from name... - if (length > 0 && isdirsep(n[length - 1])) - length --; - if (length < 1) - return 0; - - // This workaround brought to you by the fine folks at Microsoft! - // (read lots of sarcasm in that...) - - if (length == 2 && isalpha(n[0]) && n[1] == ':') { // trailing '/' already "removed" - // Always use "X:/" for drive letters - fn[0] = n[0]; - strcpy(fn + 1, ":/"); - n = fn; - length = 3; - } - - // convert filename to wide chars using *length* - utf8_to_wchar(n, wbuf, length); - - DWORD fa = GetFileAttributesW(wbuf); - return (fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY); -} - -int Fl_WinAPI_System_Driver::filename_isdir_quick(const char *n) { - // Do a quick optimization for filenames with a trailing slash... - if (*n && isdirsep(n[strlen(n) - 1])) return 1; - return filename_isdir(n); -} - -const char *Fl_WinAPI_System_Driver::filename_ext(const char *buf) { - const char *q = 0; - const char *p = buf; - for (p = buf; *p; p++) { - if (isdirsep(*p) ) q = 0; - else if (*p == '.') q = p; - } - return q ? q : p; -} - -int Fl_WinAPI_System_Driver::open_uri(const char *uri, char *msg, int msglen) { - if (msg) snprintf(msg, msglen, "open %s", uri); - return (int)(ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > (void *)32); -} - -int Fl_WinAPI_System_Driver::file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, - int lname, Fl_File_Icon *icon) { - int num_files = 0; -# ifdef __CYGWIN__ - // - // Cygwin provides an implementation of setmntent() to get the list - // of available drives... - // - FILE *m = setmntent("/-not-used-", "r"); - struct mntent *p; - while ((p = getmntent (m)) != NULL) { - browser->add(p->mnt_dir, icon); - num_files ++; - } - endmntent(m); -# else - // - // Normal Windows code uses drive bits... - // - DWORD drives; // Drive available bits - drives = GetLogicalDrives(); - for (int i = 'A'; i <= 'Z'; i ++, drives >>= 1) { - if (drives & 1) { - snprintf(filename, lname, "%c:/", i); - if (i < 'C') // see also: GetDriveType and GetVolumeInformation in Windows - browser->add(filename, icon); - else - browser->add(filename, icon); - num_files ++; - } - } -# endif // __CYGWIN__ - return num_files; -} - -int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory, char *filename, - size_t name_size, dirent ***pfiles, - Fl_File_Sort_F *sort, - char *errmsg, int errmsg_sz) -{ - strlcpy(filename, directory, name_size); - int i = (int) (strlen(filename) - 1); - if (i == 2 && filename[1] == ':' && - (filename[2] == '/' || filename[2] == '\\')) - filename[2] = '/'; - else if (filename[i] != '/' && filename[i] != '\\') - strlcat(filename, "/", name_size); - return filename_list(filename, pfiles, sort, errmsg, errmsg_sz); -} - -void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer) -{ - // First try and use the win API function UuidCreate(), but if that is not - // available, fall back to making something up from scratch. - // We do not want to link against the Rpcrt4.dll, as we will rarely use it, - // so we load the DLL dynamically, if it is available, and work from there. - static HMODULE hMod = NULL; - UUID ud; - UUID *pu = &ud; - int got_uuid = 0; - - if (!hMod) { // first time in? - hMod = LoadLibrary("Rpcrt4.dll"); - } - - if (hMod) { // do we have a usable handle to Rpcrt4.dll? - uuid_func uuid_crt = (uuid_func)GetProcAddress(hMod, "UuidCreate"); - if (uuid_crt != NULL) { - RPC_STATUS rpc_res = uuid_crt(pu); - if ( // is the return status OK for our needs? - (rpc_res == RPC_S_OK) || // all is well - (rpc_res == RPC_S_UUID_LOCAL_ONLY) || // only unique to this machine - (rpc_res == RPC_S_UUID_NO_ADDRESS) // probably only locally unique - ) { - got_uuid = -1; - snprintf(uuidBuffer, 36+1, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - pu->Data1, pu->Data2, pu->Data3, pu->Data4[0], pu->Data4[1], - pu->Data4[2], pu->Data4[3], pu->Data4[4], - pu->Data4[5], pu->Data4[6], pu->Data4[7]); - } - } - } - if (got_uuid == 0) { // did not make a UUID - use fallback logic - unsigned char b[16]; - time_t t = time(0); // first 4 byte - b[0] = (unsigned char)t; - b[1] = (unsigned char)(t>>8); - b[2] = (unsigned char)(t>>16); - b[3] = (unsigned char)(t>>24); - int r = rand(); // four more bytes - b[4] = (unsigned char)r; - b[5] = (unsigned char)(r>>8); - b[6] = (unsigned char)(r>>16); - b[7] = (unsigned char)(r>>24); - // Now we try to find 4 more "random" bytes. We extract the - // lower 4 bytes from the address of t - it is created on the - // stack so *might* be in a different place each time... - // This is now done via a union to make it compile OK on 64-bit systems. - union { void *pv; unsigned char a[sizeof(void*)]; } v; - v.pv = (void *)(&t); - // NOTE: This assume that all WinXX systems are little-endian - b[8] = v.a[0]; - b[9] = v.a[1]; - b[10] = v.a[2]; - b[11] = v.a[3]; - TCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; // only used to make last four bytes - DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1; - // GetComputerName() does not depend on any extra libs, and returns something - // analogous to gethostname() - GetComputerName(name, &nSize); - // use the first 4 TCHAR's of the name to create the last 4 bytes of our UUID - for (int ii = 0; ii < 4; ii++) { - b[12 + ii] = (unsigned char)name[ii]; - } - snprintf(uuidBuffer, 36+1, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]); - } -} - -/* - Note: `prefs` can be NULL! - */ -char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, const char *vendor, - const char *application) -{ - static char *filename = 0L; - // make enough room for a UTF-16 pathname - if (!filename) filename = (char*)::malloc(2 * FL_PATH_MAX); - HRESULT res; - - // https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw - - int appdata = CSIDL_APPDATA; // assume user preferences - if ((root & Fl_Preferences::ROOT_MASK) == Fl_Preferences::SYSTEM) - appdata = CSIDL_COMMON_APPDATA; // use system preferences - - res = SHGetFolderPathW(NULL, // hwnd: Reserved! - appdata, // csidl: User or common Application Data (Roaming) - NULL, // hToken (unused) - SHGFP_TYPE_CURRENT, // dwFlags: use current, potentially redirected path - (LPWSTR)filename); // out: filename in Windows wide string encoding - if (res != S_OK) { - // don't write data into some arbitrary directory! Just return NULL. - return 0L; - } - - // convert the path from Windows wide character (UTF-16) to UTF-8 - // FIXME: can this be simplified? Don't allocate/copy/move/free more than necessary! - char *buf = NULL; - wchar_to_utf8((wchar_t *)filename, buf); // allocates buf for conversion - strcpy(filename, buf); - free(buf); - - // Make sure that the parameters are not NULL - if ( (vendor==0L) || (vendor[0]==0) ) - vendor = "unknown"; - if ( (application==0L) || (application[0]==0) ) - application = "unknown"; - - // append vendor, application, and ".prefs", and convert '\' to '/' - snprintf(filename + strlen(filename), FL_PATH_MAX - strlen(filename), - "/%s/%s.prefs", vendor, application); - for (char *s = filename; *s; s++) if (*s == '\\') *s = '/'; - return filename; -} - -void *Fl_WinAPI_System_Driver::load(const char *filename) { - return LoadLibraryW(utf8_to_wchar(filename, wbuf)); -} - -void Fl_WinAPI_System_Driver::png_extra_rgba_processing(unsigned char *ptr, int w, int h) -{ - // Some Windows graphics drivers don't honor transparency when RGB == white - // Convert RGB to 0 when alpha == 0... - for (int i = w * h; i > 0; i --, ptr += 4) { - if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0; - } -} - -const char *Fl_WinAPI_System_Driver::next_dir_sep(const char *start) -{ - const char *p = strchr(start, '/'); - if (!p) p = strchr(start, '\\'); - return p; -} - -int Fl_WinAPI_System_Driver::file_type(const char *filename) -{ - int filetype; - if (filename[strlen(filename) - 1] == '/') - filetype = Fl_File_Icon::DIRECTORY; - else if (filename_isdir(filename)) - filetype = Fl_File_Icon::DIRECTORY; - else - filetype = Fl_File_Icon::PLAIN; - return filetype; -} - -// Note: the result is cached in a static variable -const char *Fl_WinAPI_System_Driver::home_directory_name() -{ - static std::string home; - if (!home.empty()) - return home.c_str(); - -#if (DEBUG_HOME_DIRECTORY_NAME) - print_env("HOMEDRIVE"); - print_env("HOMEPATH"); - print_env("UserProfile"); - print_env("HOME"); -#endif - - // Implement various ways to retrieve the HOME path. - // Note, from `man getenv`: - // "The implementation of getenv() is not required to be reentrant. - // The string pointed to by the return value of getenv() may be statically - // allocated, and can be modified by a subsequent call to getenv()...". - // Tests show that this is the case in some MinGW implementations. - - if (home.empty()) { - const char *home_drive = getenv("HOMEDRIVE"); - if (home_drive) { - home = home_drive; // copy *before* calling getenv() again, see above - const char *home_path = getenv("HOMEPATH"); - if (home_path) { - home.append(home_path); - } else { - home.clear(); // reset - } // home_path - } // home_drive - } // empty() - - if (home.empty()) { - const char *h = getenv("UserProfile"); - if (h) - home = h; - } - - if (home.empty()) { - const char *h = getenv("HOME"); - if (h) - home = h; - } - if (home.empty()) { - home = "~/"; // last resort - } - // Make path canonical. - for (char& c : home) { - if (c == '\\') - c = '/'; - } -#if (DEBUG_HOME_DIRECTORY_NAME) - printf("home_directory_name() returns \"%s\"\n", home.c_str()); - fflush(stdout); -#endif - return home.c_str(); -} - -void Fl_WinAPI_System_Driver::gettime(time_t *sec, int *usec) { - struct _timeb t; - _ftime(&t); - *sec = t.time; - *usec = t.millitm * 1000; -} - -// -// Code for lock support -// - -// These pointers are in Fl_win32.cxx: -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); - -// The main thread's ID -static DWORD main_thread; - -// Microsoft's version of a MUTEX... -static CRITICAL_SECTION cs; -static CRITICAL_SECTION *cs_ring; - -void Fl_WinAPI_System_Driver::unlock_ring() { - LeaveCriticalSection(cs_ring); -} - -void Fl_WinAPI_System_Driver::lock_ring() { - if (!cs_ring) { - cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION)); - InitializeCriticalSection(cs_ring); - } - EnterCriticalSection(cs_ring); -} - -// -// 'unlock_function()' - Release the lock. -// - -static void unlock_function() { - LeaveCriticalSection(&cs); -} - -// -// 'lock_function()' - Get the lock. -// - -static void lock_function() { - EnterCriticalSection(&cs); -} - -int Fl_WinAPI_System_Driver::lock() { - if (!main_thread) InitializeCriticalSection(&cs); - - lock_function(); - - if (!main_thread) { - fl_lock_function = lock_function; - fl_unlock_function = unlock_function; - main_thread = GetCurrentThreadId(); - } - return 0; -} - -void Fl_WinAPI_System_Driver::unlock() { - unlock_function(); -} - -void Fl_WinAPI_System_Driver::awake(void* msg) { - PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0); -} - -int Fl_WinAPI_System_Driver::close_fd(int fd) { - return _close(fd); -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H deleted file mode 100644 index 3cf26b67c..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H +++ /dev/null @@ -1,131 +0,0 @@ -// -// Definition of Windows window driver -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -/** - \file Fl_WinAPI_Window_Driver.H - \brief Definition of Windows window driver. - */ - -#ifndef FL_WINAPI_WINDOW_DRIVER_H -#define FL_WINAPI_WINDOW_DRIVER_H - -#include <FL/Fl_Plugin.H> -#include "../../Fl_Window_Driver.H" -#include <windows.h> - -/* - Move everything here that manages the native window interface. - - There is one window driver for each Fl_Window. Window drivers manage window - actions such as resizing, events, decoration, fullscreen modes, etc. . All - drawing and rendering is managed by the Surface device and the associated - graphics driver. - - - window specific event handling - - window types and styles, depth, etc. - - decorations - - ? where do we handle the interface between OpenGL/DirectX and Cocoa/Windows/Glx? - */ - - - -class Fl_WinAPI_Window_Driver : public Fl_Window_Driver -{ - struct icon_data { - const void *legacy_icon; - Fl_RGB_Image **icons; - int count; - HICON big_icon; - HICON small_icon; - }; - struct shape_data_type { - int lw_; ///< width of shape image - int lh_; ///< height of shape image - Fl_Image* shape_; ///< shape image - Fl_Bitmap *effective_bitmap_; ///< auxiliary bitmap image - } *shape_data_; -private: - void shape_bitmap_(Fl_Image* b); - void shape_alpha_(Fl_Image* img, int offset) FL_OVERRIDE; -public: - Fl_WinAPI_Window_Driver(Fl_Window*); - ~Fl_WinAPI_Window_Driver(); - static inline Fl_WinAPI_Window_Driver* driver(const Fl_Window *w) {return (Fl_WinAPI_Window_Driver*)Fl_Window_Driver::driver(w);} - HDC private_dc; // used for OpenGL - RECT border_width_title_bar_height(int &bx, int &by, int &bt); - - struct icon_data *icon_; - HCURSOR cursor; - int custom_cursor; - void set_minmax(LPMINMAXINFO minmax); - int fake_X_wm(int &X, int &Y, int &bt, int &bx, int &by, DWORD style = 0, DWORD styleEx = 0); - void make_fullscreen(int X, int Y, int W, int H); - // --- window data - int decorated_w() FL_OVERRIDE; - int decorated_h() FL_OVERRIDE; - const Fl_Image* shape() FL_OVERRIDE; - - // --- window management - void makeWindow() FL_OVERRIDE; - void size_range() FL_OVERRIDE { - // currently nothing to do - } - void flush_double() FL_OVERRIDE; - void flush_overlay() FL_OVERRIDE; - void draw_begin() FL_OVERRIDE; - void make_current() FL_OVERRIDE; - void show() FL_OVERRIDE; - void label(const char *name,const char *iname) FL_OVERRIDE; - void resize(int X,int Y,int W,int H) FL_OVERRIDE; - void hide() FL_OVERRIDE; - void map() FL_OVERRIDE; - void unmap() FL_OVERRIDE; - void fullscreen_on() FL_OVERRIDE; - void fullscreen_off(int X, int Y, int W, int H) FL_OVERRIDE; - void maximize() FL_OVERRIDE; - void un_maximize() FL_OVERRIDE; - bool maximize_needs_hide() FL_OVERRIDE { return true; } - void iconize() FL_OVERRIDE; - void decoration_sizes(int *top, int *left, int *right, int *bottom) FL_OVERRIDE; - // --- window cursor stuff - int set_cursor(Fl_Cursor) FL_OVERRIDE; - int set_cursor(const Fl_RGB_Image*, int, int) FL_OVERRIDE; - - void shape(const Fl_Image* img) FL_OVERRIDE; - void icons(const Fl_RGB_Image *icons[], int count) FL_OVERRIDE; - const void *icon() const FL_OVERRIDE; - void icon(const void * ic) FL_OVERRIDE; - void free_icons() FL_OVERRIDE; - void set_icons(); // driver-internal support function - // this one is implemented in Fl_win32.cxx - void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) FL_OVERRIDE; - int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) FL_OVERRIDE; -}; - - -class Fl_WinAPI_Plugin : public Fl_Plugin { -public: - Fl_WinAPI_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { } - virtual const char *klass() { return "winapi.fltk.org"; } - virtual const char *name() = 0; - virtual void invalidate(Fl_Window*) = 0; -}; - - -#endif // FL_WINAPI_WINDOW_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx deleted file mode 100644 index 4b27753bf..000000000 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx +++ /dev/null @@ -1,731 +0,0 @@ -// -// Definition of Windows window driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2025 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Image.H> -#include <FL/Fl_Bitmap.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Image_Surface.H> -#include <FL/Fl_Overlay_Window.H> -#include <FL/platform.H> -#include "Fl_WinAPI_Window_Driver.H" -#include "Fl_WinAPI_Screen_Driver.H" -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include <windows.h> -#include <ole2.h> -#include <math.h> // for ceil() - -#if USE_COLORMAP -extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx -#endif - - -Fl_WinAPI_Window_Driver::Fl_WinAPI_Window_Driver(Fl_Window *win) -: Fl_Window_Driver(win) -{ - icon_ = new icon_data; - shape_data_ = NULL; - memset(icon_, 0, sizeof(icon_data)); - cursor = NULL; - screen_num_ = -1; -} - - -Fl_WinAPI_Window_Driver::~Fl_WinAPI_Window_Driver() -{ - if (shape_data_) { - delete shape_data_->effective_bitmap_; - delete shape_data_; - } - delete icon_; -} - - -//FILE*LOG=fopen("log.log","w"); - - -RECT // frame of the decorated window in screen coordinates - Fl_WinAPI_Window_Driver::border_width_title_bar_height( - int &bx, // left and right border width - int &by, // bottom border height (=bx) - int &bt // height of window title bar - ) -{ - Fl_Window *win = pWindow; - RECT r = {0,0,0,0}; - bx = by = bt = 0; - if (win->shown() && !win->parent() && win->border() && win->visible()) { - static HMODULE dwmapi_dll = LoadLibrary("dwmapi.dll"); - typedef HRESULT (WINAPI* DwmGetWindowAttribute_type)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); - static DwmGetWindowAttribute_type DwmGetWindowAttribute = dwmapi_dll ? - (DwmGetWindowAttribute_type)GetProcAddress(dwmapi_dll, "DwmGetWindowAttribute") : NULL; - int need_r = 1; - if (DwmGetWindowAttribute) { - const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9; - if ( DwmGetWindowAttribute(fl_xid(win), DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK ) { - need_r = 0; - } - } - if (need_r) { - GetWindowRect(fl_xid(win), &r); - } - int width, height; - RECT rc; - GetClientRect(fl_xid(win), &rc); - width = rc.right; - height = rc.bottom; - bx = (r.right - r.left - width)/2; - if (bx < 1) bx = 1; - by = bx; - bt = r.bottom - r.top - height - 2 * by; - } - return r; -} - - -// --- window data - -int Fl_WinAPI_Window_Driver::decorated_w() -{ - int bt, bx, by; - float s = Fl::screen_driver()->scale(screen_num()); - border_width_title_bar_height(bx, by, bt); - int mini_bx = int(bx/s); if (mini_bx < 1) mini_bx = 1; - return w() + 2 * mini_bx; -} - -int Fl_WinAPI_Window_Driver::decorated_h() -{ - int bt, bx, by; - border_width_title_bar_height(bx, by, bt); - float s = Fl::screen_driver()->scale(screen_num()); - int mini_by = int(by / s); if (mini_by < 1) mini_by = 1; - return h() + int((bt + by) / s) + mini_by; -} - - -// --- window management - - - -void Fl_WinAPI_Window_Driver::shape_bitmap_(Fl_Image* b) { - shape_data_->shape_ = b; -} - -void Fl_WinAPI_Window_Driver::shape_alpha_(Fl_Image* img, int offset) { - int i, j, d = img->d(), w = img->w(), h = img->h(), bytesperrow = (w+7)/8; - unsigned u; - uchar byte, onebit; - // build an Fl_Bitmap covering the non-fully transparent/black part of the image - const uchar* bits = new uchar[h*bytesperrow]; // to store the bitmap - const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of rgba pixels - for (i = 0; i < h; i++) { - uchar *p = (uchar*)bits + i * bytesperrow; - byte = 0; - onebit = 1; - for (j = 0; j < w; j++) { - if (d == 3) { - u = *alpha; - u += *(alpha+1); - u += *(alpha+2); - } - else u = *alpha; - if (u > 0) { // if the pixel is not fully transparent/black - byte |= onebit; // turn on the corresponding bit of the bitmap - } - onebit = onebit << 1; // move the single set bit one position to the left - if (onebit == 0 || j == w-1) { - onebit = 1; - *p++ = byte; // store in bitmap one pack of bits - byte = 0; - } - alpha += d; // point to alpha value of next pixel - } - } - Fl_Bitmap* bitmap = new Fl_Bitmap(bits, w, h); - bitmap->alloc_array = 1; - shape_bitmap_(bitmap); - shape_data_->effective_bitmap_ = bitmap; - shape_data_->shape_ = img; -} - -void Fl_WinAPI_Window_Driver::shape(const Fl_Image* img) { - if (shape_data_) { - if (shape_data_->effective_bitmap_) { delete shape_data_->effective_bitmap_; } - } - else { - shape_data_ = new shape_data_type; - } - memset(shape_data_, 0, sizeof(shape_data_type)); - pWindow->border(false); - int d = img->d(); - if (d && img->count() >= 2) { - shape_pixmap_((Fl_Image*)img); - shape_data_->shape_ = (Fl_Image*)img; - } - else if (d == 0) shape_bitmap_((Fl_Image*)img); - else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1); - else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0); -} - - -static inline BYTE bit(int x) { return (BYTE)(1 << (x%8)); } - -static HRGN bitmap2region(Fl_Image* image) { - HRGN hRgn = 0; - /* Does this need to be dynamically determined, perhaps? */ - const int ALLOC_UNIT = 100; - DWORD maxRects = ALLOC_UNIT; - - RGNDATA* pData = (RGNDATA*)malloc(sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRects)); - pData->rdh.dwSize = sizeof(RGNDATAHEADER); - pData->rdh.iType = RDH_RECTANGLES; - pData->rdh.nCount = pData->rdh.nRgnSize = 0; - SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); - - const int bytesPerLine = (image->w() + 7)/8; - BYTE* p, *data = (BYTE*)*image->data(); - for (int y = 0; y < image->h(); y++) { - // each row, left to right - for (int x = 0; x < image->w(); x++) { - int x0 = x; - while (x < image->w()) { - p = data + x / 8; - if (!((*p) & bit(x))) break; // transparent pixel - x++; - } - if (x > x0) { - RECT *pr; - /* Add the pixels (x0, y) to (x, y+1) as a new rectangle - * in the region - */ - if (pData->rdh.nCount >= maxRects) { - maxRects += ALLOC_UNIT; - pData = (RGNDATA*)realloc(pData, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects)); - } - pr = (RECT*)&pData->Buffer; - SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1); - if (x0 < pData->rdh.rcBound.left) - pData->rdh.rcBound.left = x0; - if (y < pData->rdh.rcBound.top) - pData->rdh.rcBound.top = y; - if (x > pData->rdh.rcBound.right) - pData->rdh.rcBound.right = x; - if (y+1 > pData->rdh.rcBound.bottom) - pData->rdh.rcBound.bottom = y+1; - pData->rdh.nCount++; - /* On Windows98, ExtCreateRegion() may fail if the - * number of rectangles is too large (ie: > - * 4000). Therefore, we have to create the region by - * multiple steps. - */ - if (pData->rdh.nCount == 2000) { - HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects), pData); - if (hRgn) { - CombineRgn(hRgn, hRgn, h, RGN_OR); - DeleteObject(h); - } else - hRgn = h; - pData->rdh.nCount = 0; - SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); - } - } - } - /* Go to next row */ - data += bytesPerLine; - } - /* Create or extend the region with the remaining rectangles*/ - HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) - + (sizeof(RECT)*maxRects), pData); - if (hRgn) { - CombineRgn(hRgn, hRgn, h, RGN_OR); - DeleteObject(h); - } else hRgn = h; - free(pData); // I've created the region so I can free this now, right? - return hRgn; -} - - -void Fl_WinAPI_Window_Driver::draw_begin() -{ - if (shape_data_) { - float s = Fl::screen_driver()->scale(screen_num()); - if ((shape_data_->lw_ != s*w() || shape_data_->lh_ != s*h()) && shape_data_->shape_) { - // size of window has changed since last time - shape_data_->lw_ = int(s * w()); - shape_data_->lh_ = int(s * h()); - Fl_Image* temp = shape_data_->effective_bitmap_ ? shape_data_->effective_bitmap_ : shape_data_->shape_; - temp = temp->copy(shape_data_->lw_, shape_data_->lh_); - HRGN region = bitmap2region(temp); - SetWindowRgn(fl_xid(pWindow), region, TRUE); // the system deletes the region when it's no longer needed - delete temp; - } - } -} - - -void Fl_WinAPI_Window_Driver::flush_double() -{ - if (!shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - Fl_X *i = Fl_X::flx(pWindow); - if (!i) return; // window not yet created - - if (!other_xid) { - other_xid = new Fl_Image_Surface(w(), h(), 1); - pWindow->clear_damage(FL_DAMAGE_ALL); - } - if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { - fl_clip_region(i->region); i->region = 0; -#if 0 /* Short form that transiently changes the current Fl_Surface_Device */ - Fl_Surface_Device::push_current(other_xid); - fl_graphics_driver->clip_region( 0 ); - draw(); - Fl_Surface_Device::pop_current(); -#else - /* Alternative form that avoids changing the current Fl_Surface_Device. - The code run in the window draw() method can call Fl_Surface_Device::surface() - and conclude that it's drawing to the display, which is ultimately true - for an Fl_Double_Window. - */ - HDC sgc = fl_gc; - fl_gc = fl_makeDC((HBITMAP)other_xid->offscreen()); - int savedc = SaveDC(fl_gc); - fl_graphics_driver->gc(fl_gc); - fl_graphics_driver->restore_clip(); // duplicate clip region into new gc -# if defined(FLTK_HAVE_CAIROEXT) - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -# endif - draw(); - RestoreDC(fl_gc, savedc); - DeleteDC(fl_gc); - fl_graphics_driver->gc(sgc); -#endif - } - int X = 0, Y = 0, W = 0, H = 0; - fl_clip_box(0, 0, w(), h(), X, Y, W, H); - if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid->offscreen(), X, Y); -} - - -void Fl_WinAPI_Window_Driver::flush_overlay() -{ - Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); - - if (!shown()) return; - pWindow->make_current(); // make sure fl_gc is non-zero - Fl_X *i = Fl_X::flx(pWindow); - if (!i) return; // window not yet created - - int eraseoverlay = (pWindow->damage()&FL_DAMAGE_OVERLAY); - pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); - - if (!other_xid) { - other_xid = new Fl_Image_Surface(w(), h(), 1); - pWindow->clear_damage(FL_DAMAGE_ALL); - } - if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { - fl_clip_region(i->region); i->region = 0; - Fl_Surface_Device::push_current(other_xid); - fl_graphics_driver->clip_region(0); - draw(); - Fl_Surface_Device::pop_current(); - } - - if (eraseoverlay) fl_clip_region(0); - int X, Y, W, H; fl_clip_box(0, 0, w(), h(), X, Y, W, H); - if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid->offscreen(), X, Y); - - if (overlay() == oWindow) oWindow->draw_overlay(); -} - - -void Fl_WinAPI_Window_Driver::icons(const Fl_RGB_Image *icons[], int count) { - free_icons(); - - if (count > 0) { - icon_->icons = new Fl_RGB_Image*[count]; - icon_->count = count; - // FIXME: Fl_RGB_Image lacks const modifiers on methods - for (int i = 0;i < count;i++) { - icon_->icons[i] = (Fl_RGB_Image*)((Fl_RGB_Image*)icons[i])->copy(); - icon_->icons[i]->normalize(); - } - } - - if (Fl_X::flx(pWindow)) - set_icons(); -} - -const void *Fl_WinAPI_Window_Driver::icon() const { - return icon_->legacy_icon; -} - -void Fl_WinAPI_Window_Driver::icon(const void * ic) { - free_icons(); - icon_->legacy_icon = ic; -} - -void Fl_WinAPI_Window_Driver::free_icons() { - int i; - icon_->legacy_icon = 0L; - if (icon_->icons) { - for (i = 0;i < icon_->count;i++) - delete icon_->icons[i]; - delete [] icon_->icons; - icon_->icons = 0L; - } - icon_->count = 0; - if (icon_->big_icon) - DestroyIcon(icon_->big_icon); - if (icon_->small_icon) - DestroyIcon(icon_->small_icon); - icon_->big_icon = NULL; - icon_->small_icon = NULL; -} - - -void Fl_WinAPI_Window_Driver::make_current() { - fl_GetDC(fl_xid(pWindow)); - -#if USE_COLORMAP - // Windows maintains a hardware and software color palette; the - // SelectPalette() call updates the current soft->hard mapping - // for all drawing calls, so we must select it here before any - // code does any drawing... - fl_select_palette(); -#endif // USE_COLORMAP - - fl_graphics_driver->clip_region(0); - ((Fl_GDI_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num())); -#if defined(FLTK_HAVE_CAIROEXT) - if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow); -#endif -} - -void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) { - if (shown() && !parent()) { - if (!name) name = ""; - size_t l = strlen(name); - // WCHAR *lab = (WCHAR*) malloc((l + 1) * sizeof(short)); - // l = fl_utf2unicode((unsigned char*)name, l, (wchar_t*)lab); - unsigned wlen = fl_utf8toUtf16(name, (unsigned) l, NULL, 0); // Pass NULL to query length - wlen++; - unsigned short * lab = (unsigned short*)malloc(sizeof(unsigned short)*wlen); - wlen = fl_utf8toUtf16(name, (unsigned) l, lab, wlen); - lab[wlen] = 0; - SetWindowTextW(fl_xid(pWindow), (WCHAR *)lab); - free(lab); - } -} - - -extern void fl_clipboard_notify_retarget(HWND wnd); -extern void fl_update_clipboard(void); -extern char fl_i_own_selection[2]; - -void Fl_WinAPI_Window_Driver::hide() { - Fl_X* ip = Fl_X::flx(pWindow); - // STR#3079: if there remains a window and a non-modal window, and the window is deleted, - // the app remains running without any apparent window. - // Bug mechanism: hiding an owner window unmaps the owned (non-modal) window(s) - // but does not delete it(them) in FLTK. - // Fix for it: - // when hiding a window, build list of windows it owns, and do hide/show on them. - int count = 0; - Fl_Window *win, **doit = NULL; - for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { - if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == (HWND)ip->xid) { - count++; - } - } - if (count) { - doit = new Fl_Window*[count]; - count = 0; - for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { - if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == (HWND)ip->xid) { - doit[count++] = win; - } - } - } - - if (hide_common()) { - delete[] doit; // note: `count` and `doit` may be NULL (see PR #241) - return; - } - - // Issue #569: undo RegisterDragDrop() - RevokeDragDrop((HWND)ip->xid); - - fl_i_own_selection[1] = 0; // issue #1233 - - // make sure any custom icons get freed - // icons(NULL, 0); // free_icons() is called by the Fl_Window destructor - // this little trick keeps the current clipboard alive, even if we are about - // to destroy the window that owns the selection. - if (GetClipboardOwner() == (HWND)ip->xid) - fl_update_clipboard(); - // Make sure we unlink this window from the clipboard chain - fl_clipboard_notify_retarget((HWND)ip->xid); - // Send a message to myself so that I'll get out of the event loop... - PostMessage((HWND)ip->xid, WM_APP, 0, 0); - if (private_dc) fl_release_dc((HWND)ip->xid, private_dc); - if ((HWND)ip->xid == fl_window && fl_graphics_driver->gc()) { - fl_release_dc(fl_window, (HDC)fl_graphics_driver->gc()); - fl_window = (HWND)-1; - fl_graphics_driver->gc(0); -# ifdef FLTK_HAVE_CAIROEXT - if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); -# endif - } - - if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); - - // this little trickery seems to avoid the popup window stacking problem - HWND p = GetForegroundWindow(); - if (p==GetParent((HWND)ip->xid)) { - ShowWindow((HWND)ip->xid, SW_HIDE); - ShowWindow(p, SW_SHOWNA); - } - DestroyWindow((HWND)ip->xid); - // end of fix for STR#3079 - if (count) { - int ii; - for (ii = 0; ii < count; ii++) doit[ii]->hide(); - for (ii = 0; ii < count; ii++) { - if (ii != 0) doit[0]->show(); // Fix for STR#3165 - doit[ii]->show(); - } - } - delete[] doit; // note: `count` and `doit` may be NULL (see PR #241) - - // Try to stop the annoying "raise another program" behavior - if (pWindow->non_modal() && Fl::first_window() && Fl::first_window()->shown()) - Fl::first_window()->show(); - delete ip; - screen_num_ = -1; -} - - -void Fl_WinAPI_Window_Driver::map() { - ShowWindow(fl_xid(pWindow), SW_RESTORE); // extra map calls are harmless -} - - -void Fl_WinAPI_Window_Driver::unmap() { - ShowWindow(fl_xid(pWindow), SW_HIDE); -} - -#if !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning - -void Fl_WinAPI_Window_Driver::make_fullscreen(int X, int Y, int W, int H) { - HWND xid = fl_xid(pWindow); - int top, bottom, left, right; - int sx, sy, sw, sh; - - top = fullscreen_screen_top(); - bottom = fullscreen_screen_bottom(); - left = fullscreen_screen_left(); - right = fullscreen_screen_right(); - - if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { - top = screen_num(); - bottom = top; - left = top; - right = top; - } - - Fl_WinAPI_Screen_Driver *scr_dr = (Fl_WinAPI_Screen_Driver*)Fl::screen_driver(); - scr_dr->screen_xywh_unscaled(sx, Y, sw, sh, top); - scr_dr->screen_xywh_unscaled(sx, sy, sw, sh, bottom); - H = sy + sh - Y; - scr_dr->screen_xywh_unscaled(X, sy, sw, sh, left); - scr_dr->screen_xywh_unscaled(sx, sy, sw, sh, right); - W = sx + sw - X; - - DWORD flags = GetWindowLong(xid, GWL_STYLE); - flags = flags & ~(WS_THICKFRAME|WS_CAPTION); - SetWindowLong(xid, GWL_STYLE, flags); - - // SWP_NOSENDCHANGING is so that we can override size limits - SetWindowPos(xid, HWND_TOP, X, Y, W, H, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); -} - -#endif // !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning - - -void Fl_WinAPI_Window_Driver::fullscreen_on() { - pWindow->_set_fullscreen(); - make_fullscreen(x(), y(), w(), h()); - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_WinAPI_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { - pWindow->_clear_fullscreen(); - DWORD style = GetWindowLong(fl_xid(pWindow), GWL_STYLE); - if (pWindow->border()) style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION; - // Remove the xid temporarily so that Fl_WinAPI_Window_Driver::fake_X_wm() behaves like it - // does in Fl_WinAPI_Window_Driver::makeWindow(). - HWND xid = fl_xid(pWindow); - Fl_X::flx(pWindow)->xid = 0; - int wx, wy, bt, bx, by; - switch (fake_X_wm(wx, wy, bt, bx, by, style)) { - case 0: - break; - case 1: - style |= WS_CAPTION; - break; - case 2: - /*if (border()) { - style |= WS_THICKFRAME | WS_CAPTION; - }*/ - break; - } - Fl_X::flx(pWindow)->xid = (fl_uintptr_t)xid; - SetWindowLong(fl_xid(pWindow), GWL_STYLE, style); - if (!pWindow->maximize_active()) { - // compute window position and size in scaled units - float s = Fl::screen_driver()->scale(screen_num()); - int scaledX = int(ceil(X*s)), scaledY= int(ceil(Y*s)), scaledW = int(ceil(W*s)), scaledH = int(ceil(H*s)); - // Adjust for decorations (but not if that puts the decorations - // outside the screen) - if ((X != x()) || (Y != y())) { - scaledX -= bx; - scaledY -= by+bt; - } - scaledW += bx*2; - scaledH += by*2+bt; - SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); - } else { - int WX, WY, WW, WH; - ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->screen_xywh_unscaled(WX, WY, WW, WH, screen_num()); - SetWindowPos(fl_xid(pWindow), 0, WX, WY, WW, WH, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - Fl::handle(FL_FULLSCREEN, pWindow); -} - - -void Fl_WinAPI_Window_Driver::maximize() { - if (!border()) return Fl_Window_Driver::maximize(); - ShowWindow(fl_xid(pWindow), SW_SHOWMAXIMIZED); -} - -void Fl_WinAPI_Window_Driver::un_maximize() { - if (!border()) return Fl_Window_Driver::un_maximize(); - ShowWindow(fl_xid(pWindow), SW_SHOWNORMAL); -} - - -void Fl_WinAPI_Window_Driver::iconize() { - ShowWindow(fl_xid(pWindow), SW_SHOWMINNOACTIVE); -} - - -void Fl_WinAPI_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) { - int minw, minh, maxw, maxh, set; - set = pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL); - if (set && (maxw != minw || maxh != minh)) { - *left = *right = GetSystemMetrics(SM_CXSIZEFRAME); - *top = *bottom = GetSystemMetrics(SM_CYSIZEFRAME); - } else { - *left = *right = GetSystemMetrics(SM_CXFIXEDFRAME); - *top = *bottom = GetSystemMetrics(SM_CYFIXEDFRAME); - } - *top += GetSystemMetrics(SM_CYCAPTION); -} - -int Fl_WinAPI_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, - void (*draw_area)(void*, int,int,int,int), void* data) -{ - typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT); - static fl_GetRandomRgn_func fl_GetRandomRgn = 0L; - static char first_time = 1; - // We will have to do some Region magic now, so let's see if the - // required function is available (and it should be starting w/Win95) - if (first_time) { - HMODULE hMod = GetModuleHandle("GDI32.DLL"); - if (hMod) { - fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn"); - } - first_time = 0; - } - float s = Fl::screen_driver()->scale(screen_num()); - src_x = int(src_x * s); src_y = int(src_y * s); - src_w = int(src_w * s); src_h = int(src_h * s); - dest_x = int(dest_x * s); dest_y = int(dest_y * s); - // Now check if the source scrolling area is fully visible. - // If it is, we will do a quick scroll and just update the - // newly exposed area. If it is not, we go the safe route and - // re-render the full area instead. - // Note 1: we could go and find the areas that are actually - // obscured and recursively call fl_scroll for the newly found - // rectangles. However, this practice would rely on the - // elements of the undocumented Rgn structure. - // Note 2: although this method should take care of most - // multi-screen solutions, it will not solve issues scrolling - // from a different resolution screen onto another. - // Note 3: this has been tested with image maps, too. - HDC gc = (HDC)fl_graphics_driver->gc(); - if (fl_GetRandomRgn) { - // get the DC region minus all overlapping windows - HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0); - fl_GetRandomRgn(gc, sys_rgn, 4); - // now get the source scrolling rectangle - HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h); - POINT offset = { 0, 0 }; - if (GetDCOrgEx(gc, &offset)) { - OffsetRgn(src_rgn, offset.x, offset.y); - } - // see if all source pixels are available in the system region - // Note: we could be a bit more merciful and subtract the - // scroll destination region as well. - HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0); - int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF); - DeleteObject(dst_rgn); - DeleteObject(src_rgn); - DeleteObject(sys_rgn); - if (r != NULLREGION) { - return 1; - } - } - // Great, we can do an accelerated scroll instead of re-rendering - BitBlt(gc, dest_x, dest_y, src_w, src_h, gc, src_x, src_y,SRCCOPY); - return 0; -} - - -const Fl_Image* Fl_WinAPI_Window_Driver::shape() { - return shape_data_ ? shape_data_->shape_ : NULL; -} - - -HWND fl_win32_xid(const Fl_Window *win) { - return (HWND)Fl_Window_Driver::xid(win); -} - - -Fl_Window *fl_win32_find(HWND xid) { - return Fl_Window_Driver::find((fl_uintptr_t)xid); -} diff --git a/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx b/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx deleted file mode 100644 index b5ffe2449..000000000 --- a/src/drivers/WinAPI/fl_WinAPI_platform_init.cxx +++ /dev/null @@ -1,85 +0,0 @@ -// -// Windows-specific code to initialize Windows support. -// -// Copyright 2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include "../GDI/Fl_GDI_Copy_Surface_Driver.H" -#include "../GDI/Fl_GDI_Graphics_Driver.H" -#include "Fl_WinAPI_Screen_Driver.H" -#include "Fl_WinAPI_System_Driver.H" -#include "Fl_WinAPI_Window_Driver.H" -#include "../GDI/Fl_GDI_Image_Surface_Driver.H" -#include "../Base/Fl_Base_Pen_Events.H" - - -Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) -{ - return new Fl_GDI_Copy_Surface_Driver(w, h); -} - - -Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() -{ -#if USE_GDIPLUS - // Initialize GDI+. - static Gdiplus::GdiplusStartupInput gdiplusStartupInput; - if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_CLOSED) { - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_STARTUP; - Gdiplus::Status ret = GdiplusStartup(&Fl_GDIplus_Graphics_Driver::gdiplus_token_, &gdiplusStartupInput, NULL); - if (ret == 0) { // 0 is same as Gdiplus::Status::Ok, but old mingw64 barks at that - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_OPEN; - } else { - Fl::warning("GdiplusStartup failed with error code %d.", ret); - Fl_GDIplus_Graphics_Driver::gdiplus_state_ = Fl_GDIplus_Graphics_Driver::STATE_CLOSED; - return new Fl_GDI_Graphics_Driver(); - } - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_OPEN) { -// Fl::warning("GdiplusStartup() called, but driver is already open."); - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_SHUTDOWN) { -// Fl::warning("GdiplusStartup() called while driver is shutting down."); - } else if (Fl_GDIplus_Graphics_Driver::gdiplus_state_ == Fl_GDIplus_Graphics_Driver::STATE_STARTUP) { -// Fl::warning("GdiplusStartup() called recursively."); - } - Fl_Graphics_Driver *driver = new Fl_GDIplus_Graphics_Driver(); - return driver; -#else - return new Fl_GDI_Graphics_Driver(); -#endif -} - - -Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() -{ - return new Fl_WinAPI_Screen_Driver(); -} - - -Fl_System_Driver *Fl_System_Driver::newSystemDriver() -{ - return new Fl_WinAPI_System_Driver(); -} - - -Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) -{ - return new Fl_WinAPI_Window_Driver(w); -} - - -Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) -{ - return new Fl_GDI_Image_Surface_Driver(w, h, high_res, off); -} - diff --git a/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx index 7282528ca..822acc826 100644 --- a/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx @@ -40,12 +40,10 @@ public: } }; -#ifndef FLTK_USE_WAYLAND Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) { return new Fl_X11_Gl_Window_Driver(w); } -#endif void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { draw_string_legacy_get_list(str, n); diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H index fa3c0ee90..3904fa19e 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.H @@ -20,7 +20,7 @@ #include <FL/Fl_Copy_Surface.H> #include <FL/platform.H> #if FLTK_USE_CAIRO -# include <cairo/cairo.h> +# include <cairo.h> #endif // FLTK_USE_CAIRO class Fl_Image_Surface; diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index f60f748f5..281a6590e 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -24,7 +24,7 @@ #if FLTK_USE_CAIRO # include <cairo-xlib.h> # include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H" -# include <cairo/cairo.h> +# include <cairo.h> #else # include "Fl_Xlib_Graphics_Driver.H" #endif // FLTK_USE_CAIRO diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H index 382daf886..f90f2cc79 100644 --- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H @@ -19,7 +19,7 @@ #include <FL/Fl_Image_Surface.H> #if FLTK_USE_CAIRO -# include <cairo/cairo.h> +# include <cairo.h> #endif // FLTK_USE_CAIRO class Fl_Xlib_Image_Surface_Driver : public Fl_Image_Surface_Driver { |
