Skip to content
Permalink
Browse files
Merge pull request #4558 from nyalldawson/native-lib-mac
Add OS native interface lib, with objective-c++ interface to Mac Cocoa libraries, v3
  • Loading branch information
nyalldawson committed May 15, 2017
2 parents ae97c33 + 8f44a29 commit 87052a771208fec666faa69e43f8adae6b5407d3
@@ -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 ..)
@@ -31,6 +31,7 @@ class QgsGui
:rtype: QgsGui
%End


static QgsEditorWidgetRegistry *editorWidgetRegistry();
%Docstring
Returns the global editor widget registry, used for managing all known edit widget factories.
@@ -1,3 +1,5 @@
ADD_SUBDIRECTORY(native)

ADD_SUBDIRECTORY(core)
ADD_SUBDIRECTORY(analysis)
ADD_SUBDIRECTORY(ui)
@@ -519,6 +519,8 @@ INCLUDE_DIRECTORIES(
openstreetmap
dwg
dwg/libdxfrw
${CMAKE_SOURCE_DIR}/src/native
${CMAKE_BINARY_DIR}/src/native
)
INCLUDE_DIRECTORIES(SYSTEM
${SPATIALITE_INCLUDE_DIR}
@@ -529,7 +531,7 @@ INCLUDE_DIRECTORIES(SYSTEM
${QWTPOLAR_INCLUDE_DIR}
${QCA_INCLUDE_DIR}
${QTKEYCHAIN_INCLUDE_DIR}
)
)

IF(ENABLE_MODELTEST)
INCLUDE_DIRECTORIES(../../tests/qt_modeltest)
@@ -539,6 +541,10 @@ IF (ANDROID)
INCLUDE_DIRECTORIES(SYSTEM ${ANDROID_NDK_TOOLCHAIN_ROOT}/sysroot/usr/include)
ENDIF (ANDROID)

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

IF (POSTGRES_FOUND)
INCLUDE_DIRECTORIES(SYSTEM ${POSTGRES_INCLUDE_DIR})
ENDIF (POSTGRES_FOUND)
@@ -566,6 +572,7 @@ TARGET_LINK_LIBRARIES(qgis_app
qgis_core
qgis_gui
qgis_analysis
qgis_native
libdxfrw
)

@@ -586,6 +593,7 @@ IF (APPLE)
TARGET_LINK_LIBRARIES(qgis_app ${APP_SERVICES_LIBRARY})
ENDIF(APPLE)


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)
@@ -605,9 +613,9 @@ IF(WIN32)
TARGET_LINK_LIBRARIES(qgis_app DbgHelp Qt5::WinExtras)
ENDIF(WIN32)

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

IF (APPLE)
SET_TARGET_PROPERTIES(${QGIS_APP_NAME} PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${QGIS_LIB_DIR}
INSTALL_RPATH_USE_LINK_PATH true
@@ -100,6 +100,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
//
#ifdef Q_OS_MACX
#include <ApplicationServices/ApplicationServices.h>
#include "qgsmacnative.h"

// check macro breaks QItemDelegate
#ifdef check
@@ -205,6 +206,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgsmimedatautils.h"
#include "qgsmessagelog.h"
#include "qgsmultibandcolorrenderer.h"
#include "qgsnative.h"
#include "qgsnewvectorlayerdialog.h"
#include "qgsnewmemorylayerdialog.h"
#include "qgsoptions.h"
@@ -1210,7 +1212,7 @@ QgisApp::QgisApp()
, mMapToolGroup( nullptr )
, mPreviewGroup( nullptr )
#ifdef Q_OS_MAC
, mWindowMenu( 0 )
, mWindowMenu( nullptr )
#endif
, mPanelMenu( nullptr )
, mToolbarMenu( nullptr )
@@ -6119,12 +6121,7 @@ void QgisApp::activate()

void QgisApp::bringAllToFront()
{
#ifdef Q_OS_MAC
// Bring forward all open windows while maintaining layering order
ProcessSerialNumber psn;
GetCurrentProcess( &psn );
SetFrontProcess( &psn );
#endif
QgsGui::nativePlatformInterface()->currentAppActivateIgnoringOtherApps();
}

void QgisApp::addWindow( QAction *action )
@@ -1044,6 +1044,7 @@ INCLUDE_DIRECTORIES(SYSTEM
${QTKEYCHAIN_INCLUDE_DIR}
)


#for PAL classes
IF (WIN32)
ADD_DEFINITIONS("-D_HAVE_WINDOWS_H_")
@@ -1112,9 +1113,7 @@ 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)
TARGET_LINK_LIBRARIES(qgis_core qgis_native)

