|
|
@@ -0,0 +1,1791 @@
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+//
|
|
|
+// 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
|
|
|
+// [email protected] .
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+#include <Carbon/Carbon.h>
|
|
|
+#include <Cocoa/Cocoa.h>
|
|
|
+
|
|
|
+#include "tinyOsxGraphicsWindow.h"
|
|
|
+#include "config_tinydisplay.h"
|
|
|
+#include "tinyOsxGraphicsPipe.h"
|
|
|
+#include "pStatTimer.h"
|
|
|
+#include "keyboardButton.h"
|
|
|
+#include "mouseButton.h"
|
|
|
+#include "tinyGraphicsStateGuardian.h"
|
|
|
+#include "throw_event.h"
|
|
|
+#include "pnmImage.h"
|
|
|
+#include "virtualFileSystem.h"
|
|
|
+#include "config_util.h"
|
|
|
+
|
|
|
+#include <ApplicationServices/ApplicationServices.h>
|
|
|
+
|
|
|
+#include "pmutex.h"
|
|
|
+//#include "mutexHolder.h"
|
|
|
+
|
|
|
+////////////////////////////////////
|
|
|
+
|
|
|
+\
|
|
|
+Mutex & OSXGloablMutex()
|
|
|
+{
|
|
|
+ static Mutex m("OSXWIN_Mutex");
|
|
|
+ return m;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct work1
|
|
|
+{
|
|
|
+ volatile bool work_done;
|
|
|
+};
|
|
|
+
|
|
|
+#define PANDA_CREATE_WINDOW 101
|
|
|
+static void Post_Event_Wiait(unsigned short type, unsigned int data1 , unsigned int data2 , int target_window )
|
|
|
+{
|
|
|
+ work1 w;
|
|
|
+ w.work_done = false;
|
|
|
+ NSEvent *ev = [NSEvent otherEventWithType:NSApplicationDefined
|
|
|
+ location:NSZeroPoint
|
|
|
+ modifierFlags:0
|
|
|
+ timestamp:0.0f
|
|
|
+ windowNumber:target_window
|
|
|
+ context:nil
|
|
|
+ subtype:type
|
|
|
+ data1:data1
|
|
|
+ data2:(int)&w];
|
|
|
+
|
|
|
+ [NSApp postEvent:ev atStart:NO];
|
|
|
+ while(!w.work_done)
|
|
|
+ usleep(10);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////// Global Objects .....
|
|
|
+
|
|
|
+TypeHandle TinyOsxGraphicsWindow::_type_handle;
|
|
|
+TinyOsxGraphicsWindow * TinyOsxGraphicsWindow::FullScreenWindow = NULL;
|
|
|
+
|
|
|
+
|
|
|
+#define USER_CONTAINER
|
|
|
+
|
|
|
+#include <set>
|
|
|
+
|
|
|
+#ifdef USER_CONTAINER
|
|
|
+
|
|
|
+std::set< WindowRef > MyWindows;
|
|
|
+void AddAWindow( WindowRef window)
|
|
|
+{
|
|
|
+ MyWindows.insert(window);
|
|
|
+}
|
|
|
+bool checkmywindow(WindowRef window)
|
|
|
+{
|
|
|
+ return MyWindows.find(window) != MyWindows.end();
|
|
|
+}
|
|
|
+#else
|
|
|
+
|
|
|
+void AddAWindow( WindowRef window)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+bool checkmywindow(WindowRef window)
|
|
|
+{
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: GetCurrentOSxWindow
|
|
|
+// Access: Static,
|
|
|
+// Description: How to find the active window for events on osx..
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+TinyOsxGraphicsWindow* TinyOsxGraphicsWindow::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 && checkmywindow(window))
|
|
|
+ //if (window )
|
|
|
+ {
|
|
|
+ return (TinyOsxGraphicsWindow *)GetWRefCon (window);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::event_handler
|
|
|
+// Access: Public
|
|
|
+// Description: The standard window event handler for non-fullscreen
|
|
|
+// windows.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+OSStatus TinyOsxGraphicsWindow::event_handler(EventHandlerCallRef myHandler, EventRef event)
|
|
|
+{
|
|
|
+
|
|
|
+ OSStatus result = eventNotHandledErr;
|
|
|
+ UInt32 the_class = GetEventClass(event);
|
|
|
+ UInt32 kind = GetEventKind(event);
|
|
|
+
|
|
|
+ WindowRef window = NULL;
|
|
|
+ GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_spam())
|
|
|
+ {
|
|
|
+ tinydisplay_cat.spam() << ClockObject::get_global_clock()->get_real_time() << " event_handler: " << (void *)this << ", " << window << ", " << the_class << ", " << kind << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (the_class)
|
|
|
+ {
|
|
|
+ case kEventClassMouse:
|
|
|
+ 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: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::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: TinyOsxGraphicsWindow::SystemCloseWindow
|
|
|
+// Access: private
|
|
|
+// Description: The Windows is closed by a OS resource not by a internal request
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::SystemCloseWindow()
|
|
|
+{
|
|
|
+ if (tinydisplay_cat.is_debug())
|
|
|
+ tinydisplay_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)
|
|
|
+{
|
|
|
+#pragma unused (userData)
|
|
|
+
|
|
|
+// volatile().lock();
|
|
|
+
|
|
|
+ WindowRef window = NULL;
|
|
|
+ GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
|
|
|
+
|
|
|
+ if (window != NULL)
|
|
|
+ {
|
|
|
+ TinyOsxGraphicsWindow *osx_win = TinyOsxGraphicsWindow::GetCurrentOSxWindow(window);
|
|
|
+ if (osx_win != (TinyOsxGraphicsWindow *)NULL)
|
|
|
+ {
|
|
|
+ //OSXGloablMutex().release();
|
|
|
+ return osx_win->event_handler(myHandler, event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //OSXGloablMutex().release();
|
|
|
+ return eventNotHandledErr;
|
|
|
+}
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::DoResize(void)
|
|
|
+{
|
|
|
+ tinydisplay_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);
|
|
|
+ ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size());
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_debug())
|
|
|
+ tinydisplay_cat.debug() << " Resizing Window " << viewRect.size.width << " " << viewRect.size.height << "\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;
|
|
|
+ {
|
|
|
+
|
|
|
+ //OSXGloablMutex().lock();
|
|
|
+
|
|
|
+ TinyOsxGraphicsWindow *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 = TinyOsxGraphicsWindow::GetCurrentOSxWindow(window);
|
|
|
+ if (osx_win == NULL)
|
|
|
+ {
|
|
|
+ //OSXGloablMutex().release();
|
|
|
+ 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:
|
|
|
+ // tinydisplay_cat.info() << "Mouse movement handled by Application handler\n";
|
|
|
+ //if(TinyOsxGraphicsWindow::FullScreenWindow != NULL)
|
|
|
+ result = osx_win->handleWindowMouseEvents (myHandler, event);
|
|
|
+ //result = noErr;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //OSXGloablMutex().release();
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::handleTextInput
|
|
|
+// Access:
|
|
|
+// Description: Trap Unicode Input.
|
|
|
+//
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+OSStatus TinyOsxGraphicsWindow::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: TinyOsxGraphicsWindow::ReleaseSystemResources
|
|
|
+// Access: private..
|
|
|
+// Description: Clean up the OS level messes..
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::ReleaseSystemResources()
|
|
|
+{
|
|
|
+ if (_is_fullscreen)
|
|
|
+ {
|
|
|
+ _is_fullscreen = false;
|
|
|
+ FullScreenWindow = NULL;
|
|
|
+
|
|
|
+ if (_originalMode != NULL)
|
|
|
+ CGDisplaySwitchToMode( kCGDirectMainDisplay, _originalMode );
|
|
|
+
|
|
|
+ CGDisplayRelease( kCGDirectMainDisplay );
|
|
|
+
|
|
|
+ _originalMode = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(_osx_window != NULL)
|
|
|
+ {
|
|
|
+ SetWRefCon (_osx_window, (long int) NULL);
|
|
|
+ HideWindow (_osx_window);
|
|
|
+ DisposeWindow(_osx_window);
|
|
|
+ _osx_window = 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: TinyOsxGraphicsWindow::Constructor
|
|
|
+// Access: Public
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(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),
|
|
|
+ _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;
|
|
|
+
|
|
|
+ _cursor_hidden = false;
|
|
|
+ _display_hide_cursor = false;
|
|
|
+ _wheel_delta = 0;
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_debug())
|
|
|
+ tinydisplay_cat.debug() << "TinyOsxGraphicsWindow::TinyOsxGraphicsWindow() -" <<_ID << "\n";
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::Destructor
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+TinyOsxGraphicsWindow::~TinyOsxGraphicsWindow()
|
|
|
+{
|
|
|
+ if (tinydisplay_cat.is_debug())
|
|
|
+ tinydisplay_cat.debug() << "TinyOsxGraphicsWindow::~TinyOsxGraphicsWindow() -" <<_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: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::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.
|
|
|
+ tinydisplay_cat.warning()
|
|
|
+ << "Could not find icon filename " << icon_filename << "\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ PNMImage pnmimage;
|
|
|
+ if (!pnmimage.read(icon_pathname))
|
|
|
+ {
|
|
|
+ tinydisplay_cat.warning()
|
|
|
+ << "Could not read icon filename " << icon_pathname << "\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ CGImageRef icon_image = TinyOsxGraphicsPipe::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: TinyOsxGraphicsWindow::set_pointer_in_window
|
|
|
+// Access: Private
|
|
|
+// Description: Indicates the mouse pointer is seen within the
|
|
|
+// window.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::
|
|
|
+set_pointer_in_window(int x, int y)
|
|
|
+{
|
|
|
+ _input_devices[0].set_pointer_in_window(x, y);
|
|
|
+
|
|
|
+ if (_cursor_hidden != _display_hide_cursor) {
|
|
|
+ if (_cursor_hidden) {
|
|
|
+ CGDisplayHideCursor(kCGDirectMainDisplay);
|
|
|
+ _display_hide_cursor = true;
|
|
|
+ } else {
|
|
|
+ CGDisplayShowCursor(kCGDirectMainDisplay);
|
|
|
+ _display_hide_cursor = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::set_pointer_out_of_window
|
|
|
+// Access: Private
|
|
|
+// Description: Indicates the mouse pointer is no longer within the
|
|
|
+// window.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::
|
|
|
+set_pointer_out_of_window() {
|
|
|
+ _input_devices[0].set_pointer_out_of_window();
|
|
|
+
|
|
|
+ if (_display_hide_cursor) {
|
|
|
+ CGDisplayShowCursor(kCGDirectMainDisplay);
|
|
|
+ _display_hide_cursor = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ TinyGraphicsStateGuardian *tinygsg;
|
|
|
+ DCAST_INTO_R(tinygsg, _gsg, false);
|
|
|
+
|
|
|
+ tinygsg->_current_frame_buffer = _frame_buffer;
|
|
|
+ tinygsg->reset_if_new();
|
|
|
+
|
|
|
+ _gsg->set_current_properties(&get_fb_properties());
|
|
|
+ return _gsg->begin_frame(current_thread);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::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(TinyGraphicsStateGuardian, _gsg)->draw_resize_box();
|
|
|
+ }
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ _gsg->end_frame(current_thread);
|
|
|
+
|
|
|
+ if (mode == FM_render) {
|
|
|
+ trigger_flip();
|
|
|
+ if (_one_shot) {
|
|
|
+ prepare_for_deletion();
|
|
|
+ }
|
|
|
+ clear_cube_map_selection();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::end_flip()
|
|
|
+{
|
|
|
+ // cerr << " end_flip [" << _ID << "]\n";
|
|
|
+}
|
|
|
+
|
|
|
+void TinyOsxGraphicsWindow::begin_flip()
|
|
|
+{
|
|
|
+ if (_osx_window == NULL) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ QDErr err;
|
|
|
+
|
|
|
+ // blit rendered framebuffer into window backing store
|
|
|
+ long width = _frame_buffer->xsize;
|
|
|
+ long height = _frame_buffer->ysize;
|
|
|
+
|
|
|
+ Rect src_rect = {0, 0, height, width};
|
|
|
+ Rect ddrc_rect = {0, 0, height, width};
|
|
|
+
|
|
|
+ // create a GWorld containing our image
|
|
|
+ GWorldPtr pGWorld;
|
|
|
+ err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0,
|
|
|
+ (char *)_frame_buffer->pbuf, _frame_buffer->linesize);
|
|
|
+ if (err != noErr) {
|
|
|
+ tinydisplay_cat.error()
|
|
|
+ << " error in NewGWorldFromPtr, called from begin_flip()\n";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ GrafPtr out_port = GetWindowPort(_osx_window);
|
|
|
+ GrafPtr portSave = NULL;
|
|
|
+ Boolean portChanged = QDSwapPort(out_port, &portSave);
|
|
|
+
|
|
|
+ {
|
|
|
+ static PStatCollector b2("Wait:Flip:Begin:CopyBits");
|
|
|
+ PStatTimer t2(b2);
|
|
|
+ CopyBits(GetPortBitMapForCopyBits(pGWorld),
|
|
|
+ GetPortBitMapForCopyBits(out_port),
|
|
|
+ &src_rect, &ddrc_rect, srcCopy, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (portChanged) {
|
|
|
+ QDSwapPort(portSave, NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ DisposeGWorld(pGWorld);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::close_window
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: Closes the window right now. Called from the window
|
|
|
+// thread.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::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: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::open_window()
|
|
|
+{
|
|
|
+ // GSG Creation/Initialization
|
|
|
+ TinyGraphicsStateGuardian *tinygsg;
|
|
|
+ if (_gsg == 0) {
|
|
|
+ // There is no old gsg. Create a new one.
|
|
|
+ tinygsg = new TinyGraphicsStateGuardian(_pipe, NULL);
|
|
|
+ _gsg = tinygsg;
|
|
|
+ } else {
|
|
|
+ DCAST_INTO_R(tinygsg, _gsg, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ create_frame_buffer();
|
|
|
+ if (_frame_buffer == NULL) {
|
|
|
+ tinydisplay_cat.error()
|
|
|
+ << "Could not create frame buffer.\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ tinygsg->_current_frame_buffer = _frame_buffer;
|
|
|
+
|
|
|
+ tinygsg->reset_if_new();
|
|
|
+ if (!tinygsg->is_valid()) {
|
|
|
+ close_window();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ WindowProperties req_properties = _properties;
|
|
|
+ //OSXGloablMutex().lock();
|
|
|
+ bool answer = OSOpenWindow(req_properties);
|
|
|
+ //OSXGloablMutex().release();
|
|
|
+ return answer;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+bool TinyOsxGraphicsWindow::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 application_event_ref_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, &application_event_ref_ref1 );
|
|
|
+ GlobalInits = true;
|
|
|
+
|
|
|
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
|
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
|
+ SetFrontProcess(&psn);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (req_properties.has_fullscreen() && req_properties.get_fullscreen())
|
|
|
+ {
|
|
|
+ tinydisplay_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)
|
|
|
+ {
|
|
|
+ tinydisplay_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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _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())
|
|
|
+ {
|
|
|
+ tinydisplay_cat.info() << "Creating child window\n";
|
|
|
+
|
|
|
+ CreateNewWindow(kSimpleWindowClass, kWindowNoAttributes, &r, &_osx_window);
|
|
|
+ AddAWindow(_osx_window);
|
|
|
+
|
|
|
+ _properties.set_fixed_size(true);
|
|
|
+ tinydisplay_cat.info() << "Child window created\n";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (req_properties.has_undecorated() && req_properties.get_undecorated())
|
|
|
+ { // create a unmovable .. no edge window..
|
|
|
+
|
|
|
+ tinydisplay_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);
|
|
|
+
|
|
|
+ tinydisplay_cat.info() << "Creating standard window\n";
|
|
|
+ CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute, &r, &_osx_window);
|
|
|
+ AddAWindow(_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
|
|
|
+
|
|
|
+ if(!req_properties.has_parent_window())
|
|
|
+ {
|
|
|
+ ShowWindow (_osx_window);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ NSWindow* parentWindow = (NSWindow *)req_properties.get_parent_window();
|
|
|
+ // NSView* aView = [[parentWindow contentView] viewWithTag:378];
|
|
|
+ // NSRect aRect = [aView frame];
|
|
|
+ // NSPoint origin = [parentWindow convertBaseToScreen:aRect.origin];
|
|
|
+
|
|
|
+ // NSWindow* childWindow = [[NSWindow alloc] initWithWindowRef:_osx_window];
|
|
|
+
|
|
|
+
|
|
|
+ Post_Event_Wiait(PANDA_CREATE_WINDOW,(unsigned long) _osx_window,1,[parentWindow windowNumber]);
|
|
|
+
|
|
|
+ // [childWindow setFrameOrigin:origin];
|
|
|
+ // [childWindow setAcceptsMouseMovedEvents:YES];
|
|
|
+ // [childWindow setBackgroundColor:[NSColor blackColor]];
|
|
|
+ // this seems to block till the parent accepts the connection ?
|
|
|
+// [parentWindow addChildWindow:childWindow ordered:NSWindowAbove];
|
|
|
+// [childWindow orderFront:nil];
|
|
|
+
|
|
|
+
|
|
|
+ _properties.set_parent_window(req_properties.get_parent_window());
|
|
|
+ req_properties.clear_parent_window();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ 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: TinyOsxGraphicsWindow::process_events()
|
|
|
+// Access: virtual, protected
|
|
|
+// Description: Required Event upcall . Used to dispatch Window and Aplication Events
|
|
|
+// back into panda
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::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: TinyOsxGraphicsWindow::handleKeyInput()
|
|
|
+// Access: virtual, protected
|
|
|
+// Description: Required Event upcall . Used to dispatch Window and Aplication Events
|
|
|
+// back into panda
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// key input handler
|
|
|
+OSStatus TinyOsxGraphicsWindow::handleKeyInput (EventHandlerCallRef myHandler, EventRef event, Boolean keyDown) {
|
|
|
+
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_debug()) {
|
|
|
+ UInt32 keyCode;
|
|
|
+ GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
|
|
|
+
|
|
|
+ tinydisplay_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 CallNextEventHandler(myHandler, event);
|
|
|
+// return noErr;
|
|
|
+}
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////
|
|
|
+ // Function:
|
|
|
+ // Access:
|
|
|
+ // Description:
|
|
|
+ ////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::SystemSetWindowForground(bool forground)
|
|
|
+{
|
|
|
+ WindowProperties properties;
|
|
|
+ properties.set_foreground(forground);
|
|
|
+ system_changed_properties(properties);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function:
|
|
|
+// Access:
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::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 this_wheel_delta;
|
|
|
+ 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 )) {
|
|
|
+ if (kind == kEventMouseMoved)
|
|
|
+ {
|
|
|
+ set_pointer_out_of_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);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ if (kind == kEventMouseMoved &&
|
|
|
+ (qdGlobalPoint.h < 0 || qdGlobalPoint.v < 0)) {
|
|
|
+ // Moving into the titlebar region.
|
|
|
+ set_pointer_out_of_window();
|
|
|
+ } else {
|
|
|
+ // Moving within the window itself (or dragging anywhere).
|
|
|
+ set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v);
|
|
|
+ }
|
|
|
+ result = noErr;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case kEventMouseWheelMoved:
|
|
|
+ GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(this_wheel_delta), NULL, &this_wheel_delta);
|
|
|
+ GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(wheelAxis), NULL, &wheelAxis );
|
|
|
+ GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint);
|
|
|
+ SystemPointToLocalPoint(qdGlobalPoint);
|
|
|
+
|
|
|
+ if (wheelAxis == kEventMouseWheelAxisY)
|
|
|
+ {
|
|
|
+ set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v);
|
|
|
+ _wheel_delta += this_wheel_delta;
|
|
|
+ SInt32 wheel_scale = osx_mouse_wheel_scale;
|
|
|
+ while (_wheel_delta > wheel_scale) {
|
|
|
+ _input_devices[0].button_down(MouseButton::wheel_up());
|
|
|
+ _input_devices[0].button_up(MouseButton::wheel_up());
|
|
|
+ _wheel_delta -= wheel_scale;
|
|
|
+ }
|
|
|
+ while (_wheel_delta < -wheel_scale) {
|
|
|
+ _input_devices[0].button_down(MouseButton::wheel_down());
|
|
|
+ _input_devices[0].button_up(MouseButton::wheel_down());
|
|
|
+ _wheel_delta += wheel_scale;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result = noErr;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+// result = noErr;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////
|
|
|
+ // Function: TinyOsxGraphicsWindow::OSX_TranslateKey
|
|
|
+ // Access: Private
|
|
|
+ // Description: MAC Key Codes to Panda Key Codes
|
|
|
+ ////////////////////////////////////////////////////////////////////
|
|
|
+ ButtonHandle TinyOsxGraphicsWindow::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 (tinydisplay_cat.is_debug()) {
|
|
|
+ tinydisplay_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: TinyOsxGraphicsWindow::HandleModifireDeleta
|
|
|
+ // Access: Private
|
|
|
+ // Description: Used to emulate key events for the MAC key Modifiers..
|
|
|
+ ////////////////////////////////////////////////////////////////////
|
|
|
+ void TinyOsxGraphicsWindow::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: TinyOsxGraphicsWindow::HandleButtonDelta
|
|
|
+// Access: Private
|
|
|
+// Description: Used to emulate buttons events/
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::
|
|
|
+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: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::move_pointer(int device, int x, int y)
|
|
|
+{
|
|
|
+ if(_osx_window == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+if (tinydisplay_cat.is_debug())
|
|
|
+ tinydisplay_cat.debug() << "move_pointer " << device <<" "<< x <<" "<< y <<"\n";
|
|
|
+
|
|
|
+ Point pt = {0, 0};
|
|
|
+ pt.h = x;
|
|
|
+ pt.v = y;
|
|
|
+ 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 TinyOsxGraphicsWindow::do_reshape_request(int x_origin, int y_origin, bool has_origin,int x_size, int y_size)
|
|
|
+{
|
|
|
+ tinydisplay_cat.info() << "Do Reshape\n";
|
|
|
+
|
|
|
+ if (_properties.get_fullscreen()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_properties.has_parent_window())
|
|
|
+ {
|
|
|
+ if (has_origin)
|
|
|
+ {
|
|
|
+ NSWindow* parentWindow = (NSWindow *)_properties.get_parent_window();
|
|
|
+ NSRect parentFrame = [parentWindow frame];
|
|
|
+
|
|
|
+ MoveWindow(_osx_window, x_origin+parentFrame.origin.x, y_origin+parentFrame.origin.y, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // We sometimes get a bogus origin of (0, 0). As a special hack,
|
|
|
+ // treat this as a special case, and ignore it.
|
|
|
+ if (has_origin) {
|
|
|
+ if (x_origin != 0 || y_origin != 0) {
|
|
|
+ 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);
|
|
|
+ ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size());
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::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 TinyOsxGraphicsWindow::set_properties_now(WindowProperties &properties)
|
|
|
+{
|
|
|
+ if (tinydisplay_cat.is_debug())
|
|
|
+ {
|
|
|
+ tinydisplay_cat.debug()
|
|
|
+ << "------------------------------------------------------\n";
|
|
|
+ tinydisplay_cat.debug()
|
|
|
+ << "set_properties_now " << properties << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ GraphicsWindow::set_properties_now(properties);
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_debug()) {
|
|
|
+ tinydisplay_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());
|
|
|
+ _cursor_hidden = properties.get_cursor_hidden();
|
|
|
+ if (_cursor_hidden && _input_devices[0].has_pointer()) {
|
|
|
+ if (!_display_hide_cursor) {
|
|
|
+ CGDisplayHideCursor(kCGDirectMainDisplay);
|
|
|
+ _display_hide_cursor = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (_display_hide_cursor) {
|
|
|
+ CGDisplayShowCursor(kCGDirectMainDisplay);
|
|
|
+ _display_hide_cursor = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ properties.clear_cursor_hidden();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tinydisplay_cat.is_debug()) {
|
|
|
+ tinydisplay_cat.debug()
|
|
|
+ << "set_properties_now Out....." << _properties << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void TinyOsxGraphicsWindow::LocalPointToSystemPoint(Point &qdLocalPoint)
|
|
|
+{
|
|
|
+ if(_osx_window != NULL)
|
|
|
+ {
|
|
|
+ GrafPtr savePort;
|
|
|
+ Boolean portChanged = QDSwapPort(GetWindowPort(_osx_window), &savePort);
|
|
|
+
|
|
|
+ LocalToGlobal( &qdLocalPoint );
|
|
|
+
|
|
|
+ if (portChanged)
|
|
|
+ QDSwapPort(savePort, NULL);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::mouse_mode_relative
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: detaches mouse. Only mouse delta from now on.
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::mouse_mode_relative()
|
|
|
+{
|
|
|
+ CGAssociateMouseAndMouseCursorPosition(false);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::mouse_mode_absolute
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: reattaches mouse to location
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::mouse_mode_absolute()
|
|
|
+{
|
|
|
+ CGAssociateMouseAndMouseCursorPosition(true);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: TinyOsxGraphicsWindow::create_frame_buffer
|
|
|
+// Access: Private
|
|
|
+// Description: Creates a suitable frame buffer for the current
|
|
|
+// window size.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void TinyOsxGraphicsWindow::
|
|
|
+create_frame_buffer() {
|
|
|
+ if (_frame_buffer != NULL) {
|
|
|
+ ZB_close(_frame_buffer);
|
|
|
+ _frame_buffer = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), ZB_MODE_RGBA, 0, 0, 0, 0);
|
|
|
+}
|