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

📄 fl_mac.cxx

📁 SRI international 发布的OAA框架软件
💻 CXX
📖 第 1 页 / 共 4 页
字号:
  fl_unlock_function();
}


// DATA READY THREAD
//    Separate thread, watches for changes in user's file descriptors.
//    Sends a 'data ready event' to the main thread if any change.
//
static void *dataready_thread(void *userdata)
{
  EventRef drEvent;
  CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady,
               0, kEventAttributeUserEvent, &drEvent);
  EventQueueRef eventqueue = (EventQueueRef)userdata;

  // Thread safe local copy
  int maxfd;
  fd_set r, w, x;
  MaxFD(GET, maxfd);
  Fdset(GET, r, w, x);

  // TACK ON FD'S FOR 'CANCEL PIPE'
  FD_SET(G_pipe[0], &r);
  if ( G_pipe[0] > maxfd ) maxfd = G_pipe[0];

  // FOREVER UNTIL THREAD CANCEL OR ERROR
  while ( 1 )
  {
    timeval t = { 1000, 0 };	// 1000 seconds;
    int ret = ::select(maxfd+1, &r, &w, &x, &t);
    pthread_testcancel();	// OSX 10.0.4 and under: need to do this
                          // so parent can cancel us :(
    switch ( ret )
    {
      case  0:	// NO DATA
        continue;
      case -1:	// ERROR
      {
        DEBUGPERRORMSG("CHILD THREAD: select() failed");
        return(NULL);		// error? exit thread
      }
      default:	// DATA READY
      {
        DEBUGMSG("DATA READY EVENT: SENDING\n");
        PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard );
        return(NULL);		// done with thread
      }
    }
  }
}


/**
 * break the current event loop
 */
static void breakMacEventLoop()
{
  EventRef breakEvent;

  fl_lock_function();

  CreateEvent( 0, kEventClassFLTK, kEventFLTKBreakLoop, 0, kEventAttributeUserEvent, &breakEvent );
  PostEventToQueue( GetCurrentEventQueue(), breakEvent, kEventPriorityStandard );
  ReleaseEvent( breakEvent );

  fl_unlock_function();
}


/**
 * This function is the central event handler.
 * It reads events from the event queue using the given maximum time
 * Funny enough, it returns the same time that it got as the argument. 
 */
static double do_queued_events( double time = 0.0 ) 
{
  static bool been_here = 0;
  static RgnHandle rgn;
  
  // initialize events and a region that enables mouse move events
  if (!been_here) {
    rgn = NewRgn();
    Point mp;
    GetMouse(&mp);
    SetRectRgn(rgn, mp.h, mp.v, mp.h, mp.v);
    SetEventMask(everyEvent);
    been_here = 1;
  }
  OSStatus ret;
  static EventTargetRef target = 0;
  static EventLoopTimerRef timer = 0;
  if ( !target ) 
  {
    target = GetEventDispatcherTarget();

    EventHandlerUPP dispatchHandler = NewEventHandlerUPP( carbonDispatchHandler ); // will not be disposed by Carbon...
    static EventTypeSpec dispatchEvents[] = {
        { kEventClassWindow, kEventWindowShown },
        { kEventClassWindow, kEventWindowHidden },
        { kEventClassWindow, kEventWindowActivated },
        { kEventClassWindow, kEventWindowDeactivated },
        { kEventClassWindow, kEventWindowClose },
        { kEventClassKeyboard, kEventRawKeyDown },
        { kEventClassKeyboard, kEventRawKeyRepeat },
        { kEventClassKeyboard, kEventRawKeyUp },
        { kEventClassKeyboard, kEventRawKeyModifiersChanged },
        { kEventClassMouse, kEventMouseDown },
        { kEventClassMouse, kEventMouseUp },
        { kEventClassMouse, kEventMouseMoved },
        { kEventClassMouse, kEventMouseWheelMoved },
        { kEventClassMouse, kEventMouseDragged },
        { kEventClassFLTK, kEventFLTKBreakLoop },
        { kEventClassFLTK, kEventFLTKDataReady } };
    ret = InstallEventHandler( target, dispatchHandler, GetEventTypeCount(dispatchEvents), dispatchEvents, 0, 0L );
    static EventTypeSpec appEvents[] = {
        { kEventClassCommand, kEventCommandProcess } };
    ret = InstallApplicationEventHandler( dispatchHandler, GetEventTypeCount(appEvents), appEvents, 0, 0L );
    ret = InstallEventLoopTimer( GetMainEventLoop(), 0, 0, NewEventLoopTimerUPP( timerProcCB ), 0, &timer );
  }

  got_events = 0;

  // START A THREAD TO WATCH FOR DATA READY
  static pthread_t dataready_tid = 0;
  if ( nfds )
  {
    void *userdata = (void*)GetCurrentEventQueue();

    // PREPARE INTER-THREAD DATA
    pthread_mutex_init(&select_mutex, NULL);

    if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; }
    if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; }
    pipe(G_pipe);

    DEBUGMSG("*** START THREAD\n");
    pthread_create(&dataready_tid, NULL, dataready_thread, userdata);
  }

  fl_unlock_function();

  SetEventLoopTimerNextFireTime( timer, time );
  RunApplicationEventLoop(); // will return after the previously set time
  if ( dataready_tid != 0 )
  {
      DEBUGMSG("*** CANCEL THREAD: ");
      pthread_cancel(dataready_tid);		// cancel first
      write(G_pipe[1], "x", 1);		// then wakeup thread from select
      pthread_join(dataready_tid, NULL);	// wait for thread to finish
      if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; }
      if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; }
      dataready_tid = 0;
      DEBUGMSG("OK\n");
  }

  fl_lock_function();

