Skip to content

Commit

Permalink
Add OS native interface lib, with objective-c++ interface to Mac Coco…
Browse files Browse the repository at this point in the history
…a libraries
  • Loading branch information
dakcarto authored and nyalldawson committed May 14, 2017
1 parent f8f7d60 commit f6bd7b3
Show file tree
Hide file tree
Showing 17 changed files with 559 additions and 11 deletions.
7 changes: 5 additions & 2 deletions CMakeLists.txt
Expand Up @@ -494,8 +494,6 @@ ELSE (WIN32)
ELSE ()
SET (OSX_HAVE_LOADERPATH 0)
ENDIF ()
#this will define ${APP_SERVICES_LIBRARY}
FIND_LIBRARY(APP_SERVICES_LIBRARY ApplicationServices )

SET (DEFAULT_BIN_SUBDIR bin)
SET (QGIS_BIN_SUBDIR_REV ..)
Expand Down Expand Up @@ -750,6 +748,11 @@ ADD_CUSTOM_TARGET(version ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/qgsversion.h)
#TEST_DATA_DIR is also used by QgsRenderChecker currently in core
SET (TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata")

SET(USE_NATIVE_LIB FALSE)
IF(APPLE)
SET(USE_NATIVE_LIB TRUE)
ENDIF(APPLE)

ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(doc)
ADD_SUBDIRECTORY(images)
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
@@ -1,3 +1,7 @@
IF(USE_NATIVE_LIB)
ADD_SUBDIRECTORY(native)
ENDIF(USE_NATIVE_LIB)

ADD_SUBDIRECTORY(core)
ADD_SUBDIRECTORY(analysis)
ADD_SUBDIRECTORY(ui)
Expand Down
18 changes: 15 additions & 3 deletions src/app/CMakeLists.txt
Expand Up @@ -529,12 +529,18 @@ INCLUDE_DIRECTORIES(SYSTEM
${QWTPOLAR_INCLUDE_DIR}
${QCA_INCLUDE_DIR}
${QTKEYCHAIN_INCLUDE_DIR}
)
)

IF(ENABLE_MODELTEST)
INCLUDE_DIRECTORIES(../../tests/qt_modeltest)
ENDIF(ENABLE_MODELTEST)

IF (USE_NATIVE_LIB)
IF(APPLE)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/native/mac)
ENDIF(APPLE)
ENDIF(USE_NATIVE_LIB)

IF (ANDROID)
INCLUDE_DIRECTORIES(SYSTEM ${ANDROID_NDK_TOOLCHAIN_ROOT}/sysroot/usr/include)
ENDIF (ANDROID)
Expand Down Expand Up @@ -586,6 +592,10 @@ IF (APPLE)
TARGET_LINK_LIBRARIES(qgis_app ${APP_SERVICES_LIBRARY})
ENDIF(APPLE)

IF(USE_NATIVE_LIB)
TARGET_LINK_LIBRARIES(qgis_app qgis_native)
ENDIF(USE_NATIVE_LIB)

