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