⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fl_mac.cxx

📁 SRI international 发布的OAA框架软件
💻 CXX
📖 第 1 页 / 共 4 页
字号:
//
// "$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 + -