if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
SET_TARGET_PROPERTIES(qgis_app PROPERTIES STATIC_LIBRARY_FLAGS "/machine:x64")
ENDIF(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
Expand All @@ -605,9 +615,11 @@ IF(WIN32)
TARGET_LINK_LIBRARIES(qgis_app DbgHelp Qt5::WinExtras)
ENDIF(WIN32)

IF (APPLE)
TARGET_LINK_LIBRARIES(${QGIS_APP_NAME} ${APP_SERVICES_LIBRARY})
IF(USE_NATIVE_LIB)
TARGET_LINK_LIBRARIES(${QGIS_APP_NAME} qgis_native)
ENDIF(USE_NATIVE_LIB)

IF (APPLE)
SET_TARGET_PROPERTIES(${QGIS_APP_NAME} PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${QGIS_LIB_DIR}
INSTALL_RPATH_USE_LINK_PATH true
Expand Down
13 changes: 10 additions & 3 deletions src/app/qgisapp.cpp
Expand Up @@ -101,6 +101,12 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#ifdef Q_OS_MACX
#include <ApplicationServices/ApplicationServices.h>

// Virtual interfaces to Cocoa objective-c frameworks/classes/calls
// cocoainitializer is to handle objective-c garbage collection
// see: http://el-tramo.be/blog/mixing-cocoa-and-qt/
//#include "cocoainitializer.h"
#include "qgsmacappkit.h"

// check macro breaks QItemDelegate
#ifdef check
#undef check
Expand Down Expand Up @@ -6120,9 +6126,10 @@ void QgisApp::bringAllToFront()
{
#ifdef Q_OS_MAC
// Bring forward all open windows while maintaining layering order
ProcessSerialNumber psn;
GetCurrentProcess( &psn );
SetFrontProcess( &psn );
// method valid for Mac OS X >= 10.6
QgsNSRunningApplication* nsrapp = new QgsNSRunningApplication();
nsrapp->currentAppActivateIgnoringOtherApps();
delete nsrapp;
#endif
}

Expand Down
12 changes: 9 additions & 3 deletions src/core/CMakeLists.txt
Expand Up @@ -1044,6 +1044,12 @@ INCLUDE_DIRECTORIES(SYSTEM
${QTKEYCHAIN_INCLUDE_DIR}
)

IF(USE_NATIVE_LIB)
IF(APPLE)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/native/mac)
ENDIF(APPLE)
ENDIF(USE_NATIVE_LIB)

#for PAL classes
IF (WIN32)
ADD_DEFINITIONS("-D_HAVE_WINDOWS_H_")
Expand Down Expand Up @@ -1112,9 +1118,9 @@ IF (WIN32)
TARGET_LINK_LIBRARIES(qgis_core wsock32 ${SETUPAPI_LIBRARY} DbgHelp)
ENDIF (WIN32)

IF(APPLE)
TARGET_LINK_LIBRARIES(qgis_core "-framework CoreFoundation -framework IOKit")
ENDIF(APPLE)
IF(USE_NATIVE_LIB)
TARGET_LINK_LIBRARIES(qgis_core qgis_native)
ENDIF(USE_NATIVE_LIB)

IF (NOT WITH_INTERNAL_QEXTSERIALPORT)
TARGET_LINK_LIBRARIES(qgis_core ${QEXTSERIALPORT_LIBRARY})
Expand Down
116 changes: 116 additions & 0 deletions src/native/CMakeLists.txt
@@ -0,0 +1,116 @@
#############################################################
# locate native libs

SET(NATIVE_LINK_LIBS)

IF(APPLE)
SET(APPLE_LIB_LIST ApplicationServices CoreFoundation IOKit AppKit)
FOREACH(_lib ${APPLE_LIB_LIST})
STRING(TOUPPER ${_lib} _lib_var)
# prefer /System/Library/Frameworks, in case CMAKE_FIND_FRAMEWORK=LAST, etc.
FIND_LIBRARY(APPLE_${_lib_var}_LIBRARY
NAMES ${_lib}
PATHS /System/Library/Frameworks
NO_DEFAULT_PATH
)
# if not found, drop back to standard find paths
FIND_LIBRARY(APPLE_${_lib_var}_LIBRARY ${_lib})

IF(NOT APPLE_${_lib_var}_LIBRARY)
MESSAGE(FATAL_ERROR "Couldn't find Apple's '${_lib}' framework or library")
ENDIF(NOT APPLE_${_lib_var}_LIBRARY)

LIST(APPEND NATIVE_LINK_LIBS "-framework ${_lib}")
ENDFOREACH(_lib ${APPLE_LIB_LIST})
ENDIF(APPLE)

#############################################################
# sources

SET(QGIS_CORE_SRCS)

IF(APPLE)
SET(QGIS_APP_OBJC_SRCS
mac/cocoainitializer.mm
mac/qgsmacappkit.mm
)

SET_SOURCE_FILES_PROPERTIES(${QGIS_APP_OBJC_SRCS} PROPERTIES COMPILE_FLAGS "-x objective-c++")

SET(QGIS_CORE_SRCS ${QGIS_CORE_SRCS}
${QGIS_APP_OBJC_SRCS}
mac/qgsmacnative.cpp
)
ENDIF(APPLE)

SET(QGIS_CORE_MOC_HDRS)

QT4_WRAP_CPP(QGIS_CORE_MOC_SRCS ${QGIS_CORE_MOC_HDRS})

# install headers

IF(APPLE)
SET (QGIS_CORE_HDRS ${QGIS_CORE_HDRS}
mac/qgsmacnative.h
mac/cocoainitializer.h
mac/qgsmacappkit.h
)
ENDIF(APPLE)

INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
)

IF(APPLE)
INCLUDE_DIRECTORIES(mac)
ENDIF(APPLE)

# Test data dir for QgsRenderChecker
ADD_DEFINITIONS(-DTEST_DATA_DIR="\\"${TEST_DATA_DIR}\\"")

#############################################################
# qgis_native library

ADD_LIBRARY(qgis_native SHARED ${QGIS_CORE_SRCS} ${QGIS_CORE_MOC_SRCS} ${QGIS_CORE_HDRS} ${QGIS_CORE_MOC_HDRS})