#if CONSOLIDATE_MOTION
  if (send_motion && send_motion == fl_xmousewin) {
    send_motion = 0;
    Fl::handle(FL_MOVE, fl_xmousewin);
  }
#endif

  return time;
}


/**
 * This public function handles all events. It wait a maximum of 
 * 'time' secods for an event. This version returns 1 if events
 * other than the timeout timer were processed.
 *
 * \todo there is no socket handling in this code whatsoever
 */
int fl_wait( double time ) 
{
  do_queued_events( time );
  return (got_events);
}


/**
 * event handler for Apple-Q key combination
 * this is also called from the Carbon Window handler after all windows were closed
 */
static OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon )
{
  fl_lock_function();

  while ( Fl_X::first ) {
    Fl_X *x = Fl_X::first;
    Fl::handle( FL_CLOSE, x->w );
    if ( Fl_X::first == x ) {
      fl_unlock_function();
      return noErr; // FLTK has not close all windows, so we return to the main program now
    }
  }
  ExitToShell();

  fl_unlock_function();

  return noErr;
}


/**
 * Carbon Window handler
 * This needs to be linked into all new window event handlers
 */
static pascal OSStatus carbonWindowHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
{
  UInt32 kind = GetEventKind( event );
  OSStatus ret = eventNotHandledErr;
  Fl_Window *window = (Fl_Window*)userData;

  Rect currentBounds, originalBounds;
  WindowClass winClass;
  static Fl_Window *activeWindow = 0;
  
  fl_lock_function();
  
  switch ( kind )
  {
  case kEventWindowDrawContent:
    handleUpdateEvent( fl_xid( window ) );
    ret = noErr;
    break;
  case kEventWindowBoundsChanged: {
    GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &currentBounds );
    GetEventParameter( event, kEventParamOriginalBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &originalBounds );
    int X = currentBounds.left, W = currentBounds.right-X;
    int Y = currentBounds.top, H = currentBounds.bottom-Y;
    resize_from_system = window;
    window->resize( X, Y, W, H );
    if ( ( originalBounds.right - originalBounds.left != W ) 
      || ( originalBounds.bottom - originalBounds.top != H ) )
    {
      if ( window->shown() ) 
        handleUpdateEvent( fl_xid( window ) );
    } 
    break; }
  case kEventWindowShown:
    if ( !window->parent() )
    {
      GetWindowClass( fl_xid( window ), &winClass );
      if ( winClass != kHelpWindowClass ) {	// help windows can't get the focus!
        Fl::handle( FL_FOCUS, window);
        activeWindow = window;
      }
      Fl::handle( FL_SHOW, window);
    }
    break;
  case kEventWindowHidden:
    if ( !window->parent() ) Fl::handle( FL_HIDE, window);
    break;
  case kEventWindowActivated:
    if ( window!=activeWindow ) 
    {
      GetWindowClass( fl_xid( window ), &winClass );
      if ( winClass != kHelpWindowClass ) {	// help windows can't get the focus!
        Fl::handle( FL_FOCUS, window);
        activeWindow = window;
      }
    }
    break;
  case kEventWindowDeactivated:
    if ( window==activeWindow ) 
    {
      Fl::handle( FL_UNFOCUS, window);
      activeWindow = 0;
    }
    break;
  case kEventWindowClose:
    Fl::handle( FL_CLOSE, window ); // this might or might not close the window
    // if there are no more windows, send a high-level quit event
    if (!Fl_X::first) QuitAppleEventHandler( 0, 0, 0 );
    ret = noErr; // returning noErr tells Carbon to stop following up on this event
    break;
  }

  fl_unlock_function();

  return ret;
}


/**
 * Carbon Mousewheel handler
 * This needs to be linked into all new window event handlers
 */
