Motif ArcGIS control programming


The Solaris and Linux SDK also provides a set of Motif widgets that may be used to embed the ArcGIS controls in a Motif application. Due to the limitations of Motif, this code will only run on Solaris and Linux systems. If visual components are needed on Windows, you will need to use Visual C++, the COM API, and ActiveX controls.

Header files

To use the Motif ArcGIS controls, you will need to include both the ArcGIS Engine header file, ArcSDK.h, and the ArcGIS Engine Motif controls header file, Ao/AoMotifControls.h.

Control types and their details

Control
MwNprogID
Interface type
GlobeControl
AoPROGID_GlobeControl
IGlobeControl
MapControl
AoPROGID_MapControl
IMapControl3
PageLayoutControl
AoPROGID_PageLayoutControl
IPageLayoutControl
ReaderControl
AoPROGID_ReaderControl
IARControl
SceneControl
AoPROGID_SceneControl
ISceneControl
TOCControl
AoPROGID_TOCControl
ITOCControl
ToolbarControl
AoPROGID_ToolbarControl
IToolbarControl

API functions and arguments

  • For each ArcGIS Engine Control interface there is a smart pointer defined for you. Instead of IMapControl3* you can use IMapControlPtr.
  • MwCtlAppMainLoop replaces XtAppMainLoop
[Motif C++]
          extern
          "C"
          void MwCtlAppMainLoop(XtAppContext app);
  • MwCtlGetInterface is used to get the control's interface pointer.
[Motif C++]
HRESULT MwCtlGetInterface(Widget w, IUnknown **ppUnk);
  • mwCtlWidgetClass—argument to give the widget class for all ActiveX control widgets
  • MwNprogID—argument to pair with AoPROGID_<ControlName>Control
  • MwCtlSetCursor is used to set a custom cursor for the Motif control widget.
[Motif C++]
HRESULT MwCtlSetCursor(HCURSOR cur);

Control widget creation example

The following example demonstrates creating a MapControl that fills the entire Motif form mainForm (defined outside this code snippet) and retrieves a smart pointer for the control. The #define statements are necessary to prevent type name conflicts between X and ArcGIS Engine.
[Motif C++]
          // Motif Headers 
          #define String         esriXString
#define Cursor         esriXCursor
#define Object         esriXObject
#define ObjectClass    esriXObjectClass
#include <Xm/Xm.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/Protocols.h>
#undef String
#undef Cursor
#undef Object
#undef ObjectClass

// ArcObjects Headers// Engine#include <ArcSDK.h>
// Controls#include <Ao/AoMotifControls.h>
int main(int argc, char *argv[])
{
  // other code goes before this

  Widget mapWidget = XtVaCreateWidget("mapWidget", mwCtlWidgetClass, mainForm,
    XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM,
    XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM,
    MwNprogID, AoPROGID_MapControl, NULL);
  IMapControl3Ptr ipMapControl;
  HRESULT hr = MwCtlGetInterface(mapWidget, (IUnknown **) &ipMapControl);

  // additional code follows here
}

#define and Types for Motif

In most of the Motif samples, you will see code similar to the following:
[Motif C++]
          #define String esriXString
#define Cursor esriXCursor
#define Object esriXObject
#define ObjectClass esriXObjectClass
#include <Xm/Xm.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/Protocols.h>
#undef String
#undef Cursor
#undef Object
#undef ObjectClass
Because the type names String, Cursor, Object, and ObjectClass are used by both ArcGIS and X, all included X headers have been placed between these #define-#undef pairs to rename those types and resolve the conflict. Any other X headers must also be included in this manner. If your code uses any of those X types, you can simply substitute the original name with the replacement shown above as long as you are passing them to functions with external "C" linkage (eg. X functions).
If you pass arguments using these renamed types to C++ functions or methods, you will likely encounter compilation errors due to the compiler's name mangling scheme, which generally uses argument types to produce function and method symbol names. In this case, you must carefully segregate this code into compilation units (compiled files) separate from your ArcGIS code.

Setting the size of a control widget

If you would like to set your control widget to have a specific size, you will need to do this after the widget itself is created. DO NOT use XmNheight and XmNwidth in the XtVaCreateWidget section. Due to internal limitations, that will cause undetermined behavior in the controls. Instead, set the size of your widget after it is created with a call to XtVaSetValues. For example, to set the above mapControl to be 200x200, add the line:
[Motif C++]
XtVaSetValues(mapWidget, XmNheight, 200, XmNwidth, 200, NULL);
after the call to XtVaCreateWidget.