IF(NOT APPLE)
INSTALL(FILES ${QGIS_CORE_HDRS} ${QGIS_CORE_MOC_HDRS} DESTINATION ${QGIS_INCLUDE_DIR})
ELSE(NOT APPLE)
SET_TARGET_PROPERTIES(qgis_native PROPERTIES
CLEAN_DIRECT_OUTPUT 1
FRAMEWORK 1
FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}"
MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in"
MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION}
MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis2_native
BUILD_WITH_INSTALL_RPATH TRUE
PUBLIC_HEADER "${QGIS_CORE_HDRS};${QGIS_CORE_MOC_HDRS}"
LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}"
)
ENDIF(NOT APPLE)

#generate unversioned libs for android
IF(NOT ANDROID)
SET_TARGET_PROPERTIES(qgis_native PROPERTIES
VERSION ${COMPLETE_VERSION}
SOVERSION ${COMPLETE_VERSION}
)
ENDIF(NOT ANDROID)

TARGET_LINK_LIBRARIES(qgis_native "${NATIVE_LINK_LIBS}")

# install

INSTALL(TARGETS qgis_native
RUNTIME DESTINATION ${QGIS_BIN_DIR}
LIBRARY DESTINATION ${QGIS_LIB_DIR}
ARCHIVE DESTINATION ${QGIS_LIB_DIR}
FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR}
PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR})

# Mac dev frameworks

IF (APPLE AND QGIS_MACAPP_INSTALL_DEV)
INSTALL(TARGETS qgis_native FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX})
INSTALL(CODE "EXECUTE_PROCESS(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_native.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_native\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_native.framework/qgis_native\")")
ENDIF (APPLE AND QGIS_MACAPP_INSTALL_DEV)
23 changes: 23 additions & 0 deletions src/native/README.md
@@ -0,0 +1,23 @@
README for qgis_native lib
==========================

This library is intended to offer abstraction to the host OS's underlying public
interfaces. This is useful for OSes that provide interfaces in languages other
than C/C++, or for grouping calls to OS-specific code so that it only needs to
be updated in one place in the source tree. It is advisable to leverage existing
functions provided by Qt, rather than rely upon OS-specific code, unless such
code extends the application to provide a better OS-specific user experience or
solve a problem.

Example
-------

As of Mac OS X 10.9 (Mavericks) many system public API calls to Carbon libraries
(based upon C) have been deprecated in favor of modern Cocoa libraries (written
in Objective-C), which can no longer be directly called from C++. Coalescing
and mixing these new calls in a library, using Objective-C++ allows not only
access to the Apple system Objective-C libraries and frameworks, but also those
from third-parties, like the auto-updating Sparkle.framework.

See also: http://el-tramo.be/blog/mixing-cocoa-and-qt/
http://sparkle.andymatuschak.org/
54 changes: 54 additions & 0 deletions src/native/mac/cocoainitializer.h
@@ -0,0 +1,54 @@
/***************************************************************************
cocoaInitializer.h - used to enable Cocoa’s memory management
-------------------
copyright : (C) 2008 by Remko Troncon
email : remco at el-tramo dot be
url : http://el-tramo.be/blog/mixing-cocoa-and-qt/
***************************************************************************/

/***************************************************************************
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3)The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/

#ifndef COCOAINITIALIZER_H
#define COCOAINITIALIZER_H


class CocoaInitializer
{
public:
CocoaInitializer();
~CocoaInitializer();

private:
class Private;
Private* d;
};

#endif // COCOAINITIALIZER_H
61 changes: 61 additions & 0 deletions src/native/mac/cocoainitializer.mm
@@ -0,0 +1,61 @@
/***************************************************************************
cocoaInitializer.mm - used to enable Cocoa’s memory management
-------------------
copyright : (C) 2008 by Remko Troncon
email : remco at el-tramo dot be
url : http://el-tramo.be/blog/mixing-cocoa-and-qt/
***************************************************************************/

/***************************************************************************
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3)The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/

#include "CocoaInitializer.h"

#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>

class CocoaInitializer::Private
{
public:
NSAutoreleasePool* autoReleasePool_;
};

CocoaInitializer::CocoaInitializer()
{
d = new CocoaInitializer::Private();
NSApplicationLoad();
d->autoReleasePool_ = [[NSAutoreleasePool alloc] init];
}

CocoaInitializer::~CocoaInitializer()
{
[d->autoReleasePool_ release];
delete d;
}

0 comments on commit f6bd7b3

Please sign in to comment.