diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt new file mode 100644 index 00000000000..d42be400dff --- /dev/null +++ b/intern/ghost/CMakeLists.txt @@ -0,0 +1,173 @@ +# $Id$ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../string + ../../source/blender/imbuf + ../../source/blender/makesdna + ${GLEW_INCLUDE_PATH} +) + +set(SRC + intern/GHOST_Buttons.cpp + intern/GHOST_CallbackEventConsumer.cpp + intern/GHOST_C-api.cpp + intern/GHOST_Path-api.cpp + intern/GHOST_DisplayManager.cpp + intern/GHOST_EventManager.cpp + intern/GHOST_EventPrinter.cpp + intern/GHOST_ISystem.cpp + intern/GHOST_ISystemPaths.cpp + intern/GHOST_ModifierKeys.cpp + intern/GHOST_NDOFManager.cpp + intern/GHOST_Path-api.cpp + intern/GHOST_Rect.cpp + intern/GHOST_System.cpp + intern/GHOST_TimerManager.cpp + intern/GHOST_Window.cpp + intern/GHOST_WindowManager.cpp + + GHOST_C-api.h + GHOST_IEvent.h + GHOST_IEventConsumer.h + GHOST_ISystem.h + GHOST_ISystemPaths.h + GHOST_ITimerTask.h + GHOST_IWindow.h + GHOST_Path-api.h + GHOST_Rect.h + GHOST_Types.h + intern/GHOST_Buttons.h + intern/GHOST_CallbackEventConsumer.h + intern/GHOST_Debug.h + intern/GHOST_DisplayManager.h + intern/GHOST_Event.h + intern/GHOST_EventButton.h + intern/GHOST_EventCursor.h + intern/GHOST_EventDragnDrop.h + intern/GHOST_EventKey.h + intern/GHOST_EventManager.h + intern/GHOST_EventNDOF.h + intern/GHOST_EventPrinter.h + intern/GHOST_EventString.h + intern/GHOST_EventTrackpad.h + intern/GHOST_EventWheel.h + intern/GHOST_ModifierKeys.h + intern/GHOST_NDOFManager.h + intern/GHOST_System.h + intern/GHOST_SystemPaths.h + intern/GHOST_TimerManager.h + intern/GHOST_TimerTask.h + intern/GHOST_Window.h + intern/GHOST_WindowManager.h +) + +if(APPLE) + if(WITH_COCOA) + list(APPEND SRC + intern/GHOST_DisplayManagerCocoa.mm + intern/GHOST_SystemCocoa.mm + intern/GHOST_SystemPathsCocoa.mm + intern/GHOST_WindowCocoa.mm + + intern/GHOST_DisplayManagerCocoa.h + intern/GHOST_SystemCocoa.h + intern/GHOST_SystemPathsCocoa.h + intern/GHOST_WindowCocoa.h + ) + else() + list(APPEND SRC + intern/GHOST_DisplayManagerCarbon.cpp + intern/GHOST_SystemCarbon.cpp + intern/GHOST_SystemPathsCarbon.cpp + intern/GHOST_WindowCarbon.cpp + + intern/GHOST_DisplayManagerCarbon.h + intern/GHOST_SystemCarbon.h + intern/GHOST_SystemPathsCarbon.h + intern/GHOST_WindowCarbon.h + ) + endif() + + if(WITH_CODEC_QUICKTIME) + add_definitions(-DWITH_QUICKTIME) + endif() + +elseif(UNIX) + + if(WITH_X11_XINPUT) + add_definitions(-DWITH_X11_XINPUT) + endif() + + list(APPEND INC ${X11_X11_INCLUDE_PATH}) + + list(APPEND SRC + intern/GHOST_DisplayManagerX11.cpp + intern/GHOST_SystemX11.cpp + intern/GHOST_SystemPathsX11.cpp + intern/GHOST_WindowX11.cpp + + intern/GHOST_DisplayManagerX11.h + intern/GHOST_SystemX11.h + intern/GHOST_SystemPathsX11.h + intern/GHOST_WindowX11.h + ) + + if(NOT WITH_INSTALL_PORTABLE) + add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}") + endif() + + if(X11_XF86keysym_INCLUDE_PATH) + add_definitions(-DWITH_XF86KEYSYM) + list(APPEND INC ${X11_XF86keysym_INCLUDE_PATH}) + endif() + +elseif(WIN32) + if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") + endif() + + list(APPEND INC ${WINTAB_INC}) + + list(APPEND SRC + intern/GHOST_DisplayManagerWin32.cpp + intern/GHOST_SystemWin32.cpp + intern/GHOST_SystemPathsWin32.cpp + intern/GHOST_WindowWin32.cpp + intern/GHOST_DropTargetWin32.cpp + + intern/GHOST_DisplayManagerWin32.h + intern/GHOST_DropTargetWin32.h + intern/GHOST_SystemWin32.h + intern/GHOST_SystemPathsWin32.h + intern/GHOST_WindowWin32.h + intern/GHOST_TaskbarWin32.h + ) +endif() + +blender_add_lib(bf_intern_ghost "${SRC}" "${INC}") + diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h new file mode 100644 index 00000000000..75837239c4a --- /dev/null +++ b/intern/ghost/GHOST_C-api.h @@ -0,0 +1,864 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +/** \ingroup GHOST + * + * \file GHOST_C-api.h + * \brief GHOST C-API function and type declarations. + */ + +#ifndef GHOST_C_API_H +#define GHOST_C_API_H + +#include "GHOST_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a "handle" for a C++ GHOST object. + * A handle is just an opaque pointer to an empty struct. + * In the API the pointer is casted to the actual C++ class. + * \param name Name of the handle to create. + */ + +GHOST_DECLARE_HANDLE(GHOST_SystemHandle); +GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle); +GHOST_DECLARE_HANDLE(GHOST_WindowHandle); +GHOST_DECLARE_HANDLE(GHOST_EventHandle); +GHOST_DECLARE_HANDLE(GHOST_RectangleHandle); +GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle); + + +/** + * Definition of a callback routine that receives events. + * @param event The event received. + * @param userdata The callback's user data, supplied to GHOST_CreateSystem. + */ +typedef int (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata); + + +/** + * Creates the one and only system. + * @return a handle to the system. + */ +extern GHOST_SystemHandle GHOST_CreateSystem(void); + +/** + * Disposes the one and only system. + * @param systemhandle The handle to the system + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle); + + +/** + * Creates an event consumer object + * @param eventCallback The event callback routine. + * @param userdata Pointer to user data returned to the callback routine. + */ +extern GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata); + +/** + * Disposes an event consumer object + * @param consumerhandle Handle to the event consumer. + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle); + + +/** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @param systemhandle The handle to the system + * @return The number of milliseconds. + */ +extern GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle); + +/** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param systemhandle The handle to the system + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ +extern GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerProc, + GHOST_TUserDataPtr userData); + +/** + * Removes a timer. + * @param systemhandle The handle to the system + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle); + +/*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + +/** + * Returns the number of displays on this system. + * @param systemhandle The handle to the system + * @return The number of displays. + */ +extern GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle); + +/** + * Returns the dimensions of the main display on this system. + * @param systemhandle The handle to the system + * @param width A pointer the width gets put in + * @param height A pointer the height gets put in + * @return void. + */ +extern void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height); + +/** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param systemhandle The handle to the system + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + * @return A handle to the new window ( == NULL if creation failed). + */ +extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + const char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual, + const GHOST_TUns16 numOfAASamples); + +/** + * Returns the window user data. + * @param windowhandle The handle to the window + * @return The window user data. + */ +extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle); + +/** + * Changes the window user data. + * @param windowhandle The handle to the window + * @param data The window user data. + */ +extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, + GHOST_TUserDataPtr userdata); + +/** + * Dispose a window. + * @param systemhandle The handle to the system + * @param window Handle to the window to be disposed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Returns whether a window is valid. + * @param systemhandle The handle to the system + * @param window Handle to the window to be checked. + * @return Indication of validity. + */ +extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Begins full screen mode. + * @param systemhandle The handle to the system + * @param setting The new setting of the display. + * @return A handle to the window displayed in full screen. + * This window is invalid after full screen has been ended. + */ +extern GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual); + +/** + * Ends full screen mode. + * @param systemhandle The handle to the system + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle); + +/** + * Returns current full screen mode status. + * @param systemhandle The handle to the system + * @return The current status. + */ +extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle); + +/*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + +/** + * Retrieves events from the system and stores them in the queue. + * @param systemhandle The handle to the system + * @param waitForEvent Boolean to indicate that ProcessEvents should + * wait (block) until the next event before returning. + * @return Indication of the presence of events. + */ +extern int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent); + +/** + * Retrieves events from the queue and send them to the event consumers. + * @param systemhandle The handle to the system + * @return Indication of the presence of events. + */ +extern int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle); + +/** + * Adds the given event consumer to our list. + * @param systemhandle The handle to the system + * @param consumerhandle The event consumer to add. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, + GHOST_EventConsumerHandle consumerhandle); + +/** + * Remove the given event consumer to our list. + * @param systemhandle The handle to the system + * @param consumerhandle The event consumer to remove. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_RemoveEventConsumer(GHOST_SystemHandle systemhandle, + GHOST_EventConsumerHandle consumerhandle); + +/*************************************************************************************** + ** Progress bar functionality + ***************************************************************************************/ + +/** + * Sets the progress bar value displayed in the window/application icon + * @param windowhandle The handle to the window + * @param progress The progress % (0.0 to 1.0) + */ +extern GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle, float progress); + +/** + * Hides the progress bar in the icon + * @param windowhandle The handle to the window + */ +extern GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle); + + +/*************************************************************************************** + ** N-degree of freedom device management functionality + ***************************************************************************************/ + +/** +* Open N-degree of freedom devices + */ +extern int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen + ); + +/*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + +/** + * Returns the current cursor shape. + * @param windowhandle The handle to the window + * @return The current cursor shape. + */ +extern GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle); + +/** + * Set the shape of the cursor. + * @param windowhandle The handle to the window + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape); + +/** + * Set the shape of the cursor to a custom cursor. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); +/** + * Set the shape of the cursor to a custom cursor of specified size. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @parm sizex, sizey The size of the cursor + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @param fg_color, bg_color Colors of the cursor + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color ); + +/** + * Returns the visibility state of the cursor. + * @param windowhandle The handle to the window + * @return The visibility state of the cursor. + */ +extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle); + +/** + * Shows or hides the cursor. + * @param windowhandle The handle to the window + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible); + +/** + * Returns the current location of the cursor (location in screen coordinates) + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y); + +/** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Grabs the cursor for a modal operation, to keep receiving + * events when the mouse is outside the window. X11 only, others + * do this automatically. + * @param windowhandle The handle to the window + * @param mode The new grab state of the cursor. + * @param bounds The grab ragion (optional) - left,top,right,bottom + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, + GHOST_TGrabCursorMode mode, + int* bounds); + +/*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + +/** + * Returns the state of a modifier key (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The modifier key state to retrieve. + * @param isDown Pointer to return modifier state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown); + +/** + * Returns the state of a mouse button (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The button state to retrieve. + * @param isDown Pointer to return button state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown); + + +/*************************************************************************************** + ** Drag'n'drop operations + ***************************************************************************************/ + +/** + * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop + */ +extern void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, GHOST_TInt8 canAccept); + + +/** + * Returns the event type. + * @param eventhandle The handle to the event + * @return The event type. + */ +extern GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle); + +/** + * Returns the time this event was generated. + * @param eventhandle The handle to the event + * @return The event generation time. + */ +extern GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle); + +/** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @param eventhandle The handle to the event + * @return The generating window. + */ +extern GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle); + +/** + * Returns the event data. + * @param eventhandle The handle to the event + * @return The event data. + */ +extern GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle); + +/** + * Returns the timer callback. + * @param timertaskhandle The handle to the timertask + * @return The timer callback. + */ +extern GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the timer callback. + * @param timertaskhandle The handle to the timertask + * @param timerProc The timer callback. + */ +extern void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerProc); + +/** + * Returns the timer user data. + * @param timertaskhandle The handle to the timertask + * @return The timer user data. + */ +extern GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the time user data. + * @param timertaskhandle The handle to the timertask + * @param data The timer user data. + */ +extern void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userData); + +/** + * Returns indication as to whether the window is valid. + * @param windowhandle The handle to the window + * @return The validity of the window. + */ +extern int GHOST_GetValid(GHOST_WindowHandle windowhandle) ; + +/** + * Returns the type of drawing context used in this window. + * @param windowhandle The handle to the window + * @return The current type of drawing context. + */ +extern GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle); + +/** + * Tries to install a rendering context in this window. + * @param windowhandle The handle to the window + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ +extern GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type); + +/** + * Sets the title displayed in the title bar. + * @param windowhandle The handle to the window + * @param title The title to display in the title bar. + */ +extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + const char* title); + +/** + * Returns the title displayed in the title bar. The title + * should be free'd with free(). + * + * @param windowhandle The handle to the window + * @return The title, free with free(). + */ +extern char* GHOST_GetTitle(GHOST_WindowHandle windowhandle); + +/** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle); + +/** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle); + +/** + * Disposes a rectangle object + * @param rectanglehandle Handle to the rectangle. + */ +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Resizes client rectangle width. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width); + +/** + * Resizes client rectangle height. + * @param windowhandle The handle to the window + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height); + +/** + * Resizes client rectangle. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height); + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ +extern void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) ; + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ +extern void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY); + +/** + * Returns the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @return The state of the window. + */ +extern GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle); + +/** + * Sets the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @param state The state of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state); + + +/** + * Sets the window "modified" status, indicating unsaved changes + * @param windowhandle The handle to the window + * @param isUnsavedChanges Unsaved changes or not + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, + GHOST_TUns8 isUnsavedChanges); + +/** + * Sets the order of the window (bottom, top). + * @param windowhandle The handle to the window + * @param order The order of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order); + +/** + * Swaps front and back buffers of a window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle); + +/** + * Activates the drawing context of this window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle); + +/** + * Invalidates the contents of this window. + * @param windowhandle The handle to the window + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle); + +/** + * Returns the status of the tablet + * @param windowhandle The handle to the window + * @return Status of tablet + */ +extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle); + +/** + * Access to rectangle width. + * @param rectanglehandle The handle to the rectangle + * @return width of the rectangle + */ +extern GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Access to rectangle height. + * @param rectanglehandle The handle to the rectangle + * @return height of the rectangle + */ +extern GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Gets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l Pointer to return left coordinate in. + * @param t Pointer to return top coordinate in. + * @param r Pointer to return right coordinate in. + * @param b Pointer to return bottom coordinate in. + */ +extern void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b); + +/** + * Sets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ +extern void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b); + +/** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true == empty rectangle) + */ +extern GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true==valid rectangle) + */ +extern GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param rectanglehandle The handle to the rectangle + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ +extern void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i); + +/** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r The rectangle that is input for the union operation. + */ +extern void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Grows the rectangle to included a point. + * @param rectanglehandle The handle to the rectangle + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ +extern void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param rectanglehandle The handle to the rectangle + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return intean value (true if point is inside). + */ +extern GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the rectangle is inside this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ +extern GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ +extern void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ +extern void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h); + +/** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r the rectangle to clip + * @return whether clipping has occurred + */ +extern GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Return the data from the clipboad + * @param return the selection instead, X11 only feature + * @return clipboard data + */ +extern GHOST_TUns8* GHOST_getClipboard(int selection); + +/** + * Put data to the Clipboard + * @param set the selection instead, X11 only feature + */ +extern void GHOST_putClipboard(GHOST_TInt8 *buffer, int selection); + + + +/** + * Toggles console + * @action 0 - Hides + * 1 - Shows + * 2 - Toggles + * 3 - Hides if it runs not from command line + * * - Does nothing + * @return current status (1 -visible, 0 - hidden) + */ +extern int GHOST_toggleConsole(int action); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/intern/ghost/GHOST_IEvent.h b/intern/ghost/GHOST_IEvent.h new file mode 100644 index 00000000000..bb13179fbfe --- /dev/null +++ b/intern/ghost/GHOST_IEvent.h @@ -0,0 +1,97 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_IEvent.h + * \ingroup GHOST + * Declaration of GHOST_IEvent interface class. + */ + +#ifndef _GHOST_IEVENT_H_ +#define _GHOST_IEVENT_H_ + +#include +#include "GHOST_Types.h" + +class GHOST_IWindow; + +/** + * Interface class for events received from GHOST. + * You should not need to inherit this class. The system will pass these events + * to the GHOST_IEventConsumer::processEvent() method of event consumers.
+ * Use the getType() method to retrieve the type of event and the getData() + * method to get the event data out. Using the event type you can cast the + * event data to the correct event dat structure. + * @see GHOST_IEventConsumer#processEvent + * @see GHOST_TEventType + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IEvent +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEvent() + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() = 0; + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() = 0; + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() = 0; + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() = 0; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_IEvent"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif // _GHOST_IEVENT_H_ + diff --git a/intern/ghost/GHOST_IEventConsumer.h b/intern/ghost/GHOST_IEventConsumer.h new file mode 100644 index 00000000000..246ba8aa948 --- /dev/null +++ b/intern/ghost/GHOST_IEventConsumer.h @@ -0,0 +1,75 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_IEventConsumer.h + * \ingroup GHOST + * Declaration of GHOST_IEventConsumer interface class. + */ + +#ifndef _GHOST_IEVENT_CONSUMER_H_ +#define _GHOST_IEVENT_CONSUMER_H_ + +#include "GHOST_IEvent.h" + +/** + * Interface class for objects interested in receiving events. + * Objects interested in events should inherit this class and implement the + * processEvent() method. They should then be registered with the system that + * they want to receive events. The system will call the processEvent() method + * for every installed event consumer to pass events. + * @see GHOST_ISystem#addEventConsumer + * @author Maarten Gribnau + * @date May 14, 2001 + */ +class GHOST_IEventConsumer +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEventConsumer() + { + } + + /** + * This method is called by the system when it has events to dispatch. + * @see GHOST_ISystem#dispatchEvents + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event) = 0; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_IEventConsumer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif // _GHOST_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h new file mode 100644 index 00000000000..69e10070be5 --- /dev/null +++ b/intern/ghost/GHOST_ISystem.h @@ -0,0 +1,410 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_ISystem.h + * \ingroup GHOST + * %Main interface file for C++ Api with declaration of GHOST_ISystem interface + * class. + * Contains the doxygen documentation main page. + */ + +#ifndef _GHOST_ISYSTEM_H_ +#define _GHOST_ISYSTEM_H_ + +#include "GHOST_Types.h" +#include "GHOST_ITimerTask.h" +#include "GHOST_IWindow.h" + +class GHOST_IEventConsumer; + +/** + * \page GHOSTPage GHOST + * + * \section intro Introduction + * + * GHOST is yet another acronym. It stands for "Generic Handy Operating System + * Toolkit". It has been created to replace the OpenGL utility tool kit + * GLUT. + * GLUT was used in Blender until the + * point that Blender needed to be ported to Apple's Mac OSX. Blender needed a + * number of modifications in GLUT to work but the GLUT sources for OSX were + * unavailable at the time. The decision was made to build our own replacement + * for GLUT. In those days, NaN Technologies BV was the company that developed + * Blender. + *

+ * Enough history. What does GHOST have to offer?
+ * In short: everything that Blender needed from GLUT to run on all it's supported + * operating systems and some extra's. + * This includes : + * + * Font management has been moved to a separate library. + * + * \section platforms Platforms + * + * \section Building GHOST + * + * \section interface Interface + * GHOST has two programming interfaces: + * + * GHOST itself is writtem in C++ and the C-API is a wrapper around the C++ + * API. + * + * \subsection cplusplus_api The C++ API consists of the following files: + * + * For an example of using the C++-API, have a look at the GHOST_C-Test.cpp + * program in the ?/ghost/test/gears/ directory. + * + * \subsection c_api The C-API + * To use GHOST in programs written in C, include the file GHOST_C-API.h in + * your program. This file includes the GHOST_Types.h file for all GHOST types + * and defines functions that give you access to the same functionality present + * in the C++ API.
+ * For an example of using the C-API, have a look at the GHOST_C-Test.c program + * in the ?/ghost/test/gears/ directory. + * + * \section work Work in progress + * \todo write WIP section + */ + +/** \interface GHOST_ISystem + * Interface for classes that provide access to the operating system. + * There should be only one system class in an application. + * Therefore, the routines to create and dispose the system are static. + * Provides: + * -# Time(r) management. + * -# Display/window management (windows are only created on the main display). + * -# Event management. + * -# Cursor shape management (no custom cursors for now). + * -# Access to the state of the mouse buttons and the keyboard. + * -# Menus for windows with events generated when they are accessed (this is + * work in progress). + * @author Maarten Gribnau + * @date May 30, 2001 + */ +class GHOST_ISystem +{ +public: + /** + * Creates the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess createSystem(); + + /** + * Disposes the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess disposeSystem(); + + /** + * Returns a pointer to the one and only system (nil if it hasn't been created). + * @return A pointer to the system. + */ + static GHOST_ISystem* getSystem(); + +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_ISystem() {} + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_ISystem() {} + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const = 0; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) = 0; + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask) = 0; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const = 0; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const = 0; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0, + const GHOST_TEmbedderWindowID parentWindow = 0) = 0; + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window) = 0; + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window) = 0; + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) = 0; + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void) = 0; + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void) = 0; + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent) = 0; + + /** + * Retrieves events from the queue and send them to the event consumers. + * @return Indication of the presence of events. + */ + virtual bool dispatchEvents() = 0; + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer) = 0; + + /** + * Removes the given event consumer to our list. + * @param consumer The event consumer to remove. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer) = 0; + + /*************************************************************************************** + ** N-degree of freedom device management functionality + ***************************************************************************************/ + + /** + * Starts the N-degree of freedom device manager + */ + virtual int openNDOF(GHOST_IWindow*, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen + // original patch only + // GHOST_NDOFEventHandler_fp setNdofEventHandler + ) = 0; + + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + + /** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) = 0; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const = 0; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0; + + /** + * Toggles console + * @action 0 - Hides + * 1 - Shows + * 2 - Toggles + * 3 - Hides if it runs not from command line + * * - Does nothing + * @return current status (1 -visible, 0 - hidden) + */ + virtual int toggleConsole(int action) = 0; + + /*************************************************************************************** + ** Access to clipboard. + ***************************************************************************************/ + + /** + * Returns the selection buffer + * @return Returns "unsinged char" from X11 XA_CUT_BUFFER0 buffer + * + */ + virtual GHOST_TUns8* getClipboard(bool selection) const = 0; + + /** + * Put data to the Clipboard + */ + virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init() = 0; + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit() = 0; + + /** The one and only system */ + static GHOST_ISystem* m_system; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_ISystem"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif // _GHOST_ISYSTEM_H_ + diff --git a/intern/ghost/GHOST_ISystemPaths.h b/intern/ghost/GHOST_ISystemPaths.h new file mode 100644 index 00000000000..5c9b3c109ef --- /dev/null +++ b/intern/ghost/GHOST_ISystemPaths.h @@ -0,0 +1,103 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_ISystemPaths.h + * \ingroup GHOST + */ + +#ifndef _GHOST_ISYSTEMPATHS_H_ +#define _GHOST_ISYSTEMPATHS_H_ + +#include "GHOST_Types.h" + +class GHOST_ISystemPaths +{ +public: + /** + * Creates the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess create(); + + /** + * Disposes the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess dispose(); + + /** + * Returns a pointer to the one and only system (nil if it hasn't been created). + * @return A pointer to the system. + */ + static GHOST_ISystemPaths* get(); + +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_ISystemPaths() {} + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_ISystemPaths() {} + +public: + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ + virtual const GHOST_TUns8* getSystemDir() const = 0; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/.blender/). + */ + virtual const GHOST_TUns8* getUserDir() const = 0; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + virtual const GHOST_TUns8* getBinaryDir() const = 0; + + /** + * Add the file to the operating system most recently used files + */ + virtual void addToSystemRecentFiles(const char* filename) const = 0; + +private: + /** The one and only system paths*/ + static GHOST_ISystemPaths* m_systemPaths; +}; + +#endif diff --git a/intern/ghost/GHOST_ITimerTask.h b/intern/ghost/GHOST_ITimerTask.h new file mode 100644 index 00000000000..e6b713756d6 --- /dev/null +++ b/intern/ghost/GHOST_ITimerTask.h @@ -0,0 +1,96 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_ITimerTask.h + * \ingroup GHOST + * Declaration of GHOST_ITimerTask interface class. + */ + +#ifndef _GHOST_ITIMER_TASK_H_ +#define _GHOST_ITIMER_TASK_H_ + +#include "GHOST_Types.h" + + +/** + * Interface for a timer task. + * Timer tasks are created by the system and can be installed by the system. + * After installation, the timer callback-procedure or "timerProc" will be called + * periodically. You should not need to inherit this class. It is passed to the + * application in the timer-callback.
+ *
+ * Note that GHOST processes timers in the UI thread. You should ask GHOST + * process messages in order for the timer-callbacks to be called. + * @see GHOST_ISystem#installTimer + * @see GHOST_TimerProcPtr + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_ITimerTask +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_ITimerTask() + { + } + + /** + * Returns the timer callback. + * @return The timer callback. + */ + virtual GHOST_TimerProcPtr getTimerProc() const = 0; + + /** + * Changes the timer callback. + * @param timerProc The timer callback. + */ + virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) = 0; + + /** + * Returns the timer user data. + * @return The timer user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_ITimerTask"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif // _GHOST_ITIMER_TASK_H_ + diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h new file mode 100644 index 00000000000..97c525ef318 --- /dev/null +++ b/intern/ghost/GHOST_IWindow.h @@ -0,0 +1,317 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_IWindow.h + * \ingroup GHOST + * Declaration of GHOST_IWindow interface class. + */ + +#ifndef _GHOST_IWINDOW_H_ +#define _GHOST_IWINDOW_H_ + +#include "STR_String.h" +#include "GHOST_Rect.h" +#include "GHOST_Types.h" + + +/** + * Interface for GHOST windows. + * + * You can create a window with the system's GHOST_ISystem::createWindow + * method. + * @see GHOST_ISystem#createWindow + * + * There are two coordinate systems: + * + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IWindow +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IWindow() + { + } + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const = 0; + + /** + * Returns the associated OS object/handle + * @return The associated OS object/handle + */ + virtual void* getOSWindow() const = 0; + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + virtual GHOST_TDrawingContextType getDrawingContextType() = 0; + + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) = 0; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title) = 0; + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const = 0; + + /** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the client area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop + */ + virtual void setAcceptDragOperation(bool canAccept) = 0; + + /** + * Returns acceptance of the dropped object + * Usually called by the "object dropped" event handling function + */ + virtual bool canAcceptDragOperation() const = 0; + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const = 0; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + + /** + * Sets the window "modified" status, indicating unsaved changes + * @param isUnsavedChanges Unsaved changes or not + * @return Indication of success. + */ + virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges) = 0; + + /** + * Gets the window "modified" status, indicating unsaved changes + * @return True if there are unsaved changes + */ + virtual bool getModifiedState() = 0; + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers() = 0; + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext() = 0; + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate() = 0; + + /** + * Returns the window user data. + * @return The window user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + + /** + * Returns the tablet data (pressure etc). + * @return The tablet data (pressure etc). + */ + virtual const GHOST_TabletData* GetTabletData() = 0; + + /*************************************************************************************** + ** Progress bar functionality + ***************************************************************************************/ + + /** + * Sets the progress bar value displayed in the window/application icon + * @param progress The progress % + */ + virtual GHOST_TSuccess setProgressBar(float progress) = 0; + + /** + * Hides the progress bar in the icon + */ + virtual GHOST_TSuccess endProgressBar() = 0; + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + virtual GHOST_TStandardCursor getCursorShape() const = 0; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0; + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) = 0; + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color) = 0; + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + virtual bool getCursorVisibility() const = 0; + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible) = 0; + + /** + * Grabs the cursor for a modal operation. + * @param grab The new grab state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds) { return GHOST_kSuccess; }; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_IWindow"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif // _GHOST_IWINDOW_H_ + diff --git a/intern/ghost/GHOST_Path-api.h b/intern/ghost/GHOST_Path-api.h new file mode 100644 index 00000000000..790a529745f --- /dev/null +++ b/intern/ghost/GHOST_Path-api.h @@ -0,0 +1,87 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_Path-api.h + * \ingroup GHOST + */ + + +#ifndef GHOST_PATH_API_H +#define GHOST_PATH_API_H + +#include "GHOST_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +GHOST_DECLARE_HANDLE(GHOST_SystemPathsHandle); + +/** + * Creates the one and only instance of the system path access. + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_CreateSystemPaths(void); + +/** + * Disposes the one and only system. + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeSystemPaths(void); + +/** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ +extern const GHOST_TUns8* GHOST_getSystemDir(void); + +/** + * Determine the base dir in which user configuration is stored, not including versioning. + * @return Unsigned char string pointing to user dir (eg ~). + */ +extern const GHOST_TUns8* GHOST_getUserDir(void); + + +/** + * Determine the dir in which the binary file is found. + * @return Unsigned char string pointing to binary dir (eg ~/usr/local/bin/). + */ +extern const GHOST_TUns8* GHOST_getBinaryDir(void); + +/** +* Add the file to the operating system most recently used files +*/ +extern void GHOST_addToSystemRecentFiles(const char* filename); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h new file mode 100644 index 00000000000..c654a45c811 --- /dev/null +++ b/intern/ghost/GHOST_Rect.h @@ -0,0 +1,259 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Debug.h + * \ingroup GHOST + * Macro's used in GHOST debug target. + */ + +#ifndef _H_GHOST_Rect +#define _H_GHOST_Rect + +#include "GHOST_Types.h" + + +/** + * Implements rectangle functionality. + * The four extreme coordinates are stored as left, top, right and bottom. + * To be valid, a rectangle should have a left coordinate smaller than or equal to right. + * To be valid, a rectangle should have a top coordinate smaller than or equal to bottom. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +class GHOST_Rect { +public: + + /** + * Constructs a rectangle with the given values. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + GHOST_Rect(GHOST_TInt32 l=0, GHOST_TInt32 t=0, GHOST_TInt32 r=0, GHOST_TInt32 b=0) + : m_l(l), m_t(t), m_r(r), m_b(b) {} + + /** + * Copy constructor. + * @param r rectangle to copy + */ + GHOST_Rect(const GHOST_Rect& r) + : m_l(r.m_l), m_t(r.m_t), m_r(r.m_r), m_b(r.m_b) {} + + /** + * Destructor. + */ + virtual ~GHOST_Rect() {}; + + /** + * Access to rectangle width. + * @return width of the rectangle + */ + virtual inline GHOST_TInt32 getWidth() const; + + /** + * Access to rectangle height. + * @return height of the rectangle + */ + virtual inline GHOST_TInt32 getHeight() const; + + /** + * Sets all members of the rectangle. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + virtual inline void set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b); + + /** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @return boolean value (true==empty rectangle) + */ + virtual inline bool isEmpty() const; + + /** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @return boolean value (true==valid rectangle) + */ + virtual inline bool isValid() const; + + /** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ + virtual void inset(GHOST_TInt32 i); + + /** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param r The rectangle that is input for the union operation. + */ + virtual inline void unionRect(const GHOST_Rect& r); + + /** + * Grows the rectangle to included a point. + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ + virtual inline void unionPoint(GHOST_TInt32 x, GHOST_TInt32 y); + + /** + * Grows the rectangle to included a point. + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ + virtual inline void wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs); + + /** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return boolean value (true if point is inside). + */ + virtual inline bool isInside(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /** + * Returns whether the rectangle is inside this rectangle. + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ + virtual GHOST_TVisibility getVisibility(GHOST_Rect& r) const; + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy); + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h); + + /** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param r the rectangle to clip + * @return whether clipping has occurred + */ + virtual bool clip(GHOST_Rect& r) const; + + /** Left coordinate of the rectangle */ + GHOST_TInt32 m_l; + /** Top coordinate of the rectangle */ + GHOST_TInt32 m_t; + /** Right coordinate of the rectangle */ + GHOST_TInt32 m_r; + /** Bottom coordinate of the rectangle */ + GHOST_TInt32 m_b; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_Rect"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + + +inline GHOST_TInt32 GHOST_Rect::getWidth() const +{ + return m_r - m_l; +} + +inline GHOST_TInt32 GHOST_Rect::getHeight() const +{ + return m_b - m_t; +} + +inline void GHOST_Rect::set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b) +{ + m_l = l; m_t = t; m_r = r; m_b = b; +} + +inline bool GHOST_Rect::isEmpty() const +{ + return (getWidth() == 0) || (getHeight() == 0); +} + +inline bool GHOST_Rect::isValid() const +{ + return (m_l <= m_r) && (m_t <= m_b); +} + +inline void GHOST_Rect::unionRect(const GHOST_Rect& r) +{ + if (r.m_l < m_l) m_l = r.m_l; + if (r.m_r > m_r) m_r = r.m_r; + if (r.m_t < m_t) m_t = r.m_t; + if (r.m_b > m_b) m_b = r.m_b; +} + +inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y) +{ + if (x < m_l) m_l = x; + if (x > m_r) m_r = x; + if (y < m_t) m_t = y; + if (y > m_b) m_b = y; +} +#include +inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs) +{ + GHOST_TInt32 w= getWidth(); + GHOST_TInt32 h= getHeight(); + + /* highly unlikely but avoid eternal loop */ + if(w-ofs*2 <= 0 || h-ofs*2 <= 0) + return; + while(x-ofs < m_l) x+= w-(ofs*2); + while(y-ofs < m_t) y+= h-(ofs*2); + while(x+ofs > m_r) x-= w-(ofs*2); + while(y+ofs > m_b) y-= h-(ofs*2); +} + +inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + return (x >= m_l) && (x <= m_r) && (y >= m_t) && (y <= m_b); +} + +#endif // _H_GHOST_Rect + diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h new file mode 100644 index 00000000000..705f4916619 --- /dev/null +++ b/intern/ghost/GHOST_Types.h @@ -0,0 +1,516 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/GHOST_Types.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_TYPES_H_ +#define _GHOST_TYPES_H_ + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +#define GHOST_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +typedef char GHOST_TInt8; +typedef unsigned char GHOST_TUns8; +typedef short GHOST_TInt16; +typedef unsigned short GHOST_TUns16; +typedef int GHOST_TInt32; +typedef unsigned int GHOST_TUns32; + +#ifdef WIN32 +#define WM_BLND_NDOF_AXIS WM_USER + 1 +#define WM_BLND_NDOF_BTN WM_USER + 2 +#endif + +#if defined(WIN32) && !defined(FREE_WINDOWS) +typedef __int64 GHOST_TInt64; +typedef unsigned __int64 GHOST_TUns64; +#else +typedef long long GHOST_TInt64; +typedef unsigned long long GHOST_TUns64; +#endif + +typedef void* GHOST_TUserDataPtr; + +typedef enum +{ + GHOST_kFailure = 0, + GHOST_kSuccess +} GHOST_TSuccess; + +/* Xtilt and Ytilt represent how much the pen is tilted away from + * vertically upright in either the X or Y direction, with X and Y the + * axes of the tablet surface. + * In other words, Xtilt and Ytilt are components of a vector created by projecting + * the pen's angle in 3D space vertically downwards on to the XY plane + * --Matt + */ +typedef enum { + GHOST_kTabletModeNone = 0, + GHOST_kTabletModeStylus, + GHOST_kTabletModeEraser +} GHOST_TTabletMode; + +typedef struct GHOST_TabletData { + GHOST_TTabletMode Active; /* 0=None, 1=Stylus, 2=Eraser */ + float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ + float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ + float Ytilt; /* as above */ +} GHOST_TabletData; + + +typedef enum { + GHOST_kNotVisible = 0, + GHOST_kPartiallyVisible, + GHOST_kFullyVisible +} GHOST_TVisibility; + + +typedef enum { + GHOST_kFireTimeNever = 0xFFFFFFFF +} GHOST_TFireTimeConstant; + +typedef enum { + GHOST_kModifierKeyLeftShift = 0, + GHOST_kModifierKeyRightShift, + GHOST_kModifierKeyLeftAlt, + GHOST_kModifierKeyRightAlt, + GHOST_kModifierKeyLeftControl, + GHOST_kModifierKeyRightControl, + GHOST_kModifierKeyOS, + GHOST_kModifierKeyNumMasks +} GHOST_TModifierKeyMask; + + +typedef enum { + GHOST_kWindowStateNormal = 0, + GHOST_kWindowStateMaximized, + GHOST_kWindowStateMinimized, + GHOST_kWindowStateFullScreen, + GHOST_kWindowStateEmbedded, + GHOST_kWindowState8Normal = 8, + GHOST_kWindowState8Maximized, + GHOST_kWindowState8Minimized, + GHOST_kWindowState8FullScreen, + GHOST_kWindowStateModified, + GHOST_kWindowStateUnModified +} GHOST_TWindowState; + + +/** Constants for the answer to the blender exit request */ +typedef enum { + GHOST_kExitCancel = 0, + GHOST_kExitNow +} GHOST_TExitRequestResponse; + +typedef enum { + GHOST_kWindowOrderTop = 0, + GHOST_kWindowOrderBottom +} GHOST_TWindowOrder; + + +typedef enum { + GHOST_kDrawingContextTypeNone = 0, + GHOST_kDrawingContextTypeOpenGL +} GHOST_TDrawingContextType; + + +typedef enum { + GHOST_kButtonMaskLeft = 0, + GHOST_kButtonMaskMiddle, + GHOST_kButtonMaskRight, + GHOST_kButtonMaskButton4, + GHOST_kButtonMaskButton5, + GHOST_kButtonNumMasks +} GHOST_TButtonMask; + + +typedef enum { + GHOST_kEventUnknown = 0, + + GHOST_kEventCursorMove, /// Mouse move event + GHOST_kEventButtonDown, /// Mouse button event + GHOST_kEventButtonUp, /// Mouse button event + GHOST_kEventWheel, /// Mouse wheel event + GHOST_kEventTrackpad, /// Trackpad event + + GHOST_kEventNDOFMotion, /// N degree of freedom device motion event + GHOST_kEventNDOFButton, /// N degree of freedom device button event + + GHOST_kEventKeyDown, + GHOST_kEventKeyUp, +// GHOST_kEventKeyAuto, + + GHOST_kEventQuit, + + GHOST_kEventWindowClose, + GHOST_kEventWindowActivate, + GHOST_kEventWindowDeactivate, + GHOST_kEventWindowUpdate, + GHOST_kEventWindowSize, + GHOST_kEventWindowMove, + + GHOST_kEventDraggingEntered, + GHOST_kEventDraggingUpdated, + GHOST_kEventDraggingExited, + GHOST_kEventDraggingDropDone, + + GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup + + GHOST_kEventTimer, + + GHOST_kNumEventTypes +} GHOST_TEventType; + + +typedef enum { + GHOST_kStandardCursorFirstCursor = 0, + GHOST_kStandardCursorDefault = 0, + GHOST_kStandardCursorRightArrow, + GHOST_kStandardCursorLeftArrow, + GHOST_kStandardCursorInfo, + GHOST_kStandardCursorDestroy, + GHOST_kStandardCursorHelp, + GHOST_kStandardCursorCycle, + GHOST_kStandardCursorSpray, + GHOST_kStandardCursorWait, + GHOST_kStandardCursorText, + GHOST_kStandardCursorCrosshair, + GHOST_kStandardCursorUpDown, + GHOST_kStandardCursorLeftRight, + GHOST_kStandardCursorTopSide, + GHOST_kStandardCursorBottomSide, + GHOST_kStandardCursorLeftSide, + GHOST_kStandardCursorRightSide, + GHOST_kStandardCursorTopLeftCorner, + GHOST_kStandardCursorTopRightCorner, + GHOST_kStandardCursorBottomRightCorner, + GHOST_kStandardCursorBottomLeftCorner, + GHOST_kStandardCursorCopy, + GHOST_kStandardCursorCustom, + GHOST_kStandardCursorNumCursors, + GHOST_kStandardCursorPencil +} GHOST_TStandardCursor; + + +typedef enum { + GHOST_kKeyUnknown = -1, + GHOST_kKeyBackSpace, + GHOST_kKeyTab, + GHOST_kKeyLinefeed, + GHOST_kKeyClear, + GHOST_kKeyEnter = 0x0D, + + GHOST_kKeyEsc = 0x1B, + GHOST_kKeySpace = ' ', + GHOST_kKeyQuote = 0x27, + GHOST_kKeyComma = ',', + GHOST_kKeyMinus = '-', + GHOST_kKeyPeriod = '.', + GHOST_kKeySlash = '/', + + // Number keys + GHOST_kKey0 = '0', + GHOST_kKey1, + GHOST_kKey2, + GHOST_kKey3, + GHOST_kKey4, + GHOST_kKey5, + GHOST_kKey6, + GHOST_kKey7, + GHOST_kKey8, + GHOST_kKey9, + + GHOST_kKeySemicolon = ';', + GHOST_kKeyEqual = '=', + + // Character keys + GHOST_kKeyA = 'A', + GHOST_kKeyB, + GHOST_kKeyC, + GHOST_kKeyD, + GHOST_kKeyE, + GHOST_kKeyF, + GHOST_kKeyG, + GHOST_kKeyH, + GHOST_kKeyI, + GHOST_kKeyJ, + GHOST_kKeyK, + GHOST_kKeyL, + GHOST_kKeyM, + GHOST_kKeyN, + GHOST_kKeyO, + GHOST_kKeyP, + GHOST_kKeyQ, + GHOST_kKeyR, + GHOST_kKeyS, + GHOST_kKeyT, + GHOST_kKeyU, + GHOST_kKeyV, + GHOST_kKeyW, + GHOST_kKeyX, + GHOST_kKeyY, + GHOST_kKeyZ, + + GHOST_kKeyLeftBracket = '[', + GHOST_kKeyRightBracket = ']', + GHOST_kKeyBackslash = 0x5C, + GHOST_kKeyAccentGrave = '`', + + + GHOST_kKeyLeftShift = 0x100, + GHOST_kKeyRightShift, + GHOST_kKeyLeftControl, + GHOST_kKeyRightControl, + GHOST_kKeyLeftAlt, + GHOST_kKeyRightAlt, + GHOST_kKeyOS, // Command key on Apple, Windows key(s) on Windows + GHOST_kKeyGrLess , // German PC only! + + GHOST_kKeyCapsLock, + GHOST_kKeyNumLock, + GHOST_kKeyScrollLock, + + GHOST_kKeyLeftArrow, + GHOST_kKeyRightArrow, + GHOST_kKeyUpArrow, + GHOST_kKeyDownArrow, + + GHOST_kKeyPrintScreen, + GHOST_kKeyPause, + + GHOST_kKeyInsert, + GHOST_kKeyDelete, + GHOST_kKeyHome, + GHOST_kKeyEnd, + GHOST_kKeyUpPage, + GHOST_kKeyDownPage, + + // Numpad keys + GHOST_kKeyNumpad0, + GHOST_kKeyNumpad1, + GHOST_kKeyNumpad2, + GHOST_kKeyNumpad3, + GHOST_kKeyNumpad4, + GHOST_kKeyNumpad5, + GHOST_kKeyNumpad6, + GHOST_kKeyNumpad7, + GHOST_kKeyNumpad8, + GHOST_kKeyNumpad9, + GHOST_kKeyNumpadPeriod, + GHOST_kKeyNumpadEnter, + GHOST_kKeyNumpadPlus, + GHOST_kKeyNumpadMinus, + GHOST_kKeyNumpadAsterisk, + GHOST_kKeyNumpadSlash, + + // Function keys + GHOST_kKeyF1, + GHOST_kKeyF2, + GHOST_kKeyF3, + GHOST_kKeyF4, + GHOST_kKeyF5, + GHOST_kKeyF6, + GHOST_kKeyF7, + GHOST_kKeyF8, + GHOST_kKeyF9, + GHOST_kKeyF10, + GHOST_kKeyF11, + GHOST_kKeyF12, + GHOST_kKeyF13, + GHOST_kKeyF14, + GHOST_kKeyF15, + GHOST_kKeyF16, + GHOST_kKeyF17, + GHOST_kKeyF18, + GHOST_kKeyF19, + GHOST_kKeyF20, + GHOST_kKeyF21, + GHOST_kKeyF22, + GHOST_kKeyF23, + GHOST_kKeyF24, + + // Multimedia keypad buttons + GHOST_kKeyMediaPlay, + GHOST_kKeyMediaStop, + GHOST_kKeyMediaFirst, + GHOST_kKeyMediaLast +} GHOST_TKey; + +typedef enum { + GHOST_kGrabDisable = 0, /* grab not set */ + GHOST_kGrabNormal, /* no cursor adjustments */ + GHOST_kGrabWrap, /* wrap the mouse location to prevent limiting screen bounds */ + GHOST_kGrabHide, /* hide the mouse while grabbing and restore the original location on release (numbuts) */ +} GHOST_TGrabCursorMode; + +typedef void* GHOST_TEventDataPtr; + +typedef struct { + /** The x-coordinate of the cursor position. */ + GHOST_TInt32 x; + /** The y-coordinate of the cursor position. */ + GHOST_TInt32 y; +} GHOST_TEventCursorData; + +typedef struct { + /** The mask of the mouse button. */ + GHOST_TButtonMask button; +} GHOST_TEventButtonData; + +typedef struct { + /** Displacement of a mouse wheel. */ + GHOST_TInt32 z; +} GHOST_TEventWheelData; + +typedef enum { + GHOST_kTrackpadEventUnknown =0, + GHOST_kTrackpadEventScroll, + GHOST_kTrackpadEventRotate, + GHOST_kTrackpadEventSwipe, /* Reserved, not used for now */ + GHOST_kTrackpadEventMagnify +} GHOST_TTrackpadEventSubTypes; + + +typedef struct { + /** The event subtype */ + GHOST_TTrackpadEventSubTypes subtype; + /** The x-location of the trackpad event */ + GHOST_TInt32 x; + /** The y-location of the trackpad event */ + GHOST_TInt32 y; + /** The x-delta or value of the trackpad event */ + GHOST_TInt32 deltaX; + /** The y-delta (currently only for scroll subtype) of the trackpad event */ + GHOST_TInt32 deltaY; +} GHOST_TEventTrackpadData; + + +typedef enum { + GHOST_kDragnDropTypeUnknown =0, + GHOST_kDragnDropTypeFilenames, /*Array of strings representing file names (full path) */ + GHOST_kDragnDropTypeString, /* Unformatted text UTF-8 string */ + GHOST_kDragnDropTypeBitmap /*Bitmap image data */ +} GHOST_TDragnDropTypes; + +typedef struct { + /** The x-coordinate of the cursor position. */ + GHOST_TInt32 x; + /** The y-coordinate of the cursor position. */ + GHOST_TInt32 y; + /** The dropped item type */ + GHOST_TDragnDropTypes dataType; + /** The "dropped content" */ + GHOST_TEventDataPtr data; +} GHOST_TEventDragnDropData; + +typedef struct { + int count; + GHOST_TUns8 **strings; +} GHOST_TStringArray; + + +/* original patch used floats, but the driver return ints and uns. We will calibrate in view, no sense on doing conversions twice */ +/* as all USB device controls are likely to use ints, this is also more future proof */ +//typedef struct { +// /** N-degree of freedom device data */ +// float tx, ty, tz; /** -x left, +y up, +z forward */ +// float rx, ry, rz; +// float dt; +//} GHOST_TEventNDOFData; + +typedef struct { + /** N-degree of freedom device data v2*/ + int changed; + GHOST_TUns64 client; + GHOST_TUns64 address; + GHOST_TInt16 tx, ty, tz; /** -x left, +y up, +z forward */ + GHOST_TInt16 rx, ry, rz; + GHOST_TInt16 buttons; + GHOST_TUns64 time; + GHOST_TUns64 delta; +} GHOST_TEventNDOFData; + +typedef int (*GHOST_NDOFLibraryInit_fp)(void); +typedef void (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle); +typedef void* (*GHOST_NDOFDeviceOpen_fp)(void* platformData); + +// original patch windows callback. In mac os X version the callback is internal to the plug-in and post an event to main thead. +// not necessary faster, but better integration with other events. + +//typedef int (*GHOST_NDOFEventHandler_fp)(float* result7, void* deviceHandle, unsigned int message, unsigned int* wParam, unsigned long* lParam); +//typedef void (*GHOST_NDOFCallBack_fp)(GHOST_TEventNDOFDataV2 *VolDatas); + +typedef struct { + /** The key code. */ + GHOST_TKey key; + /** The ascii code for the key event ('\0' if none). */ + char ascii; +} GHOST_TEventKeyData; + +typedef struct { + /** Number of pixels on a line. */ + GHOST_TUns32 xPixels; + /** Number of lines. */ + GHOST_TUns32 yPixels; + /** Numberof bits per pixel. */ + GHOST_TUns32 bpp; + /** Refresh rate (in Hertz). */ + GHOST_TUns32 frequency; +} GHOST_DisplaySetting; + + +#ifdef _WIN32 +typedef long GHOST_TEmbedderWindowID; +#endif // _WIN32 + +#ifndef _WIN32 +// I can't use "Window" from "" because it conflits with Window defined in winlay.h +typedef int GHOST_TEmbedderWindowID; +#endif // _WIN32 + +/** + * A timer task callback routine. + * @param task The timer task object. + * @param time The current time. + */ +#ifdef __cplusplus +class GHOST_ITimerTask; +typedef void (*GHOST_TimerProcPtr)(GHOST_ITimerTask* task, GHOST_TUns64 time); +#else +struct GHOST_TimerTaskHandle__; +typedef void (*GHOST_TimerProcPtr)(struct GHOST_TimerTaskHandle__* task, GHOST_TUns64 time); +#endif + +#endif // _GHOST_TYPES_H_ + diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript new file mode 100644 index 00000000000..b67545f216a --- /dev/null +++ b/intern/ghost/SConscript @@ -0,0 +1,70 @@ +#!/usr/bin/python +import sys +import os + +Import ('env') + +window_system = env['OURPLATFORM'] + +sources = env.Glob('intern/*.cpp') +if window_system == 'darwin': + sources += env.Glob('intern/*.mm') + + +pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget'] +defs=['_USE_MATH_DEFINES'] + +if window_system in ('linux2', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'irix6', 'aix4', 'aix5'): + for f in pf: + try: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') + except ValueError: + pass + defs += ['PREFIX=\\"/usr/local/\\"'] # XXX, make an option + defs += ['WITH_X11_XINPUT'] # XXX, make an option + +elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'): + for f in pf: + try: + sources.remove('intern' + os.sep + f + 'X11.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') + except ValueError: + pass +elif window_system == 'darwin': + if env['WITH_GHOST_COCOA']: + if env['WITH_BF_QUICKTIME']: + defs.append('WITH_QUICKTIME') + if env['USE_QTKIT']: + defs.append('USE_QTKIT') + for f in pf: + try: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'X11.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') + except ValueError: + pass + else: + for f in pf: + try: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'X11.cpp') + sources.remove('intern' + os.sep + f + 'Cocoa.mm') + except ValueError: + pass + +else: + print "Unknown window system specified." + Exit() + +if env['BF_GHOST_DEBUG']: + defs.append('BF_GHOST_DEBUG') + +incs = '. ../string #extern/glew/include #source/blender/imbuf #source/blender/makesdna ' + env['BF_OPENGL_INC'] +if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'): + incs = env['BF_WINTAB_INC'] + ' ' + incs + +if window_system in ('win32-vc', 'win64-vc'): + env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15]) #, cc_compileflags=env['CCFLAGS'].append('/WX') ) +else: + env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15] ) diff --git a/intern/ghost/doc/ghost_interface.cfg b/intern/ghost/doc/ghost_interface.cfg new file mode 100644 index 00000000000..ebe4153ea3b --- /dev/null +++ b/intern/ghost/doc/ghost_interface.cfg @@ -0,0 +1,626 @@ +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. +PROJECT_NAME = "GHOST (Generic Handy Operating System Toolkit)" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. +OUTPUT_DIRECTORY = ./interface + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, +# Polish, Portuguese and Slovene. +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. +ALWAYS_DETAILED_SEC = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. +ENABLED_SECTION = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. +GENERATE_TESTLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. +ALIASES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. +INPUT = .. + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. +FILE_PATTERNS = *.h *.cpp *.c + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). +EXAMPLE_PATH = ../test + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. +EXAMPLE_PATTERNS = *.h *.cpp *.c + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. +GENERATE_HTMLHELP = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Netscape 4.0+ +# or Internet explorer 4.0+). +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. +ALLEXTERNALS = + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. +GENERATE_LEGEND = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. +CGI_NAME= search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. +CGI_URL= + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. +DOC_URL= + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. +DOC_ABSPATH= + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. +BIN_ABSPATH= /bin + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. +EXT_DOC_PATHS= diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp new file mode 100644 index 00000000000..9f20c103418 --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.cpp @@ -0,0 +1,79 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Buttons.cpp + * \ingroup GHOST + */ + + +#include "GHOST_Buttons.h" + + + +GHOST_Buttons::GHOST_Buttons() +{ + clear(); +} + + +bool GHOST_Buttons::get(GHOST_TButtonMask mask) const +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + return m_ButtonLeft; + case GHOST_kButtonMaskMiddle: + return m_ButtonMiddle; + case GHOST_kButtonMaskRight: + return m_ButtonRight; + default: + return false; + } +} + +void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down) +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + m_ButtonLeft = down; break; + case GHOST_kButtonMaskMiddle: + m_ButtonMiddle = down; break; + case GHOST_kButtonMaskRight: + m_ButtonRight = down; break; + default: + break; + } +} + +void GHOST_Buttons::clear() +{ + m_ButtonLeft = false; + m_ButtonMiddle = false; + m_ButtonRight = false; +} + +GHOST_Buttons::~GHOST_Buttons() {} diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h new file mode 100644 index 00000000000..bf5bdb19d7f --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.h @@ -0,0 +1,79 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Buttons.h + * \ingroup GHOST + * Declaration of GHOST_Buttons struct. + */ + +#ifndef _GHOST_BUTTONS_H_ +#define _GHOST_BUTTONS_H_ + +#include "GHOST_Types.h" + + +/** + * This struct stores the state of the mouse buttons. + * Buttons can be set using button masks. + * @author Maarten Gribnau + * @date May 15, 2001 + */ +struct GHOST_Buttons { + /** + * Constructor. + */ + GHOST_Buttons(); + + virtual ~GHOST_Buttons(); + + /** + * Returns the state of a single button. + * @param mask. Key button to return. + * @return The state of the button (pressed == true). + */ + virtual bool get(GHOST_TButtonMask mask) const; + + /** + * Updates the state of a single button. + * @param mask. Button state to update. + * @param down. The new state of the button. + */ + virtual void set(GHOST_TButtonMask mask, bool down); + + /** + * Sets the state of all buttons to up. + */ + virtual void clear(); + + GHOST_TUns8 m_ButtonLeft : 1; + GHOST_TUns8 m_ButtonMiddle : 1; + GHOST_TUns8 m_ButtonRight : 1; +}; + +#endif // _GHOST_BUTTONS_H_ + diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp new file mode 100644 index 00000000000..7ba8d7db411 --- /dev/null +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -0,0 +1,885 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_C-api.cpp + * \ingroup GHOST + */ + + +/* + + * GHOST_C-Api.cpp + * + * C Api for GHOST + * + * Version: $Id$ + */ + +#include + +#include "intern/GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" +#include "intern/GHOST_CallbackEventConsumer.h" + +GHOST_SystemHandle GHOST_CreateSystem(void) +{ + GHOST_ISystem::createSystem(); + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + + return (GHOST_SystemHandle)system; +} + + + +GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->disposeSystem(); +} + + +GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata) +{ + return (GHOST_EventConsumerHandle) new GHOST_CallbackEventConsumer (eventCallback, userdata); +} + + +GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle) +{ + delete ((GHOST_CallbackEventConsumer*)consumerhandle); + return GHOST_kSuccess; +} + + +GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getMilliSeconds(); +} + + + +GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerproc, + GHOST_TUserDataPtr userdata) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (GHOST_TimerTaskHandle) system->installTimer(delay, interval, timerproc, userdata); +} + + + +GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return system->removeTimer(timertask); +} + + + +GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getNumDisplays(); +} + + + +void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + system->getMainDisplayDimensions(*width, *height); +} + + + +GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + const char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual, + const GHOST_TUns16 numOfAASamples) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + return (GHOST_WindowHandle) system->createWindow(title, left, top, width, height, + state, type, bstereoVisual, numOfAASamples); +} + +GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getUserData(); +} +void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setUserData(userdata); +} + +GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return system->disposeWindow(window); +} + + + +int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) system->validWindow(window); +} + + + +GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = NULL; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + system->beginFullScreen(*setting, &window, bstereoVisual); + + return (GHOST_WindowHandle)window; +} + + + +GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->endFullScreen(); +} + + + +int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->getFullScreen(); +} + + + +int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->processEvents(waitForEvent?true:false); +} + + + +int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->dispatchEvents(); +} + + +GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->addEventConsumer((GHOST_CallbackEventConsumer*)consumerhandle); +} + +GHOST_TSuccess GHOST_RemoveEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->removeEventConsumer((GHOST_CallbackEventConsumer*)consumerhandle); +} + +GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle,float progress) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setProgressBar(progress); +} + +GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->endProgressBar(); +} + + +int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen) + //original patch only + /* GHOST_NDOFEventHandler_fp setNdofEventHandler)*/ +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->openNDOF((GHOST_IWindow*) windowhandle, + setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen); +// original patch +// setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen, setNdofEventHandler); +} + + + +GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getCursorShape(); +} + + + +GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorShape(cursorshape); +} + +GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, hotX, hotY); +} + +GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, sizex, sizey, + hotX, hotY, fg_color, bg_color); +} + + + +int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getCursorVisibility(); +} + + + +GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorVisibility(visible?true:false); +} + + + +GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getCursorPosition(*x, *y); +} + + + +GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->setCursorPosition(x, y); +} + + +GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, + GHOST_TGrabCursorMode mode, + int *bounds) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect bounds_rect, bounds_win; + + if(bounds) { + /* if this is X11 specific we need a function that converts */ + window->getClientBounds(bounds_win); + window->clientToScreen(bounds[0], bounds_win.getHeight() - bounds[1], bounds_rect.m_l, bounds_rect.m_t); + window->clientToScreen(bounds[2], bounds_win.getHeight() - bounds[3], bounds_rect.m_r, bounds_rect.m_b); + + } + + return window->setCursorGrab(mode, bounds ? &bounds_rect:NULL); +} + + +GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown= false; + + result = system->getModifierKeyState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + + +GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown= false; + + result = system->getButtonState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + +void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, GHOST_TInt8 canAccept) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setAcceptDragOperation(canAccept); +} + + +GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getType(); +} + + + +GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getTime(); +} + + +GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return (GHOST_WindowHandle) event->getWindow(); +} + + +GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getData(); +} + + + +GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getTimerProc(); +} + + + +void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerproc) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setTimerProc(timerproc); +} + + + +GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getUserData(); +} + + + +void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userdata) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setUserData(userdata); +} + + + +int GHOST_GetValid(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getValid(); +} + + + +GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getDrawingContextType(); +} + + + +GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setDrawingContextType(type); +} + + + +void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + const char* title) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setTitle(title); +} + + +char* GHOST_GetTitle(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + STR_String title; + + window->getTitle(title); + + char *ctitle = (char*) malloc(title.Length() + 1); + + if (ctitle == NULL) return NULL; + strcpy(ctitle, title.Ptr()); + + return ctitle; +} + + + +GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getWindowBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getClientBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle) +{ + delete (GHOST_Rect*) rectanglehandle; +} + + + +GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientWidth(width); +} + + + +GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientHeight(height); +} + + + +GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientSize(width, height); +} + + + +void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->screenToClient(inX, inY, *outX, *outY); +} + + + +void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->clientToScreen(inX, inY, *outX, *outY); +} + + + +GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getState(); +} + + + +GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setState(state); +} + + +GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, GHOST_TUns8 isUnsavedChanges) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setModifiedState(isUnsavedChanges); +} + + +GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setOrder(order); +} + + + +GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->swapBuffers(); +} + + + +GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->activateDrawingContext(); +} + + + +GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->invalidate(); +} + + +extern const GHOST_TabletData* GHOST_GetTabletData(GHOST_WindowHandle windowhandle) +{ + return ((GHOST_IWindow*)windowhandle)->GetTabletData(); +} + + +GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getWidth(); +} + + + +GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getHeight(); +} + + + +void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b) +{ + GHOST_Rect *rect= (GHOST_Rect*) rectanglehandle; + + *l= rect->m_l; + *t= rect->m_t; + *r= rect->m_r; + *b= rect->m_b; +} + + +void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b) +{ + ((GHOST_Rect*)rectanglehandle)->set(l, t, r, b); +} + + + +GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isEmpty()) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if(((GHOST_Rect*)rectanglehandle)->isValid()) + result = GHOST_kSuccess; + + return result; +} + + + +void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i) +{ + ((GHOST_Rect*)rectanglehandle)->inset(i); +} + + + +void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + ((GHOST_Rect*)rectanglehandle)->unionRect(*(GHOST_Rect*)anotherrectanglehandle); +} + + + +void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + ((GHOST_Rect*)rectanglehandle)->unionPoint(x, y); +} + + + +GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isInside(x, y)) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TVisibility visible = GHOST_kNotVisible; + + visible = ((GHOST_Rect*)rectanglehandle)->getVisibility(*(GHOST_Rect*)anotherrectanglehandle); + + return visible; +} + + + +void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy); +} + + + +void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy, w, h); +} + + + +GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->clip(*(GHOST_Rect*)anotherrectanglehandle)) + result = GHOST_kSuccess; + + return result; +} + +GHOST_TUns8* GHOST_getClipboard(int selection) +{ + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + return system->getClipboard(selection); +} + +void GHOST_putClipboard(GHOST_TInt8 *buffer, int selection) +{ + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + system->putClipboard(buffer, selection); +} + +int GHOST_toggleConsole(int action) +{ + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + return system->toggleConsole(action); +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp new file mode 100644 index 00000000000..64ec7843618 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp @@ -0,0 +1,57 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_CallbackEventConsumer.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date October 25, 2001 + */ + +#include "GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_CallbackEventConsumer.h" + +GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData) +{ + m_eventCallback = eventCallback; + m_userData = userData; +} + + +bool GHOST_CallbackEventConsumer::processEvent(GHOST_IEvent* event) +{ + return m_eventCallback((GHOST_EventHandle)event, m_userData) != 0; +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.h b/intern/ghost/intern/GHOST_CallbackEventConsumer.h new file mode 100644 index 00000000000..b0d8160a5e8 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.h @@ -0,0 +1,80 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_CallbackEventConsumer.h + * \ingroup GHOST + * Declaration of GHOST_CallbackEventConsumer class. + */ + +#ifndef _GHOST_CALLBACK_EVENT_CONSUMER_H_ +#define _GHOST_CALLBACK_EVENT_CONSUMER_H_ + +#include "GHOST_IEventConsumer.h" +#include "GHOST_C-api.h" + +/** + * Event consumer that will forward events to a call-back routine. + * Especially useful for the C-API. + * @author Maarten Gribnau + * @date October 25, 2001 + */ +class GHOST_CallbackEventConsumer : public GHOST_IEventConsumer +{ +public: + /** + * Constructor. + * @param eventCallback The call-back routine invoked. + * @param userData The data passed back though the call-back routine. + */ + GHOST_CallbackEventConsumer( + GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData); + + /** + * Destructor. + */ + virtual ~GHOST_CallbackEventConsumer(void) + { + } + + /** + * This method is called by an event producer when an event is available. + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** The call-back routine invoked. */ + GHOST_EventCallbackProcPtr m_eventCallback; + /** The data passed back though the call-back routine. */ + GHOST_TUserDataPtr m_userData; +}; + +#endif // _GHOST_CALLBACK_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h new file mode 100644 index 00000000000..e77f3b9c461 --- /dev/null +++ b/intern/ghost/intern/GHOST_Debug.h @@ -0,0 +1,70 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Debug.h + * \ingroup GHOST + * Macro's used in GHOST debug target. + */ + +#ifndef _GHOST_DEBUG_H_ +#define _GHOST_DEBUG_H_ + +#if defined(WIN32) && !defined(FREE_WINDOWS) + #ifdef DEBUG + #pragma warning (disable:4786) // suppress stl-MSVC debug info warning + // #define GHOST_DEBUG + #endif // DEBUG +#endif // WIN32 + +#ifdef BF_GHOST_DEBUG + #define GHOST_DEBUG // spit ghost events to stdout +#endif // BF_GHOST_DEBUG + +#ifdef GHOST_DEBUG + #include + #include //for printf() +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_PRINT(x) { std::cout << x; } + #define GHOST_PRINTF(x, ...) { printf(x, __VA_ARGS__); } +#else // GHOST_DEBUG + #define GHOST_PRINT(x) + #define GHOST_PRINTF(x, ...) +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_ASSERT(x, info) { if (!(x)) {GHOST_PRINT("assertion failed: "); GHOST_PRINT(info); GHOST_PRINT("\n"); } } +#else // GHOST_DEBUG + #define GHOST_ASSERT(x, info) +#endif // GHOST_DEBUG + +#endif // _GHOST_DEBUG_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp new file mode 100644 index 00000000000..80466efeee7 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.cpp @@ -0,0 +1,218 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManager.cpp + * \ingroup GHOST + */ + + +/** + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#include "GHOST_DisplayManager.h" +#include "GHOST_Debug.h" + + +GHOST_DisplayManager::GHOST_DisplayManager( + void) +: m_settingsInitialized(false) +{ +} + + +GHOST_DisplayManager::~GHOST_DisplayManager(void) +{ +} + + +GHOST_TSuccess +GHOST_DisplayManager::initialize( + void) +{ + GHOST_TSuccess success; + if (!m_settingsInitialized) { + success = initializeSettings(); + m_settingsInitialized = true; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplays( + GHOST_TUns8& /*numDisplays*/) const +{ + // Don't know if we have a display... + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays) { + numSettings = m_settings[display].size(); + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays && ((GHOST_TUns8)index < m_settings[display].size())) { + setting = m_settings[display][index]; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + GHOST_DisplaySetting& /*setting*/) const +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::setCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + const GHOST_DisplaySetting& /*setting*/) +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::findMatch( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting, + GHOST_DisplaySetting& match) const +{ + GHOST_TSuccess success = GHOST_kSuccess; + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::findMatch(): m_settingsInitialized=false"); + + int criteria[4] = { setting.xPixels, setting.yPixels, setting.bpp, setting.frequency }; + int capabilities[4]; + double field, score; + double best = 1e12; // A big number + int found = 0; + + // Look at all the display modes + for (int i = 0; (i < (int)m_settings[display].size()); i++) { + // Store the capabilities of the display device + capabilities[0] = m_settings[display][i].xPixels; + capabilities[1] = m_settings[display][i].yPixels; + capabilities[2] = m_settings[display][i].bpp; + capabilities[3] = m_settings[display][i].frequency; + + // Match against all the fields of the display settings + score = 0; + for (int j = 0; j < 4; j++) { + field = capabilities[j] - criteria[j]; + score += field * field; + } + + if (score < best) { + found = i; + best = score; + } + } + + match = m_settings[display][found]; + + GHOST_PRINT("GHOST_DisplayManager::findMatch(): settings of match:\n"); + GHOST_PRINT(" setting.xPixels=" << match.xPixels << "\n"); + GHOST_PRINT(" setting.yPixels=" << match.yPixels << "\n"); + GHOST_PRINT(" setting.bpp=" << match.bpp << "\n"); + GHOST_PRINT(" setting.frequency=" << match.frequency << "\n"); + + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::initializeSettings( + void) +{ + GHOST_TUns8 numDisplays; + GHOST_TSuccess success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + for (GHOST_TUns8 display = 0; (display < numDisplays) && (success == GHOST_kSuccess); display++) { + GHOST_DisplaySettings displaySettings; + m_settings.push_back(displaySettings); + GHOST_TInt32 numSettings; + success = getNumDisplaySettings(display, numSettings); + if (success == GHOST_kSuccess) { + GHOST_TInt32 index; + GHOST_DisplaySetting setting; + for (index = 0; (index < numSettings) && (success == GHOST_kSuccess); index++) { + success = getDisplaySetting(display, index, setting); + m_settings[display].push_back(setting); + } + } + else { + break; + } + } + } + return success; +} diff --git a/intern/ghost/intern/GHOST_DisplayManager.h b/intern/ghost/intern/GHOST_DisplayManager.h new file mode 100644 index 00000000000..16e702f692a --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.h @@ -0,0 +1,134 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManager.h + * \ingroup GHOST + * Declaration of GHOST_DisplayManager class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_H_ +#define _GHOST_DISPLAY_MANAGER_H_ + +#include "GHOST_Types.h" + +#include + +/** + * Manages system displays (platform independent implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManager +{ +public: + enum { kMainDisplay = 0 }; + /** + * Constructor. + */ + GHOST_DisplayManager(void); + + /** + * Destructor. + */ + virtual ~GHOST_DisplayManager(void); + + /** + * Initializes the list with devices and settings. + * @return Indication of success. + */ + virtual GHOST_TSuccess initialize(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * The setting given to this method is matched againts the available diplay settings. + * The best match is activated (@see findMatch()). + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The setting of the display device to be matched and activated. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + typedef std::vector GHOST_DisplaySettings; + + /** + * Finds the best display settings match. + * @param display The index of the display device. + * @param setting The setting to match. + * @param match The optimal display setting. + * @return Indication of success. + */ + GHOST_TSuccess findMatch(GHOST_TUns8 display, const GHOST_DisplaySetting& setting, GHOST_DisplaySetting& match) const; + + /** + * Retrieves settings for each display device and stores them. + * @return Indication of success. + */ + GHOST_TSuccess initializeSettings(void); + + /** Tells whether the list of display modes has been stored already. */ + bool m_settingsInitialized; + /** The list with display settings for the main display. */ + std::vector m_settings; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp new file mode 100644 index 00000000000..077b380e320 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp @@ -0,0 +1,179 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerCarbon.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment + + +GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(void) +{ + if (::CGGetActiveDisplayList(0, NULL, &m_numDisplays) != CGDisplayNoErr) + { + m_numDisplays = 0; + m_displayIDs = NULL; + } + if (m_numDisplays > 0) + { + m_displayIDs = new CGDirectDisplayID [m_numDisplays]; + GHOST_ASSERT((m_displayIDs!=NULL), "GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(): memory allocation failed"); + ::CGGetActiveDisplayList(m_numDisplays, m_displayIDs, &m_numDisplays); + } +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + numDisplays = (GHOST_TUns8) m_numDisplays; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getNumDisplaySettings(): only main display is supported"); + + CFArrayRef displayModes; + displayModes = ::CGDisplayAvailableModes(m_displayIDs[display]); + CFIndex numModes = ::CFArrayGetCount(displayModes); + numSettings = (GHOST_TInt32)numModes; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getDisplaySetting(): only main display is supported"); + + CFArrayRef displayModes; + CGDirectDisplayID d = m_displayIDs[display]; + displayModes = ::CGDisplayAvailableModes(d); + //CFIndex numModes = ::CFArrayGetCount(displayModes);/*unused*/ + //GHOST_TInt32 numSettings = (GHOST_TInt32)numModes; /*unused*/ + CFDictionaryRef displayModeValues = (CFDictionaryRef)::CFArrayGetValueAtIndex(displayModes, index); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(): only main display is supported"); + + CFDictionaryRef displayModeValues = ::CGDisplayCurrentMode(m_displayIDs[display]); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): only main display is supported"); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): requested settings:\n"); + printf(" setting.xPixels=%d\n", setting.xPixels); + printf(" setting.yPixels=%d\n", setting.yPixels); + printf(" setting.bpp=%d\n", setting.bpp); + printf(" setting.frequency=%d\n", setting.frequency); +#endif // GHOST_DEBUG + + CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate( + m_displayIDs[display], + (size_t)setting.bpp, + (size_t)setting.xPixels, + (size_t)setting.yPixels, + (CGRefreshRate)setting.frequency, + NULL); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): switching to:\n"); + printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth)); + printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight)); + printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel)); + printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate)); +#endif // GHOST_DEBUG + + CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues); + + return err == CGDisplayNoErr ? GHOST_kSuccess : GHOST_kFailure; +} + + +long GHOST_DisplayManagerCarbon::getValue(CFDictionaryRef values, CFStringRef key) const +{ + CFNumberRef numberValue = (CFNumberRef) CFDictionaryGetValue(values, key); + + if (!numberValue) + { + return -1; + } + + long intValue; + + if (!CFNumberGetValue(numberValue, kCFNumberLongType, &intValue)) + { + return -1; + } + + return intValue; +} + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.h b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h new file mode 100644 index 00000000000..6637bee1804 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h @@ -0,0 +1,117 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerCarbon.h + * \ingroup GHOST + * Declaration of GHOST_DisplayManagerCarbon class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_CARBON_H_ +#define _GHOST_DISPLAY_MANAGER_CARBON_H_ + +#ifndef __APPLE__ +#error Apple only! +#endif // __APPLE__ + +#include "GHOST_DisplayManager.h" + +#define __CARBONSOUND__ +#include + +/** + * Manages system displays (Mac OSX/Carbon implementation). + * @see GHOST_DisplayManager + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerCarbon : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerCarbon(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + /** + * Returns a value from a dictionary. + * @param values Dictionary to return value from. + * @param key Key to return value for. + * @return The value for this key. + */ + long getValue(CFDictionaryRef values, CFStringRef key) const; + + /** Cached number of displays. */ + CGDisplayCount m_numDisplays; + /** Cached display id's for each display. */ + CGDirectDisplayID* m_displayIDs; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h new file mode 100644 index 00000000000..2248019258f --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h @@ -0,0 +1,107 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerCocoa.h + * \ingroup GHOST + * Declaration of GHOST_DisplayManagerCocoa class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_COCOA_H_ +#define _GHOST_DISPLAY_MANAGER_COCOA_H_ + +#ifndef __APPLE__ +#error Apple only! +#endif // __APPLE__ + +#include "GHOST_DisplayManager.h" + +/** + * Manages system displays (Mac OSX/Cocoa implementation). + * @see GHOST_DisplayManager + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerCocoa : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerCocoa(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + //Do not cache values as OS X supports screen hot plug + /** Cached number of displays. */ + //CGDisplayCount m_numDisplays; + /** Cached display id's for each display. */ + //CGDirectDisplayID* m_displayIDs; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_COCOA_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm new file mode 100644 index 00000000000..ab3abdd659f --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm @@ -0,0 +1,168 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Maarten Gribnau 09/2001 + Damien Plisson 10/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include "GHOST_DisplayManagerCocoa.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment + + +GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(void) +{ +} + + +GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + numDisplays = (GHOST_TUns8) [[NSScreen screens] count]; + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getNumDisplaySettings(): only main display is supported"); + + numSettings = (GHOST_TInt32)3; //Width, Height, BitsPerPixel + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCocoa::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + //Note that only current display setting is available + NSScreen *askedDisplay; + + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getDisplaySetting(): only main display is supported"); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (display == kMainDisplay) //Screen #0 may not be the main one + askedDisplay = [NSScreen mainScreen]; + else + askedDisplay = [[NSScreen screens] objectAtIndex:display]; + + if(askedDisplay == nil) { + [pool drain]; + return GHOST_kFailure; + } + + NSRect frame = [askedDisplay visibleFrame]; + setting.xPixels = frame.size.width; + setting.yPixels = frame.size.height; + + setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]); + + setting.frequency = 0; //No more CRT display... + +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + NSScreen *askedDisplay; + + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(): only main display is supported"); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (display == kMainDisplay) //Screen #0 may not be the main one + askedDisplay = [NSScreen mainScreen]; + else + askedDisplay = [[NSScreen screens] objectAtIndex:display]; + + if(askedDisplay == nil) { + [pool drain]; + return GHOST_kFailure; + } + + NSRect frame = [askedDisplay visibleFrame]; + setting.xPixels = frame.size.width; + setting.yPixels = frame.size.height; + + setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]); + + setting.frequency = 0; //No more CRT display... + +#ifdef GHOST_DEBUG + printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): only main display is supported"); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): requested settings:\n"); + printf(" setting.xPixels=%d\n", setting.xPixels); + printf(" setting.yPixels=%d\n", setting.yPixels); + printf(" setting.bpp=%d\n", setting.bpp); + printf(" setting.frequency=%d\n", setting.frequency); +#endif // GHOST_DEBUG + + //Display configuration is no more available in 10.6 + +/* CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate( + m_displayIDs[display], + (size_t)setting.bpp, + (size_t)setting.xPixels, + (size_t)setting.yPixels, + (CGRefreshRate)setting.frequency, + NULL);*/ + +#ifdef GHOST_DEBUG +/* printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): switching to:\n"); + printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth)); + printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight)); + printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel)); + printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate)); */ +#endif // GHOST_DEBUG + + //CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues); + + return /*err == CGDisplayNoErr ? GHOST_kSuccess :*/ GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp new file mode 100644 index 00000000000..30d9aa31207 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -0,0 +1,182 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerWin32.cpp + * \ingroup GHOST + * \author Maarten Gribnau + * \date September 21, 2001 + */ + +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment +#include +#define COMPILE_MULTIMON_STUBS +#ifndef FREE_WINDOWS +#include +#endif + + +GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void) +{ +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + // We do not support multiple monitors at the moment + numDisplays = ::GetSystemMetrics(SM_CMONITORS); + return numDisplays > 0 ? GHOST_kSuccess : GHOST_kFailure; +} + + +/* + * When you call EnumDisplaySettings with iModeNum set to zero, the operating system + * initializes and caches information about the display device. When you call + * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns + * the information that was cached the last time the function was called with iModeNum + * set to zero. + */ +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getNumDisplaySettings(): only main displlay is supported"); + numSettings = 0; + DEVMODE dm; + while (::EnumDisplaySettings(NULL, numSettings, &dm)) { + numSettings++; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getDisplaySetting(): only main display is supported"); + GHOST_TSuccess success; + DEVMODE dm; + if (::EnumDisplaySettings(NULL, index, &dm)) { +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + setting.xPixels = dm.dmPelsWidth; + setting.yPixels = dm.dmPelsHeight; + setting.bpp = dm.dmBitsPerPel; + /* When you call the EnumDisplaySettings function, the dmDisplayFrequency member + * may return with the value 0 or 1. These values represent the display hardware's + * default refresh rate. This default rate is typically set by switches on a display + * card or computer motherboard, or by a configuration program that does not use + * Win32 display functions such as ChangeDisplaySettings. + */ + /* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings + * returned 0 or 1 but this doesn't work since later on an exact match will + * be searched. And this will never happen if we change it to 60. Now we rely + * on the default h/w setting. + */ + setting.frequency = dm.dmDisplayFrequency; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getCurrentDisplaySetting(): only main display is supported"); + return getDisplaySetting(kMainDisplay, ENUM_CURRENT_SETTINGS, setting); +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::setCurrentDisplaySetting(): only main display is supported"); + + GHOST_DisplaySetting match; + findMatch(display, setting, match); + DEVMODE dm; + int i = 0; + while (::EnumDisplaySettings(NULL, i++, &dm)) { + if ((dm.dmBitsPerPel == match.bpp) && + (dm.dmPelsWidth == match.xPixels) && + (dm.dmPelsHeight == match.yPixels) && + (dm.dmDisplayFrequency == match.frequency)) { + break; + } + } + /* + dm.dmBitsPerPel = match.bpp; + dm.dmPelsWidth = match.xPixels; + dm.dmPelsHeight = match.yPixels; + dm.dmDisplayFrequency = match.frequency; + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + dm.dmSize = sizeof(DEVMODE); + dm.dmDriverExtra = 0; + */ +#ifdef GHOST_DEBUG + printf("display change: Requested settings:\n"); + printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel); + printf(" dmPelsWidth=%d\n", dm.dmPelsWidth); + printf(" dmPelsHeight=%d\n", dm.dmPelsHeight); + printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + + LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN); +#ifdef GHOST_DEBUG + switch (status) + { + case DISP_CHANGE_SUCCESSFUL: + printf("display change: The settings change was successful.\n"); + break; + case DISP_CHANGE_RESTART: + printf("display change: The computer must be restarted in order for the graphics mode to work.\n"); + break; + case DISP_CHANGE_BADFLAGS: + printf("display change: An invalid set of flags was passed in.\n"); + break; + case DISP_CHANGE_BADPARAM: + printf("display change: An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n"); + break; + case DISP_CHANGE_FAILED: + printf("display change: The display driver failed the specified graphics mode.\n"); + break; + case DISP_CHANGE_BADMODE: + printf("display change: The graphics mode is not supported.\n"); + break; + case DISP_CHANGE_NOTUPDATED: + printf("display change: Windows NT: Unable to write settings to the registry.\n"); + break; + default: + printf("display change: Return value invalid\n"); + break; + } +#endif // GHOST_DEBUG + return status == DISP_CHANGE_SUCCESSFUL? GHOST_kSuccess : GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.h b/intern/ghost/intern/GHOST_DisplayManagerWin32.h new file mode 100644 index 00000000000..9a3a79fe28b --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.h @@ -0,0 +1,102 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerWin32.h + * \ingroup GHOST + * Declaration of GHOST_DisplayManagerWin32 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_WIN32_H_ +#define _GHOST_DISPLAY_MANAGER_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_DisplayManager.h" + + +/** + * Manages system displays (WIN32 implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerWin32 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerWin32(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: +}; + + +#endif // _GHOST_DISPLAY_MANAGER_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp new file mode 100644 index 00000000000..fe5e4471280 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp @@ -0,0 +1,126 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerX11.cpp + * \ingroup GHOST + */ + + +#include "GHOST_DisplayManagerX11.h" +#include "GHOST_SystemX11.h" + + + +GHOST_DisplayManagerX11:: +GHOST_DisplayManagerX11( + GHOST_SystemX11 *system +) : + GHOST_DisplayManager(), + m_system(system) +{ + //nothing to do. +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplays( + GHOST_TUns8& numDisplays +) const{ + numDisplays = m_system->getNumDisplays(); + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings +) const{ + + // We only have one X11 setting at the moment. + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + numSettings = GHOST_TInt32(1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting +) const { + + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n"); + + Display * x_display = m_system->getXDisplay(); + + if (x_display == NULL) { + return GHOST_kFailure; + } + + setting.xPixels = DisplayWidth(x_display, DefaultScreen(x_display)); + setting.yPixels = DisplayHeight(x_display, DefaultScreen(x_display)); + setting.bpp = DefaultDepth(x_display,DefaultScreen(x_display)); + + // Don't think it's possible to get this value from X! + // So let's guess!! + setting.frequency = 60; + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting +) const { + return getDisplaySetting(display,GHOST_TInt32(0),setting); +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting +){ + // This is never going to work robustly in X + // but it's currently part of the full screen interface + + // we fudge it for now. + + return GHOST_kSuccess; +} + + + + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.h b/intern/ghost/intern/GHOST_DisplayManagerX11.h new file mode 100644 index 00000000000..435d4383910 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.h @@ -0,0 +1,124 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DisplayManagerX11.h + * \ingroup GHOST + * Declaration of GHOST_DisplayManagerX11 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_X11_H_ +#define _GHOST_DISPLAY_MANAGER_X11_H_ + +#include "GHOST_DisplayManager.h" + + +class GHOST_SystemX11; + +/** + * Manages system displays (X11 implementation). + * @author Laurence Bourn + * @date October 26, 2001 + */ +class GHOST_DisplayManagerX11 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerX11( + GHOST_SystemX11 *system + ); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplays( + GHOST_TUns8& numDisplays + ) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting + ) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting + ); + +private : + + GHOST_SystemX11 * m_system; +}; + + +#endif // + diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp new file mode 100644 index 00000000000..2e77da42b31 --- /dev/null +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -0,0 +1,431 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DropTargetWin32.cpp + * \ingroup GHOST + */ + + +#include "GHOST_Debug.h" +#include "GHOST_DropTargetWin32.h" + +#ifdef GHOST_DEBUG +// utility +void printLastError(void); +#endif // GHOST_DEBUG + + +GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 * window, GHOST_SystemWin32 * system) +: +m_window(window), +m_system(system) +{ + m_cRef = 1; + m_hWnd = window->getHWND(); + m_draggedObjectType = GHOST_kDragnDropTypeUnknown; + + // register our window as drop target + ::RegisterDragDrop(m_hWnd, this); +} + +GHOST_DropTargetWin32::~GHOST_DropTargetWin32() +{ + ::RevokeDragDrop(m_hWnd); +} + + +/* + * IUnknown::QueryInterface + */ +HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface (REFIID riid, void ** ppvObj) +{ + + if (!ppvObj) + return E_INVALIDARG; + *ppvObj = NULL; + + if(riid == IID_IUnknown || riid == IID_IDropTarget) + { + AddRef(); + *ppvObj = (void*)this; + return S_OK; + } + else + { + *ppvObj = 0; + return E_NOINTERFACE; + } +} + + +/* + * IUnknown::AddRef + */ + +ULONG __stdcall GHOST_DropTargetWin32::AddRef(void) +{ + return ::InterlockedIncrement(&m_cRef); +} + +/* + * IUnknown::Release + */ +ULONG __stdcall GHOST_DropTargetWin32::Release(void) +{ + ULONG refs = ::InterlockedDecrement(&m_cRef); + + if(refs == 0) + { + delete this; + return 0; + } + else + { + return refs; + } +} + +/* + * Implementation of IDropTarget::DragEnter + */ +HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) +{ + // we accept all drop by default + m_window->setAcceptDragOperation(true); + *pdwEffect = DROPEFFECT_NONE; + + m_draggedObjectType = getGhostType(pDataObject); + m_system->pushDragDropEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL); + return S_OK; +} + +/* + * Implementation of IDropTarget::DragOver + */ +HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) +{ + if(m_window->canAcceptDragOperation()) + { + *pdwEffect = allowedDropEffect(*pdwEffect); + } + else + { + *pdwEffect = DROPEFFECT_NONE; + //*pdwEffect = DROPEFFECT_COPY; // XXX Uncomment to test drop. Drop will not be called if pdwEffect == DROPEFFECT_NONE. + } + m_system->pushDragDropEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, NULL); + return S_OK; +} + +/* + * Implementation of IDropTarget::DragLeave + */ +HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) +{ + m_system->pushDragDropEvent(GHOST_kEventDraggingExited, m_draggedObjectType, m_window, 0, 0, NULL); + m_draggedObjectType = GHOST_kDragnDropTypeUnknown; + return S_OK; +} + +/* Implementation of IDropTarget::Drop + * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in + * the implementation of IDropTarget::DragOver + */ +HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) +{ + void * data = getGhostData(pDataObject); + if(m_window->canAcceptDragOperation()) + { + *pdwEffect = allowedDropEffect(*pdwEffect); + + } + else + { + *pdwEffect = DROPEFFECT_NONE; + } + if (data) + m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data ); + + m_draggedObjectType = GHOST_kDragnDropTypeUnknown; + return S_OK; +} + +/* + * Helpers + */ + +DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed) +{ + DWORD dwEffect = DROPEFFECT_NONE; + if(dwAllowed & DROPEFFECT_COPY) + dwEffect = DROPEFFECT_COPY; + + return dwEffect; +} + +GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject * pDataObject) +{ + /* Text + * Note: Unicode text is aviable as CF_TEXT too, the system can do the + * conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS. + */ + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + if(pDataObject->QueryGetData(&fmtetc) == S_OK) + { + return GHOST_kDragnDropTypeString; + } + + // Filesnames + fmtetc.cfFormat = CF_HDROP; + if(pDataObject->QueryGetData(&fmtetc) == S_OK) + { + return GHOST_kDragnDropTypeFilenames; + } + + return GHOST_kDragnDropTypeUnknown; +} + +void * GHOST_DropTargetWin32::getGhostData(IDataObject * pDataObject) +{ + GHOST_TDragnDropTypes type = getGhostType(pDataObject); + switch(type) + { + case GHOST_kDragnDropTypeFilenames: + return getDropDataAsFilenames(pDataObject); + break; + case GHOST_kDragnDropTypeString: + return getDropDataAsString(pDataObject); + break; + case GHOST_kDragnDropTypeBitmap: + //return getDropDataAsBitmap(pDataObject); + break; + default: +#ifdef GHOST_DEBUG + ::printf("\nGHOST_kDragnDropTypeUnknown"); +#endif // GHOST_DEBUG + return NULL; + break; + } + return NULL; +} + +void * GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject * pDataObject) +{ + UINT totfiles, nvalid=0; + WCHAR fpath [MAX_PATH]; + char * temp_path; + GHOST_TStringArray *strArray = NULL; + FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stgmed; + HDROP hdrop; + + // Check if dataobject supplies the format we want. + // Double checking here, first in getGhostType. + if(pDataObject->QueryGetData(&fmtetc) == S_OK) + { + if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) + { + hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); + + totfiles = ::DragQueryFileW ( hdrop, -1, NULL, 0 ); + if (!totfiles) + { + ::GlobalUnlock(stgmed.hGlobal); + return NULL; + } + + strArray = (GHOST_TStringArray*) ::malloc(sizeof(GHOST_TStringArray)); + strArray->count = 0; + strArray->strings = (GHOST_TUns8**) ::malloc(totfiles*sizeof(GHOST_TUns8*)); + + for ( UINT nfile = 0; nfile < totfiles; nfile++ ) + { + if ( ::DragQueryFileW ( hdrop, nfile, fpath, MAX_PATH ) > 0 ) + { + if ( !WideCharToANSI(fpath, temp_path) ) + { + continue; + } + // Just ignore paths that could not be converted verbatim. + if (strpbrk(temp_path, "?")) + { +#ifdef GHOST_DEBUG + ::printf("\ndiscarding path that contains illegal characters: %s", temp_path); +#endif // GHOST_DEBUG + ::free(temp_path); + temp_path = NULL; + continue; + } + strArray->strings[nvalid] = (GHOST_TUns8*) temp_path; + strArray->count = nvalid+1; + nvalid++; + } + } + // Free up memory. + ::GlobalUnlock(stgmed.hGlobal); + ::ReleaseStgMedium(&stgmed); + + return strArray; + } + } + return NULL; +} + +void * GHOST_DropTargetWin32::getDropDataAsString(IDataObject * pDataObject) +{ + char* tmp_string; + FORMATETC fmtetc = { CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stgmed; + + // Try unicode first. + // Check if dataobject supplies the format we want. + if(pDataObject->QueryGetData(&fmtetc) == S_OK) + { + if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) + { + LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal); + if ( !WideCharToANSI(wstr, tmp_string) ) + { + ::GlobalUnlock(stgmed.hGlobal); + return NULL; + } + // Free memory + ::GlobalUnlock(stgmed.hGlobal); + ::ReleaseStgMedium(&stgmed); +#ifdef GHOST_DEBUG + ::printf("\n\n%s\n\n",tmp_string); +#endif // GHOST_DEBUG + return tmp_string; + } + } + + fmtetc.cfFormat = CF_TEXT; + + if(pDataObject->QueryGetData(&fmtetc) == S_OK) + { + if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) + { + char * str = (char*)::GlobalLock(stgmed.hGlobal); + + tmp_string = (char*)::malloc(::strlen(str)+1); + if ( !tmp_string ) + { + ::GlobalUnlock(stgmed.hGlobal); + return NULL; + } + + if ( !::strcpy(tmp_string, str) ) + { + ::free(tmp_string); + ::GlobalUnlock(stgmed.hGlobal); + return NULL; + } + // Free memory + ::GlobalUnlock(stgmed.hGlobal); + ::ReleaseStgMedium(&stgmed); + + return tmp_string; + } + } + + return NULL; +} + +int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char * &out) +{ + int size; + out = NULL; //caller should free if != NULL + + // Get the required size. + size = ::WideCharToMultiByte(CP_ACP, //System Default Codepage + 0x00000400, // WC_NO_BEST_FIT_CHARS + in, + -1, //-1 null terminated, makes output null terminated too. + NULL, + 0, + NULL,NULL + ); + + if(!size) + { +#ifdef GHOST_DEBUG + ::printLastError(); +#endif // GHOST_DEBUG + return 0; + } + + out = (char*)::malloc(size); + if (!out) + { + ::printf("\nmalloc failed!!!"); + return 0; + } + + size = ::WideCharToMultiByte(CP_ACP, + 0x00000400, + in, + -1, + (LPSTR) out, + size, + NULL,NULL + ); + + if(!size) + { +#ifdef GHOST_DEBUG + ::printLastError(); +#endif //GHOST_DEBUG + ::free(out); + out = NULL; + } + return size; +} + +#ifdef GHOST_DEBUG +void printLastError(void) +{ + LPTSTR s; + DWORD err; + + err = GetLastError(); + if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err, + 0, + (LPTSTR)&s, + 0, + NULL) + ) + { + printf("\nLastError: (%d) %s\n", (int)err, s); + LocalFree(s); + } +} +#endif // GHOST_DEBUG + diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h new file mode 100644 index 00000000000..0a553b6701e --- /dev/null +++ b/intern/ghost/intern/GHOST_DropTargetWin32.h @@ -0,0 +1,160 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_DropTargetWin32.h + * \ingroup GHOST + */ + +#ifndef _GHOST_DROP_TARGET_WIN32_H_ +#define _GHOST_DROP_TARGET_WIN32_H_ + +#include +#include +#include +#include "GHOST_WindowWin32.h" +#include "GHOST_SystemWin32.h" + +class GHOST_DropTargetWin32 : public IDropTarget +{ +public: + /* IUnknownd implementation. + * Enables clients to get pointers to other interfaces on a given object + * through the QueryInterface method, and manage the existence of the object + * through the AddRef and Release methods. All other COM interfaces are + * inherited, directly or indirectly, from IUnknown. Therefore, the three + * methods in IUnknown are the first entries in the VTable for every interface. + */ + HRESULT __stdcall QueryInterface (REFIID riid, void ** ppvObj); + ULONG __stdcall AddRef (void); + ULONG __stdcall Release (void); + + /* IDropTarget implementation + + The IDropTarget interface is one of the interfaces you implement to + provide drag-and-drop operations in your application. It contains methods + used in any application that can be a target for data during a + drag-and-drop operation. A drop-target application is responsible for: + * + * - Determining the effect of the drop on the target application. + * - Incorporating any valid dropped data when the drop occurs. + * - Communicating target feedback to the source so the source application + * can provide appropriate visual feedback such as setting the cursor. + * - Implementing drag scrolling. + * - Registering and revoking its application windows as drop targets. + * + * The IDropTarget interface contains methods that handle all these + * responsibilities except registering and revoking the application window + * as a drop target, for which you must call the RegisterDragDrop and the + * RevokeDragDrop functions. + */ + + HRESULT __stdcall DragEnter (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); + HRESULT __stdcall DragOver (DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); + HRESULT __stdcall DragLeave (void); + HRESULT __stdcall Drop (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); + + /** + * Constructor + * With the modifier keys, we want to distinguish left and right keys. + * Sometimes this is not possible (Windows ME for instance). Then, we want + * events generated for both keys. + * @param window The window to register as drop target. + * @param system The associated system. + */ + GHOST_DropTargetWin32(GHOST_WindowWin32 * window, GHOST_SystemWin32 * system); + + /** + * Destructor + * Do NOT destroy directly. Use Release() instead to make COM happy. + */ + ~GHOST_DropTargetWin32(); + +private: + + /* Internal helper functions */ + + /** + * Base the effect on those allowed by the dropsource. + * @param dwAllowed Drop sources allowed drop effect. + * @return The allowed drop effect. + */ + DWORD allowedDropEffect(DWORD dwAllowed); + + /** + * Query DataObject for the data types it supports. + * @param pDataObject Pointer to the DataObject. + * @return GHOST data type. + */ + GHOST_TDragnDropTypes getGhostType(IDataObject * pDataObject); + + /** + * Get data to pass in event. + * It checks the type and calls specific functions for each type. + * @param pDataObject Pointer to the DataObject. + * @return Pointer to data. + */ + void * getGhostData(IDataObject * pDataObject); + + /** + * Allocate data as file array to pass in event. + * @param pDataObject Pointer to the DataObject. + * @return Pointer to data. + */ + void * getDropDataAsFilenames(IDataObject * pDataObject); + + /** + * Allocate data as string to pass in event. + * @param pDataObject Pointer to the DataObject. + * @return Pointer to data. + */ + void * getDropDataAsString(IDataObject * pDataObject); + + /** + * Convert Unicode to ANSI, replacing unconvertable chars with '?'. + * The ANSI codepage is the system default codepage, + * and can change from system to system. + * @param in LPCWSTR. + * @param out char *. Is set to NULL on failure. + * @return 0 on failure. Else the size of the string including '\0'. + */ + int WideCharToANSI(LPCWSTR in, char * &out); + + /* Private member variables */ + /* COM reference count. */ + LONG m_cRef; + /* Handle of the associated window. */ + HWND m_hWnd; + /* The associated GHOST_WindowWin32. */ + GHOST_WindowWin32 * m_window; + /* The System. */ + GHOST_SystemWin32 * m_system; + /* Data type of the dragged object */ + GHOST_TDragnDropTypes m_draggedObjectType; + +}; + +#endif // _GHOST_DROP_TARGET_WIN32_H_ diff --git a/intern/ghost/intern/GHOST_Event.h b/intern/ghost/intern/GHOST_Event.h new file mode 100644 index 00000000000..cfcbe2ef395 --- /dev/null +++ b/intern/ghost/intern/GHOST_Event.h @@ -0,0 +1,108 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Event.h + * \ingroup GHOST + * Declaration of GHOST_Event class. + */ + +#ifndef _GHOST_EVENT_H_ +#define _GHOST_EVENT_H_ + +#include "GHOST_IEvent.h" + + +/** + * Base class for events received the operating system. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_Event : public GHOST_IEvent +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param window The generating window (or NULL if system event). + */ + GHOST_Event(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window) + : m_type(type), m_time(msec), m_window(window), m_data(0) + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() + { + return m_type; + } + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() + { + return m_time; + } + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() + { + return m_window; + } + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() + { + return m_data; + } + +protected: + /** Type of this event. */ + GHOST_TEventType m_type; + /** The time this event was generated. */ + GHOST_TUns64 m_time; + /** Pointer to the generating window. */ + GHOST_IWindow* m_window; + /** Pointer to the event data. */ + GHOST_TEventDataPtr m_data; +}; + +#endif // _GHOST_EVENT_H_ + diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h new file mode 100644 index 00000000000..3016917b810 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventButton.h @@ -0,0 +1,68 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventButton.h + * \ingroup GHOST + * Declaration of GHOST_EventButton class. + */ + +#ifndef _GHOST_EVENT_BUTTON_H_ +#define _GHOST_EVENT_BUTTON_H_ + +#include "GHOST_Event.h" + +/** + * Mouse button event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventButton : public GHOST_Event +{ +public: + /** + * Constructor. + * @param time The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + * @param buttons The state of the buttons was at at the time of the event. + */ + GHOST_EventButton(GHOST_TUns64 time, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TButtonMask button) + : GHOST_Event(time, type, window) + { + m_buttonEventData.button = button; + m_data = &m_buttonEventData; + } + +protected: + /** The button event data. */ + GHOST_TEventButtonData m_buttonEventData; +}; + +#endif // _GHOST_EVENT_BUTTON_H_ + diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h new file mode 100644 index 00000000000..db4dcb7b59b --- /dev/null +++ b/intern/ghost/intern/GHOST_EventCursor.h @@ -0,0 +1,69 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventCursor.h + * \ingroup GHOST + * Declaration of GHOST_EventCursor class. + */ + +#ifndef _GHOST_EVENT_CURSOR_H_ +#define _GHOST_EVENT_CURSOR_H_ + +#include "GHOST_Event.h" + +/** + * Cursor event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventCursor : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + */ + GHOST_EventCursor(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TInt32 x, GHOST_TInt32 y) + : GHOST_Event(msec, type, window) + { + m_cursorEventData.x = x; + m_cursorEventData.y = y; + m_data = &m_cursorEventData; + } + +protected: + /** The x,y-coordinates of the cursor position. */ + GHOST_TEventCursorData m_cursorEventData; +}; + + +#endif // _GHOST_EVENT_CURSOR_H_ + diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h new file mode 100644 index 00000000000..7ddfe36084a --- /dev/null +++ b/intern/ghost/intern/GHOST_EventDragnDrop.h @@ -0,0 +1,131 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Damien Plisson 11/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventDragnDrop.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_EVENT_DRAGNDROP_H_ +#define _GHOST_EVENT_DRAGNDROP_H_ + +#include "GHOST_Event.h" +extern "C" { +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +}; + +/** + * Drag & drop event + * + * The dragging sequence is performed in four phases: + * + *
  • Start sequence (GHOST_kEventDraggingEntered) that tells a drag'n'drop operation has started. Already gives the object data type, + * and the entering mouse location + * + *
  • Update mouse position (GHOST_kEventDraggingUpdated) sent upon each mouse move until the drag'n'drop operation stops, to give the updated mouse position. + * Useful to highlight a potential destination, and update the status (through GHOST_setAcceptDragOperation) telling if the object can be dropped at + * the current cursor position. + * + *
  • Abort drag'n'drop sequence (GHOST_kEventDraggingExited) sent when the user moved the mouse outside the window. + * + *
  • Send the dropped data (GHOST_kEventDraggingDropDone) + * + *
  • Outside of the normal sequence, dropped data can be sent (GHOST_kEventDraggingDropOnIcon). This can happen when the user drops an object + * on the application icon. (Also used in OSX to pass the filename of the document the user doubled-clicked in the finder) + * + *

    Note that the mouse positions are given in Blender coordinates (y=0 at bottom) + * + *
    Currently supported object types : + *
  • UTF-8 string + *
  • array of strings representing filenames (GHOST_TStringArray) + *
  • bitmap ImBuf + */ +class GHOST_EventDragnDrop : public GHOST_Event +{ +public: + /** + * Constructor. + * @param time The time this event was generated. + * @param type The type of this event. + * @param dataType The type of the drop candidate object + * @param window The window where the event occurred + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + * @param data The "content" dropped in the window + */ + GHOST_EventDragnDrop(GHOST_TUns64 time, GHOST_TEventType type, GHOST_TDragnDropTypes dataType, GHOST_IWindow* window, + int x, int y, GHOST_TEventDataPtr data) + : GHOST_Event(time, type, window) + { + m_dragnDropEventData.x = x; + m_dragnDropEventData.y = y; + m_dragnDropEventData.dataType = dataType; + m_dragnDropEventData.data = data; + m_data = &m_dragnDropEventData; + } + + ~GHOST_EventDragnDrop() + { + //Free the dropped object data + if (m_dragnDropEventData.data == NULL) + return; + + switch (m_dragnDropEventData.dataType) { + case GHOST_kDragnDropTypeBitmap: + IMB_freeImBuf((ImBuf*)m_dragnDropEventData.data); + break; + case GHOST_kDragnDropTypeFilenames: + { + GHOST_TStringArray *strArray = (GHOST_TStringArray*)m_dragnDropEventData.data; + int i; + + for (i=0;icount;i++) + free(strArray->strings[i]); + + free(strArray); + } + break; + case GHOST_kDragnDropTypeString: + free(m_dragnDropEventData.data); + break; + + default: + break; + } + } + + + +protected: + /** The x,y-coordinates of the cursor position. */ + GHOST_TEventDragnDropData m_dragnDropEventData; +}; + +#endif // _GHOST_EVENT_DRAGNDROP_H_ + diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h new file mode 100644 index 00000000000..3581cd86b20 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventKey.h @@ -0,0 +1,82 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventKey.h + * \ingroup GHOST + * Declaration of GHOST_EventKey class. + */ + +#ifndef _GHOST_EVENT_KEY_H_ +#define _GHOST_EVENT_KEY_H_ + +#include "GHOST_Event.h" + +/** + * Key event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventKey : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = '\0'; + m_data = &m_keyEventData; + } + + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + * @param ascii The ascii code for the key event. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key, char ascii) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = ascii; + m_data = &m_keyEventData; + } + +protected: + /** The key event data. */ + GHOST_TEventKeyData m_keyEventData; +}; + +#endif // _GHOST_EVENT_KEY_H_ + diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp new file mode 100644 index 00000000000..1483555c362 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -0,0 +1,268 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventManager.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 14, 2001 + */ + +#include "GHOST_EventManager.h" +#include +#include "GHOST_Debug.h" + + +GHOST_EventManager::GHOST_EventManager() +{ +} + + +GHOST_EventManager::~GHOST_EventManager() +{ + disposeEvents(); + + TConsumerVector::iterator iter= m_consumers.begin(); + while (iter != m_consumers.end()) + { + GHOST_IEventConsumer* consumer = *iter; + delete consumer; + m_consumers.erase(iter); + iter = m_consumers.begin(); + } +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents() +{ + return (GHOST_TUns32) m_events.size(); +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents(GHOST_TEventType type) +{ + GHOST_TUns32 numEvents = 0; + TEventStack::iterator p; + for (p = m_events.begin(); p != m_events.end(); p++) { + if ((*p)->getType() == type) { + numEvents++; + } + } + return numEvents; +} + + +GHOST_IEvent* GHOST_EventManager::peekEvent() +{ + GHOST_IEvent* event = 0; + if (m_events.size() > 0) { + event = m_events.back(); + } + return event; +} + + +GHOST_TSuccess GHOST_EventManager::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + GHOST_ASSERT(event, "invalid event"); + if (m_events.size() < m_events.max_size()) { + m_events.push_front(event); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_EventManager::dispatchEvent(GHOST_IEvent* event) +{ + bool handled; + if (event) { + handled = true; + TConsumerVector::iterator iter; + for (iter = m_consumers.begin(); iter != m_consumers.end(); iter++) { + if ((*iter)->processEvent(event)) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvent() +{ + GHOST_IEvent* event = popEvent(); + bool handled = false; + if (event) { + handled = dispatchEvent(event); + delete event; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvents() +{ + bool handled; + if (getNumEvents()) { + handled = true; + while (getNumEvents()) { + if (!dispatchEvent()) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is already in our list + TConsumerVector::const_iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter == m_consumers.end()) { + // Add the consumer + m_consumers.push_back(consumer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_EventManager::removeConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is in our list + TConsumerVector::iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter != m_consumers.end()) { + // Remove the consumer + m_consumers.erase(iter); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +void GHOST_EventManager::removeWindowEvents(GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if (event->getWindow() == window) + { + GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n"); + /* + * Found an event for this window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + +void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if ((event->getType() == type) && (!window || (event->getWindow() == window))) + { + GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n"); + /* + * Found an event of this type for the window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + + +GHOST_IEvent* GHOST_EventManager::popEvent() +{ + GHOST_IEvent* event = peekEvent(); + if (event) { + m_events.pop_back(); + } + return event; +} + + +void GHOST_EventManager::disposeEvents() +{ + while (m_events.size() > 0) { + GHOST_ASSERT(m_events[0], "invalid event"); + delete m_events[0]; + m_events.pop_front(); + } +} diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h new file mode 100644 index 00000000000..9e68a13fd74 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.h @@ -0,0 +1,175 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventManager.h + * \ingroup GHOST + * Declaration of GHOST_EventManager class. + */ + +#ifndef _GHOST_EVENT_MANAGER_H_ +#define _GHOST_EVENT_MANAGER_H_ + +#include +#include + +#include "GHOST_IEventConsumer.h" + + +/** + * Manages an event stack and a list of event consumers. + * The stack works on a FIFO (First In First Out) basis. + * Events are pushed on the front of the stack and retrieved from the back. + * Ownership of the event is transferred to the event manager as soon as an event is pushed. + * Ownership of the event is transferred from the event manager as soon as an event is popped. + * Events can be dispatched to the event consumers. + */ +class GHOST_EventManager +{ +public: + /** + * Constructor. + */ + GHOST_EventManager(); + + /** + * Destructor. + */ + virtual ~GHOST_EventManager(); + + /** + * Returns the number of events currently on the stack. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumEvents(); + + /** + * Returns the number of events of a certain type currently on the stack. + * @param type The type of events to be counted. + * @return The number of events on the stack of this type. + */ + virtual GHOST_TUns32 getNumEvents(GHOST_TEventType type); + + /** + * Return the event at the top of the stack without removal. + * Do not delete the event! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* peekEvent(); + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Dispatches the given event directly, bypassing the event stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(GHOST_IEvent* event); + + /** + * Dispatches the event at the back of the stack. + * The event will be removed from the stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(); + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds a consumer to the list of event consumers. + * @param consumer The consumer added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes a consumer from the list of event consumers. + * @param consumer The consumer removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes all events for a window from the stack. + * @param window The window to remove events for. + */ + virtual void + removeWindowEvents( + GHOST_IWindow* window + ); + + /** + * Removes all events of a certain type from the stack. + * The window parameter is optional. If non-null, the routine will remove + * events only associated with that window. + * @param type The type of events to be removed. + * @param window The window to remove the events for. + */ + virtual void + removeTypeEvents( + GHOST_TEventType type, + GHOST_IWindow* window = 0 + ); + +protected: + /** + * Returns the event at the top of the stack and removes it. + * Delete the event after use! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* popEvent(); + + /** + * Removes all events from the stack. + */ + virtual void disposeEvents(); + + /** A stack with events. */ + typedef std::deque TEventStack; + + /** The event stack. */ + std::deque m_events; + + /** A vector with event consumers. */ + typedef std::vector TConsumerVector; + + /** The list with event consumers. */ + TConsumerVector m_consumers; +}; + +#endif // _GHOST_EVENT_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h new file mode 100644 index 00000000000..70861b08fc6 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventNDOF.h @@ -0,0 +1,62 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventNDOF.h + * \ingroup GHOST + */ + + + +#ifndef _GHOST_EVENT_NDOF_H_ +#define _GHOST_EVENT_NDOF_H_ + +#include "GHOST_Event.h" + +/** + * N-degree of freedom device event. + */ +class GHOST_EventNDOF : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + */ + GHOST_EventNDOF(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, + GHOST_TEventNDOFData data) + : GHOST_Event(msec, type, window) + { + m_ndofEventData = data; + m_data = &m_ndofEventData; + } + +protected: + /** translation & rotation from the device. */ + GHOST_TEventNDOFData m_ndofEventData; +}; + + +#endif // _GHOST_EVENT_NDOF_H_ + diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp new file mode 100644 index 00000000000..139c4beb412 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -0,0 +1,347 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventPrinter.cpp + * \ingroup GHOST + * Declaration of GHOST_EventPrinter class. + */ + +#include "GHOST_EventPrinter.h" +#include +#include "GHOST_EventKey.h" +#include "GHOST_EventDragnDrop.h" +#include "GHOST_Debug.h" + + +bool GHOST_EventPrinter::processEvent(GHOST_IEvent* event) +{ + bool handled = true; + + GHOST_ASSERT(event, "event==0"); + + if (event->getType() == GHOST_kEventWindowUpdate) return false; + + std::cout << "\nGHOST_EventPrinter::processEvent, time: " << (GHOST_TInt32)event->getTime() << ", type: "; + switch (event->getType()) { + case GHOST_kEventUnknown: + std::cout << "GHOST_kEventUnknown"; handled = false; + break; + + case GHOST_kEventButtonUp: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventCursorButtonUp, button: " << buttonData->button; + } + break; + case GHOST_kEventButtonDown: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventButtonDown, button: " << buttonData->button; + } + break; + + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventWheel, z: " << wheelData->z; + } + break; + + case GHOST_kEventCursorMove: + { + GHOST_TEventCursorData* cursorData = (GHOST_TEventCursorData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventCursorMove, (x,y): (" << cursorData->x << "," << cursorData->y << ")"; + } + break; + + case GHOST_kEventKeyUp: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + std::cout << "GHOST_kEventKeyUp, key: " << str.Ptr(); + } + break; + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + std::cout << "GHOST_kEventKeyDown, key: " << str.Ptr(); + } + break; + + case GHOST_kEventDraggingEntered: + { + GHOST_TEventDragnDropData* dragnDropData = (GHOST_TEventDragnDropData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventDraggingEntered, dragged object type : " << dragnDropData->dataType; + std::cout << " mouse at x=" << dragnDropData->x << " y=" << dragnDropData->y; + } + break; + + case GHOST_kEventDraggingUpdated: + { + GHOST_TEventDragnDropData* dragnDropData = (GHOST_TEventDragnDropData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventDraggingUpdated, dragged object type : " << dragnDropData->dataType; + std::cout << " mouse at x=" << dragnDropData->x << " y=" << dragnDropData->y; + } + break; + + case GHOST_kEventDraggingExited: + { + GHOST_TEventDragnDropData* dragnDropData = (GHOST_TEventDragnDropData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventDraggingExited, dragged object type : " << dragnDropData->dataType; + } + break; + + case GHOST_kEventDraggingDropDone: + { + GHOST_TEventDragnDropData* dragnDropData = (GHOST_TEventDragnDropData*)((GHOST_IEvent*)event)->getData(); + std::cout << "GHOST_kEventDraggingDropDone,"; + std::cout << " mouse at x=" << dragnDropData->x << " y=" << dragnDropData->y; + switch (dragnDropData->dataType) { + case GHOST_kDragnDropTypeString: + std::cout << " type : GHOST_kDragnDropTypeString,"; + std::cout << "\n String received = " << (char*)dragnDropData->data; + break; + case GHOST_kDragnDropTypeFilenames: + { + GHOST_TStringArray *strArray = (GHOST_TStringArray*)dragnDropData->data; + int i; + std::cout << " type : GHOST_kDragnDropTypeFilenames,"; + std::cout << "\n Received " << strArray->count << " filename" << (strArray->count > 1 ? "s:" : ":"); + for (i=0;icount;i++) + std::cout << "\n File[" << i << "] : " << strArray->strings[i]; + } + break; + default: + break; + } + } + break; + + case GHOST_kEventOpenMainFile: + { + GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData(); + + if (eventData) + std::cout << "GHOST_kEventOpenMainFile for path : " << (char*)eventData; + else + std::cout << "GHOST_kEventOpenMainFile with no path specified!!"; + } + break; + + case GHOST_kEventQuit: + std::cout << "GHOST_kEventQuit"; + break; + case GHOST_kEventWindowClose: + std::cout << "GHOST_kEventWindowClose"; + break; + case GHOST_kEventWindowActivate: + std::cout << "GHOST_kEventWindowActivate"; + break; + case GHOST_kEventWindowDeactivate: + std::cout << "GHOST_kEventWindowDeactivate"; + break; + case GHOST_kEventWindowUpdate: + std::cout << "GHOST_kEventWindowUpdate"; + break; + case GHOST_kEventWindowSize: + std::cout << "GHOST_kEventWindowSize"; + break; + + default: + std::cout << "not found"; handled = false; + break; + } + return handled; +} + + +void GHOST_EventPrinter::getKeyString(GHOST_TKey key, STR_String& str) const +{ + if ((key >= GHOST_kKeyComma) && (key <= GHOST_kKeyRightBracket)) { + str = ((char)key); + } else if ((key >= GHOST_kKeyNumpad0) && (key <= GHOST_kKeyNumpad9)) { + int number = key - GHOST_kKeyNumpad0; + STR_String numberStr (number); + str = "Numpad"; + str += numberStr; +#if defined(__sun__) || defined(__sun) + } else if (key == 268828432) { /* solaris keyboards are messed up */ + /* This should really test XK_F11 but that doesn't work */ + str = "F11"; + } else if (key == 268828433) { /* solaris keyboards are messed up */ + /* This should really test XK_F12 but that doesn't work */ + str = "F12"; +#endif + } else if ((key >= GHOST_kKeyF1) && (key <= GHOST_kKeyF24)) { + int number = key - GHOST_kKeyF1 + 1; + STR_String numberStr (number); + str = "F"; + str += numberStr; + } else { + switch (key) + { + case GHOST_kKeyBackSpace: + str = "BackSpace"; + break; + case GHOST_kKeyTab: + str = "Tab"; + break; + case GHOST_kKeyLinefeed: + str = "Linefeed"; + break; + case GHOST_kKeyClear: + str = "Clear"; + break; + case GHOST_kKeyEnter: + str = "Enter"; + break; + case GHOST_kKeyEsc: + str = "Esc"; + break; + case GHOST_kKeySpace: + str = "Space"; + break; + case GHOST_kKeyQuote: + str = "Quote"; + break; + case GHOST_kKeyBackslash: + str = "\\"; + break; + case GHOST_kKeyAccentGrave: + str = "`"; + break; + case GHOST_kKeyLeftShift: + str = "LeftShift"; + break; + case GHOST_kKeyRightShift: + str = "RightShift"; + break; + case GHOST_kKeyLeftControl: + str = "LeftControl"; + break; + case GHOST_kKeyRightControl: + str = "RightControl"; + break; + case GHOST_kKeyLeftAlt: + str = "LeftAlt"; + break; + case GHOST_kKeyRightAlt: + str = "RightAlt"; + break; + case GHOST_kKeyOS: + str = "OS"; + break; + case GHOST_kKeyGrLess: + // PC german! + str = "GrLess"; + break; + case GHOST_kKeyCapsLock: + str = "CapsLock"; + break; + case GHOST_kKeyNumLock: + str = "NumLock"; + break; + case GHOST_kKeyScrollLock: + str = "ScrollLock"; + break; + case GHOST_kKeyLeftArrow: + str = "LeftArrow"; + break; + case GHOST_kKeyRightArrow: + str = "RightArrow"; + break; + case GHOST_kKeyUpArrow: + str = "UpArrow"; + break; + case GHOST_kKeyDownArrow: + str = "DownArrow"; + break; + case GHOST_kKeyPrintScreen: + str = "PrintScreen"; + break; + case GHOST_kKeyPause: + str = "Pause"; + break; + case GHOST_kKeyInsert: + str = "Insert"; + break; + case GHOST_kKeyDelete: + str = "Delete"; + break; + case GHOST_kKeyHome: + str = "Home"; + break; + case GHOST_kKeyEnd: + str = "End"; + break; + case GHOST_kKeyUpPage: + str = "UpPage"; + break; + case GHOST_kKeyDownPage: + str = "DownPage"; + break; + case GHOST_kKeyNumpadPeriod: + str = "NumpadPeriod"; + break; + case GHOST_kKeyNumpadEnter: + str = "NumpadEnter"; + break; + case GHOST_kKeyNumpadPlus: + str = "NumpadPlus"; + break; + case GHOST_kKeyNumpadMinus: + str = "NumpadMinus"; + break; + case GHOST_kKeyNumpadAsterisk: + str = "NumpadAsterisk"; + break; + case GHOST_kKeyNumpadSlash: + str = "NumpadSlash"; + break; + case GHOST_kKeyMediaPlay: + str = "MediaPlayPause"; + break; + case GHOST_kKeyMediaStop: + str = "MediaStop"; + break; + case GHOST_kKeyMediaFirst: + str = "MediaFirst"; + break; + case GHOST_kKeyMediaLast: + str = "MediaLast"; + break; + default: + str = "unknown"; + break; + } + } +} + diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h new file mode 100644 index 00000000000..74c379e76a8 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.h @@ -0,0 +1,65 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventPrinter.h + * \ingroup GHOST + * Declaration of GHOST_EventPrinter class. + */ + +#ifndef _GHOST_EVENT_PRINTER_H_ +#define _GHOST_EVENT_PRINTER_H_ + +#include "GHOST_IEventConsumer.h" + +#include "STR_String.h" + +/** + * An Event consumer that prints all the events to standard out. + * Really useful when debugging. + */ +class GHOST_EventPrinter : public GHOST_IEventConsumer +{ +public: + /** + * Prints all the events received to std out. + * @param event The event that can be handled or not. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** + * Converts GHOST key code to a readable string. + * @param key The GHOST key code to convert. + * @param str The GHOST key code converted to a readable string. + */ + void getKeyString(GHOST_TKey key, STR_String& str) const; +}; + +#endif // _GHOST_EVENT_PRINTER_H_ + diff --git a/intern/ghost/intern/GHOST_EventString.h b/intern/ghost/intern/GHOST_EventString.h new file mode 100644 index 00000000000..e5fe50d0b9b --- /dev/null +++ b/intern/ghost/intern/GHOST_EventString.h @@ -0,0 +1,67 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventString.h + * \ingroup GHOST + * Declaration of GHOST_EventString class. + */ + +#ifndef _GHOST_EVENTSTRING_H_ +#define _GHOST_EVENTSTRING_H_ + +#include "GHOST_Event.h" + + +/** + * Generic class for events with string data + * @author Damien Plisson + * @date Feb 1, 2010 + */ +class GHOST_EventString : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param window The generating window (or NULL if system event). + * @param data_ptr Pointer to the (unformatted) data associated with the event + */ + GHOST_EventString(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TEventDataPtr data_ptr) + : GHOST_Event(msec, type, window) { + m_data = data_ptr; + } + + ~GHOST_EventString() + { + if (m_data) free(m_data); + } +}; + +#endif // _GHOST_EVENTSTRING_H_ + diff --git a/intern/ghost/intern/GHOST_EventTrackpad.h b/intern/ghost/intern/GHOST_EventTrackpad.h new file mode 100644 index 00000000000..12ce6babb1d --- /dev/null +++ b/intern/ghost/intern/GHOST_EventTrackpad.h @@ -0,0 +1,72 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): James Deery 11/2009 + * Damien Plisson 12/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventTrackpad.h + * \ingroup GHOST + * Declaration of GHOST_EventTrackpad class. + */ + +#ifndef _GHOST_EVENT_TRACKPAD_H_ +#define _GHOST_EVENT_TRACKPAD_H_ + +#include "GHOST_Event.h" + +/** + * Trackpad (scroll, magnify, rotate, ...) event. + */ +class GHOST_EventTrackpad : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param subtype The subtype of the event. + * @param x The x-delta of the pan event. + * @param y The y-delta of the pan event. + */ + GHOST_EventTrackpad(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TTrackpadEventSubTypes subtype, GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 deltaX, GHOST_TInt32 deltaY) + : GHOST_Event(msec, GHOST_kEventTrackpad, window) + { + m_trackpadEventData.subtype = subtype; + m_trackpadEventData.x = x; + m_trackpadEventData.y = y; + m_trackpadEventData.deltaX = deltaX; + m_trackpadEventData.deltaY = deltaY; + m_data = &m_trackpadEventData; + } + +protected: + /** The mouse pan data */ + GHOST_TEventTrackpadData m_trackpadEventData; +}; + + +#endif // _GHOST_EVENT_PAN_H_ + diff --git a/intern/ghost/intern/GHOST_EventWheel.h b/intern/ghost/intern/GHOST_EventWheel.h new file mode 100644 index 00000000000..1be5de721fd --- /dev/null +++ b/intern/ghost/intern/GHOST_EventWheel.h @@ -0,0 +1,69 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_EventWheel.h + * \ingroup GHOSTeel.h + * Declaration of GHOST_EventWheel class. + */ + +#ifndef _GHOST_EVENT_WHEEL_H_ +#define _GHOST_EVENT_WHEEL_H_ + +#include "GHOST_Event.h" + +/** + * Mouse wheel event. + * The displacement of the mouse wheel is counted in ticks. + * A positive value means the wheel is turned away from the user. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventWheel : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param z The displacement of the mouse wheel. + */ + GHOST_EventWheel(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TInt32 z) + : GHOST_Event(msec, GHOST_kEventWheel, window) + { + m_wheelEventData.z = z; + m_data = &m_wheelEventData; + } + +protected: + /** The z-displacement of the mouse wheel. */ + GHOST_TEventWheelData m_wheelEventData; +}; + + +#endif // _GHOST_EVENT_WHEEL_H_ + diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp new file mode 100644 index 00000000000..040164e2c40 --- /dev/null +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -0,0 +1,108 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ISystem.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#include "GHOST_ISystem.h" + +#ifdef WIN32 +# include "GHOST_SystemWin32.h" +#else +# ifdef __APPLE__ +# ifdef GHOST_COCOA +# include "GHOST_SystemCocoa.h" +# else +# include "GHOST_SystemCarbon.h" +# endif +# else +# include "GHOST_SystemX11.h" +# endif +#endif + + +GHOST_ISystem* GHOST_ISystem::m_system = 0; + + +GHOST_TSuccess GHOST_ISystem::createSystem() +{ + GHOST_TSuccess success; + if (!m_system) { +#ifdef WIN32 + m_system = new GHOST_SystemWin32 (); +#else +# ifdef __APPLE__ +# ifdef GHOST_COCOA + m_system = new GHOST_SystemCocoa (); +# else + m_system = new GHOST_SystemCarbon (); +# endif +# else + m_system = new GHOST_SystemX11 (); +# endif +#endif + success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + if (success) { + success = m_system->init(); + } + return success; +} + +GHOST_TSuccess GHOST_ISystem::disposeSystem() +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (m_system) { + delete m_system; + m_system = 0; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_ISystem* GHOST_ISystem::getSystem() +{ + return m_system; +} + diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp new file mode 100644 index 00000000000..8873398a320 --- /dev/null +++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp @@ -0,0 +1,109 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ISystemPaths.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#include "GHOST_ISystemPaths.h" + +#ifdef WIN32 +# include "GHOST_SystemPathsWin32.h" +#else +# ifdef __APPLE__ +# ifdef GHOST_COCOA +# include "GHOST_SystemPathsCocoa.h" +# else +# include "GHOST_SystemPathsCarbon.h" +# endif +# else +# include "GHOST_SystemPathsX11.h" +# endif +#endif + + +GHOST_ISystemPaths* GHOST_ISystemPaths::m_systemPaths = 0; + + +GHOST_TSuccess GHOST_ISystemPaths::create() +{ + GHOST_TSuccess success; + if (!m_systemPaths) { +#ifdef WIN32 + m_systemPaths = new GHOST_SystemPathsWin32 (); +#else +# ifdef __APPLE__ +# ifdef GHOST_COCOA + m_systemPaths = new GHOST_SystemPathsCocoa (); +# else + m_systemPaths = new GHOST_SystemPathsarbon (); +# endif +# else + m_systemPaths = new GHOST_SystemPathsX11 (); +# endif +#endif + success = m_systemPaths != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TSuccess GHOST_ISystemPaths::dispose() +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (m_systemPaths) { + delete m_systemPaths; + m_systemPaths = 0; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_ISystemPaths* GHOST_ISystemPaths::get() +{ + if (!m_systemPaths) { + create(); + } + return m_systemPaths; +} + + + diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp new file mode 100644 index 00000000000..e8f03180e54 --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp @@ -0,0 +1,140 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ModifierKeys.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#include "GHOST_ModifierKeys.h" + + +GHOST_ModifierKeys::GHOST_ModifierKeys() +{ + clear(); +} + +GHOST_ModifierKeys::~GHOST_ModifierKeys() {} + + +GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask) +{ + GHOST_TKey key; + switch (mask) { + case GHOST_kModifierKeyLeftShift: key = GHOST_kKeyLeftShift; break; + case GHOST_kModifierKeyRightShift: key = GHOST_kKeyRightShift; break; + case GHOST_kModifierKeyLeftAlt: key = GHOST_kKeyLeftAlt; break; + case GHOST_kModifierKeyRightAlt: key = GHOST_kKeyRightAlt; break; + case GHOST_kModifierKeyLeftControl: key = GHOST_kKeyLeftControl; break; + case GHOST_kModifierKeyRightControl: key = GHOST_kKeyRightControl; break; + case GHOST_kModifierKeyOS: key = GHOST_kKeyOS; break; + default: + // Should not happen + key = GHOST_kKeyUnknown; + break; + } + return key; +} + + +bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + return m_LeftShift; + case GHOST_kModifierKeyRightShift: + return m_RightShift; + case GHOST_kModifierKeyLeftAlt: + return m_LeftAlt; + case GHOST_kModifierKeyRightAlt: + return m_RightAlt; + case GHOST_kModifierKeyLeftControl: + return m_LeftControl; + case GHOST_kModifierKeyRightControl: + return m_RightControl; + case GHOST_kModifierKeyOS: + return m_OS; + default: + return false; + } +} + + +void GHOST_ModifierKeys::set(GHOST_TModifierKeyMask mask, bool down) +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + m_LeftShift = down; break; + case GHOST_kModifierKeyRightShift: + m_RightShift = down; break; + case GHOST_kModifierKeyLeftAlt: + m_LeftAlt = down; break; + case GHOST_kModifierKeyRightAlt: + m_RightAlt = down; break; + case GHOST_kModifierKeyLeftControl: + m_LeftControl = down; break; + case GHOST_kModifierKeyRightControl: + m_RightControl = down; break; + case GHOST_kModifierKeyOS: + m_OS = down; break; + default: + break; + } +} + + +void GHOST_ModifierKeys::clear() +{ + m_LeftShift = false; + m_RightShift = false; + m_LeftAlt = false; + m_RightAlt = false; + m_LeftControl = false; + m_RightControl = false; + m_OS = false; +} + + +bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys& keys) const +{ + return (m_LeftShift == keys.m_LeftShift) && + (m_RightShift == keys.m_RightShift) && + (m_LeftAlt == keys.m_LeftAlt) && + (m_RightAlt == keys.m_RightAlt) && + (m_LeftControl == keys.m_LeftControl) && + (m_RightControl == keys.m_RightControl) && + (m_OS == keys.m_OS); +} diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h new file mode 100644 index 00000000000..08fe277d55a --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.h @@ -0,0 +1,105 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ModifierKeys.h + * \ingroup GHOST + * Declaration of GHOST_ModifierKeys struct. + */ + +#ifndef _GHOST_MODIFIER_KEYS_H_ +#define _GHOST_MODIFIER_KEYS_H_ + +#include "GHOST_Types.h" + +/** + * Stores the state of modifier keys. + * Discriminates between left and right modifier keys. + * @author Maarten Gribnau + * @date May 17, 2001 + */ +struct GHOST_ModifierKeys +{ + /** + * Constructor. + */ + GHOST_ModifierKeys(); + + virtual ~GHOST_ModifierKeys(); + + /** + * Returns the modifier key's key code from a modifier key mask. + * @param mask The mask of the modifier key. + * @return The modifier key's key code. + */ + static GHOST_TKey getModifierKeyCode(GHOST_TModifierKeyMask mask); + + + /** + * Returns the state of a single modifier key. + * @param mask. Key state to return. + * @return The state of the key (pressed == true). + */ + virtual bool get(GHOST_TModifierKeyMask mask) const; + + /** + * Updates the state of a single modifier key. + * @param mask. Key state to update. + * @param down. The new state of the key. + */ + virtual void set(GHOST_TModifierKeyMask mask, bool down); + + /** + * Sets the state of all modifier keys to up. + */ + virtual void clear(); + + /** + * Determines whether to modifier key states are equal. + * @param keys. The modifier key state to compare to. + * @return Indication of equality. + */ + virtual bool equals(const GHOST_ModifierKeys& keys) const; + + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftControl : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightControl : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_OS : 1; +}; + +#endif // _GHOST_MODIFIER_KEYS_H_ + diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp new file mode 100644 index 00000000000..95626ec26ea --- /dev/null +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -0,0 +1,132 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_NDOFManager.cpp + * \ingroup GHOST + */ + + +#include /* just for printf */ + +#include "GHOST_NDOFManager.h" + + +// the variable is outside the class because it must be accessed from plugin +static volatile GHOST_TEventNDOFData currentNdofValues = {0,0,0,0,0,0,0,0,0,0,0}; + +#if !defined(_WIN32) && !defined(__APPLE__) +#include "GHOST_SystemX11.h" +#endif + +namespace +{ + GHOST_NDOFLibraryInit_fp ndofLibraryInit = 0; + GHOST_NDOFLibraryShutdown_fp ndofLibraryShutdown = 0; + GHOST_NDOFDeviceOpen_fp ndofDeviceOpen = 0; +} + +GHOST_NDOFManager::GHOST_NDOFManager() +{ + m_DeviceHandle = 0; + + // discover the API from the plugin + ndofLibraryInit = 0; + ndofLibraryShutdown = 0; + ndofDeviceOpen = 0; +} + +GHOST_NDOFManager::~GHOST_NDOFManager() +{ + if (ndofLibraryShutdown) + ndofLibraryShutdown(m_DeviceHandle); + + m_DeviceHandle = 0; +} + + +int +GHOST_NDOFManager::deviceOpen(GHOST_IWindow* window, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen) +{ + int Pid; + + ndofLibraryInit = setNdofLibraryInit; + ndofLibraryShutdown = setNdofLibraryShutdown; + ndofDeviceOpen = setNdofDeviceOpen; + + if (ndofLibraryInit && ndofDeviceOpen) + { + Pid= ndofLibraryInit(); +#if 0 + printf("%i client \n", Pid); +#endif + #if defined(_WIN32) || defined(__APPLE__) + m_DeviceHandle = ndofDeviceOpen((void *)¤tNdofValues); + #else + GHOST_SystemX11 *sys; + sys = static_cast(GHOST_ISystem::getSystem()); + void *ndofInfo = sys->prepareNdofInfo(¤tNdofValues); + m_DeviceHandle = ndofDeviceOpen(ndofInfo); + #endif + return (Pid > 0) ? 0 : 1; + + } else + return 1; +} + + +bool +GHOST_NDOFManager::available() const +{ + return m_DeviceHandle != 0; +} + +bool +GHOST_NDOFManager::event_present() const +{ + if( currentNdofValues.changed >0) { + printf("time %llu but%u x%i y%i z%i rx%i ry%i rz%i \n" , + currentNdofValues.time, currentNdofValues.buttons, + currentNdofValues.tx,currentNdofValues.ty,currentNdofValues.tz, + currentNdofValues.rx,currentNdofValues.ry,currentNdofValues.rz); + return true; + }else + return false; + +} + +void GHOST_NDOFManager::GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const +{ + datas.tx = currentNdofValues.tx; + datas.ty = currentNdofValues.ty; + datas.tz = currentNdofValues.tz; + datas.rx = currentNdofValues.rx; + datas.ry = currentNdofValues.ry; + datas.rz = currentNdofValues.rz; + datas.buttons = currentNdofValues.buttons; + datas.client = currentNdofValues.client; + datas.address = currentNdofValues.address; + datas.time = currentNdofValues.time; + datas.delta = currentNdofValues.delta; +} diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h new file mode 100644 index 00000000000..c9e09370e09 --- /dev/null +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -0,0 +1,57 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_NDOFManager.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_NDOFMANAGER_H_ +#define _GHOST_NDOFMANAGER_H_ + +#include "GHOST_System.h" +#include "GHOST_IWindow.h" + + + +class GHOST_NDOFManager +{ +public: + GHOST_NDOFManager(); + virtual ~GHOST_NDOFManager(); + + int deviceOpen(GHOST_IWindow* window, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen); + + void GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const; + + bool available() const; + bool event_present() const; + +protected: + void* m_DeviceHandle; +}; + + +#endif diff --git a/intern/ghost/intern/GHOST_Path-api.cpp b/intern/ghost/intern/GHOST_Path-api.cpp new file mode 100644 index 00000000000..dee66029d19 --- /dev/null +++ b/intern/ghost/intern/GHOST_Path-api.cpp @@ -0,0 +1,74 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Path-api.cpp + * \ingroup GHOST + */ + + +#include "intern/GHOST_Debug.h" +#include "GHOST_Types.h" +#include "GHOST_Path-api.h" +#include "GHOST_ISystemPaths.h" + +GHOST_TSuccess GHOST_CreateSystemPaths(void) +{ + return GHOST_ISystemPaths::create();; +} + +GHOST_TSuccess GHOST_DisposeSystemPaths(void) +{ + return GHOST_ISystemPaths::dispose(); +} + +const GHOST_TUns8* GHOST_getSystemDir() +{ + GHOST_ISystemPaths* systemPaths = GHOST_ISystemPaths::get(); + return systemPaths ? systemPaths->getSystemDir() : 0; +} + +const GHOST_TUns8* GHOST_getUserDir() +{ + GHOST_ISystemPaths* systemPaths = GHOST_ISystemPaths::get(); + return systemPaths ? systemPaths->getUserDir() : 0; /* shouldn't be NULL */ +} + +const GHOST_TUns8* GHOST_getBinaryDir() +{ + GHOST_ISystemPaths* systemPaths = GHOST_ISystemPaths::get(); + return systemPaths ? systemPaths->getBinaryDir() : 0; /* shouldn't be NULL */ +} + +void GHOST_addToSystemRecentFiles(const char* filename) +{ + GHOST_ISystemPaths* systemPaths = GHOST_ISystemPaths::get(); + if (systemPaths) { + systemPaths->addToSystemRecentFiles(filename); + } +} diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp new file mode 100644 index 00000000000..606247814ec --- /dev/null +++ b/intern/ghost/intern/GHOST_Rect.cpp @@ -0,0 +1,142 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Rect.cpp + * \ingroup GHOST + */ + + +#include "GHOST_Rect.h" + + + +void GHOST_Rect::inset(GHOST_TInt32 i) +{ + if (i > 0) { + // Grow the rectangle + m_l -= i; + m_r += i; + m_t -= i; + m_b += i; + } + else if (i < 0) { + // Shrink the rectangle, check for insets larger than half the size + GHOST_TInt32 i2 = i * 2; + if (getWidth() > i2) { + m_l += i; + m_r -= i; + } + else { + m_l = m_l + ((m_r - m_l) / 2); + m_r = m_l; + } + if (getHeight() > i2) { + m_t += i; + m_b -= i; + } + else { + m_t = m_t + ((m_b - m_t) / 2); + m_b = m_t; + } + } +} + + +GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect& r) const +{ + bool lt = isInside(r.m_l, r.m_t); + bool rt = isInside(r.m_r, r.m_t); + bool lb = isInside(r.m_l, r.m_b); + bool rb = isInside(r.m_r, r.m_b); + GHOST_TVisibility v; + if (lt && rt && lb && rb) { + // All points inside, rectangle is inside this + v = GHOST_kFullyVisible; + } + else if (!(lt || rt || lb || rb)) { + // None of the points inside + // Check to see whether the rectangle is larger than this one + if ((r.m_l < m_l) && (r.m_t < m_t) && (r.m_r > m_r) && (r.m_b > m_b)) { + v = GHOST_kPartiallyVisible; + } + else { + v = GHOST_kNotVisible; + } + } + else { + // Some of the points inside, rectangle is partially inside + v = GHOST_kPartiallyVisible; + } + return v; +} + + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy) +{ + GHOST_TInt32 offset = cx - (m_l + (m_r - m_l)/2); + m_l += offset; + m_r += offset; + offset = cy - (m_t + (m_b - m_t)/2); + m_t += offset; + m_b += offset; +} + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h) +{ + long w_2, h_2; + + w_2 = w >> 1; + h_2 = h >> 1; + m_l = cx - w_2; + m_t = cy - h_2; + m_r = m_l + w; + m_b = m_t + h; +} + +bool GHOST_Rect::clip(GHOST_Rect& r) const +{ + bool clipped = false; + if (r.m_l < m_l) { + r.m_l = m_l; + clipped = true; + } + if (r.m_t < m_t) { + r.m_t = m_t; + clipped = true; + } + if (r.m_r > m_r) { + r.m_r = m_r; + clipped = true; + } + if (r.m_b > m_b) { + r.m_b = m_b; + clipped = true; + } + return clipped; +} + diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp new file mode 100644 index 00000000000..cb3e97fc574 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.cpp @@ -0,0 +1,357 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_System.cpp + * \ingroup GHOST + * \author Maarten Gribnau + * \date May 7, 2001 + */ + +#include "GHOST_System.h" + +#include +#include /* just for printf */ + +#include "GHOST_DisplayManager.h" +#include "GHOST_EventManager.h" +#include "GHOST_NDOFManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" + + +GHOST_System::GHOST_System() +: m_displayManager(0), m_timerManager(0), m_windowManager(0), m_eventManager(0), m_ndofManager(0) +{ +} + + +GHOST_System::~GHOST_System() +{ + exit(); +} + + +GHOST_TUns64 GHOST_System::getMilliSeconds() const +{ + GHOST_TUns64 millis = ::clock(); + if (CLOCKS_PER_SEC != 1000) { + millis *= 1000; + millis /= CLOCKS_PER_SEC; + } + return millis; +} + + +GHOST_ITimerTask* GHOST_System::installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData) +{ + GHOST_TUns64 millis = getMilliSeconds(); + GHOST_TimerTask* timer = new GHOST_TimerTask(millis+delay, interval, timerProc, userData); + if (timer) { + if (m_timerManager->addTimer(timer) == GHOST_kSuccess) { + // Check to see whether we need to fire the timer right away + m_timerManager->fireTimers(millis); + } + else { + delete timer; + timer = 0; + } + } + return timer; +} + + +GHOST_TSuccess GHOST_System::removeTimer(GHOST_ITimerTask* timerTask) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (timerTask) { + success = m_timerManager->removeTimer((GHOST_TimerTask*)timerTask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success; + + /* + * Remove all pending events for the window. + */ + if (m_windowManager->getWindowFound(window)) { + m_eventManager->removeWindowEvents(window); + } + if (window == m_windowManager->getFullScreenWindow()) { + success = endFullScreen(); + } + else { + if (m_windowManager->getWindowFound(window)) { + success = m_windowManager->removeWindow(window); + if (success) { + delete window; + } + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +bool GHOST_System::validWindow(GHOST_IWindow* window) +{ + return m_windowManager->getWindowFound(window); +} + + +GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager") + if (m_displayManager) { + if (!m_windowManager->getFullScreen()) { + m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + + //GHOST_PRINT("GHOST_System::beginFullScreen(): activating new display settings\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting); + if (success == GHOST_kSuccess) { + //GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); + success = createFullScreenWindow((GHOST_Window**)window, stereoVisual); + if (success == GHOST_kSuccess) { + m_windowManager->beginFullScreen(*window, stereoVisual); + } + else { + m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + } + } + } + if (success == GHOST_kFailure) { + GHOST_PRINT("GHOST_System::beginFullScreen(): could not enter full-screen mode\n"); + } + return success; +} + + +GHOST_TSuccess GHOST_System::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager") + if (m_windowManager->getFullScreen()) { + //GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving window manager full-screen mode\n"); + success = m_windowManager->endFullScreen(); + GHOST_ASSERT(m_displayManager, "GHOST_System::endFullScreen(): invalid display manager") + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving full-screen mode\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_System::getFullScreen(void) +{ + bool fullScreen; + if (m_windowManager) { + fullScreen = m_windowManager->getFullScreen(); + } + else { + fullScreen = false; + } + return fullScreen; +} + + +bool GHOST_System::dispatchEvents() +{ + bool handled; + if (m_eventManager) { + handled = m_eventManager->dispatchEvents(); + } + else { + handled = false; + } + + m_timerManager->fireTimers(getMilliSeconds()); + return handled; +} + + +GHOST_TSuccess GHOST_System::addEventConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->addConsumer(consumer); + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TSuccess GHOST_System::removeEventConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->removeConsumer(consumer); + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->pushEvent(event); + } + else { + success = GHOST_kFailure; + } + return success; +} + +int GHOST_System::openNDOF(GHOST_IWindow* w, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen) +{ + return m_ndofManager->deviceOpen(w, + setNdofLibraryInit, + setNdofLibraryShutdown, + setNdofDeviceOpen); +} + + +GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const +{ + GHOST_ModifierKeys keys; + // Get the state of all modifier keys + GHOST_TSuccess success = getModifierKeys(keys); + if (success) { + // Isolate the state of the key requested + isDown = keys.get(mask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown) const +{ + GHOST_Buttons buttons; + // Get the state of all mouse buttons + GHOST_TSuccess success = getButtons(buttons); + if (success) { + // Isolate the state of the mouse button requested + isDown = buttons.get(mask); + } + return success; +} + +GHOST_TSuccess GHOST_System::init() +{ + m_timerManager = new GHOST_TimerManager (); + m_windowManager = new GHOST_WindowManager (); + m_eventManager = new GHOST_EventManager (); + m_ndofManager = new GHOST_NDOFManager(); + +#if 0 + if(m_ndofManager) + printf("ndof manager \n"); +#endif + +#ifdef GHOST_DEBUG + if (m_eventManager) { + m_eventPrinter = new GHOST_EventPrinter(); + m_eventManager->addConsumer(m_eventPrinter); + } +#endif // GHOST_DEBUG + + if (m_timerManager && m_windowManager && m_eventManager) { + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_System::exit() +{ + if (getFullScreen()) { + endFullScreen(); + } + if (m_displayManager) { + delete m_displayManager; + m_displayManager = 0; + } + if (m_windowManager) { + delete m_windowManager; + m_windowManager = 0; + } + if (m_timerManager) { + delete m_timerManager; + m_timerManager = 0; + } + if (m_eventManager) { + delete m_eventManager; + m_eventManager = 0; + } + if (m_ndofManager) { + delete m_ndofManager; + m_ndofManager = 0; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window** window, const bool stereoVisual) +{ + GHOST_TSuccess success; + GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager") + GHOST_DisplaySetting settings; + + success = m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, settings); + if (success) { + //GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n"); + *window = (GHOST_Window*)createWindow( + STR_String (""), + 0, 0, settings.xPixels, settings.yPixels, + GHOST_kWindowStateFullScreen, + GHOST_kDrawingContextTypeOpenGL, + stereoVisual); + success = *window == 0 ? GHOST_kFailure : GHOST_kSuccess; + } + return success; +} diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h new file mode 100644 index 00000000000..b5c64bfceb6 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.h @@ -0,0 +1,373 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_System.h + * \ingroup GHOST + * Declaration of GHOST_System class. + */ + +#ifndef _GHOST_SYSTEM_H_ +#define _GHOST_SYSTEM_H_ + +#include "GHOST_ISystem.h" + +#include "GHOST_Debug.h" +#include "GHOST_Buttons.h" +#include "GHOST_ModifierKeys.h" +#include "GHOST_EventManager.h" +#ifdef GHOST_DEBUG +#include "GHOST_EventPrinter.h" +#endif // GHOST_DEBUG + +class GHOST_DisplayManager; +class GHOST_Event; +class GHOST_TimerManager; +class GHOST_Window; +class GHOST_WindowManager; +class GHOST_NDOFManager; + +/** + * Implementation of platform independent functionality of the GHOST_ISystem + * interface. + * GHOST_System is an abstract class because not all methods of GHOST_ISystem + * are implemented. + * @see GHOST_ISystem. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_System : public GHOST_ISystem +{ +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_System(); + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_System(); + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0); + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask); + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual GHOST_TUns8 getNumDisplays() const = 0; + * virtual void getMainDisplayDimensions(...) const = 0; + * virtual GHOST_IWindow* createWindow(..) + */ + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window); + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window); + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * @param stereoVisual Stereo visual for quad buffered stereo. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual); + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void); + + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual bool processEvents(bool waitForEvent) = 0; + */ + + + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer); + + /** + * Remove the given event consumer to our list. + * @param consumer The event consumer to remove. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer); + + /*************************************************************************************** + ** N-degree of freedom devcice management functionality + ***************************************************************************************/ + + /** Inherited from GHOST_ISystem + * Opens the N-degree of freedom device manager + * return 0 if device found, 1 otherwise + */ + virtual int openNDOF(GHOST_IWindow* w, + GHOST_NDOFLibraryInit_fp setNdofLibraryInit, + GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown, + GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen); + +// original patch only +// GHOST_NDOFEventHandler_fp setNdofEventHandler); + + + + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** Inherited from GHOST_ISystem but left pure virtual + * GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + * GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) + */ + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const; + + /*************************************************************************************** + ** Other (internal) functionality. + ***************************************************************************************/ + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Returns the timer manager. + * @return The timer manager. + */ + inline virtual GHOST_TimerManager* getTimerManager() const; + + /** + * Returns a pointer to our event manager. + * @return A pointer to our event manager. + */ + virtual inline GHOST_EventManager* getEventManager() const; + + /** + * Returns a pointer to our window manager. + * @return A pointer to our window manager. + */ + virtual inline GHOST_WindowManager* getWindowManager() const; + + /** + * Returns a pointer to our n-degree of freedeom manager. + * @return A pointer to our n-degree of freedeom manager. + */ + virtual inline GHOST_NDOFManager* getNDOFManager() const; + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const = 0; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const = 0; + + /** + * Returns the selection buffer + * @param selection Only used on X11 + * @return Returns the clipboard data + * + */ + virtual GHOST_TUns8* getClipboard(bool selection) const = 0; + + /** + * Put data to the Clipboard + * @param buffer The buffer to copy to the clipboard + * @param selection The clipboard to copy too only used on X11 + */ + virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init(); + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit(); + + /** + * Creates a fullscreen window. + * @param window The window created. + * @return Indication of success. + */ + virtual GHOST_TSuccess createFullScreenWindow(GHOST_Window** window, + const bool stereoVisual); + + /** The display manager (platform dependant). */ + GHOST_DisplayManager* m_displayManager; + + /** The timer manager. */ + GHOST_TimerManager* m_timerManager; + + /** The window manager. */ + GHOST_WindowManager* m_windowManager; + + /** The event manager. */ + GHOST_EventManager* m_eventManager; + + /** The N-degree of freedom device manager */ + GHOST_NDOFManager* m_ndofManager; + + /** Prints all the events. */ +#ifdef GHOST_DEBUG + GHOST_EventPrinter* m_eventPrinter; +#endif // GHOST_DEBUG + + /** Settings of the display before the display went fullscreen. */ + GHOST_DisplaySetting m_preFullScreenSetting; +}; + +inline GHOST_TimerManager* GHOST_System::getTimerManager() const +{ + return m_timerManager; +} + +inline GHOST_EventManager* GHOST_System::getEventManager() const +{ + return m_eventManager; +} + +inline GHOST_WindowManager* GHOST_System::getWindowManager() const +{ + return m_windowManager; +} + +inline GHOST_NDOFManager* GHOST_System::getNDOFManager() const +{ + return m_ndofManager; +} + +#endif // _GHOST_SYSTEM_H_ + diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp new file mode 100644 index 00000000000..d5e5fbc7a58 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -0,0 +1,1221 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemCarbon.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#include +#include +#include "GHOST_SystemCarbon.h" + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventWheel.h" +#include "GHOST_EventNDOF.h" + +#include "GHOST_TimerManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowCarbon.h" +#include "GHOST_NDOFManager.h" +#include "AssertMacros.h" + +#define GHOST_KEY_SWITCH(mac, ghost) { case (mac): ghostKey = (ghost); break; } + +/* blender class and types events */ +enum { + kEventClassBlender = 'blnd' +}; + +enum { + kEventBlenderNdofAxis = 1, + kEventBlenderNdofButtons = 2 +}; + +const EventTypeSpec kEvents[] = +{ + { kEventClassAppleEvent, kEventAppleEvent }, +/* + { kEventClassApplication, kEventAppActivated }, + { kEventClassApplication, kEventAppDeactivated }, +*/ + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + + { kEventClassWindow, kEventWindowClickZoomRgn } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpand } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpandAll }, /* for new zoom behaviour */ + + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowUpdate }, + { kEventClassWindow, kEventWindowBoundsChanged }, + + { kEventClassBlender, kEventBlenderNdofAxis }, + { kEventClassBlender, kEventBlenderNdofButtons } + + + +}; + + + +static GHOST_TButtonMask convertButton(EventMouseButton button) +{ + switch (button) { + case kEventMouseButtonPrimary: + return GHOST_kButtonMaskLeft; + case kEventMouseButtonSecondary: + return GHOST_kButtonMaskRight; + case kEventMouseButtonTertiary: + default: + return GHOST_kButtonMaskMiddle; + } +} + +static GHOST_TKey convertKey(int rawCode) +{ + /* This bit of magic converts the rawCode into a virtual + * Mac key based on the current keyboard mapping, but + * without regard to the modifiers (so we don't get 'a' + * and 'A' for example. + */ + static UInt32 dummy= 0; + Handle transData = (Handle) GetScriptManagerVariable(smKCHRCache); + unsigned char vk = KeyTranslate(transData, rawCode, &dummy); + /* Map numpad based on rawcodes first, otherwise they + * look like non-numpad events. + * Added too: mapping the number keys, for french keyboards etc (ton) + */ + // printf("GHOST: vk: %d %c raw: %d\n", vk, vk, rawCode); + + switch (rawCode) { + case 18: return GHOST_kKey1; + case 19: return GHOST_kKey2; + case 20: return GHOST_kKey3; + case 21: return GHOST_kKey4; + case 23: return GHOST_kKey5; + case 22: return GHOST_kKey6; + case 26: return GHOST_kKey7; + case 28: return GHOST_kKey8; + case 25: return GHOST_kKey9; + case 29: return GHOST_kKey0; + + case 82: return GHOST_kKeyNumpad0; + case 83: return GHOST_kKeyNumpad1; + case 84: return GHOST_kKeyNumpad2; + case 85: return GHOST_kKeyNumpad3; + case 86: return GHOST_kKeyNumpad4; + case 87: return GHOST_kKeyNumpad5; + case 88: return GHOST_kKeyNumpad6; + case 89: return GHOST_kKeyNumpad7; + case 91: return GHOST_kKeyNumpad8; + case 92: return GHOST_kKeyNumpad9; + case 65: return GHOST_kKeyNumpadPeriod; + case 76: return GHOST_kKeyNumpadEnter; + case 69: return GHOST_kKeyNumpadPlus; + case 78: return GHOST_kKeyNumpadMinus; + case 67: return GHOST_kKeyNumpadAsterisk; + case 75: return GHOST_kKeyNumpadSlash; + } + + if ((vk >= 'a') && (vk <= 'z')) { + return (GHOST_TKey) (vk - 'a' + GHOST_kKeyA); + } else if ((vk >= '0') && (vk <= '9')) { + return (GHOST_TKey) (vk - '0' + GHOST_kKey0); + } else if (vk==16) { + switch (rawCode) { + case 122: return GHOST_kKeyF1; + case 120: return GHOST_kKeyF2; + case 99: return GHOST_kKeyF3; + case 118: return GHOST_kKeyF4; + case 96: return GHOST_kKeyF5; + case 97: return GHOST_kKeyF6; + case 98: return GHOST_kKeyF7; + case 100: return GHOST_kKeyF8; + case 101: return GHOST_kKeyF9; + case 109: return GHOST_kKeyF10; + case 103: return GHOST_kKeyF11; + case 111: return GHOST_kKeyF12; // Never get, is used for ejecting the CD! + } + } else { + switch (vk) { + case kUpArrowCharCode: return GHOST_kKeyUpArrow; + case kDownArrowCharCode: return GHOST_kKeyDownArrow; + case kLeftArrowCharCode: return GHOST_kKeyLeftArrow; + case kRightArrowCharCode: return GHOST_kKeyRightArrow; + + case kReturnCharCode: return GHOST_kKeyEnter; + case kBackspaceCharCode: return GHOST_kKeyBackSpace; + case kDeleteCharCode: return GHOST_kKeyDelete; + case kEscapeCharCode: return GHOST_kKeyEsc; + case kTabCharCode: return GHOST_kKeyTab; + case kSpaceCharCode: return GHOST_kKeySpace; + + case kHomeCharCode: return GHOST_kKeyHome; + case kEndCharCode: return GHOST_kKeyEnd; + case kPageUpCharCode: return GHOST_kKeyUpPage; + case kPageDownCharCode: return GHOST_kKeyDownPage; + + case '-': return GHOST_kKeyMinus; + case '=': return GHOST_kKeyEqual; + case ',': return GHOST_kKeyComma; + case '.': return GHOST_kKeyPeriod; + case '/': return GHOST_kKeySlash; + case ';': return GHOST_kKeySemicolon; + case '\'': return GHOST_kKeyQuote; + case '\\': return GHOST_kKeyBackslash; + case '[': return GHOST_kKeyLeftBracket; + case ']': return GHOST_kKeyRightBracket; + case '`': return GHOST_kKeyAccentGrave; + } + } + + // printf("GHOST: unknown key: %d %d\n", vk, rawCode); + + return GHOST_kKeyUnknown; +} + +/* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes + * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html + * I am not sure how international this works... + * For cross-platform convention, we'll use the Latin ascii set instead. + * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html + * + */ +static unsigned char convertRomanToLatin(unsigned char ascii) +{ + + if(ascii<128) return ascii; + + switch(ascii) { + case 128: return 142; + case 129: return 143; + case 130: return 128; + case 131: return 201; + case 132: return 209; + case 133: return 214; + case 134: return 220; + case 135: return 225; + case 136: return 224; + case 137: return 226; + case 138: return 228; + case 139: return 227; + case 140: return 229; + case 141: return 231; + case 142: return 233; + case 143: return 232; + case 144: return 234; + case 145: return 235; + case 146: return 237; + case 147: return 236; + case 148: return 238; + case 149: return 239; + case 150: return 241; + case 151: return 243; + case 152: return 242; + case 153: return 244; + case 154: return 246; + case 155: return 245; + case 156: return 250; + case 157: return 249; + case 158: return 251; + case 159: return 252; + case 160: return 0; + case 161: return 176; + case 162: return 162; + case 163: return 163; + case 164: return 167; + case 165: return 183; + case 166: return 182; + case 167: return 223; + case 168: return 174; + case 169: return 169; + case 170: return 174; + case 171: return 180; + case 172: return 168; + case 173: return 0; + case 174: return 198; + case 175: return 216; + case 176: return 0; + case 177: return 177; + case 178: return 0; + case 179: return 0; + case 180: return 165; + case 181: return 181; + case 182: return 0; + case 183: return 0; + case 184: return 215; + case 185: return 0; + case 186: return 0; + case 187: return 170; + case 188: return 186; + case 189: return 0; + case 190: return 230; + case 191: return 248; + case 192: return 191; + case 193: return 161; + case 194: return 172; + case 195: return 0; + case 196: return 0; + case 197: return 0; + case 198: return 0; + case 199: return 171; + case 200: return 187; + case 201: return 201; + case 202: return 0; + case 203: return 192; + case 204: return 195; + case 205: return 213; + case 206: return 0; + case 207: return 0; + case 208: return 0; + case 209: return 0; + case 210: return 0; + + case 214: return 247; + + case 229: return 194; + case 230: return 202; + case 231: return 193; + case 232: return 203; + case 233: return 200; + case 234: return 205; + case 235: return 206; + case 236: return 207; + case 237: return 204; + case 238: return 211; + case 239: return 212; + case 240: return 0; + case 241: return 210; + case 242: return 218; + case 243: return 219; + case 244: return 217; + case 245: return 0; + case 246: return 0; + case 247: return 0; + case 248: return 0; + case 249: return 0; + case 250: return 0; + + + default: return 0; + } + +} + + +/***/ + +GHOST_SystemCarbon::GHOST_SystemCarbon() : + m_modifierMask(0) +{ + m_displayManager = new GHOST_DisplayManagerCarbon (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemCarbon::GHOST_SystemCarbon(): m_displayManager==0\n"); + m_displayManager->initialize(); + + UnsignedWide micros; + ::Microseconds(µs); + m_start_time = UnsignedWideToUInt64(micros)/1000; + m_ignoreWindowSizedMessages = false; +} + +GHOST_SystemCarbon::~GHOST_SystemCarbon() +{ +} + + +GHOST_TUns64 GHOST_SystemCarbon::getMilliSeconds() const +{ + UnsignedWide micros; + ::Microseconds(µs); + UInt64 millis; + millis = UnsignedWideToUInt64(micros); + return (millis / 1000) - m_start_time; +} + + +GHOST_TUns8 GHOST_SystemCarbon::getNumDisplays() const +{ + // We do not support multiple monitors at the moment + return 1; +} + + +void GHOST_SystemCarbon::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + BitMap screenBits; + Rect bnds = GetQDGlobalsScreenBits(&screenBits)->bounds; + width = bnds.right - bnds.left; + height = bnds.bottom - bnds.top; +} + + +GHOST_IWindow* GHOST_SystemCarbon::createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual, + const GHOST_TUns16 numOfAASamples, + const GHOST_TEmbedderWindowID parentWindow +) +{ + GHOST_IWindow* window = 0; + + window = new GHOST_WindowCarbon (title, left, top, width, height, state, type); + + if (window) { + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): window invalid\n"); + delete window; + window = 0; + } + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): could not create window\n"); + } + return window; +} + +GHOST_TSuccess GHOST_SystemCarbon::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + + // need yo make this Carbon all on 10.5 for fullscreen to work correctly + CGCaptureAllDisplays(); + + success = GHOST_System::beginFullScreen( setting, window, stereoVisual); + + if( success != GHOST_kSuccess ) { + // fullscreen failed for other reasons, release + CGReleaseAllDisplays(); + } + + return success; +} + +GHOST_TSuccess GHOST_SystemCarbon::endFullScreen(void) +{ + CGReleaseAllDisplays(); + return GHOST_System::endFullScreen(); +} + +/* this is an old style low level event queue. + As we want to handle our own timers, this is ok. + the full screen hack should be removed */ +bool GHOST_SystemCarbon::processEvents(bool waitForEvent) +{ + bool anyProcessed = false; + EventRef event; + +// SetMouseCoalescingEnabled(false, NULL); + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent) { + GHOST_TUns64 next = timerMgr->nextFireTime(); + double timeOut; + + if (next == GHOST_kFireTimeNever) { + timeOut = kEventDurationForever; + } else { + timeOut = (double)(next - getMilliSeconds())/1000.0; + if (timeOut < 0.0) + timeOut = 0.0; + } + + ::ReceiveNextEvent(0, NULL, timeOut, false, &event); + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + if (getFullScreen()) { + // Check if the full-screen window is dirty + GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) { + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + anyProcessed = true; + } + } + + /* end loop when no more events available */ + while (::ReceiveNextEvent(0, NULL, 0, true, &event)==noErr) { + OSStatus status= ::SendEventToEventTarget(event, ::GetEventDispatcherTarget()); + if (status==noErr) { + anyProcessed = true; + } else { + UInt32 i= ::GetEventClass(event); + + /* Ignore 'cgs ' class, no documentation on what they + * are, but we get a lot of them + */ + if (i!='cgs ') { + if (i!='tblt') { // tablet event. we use the one packaged in the mouse event + ; //printf("Missed - Class: '%.4s', Kind: %d\n", &i, ::GetEventKind(event)); + } + } + } + ::ReleaseEvent(event); + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + Point mouseLoc; + // Get the position of the mouse in the active port + ::GetGlobalMouse(&mouseLoc); + // Convert the coordinates to screen coordinates + x = (GHOST_TInt32)mouseLoc.h; + y = (GHOST_TInt32)mouseLoc.v; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) +{ + float xf=(float)x, yf=(float)y; + + CGAssociateMouseAndMouseCursorPosition(false); + CGSetLocalEventsSuppressionInterval(0); + CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + CGAssociateMouseAndMouseCursorPosition(true); + +//this doesn't work properly, see game engine mouse-look scripts +// CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + // this call below sends event, but empties other events (like shift) + // CGPostMouseEvent(CGPointMake(xf, yf), TRUE, 1, FALSE, 0); + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + UInt32 modifiers = ::GetCurrentKeyModifiers(); + + keys.set(GHOST_kModifierKeyOS, (modifiers & cmdKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & optionKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftShift, (modifiers & shiftKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftControl, (modifiers & controlKey) ? true : false); + + return GHOST_kSuccess; +} + + /* XXX, incorrect for multibutton mice */ +GHOST_TSuccess GHOST_SystemCarbon::getButtons(GHOST_Buttons& buttons) const +{ + Boolean theOnlyButtonIsDown = ::Button(); + buttons.clear(); + buttons.set(GHOST_kButtonMaskLeft, theOnlyButtonIsDown); + return GHOST_kSuccess; +} + +#define FIRSTFILEBUFLG 512 +static bool g_hasFirstFile = false; +static char g_firstFileBuf[512]; + +extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { + if (g_hasFirstFile) { + strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1); + buf[FIRSTFILEBUFLG - 1] = '\0'; + return 1; + } else { + return 0; + } +} + +OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + + return noErr; +} + +OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + AEDescList docs; + SInt32 ndocs; + OSErr err; + + err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs); + if (err != noErr) return err; + + err = AECountItems(&docs, &ndocs); + if (err==noErr) { + int i; + + for (i=0; ipushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) ); + + return noErr; +} + + +GHOST_TSuccess GHOST_SystemCarbon::init() +{ + + GHOST_TSuccess success = GHOST_System::init(); + if (success) { + /* + * Initialize the cursor to the standard arrow shape (so that we can change it later on). + * This initializes the cursor's visibility counter to 0. + */ + ::InitCursor(); + + MenuRef windMenu; + ::CreateStandardWindowMenu(0, &windMenu); + ::InsertMenu(windMenu, 0); + ::DrawMenuBar(); + + ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler); + + ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false); + + } + return success; +} + + +GHOST_TSuccess GHOST_SystemCarbon::exit() +{ + return GHOST_System::exit(); +} + + +OSStatus GHOST_SystemCarbon::handleWindowEvent(EventRef event) +{ + WindowRef windowRef; + GHOST_WindowCarbon *window; + OSStatus err = eventNotHandledErr; + + // Check if the event was send to a GHOST window + ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef); + window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef); + if (!validWindow(window)) { + return err; + } + + //if (!getFullScreen()) { + err = noErr; + switch(::GetEventKind(event)) + { + case kEventWindowClose: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) ); + break; + case kEventWindowActivated: + m_windowManager->setActiveWindow(window); + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) ); + break; + case kEventWindowDeactivated: + m_windowManager->setWindowInactive(window); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); + break; + case kEventWindowUpdate: + //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n"); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + break; + case kEventWindowBoundsChanged: + if (!m_ignoreWindowSizedMessages) + { + window->updateDrawingContext(); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + break; + default: + err = eventNotHandledErr; + break; + } +// } + //else { + //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n"); + //::RemoveEventFromQueue(::GetMainEventQueue(), event); + //} + + return err; +} + +OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event) +{ + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + TabletPointRec tabletPointRecord; + TabletProximityRec tabletProximityRecord; + UInt32 anInt32; + GHOST_TabletData& ct=((GHOST_WindowCarbon*)window)->GetCarbonTabletData(); + OSStatus err = eventNotHandledErr; + + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; + + // is there an embedded tablet event inside this mouse event? + if(noErr == GetEventParameter(event, kEventParamTabletEventType, typeUInt32, NULL, sizeof(UInt32), NULL, (void *)&anInt32)) + { + // yes there is one! + // Embedded tablet events can either be a proximity or pointer event. + if(anInt32 == kEventTabletPoint) + { + //GHOST_PRINT("Embedded pointer event!\n"); + + // Extract the tablet Pointer Event. If there is no Tablet Pointer data + // in this event, then this call will return an error. Just ignore the + // error and go on. This can occur when a proximity event is embedded in + // a mouse event and you did not check the mouse event to see which type + // of tablet event was embedded. + if(noErr == GetEventParameter(event, kEventParamTabletPointRec, + typeTabletPointRec, NULL, + sizeof(TabletPointRec), + NULL, (void *)&tabletPointRecord)) + { + ct.Pressure = tabletPointRecord.pressure / 65535.0f; + ct.Xtilt = tabletPointRecord.tiltX / 32767.0f; /* can be positive or negative */ + ct.Ytilt = tabletPointRecord.tiltY / 32767.0f; /* can be positive or negative */ + } + } else { + //GHOST_PRINT("Embedded proximity event\n"); + + // Extract the Tablet Proximity record from the event. + if(noErr == GetEventParameter(event, kEventParamTabletProximityRec, + typeTabletProximityRec, NULL, + sizeof(TabletProximityRec), + NULL, (void *)&tabletProximityRecord)) + { + if (tabletProximityRecord.enterProximity) { + //pointer is entering tablet area proximity + + switch(tabletProximityRecord.pointerType) + { + case 1: /* stylus */ + ct.Active = GHOST_kTabletModeStylus; + break; + case 2: /* puck, not supported so far */ + ct.Active = GHOST_kTabletModeNone; + break; + case 3: /* eraser */ + ct.Active = GHOST_kTabletModeEraser; + break; + default: + ct.Active = GHOST_kTabletModeNone; + break; + } + } else { + // pointer is leaving - return to mouse + ct.Active = GHOST_kTabletModeNone; + } + } + } + err = noErr; + } + return err; +} + +OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + + switch (kind) + { + case kEventMouseDown: + case kEventMouseUp: + // Handle Mac application responsibilities + if ((kind == kEventMouseDown) && handleMouseDown(event)) { + err = noErr; + } + else { + GHOST_TEventType type = (kind == kEventMouseDown) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp; + EventMouseButton button; + + /* Window still gets mouse up after command-H */ + if (m_windowManager->getActiveWindow()) { + // handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), type, window, convertButton(button))); + err = noErr; + } + } + break; + + case kEventMouseMoved: + case kEventMouseDragged: { + Point mousePos; + + if (window) { + //handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, mousePos.h, mousePos.v)); + err = noErr; + } + break; + } + case kEventMouseWheelMoved: + { + OSStatus status; + //UInt32 modifiers; + EventMouseWheelAxis axis; + SInt32 delta; + //status = ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); + //GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + status = ::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + if (axis == kEventMouseWheelAxisY) + { + status = ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + /* + * Limit mouse wheel delta to plus and minus one. + */ + delta = delta > 0 ? 1 : -1; + pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta)); + err = noErr; + } + } + break; + } + + return err; +} + + +OSStatus GHOST_SystemCarbon::handleKeyEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + UInt32 modifiers; + UInt32 rawCode; + GHOST_TKey key; + unsigned char ascii; + + /* Can happen, very rarely - seems to only be when command-H makes + * the window go away and we still get an HKey up. + */ + if (!window) { + //::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + //key = convertKey(rawCode); + return err; + } + + err = noErr; + switch (kind) { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + case kEventRawKeyUp: + ::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + ::GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ascii); + + key = convertKey(rawCode); + ascii= convertRomanToLatin(ascii); + + // if (key!=GHOST_kKeyUnknown) { + GHOST_TEventType type; + if (kind == kEventRawKeyDown) { + type = GHOST_kEventKeyDown; + } else if (kind == kEventRawKeyRepeat) { + type = GHOST_kEventKeyDown; /* XXX, fixme */ + } else { + type = GHOST_kEventKeyUp; + } + pushEvent( new GHOST_EventKey( getMilliSeconds(), type, window, key, ascii) ); +// } + break; + + case kEventRawKeyModifiersChanged: + /* ugh */ + ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + if ((modifiers & shiftKey) != (m_modifierMask & shiftKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & shiftKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + } + if ((modifiers & controlKey) != (m_modifierMask & controlKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & controlKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + } + if ((modifiers & optionKey) != (m_modifierMask & optionKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & optionKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + } + if ((modifiers & cmdKey) != (m_modifierMask & cmdKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); + } + + m_modifierMask = modifiers; + break; + + default: + err = eventNotHandledErr; + break; + } + + return err; +} + + +bool GHOST_SystemCarbon::handleMouseDown(EventRef event) +{ + WindowPtr window; + short part; + BitMap screenBits; + bool handled = true; + GHOST_WindowCarbon* ghostWindow; + Point mousePos = {0 , 0}; + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + + part = ::FindWindow(mousePos, &window); + ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window); + + switch (part) { + case inMenuBar: + handleMenuCommand(::MenuSelect(mousePos)); + break; + + case inDrag: + /* + * The DragWindow() routine creates a lot of kEventWindowBoundsChanged + * events. By setting m_ignoreWindowSizedMessages these are suppressed. + * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event) + */ + /* even worse: scale window also generates a load of events, and nothing + is handled (read: client's event proc called) until you release mouse (ton) */ + + GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window"); + m_ignoreWindowSizedMessages = true; + ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds); + m_ignoreWindowSizedMessages = false; + + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) ); + + break; + + case inContent: + if (window != ::FrontWindow()) { + ::SelectWindow(window); + /* + * We add a mouse down event on the newly actived window + */ + //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n"); + EventMouseButton button; + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button))); + } else { + handled = false; + } + break; + + case inGoAway: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackGoAway(window, mousePos)) + { + // todo: add option-close, because itÿs in the HIG + // if (event.modifiers & optionKey) { + // Close the clean documents, others will be confirmed one by one. + //} + // else { + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow)); + //} + } + break; + + case inGrow: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + ::ResizeWindow(window, mousePos, NULL, NULL); + break; + + case inZoomIn: + case inZoomOut: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackBox(window, mousePos, part)) { + int macState; + + macState = ghostWindow->getMac_windowState(); + if ( macState== 0) + ::ZoomWindow(window, part, true); + else + if (macState == 2) { // always ok + ::ZoomWindow(window, part, true); + ghostWindow->setMac_windowState(1); + } else { // need to force size again + // GHOST_TUns32 scr_x,scr_y; /*unused*/ + Rect outAvailableRect; + + ghostWindow->setMac_windowState(2); + ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect); + + //this->getMainDisplayDimensions(scr_x,scr_y); + ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false); + ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true); + } + + } + break; + + default: + handled = false; + break; + } + + return handled; +} + + +bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult) +{ + short menuID; + short menuItem; + UInt32 command; + bool handled; + OSErr err; + + menuID = HiWord(menuResult); + menuItem = LoWord(menuResult); + + err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command); + + handled = false; + + if (err || command == 0) { + } + else { + switch(command) { + } + } + + ::HiliteMenu(0); + return handled; +} + + +OSStatus GHOST_SystemCarbon::sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) +{ + GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) userData; + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window; + GHOST_TEventNDOFData data; + UInt32 kind; + + switch (::GetEventClass(event)) + { + case kEventClassAppleEvent: + EventRecord eventrec; + if (ConvertEventRefToEventRecord(event, &eventrec)) { + err = AEProcessAppleEvent(&eventrec); + } + break; + case kEventClassMouse: + err = sys->handleMouseEvent(event); + break; + case kEventClassWindow: + err = sys->handleWindowEvent(event); + break; + case kEventClassKeyboard: + err = sys->handleKeyEvent(event); + break; + case kEventClassBlender : + window = sys->m_windowManager->getActiveWindow(); + sys->m_ndofManager->GHOST_NDOFGetDatas(data); + kind = ::GetEventKind(event); + + switch (kind) + { + case 1: + sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFMotion, window, data)); + // printf("motion\n"); + break; + case 2: + sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFButton, window, data)); +// printf("button\n"); + break; + } + err = noErr; + break; + default : + ; + break; + } + + return err; +} + +GHOST_TUns8* GHOST_SystemCarbon::getClipboard(bool selection) const +{ + PasteboardRef inPasteboard; + PasteboardItemID itemID; + CFDataRef flavorData; + OSStatus err = noErr; + GHOST_TUns8 * temp_buff; + CFRange range; + OSStatus syncFlags; + + err = PasteboardCreate(kPasteboardClipboard, &inPasteboard); + if(err != noErr) { return NULL;} + + syncFlags = PasteboardSynchronize( inPasteboard ); + /* as we always get in a new string, we can safely ignore sync flags if not an error*/ + if(syncFlags <0) { return NULL;} + + + err = PasteboardGetItemIdentifier( inPasteboard, 1, &itemID ); + if(err != noErr) { return NULL;} + + err = PasteboardCopyItemFlavorData( inPasteboard, itemID, CFSTR("public.utf8-plain-text"), &flavorData); + if(err != noErr) { return NULL;} + + range = CFRangeMake(0, CFDataGetLength(flavorData)); + + temp_buff = (GHOST_TUns8*) malloc(range.length+1); + + CFDataGetBytes(flavorData, range, (UInt8*)temp_buff); + + temp_buff[range.length] = '\0'; + + if(temp_buff) { + return temp_buff; + } else { + return NULL; + } +} + +void GHOST_SystemCarbon::putClipboard(GHOST_TInt8 *buffer, bool selection) const +{ + if(selection) {return;} // for copying the selection, used on X11 + + PasteboardRef inPasteboard; + CFDataRef textData = NULL; + OSStatus err = noErr; /*For error checking*/ + OSStatus syncFlags; + + err = PasteboardCreate(kPasteboardClipboard, &inPasteboard); + if(err != noErr) { return;} + + syncFlags = PasteboardSynchronize( inPasteboard ); + /* as we always put in a new string, we can safely ignore sync flags */ + if(syncFlags <0) { return;} + + err = PasteboardClear( inPasteboard ); + if(err != noErr) { return;} + + textData = CFDataCreate(kCFAllocatorDefault, (UInt8*)buffer, strlen(buffer)); + + if (textData) { + err = PasteboardPutItemFlavor( inPasteboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), textData, 0); + if(err != noErr) { + if(textData) { CFRelease(textData);} + return; + } + } + + if(textData) { + CFRelease(textData); + } +} diff --git a/intern/ghost/intern/GHOST_SystemCarbon.h b/intern/ghost/intern/GHOST_SystemCarbon.h new file mode 100644 index 00000000000..b0cf622f709 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.h @@ -0,0 +1,290 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemCarbon.h + * \ingroup GHOST + * Declaration of GHOST_SystemCarbon class. + */ + +#ifndef _GHOST_SYSTEM_CARBON_H_ +#define _GHOST_SYSTEM_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#define __CARBONSOUND__ +#include + +#include "GHOST_System.h" + +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWindow; + +/** + * OSX/Carbon Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 21, 2001 + */ +class GHOST_SystemCarbon : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemCarbon(); + + /** + * Destructor. + */ + ~GHOST_SystemCarbon(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples = 0, + const GHOST_TEmbedderWindowID parentWindow = 0 + ); + + virtual GHOST_TSuccess beginFullScreen( + const GHOST_DisplaySetting& setting, + GHOST_IWindow** window, + const bool stereoVisual + ); + + virtual GHOST_TSuccess endFullScreen( void ); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y); + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + + /** + * Returns Clipboard data + * @param selection Indicate which buffer to return + * @return Returns the selected buffer + */ + virtual GHOST_TUns8* getClipboard(bool selection) const; + + /** + * Puts buffer to system clipboard + * @param buffer The buffer to be copied + * @param selection Indicates which buffer to copy too, only used on X11 + */ + virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + + /** + * @see GHOST_ISystem + */ + int toggleConsole(int action) { return 0; } + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + + /** + * Handles a tablet event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleTabletEvent(EventRef event); + /** + * Handles a mouse event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleMouseEvent(EventRef event); + + /** + * Handles a key event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleKeyEvent(EventRef event); + + /** + * Handles a window event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleWindowEvent(EventRef event); + + /** + * Handles all basic Mac application stuff for a mouse down event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + bool handleMouseDown(EventRef event); + + /** + * Handles a Mac menu command. + * @param menuResult A Mac menu/item identifier. + * @return Indication whether the event was handled. + */ + bool handleMenuCommand(GHOST_TInt32 menuResult); + + /* callback for blender generated events */ +// static OSStatus blendEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData); + + + /** + * Callback for Carbon when it has events. + */ + static OSStatus sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData); + + /** Apple Event Handlers */ + static OSErr sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + + /** + * Callback for Mac Timer tasks that expire. + * @param tmTask Pointer to the timer task that expired. + */ + //static void s_timerCallback(TMTaskPtr tmTask); + + /** Event handler reference. */ + EventHandlerRef m_handler; + + /** Start time at initialization. */ + GHOST_TUns64 m_start_time; + + /** State of the modifiers. */ + UInt32 m_modifierMask; + + /** Ignores window size messages (when window is dragged). */ + bool m_ignoreWindowSizedMessages; +}; + +#endif // _GHOST_SYSTEM_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h new file mode 100644 index 00000000000..e7a8178a382 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -0,0 +1,306 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Maarten Gribnau 05/2001 + * Damien Plisson 09/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemCocoa.h + * \ingroup GHOST + * Declaration of GHOST_SystemCocoa class. + */ + +#ifndef _GHOST_SYSTEM_COCOA_H_ +#define _GHOST_SYSTEM_COCOA_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +//#define __CARBONSOUND__ + + +#include "GHOST_System.h" + +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWindow; +class GHOST_WindowCocoa; + + +class GHOST_SystemCocoa : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemCocoa(); + + /** + * Destructor. + */ + ~GHOST_SystemCocoa(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0, + const GHOST_TEmbedderWindowID parentWindow = 0 + ); + + virtual GHOST_TSuccess beginFullScreen( + const GHOST_DisplaySetting& setting, + GHOST_IWindow** window, + const bool stereoVisual + ); + + virtual GHOST_TSuccess endFullScreen( void ); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + /** + * Handle User request to quit, from Menu bar Quit, and Cmd+Q + * Display alert panel if changes performed since last save + */ + GHOST_TUns8 handleQuitRequest(); + + /** + * Handle Cocoa openFile event + * Display confirmation request panel if changes performed since last save + */ + bool handleOpenDocumentRequest(void *filepathStr); + + /** + * Handles a drag'n'drop destination event. Called by GHOST_WindowCocoa window subclass + * @param eventType The type of drag'n'drop event + * @param draggedObjectType The type object concerned (currently array of file names, string, TIFF image) + * @param mouseX x mouse coordinate (in cocoa base window coordinates) + * @param mouseY y mouse coordinate + * @param window The window on which the event occurred + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, + GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y); + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + + /** + * Returns Clipboard data + * @param selection Indicate which buffer to return + * @return Returns the selected buffer + */ + virtual GHOST_TUns8* getClipboard(bool selection) const; + + /** + * Puts buffer to system clipboard + * @param buffer The buffer to be copied + * @param selection Indicates which buffer to copy too, only used on X11 + */ + virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + + /** + * Handles a window event. Called by GHOST_WindowCocoa window delegate + * @param eventType The type of window event + * @param window The window on which the event occurred + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window); + + /** + * Handles the Cocoa event telling the application has become active (again) + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleApplicationBecomeActiveEvent(); + + /** + * @see GHOST_ISystem + */ + int toggleConsole(int action) { return 0; } + + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Handles a tablet event. + * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) + * @param eventType The type of the event. It needs to be passed separately as it can be either directly in the event type, or as a subtype if combined with a mouse button event + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleTabletEvent(void *eventPtr, short eventType); + + /** + * Handles a mouse event. + * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleMouseEvent(void *eventPtr); + + /** + * Handles a key event. + * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleKeyEvent(void *eventPtr); + + /** + * Performs the actual cursor position update (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + GHOST_TSuccess setMouseCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y); + + /** Start time at initialization. */ + GHOST_TUns64 m_start_time; + + /** Event has been processed directly by Cocoa and has sent a ghost event to be dispatched */ + bool m_outsideLoopEventProcessed; + + /** Raised window is not yet known by the window manager, so delay application become active event handling */ + bool m_needDelayedApplicationBecomeActiveEventProcessing; + + /** Mouse buttons state */ + GHOST_TUns32 m_pressedMouseButtons; + + /** State of the modifiers. */ + GHOST_TUns32 m_modifierMask; + + /** Ignores window size messages (when window is dragged). */ + bool m_ignoreWindowSizedMessages; + + /** Stores the mouse cursor delta due to setting a new cursor position + * Needed because cocoa event delta cursor move takes setCursorPosition changes too. + */ + GHOST_TInt32 m_cursorDelta_x, m_cursorDelta_y; + + /** Multitouch trackpad availability */ + bool m_hasMultiTouchTrackpad; + + /** Multitouch gesture in progress, useful to distinguish trackpad from mouse scroll events */ + bool m_isGestureInProgress; +}; + +#endif // _GHOST_SYSTEM_COCOA_H_ + diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm new file mode 100644 index 00000000000..bf401138cf1 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -0,0 +1,1798 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Maarten Gribnau 05/2001 + * Damien Plisson 09/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#import + +/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/ +#include + +#include +#include +#include + +#include "GHOST_SystemCocoa.h" + +#include "GHOST_DisplayManagerCocoa.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventWheel.h" +#include "GHOST_EventNDOF.h" +#include "GHOST_EventTrackpad.h" +#include "GHOST_EventDragnDrop.h" +#include "GHOST_EventString.h" + +#include "GHOST_TimerManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowCocoa.h" +#include "GHOST_NDOFManager.h" +#include "AssertMacros.h" + +#pragma mark KeyMap, mouse converters +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 +/* Keycodes not defined in Tiger */ +/* + * Summary: + * Virtual keycodes + * + * Discussion: + * These constants are the virtual keycodes defined originally in + * Inside Mac Volume V, pg. V-191. They identify physical keys on a + * keyboard. Those constants with "ANSI" in the name are labeled + * according to the key position on an ANSI-standard US keyboard. + * For example, kVK_ANSI_A indicates the virtual keycode for the key + * with the letter 'A' in the US keyboard layout. Other keyboard + * layouts may have the 'A' key label on a different physical key; + * in this case, pressing 'A' will generate a different virtual + * keycode. + */ +enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_ANSI_KeypadDecimal = 0x41, + kVK_ANSI_KeypadMultiply = 0x43, + kVK_ANSI_KeypadPlus = 0x45, + kVK_ANSI_KeypadClear = 0x47, + kVK_ANSI_KeypadDivide = 0x4B, + kVK_ANSI_KeypadEnter = 0x4C, + kVK_ANSI_KeypadMinus = 0x4E, + kVK_ANSI_KeypadEquals = 0x51, + kVK_ANSI_Keypad0 = 0x52, + kVK_ANSI_Keypad1 = 0x53, + kVK_ANSI_Keypad2 = 0x54, + kVK_ANSI_Keypad3 = 0x55, + kVK_ANSI_Keypad4 = 0x56, + kVK_ANSI_Keypad5 = 0x57, + kVK_ANSI_Keypad6 = 0x58, + kVK_ANSI_Keypad7 = 0x59, + kVK_ANSI_Keypad8 = 0x5B, + kVK_ANSI_Keypad9 = 0x5C +}; + +/* keycodes for keys that are independent of keyboard layout*/ +enum { + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E +}; + +/* ISO keyboards only*/ +enum { + kVK_ISO_Section = 0x0A +}; + +/* JIS keyboards only*/ +enum { + kVK_JIS_Yen = 0x5D, + kVK_JIS_Underscore = 0x5E, + kVK_JIS_KeypadComma = 0x5F, + kVK_JIS_Eisu = 0x66, + kVK_JIS_Kana = 0x68 +}; +#endif + +static GHOST_TButtonMask convertButton(int button) +{ + switch (button) { + case 0: + return GHOST_kButtonMaskLeft; + case 1: + return GHOST_kButtonMaskRight; + case 2: + return GHOST_kButtonMaskMiddle; + case 3: + return GHOST_kButtonMaskButton4; + case 4: + return GHOST_kButtonMaskButton5; + default: + return GHOST_kButtonMaskLeft; + } +} + +/** + * Converts Mac rawkey codes (same for Cocoa & Carbon) + * into GHOST key codes + * @param rawCode The raw physical key code + * @param recvChar the character ignoring modifiers (except for shift) + * @return Ghost key code + */ +static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction) +{ + + //printf("\nrecvchar %c 0x%x",recvChar,recvChar); + switch (rawCode) { + /*Physical keycodes not used due to map changes in int'l keyboards + case kVK_ANSI_A: return GHOST_kKeyA; + case kVK_ANSI_B: return GHOST_kKeyB; + case kVK_ANSI_C: return GHOST_kKeyC; + case kVK_ANSI_D: return GHOST_kKeyD; + case kVK_ANSI_E: return GHOST_kKeyE; + case kVK_ANSI_F: return GHOST_kKeyF; + case kVK_ANSI_G: return GHOST_kKeyG; + case kVK_ANSI_H: return GHOST_kKeyH; + case kVK_ANSI_I: return GHOST_kKeyI; + case kVK_ANSI_J: return GHOST_kKeyJ; + case kVK_ANSI_K: return GHOST_kKeyK; + case kVK_ANSI_L: return GHOST_kKeyL; + case kVK_ANSI_M: return GHOST_kKeyM; + case kVK_ANSI_N: return GHOST_kKeyN; + case kVK_ANSI_O: return GHOST_kKeyO; + case kVK_ANSI_P: return GHOST_kKeyP; + case kVK_ANSI_Q: return GHOST_kKeyQ; + case kVK_ANSI_R: return GHOST_kKeyR; + case kVK_ANSI_S: return GHOST_kKeyS; + case kVK_ANSI_T: return GHOST_kKeyT; + case kVK_ANSI_U: return GHOST_kKeyU; + case kVK_ANSI_V: return GHOST_kKeyV; + case kVK_ANSI_W: return GHOST_kKeyW; + case kVK_ANSI_X: return GHOST_kKeyX; + case kVK_ANSI_Y: return GHOST_kKeyY; + case kVK_ANSI_Z: return GHOST_kKeyZ;*/ + + /* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/ + case kVK_ISO_Section: return GHOST_kKeyUnknown; + case kVK_ANSI_1: return GHOST_kKey1; + case kVK_ANSI_2: return GHOST_kKey2; + case kVK_ANSI_3: return GHOST_kKey3; + case kVK_ANSI_4: return GHOST_kKey4; + case kVK_ANSI_5: return GHOST_kKey5; + case kVK_ANSI_6: return GHOST_kKey6; + case kVK_ANSI_7: return GHOST_kKey7; + case kVK_ANSI_8: return GHOST_kKey8; + case kVK_ANSI_9: return GHOST_kKey9; + case kVK_ANSI_0: return GHOST_kKey0; + + case kVK_ANSI_Keypad0: return GHOST_kKeyNumpad0; + case kVK_ANSI_Keypad1: return GHOST_kKeyNumpad1; + case kVK_ANSI_Keypad2: return GHOST_kKeyNumpad2; + case kVK_ANSI_Keypad3: return GHOST_kKeyNumpad3; + case kVK_ANSI_Keypad4: return GHOST_kKeyNumpad4; + case kVK_ANSI_Keypad5: return GHOST_kKeyNumpad5; + case kVK_ANSI_Keypad6: return GHOST_kKeyNumpad6; + case kVK_ANSI_Keypad7: return GHOST_kKeyNumpad7; + case kVK_ANSI_Keypad8: return GHOST_kKeyNumpad8; + case kVK_ANSI_Keypad9: return GHOST_kKeyNumpad9; + case kVK_ANSI_KeypadDecimal: return GHOST_kKeyNumpadPeriod; + case kVK_ANSI_KeypadEnter: return GHOST_kKeyNumpadEnter; + case kVK_ANSI_KeypadPlus: return GHOST_kKeyNumpadPlus; + case kVK_ANSI_KeypadMinus: return GHOST_kKeyNumpadMinus; + case kVK_ANSI_KeypadMultiply: return GHOST_kKeyNumpadAsterisk; + case kVK_ANSI_KeypadDivide: return GHOST_kKeyNumpadSlash; + case kVK_ANSI_KeypadClear: return GHOST_kKeyUnknown; + + case kVK_F1: return GHOST_kKeyF1; + case kVK_F2: return GHOST_kKeyF2; + case kVK_F3: return GHOST_kKeyF3; + case kVK_F4: return GHOST_kKeyF4; + case kVK_F5: return GHOST_kKeyF5; + case kVK_F6: return GHOST_kKeyF6; + case kVK_F7: return GHOST_kKeyF7; + case kVK_F8: return GHOST_kKeyF8; + case kVK_F9: return GHOST_kKeyF9; + case kVK_F10: return GHOST_kKeyF10; + case kVK_F11: return GHOST_kKeyF11; + case kVK_F12: return GHOST_kKeyF12; + case kVK_F13: return GHOST_kKeyF13; + case kVK_F14: return GHOST_kKeyF14; + case kVK_F15: return GHOST_kKeyF15; + case kVK_F16: return GHOST_kKeyF16; + case kVK_F17: return GHOST_kKeyF17; + case kVK_F18: return GHOST_kKeyF18; + case kVK_F19: return GHOST_kKeyF19; + case kVK_F20: return GHOST_kKeyF20; + + case kVK_UpArrow: return GHOST_kKeyUpArrow; + case kVK_DownArrow: return GHOST_kKeyDownArrow; + case kVK_LeftArrow: return GHOST_kKeyLeftArrow; + case kVK_RightArrow: return GHOST_kKeyRightArrow; + + case kVK_Return: return GHOST_kKeyEnter; + case kVK_Delete: return GHOST_kKeyBackSpace; + case kVK_ForwardDelete: return GHOST_kKeyDelete; + case kVK_Escape: return GHOST_kKeyEsc; + case kVK_Tab: return GHOST_kKeyTab; + case kVK_Space: return GHOST_kKeySpace; + + case kVK_Home: return GHOST_kKeyHome; + case kVK_End: return GHOST_kKeyEnd; + case kVK_PageUp: return GHOST_kKeyUpPage; + case kVK_PageDown: return GHOST_kKeyDownPage; + + /*case kVK_ANSI_Minus: return GHOST_kKeyMinus; + case kVK_ANSI_Equal: return GHOST_kKeyEqual; + case kVK_ANSI_Comma: return GHOST_kKeyComma; + case kVK_ANSI_Period: return GHOST_kKeyPeriod; + case kVK_ANSI_Slash: return GHOST_kKeySlash; + case kVK_ANSI_Semicolon: return GHOST_kKeySemicolon; + case kVK_ANSI_Quote: return GHOST_kKeyQuote; + case kVK_ANSI_Backslash: return GHOST_kKeyBackslash; + case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket; + case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket; + case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;*/ + + case kVK_VolumeUp: + case kVK_VolumeDown: + case kVK_Mute: + return GHOST_kKeyUnknown; + + default: + /* alphanumerical or punctuation key that is remappable in int'l keyboards */ + if ((recvChar >= 'A') && (recvChar <= 'Z')) { + return (GHOST_TKey) (recvChar - 'A' + GHOST_kKeyA); + } else if ((recvChar >= 'a') && (recvChar <= 'z')) { + return (GHOST_TKey) (recvChar - 'a' + GHOST_kKeyA); + } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 + KeyboardLayoutRef keyLayout; + UCKeyboardLayout *uchrData; + + KLGetCurrentKeyboardLayout(&keyLayout); + KLGetKeyboardLayoutProperty(keyLayout, kKLuchrData, (const void **) + &uchrData); + /*get actual character value of the "remappable" keys in int'l keyboards, + if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger), + then fallback on using the received charactersIgnoringModifiers */ + if (uchrData) + { + UInt32 deadKeyState=0; + UniCharCount actualStrLength=0; + + UCKeyTranslate(uchrData, rawCode, keyAction, 0, + LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 1, &actualStrLength, &recvChar); + + } +#else + /* Leopard and Snow Leopard 64bit compatible API*/ + CFDataRef uchrHandle; /*the keyboard layout*/ + TISInputSourceRef kbdTISHandle; + + kbdTISHandle = TISCopyCurrentKeyboardLayoutInputSource(); + uchrHandle = (CFDataRef)TISGetInputSourceProperty(kbdTISHandle,kTISPropertyUnicodeKeyLayoutData); + CFRelease(kbdTISHandle); + + /*get actual character value of the "remappable" keys in int'l keyboards, + if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger), + then fallback on using the received charactersIgnoringModifiers */ + if (uchrHandle) + { + UInt32 deadKeyState=0; + UniCharCount actualStrLength=0; + + UCKeyTranslate((UCKeyboardLayout*)CFDataGetBytePtr(uchrHandle), rawCode, keyAction, 0, + LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 1, &actualStrLength, &recvChar); + + } +#endif + switch (recvChar) { + case '-': return GHOST_kKeyMinus; + case '=': return GHOST_kKeyEqual; + case ',': return GHOST_kKeyComma; + case '.': return GHOST_kKeyPeriod; + case '/': return GHOST_kKeySlash; + case ';': return GHOST_kKeySemicolon; + case '\'': return GHOST_kKeyQuote; + case '\\': return GHOST_kKeyBackslash; + case '[': return GHOST_kKeyLeftBracket; + case ']': return GHOST_kKeyRightBracket; + case '`': return GHOST_kKeyAccentGrave; + default: + return GHOST_kKeyUnknown; + } + } + } + return GHOST_kKeyUnknown; +} + + +#pragma mark defines for 10.6 api not documented in 10.5 +#ifndef MAC_OS_X_VERSION_10_6 +enum { + /* The following event types are available on some hardware on 10.5.2 and later */ + NSEventTypeGesture = 29, + NSEventTypeMagnify = 30, + NSEventTypeSwipe = 31, + NSEventTypeRotate = 18, + NSEventTypeBeginGesture = 19, + NSEventTypeEndGesture = 20 +}; + +@interface NSEvent(GestureEvents) +/* This message is valid for events of type NSEventTypeMagnify, on 10.5.2 or later */ +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 +- (float)magnification; // change in magnification. +#else +- (CGFloat)magnification; // change in magnification. +#endif +@end + +#endif + + +#pragma mark Utility functions + +#define FIRSTFILEBUFLG 512 +static bool g_hasFirstFile = false; +static char g_firstFileBuf[512]; + +//TODO:Need to investigate this. Function called too early in creator.c to have g_hasFirstFile == true +extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { + if (g_hasFirstFile) { + strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1); + buf[FIRSTFILEBUFLG - 1] = '\0'; + return 1; + } else { + return 0; + } +} + +#if defined(WITH_QUICKTIME) && !defined(USE_QTKIT) +//Need to place this quicktime function in an ObjC file +//It is used to avoid memory leak when raising the quicktime "compression settings" standard dialog +extern "C" { + struct bContext; + struct wmOperator; + extern int fromcocoa_request_qtcodec_settings(bContext *C, wmOperator *op); + + +int cocoa_request_qtcodec_settings(bContext *C, wmOperator *op) +{ + int result; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + result = fromcocoa_request_qtcodec_settings(C, op); + + [pool drain]; + return result; +} +}; +#endif + + +#pragma mark Cocoa objects + +/** + * CocoaAppDelegate + * ObjC object to capture applicationShouldTerminate, and send quit event + **/ +@interface CocoaAppDelegate : NSObject { + GHOST_SystemCocoa *systemCocoa; +} +- (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa; +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +- (void)applicationWillTerminate:(NSNotification *)aNotification; +- (void)applicationWillBecomeActive:(NSNotification *)aNotification; +@end + +@implementation CocoaAppDelegate : NSObject +-(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa +{ + systemCocoa = sysCocoa; +} + +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + return systemCocoa->handleOpenDocumentRequest(filename); +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + //TODO: implement graceful termination through Cocoa mechanism to avoid session log off to be cancelled + //Note that Cmd+Q is already handled by keyhandler + if (systemCocoa->handleQuitRequest() == GHOST_kExitNow) + return NSTerminateCancel;//NSTerminateNow; + else + return NSTerminateCancel; +} + +// To avoid cancelling a log off process, we must use Cocoa termination process +// And this function is the only chance to perform clean up +// So WM_exit needs to be called directly, as the event loop will never run before termination +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + /*G.afbreek = 0; //Let Cocoa perform the termination at the end + WM_exit(C);*/ +} + +- (void)applicationWillBecomeActive:(NSNotification *)aNotification +{ + systemCocoa->handleApplicationBecomeActiveEvent(); +} +@end + + + +#pragma mark initialization/finalization + + +GHOST_SystemCocoa::GHOST_SystemCocoa() +{ + int mib[2]; + struct timeval boottime; + size_t len; + char *rstring = NULL; + + m_modifierMask =0; + m_pressedMouseButtons =0; + m_isGestureInProgress = false; + m_cursorDelta_x=0; + m_cursorDelta_y=0; + m_outsideLoopEventProcessed = false; + m_needDelayedApplicationBecomeActiveEventProcessing = false; + m_displayManager = new GHOST_DisplayManagerCocoa (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n"); + m_displayManager->initialize(); + + //NSEvent timeStamp is given in system uptime, state start date is boot time + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + len = sizeof(struct timeval); + + sysctl(mib, 2, &boottime, &len, NULL, 0); + m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000)); + + //Detect multitouch trackpad + mib[0] = CTL_HW; + mib[1] = HW_MODEL; + sysctl( mib, 2, NULL, &len, NULL, 0 ); + rstring = (char*)malloc( len ); + sysctl( mib, 2, rstring, &len, NULL, 0 ); + + //Hack on MacBook revision, as multitouch avail. function missing + if (strstr(rstring,"MacBookAir") || + (strstr(rstring,"MacBook") && (rstring[strlen(rstring)-3]>='5') && (rstring[strlen(rstring)-3]<='9'))) + m_hasMultiTouchTrackpad = true; + else m_hasMultiTouchTrackpad = false; + + free( rstring ); + rstring = NULL; + + m_ignoreWindowSizedMessages = false; +} + +GHOST_SystemCocoa::~GHOST_SystemCocoa() +{ +} + + +GHOST_TSuccess GHOST_SystemCocoa::init() +{ + + GHOST_TSuccess success = GHOST_System::init(); + if (success) { + //ProcessSerialNumber psn; + + //Carbon stuff to move window & menu to foreground + /*if (!GetCurrentProcess(&psn)) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + }*/ + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if (NSApp == nil) { + [NSApplication sharedApplication]; + + if ([NSApp mainMenu] == nil) { + NSMenu *mainMenubar = [[NSMenu alloc] init]; + NSMenuItem *menuItem; + NSMenu *windowMenu; + NSMenu *appMenu; + + //Create the application menu + appMenu = [[NSMenu alloc] initWithTitle:@"Blender"]; + + [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + + menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + + menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)]; + + [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"]; + [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + + menuItem = [[NSMenuItem alloc] init]; + [menuItem setSubmenu:appMenu]; + + [mainMenubar addItem:menuItem]; + [menuItem release]; + [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; //Needed for 10.5 + [appMenu release]; + + //Create the window menu + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + + [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; + + menuItem = [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"]; + [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + + menuItem = [[NSMenuItem alloc] init]; + [menuItem setSubmenu:windowMenu]; + + [mainMenubar addItem:menuItem]; + [menuItem release]; + + [NSApp setMainMenu:mainMenubar]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenu release]; + } + } + if ([NSApp delegate] == nil) { + CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init]; + [appDelegate setSystemCocoa:this]; + [NSApp setDelegate:appDelegate]; + } + + [NSApp finishLaunching]; + + [pool drain]; + } + return success; +} + + +#pragma mark window management + +GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const +{ + //Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime]) + struct timeval currentTime; + + gettimeofday(¤tTime, NULL); + + //Return timestamp of system uptime + + return ((currentTime.tv_sec*1000)+(currentTime.tv_usec/1000)-m_start_time); +} + + +GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const +{ + //Note that OS X supports monitor hot plug + // We do not support multiple monitors at the moment + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + GHOST_TUns8 count = [[NSScreen screens] count]; + + [pool drain]; + return count; +} + + +void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + //Get visible frame, that is frame excluding dock and top menu bar + NSRect frame = [[NSScreen mainScreen] visibleFrame]; + + //Returns max window contents (excluding title bar...) + NSRect contentRect = [NSWindow contentRectForFrameRect:frame + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)]; + + width = contentRect.size.width; + height = contentRect.size.height; + + [pool drain]; +} + + +GHOST_IWindow* GHOST_SystemCocoa::createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual, + const GHOST_TUns16 numOfAASamples, + const GHOST_TEmbedderWindowID parentWindow +) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_IWindow* window = 0; + + //Get the available rect for including window contents + NSRect frame = [[NSScreen mainScreen] visibleFrame]; + NSRect contentRect = [NSWindow contentRectForFrameRect:frame + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)]; + + //Ensures window top left is inside this available rect + left = left > contentRect.origin.x ? left : contentRect.origin.x; + top = top > contentRect.origin.y ? top : contentRect.origin.y; + + window = new GHOST_WindowCocoa (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples); + + if (window) { + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + //Need to tell window manager the new window is the active one (Cocoa does not send the event activate upon window creation) + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + + } + else { + GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); + delete window; + window = 0; + } + } + else { + GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n"); + } + [pool drain]; + return window; +} + +GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual) +{ + GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow(); + *window = currentWindow; + + if(!currentWindow) return GHOST_kFailure; + + return currentWindow->setState(GHOST_kWindowStateFullScreen); +} + +GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void) +{ + GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow(); + if(!currentWindow) return GHOST_kFailure; + + return currentWindow->setState(GHOST_kWindowStateNormal); +} + + + +/** + * @note : returns coordinates in Cocoa screen coordinates + */ +GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + NSPoint mouseLoc = [NSEvent mouseLocation]; + + // Returns the mouse location in screen coordinates + x = (GHOST_TInt32)mouseLoc.x; + y = (GHOST_TInt32)mouseLoc.y; + return GHOST_kSuccess; +} + +/** + * @note : expect Cocoa screen coordinates + */ +GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) +{ + GHOST_TInt32 wx,wy; + GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)m_windowManager->getActiveWindow(); + if (!window) return GHOST_kFailure; + + //Cursor and mouse dissociation placed here not to interfere with continuous grab + // (in cont. grab setMouseCursorPosition is directly called) + CGAssociateMouseAndMouseCursorPosition(false); + setMouseCursorPosition(x, y); + CGAssociateMouseAndMouseCursorPosition(true); + + //Force mouse move event (not pushed by Cocoa) + window->screenToClient(x, y, wx, wy); + pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, wx,wy)); + m_outsideLoopEventProcessed = true; + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) +{ + float xf=(float)x, yf=(float)y; + GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)m_windowManager->getActiveWindow(); + if (!window) return GHOST_kFailure; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSScreen *windowScreen = window->getScreen(); + NSRect screenRect = [windowScreen frame]; + + //Set position relative to current screen + xf -= screenRect.origin.x; + yf -= screenRect.origin.y; + + //Quartz Display Services uses the old coordinates (top left origin) + yf = screenRect.size.height -yf; + + CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue], CGPointMake(xf, yf)); + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSCommandKeyMask) ? true : false); + keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false); + keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false); + keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false); + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const +{ + buttons.clear(); + buttons.set(GHOST_kButtonMaskLeft, m_pressedMouseButtons & GHOST_kButtonMaskLeft); + buttons.set(GHOST_kButtonMaskRight, m_pressedMouseButtons & GHOST_kButtonMaskRight); + buttons.set(GHOST_kButtonMaskMiddle, m_pressedMouseButtons & GHOST_kButtonMaskMiddle); + buttons.set(GHOST_kButtonMaskButton4, m_pressedMouseButtons & GHOST_kButtonMaskButton4); + buttons.set(GHOST_kButtonMaskButton5, m_pressedMouseButtons & GHOST_kButtonMaskButton5); + return GHOST_kSuccess; +} + + + +#pragma mark Event handlers + +/** + * The event queue polling function + */ +bool GHOST_SystemCocoa::processEvents(bool waitForEvent) +{ + bool anyProcessed = false; + NSEvent *event; + + // SetMouseCoalescingEnabled(false, NULL); + //TODO : implement timer ?? + + /*do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent) { + GHOST_TUns64 next = timerMgr->nextFireTime(); + double timeOut; + + if (next == GHOST_kFireTimeNever) { + timeOut = kEventDurationForever; + } else { + timeOut = (double)(next - getMilliSeconds())/1000.0; + if (timeOut < 0.0) + timeOut = 0.0; + } + + ::ReceiveNextEvent(0, NULL, timeOut, false, &event); + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + }*/ + + do { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event==nil) { + [pool drain]; + break; + } + + anyProcessed = true; + + switch ([event type]) { + case NSKeyDown: + case NSKeyUp: + case NSFlagsChanged: + handleKeyEvent(event); + + /* Support system-wide keyboard shortcuts, like Exposé, ...) =>included in always NSApp sendEvent */ + /* if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) { + [NSApp sendEvent:event]; + }*/ + break; + + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSRightMouseDown: + case NSRightMouseUp: + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSScrollWheel: + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSOtherMouseDragged: + case NSEventTypeMagnify: + case NSEventTypeRotate: + case NSEventTypeBeginGesture: + case NSEventTypeEndGesture: + handleMouseEvent(event); + break; + + case NSTabletPoint: + case NSTabletProximity: + handleTabletEvent(event,[event type]); + break; + + /* Trackpad features, fired only from OS X 10.5.2 + case NSEventTypeGesture: + case NSEventTypeSwipe: + break; */ + + /*Unused events + NSMouseEntered = 8, + NSMouseExited = 9, + NSAppKitDefined = 13, + NSSystemDefined = 14, + NSApplicationDefined = 15, + NSPeriodic = 16, + NSCursorUpdate = 17,*/ + + default: + break; + } + //Resend event to NSApp to ensure Mac wide events are handled + [NSApp sendEvent:event]; + [pool drain]; + } while (event!= nil); + //} while (waitForEvent && !anyProcessed); Needed only for timer implementation + + if (m_needDelayedApplicationBecomeActiveEventProcessing) handleApplicationBecomeActiveEvent(); + + if (m_outsideLoopEventProcessed) { + m_outsideLoopEventProcessed = false; + return true; + } + + m_ignoreWindowSizedMessages = false; + + return anyProcessed; +} + +//Note: called from NSApplication delegate +GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent() +{ + //Update the modifiers key mask, as its status may have changed when the application was not active + //(that is when update events are sent to another application) + unsigned int modifiers; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + + if (!window) { + m_needDelayedApplicationBecomeActiveEventProcessing = true; + return GHOST_kFailure; + } + else m_needDelayedApplicationBecomeActiveEventProcessing = false; + + modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags]; + + if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + } + if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + } + if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + } + if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); + } + + m_modifierMask = modifiers; + + m_outsideLoopEventProcessed = true; + return GHOST_kSuccess; +} + +//Note: called from NSWindow delegate +GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window) +{ + if (!validWindow(window)) { + return GHOST_kFailure; + } + switch(eventType) + { + case GHOST_kEventWindowClose: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) ); + break; + case GHOST_kEventWindowActivate: + m_windowManager->setActiveWindow(window); + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) ); + break; + case GHOST_kEventWindowDeactivate: + m_windowManager->setWindowInactive(window); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); + break; + case GHOST_kEventWindowUpdate: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + break; + case GHOST_kEventWindowMove: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, window) ); + break; + case GHOST_kEventWindowSize: + if (!m_ignoreWindowSizedMessages) + { + //Enforce only one resize message per event loop (coalescing all the live resize messages) + window->updateDrawingContext(); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + //Mouse up event is trapped by the resizing event loop, so send it anyway to the window manager + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, convertButton(0))); + m_ignoreWindowSizedMessages = true; + } + break; + default: + return GHOST_kFailure; + break; + } + + m_outsideLoopEventProcessed = true; + return GHOST_kSuccess; +} + +//Note: called from NSWindow subclass +GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, + GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data) +{ + if (!validWindow(window)) { + return GHOST_kFailure; + } + switch(eventType) + { + case GHOST_kEventDraggingEntered: + case GHOST_kEventDraggingUpdated: + case GHOST_kEventDraggingExited: + pushEvent(new GHOST_EventDragnDrop(getMilliSeconds(),eventType,draggedObjectType,window,mouseX,mouseY,NULL)); + break; + + case GHOST_kEventDraggingDropDone: + { + GHOST_TUns8 * temp_buff; + GHOST_TStringArray *strArray; + NSArray *droppedArray; + size_t pastedTextSize; + NSString *droppedStr; + GHOST_TEventDataPtr eventData; + int i; + + if (!data) return GHOST_kFailure; + + switch (draggedObjectType) { + case GHOST_kDragnDropTypeFilenames: + droppedArray = (NSArray*)data; + + strArray = (GHOST_TStringArray*)malloc(sizeof(GHOST_TStringArray)); + if (!strArray) return GHOST_kFailure; + + strArray->count = [droppedArray count]; + if (strArray->count == 0) return GHOST_kFailure; + + strArray->strings = (GHOST_TUns8**) malloc(strArray->count*sizeof(GHOST_TUns8*)); + + for (i=0;icount;i++) + { + droppedStr = [droppedArray objectAtIndex:i]; + + pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); + + if (!temp_buff) { + strArray->count = i; + break; + } + + strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize); + temp_buff[pastedTextSize] = '\0'; + + strArray->strings[i] = temp_buff; + } + + eventData = (GHOST_TEventDataPtr) strArray; + break; + + case GHOST_kDragnDropTypeString: + droppedStr = (NSString*)data; + pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); + + if (temp_buff == NULL) { + return GHOST_kFailure; + } + + strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize); + + temp_buff[pastedTextSize] = '\0'; + + eventData = (GHOST_TEventDataPtr) temp_buff; + break; + + case GHOST_kDragnDropTypeBitmap: + { + NSImage *droppedImg = (NSImage*)data; + NSSize imgSize = [droppedImg size]; + ImBuf *ibuf = NULL; + GHOST_TUns8 *rasterRGB = NULL; + GHOST_TUns8 *rasterRGBA = NULL; + GHOST_TUns8 *toIBuf = NULL; + int x, y, to_i, from_i; + NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA,*bitmapImage=nil; + NSEnumerator *enumerator; + NSImageRep *representation; + + ibuf = IMB_allocImBuf (imgSize.width , imgSize.height, 32, IB_rect); + if (!ibuf) { + [droppedImg release]; + return GHOST_kFailure; + } + + /*Get the bitmap of the image*/ + enumerator = [[droppedImg representations] objectEnumerator]; + while ((representation = [enumerator nextObject])) { + if ([representation isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImage = (NSBitmapImageRep *)representation; + break; + } + } + if (bitmapImage == nil) return GHOST_kFailure; + + if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) + && ![bitmapImage isPlanar]) { + /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/ + toIBuf = (GHOST_TUns8*)ibuf->rect; + rasterRGB = (GHOST_TUns8*)[bitmapImage bitmapData]; + for (y = 0; y < imgSize.height; y++) { + to_i = (imgSize.height-y-1)*imgSize.width; + from_i = y*imgSize.width; + memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*imgSize.width); + } + } + else { + /* Tell cocoa image resolution is same as current system one */ + [bitmapImage setSize:imgSize]; + + /* Convert the image in a RGBA 32bit format */ + /* As Core Graphics does not support contextes with non premutliplied alpha, + we need to get alpha key values in a separate batch */ + + /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */ + blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:imgSize.width + pixelsHigh:imgSize.height + bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:(NSBitmapFormat)0 + bytesPerRow:4*imgSize.width + bitsPerPixel:32/*RGB format padded to 32bits*/]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]]; + [bitmapImage draw]; + [NSGraphicsContext restoreGraphicsState]; + + rasterRGB = (GHOST_TUns8*)[blBitmapFormatImageRGB bitmapData]; + if (rasterRGB == NULL) { + [bitmapImage release]; + [blBitmapFormatImageRGB release]; + [droppedImg release]; + return GHOST_kFailure; + } + + /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */ + blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:imgSize.width + pixelsHigh:imgSize.height + bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:(NSBitmapFormat)0 + bytesPerRow:4*imgSize.width + bitsPerPixel:32/* RGBA */]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]]; + [bitmapImage draw]; + [NSGraphicsContext restoreGraphicsState]; + + rasterRGBA = (GHOST_TUns8*)[blBitmapFormatImageRGBA bitmapData]; + if (rasterRGBA == NULL) { + [bitmapImage release]; + [blBitmapFormatImageRGB release]; + [blBitmapFormatImageRGBA release]; + [droppedImg release]; + return GHOST_kFailure; + } + + /*Copy the image to ibuf, flipping it vertically*/ + toIBuf = (GHOST_TUns8*)ibuf->rect; + for (y = 0; y < imgSize.height; y++) { + for (x = 0; x < imgSize.width; x++) { + to_i = (imgSize.height-y-1)*imgSize.width + x; + from_i = y*imgSize.width + x; + + toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */ + toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */ + toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */ + toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */ + } + } + + [blBitmapFormatImageRGB release]; + [blBitmapFormatImageRGBA release]; + [droppedImg release]; + } + + eventData = (GHOST_TEventDataPtr) ibuf; + } + break; + + default: + return GHOST_kFailure; + break; + } + pushEvent(new GHOST_EventDragnDrop(getMilliSeconds(),eventType,draggedObjectType,window,mouseX,mouseY,eventData)); + } + break; + default: + return GHOST_kFailure; + } + m_outsideLoopEventProcessed = true; + return GHOST_kSuccess; +} + + +GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest() +{ + GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow(); + + //Discard quit event if we are in cursor grab sequence + if (window && (window->getCursorGrabMode() != GHOST_kGrabDisable) && (window->getCursorGrabMode() != GHOST_kGrabNormal)) + return GHOST_kExitCancel; + + //Check open windows if some changes are not saved + if (m_windowManager->getAnyModifiedState()) + { + int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved.\nDo you really want to quit ?", + @"Cancel", @"Quit Anyway", nil); + if (shouldQuit == NSAlertAlternateReturn) + { + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) ); + return GHOST_kExitNow; + } else { + //Give back focus to the blender window if user selected cancel quit + NSArray *windowsList = [NSApp orderedWindows]; + if ([windowsList count]) { + [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; + //Handle the modifiers keyes changed state issue + //as recovering from the quit dialog is like application + //gaining focus back. + //Main issue fixed is Cmd modifier not being cleared + handleApplicationBecomeActiveEvent(); + } + } + + } + else { + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) ); + m_outsideLoopEventProcessed = true; + return GHOST_kExitNow; + } + + return GHOST_kExitCancel; +} + +bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr) +{ + NSString *filepath = (NSString*)filepathStr; + int confirmOpen = NSAlertAlternateReturn; + NSArray *windowsList; + char * temp_buff; + size_t filenameTextSize; + GHOST_Window* window= (GHOST_Window*)m_windowManager->getActiveWindow(); + + if (!window) { + return NO; + } + + //Discard event if we are in cursor grab sequence, it'll lead to "stuck cursor" situation if the alert panel is raised + if (window && (window->getCursorGrabMode() != GHOST_kGrabDisable) && (window->getCursorGrabMode() != GHOST_kGrabNormal)) + return GHOST_kExitCancel; + + //Check open windows if some changes are not saved + if (m_windowManager->getAnyModifiedState()) + { + confirmOpen = NSRunAlertPanel([NSString stringWithFormat:@"Opening %@",[filepath lastPathComponent]], + @"Current document has not been saved.\nDo you really want to proceed?", + @"Cancel", @"Open", nil); + } + + //Give back focus to the blender window + windowsList = [NSApp orderedWindows]; + if ([windowsList count]) { + [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; + } + + if (confirmOpen == NSAlertAlternateReturn) + { + filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + temp_buff = (char*) malloc(filenameTextSize+1); + + if (temp_buff == NULL) { + return GHOST_kFailure; + } + + strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize); + + temp_buff[filenameTextSize] = '\0'; + + pushEvent(new GHOST_EventString(getMilliSeconds(),GHOST_kEventOpenMainFile,window,(GHOST_TEventDataPtr) temp_buff)); + + return YES; + } + else return NO; +} + +GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType) +{ + NSEvent *event = (NSEvent *)eventPtr; + GHOST_IWindow* window; + + window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]); + if (!window) { + //printf("\nW failure for event 0x%x",[event type]); + return GHOST_kFailure; + } + + GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData(); + + switch (eventType) { + case NSTabletPoint: + ct.Pressure = [event pressure]; + ct.Xtilt = [event tilt].x; + ct.Ytilt = [event tilt].y; + break; + + case NSTabletProximity: + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; + if ([event isEnteringProximity]) + { + //pointer is entering tablet area proximity + switch ([event pointingDeviceType]) { + case NSPenPointingDevice: + ct.Active = GHOST_kTabletModeStylus; + break; + case NSEraserPointingDevice: + ct.Active = GHOST_kTabletModeEraser; + break; + case NSCursorPointingDevice: + case NSUnknownPointingDevice: + default: + ct.Active = GHOST_kTabletModeNone; + break; + } + } else { + // pointer is leaving - return to mouse + ct.Active = GHOST_kTabletModeNone; + } + break; + + default: + GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received"); + return GHOST_kFailure; + break; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) +{ + NSEvent *event = (NSEvent *)eventPtr; + GHOST_Window* window; + + window = (GHOST_Window*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]); + if (!window) { + //printf("\nW failure for event 0x%x",[event type]); + return GHOST_kFailure; + } + + switch ([event type]) + { + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } + break; + + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: + pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } + break; + + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } + + case NSMouseMoved: + switch (window->getCursorGrabMode()) { + case GHOST_kGrabHide: //Cursor hidden grab operation : no cursor move + { + GHOST_TInt32 x_warp, y_warp, x_accum, y_accum; + + window->getCursorGrabInitPos(x_warp, y_warp); + + window->getCursorGrabAccum(x_accum, y_accum); + x_accum += [event deltaX]; + y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ... + window->setCursorGrabAccum(x_accum, y_accum); + + pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); + } + break; + case GHOST_kGrabWrap: //Wrap cursor at area/window boundaries + { + NSPoint mousePos = [event locationInWindow]; + GHOST_TInt32 x_mouse= mousePos.x; + GHOST_TInt32 y_mouse= mousePos.y; + GHOST_TInt32 x_accum, y_accum, x_cur, y_cur; + GHOST_Rect bounds, windowBounds, correctedBounds; + + /* fallback to window bounds */ + if(window->getCursorGrabBounds(bounds)==GHOST_kFailure) + window->getClientBounds(bounds); + + //Switch back to Cocoa coordinates orientation (y=0 at botton,the same as blender internal btw!), and to client coordinates + window->getClientBounds(windowBounds); + window->screenToClient(bounds.m_l,bounds.m_b, correctedBounds.m_l, correctedBounds.m_t); + window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b); + correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b; + correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t; + + //Update accumulation counts + window->getCursorGrabAccum(x_accum, y_accum); + x_accum += [event deltaX]-m_cursorDelta_x; + y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ... + window->setCursorGrabAccum(x_accum, y_accum); + + + //Warp mouse cursor if needed + x_mouse += [event deltaX]-m_cursorDelta_x; + y_mouse += -[event deltaY]-m_cursorDelta_y; + correctedBounds.wrapPoint(x_mouse, y_mouse, 2); + + //Compensate for mouse moved event taking cursor position set into account + m_cursorDelta_x = x_mouse-mousePos.x; + m_cursorDelta_y = y_mouse-mousePos.y; + + //Set new cursor position + window->clientToScreen(x_mouse, y_mouse, x_cur, y_cur); + setMouseCursorPosition(x_cur, y_cur); /* wrap */ + + //Post event + window->getCursorGrabInitPos(x_cur, y_cur); + pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x_cur + x_accum, y_cur + y_accum)); + } + break; + default: + { + //Normal cursor operation: send mouse position in window + NSPoint mousePos = [event locationInWindow]; + pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + m_cursorDelta_x=0; + m_cursorDelta_y=0; //Mouse motion occurred between two cursor warps, so we can reset the delta counter + } + break; + } + break; + + case NSScrollWheel: + { + /* Send trackpad event if inside a trackpad gesture, send wheel event otherwise */ + if (!m_hasMultiTouchTrackpad || !m_isGestureInProgress) { + GHOST_TInt32 delta; + + double deltaF = [event deltaY]; + if (deltaF == 0.0) break; //discard trackpad delta=0 events + + delta = deltaF > 0.0 ? 1 : -1; + pushEvent(new GHOST_EventWheel([event timestamp]*1000, window, delta)); + } + else { + NSPoint mousePos = [event locationInWindow]; + double dx = [event deltaX]; + double dy = -[event deltaY]; + + const double deltaMax = 50.0; + + if ((dx == 0) && (dy == 0)) break; + + /* Quadratic acceleration */ + dx = dx*(fabs(dx)+0.5); + if (dx<0.0) dx-=0.5; else dx+=0.5; + if (dx< -deltaMax) dx= -deltaMax; else if (dx>deltaMax) dx=deltaMax; + + dy = dy*(fabs(dy)+0.5); + if (dy<0.0) dy-=0.5; else dy+=0.5; + if (dy< -deltaMax) dy= -deltaMax; else if (dy>deltaMax) dy=deltaMax; + + pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventScroll, mousePos.x, mousePos.y, dx, dy)); + } + } + break; + + case NSEventTypeMagnify: + { + NSPoint mousePos = [event locationInWindow]; + pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventMagnify, mousePos.x, mousePos.y, + [event magnification]*250.0 + 0.1, 0)); + } + break; + + case NSEventTypeRotate: + { + NSPoint mousePos = [event locationInWindow]; + pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventRotate, mousePos.x, mousePos.y, + -[event rotation] * 5.0, 0)); + } + case NSEventTypeBeginGesture: + m_isGestureInProgress = true; + break; + case NSEventTypeEndGesture: + m_isGestureInProgress = false; + break; + default: + return GHOST_kFailure; + break; + } + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) +{ + NSEvent *event = (NSEvent *)eventPtr; + GHOST_IWindow* window; + unsigned int modifiers; + NSString *characters; + NSData *convertedCharacters; + GHOST_TKey keyCode; + unsigned char ascii; + NSString* charsIgnoringModifiers; + + window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]); + if (!window) { + //printf("\nW failure for event 0x%x",[event type]); + return GHOST_kFailure; + } + + switch ([event type]) { + case NSKeyDown: + case NSKeyUp: + charsIgnoringModifiers = [event charactersIgnoringModifiers]; + if ([charsIgnoringModifiers length]>0) + keyCode = convertKey([event keyCode], + [charsIgnoringModifiers characterAtIndex:0], + [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp); + else + keyCode = convertKey([event keyCode],0, + [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp); + + + characters = [event characters]; + if ([characters length]>0) { //Check for dead keys + //Convert characters to iso latin 1 encoding + convertedCharacters = [characters dataUsingEncoding:NSISOLatin1StringEncoding]; + if ([convertedCharacters length]>0) + ascii =((char*)[convertedCharacters bytes])[0]; + else + ascii = 0; //Character not available in iso latin 1 encoding + } + else + ascii= 0; + + if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask)) + break; //Cmd-Q is directly handled by Cocoa + + if ([event type] == NSKeyDown) { + pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyDown, window, keyCode, ascii) ); + //printf("\nKey down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii); + } else { + pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyUp, window, keyCode, ascii) ); + //printf("\nKey up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii); + } + break; + + case NSFlagsChanged: + modifiers = [event modifierFlags]; + + if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) { + pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + } + if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) { + pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + } + if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) { + pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + } + if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) { + pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); + } + + m_modifierMask = modifiers; + break; + + default: + return GHOST_kFailure; + break; + } + + return GHOST_kSuccess; +} + + + +#pragma mark Clipboard get/set + +GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const +{ + GHOST_TUns8 * temp_buff; + size_t pastedTextSize; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + + if (pasteBoard == nil) { + [pool drain]; + return NULL; + } + + NSArray *supportedTypes = + [NSArray arrayWithObjects: NSStringPboardType, nil]; + + NSString *bestType = [[NSPasteboard generalPasteboard] + availableTypeFromArray:supportedTypes]; + + if (bestType == nil) { + [pool drain]; + return NULL; + } + + NSString * textPasted = [pasteBoard stringForType:NSStringPboardType]; + + if (textPasted == nil) { + [pool drain]; + return NULL; + } + + pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]; + + temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); + + if (temp_buff == NULL) { + [pool drain]; + return NULL; + } + + strncpy((char*)temp_buff, [textPasted cStringUsingEncoding:NSISOLatin1StringEncoding], pastedTextSize); + + temp_buff[pastedTextSize] = '\0'; + + [pool drain]; + + if(temp_buff) { + return temp_buff; + } else { + return NULL; + } +} + +void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const +{ + NSString *textToCopy; + + if(selection) {return;} // for copying the selection, used on X11 + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + + if (pasteBoard == nil) { + [pool drain]; + return; + } + + NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType]; + + [pasteBoard declareTypes:supportedTypes owner:nil]; + + textToCopy = [NSString stringWithCString:buffer encoding:NSISOLatin1StringEncoding]; + + [pasteBoard setString:textToCopy forType:NSStringPboardType]; + + [pool drain]; +} + diff --git a/intern/ghost/intern/GHOST_SystemPaths.h b/intern/ghost/intern/GHOST_SystemPaths.h new file mode 100644 index 00000000000..94cb44c660b --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPaths.h @@ -0,0 +1,84 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPaths.h + * \ingroup GHOST + */ + +#ifndef _GHOST_SYSTEMPATHS_H_ +#define _GHOST_SYSTEMPATHS_H_ + +#include "GHOST_ISystemPaths.h" + +class GHOST_SystemPaths : public GHOST_ISystemPaths +{ +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_SystemPaths(){}; + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_SystemPaths(){}; + +public: + + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ + virtual const GHOST_TUns8* getSystemDir() const = 0; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/.blender/). + */ + virtual const GHOST_TUns8* getUserDir() const = 0; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + virtual const GHOST_TUns8* getBinaryDir() const = 0; + + /** + * Add the file to the operating system most recently used files + */ + virtual void addToSystemRecentFiles(const char* filename) const = 0; + +}; + +#endif + + diff --git a/intern/ghost/intern/GHOST_SystemPathsCarbon.cpp b/intern/ghost/intern/GHOST_SystemPathsCarbon.cpp new file mode 100644 index 00000000000..dc83e4b0eb6 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsCarbon.cpp @@ -0,0 +1,88 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Damien Plisson 2010 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsCarbon.cpp + * \ingroup GHOST + */ + + +#include +#include +#include "GHOST_SystemPathsCarbon.h" + + +/***/ + +GHOST_SystemPathsCarbon::GHOST_SystemPathsCarbon() +{ +} + +GHOST_SystemPathsCarbon::~GHOST_SystemPathsCarbon() +{ +} + +const GHOST_TUns8* GHOST_SystemPathsCarbon::getSystemDir() const +{ + return (GHOST_TUns8*)"/Library/Application Support"; +} + +const GHOST_TUns8* GHOST_SystemPathsCarbon::getUserDir() const +{ + static char usrPath[256] = ""; + char* env = getenv("HOME"); + + if (env) { + strncpy(usrPath, env, 245); + usrPath[245]=0; + strcat(usrPath, "/Library/Application Support"); + return (GHOST_TUns8*) usrPath; + } + else + return NULL; +} + +const GHOST_TUns8* GHOST_SystemPathsCarbon::getBinaryDir() const +{ + CFURLRef bundleURL; + CFStringRef pathStr; + static char path[256]; + CFBundleRef mainBundle = CFBundleGetMainBundle(); + + bundleURL = CFBundleCopyBundleURL(mainBundle); + pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); + CFStringGetCString(pathStr, path, 255, kCFStringEncodingASCII); + CFRelease(pathStr); + CFRelease(bundleURL); + return (GHOST_TUns8*)path; +} + +void GHOST_SystemPathsCarbon::addToSystemRecentFiles(const char* filename) const +{ + /* XXXXX TODO: Implementation for Carbon if possible */ + +} diff --git a/intern/ghost/intern/GHOST_SystemPathsCarbon.h b/intern/ghost/intern/GHOST_SystemPathsCarbon.h new file mode 100644 index 00000000000..b48ab6c033b --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsCarbon.h @@ -0,0 +1,92 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Damien Plisson 2010 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsCarbon.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_SYSTEM_PATHS_CARBON_H_ +#define _GHOST_SYSTEM_PATHS_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#include + +#include "GHOST_SystemPaths.h" + +/** + * OSX/Carbon Implementation of GHOST_SystemPaths class. + * @see GHOST_System. + * @author Andrea Weikert + * @date Aug 1, 2010 + */ +class GHOST_SystemPathsCarbon : public GHOST_SystemPaths { +public: + /** + * Constructor. + */ + GHOST_SystemPathsCarbon(); + + /** + * Destructor. + */ + ~GHOST_SystemPathsCarbon(); + + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ + virtual const GHOST_TUns8* getSystemDir() const; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/.blender/). + */ + virtual const GHOST_TUns8* getUserDir() const; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + virtual const GHOST_TUns8* getBinaryDir() const; + + /** + * Add the file to the operating system most recently used files + */ + void addToSystemRecentFiles(const char* filename) const; +}; + +#endif // _GHOST_SYSTEM_CARBON_H_ + + + diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.h b/intern/ghost/intern/GHOST_SystemPathsCocoa.h new file mode 100644 index 00000000000..b270896a8ca --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.h @@ -0,0 +1,84 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Damien Plisson 2010 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsCocoa.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_SYSTEM_PATHS_COCOA_H_ +#define _GHOST_SYSTEM_PATHS_COCOA_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + + +#include "GHOST_SystemPaths.h" + + +class GHOST_SystemPathsCocoa : public GHOST_SystemPaths { +public: + /** + * Constructor. + */ + GHOST_SystemPathsCocoa(); + + /** + * Destructor. + */ + ~GHOST_SystemPathsCocoa(); + + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ + virtual const GHOST_TUns8* getSystemDir() const; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/.blender/). + */ + virtual const GHOST_TUns8* getUserDir() const; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + virtual const GHOST_TUns8* getBinaryDir() const; + + /** + * Add the file to the operating system most recently used files + */ + void addToSystemRecentFiles(const char* filename) const; +}; + +#endif // _GHOST_SYSTEM_COCOA_H_ + diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm new file mode 100644 index 00000000000..238ce1a46c7 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm @@ -0,0 +1,121 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Damien Plisson 2010 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#import + +/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/ +#include + +#include +#include +#include + +#include "GHOST_SystemPathsCocoa.h" + + +#pragma mark initialization/finalization + + +GHOST_SystemPathsCocoa::GHOST_SystemPathsCocoa() +{ +} + +GHOST_SystemPathsCocoa::~GHOST_SystemPathsCocoa() +{ +} + + +#pragma mark Base directories retrieval + +const GHOST_TUns8* GHOST_SystemPathsCocoa::getSystemDir() const +{ + static GHOST_TUns8 tempPath[512] = ""; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSString *basePath; + NSArray *paths; + + paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, YES); + + if ([paths count] > 0) + basePath = [paths objectAtIndex:0]; + else { + [pool drain]; + return NULL; + } + + strcpy((char*)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]); + + [pool drain]; + return tempPath; +} + +const GHOST_TUns8* GHOST_SystemPathsCocoa::getUserDir() const +{ + static GHOST_TUns8 tempPath[512] = ""; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSString *basePath; + NSArray *paths; + + paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + + if ([paths count] > 0) + basePath = [paths objectAtIndex:0]; + else { + [pool drain]; + return NULL; + } + + strcpy((char*)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]); + + [pool drain]; + return tempPath; +} + +const GHOST_TUns8* GHOST_SystemPathsCocoa::getBinaryDir() const +{ + static GHOST_TUns8 tempPath[512] = ""; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSString *basePath; + + basePath = [[NSBundle mainBundle] bundlePath]; + + if (basePath == nil) { + [pool drain]; + return NULL; + } + + strcpy((char*)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]); + + [pool drain]; + return tempPath; +} + +void GHOST_SystemPathsCocoa::addToSystemRecentFiles(const char* filename) const +{ + /* XXXXX TODO: Implementation for X11 if possible */ +} diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp new file mode 100644 index 00000000000..becccc2c29f --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp @@ -0,0 +1,115 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * Andrea Weikert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsWin32.cpp + * \ingroup GHOST + */ + + +#include "GHOST_SystemPathsWin32.h" + +#define WIN32_LEAN_AND_MEAN +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 +#include +#include + +#if defined(__MINGW32__) || defined(__CYGWIN__) + +#if !defined(SHARD_PIDL) +#define SHARD_PIDL 0x00000001L +#endif + +#if !defined(SHARD_PATHA) +#define SHARD_PATHA 0x00000002L +#endif + +#if !defined(SHARD_PATHA) +#define SHARD_PATHW 0x00000003L +#endif + +#if !defined(SHARD_PATH) +#ifdef UNICODE +#define SHARD_PATH SHARD_PATHW +#else +#define SHARD_PATH SHARD_PATHA +#endif +#endif + +#endif + +GHOST_SystemPathsWin32::GHOST_SystemPathsWin32() +{ +} + +GHOST_SystemPathsWin32::~GHOST_SystemPathsWin32() +{ +} + +const GHOST_TUns8* GHOST_SystemPathsWin32::getSystemDir() const +{ + static char knownpath[MAX_PATH]; + HRESULT hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath); + + if (hResult == S_OK) + { + return (GHOST_TUns8*)knownpath; + } + + return NULL; +} + +const GHOST_TUns8* GHOST_SystemPathsWin32::getUserDir() const +{ + static char knownpath[MAX_PATH]; + HRESULT hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath); + + if (hResult == S_OK) + { + return (GHOST_TUns8*)knownpath; + } + + return NULL; +} + +const GHOST_TUns8* GHOST_SystemPathsWin32::getBinaryDir() const +{ + static char fullname[MAX_PATH]; + if(GetModuleFileName(0, fullname, MAX_PATH)) { + return (GHOST_TUns8*)fullname; + } + + return NULL; +} + +void GHOST_SystemPathsWin32::addToSystemRecentFiles(const char* filename) const +{ + /* SHARD_PATH resolves to SHARD_PATHA for non-UNICODE build */ + SHAddToRecentDocs(SHARD_PATH,filename); +} diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.h b/intern/ghost/intern/GHOST_SystemPathsWin32.h new file mode 100644 index 00000000000..67cc2140e0e --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.h @@ -0,0 +1,91 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsWin32.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_SYSTEM_PATHS_WIN32_H_ +#define _GHOST_SYSTEM_PATHS_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include + +#include "GHOST_SystemPaths.h" + + +/** + * WIN32 Implementation of GHOST_SystemPaths class. + * @see GHOST_SystemPaths. + * @author Andrea Weikert + * @date August 1, 2010 + */ +class GHOST_SystemPathsWin32 : public GHOST_SystemPaths { +public: + /** + * Constructor. + */ + GHOST_SystemPathsWin32(); + + /** + * Destructor. + */ + virtual ~GHOST_SystemPathsWin32(); + + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/). + */ + const GHOST_TUns8* getSystemDir() const; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/). + */ + const GHOST_TUns8* getUserDir() const; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + const GHOST_TUns8* getBinaryDir() const; + + /** + * Add the file to the operating system most recently used files + */ + void addToSystemRecentFiles(const char* filename) const; +}; + +#endif // _GHOST_SYSTEM_PATHS_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_SystemPathsX11.cpp b/intern/ghost/intern/GHOST_SystemPathsX11.cpp new file mode 100644 index 00000000000..dd8935732c5 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsX11.cpp @@ -0,0 +1,85 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsX11.cpp + * \ingroup GHOST + */ + + +#include "GHOST_SystemPathsX11.h" + +#include "GHOST_Debug.h" + +// For timing + +#include +#include + +#include // for fprintf only +#include // for exit + +using namespace std; + +GHOST_SystemPathsX11::GHOST_SystemPathsX11() +{ +} + +GHOST_SystemPathsX11::~GHOST_SystemPathsX11() +{ +} + +const GHOST_TUns8* GHOST_SystemPathsX11::getSystemDir() const +{ + /* no prefix assumes a portable build which only uses bundled scripts */ +#ifdef PREFIX + return (GHOST_TUns8*) PREFIX "/share"; +#else + return NULL; +#endif +} + +const GHOST_TUns8* GHOST_SystemPathsX11::getUserDir() const +{ + const char* env = getenv("HOME"); + if(env) { + return (GHOST_TUns8*) env; + } else { + return NULL; + } +} + +const GHOST_TUns8* GHOST_SystemPathsX11::getBinaryDir() const +{ + return NULL; +} + +void GHOST_SystemPathsX11::addToSystemRecentFiles(const char* filename) const +{ + /* XXXXX TODO: Implementation for X11 if possible */ + +} diff --git a/intern/ghost/intern/GHOST_SystemPathsX11.h b/intern/ghost/intern/GHOST_SystemPathsX11.h new file mode 100644 index 00000000000..56862398c74 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemPathsX11.h @@ -0,0 +1,82 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemPathsX11.h + * \ingroup GHOST + */ + + +#ifndef _GHOST_SYSTEM_PATHS_X11_H_ +#define _GHOST_SYSTEM_PATHS_X11_H_ + +#include "GHOST_SystemPaths.h" +#include "../GHOST_Types.h" + + +class GHOST_SystemPathsX11 : public GHOST_SystemPaths { +public: + + /** + * Constructor + * this class should only be instanciated by GHOST_ISystem. + */ + GHOST_SystemPathsX11(); + + /** + * Destructor. + */ + virtual ~GHOST_SystemPathsX11(); + + /** + * Determine the base dir in which shared resources are located. It will first try to use + * "unpack and run" path, then look for properly installed path, not including versioning. + * @return Unsigned char string pointing to system dir (eg /usr/share/blender/). + */ + const GHOST_TUns8* getSystemDir() const; + + /** + * Determine the base dir in which user configuration is stored, not including versioning. + * If needed, it will create the base directory. + * @return Unsigned char string pointing to user dir (eg ~/.blender/). + */ + const GHOST_TUns8* getUserDir() const; + + /** + * Determine the directory of the current binary + * @return Unsigned char string pointing to the binary dir + */ + const GHOST_TUns8* getBinaryDir() const; + + /** + * Add the file to the operating system most recently used files + */ + void addToSystemRecentFiles(const char* filename) const; +}; + +#endif + diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp new file mode 100644 index 00000000000..455a166ece0 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -0,0 +1,1257 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemWin32.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#include + +#ifdef FREE_WINDOWS +# define _WIN32_WINNT 0x0500 /* GetConsoleWindow() for MinGW */ +#endif + +#include "GHOST_SystemWin32.h" +#include "GHOST_EventDragnDrop.h" + +#define WIN32_LEAN_AND_MEAN +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 +#include +#include + +// win64 doesn't define GWL_USERDATA +#ifdef WIN32 +#ifndef GWL_USERDATA +#define GWL_USERDATA GWLP_USERDATA +#define GWL_WNDPROC GWLP_WNDPROC +#endif +#endif + +/* + * According to the docs the mouse wheel message is supported from windows 98 + * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the + * wheel detent value are undefined. + */ +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif // WM_MOUSEWHEEL +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */ +#endif // WHEEL_DELTA + +/* + * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2. + * MSDN: Declared in Winuser.h, include Windows.h + * This does not seem to work with MinGW so we define our own here. + */ +#ifndef XBUTTON1 +#define XBUTTON1 0x0001 +#endif // XBUTTON1 +#ifndef XBUTTON2 +#define XBUTTON2 0x0002 +#endif // XBUTTON2 +#ifndef WM_XBUTTONUP +#define WM_XBUTTONUP 524 +#endif // WM_XBUTTONUP +#ifndef WM_XBUTTONDOWN +#define WM_XBUTTONDOWN 523 +#endif // WM_XBUTTONDOWN + +#include "GHOST_Debug.h" +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventWheel.h" +#include "GHOST_EventNDOF.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowWin32.h" +#include "GHOST_NDOFManager.h" + +// Key code values not found in winuser.h +#ifndef VK_MINUS +#define VK_MINUS 0xBD +#endif // VK_MINUS +#ifndef VK_SEMICOLON +#define VK_SEMICOLON 0xBA +#endif // VK_SEMICOLON +#ifndef VK_PERIOD +#define VK_PERIOD 0xBE +#endif // VK_PERIOD +#ifndef VK_COMMA +#define VK_COMMA 0xBC +#endif // VK_COMMA +#ifndef VK_QUOTE +#define VK_QUOTE 0xDE +#endif // VK_QUOTE +#ifndef VK_BACK_QUOTE +#define VK_BACK_QUOTE 0xC0 +#endif // VK_BACK_QUOTE +#ifndef VK_SLASH +#define VK_SLASH 0xBF +#endif // VK_SLASH +#ifndef VK_BACK_SLASH +#define VK_BACK_SLASH 0xDC +#endif // VK_BACK_SLASH +#ifndef VK_EQUALS +#define VK_EQUALS 0xBB +#endif // VK_EQUALS +#ifndef VK_OPEN_BRACKET +#define VK_OPEN_BRACKET 0xDB +#endif // VK_OPEN_BRACKET +#ifndef VK_CLOSE_BRACKET +#define VK_CLOSE_BRACKET 0xDD +#endif // VK_CLOSE_BRACKET +#ifndef VK_GR_LESS +#define VK_GR_LESS 0xE2 +#endif // VK_GR_LESS + +#ifndef VK_MEDIA_NEXT_TRACK +#define VK_MEDIA_NEXT_TRACK 0xB0 +#endif // VK_MEDIA_NEXT_TRACK +#ifndef VK_MEDIA_PREV_TRACK +#define VK_MEDIA_PREV_TRACK 0xB1 +#endif // VK_MEDIA_PREV_TRACK +#ifndef VK_MEDIA_STOP +#define VK_MEDIA_STOP 0xB2 +#endif // VK_MEDIA_STOP +#ifndef VK_MEDIA_PLAY_PAUSE +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#endif // VK_MEDIA_PLAY_PAUSE + +/* + Initiates WM_INPUT messages from keyboard + That way GHOST can retrieve true keys +*/ +GHOST_TInt32 GHOST_SystemWin32::initKeyboardRawInput(void) +{ + RAWINPUTDEVICE device = {0}; + device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/ + device.usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */ + + return RegisterRawInputDevices(&device, 1, sizeof(device)); +}; + +GHOST_SystemWin32::GHOST_SystemWin32() +: m_hasPerformanceCounter(false), m_freq(0), m_start(0) +{ + m_displayManager = new GHOST_DisplayManagerWin32 (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); + m_displayManager->initialize(); + + m_consoleStatus = 1; + + // Check if current keyboard layout uses AltGr and save keylayout ID for + // specialized handling if keys like VK_OEM_*. I.e. french keylayout + // generates VK_OEM_8 for their exclamation key (key left of right shift) + this->handleKeyboardChange(); + // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32. + OleInitialize(0); +} + +GHOST_SystemWin32::~GHOST_SystemWin32() +{ + // Shutdown COM + OleUninitialize(); + toggleConsole(1); +} + + +GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const +{ + // Hardware does not support high resolution timers. We will use GetTickCount instead then. + if (!m_hasPerformanceCounter) { + return ::GetTickCount(); + } + + // Retrieve current count + __int64 count = 0; + ::QueryPerformanceCounter((LARGE_INTEGER*)&count); + + // Calculate the time passed since system initialization. + __int64 delta = 1000*(count-m_start); + + GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq); + return t; +} + + +GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const +{ + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n"); + GHOST_TUns8 numDisplays; + m_displayManager->getNumDisplays(numDisplays); + return numDisplays; +} + + +void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + width = ::GetSystemMetrics(SM_CXSCREEN); + height= ::GetSystemMetrics(SM_CYSCREEN); +} + + +GHOST_IWindow* GHOST_SystemWin32::createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow ) +{ + GHOST_Window* window = 0; + window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples, parentWindow); + if (window) { + if (window->getValid()) { + // Store the pointer to the window +// if (state != GHOST_kWindowStateFullScreen) { + m_windowManager->addWindow(window); +// } + } + else { + + // Invalid parent window hwnd + if (((GHOST_WindowWin32*)window)->getNextWindow() == NULL) { + delete window; + window = 0; + return window; + } + + // An invalid window could be one that was used to test for AA + window = ((GHOST_WindowWin32*)window)->getNextWindow(); + + // If another window is found, let the wm know about that one, but not the old one + if (window->getValid()) { + m_windowManager->addWindow(window); + } + else { + delete window; + window = 0; + } + + } + } + return window; +} + + +bool GHOST_SystemWin32::processEvents(bool waitForEvent) +{ + MSG msg; + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) { +#if 1 + ::Sleep(1); +#else + GHOST_TUns64 next = timerMgr->nextFireTime(); + GHOST_TInt64 maxSleep = next - getMilliSeconds(); + + if (next == GHOST_kFireTimeNever) { + ::WaitMessage(); + } else if(maxSleep >= 0.0) { + ::SetTimer(NULL, 0, maxSleep, NULL); + ::WaitMessage(); + ::KillTimer(NULL, 0); + } +#endif + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + // Process all the events waiting for us + while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) { + ::DispatchMessage(&msg); + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + POINT point; + if(::GetCursorPos(&point)){ + x = point.x; + y = point.y; + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) +{ + if (!GetActiveWindow()) + return GHOST_kFailure; + return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0; + keys.set(GHOST_kModifierKeyLeftShift, down); + down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0; + keys.set(GHOST_kModifierKeyRightShift, down); + + down = HIBYTE(::GetKeyState(VK_LMENU)) != 0; + keys.set(GHOST_kModifierKeyLeftAlt, down); + down = HIBYTE(::GetKeyState(VK_RMENU)) != 0; + keys.set(GHOST_kModifierKeyRightAlt, down); + + down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0; + keys.set(GHOST_kModifierKeyLeftControl, down); + down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; + keys.set(GHOST_kModifierKeyRightControl, down); + + bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0; + bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0; + if(lwindown || rwindown) + keys.set(GHOST_kModifierKeyOS, true); + else + keys.set(GHOST_kModifierKeyOS, false); + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const +{ + /* Check for swapped buttons (left-handed mouse buttons) + * GetAsyncKeyState() will give back the state of the physical mouse buttons. + */ + bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE; + + bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down); + + down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0; + buttons.set(GHOST_kButtonMaskMiddle, down); + + down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down); + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + + /* Disable scaling on high DPI displays on Vista */ + user32 = ::LoadLibraryA("user32.dll"); + typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)(); + LPFNSETPROCESSDPIAWARE SetProcessDPIAware = + (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware"); + if (SetProcessDPIAware) + SetProcessDPIAware(); + #ifdef NEED_RAW_PROC + pRegisterRawInputDevices = (LPFNDLLRRID)GetProcAddress(user32, "RegisterRawInputDevices"); + pGetRawInputData = (LPFNDLLGRID)GetProcAddress(user32, "GetRawInputData"); + #else + FreeLibrary(user32); + #endif + + /* Initiates WM_INPUT messages from keyboard */ + initKeyboardRawInput(); + + + // Determine whether this system has a high frequency performance counter. */ + m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE; + if (m_hasPerformanceCounter) { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n") + ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start); + } + else { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n") + } + + if (success) { + WNDCLASS wc; + wc.style= CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc= s_wndProc; + wc.cbClsExtra= 0; + wc.cbWndExtra= 0; + wc.hInstance= ::GetModuleHandle(0); + wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON"); + + if (!wc.hIcon) { + ::LoadIcon(NULL, IDI_APPLICATION); + } + wc.hCursor = ::LoadCursor(0, IDC_ARROW); + wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName= GHOST_WindowWin32::getWindowClassName(); + + // Use RegisterClassEx for setting small icon + if (::RegisterClass(&wc) == 0) { + success = GHOST_kFailure; + } + } + + return success; +} + + +GHOST_TSuccess GHOST_SystemWin32::exit() +{ + #ifdef NEED_RAW_PROC + FreeLibrary(user32); + #endif + + return GHOST_System::exit(); +} + +GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk) +{ + unsigned int size = 0; + char * data; + GHOST_TKey key = GHOST_kKeyUnknown; + + + if(!keyDown) + return GHOST_kKeyUnknown; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER)); + + + if((data = (char*)malloc(size)) && + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER))) + { + RAWINPUT ri; + memcpy(&ri,data,(size < sizeof(ri)) ? size : sizeof(ri)); + + if (ri.header.dwType == RIM_TYPEKEYBOARD) + { + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + + GHOST_ModifierKeys modifiers; + system->retrieveModifierKeys(modifiers); + + *keyDown = !(ri.data.keyboard.Flags & RI_KEY_BREAK); + key = this->convertKey(window, ri.data.keyboard.VKey, ri.data.keyboard.MakeCode, (ri.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0))); + + // extra handling of modifier keys: don't send repeats out from GHOST + if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt) + { + bool changed = false; + GHOST_TModifierKeyMask modifier; + switch(key) { + case GHOST_kKeyLeftShift: + { + changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown); + modifier = GHOST_kModifierKeyLeftShift; + } + break; + case GHOST_kKeyRightShift: + { + changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown); + modifier = GHOST_kModifierKeyRightShift; + } + break; + case GHOST_kKeyLeftControl: + { + changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown); + modifier = GHOST_kModifierKeyLeftControl; + } + break; + case GHOST_kKeyRightControl: + { + changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown); + modifier = GHOST_kModifierKeyRightControl; + } + break; + case GHOST_kKeyLeftAlt: + { + changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown); + modifier = GHOST_kModifierKeyLeftAlt; + } + break; + case GHOST_kKeyRightAlt: + { + changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown); + modifier = GHOST_kModifierKeyRightAlt; + } + break; + default: break; + } + + if(changed) + { + modifiers.set(modifier, (bool)*keyDown); + system->storeModifierKeys(modifiers); + } + else + { + key = GHOST_kKeyUnknown; + } + } + + + if(vk) *vk = ri.data.keyboard.VKey; + }; + + }; + free(data); + + return key; +} + +//! note: this function can be extended to include other exotic cases as they arise. +// This function was added in response to bug [#25715] +GHOST_TKey GHOST_SystemWin32::processSpecialKey(GHOST_IWindow *window, short vKey, short scanCode) const +{ + GHOST_TKey key = GHOST_kKeyUnknown; + switch(PRIMARYLANGID(m_langId)) { + case LANG_FRENCH: + if(vKey==VK_OEM_8) key = GHOST_kKeyF13; // oem key; used purely for shortcuts . + break; + } + + return key; +} + +GHOST_TKey GHOST_SystemWin32::convertKey(GHOST_IWindow *window, short vKey, short scanCode, short extend) const +{ + GHOST_TKey key; + + if ((vKey >= '0') && (vKey <= '9')) { + // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) + key = (GHOST_TKey)(vKey - '0' + GHOST_kKey0); + } + else if ((vKey >= 'A') && (vKey <= 'Z')) { + // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) + key = (GHOST_TKey)(vKey - 'A' + GHOST_kKeyA); + } + else if ((vKey >= VK_F1) && (vKey <= VK_F24)) { + key = (GHOST_TKey)(vKey - VK_F1 + GHOST_kKeyF1); + } + else { + switch (vKey) { + case VK_RETURN: + key = (extend)?GHOST_kKeyNumpadEnter : GHOST_kKeyEnter; break; + + case VK_BACK: key = GHOST_kKeyBackSpace; break; + case VK_TAB: key = GHOST_kKeyTab; break; + case VK_ESCAPE: key = GHOST_kKeyEsc; break; + case VK_SPACE: key = GHOST_kKeySpace; break; + + case VK_INSERT: + case VK_NUMPAD0: + key = (extend) ? GHOST_kKeyInsert : GHOST_kKeyNumpad0; break; + case VK_END: + case VK_NUMPAD1: + key = (extend) ? GHOST_kKeyEnd : GHOST_kKeyNumpad1; break; + case VK_DOWN: + case VK_NUMPAD2: + key = (extend) ? GHOST_kKeyDownArrow : GHOST_kKeyNumpad2; break; + case VK_NEXT: + case VK_NUMPAD3: + key = (extend) ? GHOST_kKeyDownPage : GHOST_kKeyNumpad3; break; + case VK_LEFT: + case VK_NUMPAD4: + key = (extend) ? GHOST_kKeyLeftArrow : GHOST_kKeyNumpad4; break; + case VK_CLEAR: + case VK_NUMPAD5: + key = (extend) ? GHOST_kKeyUnknown: GHOST_kKeyNumpad5; break; + case VK_RIGHT: + case VK_NUMPAD6: + key = (extend) ? GHOST_kKeyRightArrow : GHOST_kKeyNumpad6; break; + case VK_HOME: + case VK_NUMPAD7: + key = (extend) ? GHOST_kKeyHome : GHOST_kKeyNumpad7; break; + case VK_UP: + case VK_NUMPAD8: + key = (extend) ? GHOST_kKeyUpArrow : GHOST_kKeyNumpad8; break; + case VK_PRIOR: + case VK_NUMPAD9: + key = (extend) ? GHOST_kKeyUpPage : GHOST_kKeyNumpad9; break; + case VK_DECIMAL: + case VK_DELETE: + key = (extend) ? GHOST_kKeyDelete : GHOST_kKeyNumpadPeriod; break; + + case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break; + case VK_PAUSE: key = GHOST_kKeyPause; break; + case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break; + case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break; + case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break; + case VK_ADD: key = GHOST_kKeyNumpadPlus; break; + + case VK_SEMICOLON: key = GHOST_kKeySemicolon; break; + case VK_EQUALS: key = GHOST_kKeyEqual; break; + case VK_COMMA: key = GHOST_kKeyComma; break; + case VK_MINUS: key = GHOST_kKeyMinus; break; + case VK_PERIOD: key = GHOST_kKeyPeriod; break; + case VK_SLASH: key = GHOST_kKeySlash; break; + case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break; + case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break; + case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break; + case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break; + case VK_QUOTE: key = GHOST_kKeyQuote; break; + case VK_GR_LESS: key = GHOST_kKeyGrLess; break; + + case VK_SHIFT: + key = (scanCode == 0x36)? GHOST_kKeyRightShift : GHOST_kKeyLeftShift; + break; + case VK_CONTROL: + key = (extend)? GHOST_kKeyRightControl : GHOST_kKeyLeftControl; + break; + case VK_MENU: + key = (extend)? GHOST_kKeyRightAlt : GHOST_kKeyLeftAlt; + break; + case VK_LWIN: + case VK_RWIN: + key = GHOST_kKeyOS; + break; + case VK_NUMLOCK: key = GHOST_kKeyNumLock; break; + case VK_SCROLL: key = GHOST_kKeyScrollLock; break; + case VK_CAPITAL: key = GHOST_kKeyCapsLock; break; + case VK_OEM_8: + key = ((GHOST_SystemWin32*)getSystem())->processSpecialKey(window, vKey, scanCode); + break; + case VK_MEDIA_PLAY_PAUSE: key = GHOST_kKeyMediaPlay; break; + case VK_MEDIA_STOP: key = GHOST_kKeyMediaStop; break; + case VK_MEDIA_PREV_TRACK: key = GHOST_kKeyMediaFirst; break; + case VK_MEDIA_NEXT_TRACK: key = GHOST_kKeyMediaLast; break; + default: + key = GHOST_kKeyUnknown; + break; + } + } + + return key; +} + +GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask) +{ + return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask); +} + + +GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow) +{ + GHOST_TInt32 x_screen, y_screen; + GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem()); + GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow; + + system->getCursorPosition(x_screen, y_screen); + + if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal) + { + GHOST_TInt32 x_new= x_screen; + GHOST_TInt32 y_new= y_screen; + GHOST_TInt32 x_accum, y_accum; + GHOST_Rect bounds; + + /* fallback to window bounds */ + if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){ + window->getClientBounds(bounds); + } + + /* could also clamp to screen bounds + * wrap with a window outside the view will fail atm */ + + bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */ + + window->getCursorGrabAccum(x_accum, y_accum); + if(x_new != x_screen|| y_new != y_screen) { + /* when wrapping we don't need to add an event because the + * setCursorPosition call will cause a new event after */ + system->setCursorPosition(x_new, y_new); /* wrap */ + window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); + }else{ + return new GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_screen + x_accum, + y_screen + y_accum + ); + } + + } + else { + return new GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_screen, + y_screen + ); + } + return NULL; +} + + +GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) +{ + // short fwKeys = LOWORD(wParam); // key flags + int zDelta = (short) HIWORD(wParam); // wheel rotation + + // zDelta /= WHEEL_DELTA; + // temporary fix below: microsoft now has added more precision, making the above division not work + if (zDelta <= 0 ) zDelta= -1; else zDelta= 1; + + // short xPos = (short) LOWORD(lParam); // horizontal position of pointer + // short yPos = (short) HIWORD(lParam); // vertical position of pointer + return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta); +} + + +GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) +{ + int keyDown=0; + char vk; + GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem(); + GHOST_TKey key = system->hardKey(window, wParam, lParam, &keyDown, &vk); + GHOST_EventKey* event; + if (key != GHOST_kKeyUnknown) { + char ascii = '\0'; + + unsigned short utf16[2]={0}; + BYTE state[256]; + GetKeyboardState((PBYTE)state); + + if(ToAsciiEx(vk, 0, state, utf16, 0, system->m_keylayout)) + WideCharToMultiByte(CP_ACP, 0x00000400, + (wchar_t*)utf16, 1, + (LPSTR) &ascii, 1, + NULL,NULL); + + event = new GHOST_EventKey(system->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii); + +#ifdef BF_GHOST_DEBUG + std::cout << ascii << std::endl; +#endif + } + else { + event = 0; + } + return event; +} + + +GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window) +{ + return new GHOST_Event(getSystem()->getMilliSeconds(), type, window); +} + +GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, + GHOST_TDragnDropTypes draggedObjectType, + GHOST_IWindow* window, + int mouseX, int mouseY, + void* data) +{ + GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem()); + return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(), + eventType, + draggedObjectType, + window,mouseX,mouseY,data) + ); +} + +void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax) +{ + minmax->ptMinTrackSize.x=320; + minmax->ptMinTrackSize.y=240; +} + +LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + GHOST_Event* event = 0; + LRESULT lResult = 0; + GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem()); + GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized") + + if (hwnd) { + GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA); + if (window) { + switch (msg) { + // we need to check if new key layout has AltGr + case WM_INPUTLANGCHANGE: + system->handleKeyboardChange(); + break; + //////////////////////////////////////////////////////////////////////// + // Keyboard events, processed + //////////////////////////////////////////////////////////////////////// + case WM_INPUT: + // check WM_INPUT from input sink when ghost window is not in the foreground + if (wParam == RIM_INPUTSINK) { + if (GetFocus() != hwnd) // WM_INPUT message not for this window + return 0; + } //else wPAram == RIM_INPUT + event = processKeyEvent(window, wParam, lParam); + if (!event) { + GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ") + GHOST_PRINT(msg) + GHOST_PRINT(" key ignored\n") + } + break; + //////////////////////////////////////////////////////////////////////// + // Keyboard events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + /* These functions were replaced by WM_INPUT*/ + case WM_CHAR: + /* The WM_CHAR message is posted to the window with the keyboard focus when + * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR + * contains the character code of the key that was pressed. + */ + case WM_DEADCHAR: + /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a + * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR + * specifies a character code generated by a dead key. A dead key is a key that + * generates a character, such as the umlaut (double-dot), that is combined with + * another character to form a composite character. For example, the umlaut-O + * character (Ö) is generated by typing the dead key for the umlaut character, and + * then typing the O key. + */ + break; + case WM_SYSDEADCHAR: + /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when + * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. + * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, + * a dead key that is pressed while holding down the alt key. + */ + case WM_SYSCHAR: + /* The WM_SYSCHAR message is sent to the window with the keyboard focus when + * a WM_SYSCHAR message is translated by the TranslateMessage function. + * WM_SYSCHAR specifies the character code of a dead key - that is, + * a dead key that is pressed while holding down the alt key. + * To prevent the sound, DefWindowProc must be avoided by return + */ + break; + case WM_SYSCOMMAND: + /* The WM_SYSCHAR message is sent to the window when system commands such as + * maximize, minimize or close the window are triggered. Also it is sent when ALT + * button is press for menu. To prevent this we must return preventing DefWindowProc. + */ + if(wParam==SC_KEYMENU) return 0; + break; + //////////////////////////////////////////////////////////////////////// + // Tablet events, processed + //////////////////////////////////////////////////////////////////////// + case WT_PACKET: + ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam); + break; + case WT_CSRCHANGE: + case WT_PROXIMITY: + ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent(); + break; + //////////////////////////////////////////////////////////////////////// + // Mouse events, processed + //////////////////////////////////////////////////////////////////////// + case WM_LBUTTONDOWN: + window->registerMouseClickEvent(0); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONDOWN: + window->registerMouseClickEvent(0); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONDOWN: + window->registerMouseClickEvent(0); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); + break; + case WM_XBUTTONDOWN: + window->registerMouseClickEvent(0); + if ((short) HIWORD(wParam) == XBUTTON1){ + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4); + }else if((short) HIWORD(wParam) == XBUTTON2){ + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5); + } + break; + case WM_LBUTTONUP: + window->registerMouseClickEvent(1); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONUP: + window->registerMouseClickEvent(1); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONUP: + window->registerMouseClickEvent(1); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); + break; + case WM_XBUTTONUP: + window->registerMouseClickEvent(1); + if ((short) HIWORD(wParam) == XBUTTON1){ + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); + }else if((short) HIWORD(wParam) == XBUTTON2){ + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); + } + break; + case WM_MOUSEMOVE: + event = processCursorEvent(GHOST_kEventCursorMove, window); + break; + case WM_MOUSEWHEEL: + /* The WM_MOUSEWHEEL message is sent to the focus window + * when the mouse wheel is rotated. The DefWindowProc + * function propagates the message to the window's parent. + * There should be no internal forwarding of the message, + * since DefWindowProc propagates it up the parent chain + * until it finds a window that processes it. + */ + event = processWheelEvent(window, wParam, lParam); + break; + case WM_SETCURSOR: + /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor + * to move within a window and mouse input is not captured. + * This means we have to set the cursor shape every time the mouse moves! + * The DefWindowProc function uses this message to set the cursor to an + * arrow if it is not in the client area. + */ + if (LOWORD(lParam) == HTCLIENT) { + // Load the current cursor + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + // Bypass call to DefWindowProc + return 0; + } + else { + // Outside of client area show standard cursor + window->loadCursor(true, GHOST_kStandardCursorDefault); + } + break; + + //////////////////////////////////////////////////////////////////////// + // Mouse events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_NCMOUSEMOVE: + /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved + * within the nonclient area of the window. This message is posted to the window + * that contains the cursor. If a window has captured the mouse, this message is not posted. + */ + case WM_NCHITTEST: + /* The WM_NCHITTEST message is sent to a window when the cursor moves, or + * when a mouse button is pressed or released. If the mouse is not captured, + * the message is sent to the window beneath the cursor. Otherwise, the message + * is sent to the window that has captured the mouse. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Window events, processed + //////////////////////////////////////////////////////////////////////// + case WM_CLOSE: + /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */ + event = processWindowEvent(GHOST_kEventWindowClose, window); + break; + case WM_ACTIVATE: + /* The WM_ACTIVATE message is sent to both the window being activated and the window being + * deactivated. If the windows use the same input queue, the message is sent synchronously, + * first to the window procedure of the top-level window being deactivated, then to the window + * procedure of the top-level window being activated. If the windows use different input queues, + * the message is sent asynchronously, so the window is activated immediately. + */ + event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); + /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL + will not be dispatched to OUR active window if we minimize one of OUR windows. */ + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); + break; + case WM_PAINT: + /* An application sends the WM_PAINT message when the system or another application + * makes a request to paint a portion of an application's window. The message is sent + * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage + * function when the application obtains a WM_PAINT message by using the GetMessage or + * PeekMessage function. + */ + event = processWindowEvent(GHOST_kEventWindowUpdate, window); + ::ValidateRect(hwnd, NULL); + break; + case WM_GETMINMAXINFO: + /* The WM_GETMINMAXINFO message is sent to a window when the size or + * position of the window is about to change. An application can use + * this message to override the window's default maximized size and + * position, or its default minimum or maximum tracking size. + */ + processMinMaxInfo((MINMAXINFO *) lParam); + /* Let DefWindowProc handle it. */ + break; + case WM_SIZE: + /* The WM_SIZE message is sent to a window after its size has changed. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + event = processWindowEvent(GHOST_kEventWindowSize, window); + break; + case WM_CAPTURECHANGED: + window->lostMouseCapture(); + break; + case WM_MOVING: + /* The WM_MOVING message is sent to a window that the user is moving. By processing + * this message, an application can monitor the size and position of the drag rectangle + * and, if needed, change its size or position. + */ + case WM_MOVE: + /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + event = processWindowEvent(GHOST_kEventWindowMove, window); + break; + //////////////////////////////////////////////////////////////////////// + // Window events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_WINDOWPOSCHANGED: + /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place + * in the Z order has changed as a result of a call to the SetWindowPos function or + * another window-management function. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + case WM_ERASEBKGND: + /* An application sends the WM_ERASEBKGND message when the window background must be + * erased (for example, when a window is resized). The message is sent to prepare an + * invalidated portion of a window for painting. + */ + case WM_NCPAINT: + /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */ + case WM_NCACTIVATE: + /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed + * to indicate an active or inactive state. + */ + case WM_DESTROY: + /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window + * procedure of the window being destroyed after the window is removed from the screen. + * This message is sent first to the window being destroyed and then to the child windows + * (if any) as they are destroyed. During the processing of the message, it can be assumed + * that all child windows still exist. + */ + case WM_NCDESTROY: + /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The + * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY + * message. WM_DESTROY is used to free the allocated memory object associated with the window. + */ + break; + case WM_KILLFOCUS: + /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. + * We want to prevent this if a window is still active and it loses focus to nowhere*/ + if(!wParam && hwnd==GetActiveWindow()) + SetFocus(hwnd); + case WM_SHOWWINDOW: + /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */ + case WM_WINDOWPOSCHANGING: + /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in + * the Z order is about to change as a result of a call to the SetWindowPos function or + * another window-management function. + */ + case WM_SETFOCUS: + /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */ + case WM_ENTERSIZEMOVE: + /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving + * or sizing modal loop. The window enters the moving or sizing modal loop when the user + * clicks the window's title bar or sizing border, or when the window passes the + * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the + * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when + * DefWindowProc returns. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Other events + //////////////////////////////////////////////////////////////////////// + case WM_GETTEXT: + /* An application sends a WM_GETTEXT message to copy the text that + * corresponds to a window into a buffer provided by the caller. + */ + case WM_ACTIVATEAPP: + /* The WM_ACTIVATEAPP message is sent when a window belonging to a + * different application than the active window is about to be activated. + * The message is sent to the application whose window is being activated + * and to the application whose window is being deactivated. + */ + case WM_TIMER: + /* The WIN32 docs say: + * The WM_TIMER message is posted to the installing thread's message queue + * when a timer expires. You can process the message by providing a WM_TIMER + * case in the window procedure. Otherwise, the default window procedure will + * call the TimerProc callback function specified in the call to the SetTimer + * function used to install the timer. + * + * In GHOST, we let DefWindowProc call the timer callback. + */ + break; + case WM_BLND_NDOF_AXIS: + { + GHOST_TEventNDOFData ndofdata; + system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata); + system->m_eventManager-> + pushEvent(new GHOST_EventNDOF( + system->getMilliSeconds(), + GHOST_kEventNDOFMotion, + window, ndofdata)); + } + break; + case WM_BLND_NDOF_BTN: + { + GHOST_TEventNDOFData ndofdata; + system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata); + system->m_eventManager-> + pushEvent(new GHOST_EventNDOF( + system->getMilliSeconds(), + GHOST_kEventNDOFButton, + window, ndofdata)); + } + break; + } + } + else { + // Event found for a window before the pointer to the class has been set. + GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n") + /* These are events we typically miss at this point: + WM_GETMINMAXINFO 0x24 + WM_NCCREATE 0x81 + WM_NCCALCSIZE 0x83 + WM_CREATE 0x01 + We let DefWindowProc do the work. + */ + } + } + else { + // Events without valid hwnd + GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n") + } + + if (event) { + system->pushEvent(event); + } + else { + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); + } + return lResult; +} + +GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const +{ + char *buffer; + char *temp_buff; + + if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) { + HANDLE hData = GetClipboardData( CF_TEXT ); + if (hData == NULL) { + CloseClipboard(); + return NULL; + } + buffer = (char*)GlobalLock( hData ); + + temp_buff = (char*) malloc(strlen(buffer)+1); + strcpy(temp_buff, buffer); + + GlobalUnlock( hData ); + CloseClipboard(); + + temp_buff[strlen(buffer)] = '\0'; + if (buffer) { + return (GHOST_TUns8*)temp_buff; + } else { + return NULL; + } + } else { + return NULL; + } +} + +void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const +{ + if(selection) {return;} // for copying the selection, used on X11 + + if (OpenClipboard(NULL)) { + HLOCAL clipbuffer; + char *data; + + if (buffer) { + EmptyClipboard(); + + clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1))); + data = (char*)GlobalLock(clipbuffer); + + strcpy(data, (char*)buffer); + data[strlen(buffer)] = '\0'; + LocalUnlock(clipbuffer); + SetClipboardData(CF_TEXT,clipbuffer); + } + CloseClipboard(); + } else { + return; + } +} + +int GHOST_SystemWin32::toggleConsole(int action) +{ + switch(action) + { + case 3: //hide if no console + { + CONSOLE_SCREEN_BUFFER_INFO csbi = {{0}}; + if(!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) || csbi.dwCursorPosition.X || csbi.dwCursorPosition.Y>1) + break; + } + case 0: //hide + ShowWindow(GetConsoleWindow(),SW_HIDE); + m_consoleStatus = 0; + break; + case 1: //show + ShowWindow(GetConsoleWindow(),SW_SHOW); + m_consoleStatus = 1; + break; + case 2: //toggle + ShowWindow(GetConsoleWindow(),m_consoleStatus?SW_HIDE:SW_SHOW); + m_consoleStatus=!m_consoleStatus; + break; + + }; + + + return m_consoleStatus; +} diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h new file mode 100644 index 00000000000..2dad3a6f44d --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -0,0 +1,489 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemWin32.h + * \ingroup GHOST + * Declaration of GHOST_SystemWin32 class. + */ + +#ifndef _GHOST_SYSTEM_WIN32_H_ +#define _GHOST_SYSTEM_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include + +#include "GHOST_System.h" + +#if defined(__CYGWIN32__) +# define __int64 long long +#endif + +#ifndef WM_INPUT +#define WM_INPUT 0x00FF +#endif +#ifndef RID_INPUT +#define RID_INPUT 0x10000003 +#endif +#ifndef RI_KEY_BREAK +#define RI_KEY_BREAK 0x1 +#endif +#ifndef RI_KEY_E0 +#define RI_KEY_E0 0x2 +#endif +#ifndef RI_KEY_E1 +#define RI_KEY_E1 0x4 +#endif +#ifndef RIM_TYPEMOUSE +#define RIM_TYPEMOUSE 0x0 +#define RIM_TYPEKEYBOARD 0x1 +#define RIM_TYPEHID 0x2 + +typedef struct tagRAWINPUTDEVICE { + USHORT usUsagePage; + USHORT usUsage; + DWORD dwFlags; + HWND hwndTarget; +} RAWINPUTDEVICE; + + + +typedef struct tagRAWINPUTHEADER { + DWORD dwType; + DWORD dwSize; + HANDLE hDevice; + WPARAM wParam; +} RAWINPUTHEADER; + +typedef struct tagRAWMOUSE { + USHORT usFlags; + union { + ULONG ulButtons; + struct { + USHORT usButtonFlags; + USHORT usButtonData; + }; + }; + ULONG ulRawButtons; + LONG lLastX; + LONG lLastY; + ULONG ulExtraInformation; +} RAWMOUSE; + +typedef struct tagRAWKEYBOARD { + USHORT MakeCode; + USHORT Flags; + USHORT Reserved; + USHORT VKey; + UINT Message; + ULONG ExtraInformation; +} RAWKEYBOARD; + +typedef struct tagRAWHID { + DWORD dwSizeHid; + DWORD dwCount; + BYTE bRawData[1]; +} RAWHID; + +typedef struct tagRAWINPUT { + RAWINPUTHEADER header; + union { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; +} RAWINPUT; + +DECLARE_HANDLE(HRAWINPUT); +#endif + +#ifdef FREE_WINDOWS +#define NEED_RAW_PROC +typedef BOOL (WINAPI * LPFNDLLRRID)(RAWINPUTDEVICE*,UINT, UINT); +#define RegisterRawInputDevices(pRawInputDevices, uiNumDevices, cbSize) ((pRegisterRawInputDevices)?pRegisterRawInputDevices(pRawInputDevices, uiNumDevices, cbSize):0) + + +typedef UINT (WINAPI * LPFNDLLGRID)(HRAWINPUT, UINT, LPVOID, PUINT, UINT); +#define GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader) ((pGetRawInputData)?pGetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader):(UINT)-1) +#endif + +class GHOST_EventButton; +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWheel; +class GHOST_EventWindow; +class GHOST_EventDragnDrop; + +/** + * WIN32 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_SystemWin32 : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemWin32(); + + /** + * Destructor. + */ + virtual ~GHOST_SystemWin32(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * This overloaded method uses the high frequency timer if available. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0, + const GHOST_TEmbedderWindowID parentWindow = 0 ); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y); + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + + /** + * Returns unsinged char from CUT_BUFFER0 + * @param selection Used by X11 only + * @return Returns the Clipboard + */ + virtual GHOST_TUns8* getClipboard(bool selection) const; + + /** + * Puts buffer to system clipboard + * @param selection Used by X11 only + * @return No return + */ + virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + + /** + * Creates a drag'n'drop event and pushes it immediately onto the event queue. + * Called by GHOST_DropTargetWin32 class. + * @param eventType The type of drag'n'drop event + * @param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap) + * @param mouseX x mouse coordinate (in window coordinates) + * @param mouseY y mouse coordinate + * @param window The window on which the event occurred + * @return Indication whether the event was handled. + */ + static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,GHOST_IWindow* window, int mouseX, int mouseY, void* data); + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + /** + * Converts raw WIN32 key codes from the wndproc to GHOST keys. + * @param window-> The window for this handling + * @param vKey The virtual key from hardKey + * @param ScanCode The ScanCode of pressed key (simular to PS/2 Set 1) + * @param extend Flag if key is not primerly (left or right) + * @return The GHOST key (GHOST_kKeyUnknown if no match). + */ + virtual GHOST_TKey convertKey(GHOST_IWindow *window, short vKey, short ScanCode, short extend) const; + + /** + * Catches raw WIN32 key codes from WM_INPUT in the wndproc. + * @param window-> The window for this handling + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + * @param keyDown Pointer flag that specify if a key is down + * @param vk Pointer to virtual key + * @return The GHOST key (GHOST_kKeyUnknown if no match). + */ + virtual GHOST_TKey hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk); + + /** + * Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys). + * With the modifier keys, we want to distinguish left and right keys. + * Sometimes this is not possible (Windows ME for instance). Then, we want + * events generated for both keys. + * @param window The window receiving the event (the active window). + */ + GHOST_EventKey* processModifierKeys(GHOST_IWindow *window); + + /** + * Creates mouse button event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @param mask The button mask of this event. + * @return The event created. + */ + static GHOST_EventButton* processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask); + + /** + * Creates cursor event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_EventCursor* processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow); + + /** + * Creates a mouse wheel event. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventWheel* processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam); + + /** + * Creates a key event and updates the key data stored locally (m_modifierKeys). + * In most cases this is a straightforward conversion of key codes. + * For the modifier keys however, we want to distinguish left and right keys. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam); + + /** + * Process special keys (VK_OEM_*), to see if current key layout + * gives us anything special, like ! on french AZERTY. + * @param window The window receiving the event (the active window). + * @param vKey The virtual key from hardKey + * @param ScanCode The ScanCode of pressed key (simular to PS/2 Set 1) + */ + virtual GHOST_TKey processSpecialKey(GHOST_IWindow *window, short vKey, short scanCode) const; + + /** + * Creates a window event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_Event* processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window); + /** + * Handles minimum window size. + * @param minmax The MINMAXINFO structure. + */ + static void processMinMaxInfo(MINMAXINFO * minmax); + + /** + * Returns the local state of the modifier keys (from the message queue). + * @param keys The state of the keys. + */ + inline virtual void retrieveModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Stores the state of the modifier keys locally. + * For internal use only! + * @param keys The new state of the modifier keys. + */ + inline virtual void storeModifierKeys(const GHOST_ModifierKeys& keys); + + /** + * Check current key layout for AltGr + */ + inline virtual void handleKeyboardChange(void); + + /** + * Windows call back routine for our window class. + */ + static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + /** + * Initiates WM_INPUT messages from keyboard + */ + GHOST_TInt32 initKeyboardRawInput(void); + + /** + * Toggles console + * @action 0 - Hides + * 1 - Shows + * 2 - Toggles + * 3 - Hides if it runs not from command line + * * - Does nothing + * @return current status (1 -visible, 0 - hidden) + */ + int toggleConsole(int action); + + /** The current state of the modifier keys. */ + GHOST_ModifierKeys m_modifierKeys; + /** State variable set at initialization. */ + bool m_hasPerformanceCounter; + /** High frequency timer variable. */ + __int64 m_freq; + /** High frequency timer variable. */ + __int64 m_start; + /** AltGr on current keyboard layout. */ + bool m_hasAltGr; + /** language identifier. */ + WORD m_langId; + /** stores keyboard layout. */ + HKL m_keylayout; + + /** Console status */ + int m_consoleStatus; + + /** handle for user32.dll*/ + HMODULE user32; + #ifdef NEED_RAW_PROC + /* pointer to RegisterRawInputDevices function */ + LPFNDLLRRID pRegisterRawInputDevices; + /* pointer to GetRawInputData function */ + LPFNDLLGRID pGetRawInputData; + #endif +}; + +inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const +{ + keys = m_modifierKeys; +} + +inline void GHOST_SystemWin32::storeModifierKeys(const GHOST_ModifierKeys& keys) +{ + m_modifierKeys = keys; +} + +inline void GHOST_SystemWin32::handleKeyboardChange(void) +{ + m_keylayout = GetKeyboardLayout(0); // get keylayout for current thread + int i; + SHORT s; + + // save the language identifier. + m_langId = LOWORD(m_keylayout); + + for(m_hasAltGr = false, i = 32; i < 256; ++i) { + s = VkKeyScanEx((char)i, m_keylayout); + // s == -1 means no key that translates passed char code + // high byte contains shift state. bit 2 ctrl pressed, bit 4 alt pressed + // if both are pressed, we have AltGr keycombo on keylayout + if(s!=-1 && (s & 0x600) == 0x600) { + m_hasAltGr = true; + break; + } + } +} +#endif // _GHOST_SYSTEM_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp new file mode 100644 index 00000000000..b44f2b18225 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -0,0 +1,1497 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * Part of this code has been taken from Qt, under LGPL license + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemX11.cpp + * \ingroup GHOST + */ + + +#include "GHOST_SystemX11.h" +#include "GHOST_WindowX11.h" +#include "GHOST_WindowManager.h" +#include "GHOST_TimerManager.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventWheel.h" +#include "GHOST_EventNDOF.h" +#include "GHOST_NDOFManager.h" +#include "GHOST_DisplayManagerX11.h" + +#include "GHOST_Debug.h" + +#include +#include +#include /* allow detectable autorepeate */ + +#ifdef WITH_XF86KEYSYM +#include +#endif + +#ifdef __sgi + +#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS) +#include +#else +#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how) +#endif + +#endif + +// For timing + +#include +#include + +#include +#include +#include // for fprintf only +#include // for exit + +typedef struct NDOFPlatformInfo { + Display *display; + Window window; + volatile GHOST_TEventNDOFData *currValues; + Atom cmdAtom; + Atom motionAtom; + Atom btnPressAtom; + Atom btnRelAtom; +} NDOFPlatformInfo; + +static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0}; + + +//these are for copy and select copy +static char *txt_cut_buffer= NULL; +static char *txt_select_buffer= NULL; + +using namespace std; + +GHOST_SystemX11:: +GHOST_SystemX11( +) : + GHOST_System(), + m_start_time(0) +{ + m_display = XOpenDisplay(NULL); + + if (!m_display) { + std::cerr << "Unable to open a display" << std::endl; + abort(); //was return before, but this would just mean it will crash later + } + +#ifdef __sgi + m_delete_window_atom + = XSGIFastInternAtom(m_display, + "WM_DELETE_WINDOW", + SGI_XA_WM_DELETE_WINDOW, False); +#else + m_delete_window_atom + = XInternAtom(m_display, "WM_DELETE_WINDOW", True); +#endif + + m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False); + m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False); + m_wm_state= XInternAtom(m_display, "WM_STATE", False); + m_wm_change_state= XInternAtom(m_display, "WM_CHANGE_STATE", False); + m_net_state= XInternAtom(m_display, "_NET_WM_STATE", False); + m_net_max_horz= XInternAtom(m_display, + "_NET_WM_STATE_MAXIMIZED_HORZ", False); + m_net_max_vert= XInternAtom(m_display, + "_NET_WM_STATE_MAXIMIZED_VERT", False); + m_net_fullscreen= XInternAtom(m_display, + "_NET_WM_STATE_FULLSCREEN", False); + m_motif= XInternAtom(m_display, "_MOTIF_WM_HINTS", False); + m_targets= XInternAtom(m_display, "TARGETS", False); + m_string= XInternAtom(m_display, "STRING", False); + m_compound_text= XInternAtom(m_display, "COMPOUND_TEXT", False); + m_text= XInternAtom(m_display, "TEXT", False); + m_clipboard= XInternAtom(m_display, "CLIPBOARD", False); + m_primary= XInternAtom(m_display, "PRIMARY", False); + m_xclip_out= XInternAtom(m_display, "XCLIP_OUT", False); + m_incr= XInternAtom(m_display, "INCR", False); + m_utf8_string= XInternAtom(m_display, "UTF8_STRING", False); + m_last_warp = 0; + + + // compute the initial time + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not instantiate timer!"); + } + + m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000); + + + /* use detectable autorepeate, mac and windows also do this */ + int use_xkb; + int xkb_opcode, xkb_event, xkb_error; + int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion; + + use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor); + if (use_xkb) { + XkbSetDetectableAutoRepeat(m_display, true, NULL); + } + +} + +GHOST_SystemX11:: +~GHOST_SystemX11() +{ + XCloseDisplay(m_display); +} + + + GHOST_TSuccess +GHOST_SystemX11:: +init( +){ + GHOST_TSuccess success = GHOST_System::init(); + + if (success) { + m_displayManager = new GHOST_DisplayManagerX11(this); + + if (m_displayManager) { + return GHOST_kSuccess; + } + } + + return GHOST_kFailure; +} + + GHOST_TUns64 +GHOST_SystemX11:: +getMilliSeconds( +) const { + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not compute time!"); + } + + return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time; +} + + GHOST_TUns8 +GHOST_SystemX11:: +getNumDisplays( +) const { + return GHOST_TUns8(1); +} + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void +GHOST_SystemX11:: +getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height +) const { + if (m_display) { + width = DisplayWidth(m_display, DefaultScreen(m_display)); + height = DisplayHeight(m_display, DefaultScreen(m_display)); + } +} + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* +GHOST_SystemX11:: +createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual, + const GHOST_TUns16 numOfAASamples, + const GHOST_TEmbedderWindowID parentWindow +){ + GHOST_WindowX11 * window = 0; + + if (!m_display) return 0; + + + + + window = new GHOST_WindowX11 ( + this,m_display,title, left, top, width, height, state, parentWindow, type, stereoVisual + ); + + if (window) { + // Both are now handle in GHOST_WindowX11.cpp + // Focus and Delete atoms. + + if (window->getValid()) { + // Store the pointer to the window + m_windowManager->addWindow(window); + + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + else { + delete window; + window = 0; + } + } + return window; +} + + GHOST_WindowX11 * +GHOST_SystemX11:: +findGhostWindow( + Window xwind +) const { + + if (xwind == 0) return NULL; + + // It is not entirely safe to do this as the backptr may point + // to a window that has recently been removed. + // We should always check the window manager's list of windows + // and only process events on these windows. + + vector & win_vec = m_windowManager->getWindows(); + + vector::iterator win_it = win_vec.begin(); + vector::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 * window = static_cast(*win_it); + if (window->getXWindow() == xwind) { + return window; + } + } + return NULL; + +} + +static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) { + int fd = ConnectionNumber(display); + fd_set fds; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (maxSleep == -1) { + select(fd + 1, &fds, NULL, NULL, NULL); + } else { + timeval tv; + + tv.tv_sec = maxSleep/1000; + tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000; + + select(fd + 1, &fds, NULL, NULL, &tv); + } +} + +/* This function borrowed from Qt's X11 support + * qclipboard_x11.cpp + * */ +struct init_timestamp_data +{ + Time timestamp; +}; + +static Bool init_timestamp_scanner(Display*, XEvent *event, XPointer arg) +{ + init_timestamp_data *data = + reinterpret_cast(arg); + switch(event->type) + { + case ButtonPress: + case ButtonRelease: + data->timestamp = event->xbutton.time; + break; + case MotionNotify: + data->timestamp = event->xmotion.time; + break; + case KeyPress: + case KeyRelease: + data->timestamp = event->xkey.time; + break; + case PropertyNotify: + data->timestamp = event->xproperty.time; + break; + case EnterNotify: + case LeaveNotify: + data->timestamp = event->xcrossing.time; + break; + case SelectionClear: + data->timestamp = event->xselectionclear.time; + break; + default: + break; + } + + return false; +} + +Time +GHOST_SystemX11:: +lastEventTime(Time default_time) { + init_timestamp_data data; + data.timestamp = default_time; + XEvent ev; + XCheckIfEvent(m_display, &ev, &init_timestamp_scanner, (XPointer)&data); + + return data.timestamp; +} + + + + bool +GHOST_SystemX11:: +processEvents( + bool waitForEvent +){ + // Get all the current events -- translate them into + // ghost events and call base class pushEvent() method. + + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) { + GHOST_TUns64 next = timerMgr->nextFireTime(); + + if (next==GHOST_kFireTimeNever) { + SleepTillEvent(m_display, -1); + } else { + GHOST_TInt64 maxSleep = next - getMilliSeconds(); + + if(maxSleep >= 0) + SleepTillEvent(m_display, next - getMilliSeconds()); + } + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + while (XPending(m_display)) { + XEvent xevent; + XNextEvent(m_display, &xevent); + processEvent(&xevent); + anyProcessed = true; + } + + if (generateWindowExposeEvents()) { + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + void +GHOST_SystemX11::processEvent(XEvent *xe) +{ + GHOST_WindowX11 * window = findGhostWindow(xe->xany.window); + GHOST_Event * g_event = NULL; + + if (!window) { + return; + } + + switch (xe->type) { + case Expose: + { + XExposeEvent & xee = xe->xexpose; + + if (xee.count == 0) { + // Only generate a single expose event + // per read of the event queue. + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + window + ); + } + break; + } + + case MotionNotify: + { + XMotionEvent &xme = xe->xmotion; + + if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal) + { + GHOST_TInt32 x_new= xme.x_root; + GHOST_TInt32 y_new= xme.y_root; + GHOST_TInt32 x_accum, y_accum; + GHOST_Rect bounds; + + /* fallback to window bounds */ + if(window->getCursorGrabBounds(bounds)==GHOST_kFailure) + window->getClientBounds(bounds); + + /* could also clamp to screen bounds + * wrap with a window outside the view will fail atm */ + bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */ + window->getCursorGrabAccum(x_accum, y_accum); + + if(x_new != xme.x_root || y_new != xme.y_root) { + if (xme.time > m_last_warp) { + /* when wrapping we don't need to add an event because the + * setCursorPosition call will cause a new event after */ + setCursorPosition(x_new, y_new); /* wrap */ + window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new)); + m_last_warp = lastEventTime(xme.time); + } else { + setCursorPosition(x_new, y_new); /* wrap but don't accumulate */ + } + } + else { + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root + x_accum, + xme.y_root + y_accum + ); + } + } + else { + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root, + xme.y_root + ); + } + break; + } + + case KeyPress: + case KeyRelease: + { + XKeyEvent *xke = &(xe->xkey); + + KeySym key_sym = XLookupKeysym(xke,0); + char ascii; + + GHOST_TKey gkey = convertXKey(key_sym); + GHOST_TEventType type = (xke->type == KeyPress) ? + GHOST_kEventKeyDown : GHOST_kEventKeyUp; + + if (!XLookupString(xke, &ascii, 1, NULL, NULL)) { + ascii = '\0'; + } + + g_event = new + GHOST_EventKey( + getMilliSeconds(), + type, + window, + gkey, + ascii + ); + + break; + } + + case ButtonPress: + case ButtonRelease: + { + XButtonEvent & xbe = xe->xbutton; + GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft; + GHOST_TEventType type = (xbe.type == ButtonPress) ? + GHOST_kEventButtonDown : GHOST_kEventButtonUp; + + /* process wheel mouse events and break, only pass on press events */ + if(xbe.button == Button4) { + if(xbe.type == ButtonPress) + g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1); + break; + } + else if(xbe.button == Button5) { + if(xbe.type == ButtonPress) + g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1); + break; + } + + /* process rest of normal mouse buttons */ + if(xbe.button == Button1) + gbmask = GHOST_kButtonMaskLeft; + else if(xbe.button == Button2) + gbmask = GHOST_kButtonMaskMiddle; + else if(xbe.button == Button3) + gbmask = GHOST_kButtonMaskRight; + /* It seems events 6 and 7 are for horizontal scrolling. + * you can re-order button mapping like this... (swaps 6,7 with 8,9) + * xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" + */ + else if(xbe.button == 8) + gbmask = GHOST_kButtonMaskButton4; + else if(xbe.button == 9) + gbmask = GHOST_kButtonMaskButton5; + else + break; + + g_event = new + GHOST_EventButton( + getMilliSeconds(), + type, + window, + gbmask + ); + break; + } + + // change of size, border, layer etc. + case ConfigureNotify: + { + /* XConfigureEvent & xce = xe->xconfigure; */ + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowSize, + window + ); + break; + } + + case FocusIn: + case FocusOut: + { + XFocusChangeEvent &xfe = xe->xfocus; + + // May have to look at the type of event and filter some + // out. + + GHOST_TEventType gtype = (xfe.type == FocusIn) ? + GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate; + + g_event = new + GHOST_Event( + getMilliSeconds(), + gtype, + window + ); + break; + + } + case ClientMessage: + { + XClientMessageEvent & xcme = xe->xclient; + +#ifndef __sgi + if (((Atom)xcme.data.l[0]) == m_delete_window_atom) { + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowClose, + window + ); + } else +#endif + if (sNdofInfo.currValues) { + static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0}; + if (xcme.message_type == sNdofInfo.motionAtom) + { + data.changed = 1; + data.delta = xcme.data.s[8] - data.time; + data.time = xcme.data.s[8]; + data.tx = xcme.data.s[2] >> 2; + data.ty = xcme.data.s[3] >> 2; + data.tz = xcme.data.s[4] >> 2; + data.rx = xcme.data.s[5]; + data.ry = xcme.data.s[6]; + data.rz =-xcme.data.s[7]; + g_event = new GHOST_EventNDOF(getMilliSeconds(), + GHOST_kEventNDOFMotion, + window, data); + } else if (xcme.message_type == sNdofInfo.btnPressAtom) { + data.changed = 2; + data.delta = xcme.data.s[8] - data.time; + data.time = xcme.data.s[8]; + data.buttons = xcme.data.s[2]; + g_event = new GHOST_EventNDOF(getMilliSeconds(), + GHOST_kEventNDOFButton, + window, data); + } + } else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) { + XWindowAttributes attr; + Window fwin; + int revert_to; + + /* as ICCCM say, we need reply this event + * with a SetInputFocus, the data[1] have + * the valid timestamp (send by the wm). + * + * Some WM send this event before the + * window is really mapped (for example + * change from virtual desktop), so we need + * to be sure that our windows is mapped + * or this call fail and close blender. + */ + if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) { + if (XGetInputFocus(m_display, &fwin, &revert_to) == True) { + if (attr.map_state == IsViewable) { + if (fwin != xcme.window) + XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]); + } + } + } + } else { + /* Unknown client message, ignore */ + } + break; + } + + case DestroyNotify: + ::exit(-1); + // We're not interested in the following things.(yet...) + case NoExpose : + case GraphicsExpose : + break; + + case EnterNotify: + case LeaveNotify: + { + /* XCrossingEvents pointer leave enter window. + also do cursor move here, MotionNotify only + happens when motion starts & ends inside window. + we only do moves when the crossing mode is 'normal' + (really crossing between windows) since some windowmanagers + also send grab/ungrab crossings for mousewheel events. + */ + XCrossingEvent &xce = xe->xcrossing; + if( xce.mode == NotifyNormal ) { + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xce.x_root, + xce.y_root + ); + } + break; + } + case MapNotify: + /* + * From ICCCM: + * [ Clients can select for StructureNotify on their + * top-level windows to track transition between + * Normal and Iconic states. Receipt of a MapNotify + * event will indicate a transition to the Normal + * state, and receipt of an UnmapNotify event will + * indicate a transition to the Iconic state. ] + */ + if (window->m_post_init == True) { + /* + * Now we are sure that the window is + * mapped, so only need change the state. + */ + window->setState (window->m_post_state); + window->m_post_init = False; + } + break; + case UnmapNotify: + break; + case MappingNotify: + case ReparentNotify: + break; + case SelectionRequest: + { + XEvent nxe; + Atom target, string, compound_text, c_string; + XSelectionRequestEvent *xse = &xe->xselectionrequest; + + target = XInternAtom(m_display, "TARGETS", False); + string = XInternAtom(m_display, "STRING", False); + compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False); + c_string = XInternAtom(m_display, "C_STRING", False); + + /* support obsolete clients */ + if (xse->property == None) { + xse->property = xse->target; + } + + nxe.xselection.type = SelectionNotify; + nxe.xselection.requestor = xse->requestor; + nxe.xselection.property = xse->property; + nxe.xselection.display = xse->display; + nxe.xselection.selection = xse->selection; + nxe.xselection.target = xse->target; + nxe.xselection.time = xse->time; + + /*Check to see if the requestor is asking for String*/ + if(xse->target == string || xse->target == compound_text || xse->target == c_string) { + if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) { + XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer)); + } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) { + XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer)); + } + } else if (xse->target == target) { + Atom alist[4]; + alist[0] = target; + alist[1] = string; + alist[2] = compound_text; + alist[3] = c_string; + XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4); + XFlush(m_display); + } else { + //Change property to None because we do not support anything but STRING + nxe.xselection.property = None; + } + + //Send the event to the client 0 0 == False, SelectionNotify + XSendEvent(m_display, xse->requestor, 0, 0, &nxe); + XFlush(m_display); + break; + } + + default: { + if(xe->type == window->GetXTablet().MotionEvent) + { + XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe; + window->GetXTablet().CommonData.Pressure= + data->axis_data[2]/((float)window->GetXTablet().PressureLevels); + + /* the (short) cast and the &0xffff is bizarre and unexplained anywhere, + * but I got garbage data without it. Found it in the xidump.c source --matt */ + window->GetXTablet().CommonData.Xtilt= + (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels); + window->GetXTablet().CommonData.Ytilt= + (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels); + } + else if(xe->type == window->GetXTablet().ProxInEvent) + { + XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe; + if(data->deviceid == window->GetXTablet().StylusID) + window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus; + else if(data->deviceid == window->GetXTablet().EraserID) + window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser; + } + else if(xe->type == window->GetXTablet().ProxOutEvent) + window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone; + + break; + } + } + + if (g_event) { + pushEvent(g_event); + } +} + + void * +GHOST_SystemX11:: +prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues) +{ + const vector& v(m_windowManager->getWindows()); + if (v.size() > 0) + sNdofInfo.window = static_cast(v[0])->getXWindow(); + sNdofInfo.display = m_display; + sNdofInfo.currValues = currentNdofValues; + return (void*)&sNdofInfo; +} + + GHOST_TSuccess +GHOST_SystemX11:: +getModifierKeys( + GHOST_ModifierKeys& keys +) const { + + // analyse the masks retuned from XQueryPointer. + + memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector)); + + XQueryKeymap(m_display,(char *)m_keyboard_vector); + + // now translate key symobols into keycodes and + // test with vector. + + const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L); + const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R); + const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L); + const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R); + const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L); + const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R); + const KeyCode super_l = XKeysymToKeycode(m_display,XK_Super_L); + const KeyCode super_r = XKeysymToKeycode(m_display,XK_Super_R); + + // Shift + if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftShift,true); + } else { + keys.set(GHOST_kModifierKeyLeftShift,false); + } + if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) { + + keys.set(GHOST_kModifierKeyRightShift,true); + } else { + keys.set(GHOST_kModifierKeyRightShift,false); + } + + // control (weep) + if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftControl,true); + } else { + keys.set(GHOST_kModifierKeyLeftControl,false); + } + if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightControl,true); + } else { + keys.set(GHOST_kModifierKeyRightControl,false); + } + + // Alt (yawn) + if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftAlt,true); + } else { + keys.set(GHOST_kModifierKeyLeftAlt,false); + } + if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightAlt,true); + } else { + keys.set(GHOST_kModifierKeyRightAlt,false); + } + + // Super (Windows) - only one GHOST-kModifierKeyOS, so mapping + // to either + if ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) || + ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) { + keys.set(GHOST_kModifierKeyOS,true); + } else { + keys.set(GHOST_kModifierKeyOS,false); + } + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_SystemX11:: +getButtons( + GHOST_Buttons& buttons +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + + if (mask_return & Button1Mask) { + buttons.set(GHOST_kButtonMaskLeft,true); + } else { + buttons.set(GHOST_kButtonMaskLeft,false); + } + + if (mask_return & Button2Mask) { + buttons.set(GHOST_kButtonMaskMiddle,true); + } else { + buttons.set(GHOST_kButtonMaskMiddle,false); + } + + if (mask_return & Button3Mask) { + buttons.set(GHOST_kButtonMaskRight,true); + } else { + buttons.set(GHOST_kButtonMaskRight,false); + } + } + + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + x = rx; + y = ry; + } + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y +) { + + // This is a brute force move in screen coordinates + // XWarpPointer does relative moves so first determine the + // current pointer position. + + int cx,cy; + if (getCursorPosition(cx,cy) == GHOST_kFailure) { + return GHOST_kFailure; + } + + int relx = x-cx; + int rely = y-cy; + + XWarpPointer(m_display,None,None,0,0,0,0,relx,rely); + XSync(m_display, 0); /* Sync to process all requests */ + + return GHOST_kSuccess; +} + + + void +GHOST_SystemX11:: +addDirtyWindow( + GHOST_WindowX11 * bad_wind +){ + + GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)"); + + m_dirty_windows.push_back(bad_wind); +} + + + bool +GHOST_SystemX11:: +generateWindowExposeEvents( +){ + + vector::iterator w_start = m_dirty_windows.begin(); + vector::const_iterator w_end = m_dirty_windows.end(); + bool anyProcessed = false; + + for (;w_start != w_end; ++w_start) { + GHOST_Event * g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + *w_start + ); + + (*w_start)->validate(); + + if (g_event) { + pushEvent(g_event); + anyProcessed = true; + } + } + + m_dirty_windows.clear(); + return anyProcessed; +} + +#define GXMAP(k,x,y) case x: k = y; break; + + GHOST_TKey +GHOST_SystemX11:: +convertXKey( + KeySym key +){ + GHOST_TKey type; + + if ((key >= XK_A) && (key <= XK_Z)) { + type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA)); + } else if ((key >= XK_a) && (key <= XK_z)) { + type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA)); + } else if ((key >= XK_0) && (key <= XK_9)) { + type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0)); + } else if ((key >= XK_F1) && (key <= XK_F24)) { + type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1)); +#if defined(__sun) || defined(__sun__) + /* This is a bit of a hack, but it looks like sun + Used F11 and friends for its special keys Stop,again etc.. + So this little patch enables F11 and F12 to work as expected + following link has documentation on it: + http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408 + also from /usr/include/X11/Sunkeysym.h +#define SunXK_F36 0x1005FF10 // Labeled F11 +#define SunXK_F37 0x1005FF11 // Labeled F12 + + mein@cs.umn.edu + */ + + } else if (key == 268828432) { + type = GHOST_kKeyF11; + } else if (key == 268828433) { + type = GHOST_kKeyF12; +#endif + } else { + switch(key) { + GXMAP(type,XK_BackSpace, GHOST_kKeyBackSpace); + GXMAP(type,XK_Tab, GHOST_kKeyTab); + GXMAP(type,XK_Return, GHOST_kKeyEnter); + GXMAP(type,XK_Escape, GHOST_kKeyEsc); + GXMAP(type,XK_space, GHOST_kKeySpace); + + GXMAP(type,XK_Linefeed, GHOST_kKeyLinefeed); + GXMAP(type,XK_semicolon, GHOST_kKeySemicolon); + GXMAP(type,XK_period, GHOST_kKeyPeriod); + GXMAP(type,XK_comma, GHOST_kKeyComma); + GXMAP(type,XK_quoteright, GHOST_kKeyQuote); + GXMAP(type,XK_quoteleft, GHOST_kKeyAccentGrave); + GXMAP(type,XK_minus, GHOST_kKeyMinus); + GXMAP(type,XK_slash, GHOST_kKeySlash); + GXMAP(type,XK_backslash, GHOST_kKeyBackslash); + GXMAP(type,XK_equal, GHOST_kKeyEqual); + GXMAP(type,XK_bracketleft, GHOST_kKeyLeftBracket); + GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket); + GXMAP(type,XK_Pause, GHOST_kKeyPause); + + GXMAP(type,XK_Shift_L, GHOST_kKeyLeftShift); + GXMAP(type,XK_Shift_R, GHOST_kKeyRightShift); + GXMAP(type,XK_Control_L, GHOST_kKeyLeftControl); + GXMAP(type,XK_Control_R, GHOST_kKeyRightControl); + GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt); + GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt); + GXMAP(type,XK_Super_L, GHOST_kKeyOS); + GXMAP(type,XK_Super_R, GHOST_kKeyOS); + + GXMAP(type,XK_Insert, GHOST_kKeyInsert); + GXMAP(type,XK_Delete, GHOST_kKeyDelete); + GXMAP(type,XK_Home, GHOST_kKeyHome); + GXMAP(type,XK_End, GHOST_kKeyEnd); + GXMAP(type,XK_Page_Up, GHOST_kKeyUpPage); + GXMAP(type,XK_Page_Down, GHOST_kKeyDownPage); + + GXMAP(type,XK_Left, GHOST_kKeyLeftArrow); + GXMAP(type,XK_Right, GHOST_kKeyRightArrow); + GXMAP(type,XK_Up, GHOST_kKeyUpArrow); + GXMAP(type,XK_Down, GHOST_kKeyDownArrow); + + GXMAP(type,XK_Caps_Lock, GHOST_kKeyCapsLock); + GXMAP(type,XK_Scroll_Lock, GHOST_kKeyScrollLock); + GXMAP(type,XK_Num_Lock, GHOST_kKeyNumLock); + + /* keypad events */ + + GXMAP(type,XK_KP_0, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_1, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_2, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_3, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_4, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_5, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_6, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_7, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_8, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_9, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Decimal, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Insert, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_End, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_Down, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_Left, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_Begin, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_Right, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_Home, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_Up, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_Page_Up, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Delete, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Enter, GHOST_kKeyNumpadEnter); + GXMAP(type,XK_KP_Add, GHOST_kKeyNumpadPlus); + GXMAP(type,XK_KP_Subtract, GHOST_kKeyNumpadMinus); + GXMAP(type,XK_KP_Multiply, GHOST_kKeyNumpadAsterisk); + GXMAP(type,XK_KP_Divide, GHOST_kKeyNumpadSlash); + + /* Media keys in some keyboards and laptops with XFree86/Xorg */ +#ifdef WITH_XF86KEYSYM + GXMAP(type,XF86XK_AudioPlay, GHOST_kKeyMediaPlay); + GXMAP(type,XF86XK_AudioStop, GHOST_kKeyMediaStop); + GXMAP(type,XF86XK_AudioPrev, GHOST_kKeyMediaFirst); + GXMAP(type,XF86XK_AudioRewind, GHOST_kKeyMediaFirst); + GXMAP(type,XF86XK_AudioNext, GHOST_kKeyMediaLast); + GXMAP(type,XF86XK_AudioForward, GHOST_kKeyMediaLast); +#endif + + /* some extra sun cruft (NICE KEYBOARD!) */ +#ifdef __sun__ + GXMAP(type,0xffde, GHOST_kKeyNumpad1); + GXMAP(type,0xffe0, GHOST_kKeyNumpad3); + GXMAP(type,0xffdc, GHOST_kKeyNumpad5); + GXMAP(type,0xffd8, GHOST_kKeyNumpad7); + GXMAP(type,0xffda, GHOST_kKeyNumpad9); + + GXMAP(type,0xffd6, GHOST_kKeyNumpadSlash); + GXMAP(type,0xffd7, GHOST_kKeyNumpadAsterisk); +#endif + + default : + type = GHOST_kKeyUnknown; + break; + } + } + + return type; +} + +#undef GXMAP + +/* from xclip.c xcout() v0.11 */ + +#define XCLIB_XCOUT_NONE 0 /* no context */ +#define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */ +#define XCLIB_XCOUT_INCR 2 /* in an incr loop */ +#define XCLIB_XCOUT_FALLBACK 3 /* STRING failed, need fallback to UTF8 */ +#define XCLIB_XCOUT_FALLBACK_UTF8 4 /* UTF8 failed, move to compouned */ +#define XCLIB_XCOUT_FALLBACK_COMP 5 /* compouned failed, move to text. */ +#define XCLIB_XCOUT_FALLBACK_TEXT 6 + +// Retrieves the contents of a selections. +void GHOST_SystemX11::getClipboard_xcout(XEvent evt, + Atom sel, Atom target, unsigned char **txt, + unsigned long *len, unsigned int *context) const +{ + Atom pty_type; + int pty_format; + unsigned char *buffer; + unsigned long pty_size, pty_items; + unsigned char *ltxt= *txt; + + vector & win_vec = m_windowManager->getWindows(); + vector::iterator win_it = win_vec.begin(); + GHOST_WindowX11 * window = static_cast(*win_it); + Window win = window->getXWindow(); + + switch (*context) { + // There is no context, do an XConvertSelection() + case XCLIB_XCOUT_NONE: + // Initialise return length to 0 + if (*len > 0) { + free(*txt); + *len = 0; + } + + // Send a selection request + XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime); + *context = XCLIB_XCOUT_SENTCONVSEL; + return; + + case XCLIB_XCOUT_SENTCONVSEL: + if (evt.type != SelectionNotify) + return; + + if (target == m_utf8_string && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_UTF8; + return; + } + else if (target == m_compound_text && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_COMP; + return; + } + else if (target == m_text && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_TEXT; + return; + } + + // find the size and format of the data in property + XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False, + AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, &buffer); + XFree(buffer); + + if (pty_type == m_incr) { + // start INCR mechanism by deleting property + XDeleteProperty(m_display, win, m_xclip_out); + XFlush(m_display); + *context = XCLIB_XCOUT_INCR; + return; + } + + // if it's not incr, and not format == 8, then there's + // nothing in the selection (that xclip understands, anyway) + + if (pty_format != 8) { + *context = XCLIB_XCOUT_NONE; + return; + } + + // not using INCR mechanism, just read the property + XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size, + False, AnyPropertyType, &pty_type, + &pty_format, &pty_items, &pty_size, &buffer); + + // finished with property, delete it + XDeleteProperty(m_display, win, m_xclip_out); + + // copy the buffer to the pointer for returned data + ltxt = (unsigned char *) malloc(pty_items); + memcpy(ltxt, buffer, pty_items); + + // set the length of the returned data + *len = pty_items; + *txt = ltxt; + + // free the buffer + XFree(buffer); + + *context = XCLIB_XCOUT_NONE; + + // complete contents of selection fetched, return 1 + return; + + case XCLIB_XCOUT_INCR: + // To use the INCR method, we basically delete the + // property with the selection in it, wait for an + // event indicating that the property has been created, + // then read it, delete it, etc. + + // make sure that the event is relevant + if (evt.type != PropertyNotify) + return; + + // skip unless the property has a new value + if (evt.xproperty.state != PropertyNewValue) + return; + + // check size and format of the property + XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False, + AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, (unsigned char **) &buffer); + + if (pty_format != 8) { + // property does not contain text, delete it + // to tell the other X client that we have read + // it and to send the next property + XFree(buffer); + XDeleteProperty(m_display, win, m_xclip_out); + return; + } + + if (pty_size == 0) { + // no more data, exit from loop + XFree(buffer); + XDeleteProperty(m_display, win, m_xclip_out); + *context = XCLIB_XCOUT_NONE; + + // this means that an INCR transfer is now + // complete, return 1 + return; + } + + XFree(buffer); + + // if we have come this far, the propery contains + // text, we know the size. + XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size, + False, AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, (unsigned char **) &buffer); + + // allocate memory to accommodate data in *txt + if (*len == 0) { + *len = pty_items; + ltxt = (unsigned char *) malloc(*len); + } + else { + *len += pty_items; + ltxt = (unsigned char *) realloc(ltxt, *len); + } + + // add data to ltxt + memcpy(<xt[*len - pty_items], buffer, pty_items); + + *txt = ltxt; + XFree(buffer); + + // delete property to get the next item + XDeleteProperty(m_display, win, m_xclip_out); + XFlush(m_display); + return; + } + return; +} + +GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const +{ + Atom sseln; + Atom target= m_string; + Window owner; + + // from xclip.c doOut() v0.11 + unsigned char *sel_buf; + unsigned long sel_len= 0; + XEvent evt; + unsigned int context= XCLIB_XCOUT_NONE; + + if (selection == True) + sseln= m_primary; + else + sseln= m_clipboard; + + vector & win_vec = m_windowManager->getWindows(); + vector::iterator win_it = win_vec.begin(); + GHOST_WindowX11 * window = static_cast(*win_it); + Window win = window->getXWindow(); + + /* check if we are the owner. */ + owner= XGetSelectionOwner(m_display, sseln); + if (owner == win) { + if (sseln == m_clipboard) { + sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1); + strcpy((char *)sel_buf, txt_cut_buffer); + return((GHOST_TUns8*)sel_buf); + } + else { + sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1); + strcpy((char *)sel_buf, txt_select_buffer); + return((GHOST_TUns8*)sel_buf); + } + } + else if (owner == None) + return(NULL); + + while (1) { + /* only get an event if xcout() is doing something */ + if (context != XCLIB_XCOUT_NONE) + XNextEvent(m_display, &evt); + + /* fetch the selection, or part of it */ + getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context); + + /* fallback is needed. set XA_STRING to target and restart the loop. */ + if (context == XCLIB_XCOUT_FALLBACK) { + context= XCLIB_XCOUT_NONE; + target= m_string; + continue; + } + else if (context == XCLIB_XCOUT_FALLBACK_UTF8) { + /* utf8 fail, move to compouned text. */ + context= XCLIB_XCOUT_NONE; + target= m_compound_text; + continue; + } + else if (context == XCLIB_XCOUT_FALLBACK_COMP) { + /* compouned text faile, move to text. */ + context= XCLIB_XCOUT_NONE; + target= m_text; + continue; + } + + /* only continue if xcout() is doing something */ + if (context == XCLIB_XCOUT_NONE) + break; + } + + if (sel_len) { + /* only print the buffer out, and free it, if it's not + * empty + */ + unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1); + memcpy((char*)tmp_data, (char*)sel_buf, sel_len); + tmp_data[sel_len] = '\0'; + + if (sseln == m_string) + XFree(sel_buf); + else + free(sel_buf); + + return (GHOST_TUns8*)tmp_data; + } + return(NULL); +} + +void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const +{ + Window m_window, owner; + + vector & win_vec = m_windowManager->getWindows(); + vector::iterator win_it = win_vec.begin(); + GHOST_WindowX11 * window = static_cast(*win_it); + m_window = window->getXWindow(); + + if (buffer) { + if (selection == False) { + XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime); + owner= XGetSelectionOwner(m_display, m_clipboard); + if (txt_cut_buffer) + free((void*)txt_cut_buffer); + + txt_cut_buffer = (char*) malloc(strlen(buffer)+1); + strcpy(txt_cut_buffer, buffer); + } else { + XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime); + owner= XGetSelectionOwner(m_display, m_primary); + if (txt_select_buffer) + free((void*)txt_select_buffer); + + txt_select_buffer = (char*) malloc(strlen(buffer)+1); + strcpy(txt_select_buffer, buffer); + } + + if (owner != m_window) + fprintf(stderr, "failed to own primary\n"); + } +} diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h new file mode 100644 index 00000000000..0b001273634 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -0,0 +1,312 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_SystemX11.h + * \ingroup GHOST + * Declaration of GHOST_SystemX11 class. + */ + +#ifndef _GHOST_SYSTEM_X11_H_ +#define _GHOST_SYSTEM_X11_H_ + +#include +#include + +#include "GHOST_System.h" +#include "../GHOST_Types.h" + +class GHOST_WindowX11; + +/** + * X11 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_SystemX11 : public GHOST_System { +public: + + /** + * Constructor + * this class should only be instanciated by GHOST_ISystem. + */ + + GHOST_SystemX11( + ); + + /** + * Destructor. + */ + virtual ~GHOST_SystemX11(); + + + GHOST_TSuccess + init( + ); + + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * @return The number of milliseconds. + */ + GHOST_TUns64 + getMilliSeconds( + ) const; + + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + GHOST_TUns8 + getNumDisplays( + ) const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void + getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height + ) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @param parentWindow Parent (embedder) window + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* + createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples = 0, + const GHOST_TEmbedderWindowID parentWindow = 0 + ); + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + bool + processEvents( + bool waitForEvent + ); + + /** + * @section Interface Inherited from GHOST_System + */ + GHOST_TSuccess + getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y + ) const; + + GHOST_TSuccess + setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y + ); + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + GHOST_TSuccess + getModifierKeys( + GHOST_ModifierKeys& keys + ) const ; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + GHOST_TSuccess + getButtons( + GHOST_Buttons& buttons + ) const; + + /** + * @section Interface Dirty + * Flag a window as dirty. This will + * generate a GHOST window update event on a call to processEvents() + */ + + void + addDirtyWindow( + GHOST_WindowX11 * bad_wind + ); + + + /** + * return a pointer to the X11 display structure + */ + + Display * + getXDisplay( + ) { + return m_display; + } + + void * + prepareNdofInfo( + volatile GHOST_TEventNDOFData *current_values + ); + + /* Helped function for get data from the clipboard. */ + void getClipboard_xcout(XEvent evt, Atom sel, Atom target, + unsigned char **txt, unsigned long *len, + unsigned int *context) const; + + /** + * Returns unsinged char from CUT_BUFFER0 + * @param selection Get selection, X11 only feature + * @return Returns the Clipboard indicated by Flag + */ + GHOST_TUns8 *getClipboard(bool selection) const; + + /** + * Puts buffer to system clipboard + * @param buffer The buffer to copy to the clipboard + * @param selection Set the selection into the clipboard, X11 only feature + */ + void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + + /** + * @see GHOST_ISystem + */ + int toggleConsole(int action) { return 0; } + + /** + * Atom used for ICCCM, WM-spec and Motif. + * We only need get this atom at the start, it's relative + * to the display not the window and are public for every + * window that need it. + */ + Atom m_wm_state; + Atom m_wm_change_state; + Atom m_net_state; + Atom m_net_max_horz; + Atom m_net_max_vert; + Atom m_net_fullscreen; + Atom m_motif; + Atom m_wm_take_focus; + Atom m_wm_protocols; + Atom m_delete_window_atom; + + /* Atoms for Selection, copy & paste. */ + Atom m_targets; + Atom m_string; + Atom m_compound_text; + Atom m_text; + Atom m_clipboard; + Atom m_primary; + Atom m_xclip_out; + Atom m_incr; + Atom m_utf8_string; + +private : + + Display * m_display; + + /// The vector of windows that need to be updated. + std::vector m_dirty_windows; + + /// Start time at initialization. + GHOST_TUns64 m_start_time; + + /// A vector of keyboard key masks + char m_keyboard_vector[32]; + + /* to prevent multiple warp, we store the time of the last warp event + * and stop accumulating all events generated before that */ + Time m_last_warp; + + /** + * Return the ghost window associated with the + * X11 window xwind + */ + + GHOST_WindowX11 * + findGhostWindow( + Window xwind + ) const ; + + void + processEvent( + XEvent *xe + ); + + Time + lastEventTime( + Time default_time + ); + + bool + generateWindowExposeEvents( + ); + + GHOST_TKey + convertXKey( + KeySym key + ); + +}; + +#endif + diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h new file mode 100644 index 00000000000..ef9ebdf5860 --- /dev/null +++ b/intern/ghost/intern/GHOST_TaskbarWin32.h @@ -0,0 +1,76 @@ +/** \file ghost/intern/GHOST_TaskbarWin32.h + * \ingroup GHOST + */ +#ifndef GHOST_TASKBARWIN32_H_ +#define GHOST_TASKBARWIN32_H_ +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include +#include + +/* MinGW needs it */ +#ifdef FREE_WINDOWS +#ifdef WINVER +#undef WINVER +#endif +#define WINVER 0x0501 +#endif /* FREE_WINDOWS */ + +// ITaskbarList, ITaskbarList2 and ITaskbarList3 might be missing, present here in that case. +// Note, ITaskbarList3 is supported only since Windows 7, though. Check for that is done in +// GHOST_WindowWin32 +#ifndef __ITaskbarList_INTERFACE_DEFINED__ +#define __ITaskbarList_INTERFACE_DEFINED__ + extern "C" {const GUID CLSID_TaskbarList = {0x56FDF344, 0xFD6D, 0x11D0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90} }; + const GUID IID_ITaskbarList = {0x56FDF342, 0xFD6D, 0x11D0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90} }; } + class ITaskbarList : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE HrInit (void) = 0; + virtual HRESULT STDMETHODCALLTYPE AddTab (HWND hwnd) = 0; + virtual HRESULT STDMETHODCALLTYPE DeleteTab (HWND hwnd) = 0; + virtual HRESULT STDMETHODCALLTYPE ActivateTab (HWND hwnd) = 0; + virtual HRESULT STDMETHODCALLTYPE SetActiveAlt (HWND hwnd) = 0; + }; +#endif /* ITaskbarList */ + +#ifndef __ITaskbarList2_INTERFACE_DEFINED__ +#define __ITaskbarList2_INTERFACE_DEFINED__ + extern "C" {const GUID IID_ITaskbarList2 = {0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17} }; } + class ITaskbarList2 : public ITaskbarList + { + public: + virtual HRESULT STDMETHODCALLTYPE MarkFullscreenWindow(HWND hwnd, BOOL fFullscreen) = 0; + }; +#endif /* ITaskbarList2 */ + +#ifndef __ITaskbarList3_INTERFACE_DEFINED__ +#define __ITaskbarList3_INTERFACE_DEFINED__ +typedef enum THUMBBUTTONFLAGS {THBF_ENABLED = 0, THBF_DISABLED = 0x1, THBF_DISMISSONCLICK = 0x2, THBF_NOBACKGROUND = 0x4, THBF_HIDDEN = 0x8, THBF_NONINTERACTIVE = 0x10} THUMBBUTTONFLAGS; +typedef enum THUMBBUTTONMASK {THB_BITMAP = 0x1, THB_ICON = 0x2, THB_TOOLTIP = 0x4, THB_FLAGS = 0x8} THUMBBUTTONMASK; +typedef struct THUMBBUTTON {THUMBBUTTONMASK dwMask; UINT iId; UINT iBitmap; HICON hIcon; WCHAR szTip[260]; THUMBBUTTONFLAGS dwFlags; } THUMBBUTTON; +typedef enum TBPFLAG {TBPF_NOPROGRESS = 0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 } TBPFLAG; +#define THBN_CLICKED 0x1800 + extern "C" {const GUID IID_ITaskList3 = { 0xEA1AFB91, 0x9E28, 0x4B86, {0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF} };} + + class ITaskbarList3 : public ITaskbarList2 + { + public: + virtual HRESULT STDMETHODCALLTYPE SetProgressValue (HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) = 0; + virtual HRESULT STDMETHODCALLTYPE SetProgressState (HWND hwnd, TBPFLAG tbpFlags) = 0; + virtual HRESULT STDMETHODCALLTYPE RegisterTab (HWND hwndTab, HWND hwndMDI) = 0; + virtual HRESULT STDMETHODCALLTYPE UnregisterTab (HWND hwndTab) = 0; + virtual HRESULT STDMETHODCALLTYPE SetTabOrder (HWND hwndTab, HWND hwndInsertBefore) = 0; + virtual HRESULT STDMETHODCALLTYPE SetTabActive (HWND hwndTab, HWND hwndMDI, DWORD dwReserved) = 0; + virtual HRESULT STDMETHODCALLTYPE ThumbBarAddButtons (HWND hwnd, UINT cButtons, THUMBBUTTON * pButton) = 0; + virtual HRESULT STDMETHODCALLTYPE ThumbBarUpdateButtons (HWND hwnd, UINT cButtons, THUMBBUTTON * pButton) = 0; + virtual HRESULT STDMETHODCALLTYPE ThumbBarSetImageList (HWND hwnd, HIMAGELIST himl) = 0; + virtual HRESULT STDMETHODCALLTYPE SetOverlayIcon (HWND hwnd, HICON hIcon, LPCWSTR pszDescription) = 0; + virtual HRESULT STDMETHODCALLTYPE SetThumbnailTooltip (HWND hwnd, LPCWSTR pszTip) = 0; + virtual HRESULT STDMETHODCALLTYPE SetThumbnailClip (HWND hwnd, RECT *prcClip) = 0; + }; +#endif /* ITaskbarList3 */ + +#endif /*GHOST_TASKBARWIN32_H_*/ diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp new file mode 100644 index 00000000000..fac0bb55515 --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.cpp @@ -0,0 +1,165 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TimerManager.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#include "GHOST_TimerManager.h" + +#include + +#include "GHOST_TimerTask.h" + + +GHOST_TimerManager::GHOST_TimerManager() +{ +} + + +GHOST_TimerManager::~GHOST_TimerManager() +{ + disposeTimers(); +} + + +GHOST_TUns32 GHOST_TimerManager::getNumTimers() +{ + return (GHOST_TUns32)m_timers.size(); +} + + +bool GHOST_TimerManager::getTimerFound(GHOST_TimerTask* timer) +{ + TTimerVector::const_iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + return iter != m_timers.end(); +} + + +GHOST_TSuccess GHOST_TimerManager::addTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + if (!getTimerFound(timer)) { + // Add the timer task + m_timers.push_back(timer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_TimerManager::removeTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + TTimerVector::iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + if (iter != m_timers.end()) { + // Remove the timer task + m_timers.erase(iter); + delete timer; + timer = 0; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TUns64 GHOST_TimerManager::nextFireTime() +{ + GHOST_TUns64 smallest = GHOST_kFireTimeNever; + TTimerVector::iterator iter; + + for (iter = m_timers.begin(); iter != m_timers.end(); iter++) { + GHOST_TUns64 next = (*iter)->getNext(); + + if (nextgetNext(); + + // Check if the timer should be fired + if (time > next) { + // Fire the timer + GHOST_TimerProcPtr timerProc = task->getTimerProc(); + GHOST_TUns64 start = task->getStart(); + timerProc(task, time - start); + + // Update the time at which we will fire it again + GHOST_TUns64 interval = task->getInterval(); + GHOST_TUns64 numCalls = (next - start) / interval; + numCalls++; + next = start + numCalls * interval; + task->setNext(next); + + return true; + } else { + return false; + } +} + + +void GHOST_TimerManager::disposeTimers() +{ + while (m_timers.size() > 0) { + delete m_timers[0]; + m_timers.erase(m_timers.begin()); + } +} diff --git a/intern/ghost/intern/GHOST_TimerManager.h b/intern/ghost/intern/GHOST_TimerManager.h new file mode 100644 index 00000000000..fe08fe3a002 --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.h @@ -0,0 +1,126 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TimerManager.h + * \ingroup GHOST + * Declaration of GHOST_TimerManager class. + */ + +#ifndef _GHOST_TIMER_MANAGER_H_ +#define _GHOST_TIMER_MANAGER_H_ + +#include + +#include "GHOST_Types.h" + +class GHOST_TimerTask; + + +/** + * Manages a list of timer tasks. + * Timer tasks added are owned by the manager. + * Don't delete timer task objects. + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_TimerManager +{ +public: + /** + * Constructor. + */ + GHOST_TimerManager(); + + /** + * Destructor. + */ + virtual ~GHOST_TimerManager(); + + /** + * Returns the number of timer tasks. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumTimers(); + + /** + * Returns whther this timer task ins in our list. + * @return Indication of presence. + */ + virtual bool getTimerFound(GHOST_TimerTask* timer); + + /** + * Adds a timer task to the list. + * It is only added when it not already present in the list. + * @param timer The timer task added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addTimer(GHOST_TimerTask* timer); + + /** + * Removes a timer task from the list. + * It is only removed when it is found in the list. + * @param timer The timer task to be removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeTimer(GHOST_TimerTask* timer); + + /** + * Finds the soonest time the next timer would fire. + * @return The soonest time the next timer would fire, + * or GHOST_kFireTimeNever if no timers exist. + */ + virtual GHOST_TUns64 nextFireTime(); + + /** + * Checks all timer tasks to see if they are expired and fires them if needed. + * @param time The current time. + * @return True if any timers were fired. + */ + virtual bool fireTimers(GHOST_TUns64 time); + + /** + * Checks this timer task to see if they are expired and fires them if needed. + * @param time The current time. + * @param task The timer task to check and optionally fire. + * @return True if the timer fired. + */ + virtual bool fireTimer(GHOST_TUns64 time, GHOST_TimerTask* task); + +protected: + /** + * Deletes all timers. + */ + void disposeTimers(); + + typedef std::vector TTimerVector; + /** The list with event consumers. */ + TTimerVector m_timers; +}; + +#endif // _GHOST_TIMER_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h new file mode 100644 index 00000000000..945cbb7553a --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerTask.h @@ -0,0 +1,189 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TimerTask.h + * \ingroup GHOST + * Declaration of GHOST_TimerTask class. + */ + +#ifndef _GHOST_TIMER_TASK_H_ +#define _GHOST_TIMER_TASK_H_ + +#include "GHOST_ITimerTask.h" + + +/** + * Implementation of a timer task. + * @author Maarten Gribnau + * @date May 28, 2001 + */ +class GHOST_TimerTask : public GHOST_ITimerTask +{ +public: + /** + * Constructor. + * @param start The timer start time. + * @param interval The interval between calls to the timerProc + * @param timerProc The callbak invoked when the interval expires. + * @param data The timer user data. + */ + GHOST_TimerTask(GHOST_TUns64 start, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) + : m_start(start), m_interval(interval), m_next(start), m_timerProc(timerProc), m_userData(userData), m_auxData(0) + { + } + + /** + * Returns the timer start time. + * @return The timer start time. + */ + inline virtual GHOST_TUns64 getStart() const + { + return m_start; + } + + /** + * Changes the timer start time. + * @param start The timer start time. + */ + virtual void setStart(GHOST_TUns64 start) + { + m_start = start; + } + + /** + * Returns the timer interval. + * @return The timer interval. + */ + inline virtual GHOST_TUns64 getInterval() const + { + return m_interval; + } + + /** + * Changes the timer interval. + * @param interval The timer interval. + */ + virtual void setInterval(GHOST_TUns64 interval) + { + m_interval = interval; + } + + /** + * Returns the time the timerProc will be called. + * @return The time the timerProc will be called. + */ + inline virtual GHOST_TUns64 getNext() const + { + return m_next; + } + + /** + * Changes the time the timerProc will be called. + * @param next The time the timerProc will be called. + */ + virtual void setNext(GHOST_TUns64 next) + { + m_next = next; + } + + /** + * Returns the timer callback. + * @return the timer callback. + */ + inline virtual GHOST_TimerProcPtr getTimerProc() const + { + return m_timerProc; + } + + /** + * Changes the timer callback. + * @param The timer callback. + */ + inline virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) + { + m_timerProc = timerProc; + } + + /** + * Returns the timer user data. + * @return The timer user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + + /** + * Returns the auxiliary storage room. + * @return The auxiliary storage room. + */ + inline virtual GHOST_TUns32 getAuxData() const + { + return m_auxData; + } + + /** + * Changes the auxiliary storage room. + * @param auxData The auxiliary storage room. + */ + virtual void setAuxData(GHOST_TUns32 auxData) + { + m_auxData = auxData; + } + +protected: + /** The time the timer task was started. */ + GHOST_TUns64 m_start; + + /** The interval between calls. */ + GHOST_TUns64 m_interval; + + /** The time the timerProc will be called. */ + GHOST_TUns64 m_next; + + /** The callback invoked when the timer expires. */ + GHOST_TimerProcPtr m_timerProc; + + /** The timer task user data. */ + GHOST_TUserDataPtr m_userData; + + /** Auxiliary storage room. */ + GHOST_TUns32 m_auxData; +}; + +#endif // _GHOST_TIMER_TASK_H_ + diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp new file mode 100644 index 00000000000..c518272d614 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -0,0 +1,189 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Window.cpp + * \ingroup GHOST + */ + + +/** + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#include "GHOST_Window.h" + + +GHOST_Window::GHOST_Window( + const STR_String& /*title*/, + GHOST_TInt32 /*left*/, GHOST_TInt32 /*top*/, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples) +: + m_drawingContextType(type), + m_cursorVisible(true), + m_cursorGrab(GHOST_kGrabDisable), + m_cursorShape(GHOST_kStandardCursorDefault), + m_stereoVisual(stereoVisual), + m_numOfAASamples(numOfAASamples) +{ + m_isUnsavedChanges = false; + m_canAcceptDragOperation = false; + + m_progressBarVisible = false; + + m_cursorGrabAccumPos[0] = 0; + m_cursorGrabAccumPos[1] = 0; + + m_fullScreen = state == GHOST_kWindowStateFullScreen; + if (m_fullScreen) { + m_fullScreenWidth = width; + m_fullScreenHeight = height; + } +} + + +GHOST_Window::~GHOST_Window() +{ +} + +void* GHOST_Window::getOSWindow() const +{ + return NULL; +} + +GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (type != m_drawingContextType) { + success = removeDrawingContext(); + if (success) { + success = installDrawingContext(type); + m_drawingContextType = type; + } + else { + m_drawingContextType = GHOST_kDrawingContextTypeNone; + } + } + return success; +} + +GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) +{ + if (setWindowCursorVisibility(visible)) { + m_cursorVisible = visible; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds) +{ + if(m_cursorGrab == mode) + return GHOST_kSuccess; + + if (setWindowCursorGrab(mode)) { + + if(mode==GHOST_kGrabDisable) + m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; + else if (bounds) { + m_cursorGrabBounds= *bounds; + } else { /* if bounds not defined, use window */ + getClientBounds(m_cursorGrabBounds); + } + m_cursorGrab = mode; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect& bounds) +{ + bounds= m_cursorGrabBounds; + return (bounds.m_l==-1 && bounds.m_r==-1) ? GHOST_kFailure : GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (setWindowCursorShape(cursorShape)) { + m_cursorShape = cursorShape; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) +{ + return setCustomCursorShape( (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, + 16, 16, hotX, hotY, 0, 1 ); +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, + int fg_color, int bg_color ) +{ + if (setWindowCustomCursorShape(bitmap, mask, sizex, sizey,hotX, hotY, fg_color, bg_color)) { + m_cursorShape = GHOST_kStandardCursorCustom; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +void GHOST_Window::setAcceptDragOperation(bool canAccept) +{ + m_canAcceptDragOperation = canAccept; +} + +bool GHOST_Window::canAcceptDragOperation() const +{ + return m_canAcceptDragOperation; +} + +GHOST_TSuccess GHOST_Window::setModifiedState(bool isUnsavedChanges) +{ + m_isUnsavedChanges = isUnsavedChanges; + + return GHOST_kSuccess; +} + +bool GHOST_Window::getModifiedState() +{ + return m_isUnsavedChanges; +} diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h new file mode 100644 index 00000000000..e0c676f53a5 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.h @@ -0,0 +1,395 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Window.h + * \ingroup GHOST + * Declaration of GHOST_Window class. + */ + +#ifndef _GHOST_WINDOW_H_ +#define _GHOST_WINDOW_H_ + +#include "GHOST_IWindow.h" + +class STR_String; + +/** + * Platform independent implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the + * upper-left corner of the screen. + * Implements part of the GHOST_IWindow interface and adds some methods to + * be implemented by childs of this class. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_Window : public GHOST_IWindow +{ +public: + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TWindowOrder getOrder(void) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param heigh The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + */ + GHOST_Window( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0); + + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_Window(); + + /** + * Returns the associated OS object/handle + * @return The associated OS object/handle + */ + virtual void* getOSWindow() const; + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + inline virtual GHOST_TStandardCursor getCursorShape() const; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape); + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color); + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + inline virtual bool getCursorVisibility() const; + inline virtual GHOST_TGrabCursorMode getCursorGrabMode() const; + inline virtual void getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const; + inline virtual void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; + inline virtual void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible); + + /** + * Sets the cursor grab. + * @param mode The new grab state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds); + + /** + * Gets the cursor grab region, if unset the window is used. + * reset when grab is disabled. + */ + virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect& bounds); + + /** + * Sets the progress bar value displayed in the window/application icon + * @param progress The progress % (0.0 to 1.0) + */ + virtual GHOST_TSuccess setProgressBar(float progress) {return GHOST_kFailure;}; + + /** + * Hides the progress bar in the icon + */ + virtual GHOST_TSuccess endProgressBar() {return GHOST_kFailure;}; + + /** + * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop + */ + virtual void setAcceptDragOperation(bool canAccept); + + /** + * Returns acceptance of the dropped object + * Usually called by the "object dropped" event handling function + */ + virtual bool canAcceptDragOperation() const; + + /** + * Sets the window "modified" status, indicating unsaved changes + * @param isUnsavedChanges Unsaved changes or not + * @return Indication of success. + */ + virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges); + + /** + * Gets the window "modified" status, indicating unsaved changes + * @return True if there are unsaved changes + */ + virtual bool getModifiedState(); + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + inline virtual GHOST_TDrawingContextType getDrawingContextType(); + + /** + * Tries to install a rendering context in this window. + * Child classes do not need to overload this method. + * They should overload the installDrawingContext and removeDrawingContext instead. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type); + + /** + * Returns the window user data. + * @return The window user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type) = 0; + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext() = 0; + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible) = 0; + + /** + * Sets the cursor grab on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) { return GHOST_kSuccess; }; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) = 0; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) = 0; + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int szx, int szy, int hotX, int hotY, int fg, int bg) = 0; + /** The the of drawing context installed in this window. */ + GHOST_TDrawingContextType m_drawingContextType; + + /** The window user data */ + GHOST_TUserDataPtr m_userData; + + /** The current visibility of the cursor */ + bool m_cursorVisible; + + /** The current grabbed state of the cursor */ + GHOST_TGrabCursorMode m_cursorGrab; + + /** Initial grab location. */ + GHOST_TInt32 m_cursorGrabInitPos[2]; + + /** Accumulated offset from m_cursorGrabInitPos. */ + GHOST_TInt32 m_cursorGrabAccumPos[2]; + + /** Wrap the cursor within this region. */ + GHOST_Rect m_cursorGrabBounds; + + /** The current shape of the cursor */ + GHOST_TStandardCursor m_cursorShape; + + /** The presence of progress indicator with the application icon */ + bool m_progressBarVisible; + + /** The acceptance of the "drop candidate" of the current drag'n'drop operation */ + bool m_canAcceptDragOperation; + + /** Modified state : are there unsaved changes */ + bool m_isUnsavedChanges; + + /** Stores wether this is a full screen window. */ + bool m_fullScreen; + + /** Stereo visual created. Only necessary for 'real' stereo support, + * ie quad buffered stereo. This is not always possible, depends on + * the graphics h/w + */ + bool m_stereoVisual; + + /** Number of samples used in anti-aliasing, set to 0 if no AA **/ + GHOST_TUns16 m_numOfAASamples; + + /** Full-screen width */ + GHOST_TUns32 m_fullScreenWidth; + /** Full-screen height */ + GHOST_TUns32 m_fullScreenHeight; +}; + + +inline GHOST_TDrawingContextType GHOST_Window::getDrawingContextType() +{ + return m_drawingContextType; +} + +inline bool GHOST_Window::getCursorVisibility() const +{ + return m_cursorVisible; +} + +inline GHOST_TGrabCursorMode GHOST_Window::getCursorGrabMode() const +{ + return m_cursorGrab; +} + +inline void GHOST_Window::getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + x = m_cursorGrabInitPos[0]; + y = m_cursorGrabInitPos[1]; +} + +inline void GHOST_Window::getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + x= m_cursorGrabAccumPos[0]; + y= m_cursorGrabAccumPos[1]; +} + +inline void GHOST_Window::setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y) +{ + m_cursorGrabAccumPos[0]= x; + m_cursorGrabAccumPos[1]= y; +} + +inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const +{ + return m_cursorShape; +} + +#endif // _GHOST_WINDOW_H + diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp new file mode 100644 index 00000000000..1ffd117d658 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -0,0 +1,748 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowCarbon.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#include "GHOST_WindowCarbon.h" +#include "GHOST_Debug.h" + +AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL; +#ifdef GHOST_DRAW_CARBON_GUTTER +const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16; +#endif //GHOST_DRAW_CARBON_GUTTER + +static const GLint sPreferredFormatWindow[10] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_DEPTH_SIZE, 32, +AGL_NONE, +}; + +static const GLint sPreferredFormatFullScreen[11] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_FULLSCREEN, +AGL_DEPTH_SIZE, 32, +AGL_NONE, +}; + + + +WindowRef ugly_hack=NULL; + +const EventTypeSpec kWEvents[] = { + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ +}; + +static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { + WindowRef mywindow; + GHOST_WindowCarbon *ghost_window; + OSStatus err; + int theState; + + if (::GetEventKind(event) == kEventWindowZoom) { + err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow); + ghost_window = (GHOST_WindowCarbon *) GetWRefCon(mywindow); + theState = ghost_window->getMac_windowState(); + if (theState == 1) + ghost_window->setMac_windowState(2); + else if (theState == 2) + ghost_window->setMac_windowState(1); + + } + return eventNotHandledErr; +} + +GHOST_WindowCarbon::GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples +) : + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), + m_windowRef(0), + m_grafPtr(0), + m_aglCtx(0), + m_customCursor(0), + m_fullScreenDirty(false) +{ + Str255 title255; + OSStatus err; + + //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); + + if (state >= GHOST_kWindowState8Normal ) { + if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; + else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; + else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized; + else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen; + + // state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0 + + setMac_windowState(1); + } else + setMac_windowState(0); + + if (state != GHOST_kWindowStateFullScreen) { + Rect bnds = { top, left, top+height, left+width }; + // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ + gen2mac(title, title255); + + err = ::CreateNewWindow( kDocumentWindowClass, + kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, + &bnds, + &m_windowRef); + + if ( err != noErr) { + fprintf(stderr," error creating window %i \n",(int)err); + } else { + + ::SetWRefCon(m_windowRef,(SInt32)this); + setTitle(title); + err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); + if ( err != noErr) { + fprintf(stderr," error creating handler %i \n",(int)err); + } else { + // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); + ::ShowWindow(m_windowRef); + ::MoveWindow (m_windowRef, left, top,true); + + } + } + if (m_windowRef) { + m_grafPtr = ::GetWindowPort(m_windowRef); + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + } + if(ugly_hack==NULL) { + ugly_hack= m_windowRef; + // when started from commandline, window remains in the back... also for play anim + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcess(&psn); + } + } + else { + /* + Rect bnds = { top, left, top+height, left+width }; + gen2mac("", title255); + m_windowRef = ::NewCWindow( + nil, // Storage + &bnds, // Bounding rectangle of the window + title255, // Title of the window + 0, // Window initially visible + plainDBox, // procID + (WindowRef)-1L, // Put window before all other windows + 0, // Window has minimize box + (SInt32)this); // Store a pointer to the class in the refCon + */ + //GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n"); + setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); + updateDrawingContext(); + activateDrawingContext(); + + m_tablet.Active = GHOST_kTabletModeNone; + } +} + + +GHOST_WindowCarbon::~GHOST_WindowCarbon() +{ + if (m_customCursor) delete m_customCursor; + + if(ugly_hack==m_windowRef) ugly_hack= NULL; + + // printf("GHOST_WindowCarbon::~GHOST_WindowCarbon(): removing drawing context\n"); + if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_windowRef) { + ::DisposeWindow(m_windowRef); + m_windowRef = 0; + } +} + +bool GHOST_WindowCarbon::getValid() const +{ + bool valid; + if (!m_fullScreen) { + valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef); + } + else { + valid = true; + } + return valid; +} + + +void GHOST_WindowCarbon::setTitle(const STR_String& title) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setTitle(): window invalid") + Str255 title255; + gen2mac(title, title255); + ::SetWTitle(m_windowRef, title255); +} + + +void GHOST_WindowCarbon::getTitle(STR_String& title) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getTitle(): window invalid") + Str255 title255; + ::GetWTitle(m_windowRef, title255); + mac2gen(title255, title); +} + + +void GHOST_WindowCarbon::getWindowBounds(GHOST_Rect& bounds) const +{ + OSStatus success; + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getWindowBounds(): window invalid") + success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowCarbon::getClientBounds(GHOST_Rect& bounds) const +{ + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getClientBounds(): window invalid") + //::GetPortBounds(m_grafPtr, &rect); + ::GetWindowBounds(m_windowRef, kWindowContentRgn, &rect); + + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; + + // Subtract gutter height from bottom +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((bounds.m_b - bounds.m_t) > s_sizeRectSize) + { + bounds.m_b -= s_sizeRectSize; + } + else + { + bounds.m_t = bounds.m_b; + } +#endif //GHOST_DRAW_CARBON_GUTTER +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientWidth(GHOST_TUns32 width) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientWidth(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (((GHOST_TUns32)cBnds.getWidth()) != width) { + ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true); + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientHeight(GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientHeight(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientSize(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) { + ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height)) { + ::SizeWindow(m_windowRef, width, height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TWindowState GHOST_WindowCarbon::getState() const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getState(): window invalid") + GHOST_TWindowState state; + if (::IsWindowVisible(m_windowRef) == false) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsWindowInStandardState(m_windowRef, nil, nil)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowCarbon::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::screenToClient(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::GlobalToLocal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +void GHOST_WindowCarbon::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::clientToScreen(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::LocalToGlobal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setState(GHOST_TWindowState state) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setState(): window invalid") + switch (state) { + case GHOST_kWindowStateMinimized: + ::HideWindow(m_windowRef); + break; + case GHOST_kWindowStateModified: + SetWindowModified(m_windowRef, 1); + break; + case GHOST_kWindowStateUnModified: + SetWindowModified(m_windowRef, 0); + break; + case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateNormal: + default: + ::ShowWindow(m_windowRef); + break; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setOrder(GHOST_TWindowOrder order) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setOrder(): window invalid") + if (order == GHOST_kWindowOrderTop) { + //::BringToFront(m_windowRef); is wrong, front window should be active for input too + ::SelectWindow(m_windowRef); + } + else { + /* doesnt work if you do this with a mouseclick */ + ::SendBehind(m_windowRef, nil); + } + return GHOST_kSuccess; +} + +/*#define WAIT_FOR_VSYNC 1*/ +#ifdef WAIT_FOR_VSYNC +#include +#endif + +GHOST_TSuccess GHOST_WindowCarbon::swapBuffers() +{ +#ifdef WAIT_FOR_VSYNC +/* wait for vsync, to avoid tearing artifacts */ +long VBL = 1; +CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); +#endif + + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSwapBuffers(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::updateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglUpdateContext(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::activateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSetCurrentContext(m_aglCtx); +#ifdef GHOST_DRAW_CARBON_GUTTER + // Restrict drawing to non-gutter area + ::aglEnable(m_aglCtx, AGL_BUFFER_RECT); + GHOST_Rect bnds; + getClientBounds(bnds); + GLint b[4] = + { + bnds.m_l, + bnds.m_t+s_sizeRectSize, + bnds.m_r-bnds.m_l, + bnds.m_b-bnds.m_t + }; + GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); +#endif //GHOST_DRAW_CARBON_GUTTER + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + + +GHOST_TSuccess GHOST_WindowCarbon::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if (!getValid()) break; + + AGLPixelFormat pixelFormat; + if (!m_fullScreen) { + pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); + m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL\n"); +GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen); + m_aglCtx = ::aglCreateContext(pixelFormat, 0); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): created OpenGL context\n"); + //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) + success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + /* + if (success == GHOST_kSuccess) { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL succeeded\n"); + } + else { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL failed\n"); + } + */ + } + ::aglDestroyPixelFormat(pixelFormat); + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::removeDrawingContext() +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_aglCtx) { + aglSetCurrentContext(NULL); + aglSetDrawable(m_aglCtx, NULL); + //aglDestroyContext(m_aglCtx); + if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL; + success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + m_aglCtx = 0; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::invalidate() +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::invalidate(): window invalid") + if (!m_fullScreen) { + Rect rect; + ::GetPortBounds(m_grafPtr, &rect); + ::InvalWindowRect(m_windowRef, &rect); + } + else { + //EventRef event; + //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): created event " << status << " \n"); + //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): set event parameter " << status << " \n"); + //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard); + //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget()); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): added event to queue " << status << " \n"); + m_fullScreenDirty = true; + } + return GHOST_kSuccess; +} + + +void GHOST_WindowCarbon::gen2mac(const STR_String& in, Str255 out) const +{ + STR_String tempStr = in; + int num = tempStr.Length(); + if (num > 255) num = 255; + ::memcpy(out+1, tempStr.Ptr(), num); + out[0] = num; +} + + +void GHOST_WindowCarbon::mac2gen(const Str255 in, STR_String& out) const +{ + char tmp[256]; + ::memcpy(tmp, in+1, in[0]); + tmp[in[0]] = '\0'; + out = tmp; +} + +void GHOST_WindowCarbon::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + static bool systemCursorVisible = true; + + if (visible != systemCursorVisible) { + if (visible) { + ::ShowCursor(); + systemCursorVisible = true; + } + else { + ::HideCursor(); + systemCursorVisible = false; + } + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + int carbon_cursor; + +#define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break + switch (cursor) { + default: + GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor); + GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor); + GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor); + GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor); + GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor); + GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor); + GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorCopy, kThemeCopyArrowCursor); + }; +#undef GCMAP + + ::SetThemeCursor(carbon_cursor); + } +} + + +bool GHOST_WindowCarbon::getFullScreenDirty() +{ + return m_fullScreen && m_fullScreenDirty; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorVisibility(bool visible) +{ + if (::FrontWindow() == m_windowRef) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorShape(GHOST_TStandardCursor shape) +{ + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), shape); + } + + return GHOST_kSuccess; +} + +#if 0 +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} +#endif + + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) +{ + int y; + + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + m_customCursor = new Cursor; + if (!m_customCursor) return GHOST_kFailure; + + for (y=0; y<16; y++) { +#if !defined(__LITTLE_ENDIAN__) + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); +#else + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); +#endif + + } + + m_customCursor->hotSpot.h = hotX; + m_customCursor->hotSpot.v = hotY; + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); +} + + +void GHOST_WindowCarbon::setMac_windowState(short value) +{ + mac_windowState = value; +} + +short GHOST_WindowCarbon::getMac_windowState() +{ + return mac_windowState; +} diff --git a/intern/ghost/intern/GHOST_WindowCarbon.h b/intern/ghost/intern/GHOST_WindowCarbon.h new file mode 100644 index 00000000000..650788d5c70 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.h @@ -0,0 +1,313 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowCarbon.h + * \ingroup GHOST + * Declaration of GHOST_WindowCarbon class. + */ + +#ifndef _GHOST_WINDOW_CARBON_H_ +#define _GHOST_WINDOW_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#include "GHOST_Window.h" +#include "STR_String.h" + +#define __CARBONSOUND__ +#include + +#include + + +/** + * Window on Mac OSX/Carbon. + * Carbon windows have a size widget in the lower right corner of the window. + * To force it to be visible, the height of the client rectangle is reduced so + * that applications do not draw in that area. GHOST will manage that area + * which is called the gutter. + * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent + * OpenGL drawing outside the reduced client rectangle. + * @author Maarten Gribnau + * @date May 23, 2001 + */ +class GHOST_WindowCarbon : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0 + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowCarbon(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * @return Indication of success. + */ + GHOST_TSuccess updateDrawingContext(); + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; + + /** + * Returns the dirty state of the window when in full-screen mode. + * @return Whether it is dirty. + */ + virtual bool getFullScreenDirty(); + + /* accessor for fullscreen window */ + virtual void setMac_windowState(short value); + virtual short getMac_windowState(); + + + const GHOST_TabletData* GetTabletData() + { return &m_tablet; } + + GHOST_TabletData& GetCarbonTabletData() + { return m_tablet; } +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color); + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + /** + * Converts a string object to a Mac Pascal string. + * @param in The string object to be converted. + * @param out The converted string. + */ + virtual void gen2mac(const STR_String& in, Str255 out) const; + + /** + * Converts a Mac Pascal string to a string object. + * @param in The string to be converted. + * @param out The converted string object. + */ + virtual void mac2gen(const Str255 in, STR_String& out) const; + + WindowRef m_windowRef; + CGrafPtr m_grafPtr; + AGLContext m_aglCtx; + + /** The first created OpenGL context (for sharing display lists) */ + static AGLContext s_firstaglCtx; + + Cursor* m_customCursor; + + GHOST_TabletData m_tablet; + + /** When running in full-screen this tells whether to refresh the window. */ + bool m_fullScreenDirty; + + /** specific MacOs X full screen window setting as we use partially system mechanism + values : 0 not maximizable default + 1 normal state + 2 maximized state + + this will be reworked when rebuilding GHOST carbon to use new OS X apis + in order to be unified with GHOST fullscreen/maximised settings + + (lukep) + **/ + + short mac_windowState; + + + /** + * The width/height of the size rectangle in the lower right corner of a + * Mac/Carbon window. This is also the height of the gutter area. + */ +#ifdef GHOST_DRAW_CARBON_GUTTER + static const GHOST_TInt32 s_sizeRectSize; +#endif // GHOST_DRAW_CARBON_GUTTER +}; + +#endif // _GHOST_WINDOW_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h new file mode 100644 index 00000000000..98e0f9cedd1 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -0,0 +1,309 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowCocoa.h + * \ingroup GHOST + * Declaration of GHOST_WindowCocoa class. + */ + +#ifndef _GHOST_WINDOW_COCOA_H_ +#define _GHOST_WINDOW_COCOA_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#include "GHOST_Window.h" +#include "STR_String.h" + +@class CocoaWindow; + +class GHOST_SystemCocoa; + +/** + * Window on Mac OSX/Cocoa. + * Carbon windows have a size widget in the lower right corner of the window. + * To force it to be visible, the height of the client rectangle is reduced so + * that applications do not draw in that area. GHOST will manage that area + * which is called the gutter. + * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent + * OpenGL drawing outside the reduced client rectangle. + * @author Maarten Gribnau + * @date May 23, 2001 + */ +class GHOST_WindowCocoa : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param systemCocoa The associated system class to forward events to + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + */ + GHOST_WindowCocoa( + GHOST_SystemCocoa *systemCocoa, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0 + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowCocoa(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Returns the associated NSWindow object + * @return The associated NSWindow object + */ + virtual void* getOSWindow() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Sets the window "modified" status, indicating unsaved changes + * @param isUnsavedChanges Unsaved changes or not + * @return Indication of success. + */ + virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges); + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Gets the screen the window is displayed in + * @return The NSScreen object + */ + NSScreen* getScreen(); + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * @return Indication of success. + */ + GHOST_TSuccess updateDrawingContext(); + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; + + + const GHOST_TabletData* GetTabletData() + { return &m_tablet; } + + GHOST_TabletData& GetCocoaTabletData() + { return m_tablet; } + + /** + * Sets the progress bar value displayed in the window/application icon + * @param progress The progress % (0.0 to 1.0) + */ + virtual GHOST_TSuccess setProgressBar(float progress); + + /** + * Hides the progress bar icon + */ + virtual GHOST_TSuccess endProgressBar(); +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor grab on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color); + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + /** The window containing the OpenGL view */ + CocoaWindow *m_window; + + /** The openGL view */ + NSOpenGLView *m_openGLView; + + /** The opgnGL drawing context */ + NSOpenGLContext *m_openGLContext; + + /** The mother SystemCocoa class to send events */ + GHOST_SystemCocoa *m_systemCocoa; + + /** The first created OpenGL context (for sharing display lists) */ + static NSOpenGLContext *s_firstOpenGLcontext; + + NSCursor* m_customCursor; + + GHOST_TabletData m_tablet; +}; + +#endif // _GHOST_WINDOW_COCOA_H_ + diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm new file mode 100644 index 00000000000..8d28c9d5b17 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -0,0 +1,1352 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Maarten Gribnau 05/2001 + Damien Plisson 10/2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#ifndef MAC_OS_X_VERSION_10_6 +//Use of the SetSystemUIMode function (64bit compatible) +#include +#endif + +#include +/***** Multithreaded opengl code : uncomment for enabling +#include +*/ + + +#include "GHOST_WindowCocoa.h" +#include "GHOST_SystemCocoa.h" +#include "GHOST_Debug.h" + + +#pragma mark Cocoa window delegate object +/* live resize ugly patch +extern "C" { + struct bContext; + typedef struct bContext bContext; + bContext* ghostC; + extern int wm_window_timer(const bContext *C); + extern void wm_window_process_events(const bContext *C); + extern void wm_event_do_handlers(bContext *C); + extern void wm_event_do_notifiers(bContext *C); + extern void wm_draw_update(bContext *C); +};*/ +@interface CocoaWindowDelegate : NSObject +#ifdef MAC_OS_X_VERSION_10_6 + +#endif +{ + GHOST_SystemCocoa *systemCocoa; + GHOST_WindowCocoa *associatedWindow; +} + +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; +- (void)windowWillClose:(NSNotification *)notification; +- (void)windowDidBecomeKey:(NSNotification *)notification; +- (void)windowDidResignKey:(NSNotification *)notification; +- (void)windowDidExpose:(NSNotification *)notification; +- (void)windowDidResize:(NSNotification *)notification; +- (void)windowDidMove:(NSNotification *)notification; +- (void)windowWillMove:(NSNotification *)notification; +@end + +@implementation CocoaWindowDelegate : NSObject +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa +{ + systemCocoa = sysCocoa; + associatedWindow = winCocoa; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow); +} + +- (void)windowDidExpose:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); +} + +- (void)windowDidMove:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow); +} + +- (void)windowWillMove:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow); +} + +- (void)windowDidResize:(NSNotification *)notification +{ +#ifdef MAC_OS_X_VERSION_10_6 + //if (![[notification object] inLiveResize]) { + //Send event only once, at end of resize operation (when user has released mouse button) +#endif + systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow); +#ifdef MAC_OS_X_VERSION_10_6 + //} +#endif + /* Live resize ugly patch. Needed because live resize runs in a modal loop, not letting main loop run + if ([[notification object] inLiveResize]) { + systemCocoa->dispatchEvents(); + wm_window_timer(ghostC); + wm_event_do_handlers(ghostC); + wm_event_do_notifiers(ghostC); + wm_draw_update(ghostC); + }*/ +} +@end + +#pragma mark NSWindow subclass +//We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events) +@interface CocoaWindow: NSWindow +{ + GHOST_SystemCocoa *systemCocoa; + GHOST_WindowCocoa *associatedWindow; + GHOST_TDragnDropTypes m_draggedObjectType; +} +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; +- (GHOST_SystemCocoa*)systemCocoa; +@end +@implementation CocoaWindow +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa +{ + systemCocoa = sysCocoa; + associatedWindow = winCocoa; +} +- (GHOST_SystemCocoa*)systemCocoa +{ + return systemCocoa; +} + +-(BOOL)canBecomeKeyWindow +{ + return YES; +} + +//The drag'n'drop dragging destination methods +- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender +{ + NSPoint mouseLocation = [sender draggingLocation]; + NSPasteboard *draggingPBoard = [sender draggingPasteboard]; + + if ([[draggingPBoard types] containsObject:NSTIFFPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeBitmap; + else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeFilenames; + else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString; + else return NSDragOperationNone; + + associatedWindow->setAcceptDragOperation(TRUE); //Drag operation is accepted by default + systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil); + return NSDragOperationCopy; +} + +- (BOOL)wantsPeriodicDraggingUpdates +{ + return NO; //No need to overflow blender event queue. Events shall be sent only on changes +} + +- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender +{ + NSPoint mouseLocation = [sender draggingLocation]; + + systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil); + return associatedWindow->canAcceptDragOperation()?NSDragOperationCopy:NSDragOperationNone; +} + +- (void)draggingExited:(id < NSDraggingInfo >)sender +{ + systemCocoa->handleDraggingEvent(GHOST_kEventDraggingExited, m_draggedObjectType, associatedWindow, 0, 0, nil); + m_draggedObjectType = GHOST_kDragnDropTypeUnknown; +} + +- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender +{ + if (associatedWindow->canAcceptDragOperation()) + return YES; + else + return NO; +} + +- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender +{ + NSPoint mouseLocation = [sender draggingLocation]; + NSPasteboard *draggingPBoard = [sender draggingPasteboard]; + NSImage *droppedImg; + id data; + + switch (m_draggedObjectType) { + case GHOST_kDragnDropTypeBitmap: + if([NSImage canInitWithPasteboard:draggingPBoard]) { + droppedImg = [[NSImage alloc]initWithPasteboard:draggingPBoard]; + data = droppedImg; //[draggingPBoard dataForType:NSTIFFPboardType]; + } + else return NO; + break; + case GHOST_kDragnDropTypeFilenames: + data = [draggingPBoard propertyListForType:NSFilenamesPboardType]; + break; + case GHOST_kDragnDropTypeString: + data = [draggingPBoard stringForType:NSStringPboardType]; + break; + default: + return NO; + break; + } + systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, (void*)data); + return YES; +} + +@end + + + +#pragma mark NSOpenGLView subclass +//We need to subclass it in order to give Cocoa the feeling key events are trapped +@interface CocoaOpenGLView : NSOpenGLView +{ +} +@end +@implementation CocoaOpenGLView + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +//The trick to prevent Cocoa from complaining (beeping) +- (void)keyDown:(NSEvent *)theEvent +{} + +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 +//Cmd+key are handled differently before 10.5 +- (BOOL)performKeyEquivalent:(NSEvent *)theEvent +{ + NSString *chars = [theEvent charactersIgnoringModifiers]; + + if ([chars length] <1) + return NO; + + //Let cocoa handle menu shortcuts + switch ([chars characterAtIndex:0]) { + case 'q': + case 'w': + case 'h': + case 'm': + case '<': + case '>': + case '~': + case '`': + return NO; + default: + return YES; + } +} +#endif + +- (BOOL)isOpaque +{ + return YES; +} + +- (void) drawRect:(NSRect)rect +{ + if ([self inLiveResize]) + { + //Don't redraw while in live resize + } + else + { + [super drawRect:rect]; + } +} + +@end + + +#pragma mark initialization / finalization + +NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil; + +GHOST_WindowCocoa::GHOST_WindowCocoa( + GHOST_SystemCocoa *systemCocoa, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, const GHOST_TUns16 numOfAASamples +) : + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples), + m_customCursor(0) +{ + NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40]; + NSOpenGLPixelFormat *pixelFormat = nil; + int i; + + m_systemCocoa = systemCocoa; + m_fullScreen = false; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + + //Creates the window + NSRect rect; + NSSize minSize; + + rect.origin.x = left; + rect.origin.y = top; + rect.size.width = width; + rect.size.height = height; + + m_window = [[CocoaWindow alloc] initWithContentRect:rect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask + backing:NSBackingStoreBuffered defer:NO]; + if (m_window == nil) { + [pool drain]; + return; + } + + [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; + + //Forbid to resize the window below the blender defined minimum one + minSize.width = 320; + minSize.height = 240; + [m_window setContentMinSize:minSize]; + + setTitle(title); + + + // Pixel Format Attributes for the windowed NSOpenGLContext + i=0; + pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; + + // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer + // needed for 'Draw Overlap' drawing method + pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; + + pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; + //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway + + pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; + pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; + + + if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; + + if (numOfAASamples>0) { + // Multisample anti-aliasing + pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample; + + pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers; + pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1; + + pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples; + pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples; + + pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery; + } + + pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; + + pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; + + + //Fall back to no multisampling if Antialiasing init failed + if (pixelFormat == nil) { + i=0; + pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; + + // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer + // needed for 'Draw Overlap' drawing method + pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; + + pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; + //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway + + pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; + pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; + + if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; + + pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; + + pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; + + } + + if (numOfAASamples>0) { //Set m_numOfAASamples to the actual value + GLint gli; + [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; + if (m_numOfAASamples != (GHOST_TUns16)gli) { + m_numOfAASamples = (GHOST_TUns16)gli; + printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples); + } + } + + //Creates the OpenGL View inside the window + m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect + pixelFormat:pixelFormat]; + + [pixelFormat release]; + + m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after + + [m_window setContentView:m_openGLView]; + [m_window setInitialFirstResponder:m_openGLView]; + + [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window + + [m_window makeKeyAndOrderFront:nil]; + + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + + m_tablet.Active = GHOST_kTabletModeNone; + + CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; + [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; + [m_window setDelegate:windowDelegate]; + + [m_window setAcceptsMouseMovedEvents:YES]; + + [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, + NSStringPboardType, NSTIFFPboardType, nil]]; + + if (state == GHOST_kWindowStateFullScreen) + setState(GHOST_kWindowStateFullScreen); + + [pool drain]; +} + + +GHOST_WindowCocoa::~GHOST_WindowCocoa() +{ + if (m_customCursor) delete m_customCursor; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLView release]; + + if (m_window) { + [m_window close]; + [[m_window delegate] release]; + [m_window release]; + m_window = nil; + } + + //Check for other blender opened windows and make the frontmost key + NSArray *windowsList = [NSApp orderedWindows]; + if ([windowsList count]) { + [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; + } + [pool drain]; +} + +#pragma mark accessors + +bool GHOST_WindowCocoa::getValid() const +{ + return (m_window != 0); +} + +void* GHOST_WindowCocoa::getOSWindow() const +{ + return (void*)m_window; +} + +void GHOST_WindowCocoa::setTitle(const STR_String& title) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding]; + + //Set associated file if applicable + if (windowTitle && [windowTitle hasPrefix:@"Blender"]) + { + NSRange fileStrRange; + NSString *associatedFileName; + int len; + + fileStrRange.location = [windowTitle rangeOfString:@"["].location+1; + len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location; + + if (len >0) + { + fileStrRange.length = len; + associatedFileName = [windowTitle substringWithRange:fileStrRange]; + [m_window setTitle:[associatedFileName lastPathComponent]]; + + //Blender used file open/save functions converte file names into legal URL ones + associatedFileName = [associatedFileName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + @try { + [m_window setRepresentedFilename:associatedFileName]; + } + @catch (NSException * e) { + printf("\nInvalid file path given in window title"); + } + } + else { + [m_window setTitle:windowTitle]; + [m_window setRepresentedFilename:@""]; + } + + } else { + [m_window setTitle:windowTitle]; + [m_window setRepresentedFilename:@""]; + } + + + [windowTitle release]; + [pool drain]; +} + + +void GHOST_WindowCocoa::getTitle(STR_String& title) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid") + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSString *windowTitle = [m_window title]; + + if (windowTitle != nil) { + title = [windowTitle UTF8String]; + } + + [pool drain]; +} + + +void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const +{ + NSRect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid") + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSRect screenSize = [[m_window screen] visibleFrame]; + + rect = [m_window frame]; + + bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y); + bounds.m_l = rect.origin.x -screenSize.origin.x; + bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width; + bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y); + + [pool drain]; +} + + +void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const +{ + NSRect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (!m_fullScreen) + { + NSRect screenSize = [[m_window screen] visibleFrame]; + + //Max window contents as screen size (excluding title bar...) + NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; + + rect = [m_window contentRectForFrameRect:[m_window frame]]; + + bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); + bounds.m_l = rect.origin.x -contentRect.origin.x; + bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; + bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); + } + else { + NSRect screenSize = [[m_window screen] frame]; + + bounds.m_b = screenSize.origin.y + screenSize.size.height; + bounds.m_l = screenSize.origin.x; + bounds.m_r = screenSize.origin.x + screenSize.size.width; + bounds.m_t = screenSize.origin.y; + } + [pool drain]; +} + + +GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (((GHOST_TUns32)cBnds.getWidth()) != width) { + NSSize size; + size.width=width; + size.height=cBnds.getHeight(); + [m_window setContentSize:size]; + } + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (((GHOST_TUns32)cBnds.getHeight()) != height) { + NSSize size; + size.width=cBnds.getWidth(); + size.height=height; + [m_window setContentSize:size]; + } + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height)) { + NSSize size; + size.width=width; + size.height=height; + [m_window setContentSize:size]; + } + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TWindowState GHOST_WindowCocoa::getState() const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_TWindowState state; + if (m_fullScreen) { + state = GHOST_kWindowStateFullScreen; + } + else if ([m_window isMiniaturized]) { + state = GHOST_kWindowStateMinimized; + } + else if ([m_window isZoomed]) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + [pool drain]; + return state; +} + + +void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid") + + NSPoint screenCoord; + NSPoint baseCoord; + + screenCoord.x = inX; + screenCoord.y = inY; + + baseCoord = [m_window convertScreenToBase:screenCoord]; + + outX = baseCoord.x; + outY = baseCoord.y; +} + + +void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid") + + NSPoint screenCoord; + NSPoint baseCoord; + + baseCoord.x = inX; + baseCoord.y = inY; + + screenCoord = [m_window convertBaseToScreen:baseCoord]; + + outX = screenCoord.x; + outY = screenCoord.y; +} + + +NSScreen* GHOST_WindowCocoa::getScreen() +{ + return [m_window screen]; +} + + +/** + * @note Fullscreen switch is not actual fullscreen with display capture. As this capture removes all OS X window manager features. + * Instead, the menu bar and the dock are hidden, and the window is made borderless and enlarged. + * Thus, process switch, exposé, spaces, ... still work in fullscreen mode + */ +GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") + switch (state) { + case GHOST_kWindowStateMinimized: + [m_window miniaturize:nil]; + break; + case GHOST_kWindowStateMaximized: + [m_window zoom:nil]; + break; + + case GHOST_kWindowStateFullScreen: + if (!m_fullScreen) + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + //This status change needs to be done before Cocoa call to enter fullscreen mode + //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference + m_fullScreen = true; + +#ifdef MAC_OS_X_VERSION_10_6 + //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style + //Hide menu & dock if needed + if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) + { + [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)]; + } + //Make window borderless and enlarge it + [m_window setStyleMask:NSBorderlessWindowMask]; + [m_window setFrame:[[m_window screen] frame] display:YES]; + [m_window makeFirstResponder:m_openGLView]; +#else + //With 10.5, we need to create a new window to change its style to borderless + //Hide menu & dock if needed + if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) + { + //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO]; + //One of the very few 64bit compatible Carbon function + SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar); + } + //Create a fullscreen borderless window + CocoaWindow *tmpWindow = [[CocoaWindow alloc] + initWithContentRect:[[m_window screen] frame] + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + //Copy current window parameters + [tmpWindow setTitle:[m_window title]]; + [tmpWindow setRepresentedFilename:[m_window representedFilename]]; + [tmpWindow setReleasedWhenClosed:NO]; + [tmpWindow setAcceptsMouseMovedEvents:YES]; + [tmpWindow setDelegate:[m_window delegate]]; + [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; + [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, + NSStringPboardType, NSTIFFPboardType, nil]]; + + //Assign the openGL view to the new window + [tmpWindow setContentView:m_openGLView]; + + //Show the new window + [tmpWindow makeKeyAndOrderFront:m_openGLView]; + //Close and release old window + [m_window setDelegate:nil]; // To avoid the notification of "window closed" event + [m_window close]; + [m_window release]; + m_window = tmpWindow; +#endif + + //Tell WM of view new size + m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); + + [pool drain]; + } + break; + case GHOST_kWindowStateNormal: + default: + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if (m_fullScreen) + { + m_fullScreen = false; + + //Exit fullscreen +#ifdef MAC_OS_X_VERSION_10_6 + //Show again menu & dock if needed + if ([[m_window screen] isEqual:[NSScreen mainScreen]]) + { + [NSApp setPresentationOptions:NSApplicationPresentationDefault]; + } + //Make window normal and resize it + [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; + [m_window setFrame:[[m_window screen] visibleFrame] display:YES]; + //TODO for 10.6 only : window title is forgotten after the style change + [m_window makeFirstResponder:m_openGLView]; +#else + //With 10.5, we need to create a new window to change its style to borderless + //Show menu & dock if needed + if ([[m_window screen] isEqual:[NSScreen mainScreen]]) + { + //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES]; + SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function + } + //Create a fullscreen borderless window + CocoaWindow *tmpWindow = [[CocoaWindow alloc] + initWithContentRect:[[m_window screen] frame] + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:YES]; + //Copy current window parameters + [tmpWindow setTitle:[m_window title]]; + [tmpWindow setRepresentedFilename:[m_window representedFilename]]; + [tmpWindow setReleasedWhenClosed:NO]; + [tmpWindow setAcceptsMouseMovedEvents:YES]; + [tmpWindow setDelegate:[m_window delegate]]; + [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; + [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, + NSStringPboardType, NSTIFFPboardType, nil]]; + //Forbid to resize the window below the blender defined minimum one + [tmpWindow setContentMinSize:NSMakeSize(320, 240)]; + + //Assign the openGL view to the new window + [tmpWindow setContentView:m_openGLView]; + + //Show the new window + [tmpWindow makeKeyAndOrderFront:nil]; + //Close and release old window + [m_window setDelegate:nil]; // To avoid the notification of "window closed" event + [m_window close]; + [m_window release]; + m_window = tmpWindow; +#endif + + //Tell WM of view new size + m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); + } + else if ([m_window isMiniaturized]) + [m_window deminiaturize:nil]; + else if ([m_window isZoomed]) + [m_window zoom:nil]; + [pool drain]; + break; + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [m_window setDocumentEdited:isUnsavedChanges]; + + [pool drain]; + return GHOST_Window::setModifiedState(isUnsavedChanges); +} + + + +GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid") + if (order == GHOST_kWindowOrderTop) { + [m_window makeKeyAndOrderFront:nil]; + } + else { + NSArray *windowsList; + + [m_window orderBack:nil]; + + //Check for other blender opened windows and make the frontmost key + windowsList = [NSApp orderedWindows]; + if ([windowsList count]) { + [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; + } + } + + [pool drain]; + return GHOST_kSuccess; +} + +#pragma mark Drawing context + +/*#define WAIT_FOR_VSYNC 1*/ + +GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() +{ + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext flushBuffer]; + [pool drain]; + return GHOST_kSuccess; + } + } + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() +{ + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext update]; + [pool drain]; + return GHOST_kSuccess; + } + } + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() +{ + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext makeCurrentContext]; + + // Disable AA by default + if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB); + [pool drain]; + return GHOST_kSuccess; + } + } + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kFailure; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *tmpOpenGLContext; + + /***** Multithreaded opengl code : uncomment for enabling + CGLContextObj cglCtx; + */ + + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + if (!getValid()) break; + + pixelFormat = [m_openGLView pixelFormat]; + tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:s_firstOpenGLcontext]; + if (tmpOpenGLContext == nil) { + success = GHOST_kFailure; + break; + } + + //Switch openGL to multhreaded mode + /******* Multithreaded opengl code : uncomment for enabling + cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj]; + if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError) + printf("\nSwitched openGL to multithreaded mode"); + */ + + if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext; +#ifdef WAIT_FOR_VSYNC + { + GLint swapInt = 1; + /* wait for vsync, to avoid tearing artifacts */ + [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + } +#endif + [m_openGLView setOpenGLContext:tmpOpenGLContext]; + [tmpOpenGLContext setView:m_openGLView]; + + m_openGLContext = tmpOpenGLContext; + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + break; + } + [pool drain]; + return success; +} + + +GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_openGLContext) + { + [m_openGLView clearGLContext]; + if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil; + m_openGLContext = nil; + } + [pool drain]; + return GHOST_kSuccess; + case GHOST_kDrawingContextTypeNone: + [pool drain]; + return GHOST_kSuccess; + break; + default: + [pool drain]; + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_WindowCocoa::invalidate() +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLView setNeedsDisplay:YES]; + [pool drain]; + return GHOST_kSuccess; +} + +#pragma mark Progress bar + +GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if ((progress >=0.0) && (progress <=1.0)) { + NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; + + [dockIcon lockFocus]; + NSRect progressBox = {{4, 4}, {120, 16}}; + + [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; + + // Track & Outline + [[NSColor blackColor] setFill]; + NSRectFill(progressBox); + + [[NSColor whiteColor] set]; + NSFrameRect(progressBox); + + // Progress fill + progressBox = NSInsetRect(progressBox, 1, 1); + [[NSColor knobColor] setFill]; + progressBox.size.width = progressBox.size.width * progress; + NSRectFill(progressBox); + + [dockIcon unlockFocus]; + + [NSApp setApplicationIconImage:dockIcon]; + [dockIcon release]; + + m_progressBarVisible = true; + } + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCocoa::endProgressBar() +{ + if (!m_progressBarVisible) return GHOST_kFailure; + m_progressBarVisible = false; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; + [dockIcon lockFocus]; + [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; + [dockIcon unlockFocus]; + [NSApp setApplicationIconImage:dockIcon]; + [dockIcon release]; + + [pool drain]; + return GHOST_kSuccess; +} + + + +#pragma mark Cursor handling + +void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + static bool systemCursorVisible = true; + + NSCursor *tmpCursor =nil; + + if (visible != systemCursorVisible) { + if (visible) { + [NSCursor unhide]; + systemCursorVisible = true; + } + else { + [NSCursor hide]; + systemCursorVisible = false; + } + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + tmpCursor = m_customCursor; + } else { + switch (cursor) { + case GHOST_kStandardCursorDestroy: + tmpCursor = [NSCursor disappearingItemCursor]; + break; + case GHOST_kStandardCursorText: + tmpCursor = [NSCursor IBeamCursor]; + break; + case GHOST_kStandardCursorCrosshair: + tmpCursor = [NSCursor crosshairCursor]; + break; + case GHOST_kStandardCursorUpDown: + tmpCursor = [NSCursor resizeUpDownCursor]; + break; + case GHOST_kStandardCursorLeftRight: + tmpCursor = [NSCursor resizeLeftRightCursor]; + break; + case GHOST_kStandardCursorTopSide: + tmpCursor = [NSCursor resizeUpCursor]; + break; + case GHOST_kStandardCursorBottomSide: + tmpCursor = [NSCursor resizeDownCursor]; + break; + case GHOST_kStandardCursorLeftSide: + tmpCursor = [NSCursor resizeLeftCursor]; + break; + case GHOST_kStandardCursorRightSide: + tmpCursor = [NSCursor resizeRightCursor]; + break; + case GHOST_kStandardCursorRightArrow: + case GHOST_kStandardCursorInfo: + case GHOST_kStandardCursorLeftArrow: + case GHOST_kStandardCursorHelp: + case GHOST_kStandardCursorCycle: + case GHOST_kStandardCursorSpray: + case GHOST_kStandardCursorWait: + case GHOST_kStandardCursorTopLeftCorner: + case GHOST_kStandardCursorTopRightCorner: + case GHOST_kStandardCursorBottomRightCorner: + case GHOST_kStandardCursorBottomLeftCorner: + case GHOST_kStandardCursorCopy: + case GHOST_kStandardCursorDefault: + default: + tmpCursor = [NSCursor arrowCursor]; + break; + }; + } + [tmpCursor set]; +} + + + +GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; + + if ([m_window isVisible]) { + loadCursor(visible, getCursorShape()); + } + + [pool drain]; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode) +{ + GHOST_TSuccess err = GHOST_kSuccess; + + if (mode != GHOST_kGrabDisable) + { + //No need to perform grab without warp as it is always on in OS X + if(mode != GHOST_kGrabNormal) { + GHOST_TInt32 x_old,y_old; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + m_systemCocoa->getCursorPosition(x_old,y_old); + screenToClient(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + //Warp position is stored in client (window base) coordinates + setCursorGrabAccum(0, 0); + + if(mode == GHOST_kGrabHide) { + setWindowCursorVisibility(false); + } + + //Make window key if it wasn't to get the mouse move events + [m_window makeKeyWindow]; + + //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor + err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + + [pool drain]; + } + } + else { + if(m_cursorGrab==GHOST_kGrabHide) + { + //No need to set again cursor position, as it has not changed for Cocoa + setWindowCursorVisibility(true); + } + + err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + setCursorGrabAccum(0, 0); + m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ + } + return err; +} + +GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (m_customCursor) { + [m_customCursor release]; + m_customCursor = nil; + } + + if ([m_window isVisible]) { + loadCursor(getCursorVisibility(), shape); + } + + [pool drain]; + return GHOST_kSuccess; +} + +/** Reverse the bits in a GHOST_TUns8 +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} +*/ + + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} + +GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) +{ + int y,nbUns16; + NSPoint hotSpotPoint; + NSBitmapImageRep *cursorImageRep; + NSImage *cursorImage; + NSSize imSize; + GHOST_TUns16 *cursorBitmap; + + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (m_customCursor) { + [m_customCursor release]; + m_customCursor = nil; + } + + + cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:sizex + pixelsHigh:sizey + bitsPerSample:1 + samplesPerPixel:2 + hasAlpha:YES + isPlanar:YES + colorSpaceName:NSDeviceWhiteColorSpace + bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0)) + bitsPerPixel:1]; + + + cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData]; + nbUns16 = [cursorImageRep bytesPerPlane]/2; + + for (y=0; y +#include "GHOST_Debug.h" +#include "GHOST_Window.h" + + +GHOST_WindowManager::GHOST_WindowManager() : + m_fullScreenWindow(0), + m_activeWindow(0), + m_activeWindowBeforeFullScreen(0) +{ +} + + +GHOST_WindowManager::~GHOST_WindowManager() +{ + /* m_windows is freed by GHOST_System::disposeWindow */ +} + + +GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (!getWindowFound(window)) { + // Store the pointer to the window + m_windows.push_back(window); + success = GHOST_kSuccess; + } + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::removeWindow(const GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (window == m_fullScreenWindow) { + endFullScreen(); + } + else { + vector::iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + setWindowInactive(window); + m_windows.erase(result); + success = GHOST_kSuccess; + } + } + } + return success; +} + + +bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow* window) const +{ + bool found = false; + if (window) { + if (getFullScreen() && (window == m_fullScreenWindow)) { + found = true; + } + else { + vector::const_iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + found = true; + } + } + } + return found; +} + + +bool GHOST_WindowManager::getFullScreen(void) const +{ + return m_fullScreenWindow != 0; +} + + +GHOST_IWindow* GHOST_WindowManager::getFullScreenWindow(void) const +{ + return m_fullScreenWindow; +} + + +GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow* window, + bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(window, "GHOST_WindowManager::beginFullScreen(): invalid window"); + GHOST_ASSERT(window->getValid(), "GHOST_WindowManager::beginFullScreen(): invalid window"); + if (!getFullScreen()) { + m_fullScreenWindow = window; + m_activeWindowBeforeFullScreen = getActiveWindow(); + setActiveWindow(m_fullScreenWindow); + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (getFullScreen()) { + if (m_fullScreenWindow != 0) { + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n"); + setWindowInactive(m_fullScreenWindow); + delete m_fullScreenWindow; + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n"); + m_fullScreenWindow = 0; + if (m_activeWindowBeforeFullScreen) { + setActiveWindow(m_activeWindowBeforeFullScreen); + } + } + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (window != m_activeWindow) { + if (getWindowFound(window)) { + m_activeWindow = window; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_IWindow* GHOST_WindowManager::getActiveWindow(void) const +{ + return m_activeWindow; +} + + +void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow* window) +{ + if (window == m_activeWindow) { + m_activeWindow = 0; + } +} + + +std::vector &GHOST_WindowManager::getWindows() +{ + return m_windows; +} + + +GHOST_IWindow* GHOST_WindowManager::getWindowAssociatedWithOSWindow(void* osWindow) +{ + std::vector::iterator iter; + + for (iter = m_windows.begin(); iter != m_windows.end(); iter++) { + if ((*iter)->getOSWindow() == osWindow) + return *iter; + } + + return NULL; +} + +bool GHOST_WindowManager::getAnyModifiedState() +{ + bool isAnyModified = false; + std::vector::iterator iter; + + for (iter = m_windows.begin(); iter != m_windows.end(); iter++) { + if ((*iter)->getModifiedState()) + isAnyModified = true; + } + + return isAnyModified; +} diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h new file mode 100644 index 00000000000..b4baf8985fc --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowManager.h @@ -0,0 +1,174 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowManager.h + * \ingroup GHOST + * Declaration of GHOST_WindowManager class. + */ + +#ifndef _GHOST_WINDOW_MANAGER_H_ +#define _GHOST_WINDOW_MANAGER_H_ + +#include + +#include "GHOST_Rect.h" +#include "GHOST_IWindow.h" + + +/** + * Manages system windows (platform independent implementation). + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_WindowManager +{ +public: + /** + * Constructor. + */ + GHOST_WindowManager(); + + /** + * Destructor. + */ + virtual ~GHOST_WindowManager(); + + /** + * Add a window to our list. + * It is only added if it is not already in the list. + * @param window Pointer to the window to be added. + * @return Indication of success. + */ + virtual GHOST_TSuccess addWindow(GHOST_IWindow* window); + + /** + * Remove a window from our list. + * @param window Pointer to the window to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeWindow(const GHOST_IWindow* window); + + /** + * Returns whether the window is in our list. + * @param window Pointer to the window to query. + * @return A boolean indicator. + */ + virtual bool getWindowFound(const GHOST_IWindow* window) const; + + /** + * Returns whether one of the windows is fullscreen. + * @return A boolean indicator. + */ + virtual bool getFullScreen(void) const; + + /** + * Returns pointer to the full-screen window. + * @return The fll-screen window (0 if not in full-screen). + */ + virtual GHOST_IWindow* getFullScreenWindow(void) const; + + /** + * Activates fullscreen mode for a window. + * @param window The window displayed fullscreen. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(GHOST_IWindow* window, const bool stereoVisual); + + /** + * Closes fullscreen mode down. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Sets new window as active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @param window The new active window. + */ + virtual GHOST_TSuccess setActiveWindow(GHOST_IWindow* window); + + /** + * Returns the active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @return window The active window (or NULL if there is none). + */ + virtual GHOST_IWindow* getActiveWindow(void) const; + + + /** + * Set this window to be inactive (not receiving events). + * @param window The window to decativate. + */ + virtual void setWindowInactive(const GHOST_IWindow* window); + + + /** + * Return a vector of the windows currently managed by this + * class. + * @warning It is very dangerous to mess with the contents of + * this vector. Please do not destroy or add windows use the + * interface above for this, + */ + std::vector & getWindows(); + + /** + * Finds the window associated with an OS window object/handle + * @param osWindow The OS window object/handle + * @return The associated window, null if none corresponds + */ + virtual GHOST_IWindow* getWindowAssociatedWithOSWindow(void* osWindow); + + /** + * Return true if any windows has a modified status + * @return True if any window has unsaved changes + */ + bool getAnyModifiedState(); + +protected: + /** The list of windows managed */ + std::vector m_windows; + + /** Window in fullscreen state. There can be only one of this which is not in or window list. */ + GHOST_IWindow* m_fullScreenWindow; + + /** The active window. */ + GHOST_IWindow* m_activeWindow; + + /** Window that was active before entering fullscreen state. */ + GHOST_IWindow* m_activeWindowBeforeFullScreen; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GHOST:GHOST_WindowManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif + +}; + +#endif // _GHOST_WINDOW_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp new file mode 100644 index 00000000000..aae1509fda1 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -0,0 +1,1351 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowWin32.cpp + * \ingroup GHOST + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#include +#include "GHOST_WindowWin32.h" +#include "GHOST_SystemWin32.h" +#include "GHOST_DropTargetWin32.h" + +// Need glew for some defines +#include +#include +#include + +// MSVC6 still doesn't define M_PI +#ifndef M_PI +#define M_PI 3.1415926536 +#endif + +// Some more multisample defines +#define WGL_SAMPLE_BUFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +// win64 doesn't define GWL_USERDATA +#ifdef WIN32 +#ifndef GWL_USERDATA +#define GWL_USERDATA GWLP_USERDATA +#define GWL_WNDPROC GWLP_WNDPROC +#endif +#endif + +LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass"; +const int GHOST_WindowWin32::s_maxTitleLength = 128; +HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL; +HDC GHOST_WindowWin32::s_firstHDC = NULL; + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd); +static int EnumPixelFormats(HDC hdc); + +/* + * Color and depth bit values are not to be trusted. + * For instance, on TNT2: + * When the screen color depth is set to 16 bit, we get 5 color bits + * and 16 depth bits. + * When the screen color depth is set to 32 bit, we get 8 color bits + * and 24 depth bits. + * Just to be safe, we request high waulity settings. + */ +static PIXELFORMATDESCRIPTOR sPreferredFormat = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_SWAP_COPY | /* support swap copy */ + PFD_DOUBLEBUFFER, /* support double-buffering */ + PFD_TYPE_RGBA, /* color type */ + 32, /* prefered color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + 0, /* no alpha buffer */ + 0, /* alpha bits (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 32, /* depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* no layer, visible, damage masks */ +}; + +/* Intel videocards don't work fine with multiple contexts and + have to share the same context for all windows. + But if we just share context for all windows it could work incorrect + with multiple videocards configuration. Suppose, that Intel videocards + can't be in multiple-devices configuration. */ +static int is_crappy_intel_card(void) +{ + int crappy = 0; + const char *vendor = (const char*)glGetString(GL_VENDOR); + + if (strstr(vendor, "Intel")) + crappy = 1; + + return crappy; +} + +GHOST_WindowWin32::GHOST_WindowWin32( + GHOST_SystemWin32 * system, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples, + GHOST_TEmbedderWindowID parentwindowhwnd, + GHOST_TSuccess msEnabled, + int msPixelFormat) +: + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, + stereoVisual,numOfAASamples), + m_system(system), + m_hDC(0), + m_hGlRc(0), + m_hasMouseCaptured(false), + m_hasGrabMouse(false), + m_nPressedButtons(0), + m_customCursor(0), + m_wintab(NULL), + m_tabletData(NULL), + m_tablet(0), + m_maxPressure(0), + m_multisample(numOfAASamples), + m_parentWindowHwnd(parentwindowhwnd), + m_multisampleEnabled(msEnabled), + m_msPixelFormat(msPixelFormat), + //For recreation + m_title(title), + m_left(left), + m_top(top), + m_width(width), + m_height(height), + m_normal_state(GHOST_kWindowStateNormal), + m_stereo(stereoVisual), + m_nextWindow(NULL) +{ + OSVERSIONINFOEX versionInfo; + bool hasMinVersionForTaskbar = false; + + ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX)); + + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + if(!GetVersionEx((OSVERSIONINFO *)&versionInfo)) { + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if(GetVersionEx((OSVERSIONINFO*)&versionInfo)) { + if((versionInfo.dwMajorVersion==6 && versionInfo.dwMinorVersion>=1) || versionInfo.dwMajorVersion >= 7) { + hasMinVersionForTaskbar = true; + } + } + } else { + if((versionInfo.dwMajorVersion==6 && versionInfo.dwMinorVersion>=1) || versionInfo.dwMajorVersion >= 7) { + hasMinVersionForTaskbar = true; + } + } + + if (state != GHOST_kWindowStateFullScreen) { + RECT rect; + MONITORINFO monitor; + GHOST_TUns32 tw, th; + + width += GetSystemMetrics(SM_CXSIZEFRAME)*2; + height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION); + + rect.left = left; + rect.right = left + width; + rect.top = top; + rect.bottom = top + height; + + monitor.cbSize=sizeof(monitor); + monitor.dwFlags=0; + + // take taskbar into account + GetMonitorInfo(MonitorFromRect(&rect,MONITOR_DEFAULTTONEAREST),&monitor); + + th = monitor.rcWork.bottom - monitor.rcWork.top; + tw = monitor.rcWork.right - monitor.rcWork.left; + + if(tw < width) + { + width = tw; + left = monitor.rcWork.left; + } + else if(monitor.rcWork.right < left + (int)width) + left = monitor.rcWork.right - width; + else if(left < monitor.rcWork.left) + left = monitor.rcWork.left; + + if(th < height) + { + height = th; + top = monitor.rcWork.top; + } + else if(monitor.rcWork.bottom < top + (int)height) + top = monitor.rcWork.bottom - height; + else if(top < monitor.rcWork.top) + top = monitor.rcWork.top; + + int wintype = WS_OVERLAPPEDWINDOW; + if (m_parentWindowHwnd != 0) + { + wintype = WS_CHILD; + GetWindowRect((HWND)m_parentWindowHwnd, &rect); + left = 0; + top = 0; + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + wintype, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + (HWND) m_parentWindowHwnd, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + else { + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_POPUP | WS_MAXIMIZE, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + HWND_DESKTOP, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + if (m_hWnd) { + // Register this window as a droptarget. Requires m_hWnd to be valid. + // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32. + m_dropTarget = new GHOST_DropTargetWin32(this, m_system); + // Store a pointer to this class in the window structure + ::SetWindowLongPtr(m_hWnd, GWL_USERDATA, (LONG_PTR)this); + + // Store the device context + m_hDC = ::GetDC(m_hWnd); + + if(!s_firstHDC) { + s_firstHDC = m_hDC; + } + + // Show the window + int nCmdShow; + switch (state) { + case GHOST_kWindowStateMaximized: + nCmdShow = SW_SHOWMAXIMIZED; + break; + case GHOST_kWindowStateMinimized: + nCmdShow = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateNormal: + default: + nCmdShow = SW_SHOWNORMAL; + break; + } + GHOST_TSuccess success; + success = setDrawingContextType(type); + + if (success) + { + ::ShowWindow(m_hWnd, nCmdShow); + // Force an initial paint of the window + ::UpdateWindow(m_hWnd); + } + else + { + //invalidate the window + m_hWnd = 0; + } + } + + if (parentwindowhwnd != 0) { + RAWINPUTDEVICE device = {0}; + device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/ + device.usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */ + device.dwFlags |= RIDEV_INPUTSINK; // makes WM_INPUT is visible for ghost when has parent window + device.hwndTarget = m_hWnd; + RegisterRawInputDevices(&device, 1, sizeof(device)); + } + + m_wintab = ::LoadLibrary("Wintab32.dll"); + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo && fpWTInfo(0, 0, NULL)) { + // Now init the tablet + LOGCONTEXT lc; + AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */ + + // Open a Wintab context + + // Get default context information + fpWTInfo( WTI_DEFCONTEXT, 0, &lc ); + + // Open the context + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM; + + /* Set the entire tablet as active */ + fpWTInfo(WTI_DEVICES,DVC_X,&TabletX); + fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY); + + /* get the max pressure, to divide into a float */ + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + /* get the max tilt axes, to divide into floats */ + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + /* all this assumes the minimum is 0 */ + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + if (fpWTOpen) { + m_tablet = fpWTOpen( m_hWnd, &lc, TRUE ); + if (m_tablet) { + m_tabletData = new GHOST_TabletData(); + m_tabletData->Active = GHOST_kTabletModeNone; + } + } + } + } + + if(hasMinVersionForTaskbar) + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList ,(LPVOID*)&m_Bar); + else + m_Bar=NULL; +} + + +GHOST_WindowWin32::~GHOST_WindowWin32() +{ + if(m_Bar) + { + m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + m_Bar->Release(); + }; + + if (m_wintab) { + GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" ); + if (fpWTClose) { + if (m_tablet) + fpWTClose(m_tablet); + if (m_tabletData) + delete m_tabletData; + m_tabletData = NULL; + } + } + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + ::wglMakeCurrent(NULL, NULL); + m_multisampleEnabled = GHOST_kFailure; + m_multisample = 0; + setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_hDC && m_hDC != s_firstHDC) { + ::ReleaseDC(m_hWnd, m_hDC); + m_hDC = 0; + } + if (m_hWnd) { + m_dropTarget->Release(); // frees itself. + ::DestroyWindow(m_hWnd); + m_hWnd = 0; + } +} + +GHOST_Window *GHOST_WindowWin32::getNextWindow() +{ + return m_nextWindow; +} + +bool GHOST_WindowWin32::getValid() const +{ + return m_hWnd != 0; +} + +HWND GHOST_WindowWin32::getHWND() const +{ + return m_hWnd; +} + +void GHOST_WindowWin32::setTitle(const STR_String& title) +{ + ::SetWindowText(m_hWnd, title); +} + + +void GHOST_WindowWin32::getTitle(STR_String& title) const +{ + char buf[s_maxTitleLength]; + ::GetWindowText(m_hWnd, buf, s_maxTitleLength); + STR_String temp (buf); + title = buf; +} + + +void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetWindowRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const +{ + RECT rect; + GHOST_TWindowState state= this->getState(); + LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE); + int sm_cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME); + ::GetWindowRect(m_hWnd, &rect); + + if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) { + if(state==GHOST_kWindowStateMaximized) { + // in maximized state we don't have borders on the window + bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)- sm_cysizeframe*2; + bounds.m_l = rect.left + sm_cysizeframe; + bounds.m_r = rect.right - sm_cysizeframe; + bounds.m_t = rect.top; + } else if (state == GHOST_kWindowStateEmbedded) { + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; + } else { + bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)-sm_cysizeframe*2; + bounds.m_l = rect.left; + bounds.m_r = rect.right-sm_cysizeframe*2; + bounds.m_t = rect.top; + } + } else { + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; + } +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getWidth() != (GHOST_TInt32)width) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getHeight() != (GHOST_TInt32)height) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TWindowState GHOST_WindowWin32::getState() const +{ + GHOST_TWindowState state; + + // XXX 27.04.2011 + // we need to find a way to combine parented windows + resizing if we simply set the + // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else. + // It's also strange that in Windows is the only platform we need to make this separation. + if (m_parentWindowHwnd != 0) { + state = GHOST_kWindowStateEmbedded; + return state; + } + if (::IsIconic(m_hWnd)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsZoomed(m_hWnd)) { + LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE); + if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) + state = GHOST_kWindowStateMaximized; + else + state = GHOST_kWindowStateFullScreen; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ScreenToClient(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ClientToScreen(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) +{ + GHOST_TWindowState curstate = getState(); + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + ::GetWindowPlacement(m_hWnd, &wp); + + if (state == GHOST_kWindowStateNormal) + state = m_normal_state; + switch (state) { + case GHOST_kWindowStateMinimized: + wp.showCmd = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateMaximized: + ShowWindow(m_hWnd, SW_HIDE); + wp.showCmd = SW_SHOWMAXIMIZED; + SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + break; + case GHOST_kWindowStateFullScreen: + if (curstate != state && curstate != GHOST_kWindowStateMinimized) + m_normal_state = curstate; + wp.showCmd = SW_SHOWMAXIMIZED; + wp.ptMaxPosition.x = 0; + wp.ptMaxPosition.y = 0; + SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE); + break; + case GHOST_kWindowStateEmbedded: + SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD); + break; + case GHOST_kWindowStateNormal: + default: + ShowWindow(m_hWnd, SW_HIDE); + wp.showCmd = SW_SHOWNORMAL; + SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + break; + } + return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order) +{ + HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM; + return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::swapBuffers() +{ + HDC hDC = m_hDC; + + if (is_crappy_intel_card()) + hDC = ::wglGetCurrentDC(); + + return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext() +{ + GHOST_TSuccess success; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_hDC && m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::invalidate() +{ + GHOST_TSuccess success; + if (m_hWnd) { + success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd) +{ + int pixelFormat; + bool success = FALSE; + UINT numFormats; + HDC hDC = GetDC(getHWND()); + float fAttributes[] = {0, 0}; + UINT nMaxFormats = 1; + + // The attributes to look for + int iAttributes[] = { + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB, pfd.cColorBits, + WGL_DEPTH_BITS_ARB, pfd.cDepthBits, + WGL_STENCIL_BITS_ARB, pfd.cStencilBits, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, + WGL_SAMPLES_ARB, m_multisample, + 0, 0 + }; + + // Get the function + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + + if (!wglChoosePixelFormatARB) + { + m_multisampleEnabled = GHOST_kFailure; + return GHOST_kFailure; + } + + // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it. + while (iAttributes[17] > 0) { + // See if the format is valid + success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats); + GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats); + + if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) { + GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]); + m_multisampleEnabled = GHOST_kSuccess; + m_msPixelFormat = pixelFormat; + } + iAttributes[17] -= 1; + success = GHOST_kFailure; + } + if (m_multisampleEnabled == GHOST_kSuccess) { + return GHOST_kSuccess; + } + GHOST_PRINT("no available pixel format\n"); + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + // If this window has multisample enabled, use the supplied format + if (m_multisampleEnabled) + { + if (SetPixelFormat(m_hDC, m_msPixelFormat, &sPreferredFormat)==FALSE) + { + success = GHOST_kFailure; + break; + } + + // Create the context + m_hGlRc = ::wglCreateContext(m_hDC); + if (m_hGlRc) { + if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) { + if (s_firsthGLRc) { + if (is_crappy_intel_card()) { + if (::wglMakeCurrent(NULL, NULL) == TRUE) { + ::wglDeleteContext(m_hGlRc); + m_hGlRc = s_firsthGLRc; + } + else { + ::wglDeleteContext(m_hGlRc); + m_hGlRc = NULL; + } + } + else { + ::wglCopyContext(s_firsthGLRc, m_hGlRc, GL_ALL_ATTRIB_BITS); + ::wglShareLists(s_firsthGLRc, m_hGlRc); + } + } + else { + s_firsthGLRc = m_hGlRc; + } + + if (m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kFailure; + } + + if (success == GHOST_kFailure) { + printf("Failed to get a context....\n"); + } + } + else + { + if(m_stereoVisual) + sPreferredFormat.dwFlags |= PFD_STEREO; + + // Attempt to match device context pixel format to the preferred format + int iPixelFormat = EnumPixelFormats(m_hDC); + if (iPixelFormat == 0) { + success = GHOST_kFailure; + break; + } + if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) { + success = GHOST_kFailure; + break; + } + // For debugging only: retrieve the pixel format chosen + PIXELFORMATDESCRIPTOR preferredFormat; + ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat); + + // Create the context + m_hGlRc = ::wglCreateContext(m_hDC); + if (m_hGlRc) { + if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) { + if (s_firsthGLRc) { + if (is_crappy_intel_card()) { + if (::wglMakeCurrent(NULL, NULL) == TRUE) { + ::wglDeleteContext(m_hGlRc); + m_hGlRc = s_firsthGLRc; + } + else { + ::wglDeleteContext(m_hGlRc); + m_hGlRc = NULL; + } + } + else { + ::wglShareLists(s_firsthGLRc, m_hGlRc); + } + } + else { + s_firsthGLRc = m_hGlRc; + } + + if (m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kFailure; + } + + if (success == GHOST_kFailure) { + printf("Failed to get a context....\n"); + } + + // Attempt to enable multisample + if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled) + { + success = initMultisample(preferredFormat); + + if (success) + { + + // Make sure we don't screw up the context + m_drawingContextType = GHOST_kDrawingContextTypeOpenGL; + removeDrawingContext(); + + // Create a new window + GHOST_TWindowState new_state = getState(); + + m_nextWindow = new GHOST_WindowWin32((GHOST_SystemWin32*)GHOST_ISystem::getSystem(), + m_title, + m_left, + m_top, + m_width, + m_height, + new_state, + type, + m_stereo, + m_multisample, + m_parentWindowHwnd, + m_multisampleEnabled, + m_msPixelFormat); + + // Return failure so we can trash this window. + success = GHOST_kFailure; + break; + } else { + m_multisampleEnabled = GHOST_kSuccess; + printf("Multisample failed to initialized\n"); + success = GHOST_kSuccess; + } + } + } + + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + +GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext() +{ + GHOST_TSuccess success; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + // we shouldn't remove the drawing context if it's the first OpenGL context + // If we do, we get corrupted drawing. See #19997 + if (m_hGlRc && m_hGlRc!=s_firsthGLRc) { + success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + m_hGlRc = 0; + } + else { + success = GHOST_kFailure; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + success = GHOST_kFailure; + } + return success; +} + +void GHOST_WindowWin32::lostMouseCapture() +{ + if(m_hasMouseCaptured) + { m_hasGrabMouse = false; + m_nPressedButtons = 0; + m_hasMouseCaptured = false; + }; +} + +void GHOST_WindowWin32::registerMouseClickEvent(int press) +{ + + switch(press) + { + case 0: m_nPressedButtons++; break; + case 1: if(m_nPressedButtons) m_nPressedButtons--; break; + case 2: m_hasGrabMouse=true; break; + case 3: m_hasGrabMouse=false; break; + } + + if(!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured) + { + ::ReleaseCapture(); + m_hasMouseCaptured = false; + } + else if((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured) + { + ::SetCapture(m_hWnd); + m_hasMouseCaptured = true; + + } +} + + +void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + if (!visible) { + while (::ShowCursor(FALSE) >= 0); + } + else { + while (::ShowCursor(TRUE) < 0); + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + // Convert GHOST cursor to Windows OEM cursor + bool success = true; + LPCSTR id; + switch (cursor) { + case GHOST_kStandardCursorDefault: id = IDC_ARROW; break; + case GHOST_kStandardCursorRightArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorLeftArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorInfo: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorDestroy: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorHelp: id = IDC_HELP; break; // Arrow and question mark + case GHOST_kStandardCursorCycle: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorSpray: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorWait: id = IDC_WAIT; break; // Hourglass + case GHOST_kStandardCursorText: id = IDC_IBEAM; break; // I-beam + case GHOST_kStandardCursorCrosshair: id = IDC_CROSS; break; // Crosshair + case GHOST_kStandardCursorUpDown: id = IDC_SIZENS; break; // Double-pointed arrow pointing north and south + case GHOST_kStandardCursorLeftRight: id = IDC_SIZEWE; break; // Double-pointed arrow pointing west and east + case GHOST_kStandardCursorTopSide: id = IDC_UPARROW; break; // Vertical arrow + case GHOST_kStandardCursorBottomSide: id = IDC_SIZENS; break; + case GHOST_kStandardCursorLeftSide: id = IDC_SIZEWE; break; + case GHOST_kStandardCursorTopLeftCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorTopRightCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorBottomRightCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorPencil: id = IDC_ARROW; break; + case GHOST_kStandardCursorCopy: id = IDC_ARROW; break; + default: + success = false; + } + + if (success) { + ::SetCursor(::LoadCursor(0, id)); + } + } +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible) +{ + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode) +{ + if(mode != GHOST_kGrabDisable) { + if(mode != GHOST_kGrabNormal) { + m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + setCursorGrabAccum(0, 0); + + if(mode == GHOST_kGrabHide) + setWindowCursorVisibility(false); + } + registerMouseClickEvent(2); + } + else { + if (m_cursorGrab==GHOST_kGrabHide) { + m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + setWindowCursorVisibility(true); + } + if(m_cursorGrab != GHOST_kGrabNormal) { + /* use to generate a mouse move event, otherwise the last event + * blender gets can be outside the screen causing menus not to show + * properly unless the user moves the mouse */ + GHOST_TInt32 pos[2]; + m_system->getCursorPosition(pos[0], pos[1]); + m_system->setCursorPosition(pos[0], pos[1]); + } + + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + setCursorGrabAccum(0, 0); + m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ + registerMouseClickEvent(3); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), cursorShape); + } + + return GHOST_kSuccess; +} + +void GHOST_WindowWin32::processWin32TabletInitEvent() +{ + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo) { + AXIS Pressure, Orientation[3]; /* The maximum tablet size */ + + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + m_tabletData->Active = GHOST_kTabletModeNone; + } + } +} + +void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) +{ + PACKET pkt; + if (m_wintab) { + GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" ); + if (fpWTPacket) { + if (fpWTPacket((HCTX)lParam, wParam, &pkt)) { + if (m_tabletData) { + switch (pkt.pkCursor) { + case 0: /* first device */ + case 3: /* second device */ + m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */ + break; + case 1: + case 4: + m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */ + break; + case 2: + case 5: + m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */ + break; + } + if (m_maxPressure > 0) { + m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure; + } else { + m_tabletData->Pressure = 1.0f; + } + + if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ + + /* + from the wintab spec: + orAzimuth Specifies the clockwise rotation of the + cursor about the z axis through a full circular range. + + orAltitude Specifies the angle with the x-y plane + through a signed, semicircular range. Positive values + specify an angle upward toward the positive z axis; + negative values specify an angle downward toward the negative z axis. + + wintab.h defines .orAltitude as a UINT but documents .orAltitude + as positive for upward angles and negative for downward angles. + WACOM uses negative altitude values to show that the pen is inverted; + therefore we cast .orAltitude as an (int) and then use the absolute value. + */ + + /* convert raw fixed point data to radians */ + altRad = (float)((fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0); + azmRad = (float)(((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0); + + /* find length of the stylus' projected vector on the XY plane */ + vecLen = cos(altRad); + + /* from there calculate X and Y components based on azimuth */ + m_tabletData->Xtilt = sin(azmRad) * vecLen; + m_tabletData->Ytilt = (float)(sin(M_PI/2.0 - azmRad) * vecLen); + + } else { + m_tabletData->Xtilt = 0.0f; + m_tabletData->Ytilt = 0.0f; + } + } + } + } + } +} + +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, + int fg_color, int bg_color) +{ + GHOST_TUns32 andData[32]; + GHOST_TUns32 xorData[32]; + GHOST_TUns32 fullBitRow, fullMaskRow; + int x, y, cols; + + cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */ + if (sizeX%8) cols++; + + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + memset(&andData, 0xFF, sizeof(andData)); + memset(&xorData, 0, sizeof(xorData)); + + for (y=0; y=0; x--){ + fullBitRow<<=8; + fullMaskRow<<=8; + fullBitRow |= uns8ReverseBits(bitmap[cols*y + x]); + fullMaskRow |= uns8ReverseBits( mask[cols*y + x]); + } + xorData[y]= fullBitRow & fullMaskRow; + andData[y]= ~fullMaskRow; + } + + m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData); + if (!m_customCursor) { + return GHOST_kFailure; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress) +{ + /*SetProgressValue sets state to TBPF_NORMAL automaticly*/ + if(m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd,10000*progress,10000)) + return GHOST_kSuccess; + + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowWin32::endProgressBar() +{ + if(m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd,TBPF_NOPROGRESS)) + return GHOST_kSuccess; + + return GHOST_kFailure; +} + +/* Ron Fosner's code for weighting pixel formats and forcing software. + See http://www.opengl.org/resources/faq/technical/weight.cpp */ + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) { + int weight = 0; + + /* assume desktop color depth is 32 bits per pixel */ + + /* cull unusable pixel formats */ + /* if no formats can be found, can we determine why it was rejected? */ + if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) || + !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */ + ( pfd.cDepthBits <= 8 ) || + !(pfd.iPixelType == PFD_TYPE_RGBA)) + return 0; + + weight = 1; /* it's usable */ + + /* the bigger the depth buffer the better */ + /* give no weight to a 16-bit depth buffer, because those are crap */ + weight += pfd.cDepthBits - 16; + + weight += pfd.cColorBits - 8; + + /* want swap copy capability -- it matters a lot */ + if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16; + + /* but if it's a generic (not accelerated) view, it's really bad */ + if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10; + + return weight; +} + +/* A modification of Ron Fosner's replacement for ChoosePixelFormat */ +/* returns 0 on error, else returns the pixel format number to be used */ +static int EnumPixelFormats(HDC hdc) { + int iPixelFormat; + int i, n, w, weight = 0; + PIXELFORMATDESCRIPTOR pfd; + + /* we need a device context to do anything */ + if(!hdc) return 0; + + iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */ + + /* obtain detailed information about + the device context's first pixel format */ + n = 1+::DescribePixelFormat(hdc, iPixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + /* choose a pixel format using the useless Windows function in case + we come up empty handed */ + iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat ); + + if(!iPixelFormat) return 0; /* couldn't find one to use */ + + for(i=1; i<=n; i++) { /* not the idiom, but it's right */ + ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + w = WeightPixelFormat(pfd); + // be strict on stereo + if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO)) { + if(w > weight) { + weight = w; + iPixelFormat = i; + } + } + } + if (weight == 0) { + // we could find the correct stereo setting, just find any suitable format + for(i=1; i<=n; i++) { /* not the idiom, but it's right */ + ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + w = WeightPixelFormat(pfd); + if(w > weight) { + weight = w; + iPixelFormat = i; + } + } + } + return iPixelFormat; +} + + diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h new file mode 100644 index 00000000000..4055c3acf56 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -0,0 +1,400 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowWin32.h + * \ingroup GHOST + * Declaration of GHOST_WindowWin32 class. + */ + +#ifndef _GHOST_WINDOW_WIN32_H_ +#define _GHOST_WINDOW_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_Window.h" + +/* MinGW needs it */ +#ifdef FREE_WINDOWS +#ifdef WINVER +#undef WINVER +#endif +#define WINVER 0x0501 +#endif + + + +#include +#include "GHOST_TaskbarWin32.h" + + +#include +#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) +#define PACKETMODE PK_BUTTONS +#include + +class GHOST_SystemWin32; +class GHOST_DropTargetWin32; + +// typedefs for WinTab functions to allow dynamic loading +typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID ); +typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL); +typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX); +typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID); + +/** + * GHOST window on M$ Windows OSs. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_WindowWin32 : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + */ + GHOST_WindowWin32( + GHOST_SystemWin32 * system, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0, + GHOST_TEmbedderWindowID parentWindowHwnd=0, + GHOST_TSuccess msEnabled = GHOST_kFailure, + int msPixelFormat = 0 + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowWin32(); + + /** + * Returns the window to replace this one if it's getting replaced + * @return The window replacing this one. + */ + + GHOST_Window *getNextWindow(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Access to the handle of the window. + * @return The handle of the window. + */ + virtual HWND getHWND() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return Indication of success. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Invalidates the contents of this window. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Sets the progress bar value displayed in the window/application icon + * @param progress The progress % + */ + virtual GHOST_TSuccess setProgressBar(float progress); + + /** + * Hides the progress bar in the icon + */ + virtual GHOST_TSuccess endProgressBar(); + + /** + * Returns the name of the window class. + * @return The name of the window class. + */ + static LPCSTR getWindowClassName() { return s_windowClassName; } + + /** + * Register a mouse click event (should be called + * for any real button press, controls mouse + * capturing). + * + * @param press + * 0 - mouse pressed + * 1 - mouse released + * 2 - operator grab + * 3 - operator ungrab + */ + void registerMouseClickEvent(int press); + + /** + * Inform the window that it has lost mouse capture, + * called in response to native window system messages. + */ + void lostMouseCapture(); + + /** + * Loads the windows equivalent of a standard GHOST cursor. + * @param visible Flag for cursor visibility. + * @param cursorShape The cursor shape. + */ + void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; + + const GHOST_TabletData* GetTabletData() + { return m_tabletData; } + + void processWin32TabletInitEvent(); + void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); + +protected: + GHOST_TSuccess initMultisample(PIXELFORMATDESCRIPTOR pfd); + + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication of success. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor grab on the window using native window system calls. + * Using registerMouseClickEvent. + * @param mode GHOST_TGrabCursorMode. + */ + virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + virtual GHOST_TSuccess setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + + /** Pointer to system */ + GHOST_SystemWin32 * m_system; + /** Pointer to COM IDropTarget implementor */ + GHOST_DropTargetWin32 * m_dropTarget; + /** Window handle. */ + HWND m_hWnd; + /** Device context handle. */ + HDC m_hDC; + /** OpenGL rendering context. */ + HGLRC m_hGlRc; + /** The first created OpenGL context (for sharing display lists) */ + static HGLRC s_firsthGLRc; + /** The first created device context handle. */ + static HDC s_firstHDC; + /** Flag for if window has captured the mouse */ + bool m_hasMouseCaptured; + /** Flag if an operator grabs the mouse with WM_cursor_grab/ungrab() + * Multiple grabs must be realesed with a single ungrab*/ + bool m_hasGrabMouse; + /** Count of number of pressed buttons */ + int m_nPressedButtons; + /** HCURSOR structure of the custom cursor */ + HCURSOR m_customCursor; + + /** ITaskbarList3 structure for progress bar*/ + ITaskbarList3 * m_Bar; + + static LPCSTR s_windowClassName; + static const int s_maxTitleLength; + + /** WinTab dll handle */ + HMODULE m_wintab; + + /** Tablet data for GHOST */ + GHOST_TabletData* m_tabletData; + + /** Stores the Tablet context if detected Tablet features using WinTab.dll */ + HCTX m_tablet; + LONG m_maxPressure; + LONG m_maxAzimuth, m_maxAltitude; + + /** Preferred number of samples */ + GHOST_TUns16 m_multisample; + + /** Check if multisample is supported */ + GHOST_TSuccess m_multisampleEnabled; + + /** The pixelFormat to use for multisample */ + int m_msPixelFormat; + + /** We need to following to recreate the window */ + const STR_String& m_title; + GHOST_TInt32 m_left; + GHOST_TInt32 m_top; + GHOST_TUns32 m_width; + GHOST_TUns32 m_height; + GHOST_TWindowState m_normal_state; + bool m_stereo; + + /** The GHOST_System passes this to wm if this window is being replaced */ + GHOST_Window *m_nextWindow; + + /** Hwnd to parent window */ + GHOST_TEmbedderWindowID m_parentWindowHwnd; +}; + +#endif // _GHOST_WINDOW_WIN32_H_ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp new file mode 100644 index 00000000000..aea5b5156d9 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -0,0 +1,1598 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowX11.cpp + * \ingroup GHOST + */ + + +#include "GHOST_WindowX11.h" +#include "GHOST_SystemX11.h" +#include "STR_String.h" +#include "GHOST_Debug.h" + +// For standard X11 cursors +#include +#include + +#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) || defined (_AIX) +#include +#endif + +#include +#include + +#include +#include + +// For obscure full screen mode stuuf +// lifted verbatim from blut. + +typedef struct { + long flags; + long functions; + long decorations; + long input_mode; +} MotifWmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + + +// #define GHOST_X11_GRAB + +/* + * A Client can't change the window property, that is + * the work of the window manager. In case, we send + * a ClientMessage to the RootWindow with the property + * and the Action (WM-spec define this): + */ +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + +/* +import bpy +I = bpy.data.images['blender.png'] # the 48x48 icon + +# Write to a file that can be +# used within static unsigned char BLENDER_ICON_48x48x24[] = {...} +f = open('/myicon.txt', 'w') +for j in xrange(48): + for k in xrange(48): + v = I.getPixelI(j,47-k) + v.pop() + for p in v: + f.write(str(hex(p))+',') + + f.write('\n') +*/ + +// See the python script above to regenerate the 48x48 icon within blender +#define BLENDER_ICON_WIDTH 48 +#define BLENDER_ICON_HEIGHT 48 +static unsigned char BLENDER_ICON_48x48x24[] = { +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2a,0xd,0xa7,0x5b,0x1f,0xb8,0x66,0x22,0x6c,0x3b,0x14,0x5,0x3,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x3a,0x13,0xea,0x7f,0x2c,0xee,0x7e,0x2b,0xee,0x7e,0x2b,0xef,0x85,0x2e,0x5f,0x35,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x22,0xb,0xed,0x7f,0x2c,0xed,0x7c,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x80,0x2c,0xa8,0x5f,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2e,0x16,0x6,0xd0,0x6f,0x26,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x82,0x2d,0x9a,0x57,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x17,0xb,0x4,0xb9,0x60,0x21,0xed,0x7a,0x2a,0xed,0x7b,0x2a,0xed,0x7e,0x2b,0xee,0x7f,0x2c,0xee,0x7f,0x2c,0xee,0x86,0x2e,0x4e,0x2b,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1,0x0,0x0,0x96,0x4d,0x19,0xee,0x7a,0x2a,0xed,0x79,0x2a,0xed,0x7c,0x2b,0xed,0x7e,0x2b,0xed,0x7e,0x2b,0xef,0x83,0x2d,0x98,0x55,0x1c,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x20,0xf,0x5,0x4b,0x27,0xe,0x21,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x67,0x34,0x11,0xed,0x7b,0x2a,0xec,0x79,0x29,0xed,0x7b,0x2a,0xed,0x7c,0x2b,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xbb,0x69,0x24,0x11,0x9,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x38,0x1c,0x9,0xc9,0x6d,0x2c,0xf1,0x86,0x36,0xd7,0x79,0x2a,0x22,0x12,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3b,0x1d,0x9,0xe0,0x74,0x27,0xed,0x7a,0x2a,0xed,0x7c,0x2a,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xdc,0x7a,0x2a,0x1e,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa6,0x56,0x23,0xee,0x83,0x3b,0xed,0x7d,0x2c,0xf0,0x85,0x2e,0x75,0x43,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x12,0x5,0xc9,0x68,0x24,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xed,0x7e,0x2b,0xee,0x7e,0x2c,0xed,0x7d,0x2b,0xe3,0x7d,0x2b,0x3b,0x1f,0xa,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1c,0xd,0x4,0xd9,0x74,0x35,0xee,0x83,0x3a,0xee,0x7f,0x2b,0xf0,0x86,0x2e,0x83,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa,0x5,0x1,0xa1,0x54,0x1c,0xee,0x7e,0x2c,0xed,0x7e,0x2c,0xed,0x7f,0x2c,0xed,0x80,0x2c,0xed,0x7f,0x2b,0xec,0x81,0x2d,0x60,0x33,0x11,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7a,0x38,0xee,0x84,0x3a,0xee,0x82,0x2c,0xf0,0x88,0x2f,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x39,0x13,0xef,0x82,0x30,0xed,0x82,0x2f,0xee,0x82,0x2e,0xee,0x82,0x2d,0xee,0x81,0x2c,0xf0,0x83,0x2d,0x88,0x49,0x18,0x3,0x2,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7c,0x3a,0xee,0x86,0x3b,0xee,0x84,0x2d,0xf1,0x8b,0x30,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x54,0x2b,0xf,0xe9,0x80,0x30,0xee,0x87,0x33,0xef,0x88,0x32,0xef,0x88,0x30,0xee,0x85,0x2f,0xef,0x83,0x2e,0xae,0x5f,0x20,0x4,0x2,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7e,0x3d,0xef,0x8a,0x3d,0xef,0x88,0x2e,0xf1,0x8d,0x31,0x81,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0x29,0x15,0x7,0xd2,0x74,0x2d,0xf0,0x8b,0x36,0xf0,0x8d,0x35,0xef,0x8d,0x35,0xef,0x8b,0x33,0xef,0x88,0x30,0xc4,0x6d,0x26,0x18,0xc,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe1,0x80,0x3f,0xf0,0x8d,0x3f,0xef,0x8a,0x2f,0xf1,0x8f,0x32,0x81,0x4e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x3,0x0,0xb1,0x61,0x26,0xf1,0x8e,0x3a,0xf1,0x90,0x3a,0xf0,0x90,0x38,0xf0,0x90,0x36,0xef,0x8e,0x35,0xd3,0x7a,0x2c,0x22,0x11,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x12,0x5,0xe1,0x83,0x42,0xf0,0x90,0x42,0xf0,0x8d,0x30,0xf2,0x92,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x3,0x2,0x0,0x81,0x45,0x1b,0xf1,0x90,0x3e,0xf1,0x94,0x3d,0xf1,0x95,0x3c,0xf0,0x94,0x3b,0xf0,0x92,0x39,0xf0,0x90,0x35,0xd0,0x7b,0x2b,0xc2,0x6e,0x26,0xbe,0x6c,0x25,0x94,0x54,0x1c,0x5b,0x33,0x11,0x1a,0xe,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x14,0x6,0xe2,0x86,0x44,0xf1,0x94,0x45,0xf0,0x90,0x31,0xf2,0x94,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x60,0x34,0x14,0xed,0x8c,0x3e,0xf0,0x96,0x42,0xf1,0x97,0x40,0xf1,0x95,0x3f,0xf0,0x91,0x39,0xef,0x8e,0x33,0xef,0x8d,0x31,0xf0,0x8d,0x31,0xef,0x8c,0x30,0xef,0x8c,0x30,0xf0,0x8d,0x31,0xf1,0x8e,0x31,0xe1,0x85,0x2e,0x92,0x55,0x1d,0x25,0x14,0x7,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe2,0x89,0x46,0xf2,0x97,0x47,0xf1,0x92,0x32,0xf2,0x96,0x34,0x80,0x4e,0x1a,0x32,0x1a,0xa,0xe3,0x87,0x3d,0xf1,0x97,0x45,0xf1,0x98,0x44,0xf1,0x95,0x41,0xf0,0x90,0x39,0xef,0x8d,0x30,0xef,0x8f,0x31,0xf0,0x90,0x32,0xf0,0x92,0x33,0xf1,0x93,0x33,0xf1,0x94,0x34,0xf1,0x94,0x34,0xf0,0x93,0x34,0xf0,0x91,0x32,0xf1,0x91,0x33,0xe2,0x8a,0x30,0x6b,0x3f,0x15,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8b,0x49,0xf2,0x9a,0x49,0xf1,0x93,0x32,0xf2,0x98,0x35,0x8f,0x57,0x1d,0xcf,0x7c,0x38,0xf2,0x99,0x48,0xf1,0x98,0x47,0xf1,0x96,0x44,0xf0,0x90,0x39,0xef,0x8d,0x31,0xf0,0x90,0x31,0xf0,0x92,0x33,0xf1,0x94,0x33,0xf1,0x96,0x35,0xf1,0x98,0x35,0xf1,0x9a,0x36,0xf1,0x9c,0x37,0xf2,0x9d,0x37,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xf0,0x94,0x34,0xf3,0x97,0x35,0x9f,0x60,0x21,0x13,0xb,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8d,0x4b,0xf2,0x9b,0x4c,0xf1,0x93,0x32,0xf1,0x97,0x35,0xea,0x98,0x43,0xf2,0x9d,0x4d,0xf1,0x9a,0x4b,0xf1,0x99,0x49,0xf0,0x93,0x3d,0xf0,0x8d,0x30,0xf0,0x90,0x32,0xf0,0x92,0x32,0xf0,0x94,0x34,0xf1,0x96,0x34,0xf1,0x98,0x36,0xf1,0x9a,0x36,0xf2,0x9c,0x38,0xf2,0x9f,0x38,0xf2,0xa2,0x39,0xf3,0xa2,0x39,0xf3,0xa2,0x39,0xf2,0x9f,0x38,0xf1,0x99,0x35,0xf2,0x97,0x35,0xba,0x74,0x29,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x8e,0x4d,0xf2,0x9d,0x4e,0xf1,0x93,0x32,0xf2,0x9d,0x3f,0xf3,0xa4,0x54,0xf2,0x9d,0x50,0xf1,0x9b,0x4d,0xf2,0x98,0x46,0xef,0x8d,0x31,0xf0,0x8f,0x31,0xf0,0x91,0x32,0xf0,0x93,0x32,0xf1,0x94,0x32,0xf1,0x95,0x32,0xf1,0x98,0x34,0xf1,0x9b,0x36,0xf2,0x9e,0x38,0xf2,0xa1,0x39,0xf2,0xa4,0x3a,0xf3,0xa6,0x3b,0xf4,0xa8,0x3c,0xf3,0xa7,0x3c,0xf3,0xa4,0x3a,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xa9,0x69,0x25,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x90,0x50,0xf2,0x9e,0x51,0xf1,0x95,0x35,0xf4,0xa6,0x54,0xf3,0xa2,0x55,0xf2,0x9e,0x51,0xf2,0x9c,0x4e,0xf0,0x8f,0x35,0xf0,0x8e,0x31,0xf0,0x90,0x32,0xf3,0xa5,0x56,0xf7,0xc4,0x8e,0xfa,0xd8,0xb6,0xfb,0xdf,0xc2,0xfa,0xd8,0xb2,0xf7,0xc4,0x89,0xf4,0xae,0x59,0xf2,0xa1,0x38,0xf3,0xa5,0x3b,0xf4,0xa8,0x3c,0xf4,0xab,0x3d,0xf4,0xac,0x3e,0xf4,0xab,0x3d,0xf3,0xa7,0x3b,0xf2,0x9e,0x38,0xf4,0x9e,0x38,0x6f,0x45,0x17,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xc,0x5,0x63,0x36,0x18,0x3f,0x20,0x9,0x2,0x1,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x91,0x52,0xf3,0xa2,0x55,0xf2,0x9d,0x43,0xf4,0xa7,0x5b,0xf3,0xa2,0x57,0xf3,0xa0,0x55,0xf1,0x97,0x43,0xf0,0x8d,0x30,0xf2,0x9d,0x4c,0xfa,0xda,0xbc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xf6,0xfa,0xdc,0xb5,0xf4,0xae,0x4e,0xf4,0xa9,0x3c,0xf4,0xac,0x3d,0xf4,0xae,0x3f,0xf4,0xaf,0x3f,0xf4,0xad,0x3f,0xf3,0xa8,0x3d,0xf2,0x9d,0x38,0xe2,0x94,0x34,0x23,0x14,0x6,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0x9e,0x62,0x39,0xf2,0x91,0x4e,0xe7,0x79,0x29,0x48,0x25,0xc,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x27,0x13,0x6,0xe5,0x93,0x54,0xf3,0xa7,0x59,0xf4,0xa6,0x56,0xf4,0xa7,0x5d,0xf3,0xa4,0x59,0xf3,0xa2,0x57,0xf1,0x90,0x36,0xf4,0xa7,0x5d,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe3,0xf6,0xb8,0x5f,0xf4,0xac,0x3e,0xf4,0xaf,0x3f,0xf4,0xb1,0x40,0xf4,0xb2,0x40,0xf5,0xaf,0x3f,0xf3,0xa6,0x3c,0xf3,0x9f,0x38,0x90,0x5d,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3d,0x1f,0xf,0xed,0x9c,0x6a,0xef,0x8b,0x4a,0xec,0x78,0x29,0xe4,0x79,0x2a,0x29,0x15,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0x28,0x14,0x6,0xe6,0x97,0x57,0xf5,0xad,0x63,0xf5,0xac,0x62,0xf4,0xa8,0x5f,0xf4,0xa6,0x5c,0xf3,0xa0,0x53,0xf4,0xa9,0x64,0xfe,0xf8,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xf2,0xf7,0xfa,0xed,0xf4,0xf8,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xed,0xf5,0xb5,0x53,0xf5,0xb0,0x3f,0xf5,0xb3,0x41,0xf5,0xb4,0x42,0xf5,0xb3,0x41,0xf4,0xad,0x3f,0xf3,0xa1,0x39,0xe4,0x98,0x37,0x1d,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x23,0x10,0xf2,0xa1,0x70,0xf1,0x99,0x61,0xec,0x78,0x2a,0xed,0x7b,0x2a,0xc4,0x69,0x23,0x15,0xa,0x3,0x0,0x0,0x0,0x1d,0xf,0x5,0xe7,0x9b,0x5b,0xf5,0xb1,0x68,0xf5,0xad,0x65,0xf4,0xaa,0x62,0xf4,0xa8,0x5f,0xf3,0xa4,0x59,0xfd,0xec,0xde,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xfe,0xc3,0xda,0xe9,0x5c,0x9a,0xc5,0x2a,0x7b,0xb4,0x17,0x6f,0xae,0x36,0x81,0xb8,0x91,0xbb,0xd9,0xf0,0xf6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc7,0xf5,0xb2,0x43,0xf6,0xb3,0x41,0xf5,0xb5,0x43,0xf5,0xb6,0x43,0xf5,0xb3,0x42,0xf4,0xa8,0x3c,0xf4,0xa2,0x3a,0x66,0x41,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x22,0x10,0x7,0xd6,0x88,0x5b,0xf2,0xa5,0x76,0xee,0x84,0x3f,0xed,0x7a,0x2a,0xee,0x80,0x2c,0xa5,0x59,0x1e,0x7,0x3,0x1,0x19,0xd,0x4,0xe7,0x9e,0x5e,0xf6,0xb2,0x6b,0xf5,0xae,0x67,0xf5,0xac,0x65,0xf4,0xa9,0x61,0xf8,0xcc,0xa1,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xfe,0xfe,0x97,0xbf,0xdb,0x33,0x83,0xbb,0x24,0x7e,0xb9,0x3,0x6a,0xae,0x0,0x66,0xab,0x0,0x64,0xa9,0x1,0x63,0xa9,0x3c,0x87,0xbd,0xee,0xf5,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc7,0x76,0xf6,0xb4,0x41,0xf5,0xb7,0x43,0xf6,0xb8,0x44,0xf6,0xb6,0x43,0xf5,0xae,0x3f,0xf3,0xa2,0x3a,0xac,0x71,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x52,0x2c,0x16,0xf0,0xa1,0x71,0xf2,0xa2,0x6f,0xed,0x7e,0x32,0xed,0x7e,0x2b,0xef,0x82,0x2d,0x8a,0x49,0x18,0x1b,0xe,0x4,0xe7,0xa2,0x61,0xf6,0xb3,0x6e,0xf6,0xb0,0x6a,0xf5,0xae,0x67,0xf5,0xab,0x64,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xb4,0xd1,0xe5,0x3e,0x8d,0xc3,0x37,0x8e,0xc5,0x16,0x7a,0xb9,0x0,0x6b,0xaf,0x0,0x68,0xac,0x0,0x65,0xaa,0x0,0x65,0xab,0x0,0x66,0xac,0x4d,0x93,0xc4,0xf8,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc5,0xf6,0xb3,0x40,0xf6,0xb7,0x43,0xf6,0xb9,0x44,0xf6,0xb8,0x45,0xf5,0xb2,0x41,0xf3,0xa5,0x3b,0xe2,0x98,0x37,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x86,0x4e,0x2e,0xf3,0xa6,0x77,0xf1,0x9e,0x66,0xed,0x7e,0x2d,0xee,0x82,0x2c,0xf0,0x85,0x2d,0x7e,0x47,0x17,0xe8,0xa6,0x64,0xf6,0xb5,0x70,0xf6,0xb2,0x6d,0xf5,0xb0,0x6a,0xf7,0xbb,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xfb,0xfd,0x5b,0x9c,0xca,0x42,0x96,0xcb,0x3c,0x93,0xc9,0x9,0x73,0xb6,0x0,0x6b,0xb0,0x0,0x69,0xad,0x0,0x66,0xab,0x0,0x66,0xab,0x0,0x67,0xad,0x4,0x6a,0xaf,0xbb,0xd7,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf8,0xee,0xf6,0xb9,0x4f,0xf6,0xb7,0x44,0xf6,0xba,0x45,0xf6,0xba,0x45,0xf5,0xb5,0x43,0xf4,0xa8,0x3d,0xf5,0xa7,0x3d,0x1b,0xf,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0xb0,0x6d,0x45,0xf4,0xaa,0x7b,0xf1,0x9a,0x5b,0xee,0x82,0x2d,0xef,0x86,0x2e,0xee,0x91,0x36,0xf5,0xb5,0x70,0xf6,0xb7,0x73,0xf6,0xb4,0x70,0xf5,0xb1,0x6c,0xf9,0xcc,0xa1,0xff,0xff,0xff,0xff,0xff,0xff,0xd1,0xe2,0xef,0x4b,0x97,0xca,0x47,0x9a,0xce,0x3f,0x95,0xcb,0x3,0x71,0xb5,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x67,0xac,0x0,0x66,0xac,0x0,0x67,0xad,0x0,0x69,0xaf,0x66,0xa5,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfa,0xf8,0xc3,0x67,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbb,0x46,0xf6,0xb7,0x44,0xf4,0xab,0x3e,0xf8,0xab,0x3f,0x2a,0x19,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2b,0x15,0x9,0xd4,0x8a,0x5c,0xf4,0xac,0x7c,0xf1,0x98,0x54,0xee,0x85,0x2e,0xf1,0x93,0x38,0xf6,0xba,0x75,0xf6,0xb9,0x75,0xf6,0xb6,0x72,0xf6,0xb3,0x6f,0xfa,0xd5,0xb1,0xff,0xff,0xff,0xff,0xff,0xff,0xb0,0xcf,0xe5,0x51,0x9e,0xcf,0x4b,0x9d,0xd0,0x43,0x97,0xcc,0x3,0x71,0xb5,0x0,0x6d,0xb1,0x0,0x6a,0xae,0x0,0x67,0xac,0x0,0x67,0xad,0x0,0x68,0xae,0x0,0x6a,0xb0,0x3b,0x8c,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf9,0xc9,0x77,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbc,0x46,0xf6,0xb8,0x44,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x47,0x26,0x12,0xee,0xa3,0x72,0xf4,0xae,0x7b,0xf1,0x97,0x4e,0xf1,0x92,0x38,0xf6,0xbb,0x78,0xf6,0xbb,0x78,0xf6,0xb7,0x75,0xf6,0xb5,0x71,0xfa,0xd6,0xb2,0xff,0xff,0xff,0xff,0xff,0xff,0xad,0xcd,0xe4,0x54,0xa0,0xd1,0x4e,0xa0,0xd1,0x48,0x9b,0xce,0xb,0x76,0xb8,0x0,0x6d,0xb2,0x0,0x6a,0xaf,0x0,0x68,0xad,0x0,0x68,0xad,0x0,0x69,0xae,0x0,0x6b,0xb1,0x36,0x89,0xc1,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xf9,0xc9,0x76,0xf6,0xb9,0x44,0xf6,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb9,0x44,0xf4,0xad,0x3f,0xf8,0xad,0x40,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x70,0x42,0x26,0xf4,0xad,0x7b,0xf5,0xb1,0x7d,0xf3,0x9f,0x50,0xf7,0xbc,0x7b,0xf7,0xbc,0x7b,0xf6,0xb9,0x78,0xf6,0xb7,0x74,0xf9,0xd0,0xa6,0xff,0xff,0xff,0xff,0xff,0xff,0xc3,0xda,0xeb,0x56,0xa0,0xd0,0x51,0xa1,0xd2,0x4a,0x9c,0xcf,0x20,0x82,0xbf,0x0,0x6e,0xb2,0x0,0x6b,0xb0,0x0,0x68,0xae,0x0,0x68,0xae,0x0,0x69,0xaf,0x0,0x6b,0xb1,0x50,0x98,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf9,0xf8,0xc3,0x66,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb8,0x45,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x19,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xc,0x5,0x0,0xa5,0x67,0x40,0xf5,0xb1,0x7f,0xf5,0xb7,0x7e,0xf7,0xbf,0x80,0xf7,0xbe,0x7d,0xf7,0xbb,0x7b,0xf6,0xb9,0x78,0xf8,0xc2,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xf5,0xf9,0x5b,0xa0,0xce,0x53,0xa2,0xd2,0x4c,0x9e,0xd0,0x3c,0x93,0xc8,0x6,0x71,0xb4,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x69,0xae,0x0,0x6a,0xaf,0x0,0x6b,0xb1,0x9b,0xc5,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xec,0xf6,0xba,0x4e,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf5,0xb7,0x44,0xf4,0xab,0x3e,0xf5,0xa8,0x3e,0x18,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1f,0x10,0x7,0xc9,0x84,0x56,0xf5,0xb5,0x81,0xf7,0xbf,0x82,0xf8,0xc0,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x7a,0xf6,0xb8,0x77,0xfe,0xf5,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0x9a,0xc2,0xdf,0x55,0x9f,0xd0,0x4e,0x9f,0xd0,0x47,0x99,0xcc,0x2a,0x87,0xc1,0x3,0x6d,0xb1,0x0,0x69,0xaf,0x0,0x6a,0xaf,0x0,0x6a,0xb0,0x27,0x80,0xbc,0xec,0xf4,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe5,0xbf,0xf6,0xb6,0x42,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xbb,0x47,0xf5,0xb5,0x43,0xf3,0xa8,0x3d,0xdd,0x97,0x37,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x32,0x1a,0xb,0xe4,0x9d,0x6a,0xf7,0xbd,0x84,0xf8,0xc1,0x83,0xf8,0xbe,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x79,0xfa,0xd9,0xb6,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xf6,0xfa,0x74,0xac,0xd4,0x4f,0x9b,0xcd,0x48,0x99,0xcc,0x41,0x94,0xc8,0x2c,0x85,0xbe,0xb,0x70,0xb3,0x1,0x6a,0xb0,0xb,0x6e,0xb2,0xbf,0xd9,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc8,0x74,0xf6,0xb7,0x44,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xb9,0x46,0xf6,0xb2,0x42,0xf4,0xa7,0x3d,0xa6,0x70,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2e,0x18,0xef,0xaf,0x78,0xf8,0xc1,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x7f,0xf7,0xbc,0x7d,0xf7,0xbe,0x81,0xfe,0xf3,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xf2,0xf7,0xfa,0x91,0xbd,0xdb,0x4f,0x97,0xc8,0x40,0x8e,0xc3,0x37,0x8a,0xc0,0x34,0x88,0xbf,0x57,0x9c,0xca,0xcc,0xe1,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe4,0xbf,0xf5,0xb6,0x45,0xf6,0xb8,0x45,0xf6,0xba,0x46,0xf7,0xba,0x46,0xf6,0xb7,0x45,0xf5,0xad,0x3f,0xf4,0xa9,0x40,0x5c,0x3d,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x85,0x55,0x31,0xf7,0xbd,0x84,0xf8,0xc2,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x80,0xf7,0xbc,0x7d,0xf9,0xcb,0x99,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xe5,0xef,0xf6,0xc1,0xda,0xeb,0xba,0xd5,0xe9,0xd8,0xe8,0xf2,0xf9,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf3,0xe4,0xf6,0xb9,0x51,0xf5,0xb5,0x43,0xf6,0xb8,0x45,0xf6,0xb9,0x46,0xf6,0xb8,0x46,0xf6,0xb3,0x43,0xf4,0xa7,0x3e,0xdf,0x9d,0x43,0x17,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x14,0xa,0x4,0xb2,0x7b,0x4b,0xf8,0xc2,0x88,0xf8,0xc1,0x85,0xf7,0xbf,0x82,0xf7,0xbe,0x80,0xf7,0xbd,0x7d,0xf9,0xca,0x97,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe1,0xf7,0xbc,0x5d,0xf5,0xb3,0x42,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf6,0xb8,0x45,0xf6,0xb5,0x44,0xf5,0xad,0x40,0xf6,0xae,0x4c,0x88,0x5d,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1d,0x10,0x6,0xdb,0xa0,0x68,0xf8,0xc3,0x88,0xf7,0xc1,0x85,0xf7,0xc0,0x82,0xf7,0xbf,0x80,0xf7,0xbe,0x7e,0xf8,0xc4,0x88,0xfc,0xe6,0xcc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfa,0xf3,0xfa,0xda,0xa9,0xf5,0xb3,0x4a,0xf5,0xb2,0x42,0xf5,0xb3,0x43,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf5,0xb5,0x44,0xf5,0xb0,0x42,0xf5,0xad,0x4d,0xdd,0x9e,0x4a,0x19,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x50,0x33,0x19,0xec,0xb4,0x7a,0xf8,0xc2,0x87,0xf7,0xc1,0x85,0xf7,0xc1,0x83,0xf7,0xc0,0x80,0xf7,0xc0,0x7f,0xf7,0xc0,0x7c,0xf7,0xc2,0x7e,0xf8,0xcc,0x92,0xfa,0xda,0xb0,0xfb,0xdf,0xb9,0xfa,0xd9,0xad,0xf7,0xc8,0x84,0xf5,0xb4,0x54,0xf4,0xad,0x3f,0xf4,0xaf,0x41,0xf5,0xb2,0x42,0xf5,0xb4,0x43,0xf5,0xb5,0x44,0xf5,0xb4,0x44,0xf5,0xb2,0x46,0xf5,0xb2,0x54,0xf5,0xb4,0x5a,0x5e,0x3e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x71,0x4b,0x29,0xf8,0xc0,0x86,0xf7,0xc3,0x87,0xf7,0xc2,0x85,0xf7,0xc1,0x83,0xf7,0xc2,0x82,0xf7,0xc2,0x7f,0xf7,0xc2,0x7e,0xf6,0xc0,0x76,0xf4,0xb4,0x59,0xf3,0xa8,0x3e,0xf3,0xa7,0x39,0xf3,0xa9,0x3d,0xf4,0xab,0x3e,0xf4,0xad,0x40,0xf4,0xb0,0x41,0xf4,0xb2,0x42,0xf5,0xb2,0x42,0xf5,0xb3,0x45,0xf6,0xb7,0x54,0xf6,0xb7,0x60,0xf6,0xb5,0x5f,0x9d,0x6b,0x31,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x8b,0x5f,0x36,0xf9,0xc1,0x87,0xf7,0xc3,0x88,0xf8,0xc3,0x86,0xf7,0xc3,0x84,0xf8,0xc3,0x81,0xf7,0xc4,0x80,0xf7,0xc4,0x7e,0xf7,0xc4,0x7d,0xf7,0xc3,0x7a,0xf6,0xbd,0x6c,0xf5,0xb7,0x5c,0xf5,0xb5,0x54,0xf5,0xb4,0x50,0xf5,0xb6,0x52,0xf6,0xb9,0x58,0xf6,0xbd,0x62,0xf7,0xbf,0x6a,0xf6,0xba,0x66,0xf6,0xb6,0x63,0xab,0x78,0x39,0xa,0x6,0x2,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x83,0x58,0x32,0xf0,0xb9,0x7f,0xf7,0xc3,0x88,0xf7,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf8,0xc5,0x7d,0xf7,0xc4,0x7b,0xf7,0xc4,0x79,0xf7,0xc4,0x78,0xf7,0xc3,0x76,0xf7,0xc3,0x74,0xf7,0xc2,0x71,0xf6,0xbe,0x6d,0xf6,0xba,0x6a,0xf4,0xb6,0x65,0x8a,0x5e,0x2c,0xc,0x7,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x33,0x1a,0xd2,0x99,0x60,0xf8,0xc4,0x89,0xf8,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf7,0xc4,0x7e,0xf7,0xc4,0x7b,0xf7,0xc3,0x79,0xf7,0xc2,0x77,0xf6,0xc0,0x74,0xf6,0xbd,0x71,0xf6,0xbb,0x6e,0xe1,0xa4,0x59,0x5c,0x3d,0x1b,0x1,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xe,0x6,0x0,0x72,0x4b,0x28,0xd0,0x9a,0x62,0xf7,0xbf,0x80,0xf8,0xc4,0x85,0xf7,0xc3,0x82,0xf7,0xc3,0x80,0xf7,0xc3,0x7e,0xf7,0xc1,0x7c,0xf6,0xc0,0x7a,0xf7,0xbf,0x78,0xf8,0xbc,0x72,0xde,0xa2,0x5d,0x80,0x57,0x2b,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xe,0x5,0x44,0x2c,0x15,0x81,0x59,0x32,0xb2,0x80,0x4c,0xcb,0x95,0x5b,0xd2,0x9c,0x5f,0xcd,0x97,0x5a,0xb9,0x86,0x4d,0x8b,0x61,0x34,0x4a,0x30,0x17,0x15,0xc,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x1,0x0,0x0,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +}; + + +GLXContext GHOST_WindowX11::s_firstContext = NULL; + +GHOST_WindowX11:: +GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + const GHOST_TEmbedderWindowID parentWindow, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const GHOST_TUns16 numOfAASamples +) : + GHOST_Window(title,left,top,width,height,state,type,stereoVisual,numOfAASamples), + m_context(NULL), + m_display(display), + m_normal_state(GHOST_kWindowStateNormal), + m_system (system), + m_valid_setup (false), + m_invalid_window(false), + m_empty_cursor(None), + m_custom_cursor(None) +{ + + // Set up the minimum atrributes that we require and see if + // X can find us a visual matching those requirements. + + int attributes[40], i, samples; + Atom atoms[2]; + int natom; + int glxVersionMajor, glxVersionMinor; // As in GLX major.minor + + /* initialize incase X11 fails to load */ + memset(&m_xtablet, 0, sizeof(m_xtablet)); + m_visual= NULL; + + if (!glXQueryVersion(m_display, &glxVersionMajor, &glxVersionMinor)) { + printf("%s:%d: X11 glXQueryVersion() failed, verify working openGL system!\n", __FILE__, __LINE__); + + /* exit if this is the first window */ + if(s_firstContext==NULL) { + printf("initial window could not find the GLX extension, exit!\n"); + exit(1); + } + + return; + } + + /* Find the display with highest samples, starting at level requested */ + for (samples = m_numOfAASamples; samples >= 0; samples--) { + i = 0; /* Reusing attributes array, so reset counter */ + + if(m_stereoVisual) + attributes[i++] = GLX_STEREO; + + attributes[i++] = GLX_RGBA; + attributes[i++] = GLX_DOUBLEBUFFER; + attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; + /* GLX >= 1.4 required for multi-sample */ + if(samples && (glxVersionMajor >= 1) && (glxVersionMinor >= 4)) { + attributes[i++] = GLX_SAMPLE_BUFFERS; attributes[i++] = 1; + attributes[i++] = GLX_SAMPLES; attributes[i++] = samples; + } + attributes[i] = None; + + m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes); + + /* Any sample level or even zero, which means oversampling disabled, is good + but we need a valid visual to continue */ + if (m_visual == NULL) { + if (samples == 0) { + /* All options exhausted, cannot continue */ + printf("%s:%d: X11 glXChooseVisual() failed, verify working openGL system!\n", __FILE__, __LINE__); + + if(s_firstContext==NULL) { + printf("initial window could not find the GLX extension, exit!\n"); + exit(1); + } + + return; + } + } else { + if (m_numOfAASamples && (m_numOfAASamples > samples)) { + printf("%s:%d: oversampling requested %i but using %i samples\n", __FILE__, __LINE__, m_numOfAASamples, samples); + } + break; + } + } + + // Create a bunch of attributes needed to create an X window. + + + // First create a colormap for the window and visual. + // This seems pretty much a legacy feature as we are in rgba mode anyway. + + XSetWindowAttributes xattributes; + memset(&xattributes, 0, sizeof(xattributes)); + + xattributes.colormap= XCreateColormap( + m_display, + RootWindow(m_display, m_visual->screen), + m_visual->visual, + AllocNone + ); + + xattributes.border_pixel= 0; + + // Specify which events we are interested in hearing. + + xattributes.event_mask= + ExposureMask | StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask | PropertyChangeMask; + + // create the window! + + ; + if (parentWindow == 0) { + m_window = + XCreateWindow( + m_display, + RootWindow(m_display, m_visual->screen), + left, + top, + width, + height, + 0, // no border. + m_visual->depth, + InputOutput, + m_visual->visual, + CWBorderPixel|CWColormap|CWEventMask, + &xattributes + ); + } else { + + Window root_return; + int x_return,y_return; + unsigned int w_return,h_return,border_w_return,depth_return; + + XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return, + &w_return, &h_return, &border_w_return, &depth_return ); + + left = 0; + top = 0; + width = w_return; + height = h_return; + + + m_window = XCreateWindow( + m_display, + parentWindow, // reparent against embedder + left, + top, + width, + height, + 0, // no border. + m_visual->depth, + InputOutput, + m_visual->visual, + CWBorderPixel|CWColormap|CWEventMask, + &xattributes + ); + + XSelectInput(m_display , parentWindow, SubstructureNotifyMask); + + } + + /* + * One of the problem with WM-spec is that can't set a property + * to a window that isn't mapped. That is why we can't "just + * call setState" here. + * + * To fix this, we first need know that the window is really + * map waiting for the MapNotify event. + * + * So, m_post_init indicate that we need wait for the MapNotify + * event and then set the Window state to the m_post_state. + */ + if ((state != GHOST_kWindowStateNormal) && (state != GHOST_kWindowStateMinimized)) { + m_post_init = True; + m_post_state = state; + } + else { + m_post_init = False; + m_post_state = GHOST_kWindowStateNormal; + } + + // Create some hints for the window manager on how + // we want this window treated. + + XSizeHints * xsizehints = XAllocSizeHints(); + xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize; + xsizehints->x = left; + xsizehints->y = top; + xsizehints->width = width; + xsizehints->height = height; + xsizehints->min_width= 320; // size hints, could be made apart of the ghost api + xsizehints->min_height= 240; // limits are also arbitrary, but should not allow 1x1 window + xsizehints->max_width= 65535; + xsizehints->max_height= 65535; + XSetWMNormalHints(m_display, m_window, xsizehints); + XFree(xsizehints); + + XClassHint * xclasshint = XAllocClassHint(); + int len = title.Length() +1 ; + char *wmclass = (char *)malloc(sizeof(char) * len); + strncpy(wmclass, (const char*)title, sizeof(char) * len); + xclasshint->res_name = wmclass; + xclasshint->res_class = wmclass; + XSetClassHint(m_display, m_window, xclasshint); + free(wmclass); + XFree(xclasshint); + + /* The basic for a good ICCCM "work" */ + if (m_system->m_wm_protocols) { + natom= 0; + + if (m_system->m_delete_window_atom) { + atoms[natom]= m_system->m_delete_window_atom; + natom++; + } + + if (m_system->m_wm_take_focus) { + atoms[natom]= m_system->m_wm_take_focus; + natom++; + } + + if (natom) { + /* printf("Register atoms: %d\n", natom); */ + XSetWMProtocols(m_display, m_window, atoms, natom); + } + } + + // Set the window icon + XWMHints *xwmhints = XAllocWMHints(); + XImage *x_image, *mask_image; + Pixmap icon_pixmap, mask_pixmap; + icon_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 24); + mask_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 1); + GC gc_icon = XCreateGC(display, icon_pixmap, 0, NULL); + GC gc_mask = XCreateGC(display, mask_pixmap, 0, NULL); + + x_image = XCreateImage( display, m_visual->visual, 24, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 32, 0 ); + mask_image = XCreateImage( display, m_visual->visual, 1, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 8, 0); + + x_image->data = (char *)malloc(x_image->bytes_per_line * BLENDER_ICON_HEIGHT); + mask_image->data = (char *)malloc( mask_image->bytes_per_line * BLENDER_ICON_HEIGHT); + + /* copy the BLENDER_ICON_48x48x24 into the XImage */ + unsigned char *col = BLENDER_ICON_48x48x24; + int px, py; + for (px=0; pxicon_pixmap = icon_pixmap; + xwmhints->icon_mask = mask_pixmap; + XFreeGC (display, gc_icon); + XFreeGC (display, gc_mask); + XDestroyImage( x_image ); /* frees x_image->data too */ + XDestroyImage( mask_image ); + + xwmhints->initial_state = NormalState; + xwmhints->input= True; + xwmhints->flags= InputHint|IconPixmapHint|IconMaskHint|StateHint; + XSetWMHints(display, m_window, xwmhints ); + XFree(xwmhints); + // done setting the icon + + setTitle(title); + +#ifdef WITH_X11_XINPUT + initXInputDevices(); +#endif + + // now set up the rendering context. + if (installDrawingContext(type) == GHOST_kSuccess) { + m_valid_setup = true; + GHOST_PRINT("Created window\n"); + } + + XMapWindow(m_display, m_window); + GHOST_PRINT("Mapped window\n"); + + XFlush(m_display); +} + +#ifdef WITH_X11_XINPUT +/* + Dummy function to get around IO Handler exiting if device invalid + Basically it will not crash blender now if you have a X device that + is configured but not plugged in. + +*/ +static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) { + fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", + theEvent->error_code, theEvent->request_code) ; + + /* No exit! - but keep lint happy */ + return 0 ; +} + +/* These C functions are copied from Wine 1.1.13's wintab.c */ +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +static bool match_token(const char *haystack, const char *needle) +{ + const char *p, *q; + for (p = haystack; *p; ) + { + while (*p && isspace(*p)) + p++; + if (! *p) + break; + + for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++) + p++; + if (! *q && (isspace(*p) || !*p)) + return TRUE; + + while (*p && ! isspace(*p)) + p++; + } + return FALSE; +} + + +/* Determining if an X device is a Tablet style device is an imperfect science. +** We rely on common conventions around device names as well as the type reported +** by Wacom tablets. This code will likely need to be expanded for alternate tablet types +** +** Wintab refers to any device that interacts with the tablet as a cursor, +** (stylus, eraser, tablet mouse, airbrush, etc) +** this is not to be confused with wacom x11 configuration "cursor" device. +** Wacoms x11 config "cursor" refers to its device slot (which we mirror with +** our gSysCursors) for puck like devices (tablet mice essentially). +*/ +#if 0 // unused +static BOOL is_tablet_cursor(const char *name, const char *type) +{ + int i; + static const char *tablet_cursor_whitelist[] = { + "wacom", + "wizardpen", + "acecad", + "tablet", + "cursor", + "stylus", + "eraser", + "pad", + NULL + }; + + for (i=0; tablet_cursor_whitelist[i] != NULL; i++) { + if (name && match_token(name, tablet_cursor_whitelist[i])) + return TRUE; + if (type && match_token(type, tablet_cursor_whitelist[i])) + return TRUE; + } + return FALSE; +} +#endif +static BOOL is_stylus(const char *name, const char *type) +{ + int i; + static const char* tablet_stylus_whitelist[] = { + "stylus", + "wizardpen", + "acecad", + NULL + }; + + for (i=0; tablet_stylus_whitelist[i] != NULL; i++) { + if (name && match_token(name, tablet_stylus_whitelist[i])) + return TRUE; + if (type && match_token(type, tablet_stylus_whitelist[i])) + return TRUE; + } + + return FALSE; +} + +static BOOL is_eraser(const char *name, const char *type) +{ + if (name && match_token(name, "eraser")) + return TRUE; + if (type && match_token(type, "eraser")) + return TRUE; + return FALSE; +} +#undef BOOL +#undef TRUE +#undef FALSE +/* end code copied from wine */ + +void GHOST_WindowX11::initXInputDevices() +{ + static XErrorHandler old_handler = (XErrorHandler) 0 ; + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + + if(version && (version != (XExtensionVersion*)NoSuchExtension)) { + if(version->present) { + int device_count; + XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); + m_xtablet.StylusDevice = NULL; + m_xtablet.EraserDevice = NULL; + m_xtablet.CommonData.Active= GHOST_kTabletModeNone; + + /* Install our error handler to override Xlib's termination behavior */ + old_handler = XSetErrorHandler(ApplicationErrorHandler) ; + + for(int i=0; inum_classes; ++j) { + if(ici->c_class==ValuatorClass) { +// printf("\t\tfound ValuatorClass\n"); + XValuatorInfo* xvi = (XValuatorInfo*)ici; + m_xtablet.PressureLevels = xvi->axes[2].max_value; + + /* this is assuming that the tablet has the same tilt resolution in both + * positive and negative directions. It would be rather weird if it didn't.. */ + m_xtablet.XtiltLevels = xvi->axes[3].max_value; + m_xtablet.YtiltLevels = xvi->axes[4].max_value; + break; + } + + ici = (XAnyClassPtr)(((char *)ici) + ici->length); + } + } else { + m_xtablet.StylusID= 0; + } + } + else if(m_xtablet.EraserDevice==NULL && is_eraser(device_info[i].name, device_type)) { +// printf("\tfound eraser\n"); + m_xtablet.EraserID= device_info[i].id; + m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); + if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID= 0; + } + + if(device_type) { + XFree((void*)device_type); + } + } + + /* Restore handler */ + (void) XSetErrorHandler(old_handler) ; + + XFreeDeviceList(device_info); + + + XEventClass xevents[10], ev; + int dcount = 0; + + if(m_xtablet.StylusDevice) { + DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + if(m_xtablet.EraserDevice) { + DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); + } + XFree(version); + } +} + +#endif /* WITH_X11_XINPUT */ + + Window +GHOST_WindowX11:: +getXWindow( +){ + return m_window; +} + + bool +GHOST_WindowX11:: +getValid( +) const { + return m_valid_setup; +} + + void +GHOST_WindowX11:: +setTitle( + const STR_String& title +){ + Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0); + Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0); + XChangeProperty(m_display, m_window, + name, utf8str, 8, PropModeReplace, + (const unsigned char*) title.ReadPtr(), + title.Length()); + +// This should convert to valid x11 string +// and getTitle would need matching change + XStoreName(m_display,m_window,title); + + XFlush(m_display); +} + + void +GHOST_WindowX11:: +getTitle( + STR_String& title +) const { + char *name = NULL; + + XFetchName(m_display,m_window,&name); + title= name?name:"untitled"; + XFree(name); +} + + void +GHOST_WindowX11:: +getWindowBounds( + GHOST_Rect& bounds +) const { + // Getting the window bounds under X11 is not + // really supported (nor should it be desired). + getClientBounds(bounds); +} + + void +GHOST_WindowX11:: +getClientBounds( + GHOST_Rect& bounds +) const { + Window root_return; + int x_return,y_return; + unsigned int w_return,h_return,border_w_return,depth_return; + GHOST_TInt32 screen_x, screen_y; + + XGetGeometry(m_display,m_window,&root_return,&x_return,&y_return, + &w_return,&h_return,&border_w_return,&depth_return); + + clientToScreen(0, 0, screen_x, screen_y); + + bounds.m_l = screen_x; + bounds.m_r = bounds.m_l + w_return; + bounds.m_t = screen_y; + bounds.m_b = bounds.m_t + h_return; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientWidth( + GHOST_TUns32 width +){ + XWindowChanges values; + unsigned int value_mask= CWWidth; + values.width = width; + XConfigureWindow(m_display,m_window,value_mask,&values); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientHeight( + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWHeight; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWWidth | CWHeight; + values.width = width; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + void +GHOST_WindowX11:: +screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + // This is correct! + + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + RootWindow(m_display, m_visual->screen), + m_window, + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + + void +GHOST_WindowX11:: +clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + m_window, + RootWindow(m_display, m_visual->screen), + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + +void GHOST_WindowX11::icccmSetState(int state) +{ + XEvent xev; + + if (state != IconicState) + return; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = m_display; + xev.xclient.window = m_window; + xev.xclient.format = 32; + xev.xclient.message_type = m_system->m_wm_change_state; + xev.xclient.data.l[0] = state; + XSendEvent (m_display, RootWindow(m_display, DefaultScreen(m_display)), + False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +int GHOST_WindowX11::icccmGetState(void) const +{ + unsigned char *prop_ret; + unsigned long bytes_after, num_ret; + Atom type_ret; + int format_ret, st; + + prop_ret = NULL; + st = XGetWindowProperty(m_display, m_window, m_system->m_wm_state, 0, + 0x7fffffff, False, m_system->m_wm_state, &type_ret, + &format_ret, &num_ret, &bytes_after, &prop_ret); + + if ((st == Success) && (prop_ret) && (num_ret == 2)) + st = prop_ret[0]; + else + st = NormalState; + + if (prop_ret) + XFree(prop_ret); + return (st); +} + +void GHOST_WindowX11::netwmMaximized(bool set) +{ + XEvent xev; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = m_window; + xev.xclient.message_type = m_system->m_net_state; + xev.xclient.format = 32; + + if (set == True) + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + else + xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + + xev.xclient.data.l[1] = m_system->m_net_max_horz; + xev.xclient.data.l[2] = m_system->m_net_max_vert; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), + False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +bool GHOST_WindowX11::netwmIsMaximized(void) const +{ + unsigned char *prop_ret; + unsigned long bytes_after, num_ret, i; + Atom type_ret; + bool st; + int format_ret, ret, count; + + prop_ret = NULL; + st = False; + ret = XGetWindowProperty(m_display, m_window, m_system->m_net_state, 0, + 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret, + &num_ret, &bytes_after, &prop_ret); + if ((ret == Success) && (prop_ret) && (format_ret == 32)) { + count = 0; + for (i = 0; i < num_ret; i++) { + if (((unsigned long *) prop_ret)[i] == m_system->m_net_max_horz) + count++; + if (((unsigned long *) prop_ret)[i] == m_system->m_net_max_vert) + count++; + if (count == 2) { + st = True; + break; + } + } + } + + if (prop_ret) + XFree(prop_ret); + return (st); +} + +void GHOST_WindowX11::netwmFullScreen(bool set) +{ + XEvent xev; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = m_window; + xev.xclient.message_type = m_system->m_net_state; + xev.xclient.format = 32; + + if (set == True) + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + else + xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + + xev.xclient.data.l[1] = m_system->m_net_fullscreen; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), + False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +bool GHOST_WindowX11::netwmIsFullScreen(void) const +{ + unsigned char *prop_ret; + unsigned long bytes_after, num_ret, i; + Atom type_ret; + bool st; + int format_ret, ret; + + prop_ret = NULL; + st = False; + ret = XGetWindowProperty(m_display, m_window, m_system->m_net_state, 0, + 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret, + &num_ret, &bytes_after, &prop_ret); + if ((ret == Success) && (prop_ret) && (format_ret == 32)) { + for (i = 0; i < num_ret; i++) { + if (((unsigned long *) prop_ret)[i] == m_system->m_net_fullscreen) { + st = True; + break; + } + } + } + + if (prop_ret) + XFree(prop_ret); + return (st); +} + +void GHOST_WindowX11::motifFullScreen(bool set) +{ + MotifWmHints hints; + + hints.flags = MWM_HINTS_DECORATIONS; + if (set == True) + hints.decorations = 0; + else + hints.decorations = 1; + + XChangeProperty(m_display, m_window, m_system->m_motif, + m_system->m_motif, 32, PropModeReplace, + (unsigned char *) &hints, 4); +} + +bool GHOST_WindowX11::motifIsFullScreen(void) const +{ + unsigned char *prop_ret; + unsigned long bytes_after, num_ret; + MotifWmHints *hints; + Atom type_ret; + bool state; + int format_ret, st; + + prop_ret = NULL; + state = False; + st = XGetWindowProperty(m_display, m_window, m_system->m_motif, 0, + 0x7fffffff, False, m_system->m_motif, + &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret); + if ((st == Success) && (prop_ret)) { + hints = (MotifWmHints *) prop_ret; + if (hints->flags & MWM_HINTS_DECORATIONS) { + if (!hints->decorations) + state = True; + } + } + + if (prop_ret) + XFree(prop_ret); + return (state); +} + +GHOST_TWindowState GHOST_WindowX11::getState() const +{ + GHOST_TWindowState state_ret; + int state; + + state_ret = GHOST_kWindowStateNormal; + state = icccmGetState(); + /* + * In the Iconic and Withdrawn state, the window + * is unmaped, so only need return a Minimized state. + */ + if ((state == IconicState) || (state == WithdrawnState)) + state_ret = GHOST_kWindowStateMinimized; + else if (netwmIsMaximized() == True) + state_ret = GHOST_kWindowStateMaximized; + else if (netwmIsFullScreen() == True) + state_ret = GHOST_kWindowStateFullScreen; + else if (motifIsFullScreen() == True) + state_ret = GHOST_kWindowStateFullScreen; + return (state_ret); +} + +GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state) +{ + GHOST_TWindowState cur_state; + bool is_max, is_full, is_motif_full; + + cur_state = getState(); + if (state == (int)cur_state) + return GHOST_kSuccess; + + if (cur_state != GHOST_kWindowStateMinimized) { + /* + * The window don't have this property's + * if it's not mapped. + */ + is_max = netwmIsMaximized(); + is_full = netwmIsFullScreen(); + } + else { + is_max = False; + is_full = False; + } + + is_motif_full = motifIsFullScreen(); + + if (state == GHOST_kWindowStateNormal) + state = m_normal_state; + + if (state == GHOST_kWindowStateNormal) { + if (is_max == True) + netwmMaximized(False); + if (is_full == True) + netwmFullScreen(False); + if (is_motif_full == True) + motifFullScreen(False); + icccmSetState(NormalState); + return (GHOST_kSuccess); + } + + if (state == GHOST_kWindowStateFullScreen) { + /* + * We can't change to full screen if the window + * isn't mapped. + */ + if (cur_state == GHOST_kWindowStateMinimized) + return (GHOST_kFailure); + + m_normal_state = cur_state; + + if (is_max == True) + netwmMaximized(False); + if (is_full == False) + netwmFullScreen(True); + if (is_motif_full == False) + motifFullScreen(True); + return (GHOST_kSuccess); + } + + if (state == GHOST_kWindowStateMaximized) { + /* + * We can't change to Maximized if the window + * isn't mapped. + */ + if (cur_state == GHOST_kWindowStateMinimized) + return (GHOST_kFailure); + + if (is_full == True) + netwmFullScreen(False); + if (is_motif_full == True) + motifFullScreen(False); + if (is_max == False) + netwmMaximized(True); + return (GHOST_kSuccess); + } + + if (state == GHOST_kWindowStateMinimized) { + /* + * The window manager need save the current state of + * the window (maximized, full screen, etc). + */ + icccmSetState(IconicState); + return (GHOST_kSuccess); + } + + return (GHOST_kFailure); +} + +#include +using namespace std; + + GHOST_TSuccess +GHOST_WindowX11:: +setOrder( + GHOST_TWindowOrder order +){ + if (order == GHOST_kWindowOrderTop) { + XWindowAttributes attr; + Atom atom; + + /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some + window managers ignore the former (e.g. kwin from kde) and others + don't implement the latter (e.g. fluxbox pre 0.9.9) */ + + XRaiseWindow(m_display, m_window); + + atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True); + + if (atom != None) { + Window root; + XEvent xev; + long eventmask; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = m_window; + xev.xclient.message_type = atom; + + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = CurrentTime; + xev.xclient.data.l[2] = m_window; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + root = RootWindow(m_display, m_visual->screen), + eventmask = SubstructureRedirectMask | SubstructureNotifyMask; + + XSendEvent(m_display, root, False, eventmask, &xev); + } + + XGetWindowAttributes(m_display, m_window, &attr); + + /* iconized windows give bad match error */ + if (attr.map_state == IsViewable) + XSetInputFocus(m_display, m_window, RevertToPointerRoot, + CurrentTime); + XFlush(m_display); + } else if (order == GHOST_kWindowOrderBottom) { + XLowerWindow(m_display,m_window); + XFlush(m_display); + } else { + return GHOST_kFailure; + } + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +swapBuffers( +){ + if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { + glXSwapBuffers(m_display,m_window); + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + GHOST_TSuccess +GHOST_WindowX11:: +activateDrawingContext( +){ + if (m_context !=NULL) { + glXMakeCurrent(m_display, m_window,m_context); + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + + GHOST_TSuccess +GHOST_WindowX11:: +invalidate( +){ + + // So the idea of this function is to generate an expose event + // for the window. + // Unfortunately X does not handle expose events for you and + // it is the client's job to refresh the dirty part of the window. + // We need to queue up invalidate calls and generate GHOST events + // for them in the system. + + // We implement this by setting a boolean in this class to concatenate + // all such calls into a single event for this window. + + // At the same time we queue the dirty windows in the system class + // and generate events for them at the next processEvents call. + + if (m_invalid_window == false) { + m_system->addDirtyWindow(this); + m_invalid_window = true; + } + + return GHOST_kSuccess; +} + +/** + * called by the X11 system implementation when expose events + * for the window have been pushed onto the GHOST queue + */ + + void +GHOST_WindowX11:: +validate( +){ + m_invalid_window = false; +} + + +/** + * Destructor. + * Closes the window and disposes resources allocated. + */ + +GHOST_WindowX11:: +~GHOST_WindowX11( +){ + static Atom Primary_atom, Clipboard_atom; + Window p_owner, c_owner; + /*Change the owner of the Atoms to None if we are the owner*/ + Primary_atom = XInternAtom(m_display, "PRIMARY", False); + Clipboard_atom = XInternAtom(m_display, "CLIPBOARD", False); + + p_owner = XGetSelectionOwner(m_display, Primary_atom); + c_owner = XGetSelectionOwner(m_display, Clipboard_atom); + + std::map::iterator it = m_standard_cursors.begin(); + for (; it != m_standard_cursors.end(); it++) { + XFreeCursor(m_display, it->second); + } + + if (m_empty_cursor) { + XFreeCursor(m_display, m_empty_cursor); + } + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + +#ifdef WITH_X11_XINPUT + /* close tablet devices */ + if(m_xtablet.StylusDevice) + XCloseDevice(m_display, m_xtablet.StylusDevice); + + if(m_xtablet.EraserDevice) + XCloseDevice(m_display, m_xtablet.EraserDevice); +#endif /* WITH_X11_XINPUT */ + + if (m_context != s_firstContext) { + glXDestroyContext(m_display, m_context); + } + + if (p_owner == m_window) { + XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime); + } + if (c_owner == m_window) { + XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime); + } + + XDestroyWindow(m_display, m_window); + XFree(m_visual); +} + + + + +/** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +installDrawingContext( + GHOST_TDrawingContextType type +){ + // only support openGL for now. + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + m_context = glXCreateContext(m_display, m_visual, s_firstContext, True); + if (m_context !=NULL) { + if (!s_firstContext) { + s_firstContext = m_context; + } + glXMakeCurrent(m_display, m_window,m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + + +/** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +removeDrawingContext( +){ + GHOST_TSuccess success; + + if (m_context != NULL) { + glXDestroyContext(m_display, m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + return success; +} + + + Cursor +GHOST_WindowX11:: +getStandardCursor( + GHOST_TStandardCursor g_cursor +){ + unsigned int xcursor_id; + +#define GtoX(gcurs, xcurs) case gcurs: xcursor_id = xcurs + switch (g_cursor) { + GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break; + GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break; + GtoX(GHOST_kStandardCursorInfo, XC_hand1); break; + GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break; + GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break; + GtoX(GHOST_kStandardCursorCycle, XC_exchange); break; + GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break; + GtoX(GHOST_kStandardCursorWait, XC_watch); break; + GtoX(GHOST_kStandardCursorText, XC_xterm); break; + GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break; + GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break; + GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break; + GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break; + GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break; + GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break; + GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break; + GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break; + GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break; + GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break; + GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break; + GtoX(GHOST_kStandardCursorPencil, XC_pencil); break; + GtoX(GHOST_kStandardCursorCopy, XC_arrow); break; + default: + xcursor_id = 0; + } +#undef GtoX + + if (xcursor_id) { + Cursor xcursor = m_standard_cursors[xcursor_id]; + + if (!xcursor) { + xcursor = XCreateFontCursor(m_display, xcursor_id); + + m_standard_cursors[xcursor_id] = xcursor; + } + + return xcursor; + } else { + return None; + } +} + + Cursor +GHOST_WindowX11:: +getEmptyCursor( +) { + if (!m_empty_cursor) { + Pixmap blank; + XColor dummy; + char data[1] = {0}; + + /* make a blank cursor */ + blank = XCreateBitmapFromData ( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + data, 1, 1 + ); + + m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0); + XFreePixmap(m_display, blank); + } + + return m_empty_cursor; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorVisibility( + bool visible +){ + Cursor xcursor; + + if (visible) { + xcursor = getStandardCursor( getCursorShape() ); + } else { + xcursor = getEmptyCursor(); + } + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorGrab( + GHOST_TGrabCursorMode mode +){ + if(mode != GHOST_kGrabDisable) { + if(mode != GHOST_kGrabNormal) { + m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + setCursorGrabAccum(0, 0); + + if(mode == GHOST_kGrabHide) + setWindowCursorVisibility(false); + + } +#ifdef GHOST_X11_GRAB + XGrabPointer(m_display, m_window, False, ButtonPressMask| ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); +#endif + } + else { + if (m_cursorGrab==GHOST_kGrabHide) { + m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + setWindowCursorVisibility(true); + } + + if(m_cursorGrab != GHOST_kGrabNormal) { + /* use to generate a mouse move event, otherwise the last event + * blender gets can be outside the screen causing menus not to show + * properly unless the user moves the mouse */ + XWarpPointer(m_display,None,None,0,0,0,0,0,0); + } + + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + setCursorGrabAccum(0, 0); + m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ +#ifdef GHOST_X11_GRAB + XUngrabPointer(m_display, CurrentTime); +#endif + } + + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorShape( + GHOST_TStandardCursor shape +){ + Cursor xcursor = getStandardCursor( shape ); + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY +){ + +setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color +){ + Colormap colormap= DefaultColormap(m_display, DefaultScreen(m_display)); + Pixmap bitmap_pix, mask_pix; + XColor fg, bg; + + if(XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) return GHOST_kFailure; + if(XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) return GHOST_kFailure; + + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + + bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char*) bitmap, sizex, sizey); + mask_pix = XCreateBitmapFromData(m_display, m_window, (char*) mask, sizex, sizey); + + m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY); + XDefineCursor(m_display, m_window, m_custom_cursor); + XFlush(m_display); + + XFreePixmap(m_display, bitmap_pix); + XFreePixmap(m_display, mask_pix); + + XFreeColors(m_display, colormap, &fg.pixel, 1, 0L); + XFreeColors(m_display, colormap, &bg.pixel, 1, 0L); + + return GHOST_kSuccess; +} + +/* + +void glutCustomCursor(char *data1, char *data2, int size) +{ + Pixmap source, mask; + Cursor cursor; + XColor fg, bg; + + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "White", &fg, &fg) == 0) return; + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "Red", &bg, &bg) == 0) return; + + + source= XCreateBitmapFromData(__glutDisplay, xdraw, data2, size, size); + mask= XCreateBitmapFromData(__glutDisplay, xdraw, data1, size, size); + + cursor= XCreatePixmapCursor(__glutDisplay, source, mask, &fg, &bg, 7, 7); + + XFreePixmap(__glutDisplay, source); + XFreePixmap(__glutDisplay, mask); + + XDefineCursor(__glutDisplay, xdraw, cursor); +} + +*/ diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h new file mode 100644 index 00000000000..96d8ad77d10 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -0,0 +1,370 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_WindowX11.h + * \ingroup GHOST + * Declaration of GHOST_WindowX11 class. + */ + +#ifndef _GHOST_WINDOWX11_H_ +#define _GHOST_WINDOWX11_H_ + +#include "GHOST_Window.h" +#include +#include +// For tablets +#include + +#include + +class STR_String; +class GHOST_SystemX11; + +/** + * X11 implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_WindowX11 : public GHOST_Window +{ +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param parentWindow Parent (embedder) window + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + * @param numOfAASamples Number of samples used for AA (zero if no AA) + */ + GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + const GHOST_TEmbedderWindowID parentWindow, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false, + const GHOST_TUns16 numOfAASamples = 0 + ); + + bool + getValid( + ) const; + + void + setTitle(const STR_String& title); + + void + getTitle( + STR_String& title + ) const; + + void + getWindowBounds( + GHOST_Rect& bounds + ) const; + + void + getClientBounds( + GHOST_Rect& bounds + ) const; + + GHOST_TSuccess + setClientWidth( + GHOST_TUns32 width + ); + + GHOST_TSuccess + setClientHeight( + GHOST_TUns32 height + ); + + GHOST_TSuccess + setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height + ); + + void + screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + void + clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + GHOST_TWindowState + getState( + ) const ; + + GHOST_TSuccess + setState( + GHOST_TWindowState state + ); + + GHOST_TSuccess + setOrder( + GHOST_TWindowOrder order + ); + + GHOST_TSuccess + swapBuffers( + ); + + GHOST_TSuccess + activateDrawingContext( + ); + GHOST_TSuccess + invalidate( + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + ~GHOST_WindowX11(); + + /** + * @section x11specific X11 system specific calls + */ + + /** + * The reverse of invalidate! Tells this window + * that all events for it have been pushed into + * the GHOST event queue. + */ + + void + validate( + ); + + /** + * Return a handle to the x11 window type. + */ + Window + getXWindow( + ); + + class XTablet + { + public: + GHOST_TabletData CommonData; + + XDevice* StylusDevice; + XDevice* EraserDevice; + + XID StylusID, EraserID; + + int MotionEvent; + int ProxInEvent; + int ProxOutEvent; + + int PressureLevels; + int XtiltLevels, YtiltLevels; + }; + + XTablet& GetXTablet() + { return m_xtablet; } + + const GHOST_TabletData* GetTabletData() + { return &m_xtablet.CommonData; } + + /* + * Need this in case that we want start the window + * in FullScree or Maximized state. + * Check GHOST_WindowX11.cpp + */ + bool m_post_init; + GHOST_TWindowState m_post_state; + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess + installDrawingContext( + GHOST_TDrawingContextType type + ); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess + removeDrawingContext( + ); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorVisibility( + bool visible + ); + + /** + * Sets the cursor grab on the window using + * native window system calls. + * @param warp Only used when grab is enabled, hides the mouse and allows gragging outside the screen. + */ + GHOST_TSuccess + setWindowCursorGrab( + GHOST_TGrabCursorMode mode + ); + + GHOST_TGrabCursorMode + getWindowCursorGrab() const; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorShape( + GHOST_TStandardCursor shape + ); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY + ); + + /** + * Sets the cursor shape on the window using + * native window system calls (Arbitrary size/color). + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + +private : + + /// Force use of public constructor. + + GHOST_WindowX11( + ); + + GHOST_WindowX11( + const GHOST_WindowX11 & + ); + + Cursor + getStandardCursor( + GHOST_TStandardCursor g_cursor + ); + + Cursor + getEmptyCursor( + ); + + void initXInputDevices(); + + GLXContext m_context; + Window m_window; + Display *m_display; + XVisualInfo *m_visual; + GHOST_TWindowState m_normal_state; + + /** The first created OpenGL context (for sharing display lists) */ + static GLXContext s_firstContext; + + /// A pointer to the typed system class. + + GHOST_SystemX11 * m_system; + + bool m_valid_setup; + + /** Used to concatenate calls to invalidate() on this window. */ + bool m_invalid_window; + + /** XCursor structure of an empty (blank) cursor */ + Cursor m_empty_cursor; + + /** XCursor structure of the custom cursor */ + Cursor m_custom_cursor; + + /** Cache of XC_* ID's to XCursor structures */ + std::map m_standard_cursors; + + /* Tablet devices */ + XTablet m_xtablet; + + void icccmSetState(int state); + int icccmGetState() const; + + void netwmMaximized(bool set); + bool netwmIsMaximized() const; + + void netwmFullScreen(bool set); + bool netwmIsFullScreen() const; + + void motifFullScreen(bool set); + bool motifIsFullScreen() const; +}; + + +#endif // _GHOST_WINDOWX11_H_ diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c new file mode 100644 index 00000000000..b34a37132b6 --- /dev/null +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -0,0 +1,557 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#include +#include +#include +#include + +#define FALSE 0 + +#include "GHOST_C-api.h" + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + #else /* WIN32 */ + /* __APPLE__ is defined */ + #include + #endif /* WIN32 */ +#else /* defined(WIN32) || defined(__APPLE__) */ + #include +#endif /* defined(WIN32) || defined(__APPLE__) */ + + +static void gearsTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time); +int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData); + +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static int sExitRequested = 0; +static GHOST_SystemHandle shSystem = NULL; +static GHOST_WindowHandle sMainWindow = NULL; +static GHOST_WindowHandle sSecondaryWindow = NULL; +static GHOST_TStandardCursor sCursor = GHOST_kStandardCursorFirstCursor; +static GHOST_WindowHandle sFullScreenWindow = NULL; +static GHOST_TimerTaskHandle sTestTimer; +static GHOST_TimerTaskHandle sGearsTimer; + +static void testTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) +{ + printf("timer1, time=%d\n", (int)time); +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + const double pi = 3.14159264; + + r0 = inner_radius; + r1 = (float)(outer_radius - tooth_depth/2.0); + r2 = (float)(outer_radius + tooth_depth/2.0); + + da = (float)(2.0*pi / teeth / 4.0); + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = (float)(i * 2.0*pi / teeth); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle)), (float)(r1*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle+3*da)), (float)(r1*sin(angle+3*da)), (float)(width*0.5)); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = (float)(2.0*pi / teeth / 4.0); + for (i=0;iz > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + keyData = (GHOST_TEventKeyData*)GHOST_GetEventData(hEvent); + switch (keyData->key) + { + case GHOST_kKeyC: + { + cursor = sCursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) + { + cursor = GHOST_kStandardCursorFirstCursor; + } + sCursor = (GHOST_TStandardCursor)cursor; + GHOST_SetCursorShape(window, sCursor); + } + break; + case GHOST_kKeyF: + if (!GHOST_GetFullScreen(shSystem)) + { + /* Begin fullscreen mode */ + setting.bpp = 24; + setting.frequency = 85; + setting.xPixels = 640; + setting.yPixels = 480; + + /* + setting.bpp = 16; + setting.frequency = 75; + setting.xPixels = 640; + setting.yPixels = 480; + */ + + sFullScreenWindow = GHOST_BeginFullScreen(shSystem, &setting, + + FALSE /* stereo flag */); + } + else + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + break; + case GHOST_kKeyH: + { + visibility = GHOST_GetCursorVisibility(window); + GHOST_SetCursorVisibility(window, !visibility); + } + break; + case GHOST_kKeyQ: + if (GHOST_GetFullScreen(shSystem)) + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + sExitRequested = 1; + case GHOST_kKeyT: + if (!sTestTimer) + { + sTestTimer = GHOST_InstallTimer(shSystem, 0, 1000, testTimerProc, NULL); + } + else + { + GHOST_RemoveTimer(shSystem, sTestTimer); + sTestTimer = 0; + } + break; + case GHOST_kKeyW: + { + if (sMainWindow) + { + char *title = GHOST_GetTitle(sMainWindow); + char *ntitle = malloc(strlen(title)+2); + + sprintf(ntitle, "%s-", title); + GHOST_SetTitle(sMainWindow, ntitle); + + free(ntitle); + free(title); + } + } + break; + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (window2 == sMainWindow) + { + sExitRequested = 1; + } + else + { + if (sGearsTimer) + { + GHOST_RemoveTimer(shSystem, sGearsTimer); + sGearsTimer = 0; + } + GHOST_DisposeWindow(shSystem, window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = 0; + break; + case GHOST_kEventWindowDeactivate: + handled = 0; + break; + case GHOST_kEventWindowUpdate: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (!GHOST_ValidWindow(shSystem, window2)) + break; + setViewPortGL(window2); + drawGL(); + GHOST_SwapWindowBuffers(window2); + } + break; + + default: + handled = 0; + break; + } + return handled; +} + + +int main(int argc, char** argv) +{ + char* title1 = "gears - main window"; + char* title2 = "gears - secondary window"; + GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL); + + /* Create the system */ + shSystem = GHOST_CreateSystem(); + GHOST_AddEventConsumer(shSystem, consumer); + + if (shSystem) + { + /* Create the main window */ + sMainWindow = GHOST_CreateWindow(shSystem, + title1, + 10, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sMainWindow) + { + printf("could not create main window\n"); + exit(-1); + } + + /* Create a secondary window */ + sSecondaryWindow = GHOST_CreateWindow(shSystem, + title2, + 340, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sSecondaryWindow) + { + printf("could not create secondary window\n"); + exit(-1); + } + + /* Install a timer to have the gears running */ + sGearsTimer = GHOST_InstallTimer(shSystem, + 0, + 10, + gearsTimerProc, + sMainWindow); + + /* Enter main loop */ + while (!sExitRequested) + { + if (!GHOST_ProcessEvents(shSystem, 0)) + { +#ifdef WIN32 + /* If there were no events, be nice to other applications */ + Sleep(10); +#endif + } + GHOST_DispatchEvents(shSystem); + } + } + + /* Dispose windows */ + if (GHOST_ValidWindow(shSystem, sMainWindow)) + { + GHOST_DisposeWindow(shSystem, sMainWindow); + } + if (GHOST_ValidWindow(shSystem, sSecondaryWindow)) + { + GHOST_DisposeWindow(shSystem, sSecondaryWindow); + } + + /* Dispose the system */ + GHOST_DisposeSystem(shSystem); + GHOST_DisposeEventConsumer(consumer); + + return 0; +} + + +static void gearsTimerProc(GHOST_TimerTaskHandle hTask, GHOST_TUns64 time) +{ + GHOST_WindowHandle hWindow = NULL; + fAngle += 2.0; + view_roty += 1.0; + hWindow = (GHOST_WindowHandle)GHOST_GetTimerTaskUserData(hTask); + if (GHOST_GetFullScreen(shSystem)) + { + /* Running full screen */ + GHOST_InvalidateWindow(sFullScreenWindow); + } + else + { + if (GHOST_ValidWindow(shSystem, hWindow)) + { + GHOST_InvalidateWindow(hWindow); + } + } +} diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp new file mode 100644 index 00000000000..6e269e1cede --- /dev/null +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -0,0 +1,754 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + * Stereo code by Raymond de Vries, januari 2002 + */ + +#include +#include + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + +#include "STR_String.h" +#include "GHOST_Rect.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" + + +#define LEFT_EYE 0 +#define RIGHT_EYE 1 + +static bool nVidiaWindows; // very dirty but hey, it's for testing only + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); + +static class Application* fApp; +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static GHOST_ISystem* fSystem = 0; + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye); + + +static void testTimerProc(GHOST_ITimerTask* /*task*/, GHOST_TUns64 time) +{ + std::cout << "timer1, time=" << (int)time << "\n"; +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth/2.0; + r2 = outer_radius + tooth_depth/2.0; + + const double pi = 3.14159264; + da = 2.0*pi / teeth / 4.0; + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5); + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.0*pi / teeth / 4.0; + for (i=0;iactivateDrawingContext(); + GHOST_Rect bnds; + int noOfScanlines = 0, lowerScanline = 0; + int verticalBlankingInterval = 32; // hard coded for testing purposes, display device dependant + float left, right, bottom, top; + float nearplane, farplane, zeroPlane, distance; + float eyeSeparation = 0.62f; + window->getClientBounds(bnds); + + // viewport + if(stereo) + { + if(nVidiaWindows) + { + // handled by nVidia driver so act as normal (explicitly put here since + // it -is- stereo) + glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); + } + else + { // generic cross platform above-below stereo + noOfScanlines = (bnds.getHeight() - verticalBlankingInterval) / 2; + switch(eye) + { + case LEFT_EYE: + // upper half of window + lowerScanline = bnds.getHeight() - noOfScanlines; + break; + case RIGHT_EYE: + // lower half of window + lowerScanline = 0; + break; + } + } + } + else + { + noOfScanlines = bnds.getHeight(); + lowerScanline = 0; + } + + glViewport(0, lowerScanline, bnds.getWidth(), noOfScanlines); + + // projection + left = -6.0; + right = 6.0; + bottom = -4.8f; + top = 4.8f; + nearplane = 5.0; + farplane = 60.0; + + if(stereo) + { + zeroPlane = 0.0; + distance = 14.5; + switch(eye) + { + case LEFT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, -eyeSeparation / 2.0); + break; + case RIGHT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, eyeSeparation / 2.0); + break; + } + } + else + { +// left = -w; +// right = w; +// bottom = -h; +// top = h; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(left, right, bottom, top, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); + + } + + glClearColor(.2f,0.0f,0.0f,0.0f); +} + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye) +/* Perform the perspective projection for one eye's subfield. +The projection is in the direction of the negative z axis. + +-6.0, 6.0, -4.8, 4.8, +left, right, bottom, top = the coordinate range, in the plane of zero +parallax setting, which will be displayed on the screen. The +ratio between (right-left) and (top-bottom) should equal the aspect +ratio of the display. + +6.0, -6.0, +near, far = the z-coordinate values of the clipping planes. + +0.0, +zero_plane = the z-coordinate of the plane of zero parallax setting. + +14.5, +dist = the distance from the center of projection to the plane +of zero parallax. + +-0.31 +eye = half the eye separation; positive for the right eye subfield, +negative for the left eye subfield. +*/ +{ + float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw, + dx, dy, n_over_d; + + dx = right - left; + dy = top - bottom; + + xmid = (right + left) / 2.0; + ymid = (top + bottom) / 2.0; + + clip_near = dist + zero_plane - nearplane; + clip_far = dist + zero_plane - farplane; + + n_over_d = clip_near / dist; + + topw = n_over_d * dy / 2.0; + bottomw = -topw; + rightw = n_over_d * (dx / 2.0 - eye); + leftw = n_over_d *(-dx / 2.0 - eye); + + /* Need to be in projection mode for this. */ + glLoadIdentity(); + glFrustum(leftw, rightw, bottomw, topw, clip_near, clip_far); + + glTranslatef(-xmid - eye, -ymid, -zero_plane - dist); + return; +} /* stereoproj */ + + +class Application : public GHOST_IEventConsumer { +public: + Application(GHOST_ISystem* system); + ~Application(void); + virtual bool processEvent(GHOST_IEvent* event); + + GHOST_ISystem* m_system; + GHOST_IWindow* m_mainWindow; + GHOST_IWindow* m_secondaryWindow; + GHOST_IWindow* m_fullScreenWindow; + GHOST_ITimerTask* m_gearsTimer, *m_testTimer; + GHOST_TStandardCursor m_cursor; + bool m_exitRequested; + + bool stereo; +}; + + +Application::Application(GHOST_ISystem* system) + : m_system(system), m_mainWindow(0), m_secondaryWindow(0), m_fullScreenWindow(0), + m_gearsTimer(0), m_testTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor), + m_exitRequested(false), stereo(false) +{ + fApp = this; + + // Create the main window + STR_String title1 ("gears - main window"); + m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, true /* stereo flag */); + + if (!m_mainWindow) { + std::cout << "could not create main window\n"; + exit(-1); + } + + // Create a secondary window + STR_String title2 ("gears - secondary window"); + m_secondaryWindow = system->createWindow(title2, 340, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, false /* stereo flag */); + if (!m_secondaryWindow) { + cout << "could not create secondary window\n"; + exit(-1); + } + + // Install a timer to have the gears running + m_gearsTimer = system->installTimer(0 /*delay*/, 20/*interval*/, gearsTimerProc, m_mainWindow); +} + + +Application::~Application(void) +{ + // Dispose windows + if (m_system->validWindow(m_mainWindow)) { + m_system->disposeWindow(m_mainWindow); + } + if (m_system->validWindow(m_secondaryWindow)) { + m_system->disposeWindow(m_secondaryWindow); + } +} + + +bool Application::processEvent(GHOST_IEvent* event) +{ + GHOST_IWindow* window = event->getWindow(); + bool handled = true; + + switch (event->getType()) { +/* case GHOST_kEventUnknown: + break; + case GHOST_kEventCursorButton: + std::cout << "GHOST_kEventCursorButton"; break; + case GHOST_kEventCursorMove: + std::cout << "GHOST_kEventCursorMove"; break; +*/ + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) event->getData(); + if (wheelData->z > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*) event->getData(); + switch (keyData->key) { + case GHOST_kKeyC: + { + int cursor = m_cursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) { + cursor = GHOST_kStandardCursorFirstCursor; + } + m_cursor = (GHOST_TStandardCursor)cursor; + window->setCursorShape(m_cursor); + } + break; + + case GHOST_kKeyE: + { + int x = 200, y= 200; + m_system->setCursorPosition(x,y); + break; + } + + case GHOST_kKeyF: + if (!m_system->getFullScreen()) { + // Begin fullscreen mode + GHOST_DisplaySetting setting; + + setting.bpp = 16; + setting.frequency = 50; + setting.xPixels = 640; + setting.yPixels = 480; + m_system->beginFullScreen(setting, &m_fullScreenWindow, false /* stereo flag */); + } + else { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + break; + + case GHOST_kKeyH: + window->setCursorVisibility(!window->getCursorVisibility()); + break; + + case GHOST_kKeyM: + { + bool down = false; + m_system->getModifierKeyState(GHOST_kModifierKeyLeftShift,down); + if (down) { + std::cout << "left shift down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightShift,down); + if (down) { + std::cout << "right shift down\n"; } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftAlt,down); + if (down) { + std::cout << "left Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightAlt,down); + if (down) { + std::cout << "right Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftControl,down); + if (down) { + std::cout << "left control down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightControl,down); + if (down) { + std::cout << "right control down\n"; + } + } + break; + + case GHOST_kKeyQ: + if (m_system->getFullScreen()) + { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + m_exitRequested = true; + break; + + case GHOST_kKeyS: // toggle mono and stereo + if(stereo) + stereo = false; + else + stereo = true; + break; + + case GHOST_kKeyT: + if (!m_testTimer) { + m_testTimer = m_system->installTimer(0, 1000, testTimerProc); + } + + else { + m_system->removeTimer(m_testTimer); + m_testTimer = 0; + } + + break; + + case GHOST_kKeyW: + if (m_mainWindow) + { + STR_String title; + m_mainWindow->getTitle(title); + title += "-"; + m_mainWindow->setTitle(title); + + } + break; + + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_IWindow* window2 = event->getWindow(); + if (window2 == m_mainWindow) { + m_exitRequested = true; + } + else { + m_system->disposeWindow(window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = false; + break; + + case GHOST_kEventWindowDeactivate: + handled = false; + break; + + case GHOST_kEventWindowUpdate: + { + GHOST_IWindow* window2 = event->getWindow(); + if(!m_system->validWindow(window2)) + break; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if(stereo) + { + View(window2, stereo, LEFT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + + View(window2, stereo, RIGHT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + else + { + View(window2, stereo); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + window2->swapBuffers(); + } + break; + + default: + handled = false; + break; + } + return handled; +} + + +int main(int /*argc*/, char** /*argv*/) +{ + nVidiaWindows = false; +// nVidiaWindows = true; + +#ifdef WIN32 + /* Set a couple of settings in the registry for the nVidia detonator driver. + * So this is very specific... + */ + if(nVidiaWindows) + { + LONG lresult; + HKEY hkey = 0; + DWORD dwd = 0; + //unsigned char buffer[128]; + + CRegKey regkey; + //DWORD keyValue; +// lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable"); + lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + KEY_ALL_ACCESS ); + + if(lresult == ERROR_SUCCESS) + printf("Succesfully opened key\n"); +#if 0 + lresult = regkey.QueryValue(&keyValue, "StereoEnable"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully queried key\n"); +#endif + lresult = regkey.SetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + "1"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully set value for key\n"); + regkey.Close(); + if(lresult == ERROR_SUCCESS) + printf("Succesfully closed key\n"); +// regkey.Write("2"); + } +#endif // WIN32 + + // Create the system + GHOST_ISystem::createSystem(); + fSystem = GHOST_ISystem::getSystem(); + + if (fSystem) { + // Create an application object + Application app (fSystem); + + // Add the application as event consumer + fSystem->addEventConsumer(&app); + + // Enter main loop + while (!app.m_exitRequested) { + //printf("main: loop\n"); + fSystem->processEvents(true); + fSystem->dispatchEvents(); + } + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + + return 0; +} + + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 /*time*/) +{ + fAngle += 2.0; + view_roty += 1.0; + GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData(); + if (fApp->m_fullScreenWindow) { + // Running full screen + fApp->m_fullScreenWindow->invalidate(); + } + else { + if (fSystem->validWindow(window)) { + window->invalidate(); + } + } +} diff --git a/intern/ghost/test/multitest/Basic.c b/intern/ghost/test/multitest/Basic.c new file mode 100644 index 00000000000..1510c47f28a --- /dev/null +++ b/intern/ghost/test/multitest/Basic.c @@ -0,0 +1,64 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "Basic.h" + +int min_i(int a, int b) { + return (a + +#include + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "EventToBuf.h" + +char *eventtype_to_string(GHOST_TEventType type) { + switch(type) { + case GHOST_kEventCursorMove: return "CursorMove"; + case GHOST_kEventButtonDown: return "ButtonDown"; + case GHOST_kEventButtonUp: return "ButtonUp"; + + case GHOST_kEventKeyDown: return "KeyDown"; + case GHOST_kEventKeyUp: return "KeyUp"; + + case GHOST_kEventQuit: return "Quit"; + + case GHOST_kEventWindowClose: return "WindowClose"; + case GHOST_kEventWindowActivate: return "WindowActivate"; + case GHOST_kEventWindowDeactivate: return "WindowDeactivate"; + case GHOST_kEventWindowUpdate: return "WindowUpdate"; + case GHOST_kEventWindowSize: return "WindowSize"; + default: + return ""; + } +} + +static char *keytype_to_string(GHOST_TKey key) { +#define K(key) case GHOST_k##key: return #key; + switch (key) { + K(KeyBackSpace); + K(KeyTab); + K(KeyLinefeed); + K(KeyClear); + K(KeyEnter); + + K(KeyEsc); + K(KeySpace); + K(KeyQuote); + K(KeyComma); + K(KeyMinus); + K(KeyPeriod); + K(KeySlash); + + K(Key0); + K(Key1); + K(Key2); + K(Key3); + K(Key4); + K(Key5); + K(Key6); + K(Key7); + K(Key8); + K(Key9); + + K(KeySemicolon); + K(KeyEqual); + + K(KeyA); + K(KeyB); + K(KeyC); + K(KeyD); + K(KeyE); + K(KeyF); + K(KeyG); + K(KeyH); + K(KeyI); + K(KeyJ); + K(KeyK); + K(KeyL); + K(KeyM); + K(KeyN); + K(KeyO); + K(KeyP); + K(KeyQ); + K(KeyR); + K(KeyS); + K(KeyT); + K(KeyU); + K(KeyV); + K(KeyW); + K(KeyX); + K(KeyY); + K(KeyZ); + + K(KeyLeftBracket); + K(KeyRightBracket); + K(KeyBackslash); + K(KeyAccentGrave); + + K(KeyLeftShift); + K(KeyRightShift); + K(KeyLeftControl); + K(KeyRightControl); + K(KeyLeftAlt); + K(KeyRightAlt); + K(KeyOS); + + K(KeyCapsLock); + K(KeyNumLock); + K(KeyScrollLock); + + K(KeyLeftArrow); + K(KeyRightArrow); + K(KeyUpArrow); + K(KeyDownArrow); + + K(KeyPrintScreen); + K(KeyPause); + + K(KeyInsert); + K(KeyDelete); + K(KeyHome); + K(KeyEnd); + K(KeyUpPage); + K(KeyDownPage); + + K(KeyNumpad0); + K(KeyNumpad1); + K(KeyNumpad2); + K(KeyNumpad3); + K(KeyNumpad4); + K(KeyNumpad5); + K(KeyNumpad6); + K(KeyNumpad7); + K(KeyNumpad8); + K(KeyNumpad9); + K(KeyNumpadPeriod); + K(KeyNumpadEnter); + K(KeyNumpadPlus); + K(KeyNumpadMinus); + K(KeyNumpadAsterisk); + K(KeyNumpadSlash); + + K(KeyF1); + K(KeyF2); + K(KeyF3); + K(KeyF4); + K(KeyF5); + K(KeyF6); + K(KeyF7); + K(KeyF8); + K(KeyF9); + K(KeyF10); + K(KeyF11); + K(KeyF12); + K(KeyF13); + K(KeyF14); + K(KeyF15); + K(KeyF16); + K(KeyF17); + K(KeyF18); + K(KeyF19); + K(KeyF20); + K(KeyF21); + K(KeyF22); + K(KeyF23); + K(KeyF24); + + default: + return "KeyUnknown"; + } +#undef K +} + +void event_to_buf(GHOST_EventHandle evt, char buf[128]) { + GHOST_TEventType type= GHOST_GetEventType(evt); + double time= (double) ((GHOST_TInt64) GHOST_GetEventTime(evt))/1000; + GHOST_WindowHandle win= GHOST_GetEventWindow(evt); + void *data= GHOST_GetEventData(evt); + char *pos= buf; + + pos+= sprintf(pos, "event: %6.2f, %16s", time, eventtype_to_string(type)); + if (win) { + char *s= GHOST_GetTitle(win); + pos+= sprintf(pos, " - win: %s", s); + free(s); + } else { + pos+= sprintf(pos, " - sys evt"); + } + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= data; + pos+= sprintf(pos, " - pos: (%d, %d)", cd->x, cd->y); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= data; + pos+= sprintf(pos, " - but: %d", bd->button); + break; + } + + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= data; + pos+= sprintf(pos, " - key: %s (%d)", keytype_to_string(kd->key), kd->key); + if (kd->ascii) pos+= sprintf(pos, " ascii: '%c' (%d)", kd->ascii, kd->ascii); + break; + } + } +} diff --git a/intern/ghost/test/multitest/EventToBuf.h b/intern/ghost/test/multitest/EventToBuf.h new file mode 100644 index 00000000000..12dcb23f993 --- /dev/null +++ b/intern/ghost/test/multitest/EventToBuf.h @@ -0,0 +1,31 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +char *eventtype_to_string(GHOST_TEventType type); +void event_to_buf(GHOST_EventHandle evt, char buf[128]); + diff --git a/intern/ghost/test/multitest/GL.h b/intern/ghost/test/multitest/GL.h new file mode 100644 index 00000000000..1a0b322a136 --- /dev/null +++ b/intern/ghost/test/multitest/GL.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#if defined(WIN32) || defined(__APPLE__) + + #ifdef WIN32 + #include + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c new file mode 100644 index 00000000000..848601b2cc7 --- /dev/null +++ b/intern/ghost/test/multitest/MultiTest.c @@ -0,0 +1,859 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#define FALSE 0 + +#ifdef WIN32 + +#pragma warning(disable: 4244 4305) +#endif + +#include +#include +#include +#include + +#include "GL.h" + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "BMF_Api.h" + +#include "Util.h" +#include "Basic.h" +#include "ScrollBar.h" +#include "EventToBuf.h" + +#include "WindowData.h" + +/***/ + +typedef struct _MultiTestApp MultiTestApp; +typedef struct _LoggerWindow LoggerWindow; + +void loggerwindow_log(LoggerWindow *lw, char *line); + +void multitestapp_toggle_extra_window(MultiTestApp *app); +void multitestapp_free_extrawindow(MultiTestApp *app); +LoggerWindow *multitestapp_get_logger(MultiTestApp *app); +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app); +void multitestapp_exit(MultiTestApp *app); + +/**/ + +void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, float *col, int width) { + int ltidx= (side/2)%4; + int dkidx= (ltidx + 1 + (side&1))%4; + int i, corner; + + glBegin(GL_LINES); + for (i=0; iltidx)?dkf:ltf; + int lx= rect[1][0]-i-1; + int ly= rect[0][1]+i; + + glColor3f(col[0]*stf, col[1]*stf, col[2]*stf); + for (corner=0; corner<4; corner++) { + int x= (corner==0 || corner==1)?(rect[0][0]+i):(rect[1][0]-i-1); + int y= (corner==0 || corner==3)?(rect[0][1]+i):(rect[1][1]-i-1); + + if (ltidx==corner) + glColor3f(col[0]*ltf, col[1]*ltf, col[2]*ltf); + if (dkidx==corner) + glColor3f(col[0]*dkf, col[1]*dkf, col[2]*dkf); + + glVertex2i(lx, ly); + glVertex2i(lx= x, ly= y); + } + } + glEnd(); + + glColor3fv(col); + glRecti(rect[0][0]+width, rect[0][1]+width, rect[1][0]-width, rect[1][1]-width); +} + +void rect_bevel_smooth(int rect[2][2], int width) { + float *lt= malloc(sizeof(*lt)*width); + float *dk= malloc(sizeof(*dk)*width); + float col[4]; + int i; + + for (i=0; iapp), str); +} + +static void mainwindow_do_draw(MainWindow *mw) { + GHOST_ActivateWindowDrawingContext(mw->win); + + if (mw->lmbut[0]) { + glClearColor(0.5, 0.5, 0.5, 1); + } else { + glClearColor(1, 1, 1, 1); + } + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.5, 0.6, 0.8); + glRecti(mw->tmouse[0]-5, mw->tmouse[1]-5, mw->tmouse[0]+5, mw->tmouse[1]+5); + + GHOST_SwapWindowBuffers(mw->win); +} + +static void mainwindow_do_reshape(MainWindow *mw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(mw->win); + + GHOST_ActivateWindowDrawingContext(mw->win); + + mw->size[0]= GHOST_GetWidthRectangle(bounds); + mw->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, mw->size[0], mw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, mw->size[0], 0, mw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press) { + switch(key) { + case GHOST_kKeyC: + if (press) + GHOST_SetCursorShape(mw->win, (GHOST_TStandardCursor) (rand()%(GHOST_kStandardCursorNumCursors))); + break; + case GHOST_kKeyLeftBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 0); + break; + case GHOST_kKeyRightBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 1); + break; + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(mw->app); + break; + case GHOST_kKeyQ: + if (press) + multitestapp_exit(mw->app); + break; + case GHOST_kKeyT: + if (press) + mainwindow_log(mw, "TextTest~|`hello`\"world\",<>/"); + break; + case GHOST_kKeyR: + if (press) { + int i; + + mainwindow_log(mw, "Invalidating window 10 times"); + for (i=0; i<10; i++) + GHOST_InvalidateWindow(mw->win); + } + break; + case GHOST_kKeyF11: + if (press) { + GHOST_SetWindowOrder(mw->win, GHOST_kWindowOrderBottom); + } + break; + } +} + +static void mainwindow_do_move(MainWindow *mw, int x, int y) { + mw->lmouse[0]= x, mw->lmouse[1]= y; + + if (mw->lmbut[0]) { + mw->tmouse[0]= x, mw->tmouse[1]= y; + GHOST_InvalidateWindow(mw->win); + } +} + +static void mainwindow_do_button(MainWindow *mw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[0]= press; + mw->tmouse[0]= mw->lmouse[0], mw->tmouse[1]= mw->lmouse[1]; + GHOST_InvalidateWindow(mw->win); + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[2]= press; + } +} + +static void mainwindow_handle(void *priv, GHOST_EventHandle evt) { + MainWindow *mw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + mainwindow_log(mw, buf); + + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y); + mainwindow_do_move(mw, x, mw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + mainwindow_do_draw(mw); + break; + case GHOST_kEventWindowSize: + mainwindow_do_reshape(mw); + break; + } +} + +/**/ + +static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) { + MainWindow *mw= GHOST_GetTimerTaskUserData(task); + char buf[64]; + + sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time)/1000); + mainwindow_log(mw, buf); +} + +MainWindow *mainwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + MainWindow *mw= MEM_callocN(sizeof(*mw), "mainwindow_new"); + mw->app= app; + mw->win= win; + + GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle)); + + GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw); + + return mw; + } else { + return NULL; + } +} + +void mainwindow_free(MainWindow *mw) { + GHOST_SystemHandle sys= multitestapp_get_system(mw->app); + + windowdata_free(GHOST_GetWindowUserData(mw->win)); + GHOST_DisposeWindow(sys, mw->win); + MEM_freeN(mw); +} + + /* + * LoggerWindow + */ + +struct _LoggerWindow { + MultiTestApp *app; + + GHOST_WindowHandle win; + + BMF_Font *font; + int fonttexid; + int fontheight; + + int size[2]; + + int ndisplines; + int textarea[2][2]; + ScrollBar *scroll; + + char **loglines; + int nloglines, logsize; + + int lmbut[3]; + int lmouse[2]; +}; + +#define SCROLLBAR_PAD 2 +#define SCROLLBAR_WIDTH 14 +#define TEXTAREA_PAD 2 +static void loggerwindow_recalc_regions(LoggerWindow *lw) { + int nscroll[2][2]; + + nscroll[0][0]= SCROLLBAR_PAD; + nscroll[0][1]= SCROLLBAR_PAD; + nscroll[1][0]= nscroll[0][0] + SCROLLBAR_WIDTH; + nscroll[1][1]= lw->size[1] - SCROLLBAR_PAD - 1; + + lw->textarea[0][0]= nscroll[1][0] + TEXTAREA_PAD; + lw->textarea[0][1]= TEXTAREA_PAD; + lw->textarea[1][0]= lw->size[0] - TEXTAREA_PAD - 1; + lw->textarea[1][1]= lw->size[1] - TEXTAREA_PAD - 1; + + lw->ndisplines= (lw->textarea[1][1]-lw->textarea[0][1])/lw->fontheight; + + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + scrollbar_set_rect(lw->scroll, nscroll); +} + +static void loggerwindow_setup_window_gl(LoggerWindow *lw) { + glViewport(0, 0, lw->size[0], lw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void loggerwindow_do_reshape(LoggerWindow *lw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(lw->win); + + GHOST_ActivateWindowDrawingContext(lw->win); + + lw->size[0]= GHOST_GetWidthRectangle(bounds); + lw->size[1]= GHOST_GetHeightRectangle(bounds); + + loggerwindow_recalc_regions(lw); + loggerwindow_setup_window_gl(lw); +} + +static void loggerwindow_do_draw(LoggerWindow *lw) { + int i, ndisplines, startline; + int sb_rect[2][2], sb_thumb[2][2]; + + GHOST_ActivateWindowDrawingContext(lw->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + rect_bevel_smooth(lw->textarea, 4); + + scrollbar_get_rect(lw->scroll, sb_rect); + scrollbar_get_thumb(lw->scroll, sb_thumb); + + glColor3f(0.6, 0.6, 0.6); + rect_bevel_smooth(sb_rect, 1); + + if (scrollbar_is_scrolling(lw->scroll)) { + glColor3f(0.6, 0.7, 0.5); + } else { + glColor3f(0.9, 0.9, 0.92); + } + rect_bevel_smooth(sb_thumb, 1); + + startline= scrollbar_get_thumbpos(lw->scroll)*(lw->nloglines-1); + ndisplines= min_i(lw->ndisplines, lw->nloglines-startline); + + if (lw->fonttexid!=-1) { + glBindTexture(GL_TEXTURE_2D, lw->fonttexid); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + } + glColor3f(0, 0, 0); + for (i=0; iloglines[(lw->nloglines-1)-(i+startline)]; + int x_pos= lw->textarea[0][0] + 4; + int y_pos= lw->textarea[0][1] + 4 + i*lw->fontheight; + + if (lw->fonttexid==-1) { + glRasterPos2i(x_pos, y_pos); + BMF_DrawString(lw->font, line); + } else { + BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0); + } + } + if (lw->fonttexid!=-1) { + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + } + + GHOST_SwapWindowBuffers(lw->win); +} + +static void loggerwindow_do_move(LoggerWindow *lw, int x, int y) { + lw->lmouse[0]= x, lw->lmouse[1]= y; + + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_keep_scrolling(lw->scroll, y); + GHOST_InvalidateWindow(lw->win); + } +} + +static void loggerwindow_do_button(LoggerWindow *lw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + lw->lmbut[0]= press; + + if (press) { + if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) { + scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown); + GHOST_InvalidateWindow(lw->win); + } + } else { + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_stop_scrolling(lw->scroll); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault); + GHOST_InvalidateWindow(lw->win); + } + } + } else if (which==GHOST_kButtonMaskMiddle) { + lw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskRight) { + lw->lmbut[2]= press; + } +} + +static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyQ: + if (press) + multitestapp_exit(lw->app); + break; + } +} + +static void loggerwindow_handle(void *priv, GHOST_EventHandle evt) { + LoggerWindow *lw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + + switch(type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y); + loggerwindow_do_move(lw, x, lw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + loggerwindow_do_draw(lw); + break; + case GHOST_kEventWindowSize: + loggerwindow_do_reshape(lw); + break; + } +} + +/**/ + +LoggerWindow *loggerwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_TUns32 screensize[2]; + GHOST_WindowHandle win; + + GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]); + win= GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1]-432, + 800, 300, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, FALSE); + + if (win) { + LoggerWindow *lw= MEM_callocN(sizeof(*lw), "loggerwindow_new"); + int bbox[2][2]; + lw->app= app; + lw->win= win; + + lw->font= BMF_GetFont(BMF_kScreen12); + lw->fonttexid= BMF_GetFontTexture(lw->font); + + BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]); + lw->fontheight= rect_height(bbox); + + lw->nloglines= lw->logsize= 0; + lw->loglines= MEM_mallocN(sizeof(*lw->loglines)*lw->nloglines, "loglines"); + + lw->scroll= scrollbar_new(2, 40); + + GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle)); + + loggerwindow_do_reshape(lw); + + return lw; + } else { + return NULL; + } +} + +void loggerwindow_log(LoggerWindow *lw, char *line) { + if (lw->nloglines==lw->logsize) { + lw->loglines= memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines)); + } + + lw->loglines[lw->nloglines++]= string_dup(line); + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + + GHOST_InvalidateWindow(lw->win); +} + +void loggerwindow_free(LoggerWindow *lw) { + GHOST_SystemHandle sys= multitestapp_get_system(lw->app); + int i; + + for (i=0; inloglines; i++) { + MEM_freeN(lw->loglines[i]); + } + MEM_freeN(lw->loglines); + + windowdata_free(GHOST_GetWindowUserData(lw->win)); + GHOST_DisposeWindow(sys, lw->win); + MEM_freeN(lw); +} + + /* + * ExtraWindow + */ + + +typedef struct { + MultiTestApp *app; + + GHOST_WindowHandle win; + + int size[2]; +} ExtraWindow; + +static void extrawindow_do_draw(ExtraWindow *ew) { + GHOST_ActivateWindowDrawingContext(ew->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + glRecti(10, 10, ew->size[0]-10, ew->size[1]-10); + + GHOST_SwapWindowBuffers(ew->win); +} + +static void extrawindow_do_reshape(ExtraWindow *ew) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(ew->win); + + GHOST_ActivateWindowDrawingContext(ew->win); + + ew->size[0]= GHOST_GetWidthRectangle(bounds); + ew->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, ew->size[0], ew->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(ew->app); + break; + } +} + +static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) { + GHOST_TUns8 bitmap[16][2]; + GHOST_TUns8 mask[16][2]; + double ftime= (double) ((GHOST_TInt64) time)/1000; + float angle= fmod(ftime, 1.0) * 3.1415*2; + int i; + + memset(&bitmap, 0, sizeof(bitmap)); + memset(&mask, 0, sizeof(mask)); + + bitmap[0][0] |= mask[0][0] |= 0xF; + bitmap[1][0] |= mask[1][0] |= 0xF; + bitmap[2][0] |= mask[2][0] |= 0xF; + bitmap[3][0] |= mask[3][0] |= 0xF; + + for (i=0; i<7; i++) { + int x = 7 + cos(angle)*i; + int y = 7 + sin(angle)*i; + + mask[y][x/8] |= (1 << (x%8)); + } + for (i=0; i<64; i++) { + float v= (i/63.0) * 3.1415*2; + int x = 7 + cos(v)*7; + int y = 7 + sin(v)*7; + + mask[y][x/8] |= (1 << (x%8)); + } + + GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0); +} + +static void extrawindow_handle(void *priv, GHOST_EventHandle evt) { + ExtraWindow *ew= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + loggerwindow_log(multitestapp_get_logger(ew->app), buf); + + switch (type) { + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventCursorMove: { + extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt)); + break; + } + + case GHOST_kEventWindowClose: + multitestapp_free_extrawindow(ew->app); + break; + case GHOST_kEventWindowUpdate: + extrawindow_do_draw(ew); + break; + case GHOST_kEventWindowSize: + extrawindow_do_reshape(ew); + break; + } +} + +/**/ + +ExtraWindow *extrawindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + ExtraWindow *ew= MEM_callocN(sizeof(*ew), "mainwindow_new"); + ew->app= app; + ew->win= win; + + GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle)); + + return ew; + } else { + return NULL; + } +} + +void extrawindow_free(ExtraWindow *ew) { + GHOST_SystemHandle sys= multitestapp_get_system(ew->app); + + windowdata_free(GHOST_GetWindowUserData(ew->win)); + GHOST_DisposeWindow(sys, ew->win); + MEM_freeN(ew); +} + + /* + * MultiTestApp + */ + +struct _MultiTestApp { + GHOST_SystemHandle sys; + MainWindow *main; + LoggerWindow *logger; + ExtraWindow *extra; + + int exit; +}; + +static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data) { + MultiTestApp *app= data; + GHOST_WindowHandle win; + + win= GHOST_GetEventWindow(evt); + if (win && !GHOST_ValidWindow(app->sys, win)) { + loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n"); + return 1; + } + + if (win) { + WindowData *wb= GHOST_GetWindowUserData(win); + + windowdata_handle(wb, evt); + } else { + GHOST_TEventType type= GHOST_GetEventType(evt); + + /* GHOST_kEventQuit are the only 'system' events, + * that is, events without a window. + */ + switch(type) { + case GHOST_kEventQuit: + app->exit= 1; + break; + + default: + fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type)); + break; + } + } + + return 1; +} + +/**/ + +MultiTestApp *multitestapp_new(void) { + MultiTestApp *app= MEM_mallocN(sizeof(*app), "multitestapp_new"); + GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(multitest_event_handler, app); + + app->sys= GHOST_CreateSystem(); + if (!app->sys) + fatal("Unable to create ghost system"); + + if (!GHOST_AddEventConsumer(app->sys, consumer)) + fatal("Unable to add multitest event consumer "); + + app->main= mainwindow_new(app); + if (!app->main) + fatal("Unable to create main window"); + + app->logger= loggerwindow_new(app); + if (!app->logger) + fatal("Unable to create logger window"); + + app->extra= NULL; + app->exit= 0; + + return app; +} + +LoggerWindow *multitestapp_get_logger(MultiTestApp *app) { + return app->logger; +} + +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) { + return app->sys; +} + +void multitestapp_free_extrawindow(MultiTestApp *app) { + extrawindow_free(app->extra); + app->extra= NULL; +} + +void multitestapp_toggle_extra_window(MultiTestApp *app) { + if (app->extra) { + multitestapp_free_extrawindow(app); + } else { + app->extra= extrawindow_new(app); + } +} + +void multitestapp_exit(MultiTestApp *app) { + app->exit= 1; +} + +void multitestapp_run(MultiTestApp *app) { + while (!app->exit) { + GHOST_ProcessEvents(app->sys, 1); + GHOST_DispatchEvents(app->sys); + } +} + +void multitestapp_free(MultiTestApp *app) { + mainwindow_free(app->main); + loggerwindow_free(app->logger); + GHOST_DisposeSystem(app->sys); + MEM_freeN(app); +} + + /***/ + +int main(int argc, char **argv) { + MultiTestApp *app= multitestapp_new(); + + multitestapp_run(app); + multitestapp_free(app); + + return 0; +} diff --git a/intern/ghost/test/multitest/ScrollBar.c b/intern/ghost/test/multitest/ScrollBar.c new file mode 100644 index 00000000000..7574a5c85f1 --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.c @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include + +#include "MEM_guardedalloc.h" + +#include "Basic.h" +#include "ScrollBar.h" + +struct _ScrollBar { + int rect[2][2]; + float thumbpos, thumbpct; + + int inset; + int minthumb; + + int scrolling; + float scrolloffs; +}; + +static int scrollbar_get_thumbH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + + return clamp_i(sb->thumbpct*scrollable_h, sb->minthumb, scrollable_h); +} +static int scrollbar_get_thumbableH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + int thumb_h= scrollbar_get_thumbH(sb); + + return scrollable_h - thumb_h; +} + +static float scrollbar_co_to_pos(ScrollBar *sb, int yco) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + int thumbable_y= (sb->rect[0][1]+sb->inset) + thumb_h/2; + + return (float) (yco-thumbable_y)/thumbable_h; +} + +/**/ + +ScrollBar *scrollbar_new(int inset, int minthumb) { + ScrollBar *sb= MEM_callocN(sizeof(*sb), "scrollbar_new"); + sb->inset= inset; + sb->minthumb= minthumb; + + return sb; +} + +void scrollbar_get_thumb(ScrollBar *sb, int thumb_r[2][2]) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + + thumb_r[0][0]= sb->rect[0][0]+sb->inset; + thumb_r[1][0]= sb->rect[1][0]-sb->inset; + + thumb_r[0][1]= sb->rect[0][1]+sb->inset + sb->thumbpos*thumbable_h; + thumb_r[1][1]= thumb_r[0][1] + thumb_h; +} + +int scrollbar_is_scrolling(ScrollBar *sb) { + return sb->scrolling; +} +int scrollbar_contains_pt(ScrollBar *sb, int pt[2]) { + return rect_contains_pt(sb->rect, pt); +} + +void scrollbar_start_scrolling(ScrollBar *sb, int yco) { + int thumb_h_2= scrollbar_get_thumbH(sb)/2; + int thumbable_h= scrollbar_get_thumbableH(sb); + float npos= scrollbar_co_to_pos(sb, yco); + + sb->scrolloffs= sb->thumbpos - npos; + if (fabs(sb->scrolloffs) >= (float) thumb_h_2/thumbable_h) { + sb->scrolloffs= 0.0; + } + + sb->scrolling= 1; + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_keep_scrolling(ScrollBar *sb, int yco) { + float npos= scrollbar_co_to_pos(sb, yco); + + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_stop_scrolling(ScrollBar *sb) { + sb->scrolling= 0; + sb->scrolloffs= 0.0; +} + +void scrollbar_set_thumbpct(ScrollBar *sb, float pct) { + sb->thumbpct= pct; +} +void scrollbar_set_thumbpos(ScrollBar *sb, float pos) { + sb->thumbpos= clamp_f(pos, 0.0, 1.0); +} +void scrollbar_set_rect(ScrollBar *sb, int rect[2][2]) { + rect_copy(sb->rect, rect); +} + +float scrollbar_get_thumbpct(ScrollBar *sb) { + return sb->thumbpct; +} +float scrollbar_get_thumbpos(ScrollBar *sb) { + return sb->thumbpos; +} +void scrollbar_get_rect(ScrollBar *sb, int rect_r[2][2]) { + rect_copy(rect_r, sb->rect); +} + +void scrollbar_free(ScrollBar *sb) { + MEM_freeN(sb); +} diff --git a/intern/ghost/test/multitest/ScrollBar.h b/intern/ghost/test/multitest/ScrollBar.h new file mode 100644 index 00000000000..a0a850f69aa --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +typedef struct _ScrollBar ScrollBar; + + + /***/ + +ScrollBar* scrollbar_new (int inset, int minthumb); + +int scrollbar_is_scrolling (ScrollBar *sb); +int scrollbar_contains_pt (ScrollBar *sb, int pt[2]); + +void scrollbar_start_scrolling (ScrollBar *sb, int yco); +void scrollbar_keep_scrolling (ScrollBar *sb, int yco); +void scrollbar_stop_scrolling (ScrollBar *sb); + +void scrollbar_set_thumbpct (ScrollBar *sb, float pct); +void scrollbar_set_thumbpos (ScrollBar *sb, float pos); +void scrollbar_set_rect (ScrollBar *sb, int rect[2][2]); + +float scrollbar_get_thumbpct (ScrollBar *sb); +float scrollbar_get_thumbpos (ScrollBar *sb); +void scrollbar_get_rect (ScrollBar *sb, int rect_r[2][2]); + +void scrollbar_get_thumb (ScrollBar *sb, int thumb_r[2][2]); + +void scrollbar_free (ScrollBar *sb); + diff --git a/intern/ghost/test/multitest/Util.c b/intern/ghost/test/multitest/Util.c new file mode 100644 index 00000000000..abc4c2651e4 --- /dev/null +++ b/intern/ghost/test/multitest/Util.c @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "Util.h" + +void* memdbl(void *mem, int *size_pr, int item_size) { + int cur_size= *size_pr; + int new_size= cur_size?(cur_size*2):1; + void *nmem= MEM_mallocN(new_size*item_size, "memdbl"); + + memcpy(nmem, mem, cur_size*item_size); + MEM_freeN(mem); + + *size_pr= new_size; + return nmem; +} + +char* string_dup(char *str) { + int len= strlen(str); + char *nstr= MEM_mallocN(len + 1, "string_dup"); + + memcpy(nstr, str, len+1); + + return nstr; +} + +void fatal(char *fmt, ...) { + va_list ap; + + fprintf(stderr, "FATAL: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} diff --git a/intern/ghost/test/multitest/Util.h b/intern/ghost/test/multitest/Util.h new file mode 100644 index 00000000000..e4e73a19fec --- /dev/null +++ b/intern/ghost/test/multitest/Util.h @@ -0,0 +1,33 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +void* memdbl (void *mem, int *size_pr, int item_size); + +char* string_dup (char *str); +void fatal (char *fmt, ...); + diff --git a/intern/ghost/test/multitest/WindowData.c b/intern/ghost/test/multitest/WindowData.c new file mode 100644 index 00000000000..0a4c2aa8d00 --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.c @@ -0,0 +1,56 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" + +#include "WindowData.h" + +struct _WindowData { + void *data; + WindowDataHandler handler; +}; + +WindowData *windowdata_new(void *data, WindowDataHandler handler) { + WindowData *wb= MEM_mallocN(sizeof(*wb), "windowdata_new"); + wb->data= data; + wb->handler= handler; + + return wb; +} + +void windowdata_handle(WindowData *wb, GHOST_EventHandle evt) { + wb->handler(wb->data, evt); +} + +void windowdata_free(WindowData *wb) { + MEM_freeN(wb); +} diff --git a/intern/ghost/test/multitest/WindowData.h b/intern/ghost/test/multitest/WindowData.h new file mode 100644 index 00000000000..50d8aa3783a --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.h @@ -0,0 +1,37 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +typedef void (*WindowDataHandler)(void *priv, GHOST_EventHandle evt); +typedef struct _WindowData WindowData; + + /***/ + +WindowData* windowdata_new (void *data, WindowDataHandler handler); +void windowdata_handle (WindowData *wb, GHOST_EventHandle evt); +void windowdata_free (WindowData *wb); + diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt new file mode 100644 index 00000000000..4a534d94eb8 --- /dev/null +++ b/intern/guardedalloc/CMakeLists.txt @@ -0,0 +1,52 @@ +# $Id$ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC .) + +set(SRC + ./intern/mallocn.c + + MEM_guardedalloc.h + MEM_sys_types.h +) + +if(WIN32 AND NOT UNIX) + list(APPEND SRC + intern/mmap_win.c + + mmap_win.h + ) +endif() + +blender_add_lib(bf_intern_guardedalloc "${SRC}" "${INC}") + +# Override C++ alloc, optional. +if(WITH_CXX_GUARDEDALLOC) + set(SRC + cpp/mallocn.cpp + ) + blender_add_lib(bf_intern_guardedalloc_cpp "${SRC}" "${INC}") +endif() diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h new file mode 100644 index 00000000000..f96a49b9f4a --- /dev/null +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -0,0 +1,177 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file MEM_guardedalloc.h + * \ingroup MEM + * + * \author Copyright (C) 2001 NaN Technologies B.V. + * \brief Read \ref MEMPage + */ + +/** + * \page MEMPage Guarded memory(de)allocation + * + * \section aboutmem c-style guarded memory allocation + * + * \subsection memabout About the MEM module + * + * MEM provides guarded malloc/calloc calls. All memory is enclosed by + * pads, to detect out-of-bound writes. All blocks are placed in a + * linked list, so they remain reachable at all times. There is no + * back-up in case the linked-list related data is lost. + * + * \subsection memissues Known issues with MEM + * + * There are currently no known issues with MEM. Note that there is a + * second intern/ module with MEM_ prefix, for use in c++. + * + * \subsection memdependencies Dependencies + * - stdlib + * - stdio + * + * \subsection memdocs API Documentation + * See \ref MEM_guardedalloc.h + */ + +#ifndef MEM_MALLOCN_H +#define MEM_MALLOCN_H + +#include /* needed for FILE* */ +#include "MEM_sys_types.h" /* needed for uintptr_t */ + +#ifndef WARN_UNUSED +# ifdef __GNUC__ +# define WARN_UNUSED __attribute__((warn_unused_result)) +# else +# define WARN_UNUSED +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + /** Returns the length of the allocated memory segment pointed at + * by vmemh. If the pointer was not previously allocated by this + * module, the result is undefined.*/ + size_t MEM_allocN_len(void *vmemh) WARN_UNUSED; + + /** + * Release memory previously allocatred by this module. + */ + short MEM_freeN(void *vmemh); + + + /** + * Return zero if memory is not in allocated list + */ + short MEM_testN(void *vmemh); + + /** + * Duplicates a block of memory, and returns a pointer to the + * newly allocated block. */ + void *MEM_dupallocN(void *vmemh) WARN_UNUSED; + + /** + * Reallocates a block of memory, and returns pointer to the newly + * allocated block, the old one is freed. this is not as optimized + * as a system realloc but just makes a new allocation and copies + * over from existing memory. */ + void *MEM_reallocN(void *vmemh, size_t len) WARN_UNUSED; + + /** + * Allocate a block of memory of size len, with tag name str. The + * memory is cleared. The name must be static, because only a + * pointer to it is stored ! */ + void *MEM_callocN(size_t len, const char * str) WARN_UNUSED; + + /** Allocate a block of memory of size len, with tag name str. The + * name must be a static, because only a pointer to it is stored ! + * */ + void *MEM_mallocN(size_t len, const char * str) WARN_UNUSED; + + /** Same as callocN, clears memory and uses mmap (disk cached) if supported. + Can be free'd with MEM_freeN as usual. + * */ + void *MEM_mapallocN(size_t len, const char * str) WARN_UNUSED; + + /** Print a list of the names and sizes of all allocated memory + * blocks. as a python dict for easy investigation */ + void MEM_printmemlist_pydict(void); + + /** Print a list of the names and sizes of all allocated memory + * blocks. */ + void MEM_printmemlist(void); + + /** calls the function on all allocated memory blocks. */ + void MEM_callbackmemlist(void (*func)(void*)); + + /** Print statistics about memory usage */ + void MEM_printmemlist_stats(void); + + /** Set the callback function for error output. */ + void MEM_set_error_callback(void (*func)(const char *)); + + /** + * Are the start/end block markers still correct ? + * + * @retval 0 for correct memory, 1 for corrupted memory. */ + int MEM_check_memory_integrity(void); + + /** Set thread locking functions for safe memory allocation from multiple + threads, pass NULL pointers to disable thread locking again. */ + void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)); + + /** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */ + void MEM_set_memory_debug(void); + + /** Memory usage stats + * - MEM_get_memory_in_use is all memory + * - MEM_get_mapped_memory_in_use is a subset of all memory */ + uintptr_t MEM_get_memory_in_use(void); + /** Get mapped memory usage. */ + uintptr_t MEM_get_mapped_memory_in_use(void); + /** Get amount of memory blocks in use. */ + int MEM_get_memory_blocks_in_use(void); + + /** Reset the peak memory statistic to zero. */ + void MEM_reset_peak_memory(void); + + /** Get the peak memory usage in bytes, including mmap allocations. */ + uintptr_t MEM_get_peak_memory(void) WARN_UNUSED; + +#ifndef NDEBUG +const char *MEM_name_ptr(void *vmemh); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/guardedalloc/MEM_sys_types.h b/intern/guardedalloc/MEM_sys_types.h new file mode 100644 index 00000000000..c5148e84ffe --- /dev/null +++ b/intern/guardedalloc/MEM_sys_types.h @@ -0,0 +1,131 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * A platform-independent definition of [u]intXX_t + * Plus the accompanying header include for htonl/ntohl + * + * This file includes to define [u]intXX_t types, where + * XX can be 8, 16, 32 or 64. Unfortunately, not all systems have this + * file. + * - Windows uses __intXX compiler-builtin types. These are signed, + * so we have to flip the signs. + * For these rogue platforms, we make the typedefs ourselves. + * + */ + +/* +// DG: original BLO_sys_types.h is in source/blender/blenkernel +// but is not allowed be accessed here because of bad-level-call +// jesterKing: I've renamed this to MEM_sys_types.h, because otherwise +// doxygen would get a conflict +*/ + +/** \file MEM_sys_types.h + * \ingroup MEM + */ + +#ifndef MEM_SYS_TYPES_H +#define MEM_SYS_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + +/* The __intXX are built-in types of the visual complier! So we don't + * need to include anything else here. */ + +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef long intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned long uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#elif defined(__linux__) || defined(__NetBSD__) + + /* Linux-i386, Linux-Alpha, Linux-ppc */ +#include + +#elif defined (__APPLE__) + +#include + +#elif defined(FREE_WINDOWS) + +#include + +#else + + /* FreeBSD, Irix, Solaris */ +#include + +#endif /* ifdef platform for types */ + +#ifdef _WIN32 +#ifndef htonl +#define htonl(x) correctByteOrder(x) +#endif +#ifndef ntohl +#define ntohl(x) correctByteOrder(x) +#endif +#elif defined (__FreeBSD__) || defined (__OpenBSD__) +#include +#elif defined (__APPLE__) +#include +#else /* irix sun linux */ +#include +#endif /* ifdef platform for htonl/ntohl */ + +#ifdef __cplusplus +} +#endif + +#endif /* MEM_SYS_TYPES_H */ + diff --git a/intern/guardedalloc/SConscript b/intern/guardedalloc/SConscript new file mode 100644 index 00000000000..74d6e07269f --- /dev/null +++ b/intern/guardedalloc/SConscript @@ -0,0 +1,15 @@ +#!/usr/bin/python + +Import('env') + +defs = [] + +sources = ['intern/mallocn.c', 'intern/mmap_win.c'] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + sources.append('cpp/mallocn.cpp') + defs.append('WITH_CXX_GUARDEDALLOC') + +incs = '.' + +env.BlenderLib ('bf_intern_guardedalloc', sources, Split(incs), defs, libtype=['intern','player'], priority = [5,150] ) diff --git a/intern/guardedalloc/cpp/mallocn.cpp b/intern/guardedalloc/cpp/mallocn.cpp new file mode 100644 index 00000000000..0615d19d77f --- /dev/null +++ b/intern/guardedalloc/cpp/mallocn.cpp @@ -0,0 +1,46 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file guardedalloc/cpp/mallocn.cpp + * \ingroup MEM + */ + + +#include +#include "../MEM_guardedalloc.h" + +void* operator new (size_t size) +{ + return MEM_mallocN(size, "C++/anonymous"); +} + +/* not default but can be used when needing to set a string */ +void* operator new (size_t size, const char *str) +{ + return MEM_mallocN(size, str); +} + +void operator delete (void *p) +{ + MEM_freeN(p); +} diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c new file mode 100644 index 00000000000..55340d6011d --- /dev/null +++ b/intern/guardedalloc/intern/mallocn.c @@ -0,0 +1,879 @@ +/* + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file guardedalloc/intern/mallocn.c + * \ingroup MEM + */ + + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Guarded memory allocation, and boundary-write detection. + */ + +#include +#include /* memcpy */ +#include +#include +/* Blame Microsoft for LLP64 and no inttypes.h, quick workaround needed: */ +#if defined(WIN64) +#define SIZET_FORMAT "%I64u" +#define SIZET_ARG(a) ((unsigned long long)(a)) +#else +#define SIZET_FORMAT "%lu" +#define SIZET_ARG(a) ((unsigned long)(a)) +#endif + +/* mmap exception */ +#if defined(WIN32) +#include "mmap_win.h" +#else +#include +#endif + +#include "MEM_guardedalloc.h" + +/* Only for debugging: + * lets you count the allocations so as to find the allocator of unfreed memory + * in situations where the leak is predictable */ + +// #define DEBUG_MEMCOUNTER + +#ifdef DEBUG_MEMCOUNTER +#define DEBUG_MEMCOUNTER_ERROR_VAL 0 /* set this to the value that isnt being freed */ +static int _mallocn_count = 0; + +/* breakpoint here */ +static void memcount_raise(const char *name) +{ + fprintf(stderr, "%s: memcount-leak, %d\n", name, _mallocn_count); +} +#endif + +/* --------------------------------------------------------------------- */ +/* Data definition */ +/* --------------------------------------------------------------------- */ +/* all memory chunks are put in linked lists */ +typedef struct localLink +{ + struct localLink *next,*prev; +} localLink; + +typedef struct localListBase +{ + void *first, *last; +} localListBase; + + /* note: keep this struct aligned (e.g., irix/gcc) - Hos */ +typedef struct MemHead { + int tag1; + size_t len; + struct MemHead *next,*prev; + const char * name; + const char * nextname; + int tag2; + int mmap; /* if true, memory was mmapped */ +#ifdef DEBUG_MEMCOUNTER + int _count; +#endif +} MemHead; + +typedef struct MemTail { + int tag3, pad; +} MemTail; + + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink); +static void remlink(volatile localListBase *listbase, void *vlink); +static void rem_memblock(MemHead *memh); +static void MemorY_ErroR(const char *block, const char *error); +static const char *check_memlist(MemHead *memh); + +/* --------------------------------------------------------------------- */ +/* locally used defines */ +/* --------------------------------------------------------------------- */ + +#if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__)) +#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + +#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O') +#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L') +#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!') +#define MEMFREE MAKE_ID('F', 'R', 'E', 'E') + +#define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next)))) + +/* --------------------------------------------------------------------- */ +/* vars */ +/* --------------------------------------------------------------------- */ + + +static volatile int totblock= 0; +static volatile uintptr_t mem_in_use= 0, mmap_in_use= 0, peak_mem = 0; + +static volatile struct localListBase _membase; +static volatile struct localListBase *membase = &_membase; +static void (*error_callback)(const char *) = NULL; +static void (*thread_lock_callback)(void) = NULL; +static void (*thread_unlock_callback)(void) = NULL; + +static int malloc_debug_memset= 0; + +#ifdef malloc +#undef malloc +#endif + +#ifdef calloc +#undef calloc +#endif + +#ifdef free +#undef free +#endif + + +/* --------------------------------------------------------------------- */ +/* implementation */ +/* --------------------------------------------------------------------- */ + +static void print_error(const char *str, ...) +{ + char buf[512]; + va_list ap; + + va_start(ap, str); + vsnprintf(buf, sizeof(buf), str, ap); + va_end(ap); + buf[sizeof(buf) - 1] = '\0'; + + if (error_callback) error_callback(buf); +} + +static void mem_lock_thread(void) +{ + if (thread_lock_callback) + thread_lock_callback(); +} + +static void mem_unlock_thread(void) +{ + if (thread_unlock_callback) + thread_unlock_callback(); +} + +int MEM_check_memory_integrity(void) +{ + const char* err_val = NULL; + MemHead* listend; + /* check_memlist starts from the front, and runs until it finds + * the requested chunk. For this test, that's the last one. */ + listend = membase->last; + + err_val = check_memlist(listend); + + if (err_val == NULL) return 0; + return 1; +} + + +void MEM_set_error_callback(void (*func)(const char *)) +{ + error_callback = func; +} + +void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)) +{ + thread_lock_callback = lock; + thread_unlock_callback = unlock; +} + +void MEM_set_memory_debug(void) +{ + malloc_debug_memset= 1; +} + +size_t MEM_allocN_len(void *vmemh) +{ + if (vmemh) { + MemHead *memh= vmemh; + + memh--; + return memh->len; + } else + return 0; +} + +void *MEM_dupallocN(void *vmemh) +{ + void *newp= NULL; + + if (vmemh) { + MemHead *memh= vmemh; + memh--; + + if(memh->mmap) + newp= MEM_mapallocN(memh->len, "dupli_mapalloc"); + else + newp= MEM_mallocN(memh->len, "dupli_alloc"); + + if (newp == NULL) return NULL; + + memcpy(newp, vmemh, memh->len); + } + + return newp; +} + +void *MEM_reallocN(void *vmemh, size_t len) +{ + void *newp= NULL; + + if (vmemh) { + MemHead *memh= vmemh; + memh--; + + newp= MEM_mallocN(len, memh->name); + if(newp) { + if(len < memh->len) + memcpy(newp, vmemh, len); + else + memcpy(newp, vmemh, memh->len); + } + + MEM_freeN(vmemh); + } + + return newp; +} + +static void make_memhead_header(MemHead *memh, size_t len, const char *str) +{ + MemTail *memt; + + memh->tag1 = MEMTAG1; + memh->name = str; + memh->nextname = NULL; + memh->len = len; + memh->mmap = 0; + memh->tag2 = MEMTAG2; + + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len); + memt->tag3 = MEMTAG3; + + addtail(membase,&memh->next); + if (memh->next) memh->nextname = MEMNEXT(memh->next)->name; + + totblock++; + mem_in_use += len; + + peak_mem = mem_in_use > peak_mem ? mem_in_use : peak_mem; +} + +void *MEM_mallocN(size_t len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail)); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); + if(malloc_debug_memset && len) + memset(memh+1, 255, len); + +#ifdef DEBUG_MEMCOUNTER + if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL) + memcount_raise("MEM_mallocN"); + memh->_count= _mallocn_count++; +#endif + return (++memh); + } + mem_unlock_thread(); + print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use); + return NULL; +} + +void *MEM_callocN(size_t len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); +#ifdef DEBUG_MEMCOUNTER + if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL) + memcount_raise("MEM_callocN"); + memh->_count= _mallocn_count++; +#endif + return (++memh); + } + mem_unlock_thread(); + print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use); + return NULL; +} + +/* note; mmap returns zero'd memory */ +void *MEM_mapallocN(size_t len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + +#ifdef __sgi + { +#include + + int fd; + fd = open("/dev/zero", O_RDWR); + + memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + } +#else + memh= mmap(NULL, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); +#endif + + if(memh!=(MemHead *)-1) { + make_memhead_header(memh, len, str); + memh->mmap= 1; + mmap_in_use += len; + peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem; + mem_unlock_thread(); +#ifdef DEBUG_MEMCOUNTER + if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL) + memcount_raise("MEM_mapallocN"); + memh->_count= _mallocn_count++; +#endif + return (++memh); + } + else { + mem_unlock_thread(); + print_error("Mapalloc returns null, fallback to regular malloc: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mmap_in_use); + return MEM_callocN(len, str); + } +} + +/* Memory statistics print */ +typedef struct MemPrintBlock { + const char *name; + uintptr_t len; + int items; +} MemPrintBlock; + +static int compare_name(const void *p1, const void *p2) +{ + const MemPrintBlock *pb1= (const MemPrintBlock*)p1; + const MemPrintBlock *pb2= (const MemPrintBlock*)p2; + + return strcmp(pb1->name, pb2->name); +} + +static int compare_len(const void *p1, const void *p2) +{ + const MemPrintBlock *pb1= (const MemPrintBlock*)p1; + const MemPrintBlock *pb2= (const MemPrintBlock*)p2; + + if(pb1->len < pb2->len) + return 1; + else if(pb1->len == pb2->len) + return 0; + else + return -1; +} + +void MEM_printmemlist_stats() +{ + MemHead *membl; + MemPrintBlock *pb, *printblock; + int totpb, a, b; + + mem_lock_thread(); + + /* put memory blocks into array */ + printblock= malloc(sizeof(MemPrintBlock)*totblock); + + pb= printblock; + totpb= 0; + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + + while(membl) { + pb->name= membl->name; + pb->len= membl->len; + pb->items= 1; + + totpb++; + pb++; + + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + + /* sort by name and add together blocks with the same name */ + qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name); + for(a=0, b=0; aitems, (double)pb->len/(double)(1024*1024), (double)pb->len/1024.0/(double)pb->items, pb->name); + + free(printblock); + + mem_unlock_thread(); + +#if 0 /* GLIBC only */ + malloc_stats(); +#endif +} + +/* Prints in python syntax for easy */ +static void MEM_printmemlist_internal( int pydict ) +{ + MemHead *membl; + + mem_lock_thread(); + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + + if (pydict) { + print_error("# membase_debug.py\n"); + print_error("membase = [\\\n"); + } + while(membl) { + if (pydict) { + fprintf(stderr, "{'len':" SIZET_FORMAT ", 'name':'''%s''', 'pointer':'%p'},\\\n", SIZET_ARG(membl->len), membl->name, (void *)(membl+1)); + } else { +#ifdef DEBUG_MEMCOUNTER + print_error("%s len: " SIZET_FORMAT " %p, count: %d\n", membl->name, SIZET_ARG(membl->len), membl+1, membl->_count); +#else + print_error("%s len: " SIZET_FORMAT " %p\n", membl->name, SIZET_ARG(membl->len), membl+1); +#endif + } + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + if (pydict) { + fprintf(stderr, "]\n\n"); + fprintf(stderr, +"mb_userinfo = {}\n" +"totmem = 0\n" +"for mb_item in membase:\n" +"\tmb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n" +"\tmb_item_user_size[0] += 1 # Add a user\n" +"\tmb_item_user_size[1] += mb_item['len'] # Increment the size\n" +"\ttotmem += mb_item['len']\n" +"print '(membase) items:', len(membase), '| unique-names:', len(mb_userinfo), '| total-mem:', totmem\n" +"mb_userinfo_sort = mb_userinfo.items()\n" +"for sort_name, sort_func in (('size', lambda a: -a[1][1]), ('users', lambda a: -a[1][0]), ('name', lambda a: a[0])):\n" +"\tprint '\\nSorting by:', sort_name\n" +"\tmb_userinfo_sort.sort(key = sort_func)\n" +"\tfor item in mb_userinfo_sort:\n" +"\t\tprint 'name:%%s, users:%%i, len:%%i' %% (item[0], item[1][0], item[1][1])\n" + ); + } + + mem_unlock_thread(); +} + +void MEM_callbackmemlist(void (*func)(void*)) { + MemHead *membl; + + mem_lock_thread(); + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + + while(membl) { + func(membl+1); + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + + mem_unlock_thread(); +} + +short MEM_testN(void *vmemh) { + MemHead *membl; + + mem_lock_thread(); + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + + while(membl) { + if (vmemh == membl+1) { + mem_unlock_thread(); + return 1; + } + + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + + mem_unlock_thread(); + + print_error("Memoryblock %p: pointer not in memlist\n", vmemh); + return 0; +} + +void MEM_printmemlist( void ) { + MEM_printmemlist_internal(0); +} +void MEM_printmemlist_pydict( void ) { + MEM_printmemlist_internal(1); +} + +short MEM_freeN(void *vmemh) /* anders compileertie niet meer */ +{ + short error = 0; + MemTail *memt; + MemHead *memh= vmemh; + const char *name; + + if (memh == NULL){ + MemorY_ErroR("free","attempt to free NULL pointer"); + /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */ + return(-1); + } + + if(sizeof(intptr_t)==8) { + if (((intptr_t) memh) & 0x7) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + else { + if (((intptr_t) memh) & 0x3) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + + memh--; + if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) { + MemorY_ErroR(memh->name,"double free"); + return(-1); + } + + mem_lock_thread(); + if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) { + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len); + if (memt->tag3 == MEMTAG3){ + + memh->tag1 = MEMFREE; + memh->tag2 = MEMFREE; + memt->tag3 = MEMFREE; + /* after tags !!! */ + rem_memblock(memh); + + mem_unlock_thread(); + + return(0); + } + error = 2; + MemorY_ErroR(memh->name,"end corrupt"); + name = check_memlist(memh); + if (name != NULL){ + if (name != memh->name) MemorY_ErroR(name,"is also corrupt"); + } + } else{ + error = -1; + name = check_memlist(memh); + if (name == NULL) + MemorY_ErroR("free","pointer not in memlist"); + else + MemorY_ErroR(name,"error in header"); + } + + totblock--; + /* here a DUMP should happen */ + + mem_unlock_thread(); + + return(error); +} + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + link->next = NULL; + link->prev = listbase->last; + + if (listbase->last) ((struct localLink *)listbase->last)->next = link; + if (listbase->first == NULL) listbase->first = link; + listbase->last = link; +} + +static void remlink(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + if (link->next) link->next->prev = link->prev; + if (link->prev) link->prev->next = link->next; + + if (listbase->last == link) listbase->last = link->prev; + if (listbase->first == link) listbase->first = link->next; +} + +static void rem_memblock(MemHead *memh) +{ + remlink(membase,&memh->next); + if (memh->prev) { + if (memh->next) + MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name; + else + MEMNEXT(memh->prev)->nextname = NULL; + } + + totblock--; + mem_in_use -= memh->len; + + if(memh->mmap) { + mmap_in_use -= memh->len; + if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail))) + printf("Couldn't unmap memory %s\n", memh->name); + } + else { + if(malloc_debug_memset && memh->len) + memset(memh+1, 255, memh->len); + free(memh); + } +} + +static void MemorY_ErroR(const char *block, const char *error) +{ + print_error("Memoryblock %s: %s\n",block, error); +} + +static const char *check_memlist(MemHead *memh) +{ + MemHead *forw,*back,*forwok,*backok; + const char *name; + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = NULL; + while(forw){ + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = NULL; + } + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = NULL; + while(back){ + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = NULL; + } + + if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT"); + + if (forw == NULL && back == NULL){ + /* geen foute headers gevonden dan maar op zoek naar memblock*/ + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = NULL; + while(forw){ + if (forw == memh) break; + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = NULL; + } + if (forw == NULL) return NULL; + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = NULL; + while(back){ + if (back == memh) break; + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = NULL; + } + } + + if (forwok) name = forwok->nextname; + else name = "No name found"; + + if (forw == memh){ + /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */ + if (forwok){ + if (backok){ + forwok->next = (MemHead *)&backok->next; + backok->prev = (MemHead *)&forwok->next; + forwok->nextname = backok->name; + } else{ + forwok->next = NULL; + membase->last = (struct localLink *) &forwok->next; +/* membase->last = (struct Link *) &forwok->next; */ + } + } else{ + if (backok){ + backok->prev = NULL; + membase->first = &backok->next; + } else{ + membase->first = membase->last = NULL; + } + } + } else{ + MemorY_ErroR(name,"Additional error in header"); + return("Additional error in header"); + } + + return(name); +} + +uintptr_t MEM_get_peak_memory(void) +{ + uintptr_t _peak_mem; + + mem_lock_thread(); + _peak_mem = peak_mem; + mem_unlock_thread(); + + return _peak_mem; +} + +void MEM_reset_peak_memory(void) +{ + mem_lock_thread(); + peak_mem = 0; + mem_unlock_thread(); +} + +uintptr_t MEM_get_memory_in_use(void) +{ + uintptr_t _mem_in_use; + + mem_lock_thread(); + _mem_in_use= mem_in_use; + mem_unlock_thread(); + + return _mem_in_use; +} + +uintptr_t MEM_get_mapped_memory_in_use(void) +{ + uintptr_t _mmap_in_use; + + mem_lock_thread(); + _mmap_in_use= mmap_in_use; + mem_unlock_thread(); + + return _mmap_in_use; +} + +int MEM_get_memory_blocks_in_use(void) +{ + int _totblock; + + mem_lock_thread(); + _totblock= totblock; + mem_unlock_thread(); + + return _totblock; +} + +#ifndef NDEBUG +const char *MEM_name_ptr(void *vmemh) +{ + if (vmemh) { + MemHead *memh= vmemh; + memh--; + return memh->name; + } + else { + return "MEM_name_ptr(NULL)"; + } +} +#endif + +/* eof */ diff --git a/intern/guardedalloc/intern/mmap_win.c b/intern/guardedalloc/intern/mmap_win.c new file mode 100644 index 00000000000..24b48d713ef --- /dev/null +++ b/intern/guardedalloc/intern/mmap_win.c @@ -0,0 +1,273 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Andrea Weikert. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file guardedalloc/intern/mmap_win.c + * \ingroup MEM + */ + + +#if defined(WIN32) + +#include +#include +#include +#include +#include + +#include "mmap_win.h" + +#ifndef FILE_MAP_EXECUTE +//not defined in earlier versions of the Platform SDK (before February 2003) +#define FILE_MAP_EXECUTE 0x0020 +#endif + +/* copied from BKE_utildefines.h ugh */ +#ifdef __GNUC__ +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#else +# define UNUSED(x) x +#endif + +/* --------------------------------------------------------------------- */ +/* local storage definitions */ +/* --------------------------------------------------------------------- */ +/* all memory mapped chunks are put in linked lists */ +typedef struct mmapLink +{ + struct mmapLink *next,*prev; +} mmapLink; + +typedef struct mmapListBase +{ + void *first, *last; +} mmapListBase; + +typedef struct MemMap { + struct MemMap *next,*prev; + void *mmap; + HANDLE fhandle; + HANDLE maphandle; +} MemMap; + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void mmap_addtail(volatile mmapListBase *listbase, void *vlink); +static void mmap_remlink(volatile mmapListBase *listbase, void *vlink); +static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr); + +static int mmap_get_prot_flags (int flags); +static int mmap_get_access_flags (int flags); + +/* --------------------------------------------------------------------- */ +/* vars */ +/* --------------------------------------------------------------------- */ +volatile static struct mmapListBase _mmapbase; +volatile static struct mmapListBase *mmapbase = &_mmapbase; + + +/* --------------------------------------------------------------------- */ +/* implementation */ +/* --------------------------------------------------------------------- */ + +/* mmap for windows */ +void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset) +{ + HANDLE fhandle = INVALID_HANDLE_VALUE; + HANDLE maphandle; + int prot_flags = mmap_get_prot_flags(prot); + int access_flags = mmap_get_access_flags(prot); + MemMap *mm = NULL; + void *ptr = NULL; + + if ( flags & MAP_FIXED ) { + return MAP_FAILED; + } + + /* + if ( fd == -1 ) { + _set_errno( EBADF ); + return MAP_FAILED; + } + */ + + if ( fd != -1 ) { + fhandle = (HANDLE) _get_osfhandle (fd); + } + if ( fhandle == INVALID_HANDLE_VALUE ) { + if (!(flags & MAP_ANONYMOUS)) { + errno = EBADF; + return MAP_FAILED; + } + } else { + if ( !DuplicateHandle( GetCurrentProcess(), fhandle, GetCurrentProcess(), + &fhandle, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) { + return MAP_FAILED; + } + } + + maphandle = CreateFileMapping(fhandle, NULL, prot_flags, 0, len, NULL); + if ( maphandle == 0 ) { + errno = EBADF; + return MAP_FAILED; + } + + ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0); + if ( ptr == NULL ) { + DWORD dwLastErr = GetLastError(); + if ( dwLastErr == ERROR_MAPPED_ALIGNMENT ) + errno=EINVAL; + else + errno=EACCES; + CloseHandle(maphandle); + return MAP_FAILED; + } + + mm= (MemMap *)malloc(sizeof(MemMap)); + if (!mm) { + errno=ENOMEM; + } + mm->fhandle = fhandle; + mm->maphandle = maphandle; + mm->mmap = ptr; + mmap_addtail(mmapbase, mm); + + return ptr; +} + +/* munmap for windows */ +intptr_t munmap(void *ptr, intptr_t UNUSED(size)) +{ + MemMap *mm = mmap_findlink(mmapbase, ptr); + if (!mm) { + errno=EINVAL; + return -1; + } + UnmapViewOfFile( mm->mmap ); + CloseHandle( mm->maphandle ); + CloseHandle( mm->fhandle); + mmap_remlink(mmapbase, mm); + free(mm); + return 0; +} + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void mmap_addtail(volatile mmapListBase *listbase, void *vlink) +{ + struct mmapLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + link->next = 0; + link->prev = listbase->last; + + if (listbase->last) ((struct mmapLink *)listbase->last)->next = link; + if (listbase->first == 0) listbase->first = link; + listbase->last = link; +} + +static void mmap_remlink(volatile mmapListBase *listbase, void *vlink) +{ + struct mmapLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + if (link->next) link->next->prev = link->prev; + if (link->prev) link->prev->next = link->next; + + if (listbase->last == link) listbase->last = link->prev; + if (listbase->first == link) listbase->first = link->next; +} + +static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr) +{ + MemMap *mm; + + if (ptr == 0) return NULL; + if (listbase == 0) return NULL; + + mm = (MemMap *)listbase->first; + while (mm) { + if (mm->mmap == ptr) { + return mm; + } + mm = mm->next; + } + return NULL; +} + +static int mmap_get_prot_flags (int flags) +{ + int prot = PAGE_NOACCESS; + + if ( ( flags & PROT_READ ) == PROT_READ ) { + if ( ( flags & PROT_WRITE ) == PROT_WRITE ) { + prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + } else { + prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY; + } + } else if ( ( flags & PROT_WRITE ) == PROT_WRITE ) { + prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY; + } else if ( ( flags & PROT_EXEC ) == PROT_EXEC ) { + prot = PAGE_EXECUTE_READ; + } + return prot; +} + +static int mmap_get_access_flags (int flags) +{ + int access = 0; + + if ( ( flags & PROT_READ ) == PROT_READ ) { + if ( ( flags & PROT_WRITE ) == PROT_WRITE ) { + access = FILE_MAP_WRITE; + } else { + access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ; + } + } else if ( ( flags & PROT_WRITE ) == PROT_WRITE ) { + access = FILE_MAP_COPY; + } else if ( ( flags & PROT_EXEC ) == PROT_EXEC ) { + access = FILE_MAP_EXECUTE; + } + return access; +} + + +#endif // WIN32 + + + + + diff --git a/intern/guardedalloc/mmap_win.h b/intern/guardedalloc/mmap_win.h new file mode 100644 index 00000000000..7e85a79a2ac --- /dev/null +++ b/intern/guardedalloc/mmap_win.h @@ -0,0 +1,59 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Andrea Weikert. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mmap_win.h + * \ingroup MEM + * \author Andrea Weikert + */ + +#ifndef MMAP_WIN_H +#define MMAP_WIN_H + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_FILE 0 +#define MAP_SHARED 1 +#define MAP_PRIVATE 2 +#define MAP_TYPE 0xF +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS + +#define MAP_FAILED ((void *)-1) + +#include "MEM_sys_types.h" // needed for intptr_t + +void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset); +intptr_t munmap(void *ptr, intptr_t size); + +#endif + diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c new file mode 100644 index 00000000000..6b3af8b310c --- /dev/null +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -0,0 +1,161 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test of memory. + */ + + + +/* Number of chunks to test with */ +#define NUM_BLOCKS 10 + +#include +#include +#include +#include "MEM_guardedalloc.h" + +static void mem_error_cb(const char *errorStr) +{ + fprintf(stderr, "%s", errorStr); + fflush(stderr); +} + +int main (int argc, char *argv[]) +{ + int verbose = 0; + int error_status = 0; + int retval = 0; + int *ip; + + void *p[NUM_BLOCKS]; + int i = 0; + + /* ----------------------------------------------------------------- */ + switch (argc) { + case 2: + verbose = atoi(argv[1]); + if (verbose < 0) verbose = 0; + break; + case 1: + default: + verbose = 0; + } + if (verbose) { + fprintf(stderr,"\n*** Simple memory test\n|\n"); + } + + /* ----------------------------------------------------------------- */ + /* Round one, do a normal allocation, and free the blocks again. */ + /* ----------------------------------------------------------------- */ + /* flush mem lib output to stderr */ + MEM_set_error_callback(mem_error_cb); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* report on that */ + if (verbose > 1) MEM_printmemlist(); + + /* memory is there: test it */ + error_status = MEM_check_memory_integrity(); + + if (verbose) { + if (error_status) { + fprintf(stderr, "|--* Memory test FAILED\n|\n"); + } else { + fprintf(stderr, "|--* Memory tested as good (as it should be)\n|\n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + /* ----------------------------------------------------------------- */ + /* Round two, do a normal allocation, and corrupt some blocks. */ + /* ----------------------------------------------------------------- */ + /* switch off, because it will complain about some things. */ + MEM_set_error_callback(NULL); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* now corrupt a few blocks...*/ + ip = (int*) p[5] - 50 ; + for (i = 0; i< 1000; i++,ip++) *ip = i+1; + ip = (int*) p[6]; + *(ip+10005) = 0; + + retval = MEM_check_memory_integrity(); + + /* the test should have failed */ + error_status |= !retval; + if (verbose) { + if (retval) { + fprintf(stderr, "|--* Memory test failed (as it should be)\n"); + } else { + fprintf(stderr, "|--* Memory test FAILED to find corrupted blocks \n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + + if (verbose && error_status) { + fprintf(stderr,"|--* Memory was corrupted\n"); + } + /* ----------------------------------------------------------------- */ + if (verbose) { + if (error_status) { + fprintf(stderr,"|\n|--* Errors were detected\n"); + } else { + fprintf(stderr,"|\n|--* Test exited succesfully\n"); + } + + fprintf(stderr,"|\n*** Finished test\n\n"); + } + return error_status; +} + +