IF (NOT WITH_INTERNAL_QEXTSERIALPORT)
TARGET_LINK_LIBRARIES(qgis_core ${QEXTSERIALPORT_LIBRARY})
@@ -744,6 +744,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}/effects
${CMAKE_BINARY_DIR}/src/core
${CMAKE_BINARY_DIR}/src/gui
${CMAKE_BINARY_DIR}/src/native
../core
../core/annotations
../core/auth
@@ -758,6 +759,7 @@ INCLUDE_DIRECTORIES(
../core/symbology-ng
../core/effects
../core/metadata
../native
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/../ui
)
@@ -804,6 +806,7 @@ SET(QGIS_GUI_HDRS ${QGIS_GUI_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_gui.h)
IF(NOT APPLE)
INSTALL(FILES ${QGIS_GUI_HDRS} ${QGIS_GUI_MOC_HDRS} DESTINATION ${QGIS_INCLUDE_DIR})
ELSE(NOT APPLE)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/native/mac)
SET_TARGET_PROPERTIES(qgis_gui PROPERTIES
CLEAN_DIRECT_OUTPUT 1
FRAMEWORK 1
@@ -838,6 +841,7 @@ ADD_DEPENDENCIES(qgis_gui ui)

TARGET_LINK_LIBRARIES(qgis_gui
qgis_core
qgis_native
${QT_QTUITOOLS_LIBRARY}
${QWT_LIBRARY}
${QSCINTILLA_LIBRARY}
@@ -19,6 +19,11 @@
#include "qgseditorwidgetregistry.h"
#include "qgslayertreeembeddedwidgetregistry.h"
#include "qgsmaplayeractionregistry.h"
#ifdef Q_OS_MACX
#include "qgsmacnative.h"
#else
#include "qgsnative.h"
#endif
#include "qgsshortcutsmanager.h"

QgsGui *QgsGui::instance()
@@ -27,6 +32,11 @@ QgsGui *QgsGui::instance()
return sInstance;
}

QgsNative *QgsGui::nativePlatformInterface()
{
return instance()->mNative;
}

QgsEditorWidgetRegistry *QgsGui::editorWidgetRegistry()
{
return instance()->mEditorWidgetRegistry;
@@ -53,10 +63,17 @@ QgsGui::~QgsGui()
delete mEditorWidgetRegistry;
delete mMapLayerActionRegistry;
delete mShortcutsManager;
delete mNative;
}

QgsGui::QgsGui()
{
#ifdef Q_OS_MAC
mNative = new QgsMacNative();
#else
mNative = new QgsNative();
#endif

mEditorWidgetRegistry = new QgsEditorWidgetRegistry();
mShortcutsManager = new QgsShortcutsManager();
mLayerTreeEmbeddedWidgetRegistry = new QgsLayerTreeEmbeddedWidgetRegistry();
@@ -19,11 +19,13 @@
#define QGSGUI_H

#include "qgis_gui.h"
#include "qgis_sip.h"

class QgsEditorWidgetRegistry;
class QgsShortcutsManager;
class QgsLayerTreeEmbeddedWidgetRegistry;
class QgsMapLayerActionRegistry;
class QgsNative;

/**
* \ingroup gui
@@ -46,6 +48,13 @@ class GUI_EXPORT QgsGui
*/
static QgsGui *instance();

/**
* Returns the global native interface, which offers abstraction to the host OS's underlying public
* interfaces.
* \note Not available in Python bindings
*/
SIP_SKIP static QgsNative *nativePlatformInterface();

/**
* Returns the global editor widget registry, used for managing all known edit widget factories.
*/
@@ -72,6 +81,7 @@ class GUI_EXPORT QgsGui

QgsGui();

QgsNative *mNative = nullptr;
QgsEditorWidgetRegistry *mEditorWidgetRegistry = nullptr;
QgsShortcutsManager *mShortcutsManager = nullptr;
QgsLayerTreeEmbeddedWidgetRegistry *mLayerTreeEmbeddedWidgetRegistry = nullptr;
@@ -0,0 +1,120 @@
#############################################################
# 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_NATIVE_SRCS
qgsnative.cpp
)

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

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

SET(QGIS_NATIVE_SRCS ${QGIS_NATIVE_SRCS}
${QGIS_APP_OBJC_SRCS}
)
ENDIF(APPLE)

SET(QGIS_NATIVE_HDRS
qgsnative.h
)

# install headers

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

INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)

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

ADD_LIBRARY(qgis_native SHARED ${QGIS_NATIVE_SRCS} ${QGIS_NATIVE_HDRS})
SET_PROPERTY(TARGET qgis_native PROPERTY POSITION_INDEPENDENT_CODE ON)

GENERATE_EXPORT_HEADER(
qgis_native
BASE_NAME NATIVE
EXPORT_FILE_NAME qgis_native.h
)

SET(QGIS_NATIVE_HDRS ${QGIS_NATIVE_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_native.h)

IF(NOT APPLE)
INSTALL(FILES ${QGIS_NATIVE_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_NATIVE_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)
@@ -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/

0 comments on commit 87052a7

Please sign in to comment.