Salome HOME
Merge Qt5 porting.
[modules/gui.git] / src / SVTK / SVTK_SpaceMouse.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SALOME VTKViewer : build VTK viewer into Salome desktop
24 //  File   : SVTK_SpaceMouse.cxx
25 //  Author : Alexander SLADKOV
26
27 #include <string.h>
28 #include <math.h>
29 #include <stdio.h>
30
31 #include <QtGlobal>
32
33 #ifndef WIN32
34 #include <X11/X.h>
35 #include <X11/Xutil.h>
36 #include <X11/Xatom.h>
37 #include <X11/keysym.h>
38 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
39 #include <X11/Xlib.h>
40 #else
41 #include <xcb/xcb.h>
42 #endif
43 #endif
44
45 #include "SVTK_SpaceMouse.h"
46
47 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
48 SVTK_SpaceMouseX* SVTK_SpaceMouseX::myInstance = 0;
49 #else
50 SVTK_SpaceMouseXCB* SVTK_SpaceMouseXCB::myInstance = 0;
51 #endif
52
53 /*!
54   Constructor
55 */
56 SVTK_SpaceMouse::SVTK_SpaceMouse()
57 {
58   spaceMouseOn = 0;
59 }
60 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
61 /*!
62   Constructor
63 */
64 SVTK_SpaceMouseX::SVTK_SpaceMouseX()
65 : SVTK_SpaceMouse()
66 {
67 #ifndef WIN32
68   win = InputFocus;
69 #endif
70 }
71
72 /*!
73   \return shared instance of object (creates if there is no one)
74 */
75 SVTK_SpaceMouseX* SVTK_SpaceMouseX::getInstance()
76 {
77   if ( !myInstance )
78     myInstance = new SVTK_SpaceMouseX();
79   return myInstance;
80 }
81
82 #ifndef WIN32
83
84 static int errorCallback( Display *display, XErrorEvent *Error )
85 {
86   char msg[ 128 ];
87   if ( Error->error_code != BadWindow ) {
88     XGetErrorText( display,Error->error_code,msg,sizeof( msg ) );
89     fprintf( stderr, "SpaceMouse reported error = %s. Exit ... \n", msg );
90   }
91   return 0;
92 }
93
94 /*!
95   Initialization
96 */
97 int SVTK_SpaceMouseX::initialize( Display *display, Window window )
98 {
99   XMotionEvent        = XInternAtom( display, "MotionEvent",        1 );
100   XButtonPressEvent   = XInternAtom( display, "ButtonPressEvent",   1 );
101   XButtonReleaseEvent = XInternAtom( display, "ButtonReleaseEvent", 1 );
102   XCommandEvent       = XInternAtom( display, "CommandEvent",       1 );
103
104   spaceMouseOn = (XMotionEvent        != 0) &&
105                  (XButtonPressEvent   != 0) &&
106                  (XButtonReleaseEvent != 0) &&
107                  (XCommandEvent       != 0);
108   if ( !spaceMouseOn )
109     return 0;
110
111   spaceMouseOn = setWindow( display, window );
112   if ( !spaceMouseOn )
113     return 0;
114  
115   return spaceMouseOn;
116 }
117
118 /*!
119   Initialize by window
120 */
121 int SVTK_SpaceMouseX::setWindow( Display *display, Window window )
122 {
123   XTextProperty winName;
124   XEvent xEvent;
125   Atom type;
126   int format;
127   unsigned long NItems, BytesReturn;
128   unsigned char *PropReturn;
129   Window root;
130   int (*errorHandler)(Display *,XErrorEvent *);
131
132   errorHandler = XSetErrorHandler( errorCallback );
133  
134   root = RootWindow( display, DefaultScreen(display) );
135
136   PropReturn = NULL;
137   XGetWindowProperty( display, root, XCommandEvent, 0,1, 0,
138                       AnyPropertyType, &type, &format, &NItems,
139                       &BytesReturn, &PropReturn );
140
141   win = InputFocus;
142   if ( PropReturn != NULL ) {
143     win = *(Window *) PropReturn;
144     XFree( PropReturn );
145   }
146   else
147     return 0;
148
149   if ( XGetWMName( display, win, &winName ) == 0 )
150     return 0;
151
152   if ( strcmp( (char *) "Magellan Window", (char *) winName.value) != 0 )
153     return 0;
154
155   xEvent.type = ClientMessage;
156   xEvent.xclient.format = 16;
157   xEvent.xclient.send_event = 0;
158   xEvent.xclient.display = display;
159   xEvent.xclient.window = win;
160   xEvent.xclient.message_type = XCommandEvent;
161   
162   xEvent.xclient.data.s[0] = (short) ((window>>16)&0x0000FFFF);
163   xEvent.xclient.data.s[1] = (short)  (window&0x0000FFFF);
164   xEvent.xclient.data.s[2] = 27695;
165
166   if ( XSendEvent( display, win, 0, 0x0000, &xEvent ) == 0 )
167     return 0;
168
169   XFlush( display );
170
171   XSetErrorHandler( errorHandler );
172   return 1;
173 }
174
175 /*!
176   Close
177 */
178 int SVTK_SpaceMouseX::close(Display *display)
179 {
180   initialize( display, (Window)InputFocus );
181   spaceMouseOn = 0;
182   
183   return 1;
184 }
185
186 /*!
187   Custom event handler
188 */
189 int SVTK_SpaceMouseX::translateEvent( Display* display, XEvent* xEvent, MoveEvent* spaceMouseEvent,
190                     double scale, double rScale )
191 {
192   if ( !spaceMouseOn )
193     return 0;
194
195   if ( xEvent->type == ClientMessage ) {
196     if ( xEvent->xclient.message_type == XMotionEvent ) {
197       spaceMouseEvent->type = SpaceMouseMove;
198       spaceMouseEvent->data[ x ] =
199         xEvent->xclient.data.s[2] * scale;
200       spaceMouseEvent->data[ y ] =
201         xEvent->xclient.data.s[3] * scale;
202       spaceMouseEvent->data[ z ] =
203         xEvent->xclient.data.s[4] * scale;
204       spaceMouseEvent->data[ a ] =
205         xEvent->xclient.data.s[5] * rScale;
206       spaceMouseEvent->data[ b ] =
207         xEvent->xclient.data.s[6] * rScale;
208       spaceMouseEvent->data[ c ] =
209         xEvent->xclient.data.s[7] * rScale;
210       spaceMouseEvent->period = xEvent->xclient.data.s[8];
211       return 1;
212     }
213     else if ( xEvent->xclient.message_type == XButtonPressEvent ) {
214       spaceMouseEvent->type = SpaceButtonPress;
215       spaceMouseEvent->button = xEvent->xclient.data.s[2];
216       return 2;
217     }
218     else if ( xEvent->xclient.message_type == XButtonReleaseEvent ) {
219       spaceMouseEvent->type = SpaceButtonRelease;
220       spaceMouseEvent->button = xEvent->xclient.data.s[2];
221       return 3;
222     }
223   }
224   return (!display);
225 }
226 #endif
227 #else
228
229 /*!
230   Constructor
231 */
232 SVTK_SpaceMouseXCB::SVTK_SpaceMouseXCB()
233 : SVTK_SpaceMouse()
234 {
235 #ifndef WIN32
236   win = InputFocus;
237 #endif
238 }
239
240 /*!
241   \return shared instance of object (creates if there is no one)
242 */
243 SVTK_SpaceMouseXCB* SVTK_SpaceMouseXCB::getInstance()
244 {
245   if ( !myInstance )
246     myInstance = new SVTK_SpaceMouseXCB();
247   return myInstance;
248 }
249 /*!
250   Initialization
251 */
252 #ifndef WIN32
253 int SVTK_SpaceMouseXCB::initialize( xcb_connection_t *connection, xcb_window_t window )
254 {
255   // make request
256   xcb_intern_atom_cookie_t cookie = xcb_intern_atom (connection, 0, strlen("XCB_MOTION_NOTIFY"), "XCB_MOTION_NOTIFY" );
257   // get response
258   xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply ( connection, cookie, NULL );
259   XCBMotionEvent = reply->atom;
260   cookie = xcb_intern_atom (connection, 0, strlen("XCB_BUTTON_PRESS"), "XCB_BUTTON_PRESS" );
261   reply = xcb_intern_atom_reply ( connection, cookie, NULL );
262   XCBButtonPressEvent = reply->atom;
263   cookie = xcb_intern_atom (connection, 0, strlen("XCB_BUTTON_RELEASE"), "XCB_BUTTON_RELEASE" );
264   reply = xcb_intern_atom_reply ( connection, cookie, NULL );
265   XCBButtonReleaseEvent = reply->atom;
266
267   free (reply);
268
269   spaceMouseOn = (XCBMotionEvent        != 0) &&
270                  (XCBButtonPressEvent   != 0) &&
271                  (XCBButtonReleaseEvent != 0);
272   if ( !spaceMouseOn )
273     return 0;
274
275   spaceMouseOn = setWindow( connection, window );
276   if ( !spaceMouseOn )
277     return 0;
278
279   return spaceMouseOn;
280 }
281
282 /*!
283   Initialize by window
284 */
285 int SVTK_SpaceMouseXCB::setWindow( xcb_connection_t *connection, xcb_window_t window )
286 {
287   xcb_client_message_event_t xcbEvent;
288   xcb_window_t root_window;
289   xcb_screen_t* screen;
290   xcb_generic_error_t* error;
291   xcb_void_cookie_t cookie;
292
293   screen = xcb_setup_roots_iterator ( xcb_get_setup ( connection ) ).data;
294
295   /* root window */
296   if ( screen )
297     root_window = screen->root;
298
299   xcb_get_property_cookie_t prop_cookie;
300   xcb_get_property_reply_t* prop_reply;
301   prop_cookie = xcb_get_property (connection, 0, root_window, XCB_ATOM_WM_NAME,
302                                   XCB_ATOM_STRING, 0, 0);
303
304   win = InputFocus;
305
306   if (( prop_reply = xcb_get_property_reply ( connection, prop_cookie, NULL ) ))
307   {
308     int len = xcb_get_property_value_length( prop_reply );
309
310     if ( len == 0 )
311     {
312       free(prop_reply);
313       return 0;
314     }
315
316     if ( strcmp( (char *) "Magellan Window", (char *) xcb_get_property_value( prop_reply ) ) != 0 )
317       return 0;
318
319     win = * ( xcb_window_t * ) xcb_get_property_value( prop_reply );
320   }
321
322   free(prop_reply);
323
324   xcbEvent.response_type = XCB_CLIENT_MESSAGE;
325   xcbEvent.format = 16;
326   xcbEvent.sequence = 0;
327   xcbEvent.window = win;
328
329   xcbEvent.data.data16[0] = (short) ((window>>16)&0x0000FFFF);
330   xcbEvent.data.data16[1] = (short)  (window&0x0000FFFF);
331   xcbEvent.data.data16[2] = 27695;
332
333   cookie = xcb_send_event( connection, 0, win, 0x0000, (const char *)&xcbEvent );
334
335
336   if (( error = xcb_request_check( connection, cookie )))
337   {
338     if ( error->error_code != BadWindow )
339     {
340       fprintf ( stderr, "SpaceMouse reported error = %d. Exit ... \n", error->error_code);
341     }
342     return 0;
343   }
344
345   xcb_flush(connection);
346
347   return 1;
348 }
349
350 /*!
351   Close
352 */
353 int SVTK_SpaceMouseXCB::close(xcb_connection_t *connection)
354 {
355   initialize( connection, (xcb_window_t)InputFocus );
356   spaceMouseOn = 0;
357
358   return 1;
359 }
360
361 /*!
362   Custom event handler
363 */
364 int SVTK_SpaceMouseXCB::translateEvent( xcb_connection_t* connection, xcb_client_message_event_t* xcbEvent, MoveEvent* spaceMouseEvent,
365                     double scale, double rScale )
366 {
367   if ( !spaceMouseOn )
368     return 0;
369
370   if ( xcbEvent->response_type == XCB_CLIENT_MESSAGE ) {
371     if ( xcbEvent->type == XCBMotionEvent ) {
372       spaceMouseEvent->type = SpaceMouseMove;
373       spaceMouseEvent->data[ x ] =
374         xcbEvent->data.data16[2] * scale;
375       spaceMouseEvent->data[ y ] =
376         xcbEvent->data.data16[3] * scale;
377       spaceMouseEvent->data[ z ] =
378         xcbEvent->data.data16[4] * scale;
379       spaceMouseEvent->data[ a ] =
380         xcbEvent->data.data16[5] * rScale;
381       spaceMouseEvent->data[ b ] =
382         xcbEvent->data.data16[6] * rScale;
383       spaceMouseEvent->data[ c ] =
384         xcbEvent->data.data16[7] * rScale;
385       spaceMouseEvent->period = xcbEvent->data.data16[8];
386       return 1;
387     }
388     else if ( xcbEvent->type == XCBButtonPressEvent ) {
389       spaceMouseEvent->type = SpaceButtonPress;
390       spaceMouseEvent->button = xcbEvent->data.data16[2];
391       return 2;
392     }
393     else if ( xcbEvent->type == XCBButtonReleaseEvent ) {
394       spaceMouseEvent->type = SpaceButtonRelease;
395       spaceMouseEvent->button = xcbEvent->data.data16[2];
396       return 3;
397     }
398   }
399   return (!connection);
400 }
401 #endif
402 #endif