1998-10-20 00:46:58 +04:00
|
|
|
//
|
2005-02-14 16:44:24 +03:00
|
|
|
// "$Id$"
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
|
|
|
// WIN32-specific code for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2016-01-31 07:33:54 +03:00
|
|
|
// Copyright 1998-2016 by Bill Spitzak and others.
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2011-07-19 08:49:30 +04:00
|
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
//
|
|
|
|
// http://www.fltk.org/COPYING.php
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2005-04-16 04:13:17 +04:00
|
|
|
// Please report all bugs and problems on the following page:
|
|
|
|
//
|
|
|
|
// http://www.fltk.org/str.php
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
1998-10-06 23:14:55 +04:00
|
|
|
|
|
|
|
// This file contains win32-specific code for fltk which is always linked
|
2001-11-22 18:35:02 +03:00
|
|
|
// in. Search other files for "WIN32" or filenames ending in _win32.cxx
|
1998-10-06 23:14:55 +04:00
|
|
|
// for other system-specific code.
|
|
|
|
|
2016-03-25 16:08:48 +03:00
|
|
|
#if defined(WIN32) and !defined(FL_DOXYGEN)
|
|
|
|
|
|
|
|
/* We require Windows 2000 features (e.g. VK definitions) */
|
|
|
|
# if !defined(WINVER) || (WINVER < 0x0500)
|
|
|
|
# ifdef WINVER
|
|
|
|
# undef WINVER
|
|
|
|
# endif
|
|
|
|
# define WINVER 0x0500
|
|
|
|
# endif
|
|
|
|
# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
|
|
|
|
# ifdef _WIN32_WINNT
|
|
|
|
# undef _WIN32_WINNT
|
|
|
|
# endif
|
|
|
|
# define _WIN32_WINNT 0x0500
|
|
|
|
# endif
|
|
|
|
|
|
|
|
// recent versions of MinGW warn: "Please include winsock2.h before windows.h",
|
|
|
|
#if !defined(__CYGWIN__)
|
|
|
|
# include <winsock2.h>
|
|
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
|
|
#include <ole2.h>
|
2016-03-25 18:39:51 +03:00
|
|
|
#include <shellapi.h>
|
2016-03-25 16:08:48 +03:00
|
|
|
|
|
|
|
void fl_free_fonts(void);
|
|
|
|
void fl_release_dc(HWND,HDC);
|
|
|
|
void fl_cleanup_dc_list(void);
|
2010-12-09 12:03:17 +03:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
#include <FL/Fl.H>
|
2016-03-26 17:36:11 +03:00
|
|
|
#include <FL/x.H>
|
2016-02-20 01:21:02 +03:00
|
|
|
#include <FL/Fl_Window_Driver.H>
|
2016-03-25 16:08:48 +03:00
|
|
|
#include <FL/Fl_Graphics_Driver.H> // for fl_graphics_driver
|
|
|
|
#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H"
|
2008-09-19 21:40:20 +04:00
|
|
|
#include <FL/fl_utf8.h>
|
1998-10-06 23:14:55 +04:00
|
|
|
#include <FL/Fl_Window.H>
|
2008-09-11 03:56:49 +04:00
|
|
|
#include <FL/fl_draw.H>
|
2004-10-19 22:21:55 +04:00
|
|
|
#include <FL/Enumerations.H>
|
2006-06-14 14:48:36 +04:00
|
|
|
#include <FL/Fl_Tooltip.H>
|
2011-04-16 01:38:05 +04:00
|
|
|
#include <FL/Fl_Paged_Device.H>
|
2016-02-12 19:17:40 +03:00
|
|
|
#include <FL/Fl_Shared_Image.H>
|
2002-04-11 15:52:43 +04:00
|
|
|
#include "flstring.h"
|
2005-09-13 03:03:34 +04:00
|
|
|
#include "Fl_Font.H"
|
2001-04-27 19:43:38 +04:00
|
|
|
#include <stdio.h>
|
1999-01-04 22:25:40 +03:00
|
|
|
#include <stdlib.h>
|
1999-01-07 00:20:01 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <time.h>
|
2014-02-05 13:38:22 +04:00
|
|
|
#include <signal.h>
|
2002-01-01 17:14:34 +03:00
|
|
|
#ifdef __CYGWIN__
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <unistd.h>
|
2001-10-30 00:59:15 +03:00
|
|
|
#endif
|
2010-12-09 12:03:17 +03:00
|
|
|
|
|
|
|
#if !defined(NO_TRACK_MOUSE)
|
2011-02-21 21:33:46 +03:00
|
|
|
# include <commctrl.h> // TrackMouseEvent
|
|
|
|
// fabien: Ms Visual Studio >= 2003 permit embedded lib reference
|
|
|
|
// that makes fltk use easier as only fltk libs are now requested
|
2016-01-28 20:38:11 +03:00
|
|
|
// This idea could be extended to fltk libs themselves,
|
2011-02-21 21:33:46 +03:00
|
|
|
// implementer should then care about DLL linkage flags ...
|
2016-01-31 07:33:54 +03:00
|
|
|
# if defined(_MSC_VER) && (_MSC_VER>=1310)
|
2011-02-21 21:33:46 +03:00
|
|
|
# pragma comment (lib, "comctl32.lib")
|
|
|
|
# endif
|
2008-10-04 20:35:58 +04:00
|
|
|
#endif
|
2002-04-10 19:01:22 +04:00
|
|
|
|
2010-11-11 11:38:36 +03:00
|
|
|
#if defined(__GNUC__)
|
2009-01-12 15:43:03 +03:00
|
|
|
# include <wchar.h>
|
|
|
|
#endif
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
|
2016-03-25 16:08:48 +03:00
|
|
|
extern bool fl_clipboard_notify_empty(void);
|
|
|
|
extern void fl_trigger_clipboard_notify(int source);
|
|
|
|
extern HBRUSH fl_brush_action(int action);
|
|
|
|
extern void fl_cleanup_pens(void);
|
|
|
|
|
|
|
|
|
1999-12-29 06:14:41 +03:00
|
|
|
//
|
|
|
|
// USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()...
|
2008-09-02 16:03:30 +04:00
|
|
|
// USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons:
|
2009-02-21 13:01:57 +03:00
|
|
|
/*
|
|
|
|
This feature was supposed to provide an efficient alternative to the current
|
|
|
|
polling method, but as it has been discussed (Thanks Albrecht!) :
|
|
|
|
- the async mode would imply to change the socket to non blocking mode.
|
|
|
|
This can have unexpected side effects for 3rd party apps, especially
|
2016-01-28 20:38:11 +03:00
|
|
|
if it is set on-the-fly when socket service is really needed, as it is
|
2009-02-21 13:01:57 +03:00
|
|
|
done today and on purpose, but still the 3rd party developer wouldn't easily
|
|
|
|
control the sequencing of socket operations.
|
2016-01-28 20:38:11 +03:00
|
|
|
- Finer granularity of events furthered by the async select is a plus only
|
2009-02-21 13:01:57 +03:00
|
|
|
for socket 3rd party impl., it is simply not needed for the 'light' fltk
|
|
|
|
use we make of wsock, so here it would also be a bad point, because of all
|
|
|
|
the logic add-ons necessary for using this functionality, without a clear
|
|
|
|
benefit.
|
|
|
|
|
|
|
|
So async mode select would not add benefits to fltk, worse, it can slowdown
|
|
|
|
fltk because of this finer granularity and instrumentation code to be added
|
|
|
|
for async mode proper operation, not mentioning the side effects...
|
2008-09-02 16:03:30 +04:00
|
|
|
*/
|
1999-12-29 06:14:41 +03:00
|
|
|
|
2014-10-09 15:52:43 +04:00
|
|
|
// Internal functions
|
|
|
|
static void fl_clipboard_notify_target(HWND wnd);
|
|
|
|
static void fl_clipboard_notify_untarget(HWND wnd);
|
|
|
|
|
|
|
|
// Internal variables
|
|
|
|
static HWND clipboard_wnd = 0;
|
|
|
|
static HWND next_clipboard_wnd = 0;
|
|
|
|
|
|
|
|
static bool initial_clipboard = true;
|
|
|
|
|
2008-08-26 03:51:34 +04:00
|
|
|
// dynamic wsock dll handling api:
|
2008-10-04 20:35:58 +04:00
|
|
|
#if defined(__CYGWIN__) && !defined(SOCKET)
|
|
|
|
# define SOCKET int
|
|
|
|
#endif
|
2010-12-09 12:03:17 +03:00
|
|
|
|
|
|
|
// note: winsock2.h has been #include'd in Fl.cxx
|
|
|
|
#define WSCK_DLL_NAME "WS2_32.DLL"
|
|
|
|
|
2008-08-26 03:51:34 +04:00
|
|
|
typedef int (WINAPI* fl_wsk_select_f)(int, fd_set*, fd_set*, fd_set*, const struct timeval*);
|
|
|
|
typedef int (WINAPI* fl_wsk_fd_is_set_f)(SOCKET, fd_set *);
|
2009-12-24 14:40:26 +03:00
|
|
|
|
2008-08-26 03:51:34 +04:00
|
|
|
static HMODULE s_wsock_mod = 0;
|
2010-12-09 12:03:17 +03:00
|
|
|
static fl_wsk_select_f s_wsock_select = 0;
|
|
|
|
static fl_wsk_fd_is_set_f fl_wsk_fd_is_set = 0;
|
2008-08-26 03:51:34 +04:00
|
|
|
|
|
|
|
static HMODULE get_wsock_mod() {
|
2008-09-02 16:03:30 +04:00
|
|
|
if (!s_wsock_mod) {
|
|
|
|
s_wsock_mod = LoadLibrary(WSCK_DLL_NAME);
|
|
|
|
if (s_wsock_mod==NULL)
|
|
|
|
Fl::fatal("FLTK Lib Error: %s file not found! Please check your winsock dll accessibility.\n",WSCK_DLL_NAME);
|
|
|
|
s_wsock_select = (fl_wsk_select_f) GetProcAddress(s_wsock_mod, "select");
|
|
|
|
fl_wsk_fd_is_set = (fl_wsk_fd_is_set_f) GetProcAddress(s_wsock_mod, "__WSAFDIsSet");
|
|
|
|
}
|
2008-08-26 03:51:34 +04:00
|
|
|
return s_wsock_mod;
|
|
|
|
}
|
2002-02-20 22:29:57 +03:00
|
|
|
|
2008-09-11 15:14:06 +04:00
|
|
|
/*
|
|
|
|
* Dynamic linking of imm32.dll
|
2016-01-28 20:38:11 +03:00
|
|
|
* This library is only needed for a hand full (four ATM) functions relating to
|
2008-09-11 15:14:06 +04:00
|
|
|
* international text rendering and locales. Dynamically loading reduces initial
|
|
|
|
* size and link dependencies.
|
|
|
|
*/
|
|
|
|
static HMODULE s_imm_module = 0;
|
2014-09-15 13:44:35 +04:00
|
|
|
typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD);
|
|
|
|
static flTypeImmAssociateContextEx flImmAssociateContextEx = 0;
|
2008-09-11 15:14:06 +04:00
|
|
|
typedef HIMC (WINAPI* flTypeImmGetContext)(HWND);
|
|
|
|
static flTypeImmGetContext flImmGetContext = 0;
|
|
|
|
typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
|
|
|
|
static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0;
|
|
|
|
typedef BOOL (WINAPI* flTypeImmReleaseContext)(HWND, HIMC);
|
|
|
|
static flTypeImmReleaseContext flImmReleaseContext = 0;
|
2014-09-15 13:35:05 +04:00
|
|
|
|
|
|
|
static void get_imm_module() {
|
|
|
|
s_imm_module = LoadLibrary("IMM32.DLL");
|
|
|
|
if (!s_imm_module)
|
|
|
|
Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n"
|
|
|
|
"Please check your input method manager library accessibility.");
|
2014-09-15 13:44:35 +04:00
|
|
|
flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx");
|
2014-09-15 13:35:05 +04:00
|
|
|
flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext");
|
|
|
|
flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow");
|
|
|
|
flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext");
|
2008-09-11 15:14:06 +04:00
|
|
|
}
|
|
|
|
|
2008-12-07 13:53:07 +03:00
|
|
|
// USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have
|
|
|
|
// TrackMouseEvent()...
|
2002-02-20 22:29:57 +03:00
|
|
|
//
|
2008-12-07 13:53:07 +03:00
|
|
|
// Now (Dec. 2008) we can assume that current Cygwin/MinGW versions
|
|
|
|
// support the TrackMouseEvent() function, but WinCE obviously doesn't
|
2016-01-28 20:38:11 +03:00
|
|
|
// support it (STR 2095). Therefore, USE_TRACK_MOUSE is enabled by
|
2008-12-07 13:53:07 +03:00
|
|
|
// default, but you can disable it by defining NO_TRACK_MOUSE.
|
2002-02-20 22:29:57 +03:00
|
|
|
//
|
2008-12-07 13:53:07 +03:00
|
|
|
// TrackMouseEvent is only used to support window leave notifications
|
|
|
|
// under Windows. It can be used to get FL_LEAVE events, when the
|
|
|
|
// mouse leaves the _main_ application window (FLTK detects subwindow
|
|
|
|
// leave events by using normal move events).
|
2002-02-20 22:29:57 +03:00
|
|
|
//
|
2008-12-07 13:53:07 +03:00
|
|
|
// Implementation note: If the mouse cursor leaves one subwindow and
|
|
|
|
// enters another window, then Windows sends a WM_MOUSEMOVE message to
|
|
|
|
// the new window before it sends a WM_MOUSELEAVE message to the old
|
|
|
|
// (just left) window. We save the current mouse window in a static variable,
|
|
|
|
// and if we get a WM_MOUSELEAVE event for the current mouse window, this
|
|
|
|
// means that the top level window has been left (otherwise we would have
|
|
|
|
// got another WM_MOUSEMOVE message before).
|
|
|
|
|
|
|
|
// #define NO_TRACK_MOUSE
|
|
|
|
|
|
|
|
#if !defined(NO_TRACK_MOUSE)
|
|
|
|
# define USE_TRACK_MOUSE
|
|
|
|
#endif // NO_TRACK_MOUSE
|
|
|
|
|
|
|
|
static Fl_Window *track_mouse_win=0; // current TrackMouseEvent() window
|
|
|
|
|
|
|
|
// USE_CAPTURE_MOUSE_WIN - this must be defined for TrackMouseEvent to work
|
|
|
|
// correctly with subwindows - otherwise a single mouse click and release
|
|
|
|
// (without a move) would generate phantom leave events.
|
2016-01-28 20:38:11 +03:00
|
|
|
// This defines, if the current mouse window (maybe a subwindow) or the
|
2008-12-07 13:53:07 +03:00
|
|
|
// main window should get mouse events after pushing (and holding) a mouse
|
|
|
|
// button, i.e. when dragging the mouse. This is done by calling SetCapture
|
|
|
|
// (see below).
|
2002-02-20 22:29:57 +03:00
|
|
|
|
2008-12-07 13:53:07 +03:00
|
|
|
#ifdef USE_TRACK_MOUSE
|
|
|
|
#define USE_CAPTURE_MOUSE_WIN
|
|
|
|
#endif // USE_TRACK_MOUSE
|
2002-02-20 22:29:57 +03:00
|
|
|
|
1999-03-05 00:20:55 +03:00
|
|
|
//
|
|
|
|
// WM_SYNCPAINT is an "undocumented" message, which is finally defined in
|
|
|
|
// VC++ 6.0.
|
|
|
|
//
|
2002-01-01 17:14:34 +03:00
|
|
|
|
1999-03-05 00:20:55 +03:00
|
|
|
#ifndef WM_SYNCPAINT
|
|
|
|
# define WM_SYNCPAINT 0x0088
|
2002-03-07 22:22:58 +03:00
|
|
|
#endif
|
1999-03-05 00:20:55 +03:00
|
|
|
|
1999-07-22 11:27:12 +04:00
|
|
|
#ifndef WM_MOUSELEAVE
|
1999-09-16 09:34:27 +04:00
|
|
|
# define WM_MOUSELEAVE 0x02a3
|
1999-07-22 11:27:12 +04:00
|
|
|
#endif
|
|
|
|
|
2001-08-03 00:09:25 +04:00
|
|
|
#ifndef WM_MOUSEWHEEL
|
|
|
|
# define WM_MOUSEWHEEL 0x020a
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef WHEEL_DELTA
|
2002-03-07 22:22:58 +03:00
|
|
|
# define WHEEL_DELTA 120 // according to MSDN.
|
2001-08-03 00:09:25 +04:00
|
|
|
#endif
|
|
|
|
|
2014-10-08 15:57:43 +04:00
|
|
|
#ifndef SM_CXPADDEDBORDER
|
|
|
|
# define SM_CXPADDEDBORDER (92) // STR #3061
|
|
|
|
#endif
|
2002-01-01 17:14:34 +03:00
|
|
|
|
1999-12-29 06:14:41 +03:00
|
|
|
//
|
|
|
|
// WM_FLSELECT is the user-defined message that we get when one of
|
|
|
|
// the sockets has pending data, etc.
|
|
|
|
//
|
|
|
|
|
2005-02-14 16:44:24 +03:00
|
|
|
#define WM_FLSELECT (WM_APP+1) // WM_APP is used for hide-window
|
1999-12-29 06:14:41 +03:00
|
|
|
|
2002-01-01 17:14:34 +03:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// interface to poll/select call:
|
|
|
|
|
1999-01-07 00:20:01 +03:00
|
|
|
// fd's are only implemented for sockets. Microsoft Windows does not
|
|
|
|
// have a unified IO system, so it doesn't support select() on files,
|
1999-12-30 20:37:05 +03:00
|
|
|
// devices, or pipes...
|
|
|
|
//
|
|
|
|
// Microsoft provides the Berkeley select() call and an asynchronous
|
1999-12-29 06:14:41 +03:00
|
|
|
// select function that sends a WIN32 message when the select condition
|
2009-12-24 14:40:26 +03:00
|
|
|
// exists. However, we don't try to use the asynchronous WSAAsyncSelect()
|
|
|
|
// any more for good reasons (see above).
|
|
|
|
//
|
|
|
|
// A.S. Dec 2009: We got reports that current winsock2.h files define
|
|
|
|
// POLLIN, POLLOUT, and POLLERR with conflicting values WRT what we
|
|
|
|
// used before (STR #2301). Therefore we must not use these values
|
|
|
|
// for our internal purposes, but use FL_READ, FL_WRITE, and
|
|
|
|
// FL_EXCEPT, as defined for use in Fl::add_fd().
|
|
|
|
//
|
2002-01-01 17:14:34 +03:00
|
|
|
static int maxfd = 0;
|
1999-12-30 20:37:05 +03:00
|
|
|
static fd_set fdsets[3];
|
|
|
|
|
2002-05-02 00:05:19 +04:00
|
|
|
extern IDropTarget *flIDropTarget;
|
2002-02-24 20:52:18 +03:00
|
|
|
|
1999-04-17 05:02:30 +04:00
|
|
|
static int nfds = 0;
|
|
|
|
static int fd_array_size = 0;
|
|
|
|
static struct FD {
|
|
|
|
int fd;
|
|
|
|
short events;
|
2012-04-05 09:12:30 +04:00
|
|
|
void (*cb)(FL_SOCKET, void*); // keep socket api opaque at this level to reduce multiplatform deps headaches
|
1999-01-07 00:20:01 +03:00
|
|
|
void* arg;
|
1999-04-17 05:02:30 +04:00
|
|
|
} *fd = 0;
|
1999-01-07 00:20:01 +03:00
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
extern unsigned int fl_codepage;
|
|
|
|
|
|
|
|
void fl_reset_spot()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-12-27 22:22:30 +03:00
|
|
|
void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win)
|
2008-09-11 03:56:49 +04:00
|
|
|
{
|
2008-12-27 22:22:30 +03:00
|
|
|
if (!win) return;
|
|
|
|
Fl_Window* tw = win;
|
|
|
|
while (tw->parent()) tw = tw->window(); // find top level window
|
2008-12-05 16:48:26 +03:00
|
|
|
|
2014-09-15 13:35:05 +04:00
|
|
|
if (!tw->shown())
|
|
|
|
return;
|
|
|
|
|
2008-12-27 22:22:30 +03:00
|
|
|
HIMC himc = flImmGetContext(fl_xid(tw));
|
2008-12-05 16:48:26 +03:00
|
|
|
|
2008-12-27 22:22:30 +03:00
|
|
|
if (himc) {
|
|
|
|
COMPOSITIONFORM cfs;
|
2008-12-05 16:48:26 +03:00
|
|
|
cfs.dwStyle = CFS_POINT;
|
2008-12-27 22:22:30 +03:00
|
|
|
cfs.ptCurrentPos.x = X;
|
|
|
|
cfs.ptCurrentPos.y = Y - tw->labelsize();
|
|
|
|
MapWindowPoints(fl_xid(win), fl_xid(tw), &cfs.ptCurrentPos, 1);
|
2008-12-05 16:48:26 +03:00
|
|
|
flImmSetCompositionWindow(himc, &cfs);
|
2008-12-27 22:22:30 +03:00
|
|
|
flImmReleaseContext(fl_xid(tw), himc);
|
2008-12-05 16:48:26 +03:00
|
|
|
}
|
2008-09-11 03:56:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void fl_set_status(int x, int y, int w, int h)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-04-05 09:12:30 +04:00
|
|
|
void Fl::add_fd(int n, int events, void (*cb)(FL_SOCKET, void*), void *v) {
|
1999-04-17 05:02:30 +04:00
|
|
|
remove_fd(n,events);
|
|
|
|
int i = nfds++;
|
|
|
|
if (i >= fd_array_size) {
|
|
|
|
fd_array_size = 2*fd_array_size+1;
|
|
|
|
fd = (FD*)realloc(fd, fd_array_size*sizeof(FD));
|
|
|
|
}
|
|
|
|
fd[i].fd = n;
|
2002-11-19 19:37:36 +03:00
|
|
|
fd[i].events = (short)events;
|
1999-04-17 05:02:30 +04:00
|
|
|
fd[i].cb = cb;
|
|
|
|
fd[i].arg = v;
|
1999-12-30 20:37:05 +03:00
|
|
|
|
2009-12-24 14:40:26 +03:00
|
|
|
if (events & FL_READ) FD_SET((unsigned)n, &fdsets[0]);
|
|
|
|
if (events & FL_WRITE) FD_SET((unsigned)n, &fdsets[1]);
|
|
|
|
if (events & FL_EXCEPT) FD_SET((unsigned)n, &fdsets[2]);
|
2002-01-01 17:14:34 +03:00
|
|
|
if (n > maxfd) maxfd = n;
|
1999-01-07 00:20:01 +03:00
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
|
2012-04-05 09:12:30 +04:00
|
|
|
void Fl::add_fd(int fd, void (*cb)(FL_SOCKET, void*), void* v) {
|
2009-12-24 14:40:26 +03:00
|
|
|
Fl::add_fd(fd, FL_READ, cb, v);
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
1999-04-17 05:02:30 +04:00
|
|
|
void Fl::remove_fd(int n, int events) {
|
1999-01-07 00:20:01 +03:00
|
|
|
int i,j;
|
|
|
|
for (i=j=0; i<nfds; i++) {
|
1999-04-17 05:02:30 +04:00
|
|
|
if (fd[i].fd == n) {
|
2002-11-19 19:37:36 +03:00
|
|
|
short e = fd[i].events & ~events;
|
1999-04-17 05:02:30 +04:00
|
|
|
if (!e) continue; // if no events left, delete this fd
|
|
|
|
fd[i].events = e;
|
|
|
|
}
|
|
|
|
// move it down in the array if necessary:
|
|
|
|
if (j<i) {
|
|
|
|
fd[j]=fd[i];
|
|
|
|
}
|
|
|
|
j++;
|
1999-01-07 00:20:01 +03:00
|
|
|
}
|
|
|
|
nfds = j;
|
1999-12-29 06:14:41 +03:00
|
|
|
|
2009-12-24 14:40:26 +03:00
|
|
|
if (events & FL_READ) FD_CLR(unsigned(n), &fdsets[0]);
|
|
|
|
if (events & FL_WRITE) FD_CLR(unsigned(n), &fdsets[1]);
|
|
|
|
if (events & FL_EXCEPT) FD_CLR(unsigned(n), &fdsets[2]);
|
1999-04-17 05:02:30 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fl::remove_fd(int n) {
|
|
|
|
remove_fd(n, -1);
|
1999-01-07 00:20:01 +03:00
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
|
2001-12-07 01:16:49 +03:00
|
|
|
// these pointers are set by the Fl::lock() function:
|
|
|
|
static void nothing() {}
|
|
|
|
void (*fl_lock_function)() = nothing;
|
|
|
|
void (*fl_unlock_function)() = nothing;
|
|
|
|
|
|
|
|
static void* thread_message_;
|
|
|
|
void* Fl::thread_message() {
|
|
|
|
void* r = thread_message_;
|
|
|
|
thread_message_ = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-15 13:17:56 +04:00
|
|
|
extern int fl_send_system_handlers(void *e);
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
MSG fl_msg;
|
|
|
|
|
2015-04-23 13:11:23 +03:00
|
|
|
// A local helper function to flush any pending callback requests
|
|
|
|
// from the awake ring-buffer
|
|
|
|
static void process_awake_handler_requests(void) {
|
|
|
|
Fl_Awake_Handler func;
|
|
|
|
void *data;
|
|
|
|
while (Fl::get_awake_handler_(func, data) == 0) {
|
|
|
|
func(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-06-18 04:38:41 +04:00
|
|
|
// This is never called with time_to_wait < 0.0.
|
|
|
|
// It *should* return negative on error, 0 if nothing happens before
|
|
|
|
// timeout, and >0 if any callbacks were done. This version only
|
|
|
|
// returns zero if nothing happens during a 0.0 timeout, otherwise
|
|
|
|
// it returns 1.
|
|
|
|
int fl_wait(double time_to_wait) {
|
1999-05-09 18:49:14 +04:00
|
|
|
int have_message = 0;
|
|
|
|
|
2016-02-13 19:12:57 +03:00
|
|
|
Fl::run_checks();
|
2007-01-28 22:48:31 +03:00
|
|
|
|
|
|
|
// idle processing
|
|
|
|
static char in_idle;
|
|
|
|
if (Fl::idle && !in_idle) {
|
|
|
|
in_idle = 1;
|
|
|
|
Fl::idle();
|
|
|
|
in_idle = 0;
|
|
|
|
}
|
2016-01-28 20:38:11 +03:00
|
|
|
|
1999-12-30 20:37:05 +03:00
|
|
|
if (nfds) {
|
|
|
|
// For WIN32 we need to poll for socket input FIRST, since
|
|
|
|
// the event queue is not something we can select() on...
|
|
|
|
timeval t;
|
|
|
|
t.tv_sec = 0;
|
|
|
|
t.tv_usec = 0;
|
|
|
|
|
|
|
|
fd_set fdt[3];
|
2008-08-26 12:24:54 +04:00
|
|
|
memcpy(fdt, fdsets, sizeof fdt); // one shot faster fdt init
|
2008-08-26 03:51:34 +04:00
|
|
|
if (get_wsock_mod()&& s_wsock_select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) {
|
1999-12-30 20:37:05 +03:00
|
|
|
// We got something - do the callback!
|
|
|
|
for (int i = 0; i < nfds; i ++) {
|
2008-08-26 03:51:34 +04:00
|
|
|
SOCKET f = fd[i].fd;
|
1999-12-30 20:37:05 +03:00
|
|
|
short revents = 0;
|
2009-12-24 14:40:26 +03:00
|
|
|
if (fl_wsk_fd_is_set(f, &fdt[0])) revents |= FL_READ;
|
|
|
|
if (fl_wsk_fd_is_set(f, &fdt[1])) revents |= FL_WRITE;
|
|
|
|
if (fl_wsk_fd_is_set(f, &fdt[2])) revents |= FL_EXCEPT;
|
1999-12-30 20:37:05 +03:00
|
|
|
if (fd[i].events & revents) fd[i].cb(f, fd[i].arg);
|
|
|
|
}
|
2000-06-18 04:38:41 +04:00
|
|
|
time_to_wait = 0.0; // just peek for any messages
|
|
|
|
} else {
|
|
|
|
// we need to check them periodically, so set a short timeout:
|
|
|
|
if (time_to_wait > .001) time_to_wait = .001;
|
1999-12-30 20:37:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-28 20:38:11 +03:00
|
|
|
if (Fl::idle || Fl::damage())
|
2005-12-16 14:34:04 +03:00
|
|
|
time_to_wait = 0.0;
|
2005-12-14 04:25:21 +03:00
|
|
|
|
2007-02-23 22:27:43 +03:00
|
|
|
// if there are no more windows and this timer is set
|
2009-02-21 13:01:57 +03:00
|
|
|
// to FOREVER, continue through or look up indefinitely
|
2007-02-23 22:27:43 +03:00
|
|
|
if (!Fl::first_window() && time_to_wait==1e20)
|
|
|
|
time_to_wait = 0.0;
|
|
|
|
|
2001-12-07 01:16:49 +03:00
|
|
|
fl_unlock_function();
|
|
|
|
|
2005-10-13 00:19:30 +04:00
|
|
|
time_to_wait = (time_to_wait > 10000 ? 10000 : time_to_wait);
|
|
|
|
int t_msec = (int) (time_to_wait * 1000.0 + 0.5);
|
2006-05-05 18:36:58 +04:00
|
|
|
MsgWaitForMultipleObjects(0, NULL, FALSE, t_msec, QS_ALLINPUT);
|
1999-01-07 00:20:01 +03:00
|
|
|
|
2001-12-07 01:16:49 +03:00
|
|
|
fl_lock_function();
|
|
|
|
|
2000-06-18 04:38:41 +04:00
|
|
|
// Execute the message we got, and all other pending messages:
|
2009-02-21 13:01:57 +03:00
|
|
|
// have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
|
2014-09-15 13:14:07 +04:00
|
|
|
while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) {
|
2014-09-15 13:17:56 +04:00
|
|
|
if (fl_send_system_handlers(&fl_msg))
|
|
|
|
continue;
|
|
|
|
|
2014-09-15 13:14:07 +04:00
|
|
|
// Let applications treat WM_QUIT identical to SIGTERM on *nix
|
|
|
|
if (fl_msg.message == WM_QUIT)
|
|
|
|
raise(SIGTERM);
|
|
|
|
|
|
|
|
if (fl_msg.message == fl_wake_msg) {
|
|
|
|
// Used for awaking wait() from another thread
|
|
|
|
thread_message_ = (void*)fl_msg.wParam;
|
2015-04-23 13:11:23 +03:00
|
|
|
process_awake_handler_requests();
|
2005-10-13 00:19:30 +04:00
|
|
|
}
|
2014-09-15 13:14:07 +04:00
|
|
|
|
|
|
|
TranslateMessage(&fl_msg);
|
|
|
|
DispatchMessageW(&fl_msg);
|
2005-10-13 00:19:30 +04:00
|
|
|
}
|
2015-04-23 13:11:23 +03:00
|
|
|
|
|
|
|
// The following conditional test:
|
|
|
|
// (Fl::awake_ring_head_ != Fl::awake_ring_tail_)
|
|
|
|
// is a workaround / fix for STR #3143. This works, but a better solution
|
|
|
|
// would be to understand why the PostThreadMessage() messages are not
|
|
|
|
// seen by the main window if it is being dragged/ resized at the time.
|
|
|
|
// If a worker thread posts an awake callback to the ring buffer
|
|
|
|
// whilst the main window is unresponsive (if a drag or resize operation
|
|
|
|
// is in progress) we may miss the PostThreadMessage(). So here, we check if
|
|
|
|
// there is anything pending in the awake ring buffer and if so process
|
|
|
|
// it. This is not strictly thread safe (for speed it compares the head
|
|
|
|
// and tail indices without first locking the ring buffer) but is intended
|
|
|
|
// only as a fall-back recovery mechanism if the awake processing stalls.
|
|
|
|
// If the test erroneously returns true (may happen if we test the indices
|
|
|
|
// whilst they are being modified) we will call process_awake_handler_requests()
|
|
|
|
// unnecessarily, but this has no harmful consequences so is safe to do.
|
|
|
|
// Note also that if we miss the PostThreadMessage(), then thread_message_
|
|
|
|
// will not be updated, so this is not a perfect solution, but it does
|
|
|
|
// recover and process any pending awake callbacks.
|
|
|
|
// Normally the ring buffer head and tail indices will match and this
|
|
|
|
// comparison will do nothing. Addresses STR #3143
|
|
|
|
if (Fl::awake_ring_head_ != Fl::awake_ring_tail_) {
|
|
|
|
process_awake_handler_requests();
|
|
|
|
}
|
|
|
|
|
2005-11-04 12:16:16 +03:00
|
|
|
Fl::flush();
|
2001-12-07 01:16:49 +03:00
|
|
|
|
2000-06-18 04:38:41 +04:00
|
|
|
// This should return 0 if only timer events were handled:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fl_ready() is just like fl_wait(0.0) except no callbacks are done:
|
|
|
|
int fl_ready() {
|
|
|
|
if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1;
|
2008-09-02 16:03:30 +04:00
|
|
|
if (!nfds) return 0;
|
2000-06-18 04:38:41 +04:00
|
|
|
timeval t;
|
|
|
|
t.tv_sec = 0;
|
|
|
|
t.tv_usec = 0;
|
|
|
|
fd_set fdt[3];
|
2008-08-26 12:24:54 +04:00
|
|
|
memcpy(fdt, fdsets, sizeof fdt);
|
|
|
|
return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0;
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
2014-09-15 13:35:05 +04:00
|
|
|
void fl_open_display() {
|
|
|
|
static char beenHereDoneThat = 0;
|
|
|
|
|
|
|
|
if (beenHereDoneThat)
|
|
|
|
return;
|
|
|
|
|
|
|
|
beenHereDoneThat = 1;
|
|
|
|
|
|
|
|
OleInitialize(0L);
|
|
|
|
|
|
|
|
get_imm_module();
|
|
|
|
}
|
|
|
|
|
|
|
|
class Fl_Win32_At_Exit {
|
|
|
|
public:
|
|
|
|
Fl_Win32_At_Exit() { }
|
|
|
|
~Fl_Win32_At_Exit() {
|
|
|
|
fl_free_fonts(); // do some WIN32 cleanup
|
|
|
|
fl_cleanup_pens();
|
|
|
|
OleUninitialize();
|
|
|
|
fl_brush_action(1);
|
|
|
|
fl_cleanup_dc_list();
|
2014-10-09 16:52:05 +04:00
|
|
|
// This is actually too late in the cleanup process to remove the
|
|
|
|
// clipboard notifications, but we have no earlier hook so we try
|
|
|
|
// to work around it anyway.
|
|
|
|
if (clipboard_wnd != NULL)
|
|
|
|
fl_clipboard_notify_untarget(clipboard_wnd);
|
2014-09-15 13:35:05 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
static Fl_Win32_At_Exit win32_at_exit;
|
|
|
|
|
2014-09-15 13:44:35 +04:00
|
|
|
static char im_enabled = 1;
|
|
|
|
|
|
|
|
void Fl::enable_im() {
|
|
|
|
fl_open_display();
|
|
|
|
|
|
|
|
Fl_X* i = Fl_X::first;
|
|
|
|
while (i) {
|
|
|
|
flImmAssociateContextEx(i->xid, 0, IACE_DEFAULT);
|
|
|
|
i = i->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
im_enabled = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl::disable_im() {
|
|
|
|
fl_open_display();
|
|
|
|
|
|
|
|
Fl_X* i = Fl_X::first;
|
|
|
|
while (i) {
|
|
|
|
flImmAssociateContextEx(i->xid, 0, 0);
|
|
|
|
i = i->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
im_enabled = 0;
|
|
|
|
}
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void Fl::get_mouse(int &x, int &y) {
|
|
|
|
POINT p;
|
|
|
|
GetCursorPos(&p);
|
|
|
|
x = p.x;
|
|
|
|
y = p.y;
|
|
|
|
}
|
|
|
|
|
2002-03-07 22:22:58 +03:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// code used for selections:
|
|
|
|
|
2002-03-25 22:17:05 +03:00
|
|
|
char *fl_selection_buffer[2];
|
|
|
|
int fl_selection_length[2];
|
|
|
|
int fl_selection_buffer_length[2];
|
|
|
|
char fl_i_own_selection[2];
|
2002-03-07 22:22:58 +03:00
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
UINT fl_get_lcid_codepage(LCID id)
|
|
|
|
{
|
2009-02-21 13:18:47 +03:00
|
|
|
char buf[8];
|
|
|
|
buf[GetLocaleInfo(id, LOCALE_IDEFAULTANSICODEPAGE, buf, 8)] = 0;
|
|
|
|
return atol(buf);
|
2008-09-11 03:56:49 +04:00
|
|
|
}
|
|
|
|
|
2005-08-08 04:57:00 +04:00
|
|
|
// Convert \n -> \r\n
|
|
|
|
class Lf2CrlfConvert {
|
|
|
|
char *out;
|
|
|
|
int outlen;
|
|
|
|
public:
|
2005-08-22 02:05:48 +04:00
|
|
|
Lf2CrlfConvert(const char *in, int inlen) {
|
2005-08-08 04:57:00 +04:00
|
|
|
outlen = 0;
|
|
|
|
const char *i;
|
|
|
|
char *o;
|
2005-08-22 02:05:48 +04:00
|
|
|
int lencount;
|
2005-08-08 04:57:00 +04:00
|
|
|
// Predict size of \r\n conversion buffer
|
2005-08-22 02:05:48 +04:00
|
|
|
for ( i=in, lencount = inlen; lencount--; ) {
|
2005-08-08 04:57:00 +04:00
|
|
|
if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated
|
|
|
|
{ i+=2; outlen+=2; }
|
|
|
|
else if ( *i == '\n' ) // \n by itself? leave room to insert \r
|
|
|
|
{ i++; outlen+=2; }
|
|
|
|
else
|
|
|
|
{ ++i; ++outlen; }
|
|
|
|
}
|
|
|
|
// Alloc conversion buffer + NULL
|
|
|
|
out = new char[outlen+1];
|
|
|
|
// Handle \n -> \r\n conversion
|
2005-08-22 02:05:48 +04:00
|
|
|
for ( i=in, o=out, lencount = inlen; lencount--; ) {
|
2005-08-08 04:57:00 +04:00
|
|
|
if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated
|
|
|
|
{ *o++ = *i++; *o++ = *i++; }
|
|
|
|
else if ( *i == '\n' ) // \n by itself? insert \r
|
|
|
|
{ *o++ = '\r'; *o++ = *i++; }
|
|
|
|
else
|
|
|
|
{ *o++ = *i++; }
|
|
|
|
}
|
|
|
|
*o++ = 0;
|
|
|
|
}
|
|
|
|
~Lf2CrlfConvert() {
|
|
|
|
delete[] out;
|
|
|
|
}
|
|
|
|
int GetLength() const { return(outlen); }
|
|
|
|
const char* GetValue() const { return(out); }
|
|
|
|
};
|
|
|
|
|
2013-09-11 15:11:22 +04:00
|
|
|
void fl_update_clipboard(void) {
|
|
|
|
Fl_Window *w1 = Fl::first_window();
|
|
|
|
if (!w1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
HWND hwnd = fl_xid(w1);
|
|
|
|
|
|
|
|
if (!OpenClipboard(hwnd))
|
|
|
|
return;
|
|
|
|
|
|
|
|
EmptyClipboard();
|
|
|
|
|
|
|
|
int utf16_len = fl_utf8toUtf16(fl_selection_buffer[1],
|
|
|
|
fl_selection_length[1], 0, 0);
|
|
|
|
|
|
|
|
HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc.
|
|
|
|
LPVOID memLock = GlobalLock(hMem);
|
|
|
|
|
|
|
|
fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1],
|
|
|
|
(unsigned short*) memLock, utf16_len + 1);
|
|
|
|
|
|
|
|
GlobalUnlock(hMem);
|
|
|
|
SetClipboardData(CF_UNICODETEXT, hMem);
|
|
|
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
|
|
|
// In case Windows managed to lob of a WM_DESTROYCLIPBOARD during
|
|
|
|
// the above.
|
|
|
|
fl_i_own_selection[1] = 1;
|
|
|
|
}
|
|
|
|
|
2002-03-07 22:22:58 +03:00
|
|
|
// call this when you create a selection:
|
2014-05-23 20:47:21 +04:00
|
|
|
void Fl::copy(const char *stuff, int len, int clipboard, const char *type) {
|
2002-03-07 22:22:58 +03:00
|
|
|
if (!stuff || len<0) return;
|
2015-05-18 12:10:06 +03:00
|
|
|
if (clipboard >= 2)
|
|
|
|
clipboard = 1; // Only on X11 do multiple clipboards make sense.
|
2005-08-08 04:57:00 +04:00
|
|
|
|
|
|
|
// Convert \n -> \r\n (for old apps like Notepad, DOS)
|
2005-08-22 02:05:48 +04:00
|
|
|
Lf2CrlfConvert buf(stuff, len);
|
2005-08-08 04:57:00 +04:00
|
|
|
len = buf.GetLength();
|
|
|
|
stuff = buf.GetValue();
|
|
|
|
|
2002-03-25 22:17:05 +03:00
|
|
|
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;
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2002-03-25 22:17:05 +03:00
|
|
|
memcpy(fl_selection_buffer[clipboard], stuff, len);
|
|
|
|
fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
|
|
|
|
fl_selection_length[clipboard] = len;
|
2013-09-11 15:11:22 +04:00
|
|
|
fl_i_own_selection[clipboard] = 1;
|
|
|
|
if (clipboard)
|
|
|
|
fl_update_clipboard();
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Call this when a "paste" operation happens:
|
2014-05-23 20:47:21 +04:00
|
|
|
void Fl::paste(Fl_Widget &receiver, int clipboard, const char *type) {
|
|
|
|
if (!clipboard || (fl_i_own_selection[clipboard] && strcmp(type, Fl::clipboard_plain_text) == 0)) {
|
2002-03-07 22:22:58 +03:00
|
|
|
// We already have it, do it quickly without window server.
|
|
|
|
// Notice that the text is clobbered if set_selection is
|
|
|
|
// called in response to FL_PASTE!
|
2005-09-05 14:09:14 +04:00
|
|
|
char *i = fl_selection_buffer[clipboard];
|
|
|
|
if (i==0L) {
|
2016-01-28 20:38:11 +03:00
|
|
|
Fl::e_text = 0;
|
2005-09-05 14:09:14 +04:00
|
|
|
return;
|
|
|
|
}
|
2005-08-08 04:57:00 +04:00
|
|
|
Fl::e_text = new char[fl_selection_length[clipboard]+1];
|
2005-09-05 14:09:14 +04:00
|
|
|
char *o = Fl::e_text;
|
2014-05-23 20:47:21 +04:00
|
|
|
while (*i) { // Convert \r\n -> \n
|
2005-08-08 04:57:00 +04:00
|
|
|
if ( *i == '\r' && *(i+1) == '\n') i++;
|
|
|
|
else *o++ = *i++;
|
|
|
|
}
|
|
|
|
*o = 0;
|
2012-04-05 09:12:30 +04:00
|
|
|
Fl::e_length = (int) (o - Fl::e_text);
|
2014-05-23 20:47:21 +04:00
|
|
|
Fl::e_clipboard_type = Fl::clipboard_plain_text;
|
2002-03-07 22:22:58 +03:00
|
|
|
receiver.handle(FL_PASTE);
|
2005-08-08 04:57:00 +04:00
|
|
|
delete [] Fl::e_text;
|
|
|
|
Fl::e_text = 0;
|
2014-05-23 20:47:21 +04:00
|
|
|
} else if (clipboard) {
|
|
|
|
HANDLE h;
|
2002-03-07 22:22:58 +03:00
|
|
|
if (!OpenClipboard(NULL)) return;
|
2014-05-23 20:47:21 +04:00
|
|
|
if (strcmp(type, Fl::clipboard_plain_text) == 0) { // we want plain text from clipboard
|
|
|
|
if ((h = GetClipboardData(CF_UNICODETEXT))) { // there's text in the clipboard
|
|
|
|
wchar_t *memLock = (wchar_t*) GlobalLock(h);
|
|
|
|
size_t utf16_len = wcslen(memLock);
|
|
|
|
Fl::e_text = new char[utf16_len * 4 + 1];
|
|
|
|
unsigned utf8_len = fl_utf8fromwc(Fl::e_text, (unsigned) (utf16_len * 4), memLock, (unsigned) utf16_len);
|
|
|
|
*(Fl::e_text + utf8_len) = 0;
|
|
|
|
GlobalUnlock(h);
|
|
|
|
LPSTR a,b;
|
|
|
|
a = b = Fl::e_text;
|
|
|
|
while (*a) { // strip the CRLF pairs ($%$#@^)
|
|
|
|
if (*a == '\r' && a[1] == '\n') a++;
|
|
|
|
else *b++ = *a++;
|
|
|
|
}
|
|
|
|
*b = 0;
|
|
|
|
Fl::e_length = (int) (b - Fl::e_text);
|
|
|
|
Fl::e_clipboard_type = Fl::clipboard_plain_text; // indicates that the paste event is for plain UTF8 text
|
|
|
|
receiver.handle(FL_PASTE); // send the FL_PASTE event to the widget
|
|
|
|
delete[] Fl::e_text;
|
|
|
|
Fl::e_text = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp(type, Fl::clipboard_image) == 0) { // we want an image from clipboard
|
|
|
|
uchar *rgb = NULL;
|
|
|
|
int width, height, depth;
|
|
|
|
if ( (h = GetClipboardData(CF_DIB)) ) { // if there's a DIB in clipboard
|
|
|
|
LPBITMAPINFO lpBI = (LPBITMAPINFO)GlobalLock(h) ;
|
|
|
|
width = lpBI->bmiHeader.biWidth; // bitmap width & height
|
|
|
|
height = lpBI->bmiHeader.biHeight;
|
2016-01-28 20:38:11 +03:00
|
|
|
if ( (lpBI->bmiHeader.biBitCount == 24 || lpBI->bmiHeader.biBitCount == 32) &&
|
2014-05-23 20:47:21 +04:00
|
|
|
lpBI->bmiHeader.biCompression == BI_RGB &&
|
|
|
|
lpBI->bmiHeader.biClrUsed == 0) { // direct use of the DIB data if it's RGB or RGBA
|
|
|
|
int linewidth; // row length
|
|
|
|
depth = lpBI->bmiHeader.biBitCount/8; // 3 or 4
|
|
|
|
if (depth == 3) linewidth = 4 * ((3*width + 3)/4); // row length: series of groups of 3 bytes, rounded to multiple of 4 bytes
|
|
|
|
else linewidth = 4*width;
|
|
|
|
rgb = new uchar[width * height * depth]; // will hold the image data
|
|
|
|
uchar *p = rgb, *r, rr, gg, bb;
|
|
|
|
for (int i=height-1; i>=0; i--) { // for each row, from last to first
|
|
|
|
r = (uchar*)(lpBI->bmiColors) + i*linewidth; // beginning of pixel data for the ith row
|
|
|
|
for (int j=0; j<width; j++) { // for each pixel in a row
|
|
|
|
bb = *r++; // BGR is in DIB
|
|
|
|
gg = *r++;
|
|
|
|
rr = *r++;
|
|
|
|
*p++ = rr; // we want RGB
|
|
|
|
*p++ = gg;
|
|
|
|
*p++ = bb;
|
|
|
|
if (depth == 4) *p++ = *r++; // copy alpha if present
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // the system will decode a complex DIB
|
2016-01-28 20:38:11 +03:00
|
|
|
void *pDIBBits = (void*)(lpBI->bmiColors);
|
2014-05-23 20:47:21 +04:00
|
|
|
if (lpBI->bmiHeader.biCompression == BI_BITFIELDS) pDIBBits = (void*)(lpBI->bmiColors + 3);
|
|
|
|
else if (lpBI->bmiHeader.biClrUsed > 0) pDIBBits = (void*)(lpBI->bmiColors + lpBI->bmiHeader.biClrUsed);
|
|
|
|
Fl_Offscreen off = fl_create_offscreen(width, height);
|
|
|
|
fl_begin_offscreen(off);
|
2016-02-19 15:40:24 +03:00
|
|
|
SetDIBitsToDevice((HDC)fl_graphics_driver->gc(), 0, 0, width, height, 0, 0, 0, height, pDIBBits, lpBI, DIB_RGB_COLORS);
|
2014-05-23 20:47:21 +04:00
|
|
|
rgb = fl_read_image(NULL, 0, 0, width, height);
|
|
|
|
depth = 3;
|
|
|
|
fl_end_offscreen();
|
|
|
|
fl_delete_offscreen(off);
|
|
|
|
}
|
|
|
|
GlobalUnlock(h);
|
|
|
|
}
|
|
|
|
else if ((h = GetClipboardData(CF_ENHMETAFILE))) { // if there's an enhanced metafile in clipboard
|
|
|
|
ENHMETAHEADER header;
|
|
|
|
GetEnhMetaFileHeader((HENHMETAFILE)h, sizeof(header), &header); // get structure containing metafile dimensions
|
|
|
|
width = (header.rclFrame.right - header.rclFrame.left + 1); // in .01 mm units
|
|
|
|
height = (header.rclFrame.bottom - header.rclFrame.top + 1);
|
|
|
|
HDC hdc = GetDC(NULL); // get unit correspondance between .01 mm and screen pixels
|
|
|
|
int hmm = GetDeviceCaps(hdc, HORZSIZE);
|
|
|
|
int hdots = GetDeviceCaps(hdc, HORZRES);
|
|
|
|
int vmm = GetDeviceCaps(hdc, VERTSIZE);
|
|
|
|
int vdots = GetDeviceCaps(hdc, VERTRES);
|
|
|
|
ReleaseDC(NULL, hdc);
|
2016-01-29 23:50:04 +03:00
|
|
|
float factorw = (100.f * hmm) / hdots;
|
|
|
|
float factorh = (100.f * vmm) / vdots + 0.5f;
|
|
|
|
width = (int)(width/factorw); height = (int)(height/factorh); // convert to screen pixel unit
|
2014-05-23 20:47:21 +04:00
|
|
|
RECT rect = {0, 0, width, height};
|
|
|
|
Fl_Offscreen off = fl_create_offscreen(width, height);
|
|
|
|
fl_begin_offscreen(off);
|
|
|
|
fl_color(FL_WHITE); fl_rectf(0,0,width, height); // draw white background
|
2016-02-19 15:40:24 +03:00
|
|
|
PlayEnhMetaFile((HDC)fl_graphics_driver->gc(), (HENHMETAFILE)h, &rect); // draw metafile to offscreen buffer
|
2014-05-23 20:47:21 +04:00
|
|
|
rgb = fl_read_image(NULL, 0, 0, width, height); // read pixels from offscreen buffer
|
|
|
|
depth = 3;
|
|
|
|
fl_end_offscreen();
|
|
|
|
fl_delete_offscreen(off);
|
|
|
|
}
|
|
|
|
if (rgb) {
|
|
|
|
Fl_RGB_Image *image = new Fl_RGB_Image(rgb, width, height, depth); // create new image from pixel data
|
|
|
|
image->alloc_array = 1;
|
|
|
|
Fl::e_clipboard_data = image;
|
|
|
|
Fl::e_clipboard_type = Fl::clipboard_image; // indicates that the paste event is for image data
|
|
|
|
int done = receiver.handle(FL_PASTE); // send FL_PASTE event to widget
|
|
|
|
Fl::e_clipboard_type = "";
|
|
|
|
if (done == 0) { // if widget did not handle the event, delete the image
|
|
|
|
Fl::e_clipboard_data = NULL;
|
|
|
|
delete image;
|
|
|
|
}
|
|
|
|
}
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2014-05-23 20:47:21 +04:00
|
|
|
CloseClipboard();
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2014-05-23 20:47:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int Fl::clipboard_contains(const char *type)
|
|
|
|
{
|
|
|
|
int retval = 0;
|
|
|
|
if (!OpenClipboard(NULL)) return 0;
|
|
|
|
if (strcmp(type, Fl::clipboard_plain_text) == 0 || type[0] == 0) {
|
|
|
|
retval = IsClipboardFormatAvailable(CF_UNICODETEXT);
|
|
|
|
}
|
|
|
|
else if (strcmp(type, Fl::clipboard_image) == 0) {
|
|
|
|
retval = IsClipboardFormatAvailable(CF_DIB) || IsClipboardFormatAvailable(CF_ENHMETAFILE);
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2014-05-23 20:47:21 +04:00
|
|
|
CloseClipboard();
|
|
|
|
return retval;
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
|
|
|
|
2014-10-08 16:47:20 +04:00
|
|
|
static void fl_clipboard_notify_target(HWND wnd) {
|
2013-09-11 16:54:40 +04:00
|
|
|
if (clipboard_wnd)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We get one fake WM_DRAWCLIPBOARD immediately, which we therefore
|
|
|
|
// need to ignore.
|
|
|
|
initial_clipboard = true;
|
|
|
|
|
|
|
|
clipboard_wnd = wnd;
|
|
|
|
next_clipboard_wnd = SetClipboardViewer(wnd);
|
|
|
|
}
|
|
|
|
|
2014-10-08 16:47:20 +04:00
|
|
|
static void fl_clipboard_notify_untarget(HWND wnd) {
|
2013-09-11 16:54:40 +04:00
|
|
|
if (wnd != clipboard_wnd)
|
|
|
|
return;
|
|
|
|
|
2014-10-09 16:52:05 +04:00
|
|
|
// We might be called late in the cleanup where Windows has already
|
|
|
|
// implicitly destroyed our clipboard window. At that point we need
|
|
|
|
// to do some extra work to manually repair the clipboard chain.
|
|
|
|
if (IsWindow(wnd))
|
|
|
|
ChangeClipboardChain(wnd, next_clipboard_wnd);
|
|
|
|
else {
|
|
|
|
HWND tmp, head;
|
|
|
|
|
|
|
|
tmp = CreateWindow("STATIC", "Temporary FLTK Clipboard Window", 0,
|
|
|
|
0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
|
|
|
if (tmp == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
head = SetClipboardViewer(tmp);
|
|
|
|
if (head == NULL)
|
|
|
|
ChangeClipboardChain(tmp, next_clipboard_wnd);
|
|
|
|
else {
|
|
|
|
SendMessage(head, WM_CHANGECBCHAIN, (WPARAM)wnd, (LPARAM)next_clipboard_wnd);
|
|
|
|
ChangeClipboardChain(tmp, head);
|
|
|
|
}
|
|
|
|
|
|
|
|
DestroyWindow(tmp);
|
|
|
|
}
|
|
|
|
|
2013-09-11 16:54:40 +04:00
|
|
|
clipboard_wnd = next_clipboard_wnd = 0;
|
2014-10-08 16:47:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void fl_clipboard_notify_retarget(HWND wnd) {
|
|
|
|
// The given window is getting destroyed. If it's part of the
|
|
|
|
// clipboard chain then we need to unregister it and find a
|
|
|
|
// replacement window.
|
|
|
|
if (wnd != clipboard_wnd)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fl_clipboard_notify_untarget(wnd);
|
2013-09-11 16:54:40 +04:00
|
|
|
|
|
|
|
if (Fl::first_window())
|
|
|
|
fl_clipboard_notify_target(fl_xid(Fl::first_window()));
|
|
|
|
}
|
|
|
|
|
2014-10-08 16:47:20 +04:00
|
|
|
void fl_clipboard_notify_change() {
|
|
|
|
// untarget clipboard monitor if no handlers are registered
|
|
|
|
if (clipboard_wnd != NULL && fl_clipboard_notify_empty()) {
|
|
|
|
fl_clipboard_notify_untarget(clipboard_wnd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there are clipboard notify handlers but no window targeted
|
|
|
|
// target first window if available
|
|
|
|
if (clipboard_wnd == NULL && Fl::first_window())
|
|
|
|
fl_clipboard_notify_target(fl_xid(Fl::first_window()));
|
|
|
|
}
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
2008-09-11 03:56:49 +04:00
|
|
|
void fl_get_codepage()
|
|
|
|
{
|
2009-02-21 13:18:47 +03:00
|
|
|
HKL hkl = GetKeyboardLayout(0);
|
|
|
|
TCHAR ld[8];
|
|
|
|
|
|
|
|
GetLocaleInfo (LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6);
|
|
|
|
DWORD ccp = atol(ld);
|
|
|
|
fl_codepage = ccp;
|
2008-09-11 03:56:49 +04:00
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
|
1999-02-03 11:43:35 +03:00
|
|
|
HWND fl_capture;
|
1998-10-06 23:14:55 +04:00
|
|
|
|
|
|
|
static int mouse_event(Fl_Window *window, int what, int button,
|
2009-02-21 13:18:47 +03:00
|
|
|
WPARAM wParam, LPARAM lParam)
|
1998-10-06 23:14:55 +04:00
|
|
|
{
|
|
|
|
static int px, py, pmx, pmy;
|
|
|
|
POINT pt;
|
|
|
|
Fl::e_x = pt.x = (signed short)LOWORD(lParam);
|
|
|
|
Fl::e_y = pt.y = (signed short)HIWORD(lParam);
|
|
|
|
ClientToScreen(fl_xid(window), &pt);
|
|
|
|
Fl::e_x_root = pt.x;
|
|
|
|
Fl::e_y_root = pt.y;
|
2008-12-07 13:53:07 +03:00
|
|
|
#ifdef USE_CAPTURE_MOUSE_WIN
|
|
|
|
Fl_Window *mouse_window = window; // save "mouse window"
|
|
|
|
#endif
|
1998-10-06 23:14:55 +04:00
|
|
|
while (window->parent()) {
|
|
|
|
Fl::e_x += window->x();
|
|
|
|
Fl::e_y += window->y();
|
|
|
|
window = window->window();
|
|
|
|
}
|
|
|
|
|
|
|
|
ulong state = Fl::e_state & 0xff0000; // keep shift key states
|
|
|
|
#if 0
|
|
|
|
// mouse event reports some shift flags, perhaps save them?
|
|
|
|
if (wParam & MK_SHIFT) state |= FL_SHIFT;
|
|
|
|
if (wParam & MK_CONTROL) state |= FL_CTRL;
|
|
|
|
#endif
|
|
|
|
if (wParam & MK_LBUTTON) state |= FL_BUTTON1;
|
|
|
|
if (wParam & MK_MBUTTON) state |= FL_BUTTON2;
|
|
|
|
if (wParam & MK_RBUTTON) state |= FL_BUTTON3;
|
|
|
|
Fl::e_state = state;
|
|
|
|
|
|
|
|
switch (what) {
|
|
|
|
case 1: // double-click
|
|
|
|
if (Fl::e_is_click) {Fl::e_clicks++; goto J1;}
|
|
|
|
case 0: // single-click
|
|
|
|
Fl::e_clicks = 0;
|
|
|
|
J1:
|
2008-12-07 13:53:07 +03:00
|
|
|
#ifdef USE_CAPTURE_MOUSE_WIN
|
|
|
|
if (!fl_capture) SetCapture(fl_xid(mouse_window)); // use mouse window
|
|
|
|
#else
|
|
|
|
if (!fl_capture) SetCapture(fl_xid(window)); // use main window
|
|
|
|
#endif
|
1998-10-06 23:14:55 +04:00
|
|
|
Fl::e_keysym = FL_Button + button;
|
|
|
|
Fl::e_is_click = 1;
|
|
|
|
px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root;
|
|
|
|
return Fl::handle(FL_PUSH,window);
|
|
|
|
|
|
|
|
case 2: // release:
|
|
|
|
if (!fl_capture) ReleaseCapture();
|
|
|
|
Fl::e_keysym = FL_Button + button;
|
|
|
|
return Fl::handle(FL_RELEASE,window);
|
|
|
|
|
|
|
|
case 3: // move:
|
|
|
|
default: // avoid compiler warning
|
|
|
|
// MSWindows produces extra events even if mouse does not move, ignore em:
|
|
|
|
if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1;
|
|
|
|
pmx = Fl::e_x_root; pmy = Fl::e_y_root;
|
|
|
|
if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0;
|
|
|
|
return Fl::handle(FL_MOVE,window);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert a MSWindows VK_x to an Fltk (X) Keysym:
|
2001-11-22 18:35:02 +03:00
|
|
|
// See also the inverse converter in Fl_get_key_win32.cxx
|
1998-10-06 23:14:55 +04:00
|
|
|
// This table is in numeric order by VK:
|
1998-10-20 01:00:26 +04:00
|
|
|
static const struct {unsigned short vk, fltk, extended;} vktab[] = {
|
1998-10-06 23:14:55 +04:00
|
|
|
{VK_BACK, FL_BackSpace},
|
|
|
|
{VK_TAB, FL_Tab},
|
1999-04-23 10:55:53 +04:00
|
|
|
{VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/},
|
1998-10-20 01:00:26 +04:00
|
|
|
{VK_RETURN, FL_Enter, FL_KP_Enter},
|
|
|
|
{VK_SHIFT, FL_Shift_L, FL_Shift_R},
|
|
|
|
{VK_CONTROL, FL_Control_L, FL_Control_R},
|
|
|
|
{VK_MENU, FL_Alt_L, FL_Alt_R},
|
1998-10-06 23:14:55 +04:00
|
|
|
{VK_PAUSE, FL_Pause},
|
|
|
|
{VK_CAPITAL, FL_Caps_Lock},
|
|
|
|
{VK_ESCAPE, FL_Escape},
|
|
|
|
{VK_SPACE, ' '},
|
1998-10-20 01:00:26 +04:00
|
|
|
{VK_PRIOR, FL_KP+'9', FL_Page_Up},
|
|
|
|
{VK_NEXT, FL_KP+'3', FL_Page_Down},
|
|
|
|
{VK_END, FL_KP+'1', FL_End},
|
|
|
|
{VK_HOME, FL_KP+'7', FL_Home},
|
|
|
|
{VK_LEFT, FL_KP+'4', FL_Left},
|
|
|
|
{VK_UP, FL_KP+'8', FL_Up},
|
|
|
|
{VK_RIGHT, FL_KP+'6', FL_Right},
|
|
|
|
{VK_DOWN, FL_KP+'2', FL_Down},
|
1998-10-15 18:38:16 +04:00
|
|
|
{VK_SNAPSHOT, FL_Print}, // does not work on NT
|
1998-10-20 01:00:26 +04:00
|
|
|
{VK_INSERT, FL_KP+'0', FL_Insert},
|
|
|
|
{VK_DELETE, FL_KP+'.', FL_Delete},
|
1998-10-06 23:14:55 +04:00
|
|
|
{VK_LWIN, FL_Meta_L},
|
|
|
|
{VK_RWIN, FL_Meta_R},
|
|
|
|
{VK_APPS, FL_Menu},
|
2011-05-22 01:55:59 +04:00
|
|
|
{VK_SLEEP, FL_Sleep},
|
1998-10-06 23:14:55 +04:00
|
|
|
{VK_MULTIPLY, FL_KP+'*'},
|
|
|
|
{VK_ADD, FL_KP+'+'},
|
|
|
|
{VK_SUBTRACT, FL_KP+'-'},
|
|
|
|
{VK_DECIMAL, FL_KP+'.'},
|
|
|
|
{VK_DIVIDE, FL_KP+'/'},
|
|
|
|
{VK_NUMLOCK, FL_Num_Lock},
|
|
|
|
{VK_SCROLL, FL_Scroll_Lock},
|
2011-05-22 01:55:59 +04:00
|
|
|
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
|
|
|
|
{VK_BROWSER_BACK, FL_Back},
|
|
|
|
{VK_BROWSER_FORWARD, FL_Forward},
|
|
|
|
{VK_BROWSER_REFRESH, FL_Refresh},
|
|
|
|
{VK_BROWSER_STOP, FL_Stop},
|
|
|
|
{VK_BROWSER_SEARCH, FL_Search},
|
|
|
|
{VK_BROWSER_FAVORITES, FL_Favorites},
|
|
|
|
{VK_BROWSER_HOME, FL_Home_Page},
|
|
|
|
{VK_VOLUME_MUTE, FL_Volume_Mute},
|
|
|
|
{VK_VOLUME_DOWN, FL_Volume_Down},
|
|
|
|
{VK_VOLUME_UP, FL_Volume_Up},
|
|
|
|
{VK_MEDIA_NEXT_TRACK, FL_Media_Next},
|
|
|
|
{VK_MEDIA_PREV_TRACK, FL_Media_Prev},
|
|
|
|
{VK_MEDIA_STOP, FL_Media_Stop},
|
|
|
|
{VK_MEDIA_PLAY_PAUSE, FL_Media_Play},
|
|
|
|
{VK_LAUNCH_MAIL, FL_Mail},
|
|
|
|
#endif
|
1998-10-06 23:14:55 +04:00
|
|
|
{0xba, ';'},
|
|
|
|
{0xbb, '='},
|
|
|
|
{0xbc, ','},
|
|
|
|
{0xbd, '-'},
|
|
|
|
{0xbe, '.'},
|
|
|
|
{0xbf, '/'},
|
|
|
|
{0xc0, '`'},
|
|
|
|
{0xdb, '['},
|
|
|
|
{0xdc, '\\'},
|
|
|
|
{0xdd, ']'},
|
2012-03-26 20:54:54 +04:00
|
|
|
{0xde, '\''},
|
|
|
|
{VK_OEM_102, FL_Iso_Key}
|
1998-10-06 23:14:55 +04:00
|
|
|
};
|
2012-04-05 09:12:30 +04:00
|
|
|
static int ms2fltk(WPARAM vk, int extended) {
|
1998-10-06 23:14:55 +04:00
|
|
|
static unsigned short vklut[256];
|
1998-10-20 01:00:26 +04:00
|
|
|
static unsigned short extendedlut[256];
|
1998-10-06 23:14:55 +04:00
|
|
|
if (!vklut[1]) { // init the table
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 256; i++) vklut[i] = tolower(i);
|
|
|
|
for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1));
|
|
|
|
for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0);
|
1998-10-20 01:00:26 +04:00
|
|
|
for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) {
|
1998-10-06 23:14:55 +04:00
|
|
|
vklut[vktab[i].vk] = vktab[i].fltk;
|
1998-10-20 01:00:26 +04:00
|
|
|
extendedlut[vktab[i].vk] = vktab[i].extended;
|
1998-11-08 17:36:56 +03:00
|
|
|
}
|
1998-12-02 18:47:30 +03:00
|
|
|
for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i];
|
|
|
|
}
|
1998-10-20 01:00:26 +04:00
|
|
|
return extended ? extendedlut[vk] : vklut[vk];
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#if USE_COLORMAP
|
2001-11-22 18:35:02 +03:00
|
|
|
extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
|
1998-10-06 23:14:55 +04:00
|
|
|
#endif
|
|
|
|
|
2005-10-13 00:19:30 +04:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
static Fl_Window* resize_bug_fix;
|
|
|
|
|
2001-09-30 16:42:33 +04:00
|
|
|
extern void fl_save_pen(void);
|
|
|
|
extern void fl_restore_pen(void);
|
|
|
|
|
1999-03-29 21:39:46 +04:00
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
1998-10-06 23:14:55 +04:00
|
|
|
{
|
2002-04-16 11:47:31 +04:00
|
|
|
// Copy the message to fl_msg so add_handler code can see it, it is
|
|
|
|
// already there if this is called by DispatchMessage, but not if
|
|
|
|
// Windows calls this directly.
|
|
|
|
fl_msg.hwnd = hWnd;
|
1998-10-06 23:14:55 +04:00
|
|
|
fl_msg.message = uMsg;
|
2002-04-16 11:47:31 +04:00
|
|
|
fl_msg.wParam = wParam;
|
|
|
|
fl_msg.lParam = lParam;
|
|
|
|
//fl_msg.time = ???
|
|
|
|
//fl_msg.pt = ???
|
|
|
|
//fl_msg.lPrivate = ???
|
1998-10-06 23:14:55 +04:00
|
|
|
|
|
|
|
Fl_Window *window = fl_find(hWnd);
|
|
|
|
|
|
|
|
if (window) switch (uMsg) {
|
|
|
|
|
|
|
|
case WM_QUIT: // this should not happen?
|
|
|
|
Fl::fatal("WM_QUIT message");
|
|
|
|
|
|
|
|
case WM_CLOSE: // user clicked close box
|
|
|
|
Fl::handle(FL_CLOSE, window);
|
|
|
|
return 0;
|
|
|
|
|
2001-11-30 19:10:08 +03:00
|
|
|
case WM_SYNCPAINT :
|
|
|
|
case WM_NCPAINT :
|
|
|
|
case WM_ERASEBKGND :
|
|
|
|
// Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc
|
|
|
|
// so that Windows can generate the proper paint messages...
|
|
|
|
// Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too...
|
|
|
|
break;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
case WM_PAINT: {
|
2005-05-19 20:22:29 +04:00
|
|
|
Fl_Region R;
|
1998-10-15 18:06:16 +04:00
|
|
|
Fl_X *i = Fl_X::i(window);
|
1998-10-20 01:00:26 +04:00
|
|
|
i->wait_for_expose = 0;
|
2005-07-25 13:51:20 +04:00
|
|
|
char redraw_whole_window = false;
|
2002-10-29 23:18:55 +03:00
|
|
|
if (!i->region && window->damage()) {
|
|
|
|
// Redraw the whole window...
|
|
|
|
i->region = CreateRectRgn(0, 0, window->w(), window->h());
|
2005-07-25 13:51:20 +04:00
|
|
|
redraw_whole_window = true;
|
2005-05-19 20:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// We need to merge WIN32's damage into FLTK's damage.
|
|
|
|
R = CreateRectRgn(0,0,0,0);
|
2005-07-25 13:51:20 +04:00
|
|
|
int r = GetUpdateRgn(hWnd,R,0);
|
|
|
|
if (r==NULLREGION && !redraw_whole_window) {
|
2015-08-25 15:55:59 +03:00
|
|
|
XDestroyRegion(R);
|
2005-07-25 13:51:20 +04:00
|
|
|
break;
|
|
|
|
}
|
2005-05-19 20:22:29 +04:00
|
|
|
|
|
|
|
if (i->region) {
|
|
|
|
// Also tell WIN32 that we are drawing someplace else as well...
|
|
|
|
CombineRgn(i->region, i->region, R, RGN_OR);
|
|
|
|
XDestroyRegion(R);
|
2002-10-22 21:39:12 +04:00
|
|
|
} else {
|
2005-05-19 20:22:29 +04:00
|
|
|
i->region = R;
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
2007-05-16 16:47:49 +04:00
|
|
|
if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0);
|
|
|
|
else ValidateRgn(hWnd,i->region);
|
2005-05-19 20:22:29 +04:00
|
|
|
|
2002-11-19 19:37:36 +03:00
|
|
|
window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE));
|
2000-04-25 11:48:07 +04:00
|
|
|
// These next two statements should not be here, so that all update
|
2002-10-22 21:39:12 +04:00
|
|
|
// is deferred until Fl::flush() is called during idle. However WIN32
|
2000-04-25 11:48:07 +04:00
|
|
|
// apparently is very unhappy if we don't obey it and draw right now.
|
|
|
|
// Very annoying!
|
2002-07-02 00:14:08 +04:00
|
|
|
fl_GetDC(hWnd); // Make sure we have a DC for this window...
|
2001-09-30 16:42:33 +04:00
|
|
|
fl_save_pen();
|
1998-10-15 18:06:16 +04:00
|
|
|
i->flush();
|
2001-09-30 16:42:33 +04:00
|
|
|
fl_restore_pen();
|
1998-10-15 18:06:16 +04:00
|
|
|
window->clear_damage();
|
2002-01-23 19:58:01 +03:00
|
|
|
} return 0;
|
1998-10-06 23:14:55 +04:00
|
|
|
|
|
|
|
case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0;
|
|
|
|
case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0;
|
|
|
|
case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0;
|
|
|
|
case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0;
|
|
|
|
case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0;
|
|
|
|
case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0;
|
|
|
|
case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0;
|
|
|
|
case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0;
|
|
|
|
case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0;
|
|
|
|
|
2002-01-07 23:40:02 +03:00
|
|
|
case WM_MOUSEMOVE:
|
2002-02-20 22:29:57 +03:00
|
|
|
#ifdef USE_TRACK_MOUSE
|
2008-12-07 13:53:07 +03:00
|
|
|
if (track_mouse_win != window) {
|
2002-03-07 22:22:58 +03:00
|
|
|
TRACKMOUSEEVENT tme;
|
|
|
|
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
|
|
|
tme.dwFlags = TME_LEAVE;
|
|
|
|
tme.hwndTrack = hWnd;
|
|
|
|
_TrackMouseEvent(&tme);
|
2008-12-07 13:53:07 +03:00
|
|
|
track_mouse_win = window;
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2002-02-20 22:29:57 +03:00
|
|
|
#endif // USE_TRACK_MOUSE
|
2002-03-07 22:22:58 +03:00
|
|
|
mouse_event(window, 3, 0, wParam, lParam);
|
|
|
|
return 0;
|
2002-01-07 23:40:02 +03:00
|
|
|
|
1999-07-22 11:27:12 +04:00
|
|
|
case WM_MOUSELEAVE:
|
2008-12-07 13:53:07 +03:00
|
|
|
if (track_mouse_win == window) { // we left the top level window !
|
|
|
|
Fl_Window *tw = window;
|
|
|
|
while (tw->parent()) tw = tw->window(); // find top level window
|
|
|
|
Fl::belowmouse(0);
|
|
|
|
Fl::handle(FL_LEAVE, tw);
|
|
|
|
}
|
|
|
|
track_mouse_win = 0; // force TrackMouseEvent() restart
|
1999-07-22 11:27:12 +04:00
|
|
|
break;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
case WM_SETFOCUS:
|
2014-06-11 18:09:28 +04:00
|
|
|
if ((Fl::modal_) && (Fl::modal_ != window)) {
|
|
|
|
SetFocus(fl_xid(Fl::modal_));
|
|
|
|
return 0;
|
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
Fl::handle(FL_FOCUS, window);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_KILLFOCUS:
|
|
|
|
Fl::handle(FL_UNFOCUS, window);
|
|
|
|
Fl::flush(); // it never returns to main loop when deactivated...
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SHOWWINDOW:
|
2000-04-25 11:48:07 +04:00
|
|
|
if (!window->parent()) {
|
1998-10-06 23:14:55 +04:00
|
|
|
Fl::handle(wParam ? FL_SHOW : FL_HIDE, window);
|
2000-04-25 11:48:07 +04:00
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
break;
|
|
|
|
|
2001-04-27 18:39:27 +04:00
|
|
|
case WM_ACTIVATEAPP:
|
|
|
|
// From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP
|
|
|
|
// messages to restore the correct state of the shift/ctrl/alt/lock
|
2001-04-27 19:43:38 +04:00
|
|
|
// keys... Added control, shift, alt, and meta keys, and changed
|
|
|
|
// to use GetAsyncKeyState and do it when wParam is 1
|
|
|
|
// (that means we have focus...)
|
|
|
|
if (wParam)
|
2001-04-27 18:39:27 +04:00
|
|
|
{
|
|
|
|
ulong state = 0;
|
2001-04-27 19:21:33 +04:00
|
|
|
if (GetAsyncKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
|
|
|
|
if (GetAsyncKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
|
|
|
|
if (GetAsyncKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
|
2001-04-27 18:55:33 +04:00
|
|
|
if (GetAsyncKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
|
|
|
|
if (GetAsyncKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
|
2001-04-27 19:21:33 +04:00
|
|
|
if (GetAsyncKeyState(VK_MENU)) state |= FL_ALT;
|
2001-04-27 19:43:38 +04:00
|
|
|
if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META;
|
2001-04-27 18:39:27 +04:00
|
|
|
Fl::e_state = state;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
case WM_INPUTLANGCHANGE:
|
|
|
|
fl_get_codepage();
|
|
|
|
break;
|
|
|
|
case WM_IME_COMPOSITION:
|
|
|
|
// if (!fl_is_nt4() && lParam & GCS_RESULTCLAUSE) {
|
|
|
|
// HIMC himc = ImmGetContext(hWnd);
|
|
|
|
// wlen = ImmGetCompositionStringW(himc, GCS_RESULTSTR,
|
|
|
|
// wbuf, sizeof(wbuf)) / sizeof(short);
|
|
|
|
// if (wlen < 0) wlen = 0;
|
|
|
|
// wbuf[wlen] = 0;
|
|
|
|
// ImmReleaseContext(hWnd, himc);
|
|
|
|
// }
|
|
|
|
break;
|
1998-10-06 23:14:55 +04:00
|
|
|
case WM_KEYDOWN:
|
|
|
|
case WM_SYSKEYDOWN:
|
|
|
|
case WM_KEYUP:
|
|
|
|
case WM_SYSKEYUP:
|
1999-12-15 07:58:27 +03:00
|
|
|
// save the keysym until we figure out the characters:
|
2006-06-09 11:48:08 +04:00
|
|
|
Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam,lParam&(1<<24));
|
1999-12-15 07:58:27 +03:00
|
|
|
// See if TranslateMessage turned it into a WM_*CHAR message:
|
2008-09-11 03:56:49 +04:00
|
|
|
if (PeekMessageW(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE))
|
|
|
|
{
|
1998-10-06 23:14:55 +04:00
|
|
|
uMsg = fl_msg.message;
|
|
|
|
wParam = fl_msg.wParam;
|
|
|
|
lParam = fl_msg.lParam;
|
|
|
|
}
|
|
|
|
case WM_DEADCHAR:
|
|
|
|
case WM_SYSDEADCHAR:
|
|
|
|
case WM_CHAR:
|
2000-06-03 12:37:09 +04:00
|
|
|
case WM_SYSCHAR: {
|
|
|
|
ulong state = Fl::e_state & 0xff000000; // keep the mouse button state
|
|
|
|
// if GetKeyState is expensive we might want to comment some of these out:
|
|
|
|
if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
|
2001-04-27 19:21:33 +04:00
|
|
|
if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
|
2000-06-03 12:37:09 +04:00
|
|
|
if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
|
|
|
|
// Alt gets reported for the Alt-GR switch on foreign keyboards.
|
|
|
|
// so we need to check the event as well to get it right:
|
|
|
|
if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU)
|
1998-10-06 23:14:55 +04:00
|
|
|
&& uMsg != WM_CHAR) state |= FL_ALT;
|
2001-04-27 19:21:33 +04:00
|
|
|
if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
|
2001-04-27 19:43:38 +04:00
|
|
|
if ((GetKeyState(VK_LWIN)|GetKeyState(VK_RWIN))&~1) {
|
2000-06-03 12:37:09 +04:00
|
|
|
// WIN32 bug? GetKeyState returns garbage if the user hit the
|
|
|
|
// meta key to pop up start menu. Sigh.
|
2001-04-27 19:43:38 +04:00
|
|
|
if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1)
|
2000-06-03 12:37:09 +04:00
|
|
|
state |= FL_META;
|
|
|
|
}
|
2001-04-27 19:21:33 +04:00
|
|
|
if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
|
2000-06-03 12:37:09 +04:00
|
|
|
Fl::e_state = state;
|
2008-09-11 03:56:49 +04:00
|
|
|
static char buffer[1024];
|
1998-10-20 01:00:26 +04:00
|
|
|
if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
|
2008-09-11 03:56:49 +04:00
|
|
|
|
2009-02-21 13:18:47 +03:00
|
|
|
xchar u = (xchar) wParam;
|
|
|
|
// Fl::e_length = fl_unicode2utf(&u, 1, buffer);
|
|
|
|
Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
|
|
|
|
buffer[Fl::e_length] = 0;
|
2008-09-11 03:56:49 +04:00
|
|
|
|
|
|
|
|
2004-10-19 00:22:25 +04:00
|
|
|
} else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
|
|
|
|
if (state & FL_NUM_LOCK) {
|
|
|
|
// Convert to regular keypress...
|
|
|
|
buffer[0] = Fl::e_keysym-FL_KP;
|
|
|
|
Fl::e_length = 1;
|
|
|
|
} else {
|
|
|
|
// Convert to special keypress...
|
|
|
|
buffer[0] = 0;
|
|
|
|
Fl::e_length = 0;
|
|
|
|
switch (Fl::e_keysym) {
|
|
|
|
case FL_KP + '0' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Insert;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '1' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_End;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '2' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Down;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '3' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Page_Down;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '4' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Left;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '6' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Right;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '7' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Home;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '8' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Up;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '9' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Page_Up;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '.' :
|
2004-10-19 22:21:55 +04:00
|
|
|
Fl::e_keysym = FL_Delete;
|
2004-10-19 00:22:25 +04:00
|
|
|
break;
|
|
|
|
case FL_KP + '/' :
|
|
|
|
case FL_KP + '*' :
|
|
|
|
case FL_KP + '-' :
|
|
|
|
case FL_KP + '+' :
|
|
|
|
buffer[0] = Fl::e_keysym-FL_KP;
|
|
|
|
Fl::e_length = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-01-11 23:50:36 +03:00
|
|
|
} else if ((lParam & (1<<31))==0) {
|
|
|
|
#ifdef FLTK_PREVIEW_DEAD_KEYS
|
|
|
|
if ((lParam & (1<<24))==0) { // clear if dead key (always?)
|
2011-01-11 19:43:52 +03:00
|
|
|
xchar u = (xchar) wParam;
|
|
|
|
Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
|
|
|
|
buffer[Fl::e_length] = 0;
|
|
|
|
} else { // set if "extended key" (never printable?)
|
|
|
|
buffer[0] = 0;
|
|
|
|
Fl::e_length = 0;
|
|
|
|
}
|
2011-01-11 23:50:36 +03:00
|
|
|
#else
|
|
|
|
buffer[0] = 0;
|
|
|
|
Fl::e_length = 0;
|
|
|
|
#endif
|
1998-10-20 01:00:26 +04:00
|
|
|
}
|
|
|
|
Fl::e_text = buffer;
|
2006-06-09 11:48:08 +04:00
|
|
|
if (lParam & (1<<31)) { // key up events.
|
|
|
|
if (Fl::handle(FL_KEYUP, window)) return 0;
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 23:14:55 +04:00
|
|
|
// for (int i = lParam&0xff; i--;)
|
|
|
|
while (window->parent()) window = window->window();
|
2011-01-07 04:12:04 +03:00
|
|
|
if (Fl::handle(FL_KEYBOARD,window)) {
|
|
|
|
if (uMsg==WM_DEADCHAR || uMsg==WM_SYSDEADCHAR)
|
|
|
|
Fl::compose_state = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2000-06-03 12:37:09 +04:00
|
|
|
break;}
|
1998-10-06 23:14:55 +04:00
|
|
|
|
2001-08-03 00:09:25 +04:00
|
|
|
case WM_MOUSEWHEEL: {
|
|
|
|
static int delta = 0; // running total of all motion
|
|
|
|
delta += (SHORT)(HIWORD(wParam));
|
2012-06-21 12:52:29 +04:00
|
|
|
Fl::e_dx = 0;
|
2001-08-03 06:28:32 +04:00
|
|
|
Fl::e_dy = -delta / WHEEL_DELTA;
|
|
|
|
delta += Fl::e_dy * WHEEL_DELTA;
|
2001-08-03 00:09:25 +04:00
|
|
|
if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-21 12:52:29 +04:00
|
|
|
// This is only defined on Vista and upwards...
|
|
|
|
#ifndef WM_MOUSEHWHEEL
|
|
|
|
#define WM_MOUSEHWHEEL 0x020E
|
|
|
|
#endif
|
2016-01-28 20:38:11 +03:00
|
|
|
|
2012-06-21 12:52:29 +04:00
|
|
|
case WM_MOUSEHWHEEL: {
|
|
|
|
static int delta = 0; // running total of all motion
|
|
|
|
delta += (SHORT)(HIWORD(wParam));
|
|
|
|
Fl::e_dy = 0;
|
|
|
|
Fl::e_dx = delta / WHEEL_DELTA;
|
|
|
|
delta -= Fl::e_dx * WHEEL_DELTA;
|
|
|
|
if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
case WM_GETMINMAXINFO:
|
|
|
|
Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SIZE:
|
|
|
|
if (!window->parent()) {
|
|
|
|
if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) {
|
|
|
|
Fl::handle(FL_HIDE, window);
|
|
|
|
} else {
|
|
|
|
Fl::handle(FL_SHOW, window);
|
|
|
|
resize_bug_fix = window;
|
|
|
|
window->size(LOWORD(lParam), HIWORD(lParam));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2005-05-12 20:51:18 +04:00
|
|
|
case WM_MOVE: {
|
1998-10-06 23:14:55 +04:00
|
|
|
resize_bug_fix = window;
|
2005-05-12 18:08:02 +04:00
|
|
|
int nx = LOWORD(lParam);
|
|
|
|
int ny = HIWORD(lParam);
|
|
|
|
if (nx & 0x8000) nx -= 65536;
|
|
|
|
if (ny & 0x8000) ny -= 65536;
|
2005-05-12 20:51:18 +04:00
|
|
|
window->position(nx, ny); }
|
1998-10-06 23:14:55 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SETCURSOR:
|
|
|
|
if (LOWORD(lParam) == HTCLIENT) {
|
|
|
|
while (window->parent()) window = window->window();
|
|
|
|
SetCursor(Fl_X::i(window)->cursor);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
#if USE_COLORMAP
|
|
|
|
case WM_QUERYNEWPALETTE :
|
|
|
|
fl_GetDC(hWnd);
|
1998-11-08 20:02:40 +03:00
|
|
|
if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE);
|
1998-10-06 23:14:55 +04:00
|
|
|
break;
|
1999-03-29 21:39:46 +04:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
case WM_PALETTECHANGED:
|
2016-02-18 19:21:51 +03:00
|
|
|
//fl_GetDC(hWnd);
|
|
|
|
//if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc);
|
|
|
|
if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_GetDC(hWnd));
|
1998-10-06 23:14:55 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_CREATE :
|
|
|
|
fl_GetDC(hWnd);
|
1998-11-08 20:02:40 +03:00
|
|
|
fl_select_palette();
|
1998-10-06 23:14:55 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2002-03-07 22:22:58 +03:00
|
|
|
case WM_DESTROYCLIPBOARD:
|
2002-03-25 22:17:05 +03:00
|
|
|
fl_i_own_selection[1] = 0;
|
2002-03-07 22:22:58 +03:00
|
|
|
return 1;
|
|
|
|
|
2011-09-30 12:03:22 +04:00
|
|
|
case WM_DISPLAYCHANGE: // occurs when screen configuration (number, position) changes
|
2011-09-30 17:09:06 +04:00
|
|
|
Fl::call_screen_init();
|
2011-09-30 12:03:22 +04:00
|
|
|
Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL);
|
|
|
|
return 0;
|
2002-03-07 22:22:58 +03:00
|
|
|
|
2013-09-11 16:54:40 +04:00
|
|
|
case WM_CHANGECBCHAIN:
|
2014-06-10 18:21:26 +04:00
|
|
|
if ((hWnd == clipboard_wnd) && (next_clipboard_wnd == (HWND)wParam))
|
2013-09-11 16:54:40 +04:00
|
|
|
next_clipboard_wnd = (HWND)lParam;
|
2014-06-10 18:21:26 +04:00
|
|
|
else
|
|
|
|
SendMessage(next_clipboard_wnd, WM_CHANGECBCHAIN, wParam, lParam);
|
|
|
|
return 0;
|
2013-09-11 16:54:40 +04:00
|
|
|
|
|
|
|
case WM_DRAWCLIPBOARD:
|
|
|
|
// When the clipboard moves between two FLTK windows,
|
|
|
|
// fl_i_own_selection will temporarily be false as we are
|
|
|
|
// processing this message. Hence the need to use fl_find().
|
|
|
|
if (!initial_clipboard && !fl_find(GetClipboardOwner()))
|
|
|
|
fl_trigger_clipboard_notify(1);
|
|
|
|
initial_clipboard = false;
|
|
|
|
|
|
|
|
if (next_clipboard_wnd)
|
|
|
|
SendMessage(next_clipboard_wnd, WM_DRAWCLIPBOARD, wParam, lParam);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
default:
|
|
|
|
if (Fl::handle(0,0)) return 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
|
2009-02-21 13:18:47 +03:00
|
|
|
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
1998-11-05 19:04:53 +03:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// This function gets the dimensions of the top/left borders and
|
|
|
|
// the title bar, if there is one, based on the FL_BORDER, FL_MODAL
|
1999-03-29 21:39:46 +04:00
|
|
|
// and FL_NONMODAL flags, and on the window's size range.
|
1998-11-05 19:04:53 +03:00
|
|
|
// It returns the following values:
|
|
|
|
//
|
|
|
|
// value | border | title bar
|
|
|
|
// 0 | none | no
|
1998-11-08 17:36:56 +03:00
|
|
|
// 1 | fix | yes
|
|
|
|
// 2 | size | yes
|
1998-11-05 19:04:53 +03:00
|
|
|
|
2015-04-07 09:28:34 +03:00
|
|
|
static int fake_X_wm_style(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by, DWORD style, DWORD styleEx,
|
|
|
|
int w_maxw, int w_minw, int w_maxh, int w_minh, uchar w_size_range_set) {
|
1998-11-08 17:36:56 +03:00
|
|
|
int W, H, xoff, yoff, dx, dy;
|
|
|
|
int ret = bx = by = bt = 0;
|
2005-05-30 02:36:25 +04:00
|
|
|
|
|
|
|
int fallback = 1;
|
|
|
|
if (!w->parent()) {
|
2015-04-07 09:28:34 +03:00
|
|
|
if (fl_xid(w) || style) {
|
2005-05-30 02:36:25 +04:00
|
|
|
// The block below calculates the window borders by requesting the
|
|
|
|
// required decorated window rectangle for a desired client rectangle.
|
2016-01-28 20:38:11 +03:00
|
|
|
// If any part of the function above fails, we will drop to a
|
2005-05-30 02:36:25 +04:00
|
|
|
// fallback to get the best guess which is always available.
|
2016-01-28 20:38:11 +03:00
|
|
|
|
2015-04-07 09:28:34 +03:00
|
|
|
if (!style) {
|
|
|
|
HWND hwnd = fl_xid(w);
|
|
|
|
// request the style flags of this window, as WIN32 sees them
|
|
|
|
style = GetWindowLong(hwnd, GWL_STYLE);
|
|
|
|
styleEx = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
|
|
}
|
|
|
|
|
2005-05-30 02:36:25 +04:00
|
|
|
RECT r;
|
|
|
|
r.left = w->x();
|
|
|
|
r.top = w->y();
|
|
|
|
r.right = w->x()+w->w();
|
|
|
|
r.bottom = w->y()+w->h();
|
|
|
|
// get the decoration rectangle for the desired client rectangle
|
2015-04-07 09:28:34 +03:00
|
|
|
BOOL ok = AdjustWindowRectEx(&r, style, FALSE, styleEx);
|
2005-05-30 02:36:25 +04:00
|
|
|
if (ok) {
|
|
|
|
X = r.left;
|
|
|
|
Y = r.top;
|
|
|
|
W = r.right - r.left;
|
|
|
|
H = r.bottom - r.top;
|
|
|
|
bx = w->x() - r.left;
|
2016-01-10 22:08:16 +03:00
|
|
|
by = r.bottom - w->y() - w->h(); // height of the bottom frame
|
2005-08-22 02:28:57 +04:00
|
|
|
bt = w->y() - r.top - by; // height of top caption bar
|
2005-05-30 02:36:25 +04:00
|
|
|
xoff = bx;
|
|
|
|
yoff = by + bt;
|
|
|
|
dx = W - w->w();
|
|
|
|
dy = H - w->h();
|
2015-04-07 09:28:34 +03:00
|
|
|
if (w_size_range_set && (w_maxw != w_minw || w_maxh != w_minh))
|
2005-05-30 02:36:25 +04:00
|
|
|
ret = 2;
|
|
|
|
else
|
|
|
|
ret = 1;
|
|
|
|
fallback = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// This is the original (pre 1.1.7) routine to calculate window border sizes.
|
|
|
|
if (fallback) {
|
|
|
|
if (w->border() && !w->parent()) {
|
2015-04-07 09:28:34 +03:00
|
|
|
if (w_size_range_set && (w_maxw != w_minw || w_maxh != w_minh)) {
|
2014-10-08 15:57:43 +04:00
|
|
|
ret = 2;
|
|
|
|
bx = GetSystemMetrics(SM_CXSIZEFRAME);
|
|
|
|
by = GetSystemMetrics(SM_CYSIZEFRAME);
|
2005-05-30 02:36:25 +04:00
|
|
|
} else {
|
2014-10-08 15:57:43 +04:00
|
|
|
ret = 1;
|
|
|
|
int padding = GetSystemMetrics(SM_CXPADDEDBORDER);
|
|
|
|
NONCLIENTMETRICS ncm;
|
|
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
|
|
|
|
bx = GetSystemMetrics(SM_CXFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0);
|
|
|
|
by = GetSystemMetrics(SM_CYFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0);
|
2005-05-30 02:36:25 +04:00
|
|
|
}
|
|
|
|
bt = GetSystemMetrics(SM_CYCAPTION);
|
1998-11-08 17:36:56 +03:00
|
|
|
}
|
2005-05-30 02:36:25 +04:00
|
|
|
//The coordinates of the whole window, including non-client area
|
|
|
|
xoff = bx;
|
|
|
|
yoff = by + bt;
|
|
|
|
dx = 2*bx;
|
|
|
|
dy = 2*by + bt;
|
|
|
|
X = w->x()-xoff;
|
|
|
|
Y = w->y()-yoff;
|
|
|
|
W = w->w()+dx;
|
|
|
|
H = w->h()+dy;
|
1998-11-05 19:04:53 +03:00
|
|
|
}
|
1998-11-08 17:36:56 +03:00
|
|
|
|
|
|
|
//Proceed to positioning the window fully inside the screen, if possible
|
2011-08-19 18:11:30 +04:00
|
|
|
//Find screen that contains most of the window
|
|
|
|
//FIXME: this ought to be the "work area" instead of the entire screen !
|
2005-04-01 00:31:39 +04:00
|
|
|
int scr_x, scr_y, scr_w, scr_h;
|
2011-08-19 18:11:30 +04:00
|
|
|
Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y, W, H);
|
|
|
|
//Make border's lower right corner visible
|
2005-07-24 02:10:47 +04:00
|
|
|
if (scr_x+scr_w < X+W) X = scr_x+scr_w - W;
|
2005-04-01 00:31:39 +04:00
|
|
|
if (scr_y+scr_h < Y+H) Y = scr_y+scr_h - H;
|
1998-11-08 17:36:56 +03:00
|
|
|
//Make border's upper left corner visible
|
2005-04-01 00:31:39 +04:00
|
|
|
if (X<scr_x) X = scr_x;
|
|
|
|
if (Y<scr_y) Y = scr_y;
|
1998-11-08 17:36:56 +03:00
|
|
|
//Make client area's lower right corner visible
|
2005-04-01 00:31:39 +04:00
|
|
|
if (scr_x+scr_w < X+dx+ w->w()) X = scr_x+scr_w - w->w() - dx;
|
|
|
|
if (scr_y+scr_h < Y+dy+ w->h()) Y = scr_y+scr_h - w->h() - dy;
|
1998-11-08 17:36:56 +03:00
|
|
|
//Make client area's upper left corner visible
|
2005-04-01 00:31:39 +04:00
|
|
|
if (X+xoff < scr_x) X = scr_x-xoff;
|
|
|
|
if (Y+yoff < scr_y) Y = scr_y-yoff;
|
1998-11-08 17:36:56 +03:00
|
|
|
//Return the client area's top left corner in (X,Y)
|
|
|
|
X+=xoff;
|
|
|
|
Y+=yoff;
|
|
|
|
|
2012-04-09 13:12:34 +04:00
|
|
|
if (w->fullscreen_active()) {
|
2012-03-23 20:47:53 +04:00
|
|
|
bx = by = bt = 0;
|
|
|
|
}
|
|
|
|
|
1998-11-05 19:04:53 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-04-07 09:28:34 +03:00
|
|
|
int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) {
|
2015-12-31 13:39:51 +03:00
|
|
|
return fake_X_wm_style(w, X, Y, bt, bx, by, 0, 0, w->maxw, w->minw, w->maxh, w->minh, w->size_range_set);
|
2015-04-07 09:28:34 +03:00
|
|
|
}
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-03-23 00:21:08 +03:00
|
|
|
void Fl_WinAPI_Window_Driver::resize(int X,int Y,int W,int H) {
|
2016-01-28 20:38:11 +03:00
|
|
|
UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER
|
2005-06-01 13:26:16 +04:00
|
|
|
| SWP_NOACTIVATE | SWP_NOOWNERZORDER;
|
2016-03-24 04:20:08 +03:00
|
|
|
int is_a_resize = (W != w() || H != h());
|
2016-03-23 00:21:08 +03:00
|
|
|
int resize_from_program = (pWindow != resize_bug_fix);
|
1998-10-20 01:00:26 +04:00
|
|
|
if (!resize_from_program) resize_bug_fix = 0;
|
2016-03-24 04:20:08 +03:00
|
|
|
if (X != x() || Y != y()) {
|
2009-12-24 14:40:26 +03:00
|
|
|
force_position(1);
|
2002-04-10 01:17:01 +04:00
|
|
|
} else {
|
|
|
|
if (!is_a_resize) return;
|
|
|
|
flags |= SWP_NOMOVE;
|
|
|
|
}
|
1998-10-20 01:00:26 +04:00
|
|
|
if (is_a_resize) {
|
2016-03-23 00:21:08 +03:00
|
|
|
pWindow->Fl_Group::resize(X,Y,W,H);
|
2016-03-24 04:20:08 +03:00
|
|
|
if (visible_r()) {
|
2016-03-23 00:21:08 +03:00
|
|
|
pWindow->redraw();
|
2016-01-28 20:38:11 +03:00
|
|
|
// only wait for exposure if this window has a size - a window
|
2007-12-20 19:22:53 +03:00
|
|
|
// with no width or height will never get an exposure event
|
2016-03-23 00:21:08 +03:00
|
|
|
Fl_X *i = Fl_X::i(pWindow);
|
2008-01-11 00:53:34 +03:00
|
|
|
if (i && W>0 && H>0)
|
2007-12-20 19:22:53 +03:00
|
|
|
i->wait_for_expose = 1;
|
|
|
|
}
|
1998-10-20 01:00:26 +04:00
|
|
|
} else {
|
|
|
|
x(X); y(Y);
|
1998-11-08 17:36:56 +03:00
|
|
|
flags |= SWP_NOSIZE;
|
1998-10-20 01:00:26 +04:00
|
|
|
}
|
2016-03-24 04:20:08 +03:00
|
|
|
if (!border()) flags |= SWP_NOACTIVATE;
|
|
|
|
if (resize_from_program && shown()) {
|
|
|
|
if (!pWindow->resizable()) pWindow->size_range(w(), h(), w(), h());
|
2005-05-30 02:36:25 +04:00
|
|
|
int dummy_x, dummy_y, bt, bx, by;
|
1998-11-08 17:36:56 +03:00
|
|
|
//Ignore window managing when resizing, so that windows (and more
|
|
|
|
//specifically menus) can be moved offscreen.
|
2016-03-23 00:21:08 +03:00
|
|
|
if (Fl_X::fake_X_wm(pWindow, dummy_x, dummy_y, bt, bx, by)) {
|
1998-11-05 19:04:53 +03:00
|
|
|
X -= bx;
|
|
|
|
Y -= by+bt;
|
|
|
|
W += 2*bx;
|
|
|
|
H += 2*by+bt;
|
1998-11-08 17:36:56 +03:00
|
|
|
}
|
2006-08-23 15:47:58 +04:00
|
|
|
// avoid zero size windows. A zero sized window on Win32
|
|
|
|
// will cause continouly new redraw events.
|
|
|
|
if (W<=0) W = 1;
|
|
|
|
if (H<=0) H = 1;
|
2016-03-23 00:21:08 +03:00
|
|
|
SetWindowPos(fl_xid(pWindow), 0, X, Y, W, H, flags);
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 20:47:53 +04:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2005-09-14 11:30:32 +04:00
|
|
|
/*
|
2016-01-28 20:38:11 +03:00
|
|
|
* This silly little class remembers the name of all window classes
|
|
|
|
* we register to avoid double registration. It has the added bonus
|
2009-02-21 13:18:47 +03:00
|
|
|
* of freeing everything on application close as well.
|
2005-09-14 11:30:32 +04:00
|
|
|
*/
|
|
|
|
class NameList {
|
|
|
|
public:
|
|
|
|
NameList() { name = (char**)malloc(sizeof(char**)); NName = 1; nName = 0; }
|
2016-01-28 20:38:11 +03:00
|
|
|
~NameList() {
|
2005-09-14 11:30:32 +04:00
|
|
|
int i;
|
|
|
|
for (i=0; i<nName; i++) free(name[i]);
|
2016-01-28 20:38:11 +03:00
|
|
|
if (name) free(name);
|
2005-09-14 11:30:32 +04:00
|
|
|
}
|
|
|
|
void add_name(const char *n) {
|
|
|
|
if (NName==nName) {
|
|
|
|
NName += 5;
|
|
|
|
name = (char**)realloc(name, NName * sizeof(char*));
|
|
|
|
}
|
|
|
|
name[nName++] = strdup(n);
|
|
|
|
}
|
|
|
|
char has_name(const char *n) {
|
|
|
|
int i;
|
|
|
|
for (i=0; i<nName; i++) {
|
|
|
|
if (strcmp(name[i], n)==0) return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
char **name;
|
|
|
|
int nName, NName;
|
|
|
|
};
|
|
|
|
|
2001-11-22 18:35:02 +03:00
|
|
|
void fl_fix_focus(); // in Fl.cxx
|
1999-03-03 10:40:18 +03:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
// int fl_background_pixel = -1; // color to use for background
|
2002-07-02 00:14:08 +04:00
|
|
|
UINT fl_wake_msg = 0;
|
1998-10-06 23:14:55 +04:00
|
|
|
int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
|
|
|
|
|
|
|
|
Fl_X* Fl_X::make(Fl_Window* w) {
|
|
|
|
Fl_Group::current(0); // get rid of very common user bug: forgot end()
|
|
|
|
|
2014-09-15 13:35:05 +04:00
|
|
|
fl_open_display();
|
|
|
|
|
2007-06-18 17:08:57 +04:00
|
|
|
// if the window is a subwindow and our parent is not mapped yet, we
|
|
|
|
// mark this window visible, so that mapping the parent at a later
|
|
|
|
// point in time will call this function again to finally map the subwindow.
|
|
|
|
if (w->parent() && !Fl_X::i(w->window())) {
|
|
|
|
w->set_visible();
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
2005-09-14 11:30:32 +04:00
|
|
|
static NameList class_name_list;
|
2005-07-24 23:08:31 +04:00
|
|
|
static const char *first_class_name = 0L;
|
|
|
|
const char *class_name = w->xclass();
|
|
|
|
if (!class_name) class_name = first_class_name; // reuse first class name used
|
|
|
|
if (!class_name) class_name = "FLTK"; // default to create a "FLTK" WNDCLASS
|
|
|
|
if (!first_class_name) {
|
|
|
|
first_class_name = class_name;
|
|
|
|
}
|
1999-01-04 22:25:40 +03:00
|
|
|
|
2010-09-09 19:59:20 +04:00
|
|
|
wchar_t class_namew[100]; // (limited) buffer for Windows class name
|
|
|
|
|
|
|
|
// convert UTF-8 class_name to wchar_t for RegisterClassExW and CreateWindowExW
|
|
|
|
|
2012-04-05 09:12:30 +04:00
|
|
|
fl_utf8toUtf16(class_name,
|
|
|
|
(unsigned)strlen(class_name), // in
|
2010-09-09 19:59:20 +04:00
|
|
|
(unsigned short*)class_namew, // out
|
2012-04-05 09:12:30 +04:00
|
|
|
(unsigned)sizeof(class_namew)/sizeof(wchar_t)); // max. size
|
2010-09-09 19:59:20 +04:00
|
|
|
|
2005-09-14 11:30:32 +04:00
|
|
|
if (!class_name_list.has_name(class_name)) {
|
2009-02-21 13:01:57 +03:00
|
|
|
WNDCLASSEXW wcw;
|
2008-09-11 03:56:49 +04:00
|
|
|
memset(&wcw, 0, sizeof(wcw));
|
|
|
|
wcw.cbSize = sizeof(WNDCLASSEXW);
|
|
|
|
|
2005-09-13 03:03:34 +04:00
|
|
|
// Documentation states a device context consumes about 800 bytes
|
|
|
|
// of memory... so who cares? If 800 bytes per window is what it
|
|
|
|
// takes to speed things up, I'm game.
|
|
|
|
//wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
|
2008-09-11 03:56:49 +04:00
|
|
|
wcw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
|
|
|
|
wcw.lpfnWndProc = (WNDPROC)WndProc;
|
|
|
|
wcw.cbClsExtra = wcw.cbWndExtra = 0;
|
|
|
|
wcw.hInstance = fl_display;
|
2016-03-22 16:27:22 +03:00
|
|
|
if (!w->icon() && !((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->count)
|
2005-09-13 03:03:34 +04:00
|
|
|
w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
|
2008-09-11 03:56:49 +04:00
|
|
|
wcw.hIcon = wcw.hIconSm = (HICON)w->icon();
|
2014-06-16 15:17:57 +04:00
|
|
|
wcw.hCursor = LoadCursor(NULL, IDC_ARROW);
|
2005-09-13 03:03:34 +04:00
|
|
|
//uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
|
|
|
|
//wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
|
2008-09-11 03:56:49 +04:00
|
|
|
wcw.hbrBackground = NULL;
|
|
|
|
wcw.lpszMenuName = NULL;
|
|
|
|
wcw.lpszClassName = class_namew;
|
|
|
|
RegisterClassExW(&wcw);
|
2010-09-09 19:59:20 +04:00
|
|
|
class_name_list.add_name(class_name);
|
2009-02-21 13:01:57 +03:00
|
|
|
}
|
2005-09-14 11:30:32 +04:00
|
|
|
|
2010-09-09 19:59:20 +04:00
|
|
|
const wchar_t* message_namew = L"FLTK::ThreadWakeup";
|
2009-02-21 13:01:57 +03:00
|
|
|
if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessageW(message_namew);
|
1998-10-06 23:14:55 +04:00
|
|
|
|
|
|
|
HWND parent;
|
1998-11-05 19:04:53 +03:00
|
|
|
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
|
|
|
DWORD styleEx = WS_EX_LEFT;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
int xp = w->x();
|
|
|
|
int yp = w->y();
|
|
|
|
int wp = w->w();
|
|
|
|
int hp = w->h();
|
|
|
|
|
2000-04-25 11:48:07 +04:00
|
|
|
int showit = 1;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
if (w->parent()) {
|
2000-02-04 09:35:22 +03:00
|
|
|
style |= WS_CHILD;
|
|
|
|
styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
|
1998-10-06 23:14:55 +04:00
|
|
|
parent = fl_xid(w->window());
|
|
|
|
} else {
|
|
|
|
if (!w->size_range_set) {
|
|
|
|
if (w->resizable()) {
|
|
|
|
Fl_Widget *o = w->resizable();
|
|
|
|
int minw = o->w(); if (minw > 100) minw = 100;
|
|
|
|
int minh = o->h(); if (minh > 100) minh = 100;
|
|
|
|
w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0);
|
|
|
|
} else {
|
|
|
|
w->size_range(w->w(), w->h(), w->w(), w->h());
|
|
|
|
}
|
|
|
|
}
|
1998-11-05 19:04:53 +03:00
|
|
|
styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
|
2015-04-07 09:28:34 +03:00
|
|
|
|
|
|
|
int wintype = 0;
|
|
|
|
if (w->border() && !w->parent()) {
|
|
|
|
if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) wintype = 2;
|
|
|
|
else wintype = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (wintype) {
|
2002-04-30 00:18:01 +04:00
|
|
|
// No border (used for menus)
|
2012-03-23 20:47:53 +04:00
|
|
|
case 0:
|
|
|
|
style |= WS_POPUP;
|
|
|
|
styleEx |= WS_EX_TOOLWINDOW;
|
2002-04-30 00:18:01 +04:00
|
|
|
break;
|
1998-11-05 19:04:53 +03:00
|
|
|
|
|
|
|
// Thin border and title bar
|
2012-03-23 20:47:53 +04:00
|
|
|
case 1:
|
|
|
|
style |= WS_DLGFRAME | WS_CAPTION;
|
|
|
|
if (!w->modal())
|
|
|
|
style |= WS_SYSMENU | WS_MINIMIZEBOX;
|
|
|
|
break;
|
1998-11-05 19:04:53 +03:00
|
|
|
|
|
|
|
// Thick, resizable border and title bar, with maximize button
|
2012-03-23 20:47:53 +04:00
|
|
|
case 2:
|
|
|
|
style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION;
|
|
|
|
if (!w->modal())
|
|
|
|
style |= WS_MINIMIZEBOX;
|
|
|
|
break;
|
1998-11-08 17:36:56 +03:00
|
|
|
}
|
2015-04-07 09:28:34 +03:00
|
|
|
|
|
|
|
int xwm = xp , ywm = yp , bt, bx, by;
|
|
|
|
fake_X_wm_style(w, xwm, ywm, bt, bx, by, style, styleEx, w->maxw, w->minw, w->maxh, w->minh, w->size_range_set);
|
1998-11-08 17:36:56 +03:00
|
|
|
if (by+bt) {
|
|
|
|
wp += 2*bx;
|
|
|
|
hp += 2*by+bt;
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
2009-12-24 14:40:26 +03:00
|
|
|
if (!w->force_position()) {
|
1998-10-06 23:14:55 +04:00
|
|
|
xp = yp = CW_USEDEFAULT;
|
1998-11-05 19:04:53 +03:00
|
|
|
} else {
|
1998-11-08 17:36:56 +03:00
|
|
|
if (!Fl::grab()) {
|
|
|
|
xp = xwm; yp = ywm;
|
|
|
|
w->x(xp);w->y(yp);
|
|
|
|
}
|
1998-11-05 19:04:53 +03:00
|
|
|
xp -= bx;
|
|
|
|
yp -= by+bt;
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
1998-11-05 19:04:53 +03:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
parent = 0;
|
1999-01-07 19:43:04 +03:00
|
|
|
if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) {
|
1998-10-06 23:14:55 +04:00
|
|
|
// find some other window to be "transient for":
|
1999-01-07 19:43:04 +03:00
|
|
|
Fl_Window* w = Fl_X::first->w;
|
|
|
|
while (w->parent()) w = w->window();
|
|
|
|
parent = fl_xid(w);
|
2000-04-25 11:48:07 +04:00
|
|
|
if (!w->visible()) showit = 0;
|
2001-08-03 19:48:20 +04:00
|
|
|
} else if (Fl::grab()) parent = fl_xid(Fl::grab());
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
2016-03-08 00:56:12 +03:00
|
|
|
Fl_X *x = new Fl_X;
|
1998-10-06 23:14:55 +04:00
|
|
|
x->other_xid = 0;
|
|
|
|
x->setwindow(w);
|
|
|
|
x->region = 0;
|
|
|
|
x->private_dc = 0;
|
2014-06-16 15:17:57 +04:00
|
|
|
x->cursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
x->custom_cursor = 0;
|
2008-09-11 03:56:49 +04:00
|
|
|
if (!fl_codepage) fl_get_codepage();
|
|
|
|
|
2009-02-21 13:01:57 +03:00
|
|
|
WCHAR *lab = NULL;
|
|
|
|
if (w->label()) {
|
2012-04-05 09:12:30 +04:00
|
|
|
size_t l = strlen(w->label());
|
2009-02-21 13:18:47 +03:00
|
|
|
// lab = (WCHAR*) malloc((l + 1) * sizeof(short));
|
|
|
|
// l = fl_utf2unicode((unsigned char*)w->label(), l, (xchar*)lab);
|
|
|
|
// lab[l] = 0;
|
2012-04-05 09:12:30 +04:00
|
|
|
unsigned wlen = fl_utf8toUtf16(w->label(), (unsigned) l, NULL, 0); // Pass NULL to query length
|
2009-02-21 13:01:57 +03:00
|
|
|
wlen++;
|
|
|
|
lab = (WCHAR *) malloc(sizeof(WCHAR)*wlen);
|
2012-04-05 09:12:30 +04:00
|
|
|
wlen = fl_utf8toUtf16(w->label(), (unsigned) l, (unsigned short*)lab, wlen);
|
2009-02-21 13:01:57 +03:00
|
|
|
lab[wlen] = 0;
|
|
|
|
}
|
|
|
|
x->xid = CreateWindowExW(
|
1998-10-06 23:14:55 +04:00
|
|
|
styleEx,
|
2009-02-21 13:01:57 +03:00
|
|
|
class_namew, lab, style,
|
1998-10-06 23:14:55 +04:00
|
|
|
xp, yp, wp, hp,
|
|
|
|
parent,
|
|
|
|
NULL, // menu
|
|
|
|
fl_display,
|
|
|
|
NULL // creation parameters
|
2009-02-21 13:01:57 +03:00
|
|
|
);
|
|
|
|
if (lab) free(lab);
|
2008-09-11 03:56:49 +04:00
|
|
|
|
2014-10-20 19:14:12 +04:00
|
|
|
x->next = Fl_X::first;
|
|
|
|
Fl_X::first = x;
|
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
x->set_icons();
|
|
|
|
|
2012-04-09 13:12:34 +04:00
|
|
|
if (w->fullscreen_active()) {
|
2012-03-23 20:47:53 +04:00
|
|
|
/* We need to make sure that the fullscreen is created on the
|
|
|
|
default monitor, ie the desktop where the shortcut is located
|
|
|
|
etc. This requires that CreateWindow is called with CW_USEDEFAULT
|
|
|
|
for x and y. We can then use GetWindowRect to determine which
|
|
|
|
monitor the window was placed on. */
|
|
|
|
RECT rect;
|
|
|
|
GetWindowRect(x->xid, &rect);
|
2016-01-28 20:38:11 +03:00
|
|
|
x->make_fullscreen(rect.left, rect.top,
|
2014-06-11 13:10:53 +04:00
|
|
|
rect.right - rect.left, rect.bottom - rect.top);
|
2012-03-23 20:47:53 +04:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:23:46 +04:00
|
|
|
// Setup clipboard monitor target if there are registered handlers and
|
|
|
|
// no window is targeted.
|
|
|
|
if (!fl_clipboard_notify_empty() && clipboard_wnd == NULL)
|
|
|
|
fl_clipboard_notify_target(x->xid);
|
2013-09-11 16:54:40 +04:00
|
|
|
|
1998-10-20 01:00:26 +04:00
|
|
|
x->wait_for_expose = 1;
|
2016-03-23 21:00:37 +03:00
|
|
|
if (Fl_Window::show_iconic_) {showit = 0; Fl_Window::show_iconic_ = 0;}
|
2000-04-25 11:48:07 +04:00
|
|
|
if (showit) {
|
|
|
|
w->set_visible();
|
2004-12-03 06:14:17 +03:00
|
|
|
int old_event = Fl::e_number;
|
|
|
|
w->handle(Fl::e_number = FL_SHOW); // get child windows to appear
|
|
|
|
Fl::e_number = old_event;
|
2000-04-25 11:48:07 +04:00
|
|
|
w->redraw(); // force draw to happen
|
|
|
|
}
|
2014-06-11 18:09:28 +04:00
|
|
|
|
|
|
|
// Needs to be done before ShowWindow() to get the correct behaviour
|
|
|
|
// when we get WM_SETFOCUS.
|
|
|
|
if (w->modal()) {Fl::modal_ = w; fl_fix_focus();}
|
|
|
|
|
2006-06-28 14:23:33 +04:00
|
|
|
// If we've captured the mouse, we dont want to activate any
|
2011-04-24 21:09:41 +04:00
|
|
|
// other windows from the code, or we lose the capture.
|
2000-04-25 11:48:07 +04:00
|
|
|
ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
|
2012-03-23 20:47:53 +04:00
|
|
|
(Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
|
2002-04-10 19:01:22 +04:00
|
|
|
|
|
|
|
// Register all windows for potential drag'n'drop operations
|
2002-05-02 00:05:19 +04:00
|
|
|
RegisterDragDrop(x->xid, flIDropTarget);
|
2010-09-27 18:57:53 +04:00
|
|
|
|
2014-09-15 13:44:35 +04:00
|
|
|
if (!im_enabled)
|
|
|
|
flImmAssociateContextEx(x->xid, 0, 0);
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2005-10-13 00:19:30 +04:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-05-24 18:03:47 +04:00
|
|
|
HINSTANCE fl_display = GetModuleHandle(NULL);
|
1999-01-04 22:25:40 +03:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
void Fl_X::set_minmax(LPMINMAXINFO minmax)
|
|
|
|
{
|
2005-05-30 02:36:25 +04:00
|
|
|
int td, wd, hd, dummy_x, dummy_y;
|
1998-11-05 19:04:53 +03:00
|
|
|
|
2005-05-30 02:36:25 +04:00
|
|
|
fake_X_wm(w, dummy_x, dummy_y, td, wd, hd);
|
1998-11-05 19:04:53 +03:00
|
|
|
wd *= 2;
|
|
|
|
hd *= 2;
|
|
|
|
hd += td;
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
minmax->ptMinTrackSize.x = w->minw + wd;
|
|
|
|
minmax->ptMinTrackSize.y = w->minh + hd;
|
|
|
|
if (w->maxw) {
|
|
|
|
minmax->ptMaxTrackSize.x = w->maxw + wd;
|
|
|
|
minmax->ptMaxSize.x = w->maxw + wd;
|
|
|
|
}
|
|
|
|
if (w->maxh) {
|
|
|
|
minmax->ptMaxTrackSize.y = w->maxh + hd;
|
|
|
|
minmax->ptMaxSize.y = w->maxh + hd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-03-26 00:08:42 +03:00
|
|
|
#include <FL/filename.H> // need so FL_EXPORT fl_filename_name works
|
1999-05-11 13:39:31 +04:00
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
// returns pointer to the filename, or null if name ends with '/'
|
2002-03-26 00:08:42 +03:00
|
|
|
const char *fl_filename_name(const char *name) {
|
1998-10-06 23:14:55 +04:00
|
|
|
const char *p,*q;
|
2002-04-07 22:31:55 +04:00
|
|
|
if (!name) return (0);
|
1998-10-06 23:14:55 +04:00
|
|
|
q = name;
|
|
|
|
if (q[0] && q[1]==':') q += 2; // skip leading drive letter
|
|
|
|
for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 15:17:57 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
static HICON image_to_icon(const Fl_RGB_Image *image, bool is_icon,
|
|
|
|
int hotx, int hoty) {
|
2014-06-16 15:17:57 +04:00
|
|
|
BITMAPV5HEADER bi;
|
|
|
|
HBITMAP bitmap, mask;
|
|
|
|
DWORD *bits;
|
2014-06-16 15:39:32 +04:00
|
|
|
HICON icon;
|
2014-06-16 15:17:57 +04:00
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
if (!is_icon) {
|
|
|
|
if ((hotx < 0) || (hotx >= image->w()))
|
|
|
|
return NULL;
|
|
|
|
if ((hoty < 0) || (hoty >= image->h()))
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-06-16 15:17:57 +04:00
|
|
|
|
|
|
|
memset(&bi, 0, sizeof(BITMAPV5HEADER));
|
|
|
|
|
|
|
|
bi.bV5Size = sizeof(BITMAPV5HEADER);
|
|
|
|
bi.bV5Width = image->w();
|
|
|
|
bi.bV5Height = -image->h(); // Negative for top-down
|
|
|
|
bi.bV5Planes = 1;
|
|
|
|
bi.bV5BitCount = 32;
|
|
|
|
bi.bV5Compression = BI_BITFIELDS;
|
|
|
|
bi.bV5RedMask = 0x00FF0000;
|
|
|
|
bi.bV5GreenMask = 0x0000FF00;
|
|
|
|
bi.bV5BlueMask = 0x000000FF;
|
|
|
|
bi.bV5AlphaMask = 0xFF000000;
|
|
|
|
|
|
|
|
HDC hdc;
|
|
|
|
|
|
|
|
hdc = GetDC(NULL);
|
|
|
|
bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
|
|
|
|
if (bits == NULL)
|
2014-06-16 15:39:32 +04:00
|
|
|
return NULL;
|
2014-06-16 15:17:57 +04:00
|
|
|
|
|
|
|
const uchar *i = (const uchar*)*image->data();
|
|
|
|
for (int y = 0;y < image->h();y++) {
|
|
|
|
for (int x = 0;x < image->w();x++) {
|
|
|
|
switch (image->d()) {
|
|
|
|
case 1:
|
|
|
|
*bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
*bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
*bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
*bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += image->d();
|
|
|
|
bits++;
|
|
|
|
}
|
|
|
|
i += image->ld();
|
|
|
|
}
|
|
|
|
|
|
|
|
// A mask bitmap is still needed even though it isn't used
|
|
|
|
mask = CreateBitmap(image->w(),image->h(),1,1,NULL);
|
|
|
|
if (mask == NULL) {
|
|
|
|
DeleteObject(bitmap);
|
2014-06-16 15:39:32 +04:00
|
|
|
return NULL;
|
2014-06-16 15:17:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ICONINFO ii;
|
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
ii.fIcon = is_icon;
|
2014-06-16 15:17:57 +04:00
|
|
|
ii.xHotspot = hotx;
|
|
|
|
ii.yHotspot = hoty;
|
|
|
|
ii.hbmMask = mask;
|
|
|
|
ii.hbmColor = bitmap;
|
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
icon = CreateIconIndirect(&ii);
|
2014-06-16 15:17:57 +04:00
|
|
|
|
|
|
|
DeleteObject(bitmap);
|
|
|
|
DeleteObject(mask);
|
|
|
|
|
2014-06-16 15:39:32 +04:00
|
|
|
if (icon == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
static HICON default_big_icon = NULL;
|
|
|
|
static HICON default_small_icon = NULL;
|
|
|
|
|
2016-01-28 20:38:11 +03:00
|
|
|
static const Fl_RGB_Image *find_best_icon(int ideal_width,
|
2014-06-16 15:39:32 +04:00
|
|
|
const Fl_RGB_Image *icons[],
|
|
|
|
int count) {
|
|
|
|
const Fl_RGB_Image *best;
|
|
|
|
|
|
|
|
best = NULL;
|
|
|
|
|
|
|
|
for (int i = 0;i < count;i++) {
|
|
|
|
if (best == NULL)
|
|
|
|
best = icons[i];
|
|
|
|
else {
|
|
|
|
if (best->w() < ideal_width) {
|
|
|
|
if (icons[i]->w() > best->w())
|
|
|
|
best = icons[i];
|
|
|
|
} else {
|
|
|
|
if ((icons[i]->w() >= ideal_width) &&
|
|
|
|
(icons[i]->w() < best->w()))
|
|
|
|
best = icons[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2016-03-24 09:19:10 +03:00
|
|
|
void Fl_Window_Driver::default_icons(const Fl_RGB_Image *icons[], int count) {
|
2014-06-16 15:39:32 +04:00
|
|
|
const Fl_RGB_Image *best_big, *best_small;
|
|
|
|
|
|
|
|
if (default_big_icon != NULL)
|
|
|
|
DestroyIcon(default_big_icon);
|
|
|
|
if (default_small_icon != NULL)
|
|
|
|
DestroyIcon(default_small_icon);
|
|
|
|
|
|
|
|
default_big_icon = NULL;
|
|
|
|
default_small_icon = NULL;
|
|
|
|
|
|
|
|
best_big = find_best_icon(GetSystemMetrics(SM_CXICON), icons, count);
|
|
|
|
best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), icons, count);
|
|
|
|
|
|
|
|
if (best_big != NULL)
|
|
|
|
default_big_icon = image_to_icon(best_big, true, 0, 0);
|
|
|
|
|
|
|
|
if (best_small != NULL)
|
|
|
|
default_small_icon = image_to_icon(best_small, true, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_X::set_default_icons(HICON big_icon, HICON small_icon) {
|
|
|
|
if (default_big_icon != NULL)
|
|
|
|
DestroyIcon(default_big_icon);
|
|
|
|
if (default_small_icon != NULL)
|
|
|
|
DestroyIcon(default_small_icon);
|
|
|
|
|
|
|
|
default_big_icon = NULL;
|
|
|
|
default_small_icon = NULL;
|
|
|
|
|
|
|
|
if (big_icon != NULL)
|
|
|
|
default_big_icon = CopyIcon(big_icon);
|
|
|
|
if (small_icon != NULL)
|
|
|
|
default_small_icon = CopyIcon(small_icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_X::set_icons() {
|
|
|
|
HICON big_icon, small_icon;
|
|
|
|
|
|
|
|
// Windows doesn't copy the icons, so we have to "leak" them when
|
|
|
|
// setting, and clean up when we change to some other icons.
|
|
|
|
big_icon = (HICON)SendMessage(xid, WM_GETICON, ICON_BIG, 0);
|
|
|
|
if ((big_icon != NULL) && (big_icon != default_big_icon))
|
|
|
|
DestroyIcon(big_icon);
|
|
|
|
small_icon = (HICON)SendMessage(xid, WM_GETICON, ICON_SMALL, 0);
|
|
|
|
if ((small_icon != NULL) && (small_icon != default_small_icon))
|
|
|
|
DestroyIcon(small_icon);
|
|
|
|
|
|
|
|
big_icon = NULL;
|
|
|
|
small_icon = NULL;
|
|
|
|
|
2016-03-22 16:27:22 +03:00
|
|
|
if (((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->count) {
|
2014-06-16 15:39:32 +04:00
|
|
|
const Fl_RGB_Image *best_big, *best_small;
|
|
|
|
|
|
|
|
best_big = find_best_icon(GetSystemMetrics(SM_CXICON),
|
2016-03-22 16:27:22 +03:00
|
|
|
(const Fl_RGB_Image **)((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->icons,
|
|
|
|
((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->count);
|
2014-06-16 15:39:32 +04:00
|
|
|
best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON),
|
2016-03-22 16:27:22 +03:00
|
|
|
(const Fl_RGB_Image **)((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->icons,
|
|
|
|
((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->count);
|
2014-06-16 15:39:32 +04:00
|
|
|
|
|
|
|
if (best_big != NULL)
|
|
|
|
big_icon = image_to_icon(best_big, true, 0, 0);
|
|
|
|
if (best_small != NULL)
|
|
|
|
small_icon = image_to_icon(best_small, true, 0, 0);
|
|
|
|
} else {
|
2016-03-22 16:27:22 +03:00
|
|
|
if ((((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->big_icon != NULL) || (((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->small_icon != NULL)) {
|
|
|
|
big_icon = ((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->big_icon;
|
|
|
|
small_icon = ((Fl_WinAPI_Window_Driver*)w->pWindowDriver)->icon_->small_icon;
|
2014-06-16 15:39:32 +04:00
|
|
|
} else {
|
|
|
|
big_icon = default_big_icon;
|
|
|
|
small_icon = default_small_icon;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SendMessage(xid, WM_SETICON, ICON_BIG, (LPARAM)big_icon);
|
|
|
|
SendMessage(xid, WM_SETICON, ICON_SMALL, (LPARAM)small_icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifndef IDC_HAND
|
|
|
|
# define IDC_HAND MAKEINTRESOURCE(32649)
|
|
|
|
#endif // !IDC_HAND
|
|
|
|
|
|
|
|
int Fl_X::set_cursor(Fl_Cursor c) {
|
|
|
|
LPSTR n;
|
|
|
|
HCURSOR new_cursor;
|
|
|
|
|
|
|
|
if (c == FL_CURSOR_NONE)
|
|
|
|
new_cursor = NULL;
|
|
|
|
else {
|
|
|
|
switch (c) {
|
|
|
|
case FL_CURSOR_ARROW: n = IDC_ARROW; break;
|
|
|
|
case FL_CURSOR_CROSS: n = IDC_CROSS; break;
|
|
|
|
case FL_CURSOR_WAIT: n = IDC_WAIT; break;
|
|
|
|
case FL_CURSOR_INSERT: n = IDC_IBEAM; break;
|
|
|
|
case FL_CURSOR_HAND: n = IDC_HAND; break;
|
|
|
|
case FL_CURSOR_HELP: n = IDC_HELP; break;
|
|
|
|
case FL_CURSOR_MOVE: n = IDC_SIZEALL; break;
|
|
|
|
case FL_CURSOR_N:
|
|
|
|
case FL_CURSOR_S:
|
|
|
|
// FIXME: Should probably have fallbacks for these instead
|
|
|
|
case FL_CURSOR_NS: n = IDC_SIZENS; break;
|
|
|
|
case FL_CURSOR_NE:
|
|
|
|
case FL_CURSOR_SW:
|
|
|
|
// FIXME: Dito.
|
|
|
|
case FL_CURSOR_NESW: n = IDC_SIZENESW; break;
|
|
|
|
case FL_CURSOR_E:
|
|
|
|
case FL_CURSOR_W:
|
|
|
|
// FIXME: Dito.
|
|
|
|
case FL_CURSOR_WE: n = IDC_SIZEWE; break;
|
|
|
|
case FL_CURSOR_SE:
|
|
|
|
case FL_CURSOR_NW:
|
|
|
|
// FIXME: Dito.
|
|
|
|
case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_cursor = LoadCursor(NULL, n);
|
|
|
|
if (new_cursor == NULL)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((cursor != NULL) && custom_cursor)
|
|
|
|
DestroyIcon(cursor);
|
|
|
|
|
|
|
|
cursor = new_cursor;
|
|
|
|
custom_cursor = 0;
|
|
|
|
|
|
|
|
SetCursor(cursor);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
|
|
|
|
HCURSOR new_cursor;
|
|
|
|
|
|
|
|
new_cursor = image_to_icon(image, false, hotx, hoty);
|
2014-06-16 15:17:57 +04:00
|
|
|
if (new_cursor == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((cursor != NULL) && custom_cursor)
|
|
|
|
DestroyIcon(cursor);
|
|
|
|
|
|
|
|
cursor = new_cursor;
|
|
|
|
custom_cursor = 1;
|
|
|
|
|
|
|
|
SetCursor(cursor);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1998-10-06 23:14:55 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Implement the virtual functions for the base Fl_Window class:
|
|
|
|
|
|
|
|
// If the box is a filled rectangle, we can make the redisplay *look*
|
|
|
|
// faster by using X's background pixel erasing. We can make it
|
|
|
|
// actually *be* faster by drawing the frame only, this is done by
|
2001-11-22 18:35:02 +03:00
|
|
|
// setting fl_boxcheat, which is seen by code in fl_drawbox.cxx:
|
1998-10-06 23:14:55 +04:00
|
|
|
// For WIN32 it looks like all windows share a background color, so
|
|
|
|
// I use FL_GRAY for this and only do this cheat for windows that are
|
|
|
|
// that color.
|
|
|
|
// Actually it is totally disabled.
|
|
|
|
// Fl_Widget *fl_boxcheat;
|
|
|
|
//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);}
|
|
|
|
|
2016-03-22 20:47:44 +03:00
|
|
|
void Fl_WinAPI_Window_Driver::show() {
|
2016-03-24 04:20:08 +03:00
|
|
|
if (!shown()) {
|
1998-10-06 23:14:55 +04:00
|
|
|
// if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color());
|
2016-03-22 20:47:44 +03:00
|
|
|
Fl_X::make(pWindow);
|
1998-10-06 23:14:55 +04:00
|
|
|
} else {
|
1998-10-15 18:06:16 +04:00
|
|
|
// Once again, we would lose the capture if we activated the window.
|
2016-03-22 20:47:44 +03:00
|
|
|
Fl_X *i = Fl_X::i(pWindow);
|
1998-11-05 19:04:53 +03:00
|
|
|
if (IsIconic(i->xid)) OpenIcon(i->xid);
|
|
|
|
if (!fl_capture) BringWindowToTop(i->xid);
|
|
|
|
//ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE);
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
2010-03-16 21:27:19 +03:00
|
|
|
#ifdef USE_PRINT_BUTTON
|
2015-07-27 21:13:46 +03:00
|
|
|
void preparePrintFront(void);
|
|
|
|
preparePrintFront();
|
2010-03-16 21:27:19 +03:00
|
|
|
#endif
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// the current context
|
|
|
|
// the current window handle, initially set to -1 so we can correctly
|
|
|
|
// allocate fl_GetDC(0)
|
2005-05-20 06:39:39 +04:00
|
|
|
HWND fl_window = NULL;
|
1998-10-06 23:14:55 +04:00
|
|
|
|
1998-10-15 18:06:16 +04:00
|
|
|
// Here we ensure only one GetDC is ever in place.
|
1998-10-06 23:14:55 +04:00
|
|
|
HDC fl_GetDC(HWND w) {
|
2016-02-19 15:40:24 +03:00
|
|
|
HDC gc = (HDC)Fl_Display_Device::display_device()->driver()->gc();
|
2016-02-18 19:21:51 +03:00
|
|
|
if (gc) {
|
|
|
|
if (w == fl_window && fl_window != NULL) return gc;
|
|
|
|
if (fl_window) fl_release_dc(fl_window, gc); // ReleaseDC
|
|
|
|
}
|
|
|
|
gc = GetDC(w);
|
2016-02-19 15:40:24 +03:00
|
|
|
Fl_Display_Device::display_device()->driver()->gc(gc);
|
2016-02-18 19:21:51 +03:00
|
|
|
fl_save_dc(w, gc);
|
1998-10-06 23:14:55 +04:00
|
|
|
fl_window = w;
|
|
|
|
// calling GetDC seems to always reset these: (?)
|
2016-02-18 19:21:51 +03:00
|
|
|
SetTextAlign(gc, TA_BASELINE|TA_LEFT);
|
|
|
|
SetBkMode(gc, TRANSPARENT);
|
2008-09-25 22:26:33 +04:00
|
|
|
|
2016-02-18 19:21:51 +03:00
|
|
|
return gc;
|
1998-10-06 23:14:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-28 20:38:11 +03:00
|
|
|
/* Make sure that all allocated fonts are released. This works only if
|
2005-09-13 03:03:34 +04:00
|
|
|
Fl::run() is allowed to exit by closing all windows. Calling 'exit(int)'
|
|
|
|
will not automatically free any fonts. */
|
|
|
|
void fl_free_fonts(void)
|
|
|
|
{
|
2008-08-16 01:18:27 +04:00
|
|
|
// remove the Fl_Font_Descriptor chains
|
2005-09-13 03:03:34 +04:00
|
|
|
int i;
|
|
|
|
Fl_Fontdesc * s;
|
2008-08-16 01:18:27 +04:00
|
|
|
Fl_Font_Descriptor * f;
|
|
|
|
Fl_Font_Descriptor * ff;
|
2005-09-13 03:03:34 +04:00
|
|
|
for (i=0; i<FL_FREE_FONT; i++) {
|
|
|
|
s = fl_fonts + i;
|
|
|
|
for (f=s->first; f; f=ff) {
|
|
|
|
ff = f->next;
|
2006-08-28 18:45:20 +04:00
|
|
|
delete f;
|
2005-09-13 03:03:34 +04:00
|
|
|
s->first = ff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// The following routines help fix a problem with the leaking of Windows
|
|
|
|
// Device Context (DC) objects. The 'proper' protocol is for a program to
|
|
|
|
// acquire a DC, save its state, do the modifications needed for drawing,
|
|
|
|
// perform the drawing, restore the initial state, and release the DC. In
|
|
|
|
// FLTK, the save and restore steps have previously been omitted and DCs are
|
|
|
|
// not properly released, leading to a great number of DC leaks. As some
|
|
|
|
// Windows "OSs" will hang when any process exceeds roughly 10,000 GDI objects,
|
|
|
|
// it is important to control GDI leaks, which are much more important than memory
|
|
|
|
// leaks. The following struct, global variable, and routines help implement
|
|
|
|
// the above protocol for those cases where the GetDC and RestoreDC are not in
|
2016-01-28 20:38:11 +03:00
|
|
|
// the same routine. For each GetDC, fl_save_dc is used to create an entry in
|
2005-09-13 03:03:34 +04:00
|
|
|
// a linked list that saves the window handle, the DC handle, and the initial
|
|
|
|
// state. When the DC is to be released, 'fl_release_dc' is called. It restores
|
|
|
|
// the initial state and releases the DC. When the program exits, 'fl_cleanup_dc_list'
|
|
|
|
// frees any remaining nodes in the list.
|
|
|
|
|
2016-01-28 20:38:11 +03:00
|
|
|
struct Win_DC_List { // linked list
|
2005-09-13 03:03:34 +04:00
|
|
|
HWND window; // window handle
|
|
|
|
HDC dc; // device context handle
|
|
|
|
int saved_dc; // initial state of DC
|
|
|
|
Win_DC_List * next; // pointer to next item
|
|
|
|
};
|
|
|
|
|
|
|
|
static Win_DC_List * win_DC_list = 0;
|
|
|
|
|
|
|
|
void fl_save_dc( HWND w, HDC dc) {
|
|
|
|
Win_DC_List * t;
|
|
|
|
t = new Win_DC_List;
|
|
|
|
t->window = w;
|
|
|
|
t->dc = dc;
|
|
|
|
t->saved_dc = SaveDC(dc);
|
|
|
|
if (win_DC_list)
|
|
|
|
t->next = win_DC_list;
|
|
|
|
else
|
|
|
|
t->next = NULL;
|
|
|
|
win_DC_list = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fl_release_dc(HWND w, HDC dc) {
|
|
|
|
Win_DC_List * t= win_DC_list;
|
|
|
|
Win_DC_List * prev = 0;
|
|
|
|
if (!t)
|
|
|
|
return;
|
|
|
|
do {
|
|
|
|
if (t->dc == dc) {
|
|
|
|
RestoreDC(dc, t->saved_dc);
|
|
|
|
ReleaseDC(w, dc);
|
|
|
|
if (!prev) {
|
|
|
|
win_DC_list = t->next; // delete first item
|
|
|
|
} else {
|
|
|
|
prev->next = t->next; // one in the middle
|
|
|
|
}
|
|
|
|
delete (t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = t;
|
|
|
|
t = t->next;
|
|
|
|
} while (t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fl_cleanup_dc_list(void) { // clean up the list
|
|
|
|
Win_DC_List * t = win_DC_list;
|
|
|
|
if (!t)return;
|
|
|
|
do {
|
|
|
|
RestoreDC(t->dc, t->saved_dc);
|
|
|
|
ReleaseDC(t->window, t->dc);
|
|
|
|
win_DC_list = t->next;
|
|
|
|
delete (t);
|
|
|
|
t = win_DC_list;
|
|
|
|
} while(t);
|
|
|
|
}
|
2010-03-14 21:07:24 +03:00
|
|
|
|
|
|
|
Fl_Region XRectangleRegion(int x, int y, int w, int h) {
|
2012-03-18 22:48:29 +04:00
|
|
|
if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) return CreateRectRgn(x,y,x+w,y+h);
|
2010-03-14 21:07:24 +03:00
|
|
|
// 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} };
|
2016-02-19 15:40:24 +03:00
|
|
|
LPtoDP((HDC)fl_graphics_driver->gc(), pt, 4);
|
2010-03-14 21:07:24 +03:00
|
|
|
return CreatePolygonRgn(pt, 4, ALTERNATE);
|
|
|
|
}
|
|
|
|
|
2011-06-18 16:29:49 +04:00
|
|
|
FL_EXPORT Window fl_xid_(const Fl_Window *w) {
|
2016-01-28 20:38:11 +03:00
|
|
|
Fl_X *temp = Fl_X::i(w);
|
2011-01-18 02:52:32 +03:00
|
|
|
return temp ? temp->xid : 0;
|
|
|
|
}
|
|
|
|
|
2016-01-10 22:08:16 +03:00
|
|
|
/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders.
|
|
|
|
On the WIN32 platform, this function exploits a feature of fl_read_image() which, when called
|
|
|
|
with NULL first argument and when fl_gc is set to the screen device context, captures the window decoration.
|
|
|
|
*/
|
2016-03-11 10:07:42 +03:00
|
|
|
void Fl_WinAPI_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, Fl_Shared_Image*& left, Fl_Shared_Image*& bottom, Fl_Shared_Image*& right)
|
2015-11-24 17:26:52 +03:00
|
|
|
{
|
2016-02-12 19:17:40 +03:00
|
|
|
Fl_RGB_Image *r_top, *r_left, *r_bottom, *r_right;
|
2016-01-10 22:08:16 +03:00
|
|
|
top = left = bottom = right = NULL;
|
2016-03-24 04:20:08 +03:00
|
|
|
if (!shown() || parent() || !border() || !visible()) return;
|
2016-01-10 22:08:16 +03:00
|
|
|
int wsides, hbottom, bt;
|
2016-03-13 01:24:20 +03:00
|
|
|
RECT r = border_width_title_bar_height(wsides, hbottom, bt);
|
2016-01-10 22:08:16 +03:00
|
|
|
int htop = bt + hbottom;
|
|
|
|
Fl_Surface_Device *previous = Fl_Surface_Device::surface();
|
2016-02-18 19:21:51 +03:00
|
|
|
Window save_win = fl_window;
|
2016-01-10 22:08:16 +03:00
|
|
|
Fl_Display_Device::display_device()->set_current();
|
2016-03-11 10:07:42 +03:00
|
|
|
pWindow->show();
|
2016-01-10 22:08:16 +03:00
|
|
|
Fl::check();
|
2016-02-19 15:40:24 +03:00
|
|
|
void* save_gc = fl_graphics_driver->gc();
|
|
|
|
fl_graphics_driver->gc(GetDC(NULL));
|
2016-03-24 04:20:08 +03:00
|
|
|
int ww = w() + 2 * wsides;
|
2011-04-16 01:38:05 +04:00
|
|
|
// capture the 4 window sides from screen
|
2014-11-06 19:48:57 +03:00
|
|
|
fl_window = NULL; // force use of read_win_rectangle() by fl_read_image()
|
2016-01-10 22:08:16 +03:00
|
|
|
uchar *rgb;
|
|
|
|
if (htop) {
|
|
|
|
rgb = fl_read_image(NULL, r.left, r.top, ww, htop);
|
2016-02-12 19:17:40 +03:00
|
|
|
r_top = new Fl_RGB_Image(rgb, ww, htop, 3);
|
|
|
|
r_top->alloc_array = 1;
|
|
|
|
top = Fl_Shared_Image::get(r_top);
|
2016-01-10 22:08:16 +03:00
|
|
|
}
|
|
|
|
if (wsides) {
|
2016-03-24 04:20:08 +03:00
|
|
|
rgb = fl_read_image(NULL, r.left, r.top + htop, wsides, h());
|
|
|
|
r_left = new Fl_RGB_Image(rgb, wsides, h(), 3);
|
2016-02-12 19:17:40 +03:00
|
|
|
r_left->alloc_array = 1;
|
|
|
|
left = Fl_Shared_Image::get(r_left);
|
2016-03-24 04:20:08 +03:00
|
|
|
rgb = fl_read_image(NULL, r.right - wsides, r.top + htop, wsides, h());
|
|
|
|
r_right = new Fl_RGB_Image(rgb, wsides, h(), 3);
|
2016-02-12 19:17:40 +03:00
|
|
|
r_right->alloc_array = 1;
|
|
|
|
right = Fl_Shared_Image::get(r_right);
|
2016-01-10 22:08:16 +03:00
|
|
|
rgb = fl_read_image(NULL, r.left, r.bottom-hbottom, ww, hbottom);
|
2016-02-12 19:17:40 +03:00
|
|
|
r_bottom = new Fl_RGB_Image(rgb, ww, hbottom, 3);
|
|
|
|
r_bottom->alloc_array = 1;
|
|
|
|
bottom = Fl_Shared_Image::get(r_bottom);
|
2016-01-10 22:08:16 +03:00
|
|
|
}
|
2016-02-19 15:40:24 +03:00
|
|
|
ReleaseDC(NULL, (HDC)fl_graphics_driver->gc());
|
2014-11-06 19:48:57 +03:00
|
|
|
fl_window = save_win;
|
2016-02-19 15:40:24 +03:00
|
|
|
fl_graphics_driver->gc(save_gc);
|
2016-01-10 22:08:16 +03:00
|
|
|
previous->Fl_Surface_Device::set_current();
|
|
|
|
}
|
2011-04-16 01:38:05 +04:00
|
|
|
|
2010-03-16 21:27:19 +03:00
|
|
|
#ifdef USE_PRINT_BUTTON
|
|
|
|
// to test the Fl_Printer class creating a "Print front window" button in a separate window
|
2010-03-14 21:07:24 +03:00
|
|
|
// contains also preparePrintFront call above
|
|
|
|
#include <FL/Fl_Printer.H>
|
|
|
|
#include <FL/Fl_Button.H>
|
|
|
|
void printFront(Fl_Widget *o, void *data)
|
|
|
|
{
|
|
|
|
Fl_Printer printer;
|
|
|
|
o->window()->hide();
|
|
|
|
Fl_Window *win = Fl::first_window();
|
|
|
|
if(!win) return;
|
|
|
|
int w, h;
|
|
|
|
if( printer.start_job(1) ) { o->window()->show(); return; }
|
|
|
|
if( printer.start_page() ) { o->window()->show(); return; }
|
|
|
|
printer.printable_rect(&w,&h);
|
2011-04-16 01:38:05 +04:00
|
|
|
int wh, ww;
|
|
|
|
wh = win->decorated_h();
|
|
|
|
ww = win->decorated_w();
|
2010-03-14 21:07:24 +03:00
|
|
|
// scale the printer device so that the window fits on the page
|
|
|
|
float scale = 1;
|
2011-04-16 01:38:05 +04:00
|
|
|
if (ww > w || wh > h) {
|
|
|
|
scale = (float)w/ww;
|
|
|
|
if ((float)h/wh < scale) scale = (float)h/wh;
|
2010-03-14 21:07:24 +03:00
|
|
|
printer.scale(scale, scale);
|
|
|
|
}
|
|
|
|
// #define ROTATE 20.0
|
|
|
|
#ifdef ROTATE
|
|
|
|
printer.scale(scale * 0.8, scale * 0.8);
|
|
|
|
printer.printable_rect(&w, &h);
|
|
|
|
printer.origin(w/2, h/2 );
|
|
|
|
printer.rotate(ROTATE);
|
|
|
|
printer.print_widget( win, - win->w()/2, - win->h()/2 );
|
2010-03-16 21:27:19 +03:00
|
|
|
//printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 );
|
2016-01-28 20:38:11 +03:00
|
|
|
#else
|
2011-04-16 01:38:05 +04:00
|
|
|
printer.print_window(win);
|
2010-03-14 21:07:24 +03:00
|
|
|
#endif
|
|
|
|
printer.end_page();
|
|
|
|
printer.end_job();
|
|
|
|
o->window()->show();
|
|
|
|
}
|
|
|
|
|
2015-11-24 17:26:52 +03:00
|
|
|
#include <FL/Fl_Copy_Surface.H>
|
|
|
|
void copyFront(Fl_Widget *o, void *data)
|
|
|
|
{
|
|
|
|
o->window()->hide();
|
|
|
|
Fl_Window *win = Fl::first_window();
|
|
|
|
if (!win) return;
|
2016-02-01 20:27:59 +03:00
|
|
|
Fl_Copy_Surface *surf = new Fl_Copy_Surface(win->decorated_w(), win->decorated_h());
|
2015-11-24 17:26:52 +03:00
|
|
|
surf->set_current();
|
|
|
|
surf->draw_decorated_window(win); // draw the window content
|
|
|
|
delete surf; // put the window on the clipboard
|
|
|
|
Fl_Display_Device::display_device()->set_current();
|
|
|
|
o->window()->show();
|
|
|
|
}
|
|
|
|
|
2010-03-14 21:07:24 +03:00
|
|
|
void preparePrintFront(void)
|
|
|
|
{
|
|
|
|
static BOOL first=TRUE;
|
|
|
|
if(!first) return;
|
|
|
|
first=FALSE;
|
2015-11-24 17:26:52 +03:00
|
|
|
static Fl_Window w(0,0,120,60);
|
|
|
|
static Fl_Button bp(0,0,w.w(),30, "Print front window");
|
|
|
|
bp.callback(printFront);
|
|
|
|
static Fl_Button bc(0,30,w.w(),30, "Copy front window");
|
|
|
|
bc.callback(copyFront);
|
2010-03-14 21:07:24 +03:00
|
|
|
w.end();
|
|
|
|
w.show();
|
|
|
|
}
|
2010-03-16 21:27:19 +03:00
|
|
|
#endif // USE_PRINT_BUTTON
|
|
|
|
|
2016-03-25 16:08:48 +03:00
|
|
|
#endif // defined(WIN32) and !defined(FL_DOXYGEN)
|
2005-09-13 03:03:34 +04:00
|
|
|
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2005-02-14 16:44:24 +03:00
|
|
|
// End of "$Id$".
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|