📄 fl_win32.cxx
字号:
//
// "$Id: Fl_win32.cxx,v 1.3 2005/03/30 18:24:34 agno Exp $"
//
// WIN32-specific code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2003 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to "fltk-bugs@fltk.org".
//
// This file contains win32-specific code for fltk which is always linked
// in. Search other files for "WIN32" or filenames ending in _win32.cxx
// for other system-specific code.
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/Fl_Window.H>
#include "flstring.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#ifdef __CYGWIN__
# include <sys/time.h>
# include <unistd.h>
#else
# include <winsock.h>
#endif
#include <winuser.h>
#include <commctrl.h>
// The following include files require GCC 3.x or a non-GNU compiler...
#if !defined(__GNUC__) || __GNUC__ >= 3
# include <ole2.h>
# include <ShellApi.h>
#endif // !__GNUC__ || __GNUC__ >= 3
//
// USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()...
//
// This currently doesn't appear to work; needs to be fixed!
//
//#define USE_ASYNC_SELECT
//
// USE_TRACK_MOUSE - define it if you have TrackMouseEvent()...
//
// Apparently, at least some versions of Cygwin/MingW don't provide
// the TrackMouseEvent() function. You can define this by hand
// if you have it - this is only needed to support subwindow
// enter/leave notification under Windows.
//
//#define USE_TRACK_MOUSE
#if !defined(__GNUC__)
# define USE_TRACK_MOUSE
#endif // !__GNUC__
#undef USE_TRACK_MOUSE;
//
// WM_SYNCPAINT is an "undocumented" message, which is finally defined in
// VC++ 6.0.
//
#ifndef WM_SYNCPAINT
# define WM_SYNCPAINT 0x0088
#endif
#ifndef WM_MOUSELEAVE
# define WM_MOUSELEAVE 0x02a3
#endif
#ifndef WM_MOUSEWHEEL
# define WM_MOUSEWHEEL 0x020a
#endif
#ifndef WHEEL_DELTA
# define WHEEL_DELTA 120 // according to MSDN.
#endif
//
// WM_FLSELECT is the user-defined message that we get when one of
// the sockets has pending data, etc.
//
#define WM_FLSELECT (WM_USER+0x0400)
////////////////////////////////////////////////////////////////
// interface to poll/select call:
// fd's are only implemented for sockets. Microsoft Windows does not
// have a unified IO system, so it doesn't support select() on files,
// devices, or pipes...
//
// Microsoft provides the Berkeley select() call and an asynchronous
// select function that sends a WIN32 message when the select condition
// exists...
static int maxfd = 0;
#ifndef USE_ASYNC_SELECT
static fd_set fdsets[3];
#endif // !USE_ASYNC_SELECT
#define POLLIN 1
#define POLLOUT 4
#define POLLERR 8
#if !defined(__GNUC__) || __GNUC__ >= 3
extern IDropTarget *flIDropTarget;
#endif // !__GNUC__ || __GNUC__ >= 3
static int nfds = 0;
static int fd_array_size = 0;
static struct FD {
int fd;
short events;
void (*cb)(int, void*);
void* arg;
} *fd = 0;
void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {
remove_fd(n,events);
int i = nfds++;
if (i >= fd_array_size) {
fd_array_size = 2*fd_array_size+1;
fd = (FD*)realloc(fd, fd_array_size*sizeof(FD));
}
fd[i].fd = n;
fd[i].events = (short)events;
fd[i].cb = cb;
fd[i].arg = v;
#ifdef USE_ASYNC_SELECT
int mask = 0;
if (events & POLLIN) mask |= FD_READ;
if (events & POLLOUT) mask |= FD_WRITE;
if (events & POLLERR) mask |= FD_CLOSE;
WSAAsyncSelect(n, fl_window, WM_FLSELECT, mask);
#else
if (events & POLLIN) FD_SET(n, &fdsets[0]);
if (events & POLLOUT) FD_SET(n, &fdsets[1]);
if (events & POLLERR) FD_SET(n, &fdsets[2]);
if (n > maxfd) maxfd = n;
#endif // USE_ASYNC_SELECT
}
void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) {
Fl::add_fd(fd, POLLIN, cb, v);
}
void Fl::remove_fd(int n, int events) {
int i,j;
for (i=j=0; i<nfds; i++) {
if (fd[i].fd == n) {
short e = fd[i].events & ~events;
if (!e) continue; // if no events left, delete this fd
fd[i].events = e;
}
// move it down in the array if necessary:
if (j<i) {
fd[j]=fd[i];
}
j++;
}
nfds = j;
#ifdef USE_ASYNC_SELECT
WSAAsyncSelect(n, 0, 0, 0);
#else
if (events & POLLIN) FD_CLR(unsigned(n), &fdsets[0]);
if (events & POLLOUT) FD_CLR(unsigned(n), &fdsets[1]);
if (events & POLLERR) FD_CLR(unsigned(n), &fdsets[2]);
#endif // USE_ASYNC_SELECT
}
void Fl::remove_fd(int n) {
remove_fd(n, -1);
}
// these pointers are set by the Fl::lock() function:
static void nothing() {}
void (*fl_lock_function)() = nothing;
void (*fl_unlock_function)() = nothing;
static void* thread_message_;
void* Fl::thread_message() {
void* r = thread_message_;
thread_message_ = 0;
return r;
}
MSG fl_msg;
// 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) {
int have_message = 0;
int timerid;
#ifndef USE_ASYNC_SELECT
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];
fdt[0] = fdsets[0];
fdt[1] = fdsets[1];
fdt[2] = fdsets[2];
if (::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) {
// We got something - do the callback!
for (int i = 0; i < nfds; i ++) {
int f = fd[i].fd;
short revents = 0;
if (FD_ISSET(f,&fdt[0])) revents |= POLLIN;
if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT;
if (FD_ISSET(f,&fdt[2])) revents |= POLLERR;
if (fd[i].events & revents) fd[i].cb(f, fd[i].arg);
}
time_to_wait = 0.0; // just peek for any messages
#ifdef __CYGWIN__
}
#else
} else {
// we need to check them periodically, so set a short timeout:
if (time_to_wait > .001) time_to_wait = .001;
}
#endif
}
#endif // USE_ASYNC_SELECT
fl_unlock_function();
if (time_to_wait < 2147483.648) {
// Perform the requested timeout...
have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
if (!have_message) {
int t = (int)(time_to_wait * 1000.0 + .5);
if (t <= 0) { // too short to measure
fl_lock_function();
return 0;
}
timerid = SetTimer(NULL, 0, t, NULL);
have_message = GetMessage(&fl_msg, NULL, 0, 0);
KillTimer(NULL, timerid);
}
} else {
have_message = GetMessage(&fl_msg, NULL, 0, 0);
}
fl_lock_function();
// Execute the message we got, and all other pending messages:
while (have_message) {
#ifdef USE_ASYNC_SELECT
if (fl_msg.message == WM_FLSELECT) {
// Got notification for socket
for (int i = 0; i < nfds; i ++)
if (fd[i].fd == (int)fl_msg.wParam) {
(fd[i].cb)(fd[i].fd, fd[i].arg);
break;
}
// looks like it is best to do the dispatch-message anyway:
}
#endif
if (fl_msg.message == fl_wake_msg) // Used for awaking wait() from another thread
thread_message_ = (void*)fl_msg.wParam;
TranslateMessage(&fl_msg);
DispatchMessage(&fl_msg);
have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
}
// 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;
#ifdef USE_ASYNC_SELECT
return 0;
#else
timeval t;
t.tv_sec = 0;
t.tv_usec = 0;
fd_set fdt[3];
fdt[0] = fdsets[0];
fdt[1] = fdsets[1];
fdt[2] = fdsets[2];
return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t);
#endif // USE_ASYNC_SELECT
}
////////////////////////////////////////////////////////////////
int Fl::x()
{
RECT r;
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
return r.left;
}
int Fl::y()
{
RECT r;
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
return r.top;
}
int Fl::h()
{
RECT r;
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
return r.bottom - r.top;
}
int Fl::w()
{
RECT r;
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
return r.right - r.left;
}
void Fl::get_mouse(int &x, int &y) {
POINT p;
GetCursorPos(&p);
x = p.x;
y = p.y;
}
////////////////////////////////////////////////////////////////
// code used for selections:
char *fl_selection_buffer[2];
int fl_selection_length[2];
int fl_selection_buffer_length[2];
char fl_i_own_selection[2];
// call this when you create a selection:
void Fl::copy(const char *stuff, int len, int clipboard) {
if (!stuff || len<0) return;
if (len+1 > fl_selection_buffer_length[clipboard]) {
delete[] fl_selection_buffer[clipboard];
fl_selection_buffer[clipboard] = new char[len+100];
fl_selection_buffer_length[clipboard] = len+100;
}
memcpy(fl_selection_buffer[clipboard], stuff, len);
fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
fl_selection_length[clipboard] = len;
if (clipboard) {
// set up for "delayed rendering":
if (OpenClipboard(fl_xid(Fl::first_window()))) {
EmptyClipboard();
SetClipboardData(CF_TEXT, NULL);
CloseClipboard();
}
fl_i_own_selection[clipboard] = 1;
}
}
// Call this when a "paste" operation happens:
void Fl::paste(Fl_Widget &receiver, int clipboard) {
if (!clipboard || fl_i_own_selection[clipboard]) {
// 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!
Fl::e_text = fl_selection_buffer[clipboard];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -