📄 fl_mac.cxx
字号:
//
// "$Id: Fl_mac.cxx,v 1.1.1.1 2003/06/03 22:25:45 agno Exp $"
//
// MacOS 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".
//
//// From the inner edge of a MetroWerks CodeWarrior CD:
// (without permission)
//
// Three Compiles for 68Ks under the sky,
// Seven Compiles for PPCs in their fragments of code,
// Nine Compiles for Mortal Carbon doomed to die,
// One Compile for Mach-O Cocoa on its Mach-O throne,
// in the Land of MacOS X where the Drop-Shadows lie.
//
// One Compile to link them all, One Compile to merge them,
// One Compile to copy them all and in the bundle bind them,
// in the Land of MacOS X where the Drop-Shadows lie.
// we don't need the following definition because we deliver only
// true mouse moves. On very slow systems however, this flag may
// still be useful.
#define CONSOLIDATE_MOTION 0
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/Fl_Tooltip.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Sys_Menu_Bar.H>
#include <stdio.h>
#include <stdlib.h>
#include "flstring.h"
#include <unistd.h>
#include <pthread.h>
// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING
#ifdef DEBUG_SELECT
#include <stdio.h> // testing
#define DEBUGMSG(msg) fprintf(stderr, msg);
#define DEBUGPERRORMSG(msg) perror(msg)
#else
#define DEBUGMSG(msg)
#define DEBUGPERRORMSG(msg)
#endif /*DEBUGSELECT*/
// external functions
extern Fl_Window* fl_find(Window);
extern void fl_fix_focus();
// forward definition of functions in this file
static void handleUpdateEvent( WindowPtr xid );
//+ int fl_handle(const EventRecord &event);
// public variables
int fl_screen;
Handle fl_system_menu;
Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
CursHandle fl_default_cursor;
WindowRef fl_capture = 0; // we need this to compensate for a missing(?) mouse capture
ulong fl_event_time; // the last timestamp from an x event
char fl_key_vector[32]; // used by Fl::get_key()
bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state
int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
const Fl_Window* fl_modal_for; // parent of modal() window
Fl_Region fl_window_region = 0;
Window fl_window;
Fl_Window *Fl_Window::current_;
EventRef fl_os_event; // last (mouse) event
// forward declarations of variables in this file
static int got_events = 0;
static Fl_Window* resize_from_system;
static CursPtr default_cursor_ptr;
static Cursor default_cursor;
static WindowRef fl_os_capture = 0; // the dispatch handler will redirect mose move and drag events to these windows
#if CONSOLIDATE_MOTION
static Fl_Window* send_motion;
extern Fl_Window* fl_xmousewin;
#endif
enum { kEventClassFLTK = 'fltk' };
enum { kEventFLTKBreakLoop = 1, kEventFLTKDataReady };
/**
* Mac keyboard lookup table
*/
static unsigned short macKeyLookUp[128] =
{
'a', 's', 'd', 'f', 'h', 'g', 'z', 'x',
'c', 'v', 0/*ISO extra ('#' on German keyboard)*/, 'b', 'q', 'w', 'e', 'r',
'y', 't', '1', '2', '3', '4', '6', '5',
'=', '9', '7', '-', '8', '0', ']', 'o',
'u', '[', 'i', 'p', FL_Enter, 'l', 'j', '\'',
'k', ';', '\\', ',', '/', 'n', 'm', '.',
FL_Tab, ' ', '`', FL_BackSpace, 0, FL_Escape, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, FL_KP+'.', FL_Right, FL_KP+'*', 0, FL_KP+'+', FL_Left, FL_Num_Lock,
FL_Down, 0, 0, FL_KP+'/', FL_KP_Enter, FL_Up, FL_KP+'-', 0,
0, FL_KP+'=', FL_KP+'0', FL_KP+'1', FL_KP+'2', FL_KP+'3', FL_KP+'4', FL_KP+'5',
FL_KP+'6', FL_KP+'7', 0, FL_KP+'8', FL_KP+'9', 0, 0, 0,
FL_F+5, FL_F+6, FL_F+7, FL_F+3, FL_F+8, FL_F+9, 0, FL_F+11,
0, 0, FL_Print, FL_Scroll_Lock, 0, FL_F+10, 0, FL_F+12,
0, FL_Pause, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End,
FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0,
};
// these pointers are set by the Fl::lock() function:
static void nothing() {}
void (*fl_lock_function)() = nothing;
void (*fl_unlock_function)() = nothing;
//
// Select interface
//
#define POLLIN 1
#define POLLOUT 4
#define POLLERR 8
struct FD
{
int fd;
short events;
void (*cb)(int, void*);
void* arg;
};
static int nfds = 0;
static int fd_array_size = 0;
static FD *fd = 0;
static int G_pipe[2] = { 0,0 }; // work around pthread_cancel() problem
enum GetSet { GET = 1, SET = 2 };
static pthread_mutex_t select_mutex; // global data lock
// MAXFD ACCESSOR (HANDLES LOCKING)
static void MaxFD(GetSet which, int& val)
{
static int maxfd = 0;
pthread_mutex_lock(&select_mutex);
if ( which == GET ) { val = maxfd; }
else { maxfd = val; }
pthread_mutex_unlock(&select_mutex);
}
// FDSET ACCESSOR (HANDLES LOCKING)
static void Fdset(GetSet which, fd_set& r, fd_set &w, fd_set &x)
{
static fd_set fdsets[3];
pthread_mutex_lock(&select_mutex);
if ( which == GET ) { r = fdsets[0]; w = fdsets[1]; x = fdsets[2]; }
else { fdsets[0] = r; fdsets[1] = w; fdsets[2] = x; }
pthread_mutex_unlock(&select_mutex);
}
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 *temp;
fd_array_size = 2*fd_array_size+1;
if (!fd) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); }
else { temp = (FD*)realloc(fd, fd_array_size*sizeof(FD)); }
if (!temp) return;
fd = temp;
}
fd[i].cb = cb;
fd[i].arg = v;
fd[i].fd = n;
fd[i].events = events;
{
int maxfd;
fd_set r, w, x;
MaxFD(GET, maxfd);
Fdset(GET, r, w, x);
if (events & POLLIN) FD_SET(n, &r);
if (events & POLLOUT) FD_SET(n, &w);
if (events & POLLERR) FD_SET(n, &x);
if (n > maxfd) maxfd = n;
Fdset(SET, r, w, x);
MaxFD(SET, maxfd);
}
}
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) {
int 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;
{
int maxfd;
fd_set r, w, x;
MaxFD(GET, maxfd);
Fdset(GET, r, w, x);
if (events & POLLIN) FD_CLR(n, &r);
if (events & POLLOUT) FD_CLR(n, &w);
if (events & POLLERR) FD_CLR(n, &x);
if (n == maxfd) maxfd--;
Fdset(SET, r, w, x);
MaxFD(SET, maxfd);
}
}
void Fl::remove_fd(int n)
{
remove_fd(n, -1);
}
/**
* Check if there is actually a message pending!
*/
int fl_ready()
{
if (GetNumEventsInQueue(GetCurrentEventQueue()) > 0) return 1;
return 0;
}
// CHECK IF USER DATA READY
static int CheckDataReady(fd_set& r, fd_set& w, fd_set& x)
{
int maxfd;
MaxFD(GET, maxfd);
timeval t = { 0, 1 }; // quick check
int ret = ::select(maxfd+1, &r, &w, &x, &t);
if ( ret == -1 )
{ DEBUGPERRORMSG("CheckDataReady(): select()"); }
return(ret);
}
// HANDLE DATA READY CALLBACKS
static void HandleDataReady(fd_set& r, fd_set& w, fd_set& x)
{
for (int i=0; i<nfds; i++)
{
// fprintf(stderr, "CHECKING FD %d OF %d (%d)\n", i, nfds, fd[i].fd);
int f = fd[i].fd;
short revents = 0;
if (FD_ISSET(f, &r)) revents |= POLLIN;
if (FD_ISSET(f, &w)) revents |= POLLOUT;
if (FD_ISSET(f, &x)) revents |= POLLERR;
if (fd[i].events & revents)
{
DEBUGMSG("DOING CALLBACK: ");
fd[i].cb(f, fd[i].arg);
DEBUGMSG("DONE\n");
}
}
}
/**
* handle Apple Menu items (can be created using the Fl_Sys_Menu_Bar
* returns eventNotHandledErr if the menu item could not be handled
*/
OSStatus HandleMenu( HICommand *cmd )
{
OSStatus ret = eventNotHandledErr;
// attributes, commandIDm menu.menuRef, menu.menuItemIndex
UInt32 ref;
OSErr rrc = GetMenuItemRefCon( cmd->menu.menuRef, cmd->menu.menuItemIndex, &ref );
//printf( "%d, %08x, %08x, %d, %d, %8x\n", rrc, cmd->attributes, cmd->commandID, cmd->menu.menuRef, cmd->menu.menuItemIndex, rrc );
if ( rrc==noErr && ref )
{
Fl_Menu_Item *m = (Fl_Menu_Item*)ref;
//printf( "Menu: %s\n", m->label() );
fl_sys_menu_bar->picked( m );
if ( m->flags & FL_MENU_TOGGLE ) // update the menu toggle symbol
SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, (m->flags & FL_MENU_VALUE ) ? 0x12 : 0 );
if ( m->flags & FL_MENU_RADIO ) // update all radio buttons in this menu
{
Fl_Menu_Item *j = m;
int i = cmd->menu.menuItemIndex;
for (;;)
{
if ( j->flags & FL_MENU_DIVIDER )
break;
j++; i++;
if ( !j->text || !j->radio() )
break;
SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
}
j = m-1; i = cmd->menu.menuItemIndex-1;
for ( ; i>0; j--, i-- )
{
if ( !j->text || j->flags&FL_MENU_DIVIDER || !j->radio() )
break;
SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
}
SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
}
ret = noErr; // done handling this event
}
HiliteMenu(0);
return ret;
}
/**
* We can make every event pass through this function
* - mouse events need to be manipulated to use a mouse focus window
* - keyboard, mouse and some window events need to quit the Apple Event Loop
* so FLTK can continue its own management
*/
static pascal OSStatus carbonDispatchHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
{
OSStatus ret = eventNotHandledErr;
HICommand cmd;
fl_lock_function();
got_events = 1;
switch ( GetEventClass( event ) )
{
case kEventClassMouse:
switch ( GetEventKind( event ) )
{
case kEventMouseUp:
case kEventMouseMoved:
case kEventMouseDragged:
if ( fl_capture )
ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_capture ) );
else if ( fl_os_capture )
ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_os_capture ) );
break;
}
break;
case kEventClassCommand:
switch (GetEventKind( event ) )
{
case kEventCommandProcess:
GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd );
ret = HandleMenu( &cmd );
break;
}
break;
case kEventClassFLTK:
switch ( GetEventKind( event ) )
{
case kEventFLTKBreakLoop:
ret = noErr;
break;
case kEventFLTKDataReady:
{
DEBUGMSG("DATA READY EVENT: RECEIVED\n");
// CHILD THREAD TELLS US DATA READY
// Check to see what's ready, and invoke user's cb's
//
fd_set r, w, x;
Fdset(GET, r, w, x);
switch ( CheckDataReady(r, w, x) )
{
case 0: // NO DATA
break;
case -1: // ERROR
break;
default: // DATA READY
HandleDataReady(r, w, x);
break;
}
}
ret = noErr;
break;
}
}
if ( ret == eventNotHandledErr )
ret = CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect
QuitApplicationEventLoop();
fl_unlock_function();
return ret;
}
/**
* this callback simply quits the main event loop handler, so FLTK can do its magic
*/
static pascal void timerProcCB( EventLoopTimerRef, void* )
{
fl_lock_function();
QuitApplicationEventLoop();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -