//////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #include #include #include "osxGraphicsWindow.h" #include "config_osxdisplay.h" #include "osxGraphicsPipe.h" #include "pStatTimer.h" #include "glgsg.h" #include "keyboardButton.h" #include "mouseButton.h" #include "osxGraphicsStateGuardian.h" #include "osxGraphicsPipe.h" #include "throw_event.h" #include "pnmImage.h" #include "virtualFileSystem.h" #include "config_util.h" #include #include #include ////////////////////////// Global Objects ..... TypeHandle osxGraphicsWindow::_type_handle; osxGraphicsWindow * osxGraphicsWindow::FullScreenWindow = NULL; //////////////////////////////////////////////////////////////////// // Function: GetCurrentOSxWindow // Access: Static, // Description: How to find the active window for events on osx.. // //////////////////////////////////////////////////////////////////// osxGraphicsWindow* osxGraphicsWindow::GetCurrentOSxWindow(WindowRef window) { if(FullScreenWindow != NULL) return FullScreenWindow; if (NULL == window) // HID use this path { // Assume first we are a child window. If we cant find a window of that class, then we // are standalone and can jsut grab the front window. window = GetFrontWindowOfClass(kSimpleWindowClass, TRUE); if (NULL == window) window = FrontNonFloatingWindow(); } if (window) return (osxGraphicsWindow *)GetWRefCon (window); else return NULL; } //////////////////////////////////////////////////////////////////// // Function: aglReportError // Access: public // Description: Helper function for AGL error message and Grabing error code if any // //////////////////////////////////////////////////////////////////// OSStatus aglReportError(const std::string &comment) { GLenum err = aglGetError(); if (err != AGL_NO_ERROR ) osxdisplay_cat.error()<<"AGL Error " << aglErrorString(err) << "[" <> 1; i += rowBytes, j -= rowBytes) { memcpy( tBuffer, &imageData[i], rowBytes ); memcpy( &imageData[i], &imageData[j], rowBytes ); memcpy( &imageData[j], tBuffer, rowBytes ); } free(tBuffer); } //////////////////////////////////////////////////////////////////// // Function: CompositeGLBufferIntoWindow // Access: file scopre, static // Description: Drop a Gl overlay onto a carbon window.. // //////////////////////////////////////////////////////////////////// static void CompositeGLBufferIntoWindow (AGLContext ctx, Rect *bufferRect, GrafPtr out_port) { GWorldPtr pGWorld; QDErr err; // blit OpenGL content into window backing store // allocate buffer to hold pane image long width = (bufferRect->right - bufferRect->left); long height = (bufferRect->bottom - bufferRect->top); Rect src_rect = {0, 0, height, width}; Rect ddrc_rect = {0, 0, height, width}; long rowBytes = width * 4; long imageSize = rowBytes * height; char *image = (char *) NewPtr (imageSize); if (!image) { osxdisplay_cat.error() << "Out of memory in CompositeGLBufferIntoWindow()!\n"; return; // no harm in continuing } // pull GL content down to our image buffer aglSetCurrentContext( ctx ); glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image); // GL buffers are upside-down relative to QD buffers, so we need to flip it InvertGLImage( image, imageSize, rowBytes ); // create a GWorld containing our image err = NewGWorldFromPtr (&pGWorld, k32ARGBPixelFormat, &src_rect, 0, 0, 0, image, rowBytes); if (err != noErr) { osxdisplay_cat.error() << " error in NewGWorldFromPtr, called from CompositeGLBufferIntoWindow()\n"; free(image); return; } GrafPtr portSave = NULL; Boolean portChanged = QDSwapPort(out_port, &portSave); CopyBits(GetPortBitMapForCopyBits (pGWorld), GetPortBitMapForCopyBits (out_port), &src_rect, &ddrc_rect, srcCopy, 0); if (portChanged) QDSwapPort(portSave, NULL); DisposeGWorld(pGWorld); DisposePtr(image); } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::event_handler // Access: Public // Description: The standard window event handler for non-fullscreen // windows. //////////////////////////////////////////////////////////////////// OSStatus osxGraphicsWindow::event_handler(EventHandlerCallRef myHandler, EventRef event) { OSStatus result = eventNotHandledErr; UInt32 the_class = GetEventClass(event); UInt32 kind = GetEventKind(event); WindowRef window = _osx_window; // NULL; // GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); if (osxdisplay_cat.is_spam()) { osxdisplay_cat.spam() << ClockObject::get_global_clock()->get_real_time() << " event_handler: " << (void *)this << ", " << window << ", " << the_class << ", " << kind << "\n"; } switch (the_class) { case kEventClassMouse: osxdisplay_cat.info() << "Mouse movement handled by Window handler\n"; result = handleWindowMouseEvents (myHandler, event); break; case kEventClassWindow: switch (kind) { case kEventWindowCollapsing: /* Rect r; GetWindowPortBounds (window, &r); CompositeGLBufferIntoWindow( get_context(), &r, GetWindowPort (window)); UpdateCollapsedWindowDockTile (window); */ SystemSetWindowForground(false); break; case kEventWindowActivated: // called on click activation and initially SystemSetWindowForground(true); DoResize(); break; case kEventWindowDeactivated: SystemSetWindowForground(false); break; case kEventWindowClose: // called when window is being closed (close box) // This is a message from the window manager indicating that // the user has requested to close the window. user_close_request(); result = noErr; break; case kEventWindowShown: // called on initial show (not on un-minimize) if (window == FrontNonFloatingWindow ()) SetUserFocusWindow (window); break; case kEventWindowBoundsChanged: // called for resize and moves (drag) DoResize(); break; case kEventWindowZoomed: break; case kEventWindowCollapsed: { WindowProperties properties; properties.set_minimized(true); system_changed_properties(properties); } break; case kEventWindowExpanded: { WindowProperties properties; properties.set_minimized(false); system_changed_properties(properties); } break; } break; } return result; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::user_close_request // Access: Private // Description: The user has requested to close the window, for // instance with Cmd-W, or by clicking on the close // button. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::user_close_request() { string close_request_event = get_close_request_event(); if (!close_request_event.empty()) { // In this case, the app has indicated a desire to intercept the request and process it directly. throw_event(close_request_event); } else { // In this case, the default case, the app does not intend to service the request, so we do by closing the window. close_window(); } } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::SystemCloseWindow // Access: private // Description: The Windows is closed by a OS resource not by a internal request // //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::SystemCloseWindow() { if (osxdisplay_cat.is_debug()) osxdisplay_cat.debug() << "System Closing Window \n"; ReleaseSystemResources(); }; //////////////////////////////////////////////////////////////////// // Function: windowEvtHndlr // Access: file scope static // Description: The C callback for Window Events .. // // We only hook this up for non fullscreen window... so we only // handle system window events.. // //////////////////////////////////////////////////////////////////// static pascal OSStatus windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void *userData) { osxGraphicsWindow* osx_win = (osxGraphicsWindow *)userData; if (osx_win != (osxGraphicsWindow *)NULL) return osx_win->event_handler(myHandler, event); //#pragma unused (userData) // WindowRef window = NULL; // GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); // if (window != NULL) // { // osxGraphicsWindow *osx_win = osxGraphicsWindow::GetCurrentOSxWindow(window); // if (osx_win != (osxGraphicsWindow *)NULL) // return osx_win->event_handler(myHandler, event); // } return eventNotHandledErr; } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::DoResize // Access: // Description: The C callback for Window Events .. // // We only hook this up for none fullscreen window... so we only handle system window events.. // //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::DoResize(void) { osxdisplay_cat.info() << "In Resize....." << _properties << "\n"; // only in window mode .. not full screen if(_osx_window != NULL && !_is_fullscreen && _properties.has_size()) { Rect rectPort = {0,0,0,0}; CGRect viewRect = {{0.0f, 0.0f}, {0.0f, 0.0f}}; GetWindowPortBounds (_osx_window, &rectPort); viewRect.size.width = (float) (rectPort.right - rectPort.left); viewRect.size.height = (float) (rectPort.bottom - rectPort.top); // tell panda WindowProperties properties; properties.set_size((int)viewRect.size.width,(int)viewRect.size.height); properties.set_origin((int) rectPort.left,(int)rectPort.top); system_changed_properties(properties); if (osxdisplay_cat.is_debug()) osxdisplay_cat.debug() << " Resizing Window " << viewRect.size.width << " " << viewRect.size.height << "\n"; // ping gl aglUpdateContext (aglGetCurrentContext()); aglReportError("aglUpdateContext .. This is a Resize.."); osxdisplay_cat.info() << "Resize Complete.....\n"; } }; /////////////////////////////////////////////////////////////////// // Function: appEvtHndlr // Access: // Description: The C callback for APlication Events.. // // Hooked once for application // //////////////////////////////////////////////////////////////////// static pascal OSStatus appEvtHndlr (EventHandlerCallRef myHandler, EventRef event, void* userData) { #pragma unused (myHandler) OSStatus result = eventNotHandledErr; osxGraphicsWindow *osx_win = NULL; WindowRef window = NULL; UInt32 the_class = GetEventClass (event); UInt32 kind = GetEventKind (event); GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, sizeof(WindowRef), NULL, (void*) &window); osx_win = osxGraphicsWindow::GetCurrentOSxWindow(window); if (osx_win == NULL) return eventNotHandledErr; switch (the_class) { case kEventClassTextInput: if(kind == kEventTextInputUnicodeForKeyEvent) osx_win->handleTextInput(myHandler, event); //result = noErr; // // can not report handled .. the os will not sent the raw key strokes then // if(osx_win->handleTextInput(myHandler, event) == noErr) // result = noErr; break; case kEventClassKeyboard: { switch (kind) { case kEventRawKeyRepeat: case kEventRawKeyDown: result = osx_win->handleKeyInput (myHandler, event, true); break; case kEventRawKeyUp: result = osx_win->handleKeyInput (myHandler, event, false); break; case kEventRawKeyModifiersChanged: { UInt32 newModifiers; OSStatus error = GetEventParameter(event, kEventParamKeyModifiers,typeUInt32, NULL,sizeof(UInt32), NULL, &newModifiers); if(error == noErr) { osx_win->HandleModifireDeleta(newModifiers); result = noErr; } } break; } } break; case kEventClassMouse: osxdisplay_cat.info() << "Mouse movement handled by Application handler\n"; //if(osxGraphicsWindow::FullScreenWindow != NULL) result = osx_win->handleWindowMouseEvents (myHandler, event); //result = noErr; break; } return result; } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::handleTextInput // Access: // Description: Trap Unicode Input. // // //////////////////////////////////////////////////////////////////// OSStatus osxGraphicsWindow::handleTextInput (EventHandlerCallRef myHandler, EventRef theTextEvent) { UniChar *text = NULL; UInt32 actualSize = 0; OSStatus ret = GetEventParameter (theTextEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, 0, &actualSize, NULL); if(ret != noErr) return ret; text = (UniChar*)NewPtr(actualSize); if(text!= NULL) { ret = GetEventParameter (theTextEvent, kEventParamTextInputSendText,typeUnicodeText, NULL, actualSize, NULL, text); if(ret != noErr) return ret; for(unsigned int x = 0; x < actualSize/sizeof(UniChar); ++x) _input_devices[0].keystroke(text[x]); DisposePtr((char *)text); } return ret; } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::ReleaseSystemResources // Access: private.. // Description: Clean up the OS level messes.. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::ReleaseSystemResources() { if (_is_fullscreen) { _is_fullscreen = false; FullScreenWindow = NULL; if (_originalMode != NULL) CGDisplaySwitchToMode( kCGDirectMainDisplay, _originalMode ); CGDisplayRelease( kCGDirectMainDisplay ); aglSetDrawable (get_ggs_context(), NULL); _originalMode = NULL; } // if the ggs context is assigned to this window // clear it.. if (_osx_window != NULL && GetWindowPort (_osx_window) == (GrafPtr)aglGetDrawable(get_ggs_context())) aglSetDrawable (get_ggs_context(),NULL); // if we are the active gl context clear it.. if(aglGetCurrentContext() == get_ggs_context()) aglSetCurrentContext (NULL); if(_osx_window != NULL) { SetWRefCon (_osx_window, (long int) NULL); HideWindow (_osx_window); DisposeWindow(_osx_window); _osx_window = NULL; } if (_holder_aglcontext) { aglDestroyContext (_holder_aglcontext); _holder_aglcontext = NULL; } if (_pending_icon != NULL) { CGImageRelease(_pending_icon); _pending_icon = NULL; } if (_current_icon != NULL) { cerr << "release current icon\n"; CGImageRelease(_current_icon); _current_icon = NULL; } WindowProperties properties; properties.set_foreground(false); properties.set_open(false); properties.set_cursor_filename(Filename()); system_changed_properties(properties); _is_fullscreen = false; _osx_window = NULL; } static int id_seed = 100; //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// osxGraphicsWindow::osxGraphicsWindow(GraphicsPipe *pipe, const string &name, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg, GraphicsOutput *host) : GraphicsWindow(pipe, name, fb_prop, win_prop, flags, gsg, host), _osx_window(NULL), _is_fullscreen(false), _pending_icon(NULL), _current_icon(NULL), #ifdef HACK_SCREEN_HASH_CONTEXT _holder_aglcontext(NULL), #endif _originalMode(NULL), _ID(id_seed++) { GraphicsWindowInputDevice device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse"); _input_devices.push_back(device); _input_devices[0].set_pointer_in_window(0, 0); _last_key_modifiers = 0; _last_buttons = 0; if (osxdisplay_cat.is_debug()) osxdisplay_cat.debug() << "osxGraphicsWindow::osxGraphicsWindow() -" <<_ID << "\n"; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::Destructor // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// osxGraphicsWindow::~osxGraphicsWindow() { if (osxdisplay_cat.is_debug()) osxdisplay_cat.debug() << "osxGraphicsWindow::~osxGraphicsWindow() -" <<_ID << "\n"; // Make sure the window callback won't come back to this // (destructed) object any more. if (_osx_window) { SetWRefCon (_osx_window, (long) NULL); } ReleaseSystemResources(); } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::get_context // Access: private.. // Description: Helper to Decide whitch context to use if any //////////////////////////////////////////////////////////////////// AGLContext osxGraphicsWindow::get_context(void) { if(_holder_aglcontext != NULL) return _holder_aglcontext; return get_ggs_context(); } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::get_ggs_context // Access: private.. // Description: //////////////////////////////////////////////////////////////////// AGLContext osxGraphicsWindow::get_ggs_context(void) { if(_gsg != NULL) { osxGraphicsStateGuardian *osxgsg = NULL; osxgsg = DCAST(osxGraphicsStateGuardian, _gsg); return osxgsg->get_context(); } return NULL; } /////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::buildGL // Access: private.. // Description: Code of the class.. used to control the GL context Allocation .. //////////////////////////////////////////////////////////////////// OSStatus osxGraphicsWindow:: buildGL(bool full_screen) { // make sure the ggs is up and runnig.. osxGraphicsStateGuardian *osxgsg = NULL; osxgsg = DCAST(osxGraphicsStateGuardian, _gsg); OSStatus stat = osxgsg->buildGL(*this, full_screen, _fb_properties); if(stat != noErr) { return stat; } OSStatus err = noErr; if (osxgsg->getAGlPixelFormat()) { _holder_aglcontext = aglCreateContext(osxgsg->getAGlPixelFormat(),NULL); err = aglReportError ("aglCreateContext"); if(_holder_aglcontext == NULL) { osxdisplay_cat.error() << "osxGraphicsWindow::buildG Error aglCreateContext \n"; if(err ==noErr) err = -1; } else { aglSetInteger (_holder_aglcontext, AGL_BUFFER_NAME, &osxgsg->SharedBuffer); err = aglReportError ("aglSetInteger AGL_BUFFER_NAME"); } } else { osxdisplay_cat.error() << "osxGraphicsWindow::buildG Error Getting PixelFormat \n"; if(err ==noErr) { err = -1; } } return err; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::set_icon_filename // Access: Private // Description: Called internally to load up an icon file that should // be applied to the window. Returns true on success, // false on failure. //////////////////////////////////////////////////////////////////// bool osxGraphicsWindow::set_icon_filename(const Filename &icon_filename) { VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); Filename icon_pathname = icon_filename; if (!vfs->resolve_filename(icon_pathname, model_path)) { // The filename doesn't exist. osxdisplay_cat.warning() << "Could not find icon filename " << icon_filename << "\n"; return false; } PNMImage pnmimage; if (!pnmimage.read(icon_pathname)) { osxdisplay_cat.warning() << "Could not read icon filename " << icon_pathname << "\n"; return false; } CGImageRef icon_image = osxGraphicsPipe::create_cg_image(pnmimage); if (icon_image == NULL) { return false; } if (_pending_icon != NULL) { CGImageRelease(_pending_icon); _pending_icon = NULL; } _pending_icon = icon_image; return true; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::begin_frame // Access: Public, Virtual // Description: This function will be called within the draw thread // before beginning rendering for a given frame. It // should do whatever setup is required, and return true // if the frame should be rendered, or false if it // should be skipped. //////////////////////////////////////////////////////////////////// bool osxGraphicsWindow::begin_frame(FrameMode mode, Thread *current_thread) { PStatTimer timer(_make_current_pcollector); begin_frame_spam(mode); if (_gsg == (GraphicsStateGuardian *)NULL || (_osx_window == NULL && !_is_fullscreen)) { // not powered up .. just abort.. return false; } // Now is a good time to apply the icon change that may have // recently been requested. By this point, we should be able to get // a handle to the dock context. if (_pending_icon != NULL) { CGContextRef context = BeginCGContextForApplicationDockTile(); if (context != NULL) { SetApplicationDockTileImage(_pending_icon); EndCGContextForApplicationDockTile(context); if (_current_icon != NULL) { CGImageRelease(_current_icon); _current_icon = NULL; } _current_icon = _pending_icon; _pending_icon = NULL; } } if (_is_fullscreen) { aglSetFullScreen(get_ggs_context(),0,0,0,0); aglReportError ("aglSetFullScreen"); if (!aglSetCurrentContext(get_ggs_context())) aglReportError ("aglSetCurrentContext"); }else { if (FullScreenWindow != NULL) { return false; } if (!aglSetDrawable (get_ggs_context(), GetWindowPort (_osx_window))) { osxdisplay_cat.error() << "Error aglSetDrawable \n"; aglReportError("aglSetDrawable"); } if (!aglSetCurrentContext(get_ggs_context())) { osxdisplay_cat.error() << "Error in aglSetCurrentContext \n"; aglReportError ("aglSetCurrentContext"); } } _gsg->reset_if_new(); _gsg->set_current_properties(&get_fb_properties()); return _gsg->begin_frame(current_thread); } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::end_frame // Access: Public, Virtual // Description: This function will be called within the draw thread // after rendering is completed for a given frame. It // should do whatever finalization is required. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::end_frame(FrameMode mode, Thread *current_thread) { end_frame_spam(mode); if(mode == FM_render ) { nassertv(_gsg != (GraphicsStateGuardian *)NULL); if (!_properties.get_fixed_size() && !_properties.get_undecorated() && !_properties.get_fullscreen() && show_resize_box) { // Draw a kludgey little resize box in the corner of the window, // so the user knows he's supposed to be able to drag the window // if he wants. DisplayRegionPipelineReader dr_reader(_default_display_region, current_thread); _gsg->prepare_display_region(&dr_reader, Lens::SC_mono); DCAST(osxGraphicsStateGuardian, _gsg)->draw_resize_box(); } aglSwapBuffers (get_ggs_context()); _gsg->end_frame(current_thread); } } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::begin_flip // Access: Public, Virtual // Description: This function will be called within the draw thread // after end_frame() has been called on all windows, to // initiate the exchange of the front and back buffers. // // This should instruct the window to prepare for the // flip at the next video sync, but it should not wait. // // We have the two separate functions, begin_flip() and // end_flip(), to make it easier to flip all of the // windows at the same time. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::end_flip() { // cerr << " end_flip [" << _ID << "]\n"; } void osxGraphicsWindow::begin_flip() { // this forces a rip to proper context // cerr << " begin_flip [" << _ID << "]\n"; return; if(_is_fullscreen) { aglSetFullScreen(get_ggs_context(),0,0,0,0); aglReportError ("aglSetFullScreen"); if (!aglSetCurrentContext(get_ggs_context())) aglReportError ("aglSetCurrentContext"); aglSwapBuffers (get_ggs_context()); } else { if(!aglSetDrawable (get_ggs_context(),GetWindowPort (_osx_window))) { osxdisplay_cat.error() << "Error aglSetDrawable \n"; aglReportError("aglSetDrawable"); } if (!aglSetCurrentContext(get_ggs_context())) { osxdisplay_cat.error() << "Error in aglSetCurrentContext \n"; aglReportError ("aglSetCurrentContext"); } aglSwapBuffers (get_ggs_context()); } } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::close_window // Access: Protected, Virtual // Description: Closes the window right now. Called from the window // thread. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::close_window() { SystemCloseWindow(); WindowProperties properties; properties.set_open(false); system_changed_properties(properties); ReleaseSystemResources(); _gsg.clear(); _active = false; GraphicsWindow::close_window(); } ////////////////////////////////////////////////////////// // HACK ALLERT ************ Undocumented OSX calls... // I can not find any other way to get the mouse focus to a window in OSX.. // //extern "C" { // struct CPSProcessSerNum // { // UInt32 lo; // UInt32 hi; // }; // //extern OSErr CPSGetCurrentProcess(CPSProcessSerNum *psn); //extern OSErr CPSEnableForegroundOperation( struct CPSProcessSerNum *psn); //extern OSErr CPSSetProcessName ( struct CPSProcessSerNum *psn, char *processname); //extern OSErr CPSSetFrontProcess( struct CPSProcessSerNum *psn); //}; //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::open_window // Access: Protected, Virtual // Description: Opens the window right now. Called from the window // thread. Returns true if the window is successfully // opened, or false if there was a problem. //////////////////////////////////////////////////////////////////// bool osxGraphicsWindow::open_window() { WindowProperties req_properties = _properties; if (_gsg == 0) { _gsg = new osxGraphicsStateGuardian(_pipe, NULL); } return OSOpenWindow(req_properties); } bool osxGraphicsWindow::OSOpenWindow(WindowProperties &req_properties) { OSErr err = noErr; if (_current_icon != NULL && _pending_icon == NULL) { // If we already have an icon specified, we'll need to reapply it // when the window is succesfully created. _pending_icon = _current_icon; _current_icon = NULL; } static bool GlobalInits = false; if (!GlobalInits) { // // one time aplication inits.. to get a window open from a standalone aplication.. EventHandlerRef ref1; EventTypeSpec list1[] = { //{ kEventClassCommand, kEventProcessCommand }, //{ kEventClassCommand, kEventCommandUpdateStatus }, { kEventClassMouse, kEventMouseDown },// handle trackball functionality globaly because there is only a single user { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseWheelMoved } , { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyUp } , { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassKeyboard, kEventRawKeyModifiersChanged } , { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}, }; EventHandlerUPP gEvtHandler = NewEventHandlerUPP(appEvtHndlr); err = InstallApplicationEventHandler (gEvtHandler, GetEventTypeCount (list1) , list1, this, &ref1 ); GlobalInits = true; // Replicating the hacky code with more document/support code which should do the same thing ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToForegroundApplication); SetFrontProcess(&psn); // Hacky code // struct CPSProcessSerNum PSN; // GetCurrentProcess((ProcessSerialNumber *)&PSN); // err = CPSGetCurrentProcess(&PSN); // if (req_properties.has_title()) // err = CPSSetProcessName(&PSN,(char *)req_properties.get_title().c_str()); // else // err = CPSSetProcessName(&PSN,""); // err = CPSEnableForegroundOperation(&PSN); // err = CPSSetFrontProcess(&PSN); } if (req_properties.has_fullscreen() && req_properties.get_fullscreen()) { osxdisplay_cat.info() << "Creating full screen\n"; // capture the main display CGDisplayCapture( kCGDirectMainDisplay ); // if sized try and switch it.. if (req_properties.has_size()) { _originalMode = CGDisplayCurrentMode( kCGDirectMainDisplay ); CFDictionaryRef newMode = CGDisplayBestModeForParameters( kCGDirectMainDisplay, 32, req_properties.get_x_size(), req_properties.get_y_size(), 0 ); if (newMode == NULL) { osxdisplay_cat.error() << "Invalid fullscreen size: " << req_properties.get_x_size() << ", " << req_properties.get_y_size() << "\n"; } else { CGDisplaySwitchToMode( kCGDirectMainDisplay, newMode); // Set our new window size according to the size we actually got. SInt32 width, height; CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayWidth), kCFNumberSInt32Type, &width); CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayHeight), kCFNumberSInt32Type, &height); _properties.set_size(width, height); } } if (buildGL(true) != noErr) { if(_originalMode != NULL) CGDisplaySwitchToMode( kCGDirectMainDisplay, _originalMode ); _originalMode = NULL; CGDisplayRelease( kCGDirectMainDisplay ); return false; } _properties.set_fullscreen(true); _is_fullscreen =true; FullScreenWindow = this; req_properties.clear_fullscreen(); } else { Rect r; if (req_properties.has_origin()) { r.top = req_properties.get_y_origin(); r.left =req_properties.get_x_origin(); } else { r.top = 50; r.left = 10; } if (req_properties.has_size()) { r.right = r.left + req_properties.get_x_size(); r.bottom = r.top + req_properties.get_y_size(); } else { r.right = r.left + 512; r.bottom = r.top + 512; } if (req_properties.has_parent_window()) { NSWindow* parentWindow = (NSWindow *)req_properties.get_parent_window(); NSView* aView = [[parentWindow contentView] viewWithTag:378]; NSRect aRect = [aView frame]; NSPoint origin = [parentWindow convertBaseToScreen:aRect.origin]; osxdisplay_cat.info() << "Creating child window\n"; CreateNewWindow(kSimpleWindowClass, kWindowNoAttributes, &r, &_osx_window); NSWindow* childWindow = [[NSWindow alloc] initWithWindowRef:_osx_window]; [childWindow setFrameOrigin:origin]; [childWindow setAcceptsMouseMovedEvents:YES]; [childWindow setBackgroundColor:[NSColor blackColor]]; [parentWindow addChildWindow:childWindow ordered:NSWindowAbove]; [childWindow orderFront:nil]; _properties.set_fixed_size(true); } else { if (req_properties.has_undecorated() && req_properties.get_undecorated()) { // create a unmovable .. no edge window.. osxdisplay_cat.info() << "Creating undecorated window\n"; CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowNoTitleBarAttribute, &r, &_osx_window); } else { // create a window with crome and sizing and sucj // In this case, we want to constrain the window to the // available size. Rect bounds; GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); r.left = max(r.left, bounds.left); r.right = min(r.right, bounds.right); r.top = max(r.top, bounds.top); r.bottom = min(r.bottom, bounds.bottom); osxdisplay_cat.info() << "Creating standard window\n"; CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute, &r, &_osx_window); } } if (_osx_window) { EventHandlerUPP gWinEvtHandler; // window event handler EventTypeSpec list[] = { { kEventClassWindow, kEventWindowCollapsing }, { kEventClassWindow, kEventWindowShown }, { kEventClassWindow, kEventWindowActivated }, { kEventClassWindow, kEventWindowDeactivated }, { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowExpanded }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowClosed }, }; SetWRefCon (_osx_window, (long) this); // point to the window record in the ref con of the window gWinEvtHandler = NewEventHandlerUPP(windowEvtHndlr); InstallWindowEventHandler(_osx_window, gWinEvtHandler, GetEventTypeCount(list), list, (void*)this, NULL); // add event handler ShowWindow (_osx_window); if(buildGL(false) != noErr) { osxdisplay_cat.error() << " Error In Generate GL \n"; HideWindow (_osx_window); SetWRefCon (_osx_window, (long int) NULL); DisposeWindow(_osx_window); _osx_window = NULL; return false; } // // atach the holder context to the window.. // if (!aglSetDrawable(_holder_aglcontext, GetWindowPort (_osx_window))) err = aglReportError ("aglSetDrawable"); if (req_properties.has_fullscreen()) { _properties.set_fullscreen(false); req_properties.clear_fullscreen(); } if (req_properties.has_undecorated()) { _properties.set_undecorated(req_properties.get_undecorated()); req_properties.clear_undecorated(); } } // Now measure the size and placement of the window we // actually ended up with. Rect rectPort = {0,0,0,0}; GetWindowPortBounds (_osx_window, &rectPort); _properties.set_size((int)(rectPort.right - rectPort.left),(int) (rectPort.bottom - rectPort.top)); req_properties.clear_size(); req_properties.clear_origin(); } if (req_properties.has_icon_filename()) set_icon_filename(req_properties.get_icon_filename()); _properties.set_foreground(true); _properties.set_minimized(false); _properties.set_open(true); if (_properties.has_size()) set_size_and_recalc(_properties.get_x_size(), _properties.get_y_size()); return (err == noErr); } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::process_events() // Access: virtual, protected // Description: Required Event upcall . Used to dispatch Window and Aplication Events // back into panda // //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::process_events() { GraphicsWindow::process_events(); if (!osx_disable_event_loop) { EventRef theEvent; EventTargetRef theTarget = GetEventDispatcherTarget(); if (!_properties.has_parent_window()) { while (ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &theEvent)== noErr) { SendEventToEventTarget (theEvent, theTarget); ReleaseEvent(theEvent); } } } }; //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::handleKeyInput() // Access: virtual, protected // Description: Required Event upcall . Used to dispatch Window and Aplication Events // back into panda // //////////////////////////////////////////////////////////////////// // key input handler OSStatus osxGraphicsWindow::handleKeyInput (EventHandlerCallRef myHandler, EventRef event, Boolean keyDown) { if (osxdisplay_cat.is_debug()) { UInt32 keyCode; GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); osxdisplay_cat.debug() << ClockObject::get_global_clock()->get_real_time() << " handleKeyInput: " << (void *)this << ", " << keyCode << ", " << (int)keyDown << "\n"; } CallNextEventHandler(myHandler, event); // We don't check the result of the above function. In principle, // this should return eventNotHandledErr if the key event is not // handled by the OS, but in practice, testing this just seems to // eat the Escape keypress meaninglessly. Keypresses like F11 that // are already mapped in the desktop seem to not even come into this // function in the first place. UInt32 newModifiers = 0; OSStatus error = GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &newModifiers); if(error == noErr) HandleModifireDeleta(newModifiers); UInt32 keyCode; GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); ButtonHandle button = OSX_TranslateKey(keyCode, event); if (keyDown) { if ((newModifiers & cmdKey) != 0) { if (button == KeyboardButton::ascii_key("q") || button == KeyboardButton::ascii_key("w")) { // Command-Q or Command-W: quit the application or close the // window, respectively. For now, we treat them both the // same: close the window. user_close_request(); } } SendKeyEvent(button, true); } else { SendKeyEvent(button, false); } return noErr; } //////////////////////////////////////////////////////////////////// // Function: // Access: // Description: //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::SystemSetWindowForground(bool forground) { WindowProperties properties; properties.set_foreground(forground); system_changed_properties(properties); } //////////////////////////////////////////////////////////////////// // Function: // Access: // Description: //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::SystemPointToLocalPoint(Point &qdGlobalPoint) { if(_osx_window != NULL) { GrafPtr savePort; Boolean portChanged = QDSwapPort(GetWindowPort(_osx_window), &savePort); GlobalToLocal(&qdGlobalPoint); if (portChanged) QDSwapPort(savePort, NULL); } } //////////////////////////////////////////////////////////////////// // Function: // Access: // Description: //////////////////////////////////////////////////////////////////// OSStatus osxGraphicsWindow::handleWindowMouseEvents (EventHandlerCallRef myHandler, EventRef event) { WindowRef window = NULL; OSStatus result = eventNotHandledErr; UInt32 kind = GetEventKind (event); EventMouseButton button = 0; Point qdGlobalPoint = {0, 0}; UInt32 modifiers = 0; Rect rectPort; SInt32 wheelDelta; EventMouseWheelAxis wheelAxis; // cerr <<" Start Mouse Event " << _ID << "\n"; // Mac OS X v10.1 and later // should this be front window??? GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); if(!_is_fullscreen && (window == NULL || window != _osx_window )) return eventNotHandledErr; GetWindowPortBounds (window, &rectPort); result = CallNextEventHandler(myHandler, event); if (eventNotHandledErr == result) { // only handle events not already handled (prevents wierd resize interaction) switch (kind) { // Whenever mouse button state changes, generate the // appropriate Panda down/up events to represent the // change. case kEventMouseDown: case kEventMouseUp: { GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (_properties.get_mouse_mode() == WindowProperties::M_relative) { GetEventParameter(event, kEventParamMouseDelta,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); MouseData currMouse = get_pointer(0); qdGlobalPoint.h += currMouse.get_x(); qdGlobalPoint.v += currMouse.get_y(); } else { GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); SystemPointToLocalPoint(qdGlobalPoint); } _input_devices[0].set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); UInt32 new_buttons = GetCurrentEventButtonState(); HandleButtonDelta(new_buttons); } result = noErr; break; case kEventMouseMoved: case kEventMouseDragged: if(_properties.get_mouse_mode()==WindowProperties::M_relative) { GetEventParameter(event, kEventParamMouseDelta,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); MouseData currMouse=get_pointer(0); qdGlobalPoint.h+=currMouse.get_x(); qdGlobalPoint.v+=currMouse.get_y(); } else { GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); SystemPointToLocalPoint(qdGlobalPoint); } _input_devices[0].set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); result = noErr; break; case kEventMouseWheelMoved: GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(wheelDelta), NULL, &wheelDelta); GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(wheelAxis), NULL, &wheelAxis ); GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); SystemPointToLocalPoint(qdGlobalPoint); if (wheelAxis == kEventMouseWheelAxisY) { _input_devices[0].set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); if (wheelDelta > 0) { _input_devices[0].button_down(MouseButton::wheel_up()); result = noErr; } else if (wheelDelta < 0) { _input_devices[0].button_down(MouseButton::wheel_down()); } } result = noErr; break; } // result = noErr; } // cerr <<" End Mouse Event \n"; return result; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::OSX_TranslateKey // Access: Private // Description: MAC Key Codes to Panda Key Codes //////////////////////////////////////////////////////////////////// ButtonHandle osxGraphicsWindow::OSX_TranslateKey(UInt32 key, EventRef event) { ButtonHandle nk = ButtonHandle::none(); switch ( key ) { case 0: nk = KeyboardButton::ascii_key('a'); break; case 11: nk = KeyboardButton::ascii_key('b'); break; case 8: nk = KeyboardButton::ascii_key('c'); break; case 2: nk = KeyboardButton::ascii_key('d'); break; case 14: nk = KeyboardButton::ascii_key('e'); break; case 3: nk = KeyboardButton::ascii_key('f'); break; case 5: nk = KeyboardButton::ascii_key('g'); break; case 4: nk = KeyboardButton::ascii_key('h'); break; case 34: nk = KeyboardButton::ascii_key('i'); break; case 38: nk = KeyboardButton::ascii_key('j'); break; case 40: nk = KeyboardButton::ascii_key('k'); break; case 37: nk = KeyboardButton::ascii_key('l'); break; case 46: nk = KeyboardButton::ascii_key('m'); break; case 45: nk = KeyboardButton::ascii_key('n'); break; case 31: nk = KeyboardButton::ascii_key('o'); break; case 35: nk = KeyboardButton::ascii_key('p'); break; case 12: nk = KeyboardButton::ascii_key('q'); break; case 15: nk = KeyboardButton::ascii_key('r'); break; case 1: nk = KeyboardButton::ascii_key('s'); break; case 17: nk = KeyboardButton::ascii_key('t'); break; case 32: nk = KeyboardButton::ascii_key('u'); break; case 9: nk = KeyboardButton::ascii_key('v'); break; case 13: nk = KeyboardButton::ascii_key('w'); break; case 7: nk = KeyboardButton::ascii_key('x'); break; case 16: nk = KeyboardButton::ascii_key('y'); break; case 6: nk = KeyboardButton::ascii_key('z'); break; // top row numbers case 29: nk = KeyboardButton::ascii_key('0'); break; case 18: nk = KeyboardButton::ascii_key('1'); break; case 19: nk = KeyboardButton::ascii_key('2'); break; case 20: nk = KeyboardButton::ascii_key('3'); break; case 21: nk = KeyboardButton::ascii_key('4'); break; case 23: nk = KeyboardButton::ascii_key('5'); break; case 22: nk = KeyboardButton::ascii_key('6'); break; case 26: nk = KeyboardButton::ascii_key('7'); break; case 28: nk = KeyboardButton::ascii_key('8'); break; case 25: nk = KeyboardButton::ascii_key('9'); break; // key pad ... do they really map to the top number in panda ? case 82: nk = KeyboardButton::ascii_key('0'); break; case 83: nk = KeyboardButton::ascii_key('1'); break; case 84: nk = KeyboardButton::ascii_key('2'); break; case 85: nk = KeyboardButton::ascii_key('3'); break; case 86: nk = KeyboardButton::ascii_key('4'); break; case 87: nk = KeyboardButton::ascii_key('5'); break; case 88: nk = KeyboardButton::ascii_key('6'); break; case 89: nk = KeyboardButton::ascii_key('7'); break; case 91: nk = KeyboardButton::ascii_key('8'); break; case 92: nk = KeyboardButton::ascii_key('9'); break; // case 36: nk = KeyboardButton::ret(); break; // no return in panda ??? case 49: nk = KeyboardButton::space(); break; case 51: nk = KeyboardButton::backspace(); break; case 48: nk = KeyboardButton::tab(); break; case 53: nk = KeyboardButton::escape(); break; case 76: nk = KeyboardButton::enter(); break; case 36: nk = KeyboardButton::enter(); break; case 123: nk = KeyboardButton::left(); break; case 124: nk = KeyboardButton::right(); break; case 125: nk = KeyboardButton::down(); break; case 126: nk = KeyboardButton::up(); break; case 116: nk = KeyboardButton::page_up(); break; case 121: nk = KeyboardButton::page_down(); break; case 115: nk = KeyboardButton::home(); break; case 119: nk = KeyboardButton::end(); break; case 114: nk = KeyboardButton::help(); break; case 117: nk = KeyboardButton::del(); break; // case 71: nk = KeyboardButton::num_lock() break; case 122: nk = KeyboardButton::f1(); break; case 120: nk = KeyboardButton::f2(); break; case 99: nk = KeyboardButton::f3(); break; case 118: nk = KeyboardButton::f4(); break; case 96: nk = KeyboardButton::f5(); break; case 97: nk = KeyboardButton::f6(); break; case 98: nk = KeyboardButton::f7(); break; case 100: nk = KeyboardButton::f8(); break; case 101: nk = KeyboardButton::f9(); break; case 109: nk = KeyboardButton::f10(); break; case 103: nk = KeyboardButton::f11(); break; case 111: nk = KeyboardButton::f12(); break; case 105: nk = KeyboardButton::f13(); break; case 107: nk = KeyboardButton::f14(); break; case 113: nk = KeyboardButton::f15(); break; case 106: nk = KeyboardButton::f16(); break; // shiftable chartablet case 50: nk = KeyboardButton::ascii_key('`'); break; case 27: nk = KeyboardButton::ascii_key('-'); break; case 24: nk = KeyboardButton::ascii_key('='); break; case 33: nk = KeyboardButton::ascii_key('['); break; case 30: nk = KeyboardButton::ascii_key(']'); break; case 42: nk = KeyboardButton::ascii_key('\\'); break; case 41: nk = KeyboardButton::ascii_key(';'); break; case 39: nk = KeyboardButton::ascii_key('\''); break; case 43: nk = KeyboardButton::ascii_key(','); break; case 47: nk = KeyboardButton::ascii_key('.'); break; case 44: nk = KeyboardButton::ascii_key('/'); break; default: if (osxdisplay_cat.is_debug()) { osxdisplay_cat.debug() << " Untranslated KeyCode: " << key << " (0x" << hex << key << dec << ")\n"; } // not sure this is right .. but no mapping for keypad and such // this at least does a best gess.. char charCode = 0; if(GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, nil, sizeof( charCode ), nil, &charCode ) == noErr) nk = KeyboardButton::ascii_key(charCode); } return nk; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::HandleModifireDeleta // Access: Private // Description: Used to emulate key events for the MAC key Modifiers.. //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::HandleModifireDeleta(UInt32 newModifiers) { UInt32 changed = _last_key_modifiers ^ newModifiers; if ((changed & (shiftKey | rightShiftKey)) != 0) SendKeyEvent(KeyboardButton::shift(),(newModifiers & (shiftKey | rightShiftKey)) != 0) ; if ((changed & (optionKey | rightOptionKey)) != 0) SendKeyEvent(KeyboardButton::alt(),(newModifiers & (optionKey | rightOptionKey)) != 0); if ((changed & (controlKey | rightControlKey)) != 0) SendKeyEvent(KeyboardButton::control(),(newModifiers & (controlKey | rightControlKey)) != 0); if ((changed & cmdKey) != 0) SendKeyEvent(KeyboardButton::meta(),(newModifiers & cmdKey) != 0); if ((changed & alphaLock) != 0) SendKeyEvent(KeyboardButton::caps_lock(),(newModifiers & alphaLock) != 0); // save current state _last_key_modifiers = newModifiers; }; //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::HandleButtonDelta // Access: Private // Description: Used to emulate buttons events/ //////////////////////////////////////////////////////////////////// void osxGraphicsWindow:: HandleButtonDelta(UInt32 new_buttons) { UInt32 changed = _last_buttons ^ new_buttons; if (changed & 0x01) { if (new_buttons & 0x01) { _input_devices[0].button_down(MouseButton::one()); } else { _input_devices[0].button_up(MouseButton::one()); } } if (changed & 0x04) { if (new_buttons & 0x04) { _input_devices[0].button_down(MouseButton::two()); } else { _input_devices[0].button_up(MouseButton::two()); } } if (changed & 0x02) { if (new_buttons & 0x02) { _input_devices[0].button_down(MouseButton::three()); } else { _input_devices[0].button_up(MouseButton::three()); } } _last_buttons = new_buttons; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::move_pointer // Access: Published, Virtual // Description: Forces the pointer to the indicated position within // the window, if possible. // // Returns true if successful, false on failure. This // may fail if the mouse is not currently within the // window, or if the API doesn't support this operation. //////////////////////////////////////////////////////////////////// bool osxGraphicsWindow::move_pointer(int device, int x, int y) { if(_osx_window == NULL) return false; if (osxdisplay_cat.is_debug()) osxdisplay_cat.debug() << "move_pointer " << device <<" "<< x <<" "<< y <<"\n"; Point pt = {0, 0}; pt.h = x; pt.v = y; _input_devices[0].set_pointer_in_window(x, y); if(_properties.get_mouse_mode()==WindowProperties::M_absolute) { LocalPointToSystemPoint(pt); CGPoint newCursorPosition = {0, 0}; newCursorPosition.x = pt.h; newCursorPosition.y = pt.v; mouse_mode_relative(); CGWarpMouseCursorPosition(newCursorPosition); mouse_mode_absolute(); } return true; }; bool osxGraphicsWindow::do_reshape_request(int x_origin, int y_origin, bool has_origin,int x_size, int y_size) { osxdisplay_cat.info() << "Do Reshape\n"; if (_properties.get_fullscreen()) { return false; } // For now, ignore the origin, since we seem to be getting a bogus // origin of (0, 0). // // We need this to be here so that changing window size places the // window in the correct position. if (has_origin) { MoveWindow(_osx_window, x_origin, y_origin, false); } if (!_properties.get_undecorated()) { // Constrain the window to the available desktop size. Rect bounds; GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); x_size = min(x_size, bounds.right - bounds.left); y_size = min(y_size, bounds.bottom - bounds.top); } SizeWindow(_osx_window, x_size, y_size, false); system_changed_size(x_size, y_size); return true; } //////////////////////////////////////////////////////////////////// // Function: osxGraphicsWindow::set_properties_now // Access: Public, Virtual // Description: Applies the requested set of properties to the // window, if possible, for instance to request a change // in size or minimization status. // // The window properties are applied immediately, rather // than waiting until the next frame. This implies that // this method may *only* be called from within the // window thread. // // The properties that have been applied are cleared // from the structure by this function; so on return, // whatever remains in the properties structure are // those that were unchanged for some reason (probably // because the underlying interface does not support // changing that property on an open window). //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::set_properties_now(WindowProperties &properties) { if (osxdisplay_cat.is_debug()) { osxdisplay_cat.debug() << "------------------------------------------------------\n"; osxdisplay_cat.debug() << "set_properties_now " << properties << "\n"; } GraphicsWindow::set_properties_now(properties); if (osxdisplay_cat.is_debug()) { osxdisplay_cat.debug() << "set_properties_now After Base Class" << properties << "\n"; } // for some changes .. a full rebuild is required for the OS layer Window. // I think it is the crome atribute and full screen behaviour. bool need_full_rebuild = false; // if we are not full and transitioning to full if (properties.has_fullscreen() && properties.get_fullscreen() != _properties.get_fullscreen()) { need_full_rebuild = true; } // If we are fullscreen and requesting a size change if (_properties.get_fullscreen() && (properties.has_size() && (properties.get_x_size() != _properties.get_x_size() || properties.get_y_size() != _properties.get_y_size()))) { need_full_rebuild = true; } if (need_full_rebuild) { // Logic here is .. take a union of the properties .. with the // new allowed to overwrite the old states. and start a bootstrap // of a new window .. // get a copy of my properties.. WindowProperties req_properties(_properties); ReleaseSystemResources(); req_properties.add_properties(properties); OSOpenWindow(req_properties); // Now we've handled all of the requested properties. properties.clear(); } if (properties.has_title()) { _properties.set_title(properties.get_title()); if (_osx_window) { SetWindowTitleWithCFString(_osx_window, CFStringCreateWithCString(NULL,properties.get_title().c_str(), kCFStringEncodingMacRoman)); } properties.clear_title(); } // An icon filename means to load up the icon and save it. We can't // necessarily apply it immediately; it will get applied later, in // the window event handler. if (properties.has_icon_filename()) { if (set_icon_filename(properties.get_icon_filename())) { properties.clear_icon_filename(); } } // decorated .. if this changes it reqires a new window if (properties.has_undecorated()) { _properties.set_undecorated(properties.get_undecorated()); properties.clear_undecorated(); } if (properties.has_cursor_hidden()) { _properties.set_cursor_hidden(properties.get_cursor_hidden()); if (properties.get_cursor_hidden()) { CGDisplayHideCursor(kCGDirectMainDisplay); } else { CGDisplayShowCursor(kCGDirectMainDisplay); } properties.clear_cursor_hidden(); } if (osxdisplay_cat.is_debug()) { osxdisplay_cat.debug() << "set_properties_now Out....." << _properties << "\n"; } return; } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// void osxGraphicsWindow::LocalPointToSystemPoint(Point &qdLocalPoint) { if(_osx_window != NULL) { GrafPtr savePort; Boolean portChanged = QDSwapPort(GetWindowPort(_osx_window), &savePort); LocalToGlobal( &qdLocalPoint ); if (portChanged) QDSwapPort(savePort, NULL); } } //////////////////////////////////////////////////////////////////// // Function: OSXGraphicsWindow::mouse_mode_relative // Access: Protected, Virtual // Description: detaches mouse. Only mouse delta from now on. // //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::mouse_mode_relative() { CGAssociateMouseAndMouseCursorPosition(false); } //////////////////////////////////////////////////////////////////// // Function: OSXGraphicsWindow::mouse_mode_absolute // Access: Protected, Virtual // Description: reattaches mouse to location // //////////////////////////////////////////////////////////////////// void osxGraphicsWindow::mouse_mode_absolute() { CGAssociateMouseAndMouseCursorPosition(true); }