1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkTDxUnixDevice.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkTDxUnixDevice.h"
16 
17 #include <cassert>
18 
19 #include <X11/Xlib.h> // Needed for X types used in the public interface
20 // Display *DisplayId; // Actually a "Display *" but we cannot include Xlib.h
21 //  Window WindowId; // Actually a "Window" but we cannot include Xlib.h
22 
23 
24 #define SGI // Used in xdrvlib.h to define ParameterCheck
25 
26 // xdrvlib.h does not have the usual __cplusplus extern "C" guard
27 extern "C" {
28 #include "xdrvlib.h" // Magellan X-Window driver API.
29 }
30 
31 #include "vtkTDxMotionEventInfo.h"
32 #include "vtkCommand.h"
33 #include "vtkObjectFactory.h"
34 #include "vtkRenderWindowInteractor.h"
35 #include "vtkMath.h"
36 
37 vtkStandardNewMacro(vtkTDxUnixDevice);
38 
39 // ----------------------------------------------------------------------------
40 // Description:
41 // Default constructor. Just set initial values for
42 // DisplayId (0), WindowId (0)), TranslationScale (1.0),
43 // RotationScale (1.0).
vtkTDxUnixDevice()44 vtkTDxUnixDevice::vtkTDxUnixDevice()
45 {
46   this->DisplayId=0;
47   this->WindowId=0;
48   this->TranslationScale=1.0;
49   this->RotationScale=1.0;
50   this->Interactor=0;
51 //  this->DebugOn();
52 }
53 
54 // ----------------------------------------------------------------------------
55 // Description:
56 // Destructor. If the device is not initialized, do nothing. If the device
57 // is initialized, close the device.
~vtkTDxUnixDevice()58 vtkTDxUnixDevice::~vtkTDxUnixDevice()
59 {
60   if(this->Initialized)
61     {
62     this->Close();
63     }
64 }
65 
66 // ----------------------------------------------------------------------------
67 // Description:
68 // Get the ID of the X Display. Initial value is 0.
GetDisplayId() const69 vtkTDxUnixDeviceDisplay *vtkTDxUnixDevice::GetDisplayId() const
70 {
71   return this->DisplayId;
72 }
73 
74 // ----------------------------------------------------------------------------
75 // Description:
76 // Get the ID of the X Window. Initial value is 0.
GetWindowId() const77 vtkTDxUnixDeviceWindow vtkTDxUnixDevice::GetWindowId() const
78 {
79   return this->WindowId;
80 }
81 
82 // ----------------------------------------------------------------------------
83 // Description:
84 // Set the ID of the X Display.
85 // \pre not_yet_initialized: !GetInitialized()
SetDisplayId(vtkTDxUnixDeviceDisplay * id)86 void vtkTDxUnixDevice::SetDisplayId(vtkTDxUnixDeviceDisplay *id)
87 {
88   assert("pre: not_yet_initialized" && !this->GetInitialized());
89   if(this->DisplayId!=id)
90     {
91     this->DisplayId=id;
92     this->Modified();
93     }
94 }
95 
96 // ----------------------------------------------------------------------------
97 // Description:
98 // Set the ID of the X Window.
99 // \pre not_yet_initialized: !GetInitialized()
SetWindowId(vtkTDxUnixDeviceWindow id)100 void vtkTDxUnixDevice::SetWindowId(vtkTDxUnixDeviceWindow id)
101 {
102   assert("pre: not_yet_initialized" && !this->GetInitialized());
103   if(this->WindowId!=id)
104     {
105     this->WindowId=id;
106     this->Modified();
107     }
108 }
109 
110 // ----------------------------------------------------------------------------
111 // Description:
112 // Initialize the device with the current display and window ids.
113 // It updates the value of GetInitialized().
114 // Initialization can fail. You must look for the value of
115 // GetInitialized() before processing further.
116 // \pre not_yet_initialized: !GetInitialized()
117 // \pre valid_display: GetDisplayId()!=0
118 // \pre valid_window: GetWindowId()!=0
119 // \pre valid_interactor: GetInteractor()!=0
Initialize()120 void vtkTDxUnixDevice::Initialize()
121 {
122   assert("pre: not_yet_initialized" && !this->GetInitialized());
123   assert("pre: valid_display" && this->GetDisplayId()!=0);
124   assert("pre: valid_window" && this->GetWindowId()!=0);
125 
126   int status=MagellanInit(static_cast<Display *>(this->DisplayId),
127                           static_cast<Window>(this->WindowId));
128   this->Initialized=status==1;
129 }
130 
131 // ----------------------------------------------------------------------------
132 // Description:
133 // Close the device. This is called by the destructor.
134 // You don't have to close the device explicitly, as the destructor do it
135 // automatically, but you can.
136 // \pre initialized: GetInitialized().
137 // \post restored: !GetInitialized()
Close()138 void vtkTDxUnixDevice::Close()
139 {
140   assert("pre: initialized" && this->GetInitialized());
141 
142   vtkDebugMacro(<< "Close()" );
143   MagellanClose(static_cast<Display *>(this->DisplayId));
144   this->Initialized=false;
145 
146   assert("post: restored" && !this->GetInitialized());
147 }
148 
149 // ----------------------------------------------------------------------------
150 // Description:
151 // Translate the X11 event by invoking a VTK event, if the event came from
152 // the device.
153 // Return true if the event passed in argument was effectively an event from
154 // the device, return false otherwise.
155 // \pre initialized: GetInitialized()
156 // \pre e_exists: e!=0
157 // \pre e_is_client_message: e->type==ClientMessage
ProcessEvent(const vtkTDxUnixDeviceXEvent * e)158 bool vtkTDxUnixDevice::ProcessEvent(const vtkTDxUnixDeviceXEvent *e)
159 {
160   assert("pre: initialized" && this->GetInitialized());
161   assert("pre: e_exists" && e!=0);
162   assert("pre: e_is_client_message" &&
163          static_cast<const XEvent *>(e)->type==ClientMessage);
164 
165   MagellanFloatEvent info;
166 
167   const XEvent *event=static_cast<const XEvent *>(e);
168 
169   int deviceEvent=MagellanTranslateEvent(
170     static_cast<Display *>(this->DisplayId),
171     const_cast<XEvent *>(event),
172     &info,
173     this->TranslationScale,
174     this->RotationScale);
175 
176   vtkDebugMacro(<< "deviceEvent=" << deviceEvent);
177 
178   vtkTDxMotionEventInfo motionInfo;
179   int buttonInfo;
180   double axis[3];
181 
182   bool result;
183   switch(deviceEvent)
184     {
185     case MagellanInputMotionEvent:
186       vtkDebugMacro(<< "it is MagellanInputMotionEvent");
187       MagellanRemoveMotionEvents(static_cast<Display *>(this->DisplayId));
188       motionInfo.X=info.MagellanData[MagellanX];
189       motionInfo.Y=info.MagellanData[MagellanY];
190 
191       // On Unix, the Z axis is reversed (wrong). We want to have a
192       // right-handed coordinate system, so positive Z has to come towards us,
193       // as on Windows.
194       motionInfo.Z=-info.MagellanData[MagellanZ];
195 
196       axis[0]=info.MagellanData[MagellanA];
197       axis[1]=info.MagellanData[MagellanB];
198 
199       // On Unix, the Z axis is reserved (wrong).
200       axis[2]=-info.MagellanData[MagellanC];
201 
202       motionInfo.Angle=vtkMath::Norm(axis);
203       if(motionInfo.Angle==0.0)
204         {
205         motionInfo.AxisX=0.0;
206         motionInfo.AxisY=0.0;
207         motionInfo.AxisZ=1.0;
208         }
209       else
210         {
211         motionInfo.AxisX=axis[0]/motionInfo.Angle;
212         motionInfo.AxisY=axis[1]/motionInfo.Angle;
213         motionInfo.AxisZ=axis[2]/motionInfo.Angle;
214         }
215       if(this->Interactor!=0)
216         {
217         this->Interactor->InvokeEvent(vtkCommand::TDxMotionEvent,&motionInfo);
218         }
219       result=true;
220       break;
221     case MagellanInputButtonPressEvent:
222       vtkDebugMacro(<< "it is  MagellanInputButtonPressEvent");
223       buttonInfo=info.MagellanButton;
224       if(this->Interactor!=0)
225         {
226         this->Interactor->InvokeEvent(vtkCommand::TDxButtonPressEvent,
227                                       &buttonInfo);
228         }
229       result=true;
230       break;
231     case MagellanInputButtonReleaseEvent:
232       vtkDebugMacro(<< "it is  MagellanInputButtonReleaseEvent");
233       buttonInfo=info.MagellanButton;
234       if(this->Interactor!=0)
235         {
236         this->Interactor->InvokeEvent(vtkCommand::TDxButtonReleaseEvent,
237                                       &buttonInfo);
238         }
239       result=true;
240       break;
241     default:
242       vtkDebugMacro(<< "it is not a Magellan event");
243       result=false;
244       break;
245     }
246 
247   return result;
248 }
249 
250 // ----------------------------------------------------------------------------
251 // Description:
252 // Set the sensitivity of the device for the current application.
253 // A neutral value is 1.0.
254 // \pre initialized: GetInitialized()
SetSensitivity(double sensitivity)255 void vtkTDxUnixDevice::SetSensitivity(double sensitivity)
256 {
257   assert("pre: initialized" && this->GetInitialized());
258 
259   MagellanApplicationSensitivity(static_cast<Display *>(this->DisplayId),
260                                  sensitivity);
261 }
262 
263 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)264 void vtkTDxUnixDevice::PrintSelf(ostream& os, vtkIndent indent)
265 {
266   this->Superclass::PrintSelf(os,indent);
267 
268   os << indent << "RotationScale: " << this->RotationScale << endl;
269   os << indent << "TranslationScale: " << this->TranslationScale << endl;
270 }
271