static pascal OSStatus carbonMousewheelHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
{
  Fl_Window *window = (Fl_Window*)userData;
  EventMouseWheelAxis axis;

  fl_lock_function();
  
  GetEventParameter( event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &axis );
  long delta;
  GetEventParameter( event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(long), NULL, &delta );
  if ( axis == kEventMouseWheelAxisX )
  {
    Fl::e_dx = delta;
    if ( Fl::e_dx) Fl::handle( FL_MOUSEWHEEL, window );
  }
  else if ( axis == kEventMouseWheelAxisY )
  {
    Fl::e_dy = -delta;
    if ( Fl::e_dy) Fl::handle( FL_MOUSEWHEEL, window );
  }
  else {
    fl_unlock_function();

    return eventNotHandledErr;
  }

  fl_unlock_function();
  
  return noErr;
}


/**
 * convert the current mouse chord into the FLTK modifier state
 */
static void chord_to_e_state( UInt32 chord )
{
  static ulong state[] = 
  { 
    0, FL_BUTTON1, FL_BUTTON3, FL_BUTTON1|FL_BUTTON3, FL_BUTTON2,
    FL_BUTTON2|FL_BUTTON1, FL_BUTTON2|FL_BUTTON3, FL_BUTTON2|FL_BUTTON1|FL_BUTTON3
  };
  Fl::e_state = ( Fl::e_state & 0xff0000 ) | state[ chord & 0x07 ];
}


/**
 * Carbon Mouse Button Handler
 */
static pascal OSStatus carbonMouseHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
{
  static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 };
  static int px, py;

  fl_lock_function();
  
  fl_os_event = event;
  Fl_Window *window = (Fl_Window*)userData;
  Point pos;
  GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pos );
  EventMouseButton btn;
  GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &btn );
  UInt32 clickCount;
  GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &clickCount );
  UInt32 chord;
  GetEventParameter( event, kEventParamMouseChord, typeUInt32, NULL, sizeof(UInt32), NULL, &chord );
  WindowRef xid = fl_xid(window), tempXid;
  int sendEvent = 0, part;
  switch ( GetEventKind( event ) )
  {
  case kEventMouseDown:
    part = FindWindow( pos, &tempXid );
    if ( part != inContent ) {
      fl_unlock_function();
      return CallNextEventHandler( nextHandler, event ); // let the OS handle this for us
    }
    if ( !IsWindowActive( xid ) )
      CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect
    // normal handling of mouse-down follows
    fl_os_capture = xid;
    sendEvent = FL_PUSH;
    Fl::e_is_click = 1; px = pos.h; py = pos.v;
    Fl::e_clicks = clickCount-1;
    // fall through
  case kEventMouseUp:
    if ( !window ) break;
    if ( !sendEvent ) {
      sendEvent = FL_RELEASE; 
    }
    Fl::e_keysym = keysym[ btn ];
    // fall through
  case kEventMouseMoved:
    if ( !sendEvent ) { 
      sendEvent = FL_MOVE; chord = 0; 
    }
    // fall through
  case kEventMouseDragged:
    if ( !sendEvent ) {
      sendEvent = FL_MOVE; // Fl::handle will convert into FL_DRAG
      if (abs(pos.h-px)>5 || abs(pos.v-py)>5) 
        Fl::e_is_click = 0;
    }
    chord_to_e_state( chord );
    GrafPtr oldPort;
    GetPort( &oldPort );
    SetPort( GetWindowPort(xid) ); // \todo replace this! There must be some GlobalToLocal call that has a port as an argument
    SetOrigin(0, 0);
    Fl::e_x_root = pos.h;
    Fl::e_y_root = pos.v;
    GlobalToLocal( &pos );
    Fl::e_x = pos.h;
    Fl::e_y = pos.v;
    SetPort( oldPort );
    Fl::handle( sendEvent, window );
    break;
  }

  fl_unlock_function();
  
  return noErr;
}


/**
 * convert the current mouse chord into the FLTK modifier state
 */
static void mods_to_e_state( UInt32 mods )
{
  long state = 0;
  if ( mods & kEventKeyModifierNumLockMask ) state |= FL_NUM_LOCK;
  if ( mods & cmdKey ) state |= FL_META;
  if ( mods & (optionKey|rightOptionKey) ) state |= FL_ALT;
  if ( mods & (controlKey|rightControlKey) ) state |= FL_CTRL;
  if ( mods & (shiftKey|rightShiftKey) ) state |= FL_SHIFT;
  if ( mods & alphaLock ) state |= FL_CAPS_LOCK;
  Fl::e_state = ( Fl::e_state & 0xff000000 ) | state;
  //printf( "State 0x%08x (%04x)\n", Fl::e_state, mods );
}


/**
 * convert the current mouse chord into the FLTK keysym
 */
static void mods_to_e_keysym( UInt32 mods )
{
  if ( mods & cmdKey ) Fl::e_keysym = FL_Meta_L;
  else if ( mods & kEventKeyModifierNumLockMask ) Fl::e_keysym = FL_Num_Lock;
  else if ( mods & optionKey ) Fl::e_keysym = FL_Alt_L;
  else if ( mods & rightOptionKey ) Fl::e_keysym = FL_Alt_R;
  else if ( mods & controlKey ) Fl::e_keysym = FL_Control_L;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -