2006-12-21 20:19:14 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and / or modified under
* the terms of the OpenSceneGraph Public License ( OSGPL ) version 0.0 or
* ( at your option ) any later version . The full license is in LICENSE file
* included with this distribution , and on the openscenegraph . org website .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* OpenSceneGraph Public License for more details .
*/
/* Note, elements of GraphicsWindowX11 have used Prodcer/RenderSurface_X11.cpp as both
* a guide to use of X11 / GLX and copiying directly in the case of setBorder ( ) .
* These elements are license under OSGPL as above , with Copyright ( C ) 2001 - 2004 Don Burns .
*/
2007-04-10 19:03:37 +08:00
# include <osgViewer/api/X11/GraphicsWindowX11>
2007-06-20 01:12:05 +08:00
# include <osgViewer/api/X11/PixelBufferX11>
2006-12-21 20:19:14 +08:00
2007-07-06 21:08:51 +08:00
# include <osg/DeleteHandler>
2006-12-21 20:24:20 +08:00
# include <X11/Xlib.h>
# include <X11/Xutil.h>
# include <X11/Xmd.h>
# include <X11/keysym.h>
# include <X11/cursorfont.h>
2007-04-25 17:32:12 +08:00
# include <X11/Xmd.h> /* For CARD16 */
2006-12-21 20:24:20 +08:00
2007-12-21 21:32:13 +08:00
# ifdef OSGVIEWER_USE_XRANDR
# include <X11/extensions/Xrandr.h>
# endif
2007-04-14 16:31:40 +08:00
# include <unistd.h>
2006-12-21 20:19:14 +08:00
using namespace osgViewer ;
2007-01-02 02:20:10 +08:00
class X11KeyboardMap
{
public :
X11KeyboardMap ( )
{
_keymap [ XK_Escape ] = osgGA : : GUIEventAdapter : : KEY_Escape ;
_keymap [ XK_F1 ] = osgGA : : GUIEventAdapter : : KEY_F1 ;
_keymap [ XK_F2 ] = osgGA : : GUIEventAdapter : : KEY_F2 ;
_keymap [ XK_F3 ] = osgGA : : GUIEventAdapter : : KEY_F3 ;
_keymap [ XK_F4 ] = osgGA : : GUIEventAdapter : : KEY_F4 ;
_keymap [ XK_F5 ] = osgGA : : GUIEventAdapter : : KEY_F5 ;
_keymap [ XK_F6 ] = osgGA : : GUIEventAdapter : : KEY_F6 ;
_keymap [ XK_F7 ] = osgGA : : GUIEventAdapter : : KEY_F7 ;
_keymap [ XK_F8 ] = osgGA : : GUIEventAdapter : : KEY_F8 ;
_keymap [ XK_F9 ] = osgGA : : GUIEventAdapter : : KEY_F9 ;
_keymap [ XK_F10 ] = osgGA : : GUIEventAdapter : : KEY_F10 ;
_keymap [ XK_F11 ] = osgGA : : GUIEventAdapter : : KEY_F11 ;
_keymap [ XK_F12 ] = osgGA : : GUIEventAdapter : : KEY_F12 ;
_keymap [ XK_quoteleft ] = ' " ' ;
_keymap [ XK_1 ] = ' 1 ' ;
_keymap [ XK_2 ] = ' 2 ' ;
_keymap [ XK_3 ] = ' 3 ' ;
_keymap [ XK_4 ] = ' 4 ' ;
_keymap [ XK_5 ] = ' 5 ' ;
_keymap [ XK_6 ] = ' 6 ' ;
_keymap [ XK_7 ] = ' 7 ' ;
_keymap [ XK_8 ] = ' 8 ' ;
_keymap [ XK_9 ] = ' 9 ' ;
_keymap [ XK_0 ] = ' 0 ' ;
_keymap [ XK_minus ] = ' - ' ;
_keymap [ XK_equal ] = ' = ' ;
_keymap [ XK_BackSpace ] = osgGA : : GUIEventAdapter : : KEY_BackSpace ;
_keymap [ XK_Tab ] = osgGA : : GUIEventAdapter : : KEY_Tab ;
_keymap [ XK_a ] = ' A ' ;
_keymap [ XK_b ] = ' B ' ;
_keymap [ XK_c ] = ' C ' ;
_keymap [ XK_d ] = ' D ' ;
_keymap [ XK_e ] = ' E ' ;
_keymap [ XK_f ] = ' F ' ;
_keymap [ XK_g ] = ' G ' ;
_keymap [ XK_h ] = ' H ' ;
_keymap [ XK_i ] = ' I ' ;
_keymap [ XK_j ] = ' J ' ;
_keymap [ XK_k ] = ' K ' ;
_keymap [ XK_l ] = ' L ' ;
_keymap [ XK_m ] = ' M ' ;
_keymap [ XK_n ] = ' N ' ;
_keymap [ XK_o ] = ' O ' ;
_keymap [ XK_p ] = ' P ' ;
_keymap [ XK_q ] = ' Q ' ;
_keymap [ XK_r ] = ' R ' ;
_keymap [ XK_s ] = ' S ' ;
_keymap [ XK_t ] = ' T ' ;
_keymap [ XK_u ] = ' U ' ;
_keymap [ XK_v ] = ' V ' ;
_keymap [ XK_w ] = ' W ' ;
_keymap [ XK_x ] = ' X ' ;
_keymap [ XK_y ] = ' Y ' ;
_keymap [ XK_z ] = ' Z ' ;
_keymap [ XK_bracketleft ] = ' ( ' ;
_keymap [ XK_bracketright ] = ' ) ' ;
_keymap [ XK_backslash ] = ' \\ ' ;
_keymap [ XK_Caps_Lock ] = osgGA : : GUIEventAdapter : : KEY_Caps_Lock ;
_keymap [ XK_semicolon ] = ' ; ' ;
_keymap [ XK_apostrophe ] = ' \' ' ;
_keymap [ XK_Return ] = osgGA : : GUIEventAdapter : : KEY_Return ;
_keymap [ XK_Shift_L ] = osgGA : : GUIEventAdapter : : KEY_Shift_L ;
_keymap [ XK_comma ] = ' , ' ;
_keymap [ XK_period ] = ' . ' ;
_keymap [ XK_slash ] = ' / ' ;
_keymap [ XK_Shift_R ] = osgGA : : GUIEventAdapter : : KEY_Shift_R ;
_keymap [ XK_Control_L ] = osgGA : : GUIEventAdapter : : KEY_Control_L ;
_keymap [ XK_Super_L ] = osgGA : : GUIEventAdapter : : KEY_Super_L ;
_keymap [ XK_space ] = ' ' ;
_keymap [ XK_Alt_L ] = osgGA : : GUIEventAdapter : : KEY_Alt_L ;
_keymap [ XK_Alt_R ] = osgGA : : GUIEventAdapter : : KEY_Alt_R ;
_keymap [ XK_Super_R ] = osgGA : : GUIEventAdapter : : KEY_Super_R ;
_keymap [ XK_Menu ] = osgGA : : GUIEventAdapter : : KEY_Menu ;
_keymap [ XK_Control_R ] = osgGA : : GUIEventAdapter : : KEY_Control_R ;
_keymap [ XK_Print ] = osgGA : : GUIEventAdapter : : KEY_Print ;
_keymap [ XK_Scroll_Lock ] = osgGA : : GUIEventAdapter : : KEY_Scroll_Lock ;
_keymap [ XK_Pause ] = osgGA : : GUIEventAdapter : : KEY_Pause ;
_keymap [ XK_Home ] = osgGA : : GUIEventAdapter : : KEY_Home ;
_keymap [ XK_Page_Up ] = osgGA : : GUIEventAdapter : : KEY_Page_Up ;
_keymap [ XK_End ] = osgGA : : GUIEventAdapter : : KEY_End ;
_keymap [ XK_Page_Down ] = osgGA : : GUIEventAdapter : : KEY_Page_Down ;
_keymap [ XK_Delete ] = osgGA : : GUIEventAdapter : : KEY_Delete ;
_keymap [ XK_Insert ] = osgGA : : GUIEventAdapter : : KEY_Insert ;
_keymap [ XK_Left ] = osgGA : : GUIEventAdapter : : KEY_Left ;
_keymap [ XK_Up ] = osgGA : : GUIEventAdapter : : KEY_Up ;
_keymap [ XK_Right ] = osgGA : : GUIEventAdapter : : KEY_Right ;
_keymap [ XK_Down ] = osgGA : : GUIEventAdapter : : KEY_Down ;
_keymap [ XK_Num_Lock ] = osgGA : : GUIEventAdapter : : KEY_Num_Lock ;
_keymap [ XK_KP_Divide ] = osgGA : : GUIEventAdapter : : KEY_KP_Divide ;
_keymap [ XK_KP_Multiply ] = osgGA : : GUIEventAdapter : : KEY_KP_Multiply ;
_keymap [ XK_KP_Subtract ] = osgGA : : GUIEventAdapter : : KEY_KP_Subtract ;
_keymap [ XK_KP_Add ] = osgGA : : GUIEventAdapter : : KEY_KP_Add ;
_keymap [ XK_KP_Home ] = osgGA : : GUIEventAdapter : : KEY_KP_Home ;
_keymap [ XK_KP_Up ] = osgGA : : GUIEventAdapter : : KEY_KP_Up ;
_keymap [ XK_KP_Page_Up ] = osgGA : : GUIEventAdapter : : KEY_KP_Page_Up ;
_keymap [ XK_KP_Left ] = osgGA : : GUIEventAdapter : : KEY_KP_Left ;
_keymap [ XK_KP_Begin ] = osgGA : : GUIEventAdapter : : KEY_KP_Begin ;
_keymap [ XK_KP_Right ] = osgGA : : GUIEventAdapter : : KEY_KP_Right ;
_keymap [ XK_KP_End ] = osgGA : : GUIEventAdapter : : KEY_KP_End ;
_keymap [ XK_KP_Down ] = osgGA : : GUIEventAdapter : : KEY_KP_Down ;
_keymap [ XK_KP_Page_Down ] = osgGA : : GUIEventAdapter : : KEY_KP_Page_Down ;
_keymap [ XK_KP_Insert ] = osgGA : : GUIEventAdapter : : KEY_KP_Insert ;
_keymap [ XK_KP_Delete ] = osgGA : : GUIEventAdapter : : KEY_KP_Delete ;
_keymap [ XK_KP_Enter ] = osgGA : : GUIEventAdapter : : KEY_KP_Enter ;
}
~ X11KeyboardMap ( ) { }
int remapKey ( int key )
{
KeyMap : : iterator itr = _keymap . find ( key ) ;
if ( itr = = _keymap . end ( ) ) return key ;
else return itr - > second ;
}
protected :
typedef std : : map < int , int > KeyMap ;
KeyMap _keymap ;
} ;
static int remapX11Key ( int key )
{
static X11KeyboardMap s_x11KeyboardMap ;
return s_x11KeyboardMap . remapKey ( key ) ;
}
2007-01-04 00:06:12 +08:00
GraphicsWindowX11 : : ~ GraphicsWindowX11 ( )
{
close ( true ) ;
}
2007-04-13 21:22:52 +08:00
Display * GraphicsWindowX11 : : getDisplayToUse ( ) const
{
if ( _threadOfLastMakeCurrent = = 0 )
{
return _display ;
}
if ( OpenThreads : : Thread : : CurrentThread ( ) = = _threadOfLastMakeCurrent )
{
return _display ;
}
else
{
return _eventDisplay ;
}
}
2006-12-21 20:19:14 +08:00
bool GraphicsWindowX11 : : createVisualInfo ( )
{
2007-09-26 17:50:32 +08:00
if ( _window ! = 0 )
{
XWindowAttributes watt ;
XGetWindowAttributes ( _display , _window , & watt ) ;
XVisualInfo temp ;
temp . visualid = XVisualIDFromVisual ( watt . visual ) ;
int n ;
_visualInfo = XGetVisualInfo ( _display , VisualIDMask , & temp , & n ) ;
}
else
{
2006-12-23 05:53:44 +08:00
2007-09-26 17:50:32 +08:00
typedef std : : vector < int > Attributes ;
Attributes attributes ;
attributes . push_back ( GLX_USE_GL ) ;
attributes . push_back ( GLX_RGBA ) ;
if ( _traits - > doubleBuffer ) attributes . push_back ( GLX_DOUBLEBUFFER ) ;
if ( _traits - > quadBufferStereo ) attributes . push_back ( GLX_STEREO ) ;
attributes . push_back ( GLX_RED_SIZE ) ; attributes . push_back ( _traits - > red ) ;
attributes . push_back ( GLX_GREEN_SIZE ) ; attributes . push_back ( _traits - > green ) ;
attributes . push_back ( GLX_BLUE_SIZE ) ; attributes . push_back ( _traits - > blue ) ;
attributes . push_back ( GLX_DEPTH_SIZE ) ; attributes . push_back ( _traits - > depth ) ;
if ( _traits - > alpha ) { attributes . push_back ( GLX_ALPHA_SIZE ) ; attributes . push_back ( _traits - > alpha ) ; }
if ( _traits - > stencil ) { attributes . push_back ( GLX_STENCIL_SIZE ) ; attributes . push_back ( _traits - > stencil ) ; }
2006-12-21 20:19:14 +08:00
2007-09-26 17:50:32 +08:00
# if defined(GLX_SAMPLE_BUFFERS) && defined (GLX_SAMPLES)
2006-12-21 20:19:14 +08:00
2007-09-26 17:50:32 +08:00
if ( _traits - > sampleBuffers ) { attributes . push_back ( GLX_SAMPLE_BUFFERS ) ; attributes . push_back ( _traits - > sampleBuffers ) ; }
if ( _traits - > sampleBuffers ) { attributes . push_back ( GLX_SAMPLES ) ; attributes . push_back ( _traits - > samples ) ; }
# endif
// TODO
// GLX_AUX_BUFFERS
// GLX_ACCUM_RED_SIZE
// GLX_ACCUM_GREEN_SIZE
// GLX_SAMPLE_BUFFERS
// GLX_SAMPLES
attributes . push_back ( None ) ;
_visualInfo = glXChooseVisual ( _display , _traits - > screenNum , & ( attributes . front ( ) ) ) ;
}
2006-12-21 20:19:14 +08:00
return _visualInfo ! = 0 ;
}
2007-06-24 05:55:35 +08:00
# define MWM_HINTS_FUNCTIONS (1L << 0)
# define MWM_HINTS_DECORATIONS (1L << 1)
# define MWM_HINTS_INPUT_MODE (1L << 2)
# define MWM_HINTS_STATUS (1L << 3)
# define MWM_DECOR_ALL (1L<<0)
# define MWM_DECOR_BORDER (1L<<1)
# define MWM_DECOR_RESIZEH (1L<<2)
# define MWM_DECOR_TITLE (1L<<3)
# define MWM_DECOR_MENU (1L<<4)
# define MWM_DECOR_MINIMIZE (1L<<5)
# define MWM_DECOR_MAXIMIZE (1L<<6)
# define MWM_FUNC_ALL (1L<<0)
# define MWM_FUNC_RESIZE (1L<<1)
# define MWM_FUNC_MOVE (1L<<2)
# define MWM_FUNC_MINIMIZE (1L<<3)
# define MWM_FUNC_MAXIMIZE (1L<<4)
# define MWM_FUNC_CLOSE (1L<<5)
2006-12-21 20:19:14 +08:00
2007-12-07 01:28:29 +08:00
bool GraphicsWindowX11 : : checkAndSendEventFullScreenIfNeeded ( Display * display , int x , int y , int width , int height , bool windowDecoration )
{
osg : : GraphicsContext : : WindowingSystemInterface * wsi = osg : : GraphicsContext : : getWindowingSystemInterface ( ) ;
if ( wsi = = NULL ) {
osg : : notify ( osg : : NOTICE ) < < " Error, no WindowSystemInterface available, cannot toggle window fullscreen. " < < std : : endl ;
return false ;
}
unsigned int screenWidth ;
unsigned int screenHeight ;
wsi - > getScreenResolution ( * _traits , screenWidth , screenHeight ) ;
bool isFullScreen = x = = 0 & & y = = 0 & & width = = ( int ) screenWidth & & height = = ( int ) screenHeight & & ! windowDecoration ;
Atom netWMStateAtom = XInternAtom ( display , " _NET_WM_STATE " , True ) ;
Atom netWMStateFullscreenAtom = XInternAtom ( display ,
" _NET_WM_STATE_FULLSCREEN " , True ) ;
if ( netWMStateAtom ! = None & & netWMStateFullscreenAtom ! = None ) {
XEvent xev ;
xev . xclient . type = ClientMessage ;
xev . xclient . serial = 0 ;
xev . xclient . send_event = True ;
xev . xclient . window = _window ;
xev . xclient . message_type = netWMStateAtom ;
xev . xclient . format = 32 ;
xev . xclient . data . l [ 0 ] = isFullScreen ? 1 : 0 ;
xev . xclient . data . l [ 1 ] = netWMStateFullscreenAtom ;
xev . xclient . data . l [ 2 ] = 0 ;
XSendEvent ( display , RootWindow ( display , DefaultScreen ( display ) ) ,
False , SubstructureRedirectMask | SubstructureNotifyMask , & xev ) ;
return true ;
}
return false ;
}
2007-06-11 03:53:18 +08:00
bool GraphicsWindowX11 : : setWindowDecorationImplementation ( bool flag )
2006-12-21 20:19:14 +08:00
{
2007-04-13 21:22:52 +08:00
Display * display = getDisplayToUse ( ) ;
2007-12-07 01:28:29 +08:00
XMapWindow ( display , _window ) ;
checkAndSendEventFullScreenIfNeeded ( display , _traits - > x , _traits - > y , _traits - > width , _traits - > height , flag ) ;
struct
{
unsigned long flags ;
unsigned long functions ;
unsigned long decorations ;
long inputMode ;
unsigned long status ;
} wmHints ;
2006-12-21 20:19:14 +08:00
Atom atom ;
2007-12-07 01:28:29 +08:00
bool result = false ;
2007-02-09 21:51:28 +08:00
if ( ( atom = XInternAtom ( display , " _MOTIF_WM_HINTS " , 0 ) ) ! = None )
2006-12-21 20:19:14 +08:00
{
2007-06-24 05:55:35 +08:00
wmHints . flags = 0 ;
wmHints . functions = MWM_FUNC_ALL ;
wmHints . decorations = MWM_DECOR_ALL ;
wmHints . inputMode = 0 ;
wmHints . status = 0 ;
if ( ! flag )
{
wmHints . flags = MWM_HINTS_DECORATIONS ;
wmHints . decorations = 0 ;
}
else
{
wmHints . flags | = MWM_HINTS_FUNCTIONS ;
if ( _traits . valid ( ) & & ! _traits - > supportsResize ) wmHints . functions | = MWM_FUNC_RESIZE ;
}
XChangeProperty ( display , _window , atom , atom , 32 , PropModeReplace , ( unsigned char * ) & wmHints , 5 ) ;
2007-12-07 01:28:29 +08:00
result = true ;
2006-12-21 20:19:14 +08:00
}
else
2007-06-11 03:53:18 +08:00
{
2006-12-21 20:19:14 +08:00
osg : : notify ( osg : : NOTICE ) < < " Error: GraphicsWindowX11::setBorder( " < < flag < < " ) - couldn't change decorations. " < < std : : endl ;
2007-12-07 01:28:29 +08:00
result = false ;
2007-06-11 03:53:18 +08:00
}
2007-12-07 01:28:29 +08:00
XFlush ( display ) ;
XSync ( display , 0 ) ;
// add usleep here to give window manager a chance to handle the request, if
// we don't add this sleep then any X11 calls right afterwards can produce
// X11 errors.
usleep ( 100000 ) ;
return result ;
2006-12-21 20:19:14 +08:00
}
2007-06-11 03:53:18 +08:00
bool GraphicsWindowX11 : : setWindowRectangleImplementation ( int x , int y , int width , int height )
2007-04-13 21:22:52 +08:00
{
2007-10-01 19:02:02 +08:00
if ( ! _initialized ) return false ;
2007-04-13 21:22:52 +08:00
Display * display = getDisplayToUse ( ) ;
XMoveResizeWindow ( display , _window , x , y , width , height ) ;
XFlush ( display ) ;
XSync ( display , 0 ) ;
2007-04-13 22:54:22 +08:00
2007-12-07 01:28:29 +08:00
checkAndSendEventFullScreenIfNeeded ( display , x , y , width , height , _traits - > windowDecoration ) ;
2007-04-13 22:54:22 +08:00
// add usleep here to give window manager a chance to handle the request, if
// we don't add this sleep then any X11 calls right afterwards can produce
// X11 errors.
usleep ( 100000 ) ;
2007-12-07 01:28:29 +08:00
2007-06-11 03:53:18 +08:00
return true ;
2007-04-13 21:22:52 +08:00
}
2007-09-26 17:50:32 +08:00
void GraphicsWindowX11 : : setWindowName ( const std : : string & name )
{
2007-10-01 19:02:02 +08:00
if ( _window = = 0 ) return ;
2007-09-26 17:50:32 +08:00
// char *slist[] = { name.c_str(), 0L };
// XTextProperty xtp;
// XStringListToTextProperty( slist, 1, &xtp );
Display * display = getDisplayToUse ( ) ;
if ( ! display ) return ;
// XSetWMName( display, _window, &xtp );
XStoreName ( display , _window , name . c_str ( ) ) ;
XSetIconName ( display , _window , name . c_str ( ) ) ;
XFlush ( display ) ;
XSync ( display , 0 ) ;
2007-10-01 19:02:02 +08:00
_traits - > windowName = name ;
2007-09-26 17:50:32 +08:00
}
2007-06-02 03:43:28 +08:00
void GraphicsWindowX11 : : setCursor ( MouseCursor mouseCursor )
2007-01-02 20:50:57 +08:00
{
2007-06-02 03:43:28 +08:00
Cursor newCursor = getOrCreateCursor ( mouseCursor ) ;
if ( newCursor = = _currentCursor ) return ;
_currentCursor = newCursor ;
if ( ! _window ) return ;
2007-04-13 21:22:52 +08:00
Display * display = getDisplayToUse ( ) ;
2007-06-02 03:43:28 +08:00
if ( ! display ) return ;
XDefineCursor ( display , _window , _currentCursor ) ;
XFlush ( display ) ;
XSync ( display , 0 ) ;
2007-02-09 21:51:28 +08:00
2007-06-02 03:43:28 +08:00
_traits - > useCursor = ( _currentCursor ! = getOrCreateCursor ( NoCursor ) ) ;
}
Cursor GraphicsWindowX11 : : getOrCreateCursor ( MouseCursor mouseCursor )
{
std : : map < MouseCursor , Cursor > : : iterator i = _mouseCursorMap . find ( mouseCursor ) ;
if ( i ! = _mouseCursorMap . end ( ) ) return i - > second ;
2007-01-02 20:50:57 +08:00
2007-06-02 03:43:28 +08:00
Display * display = getDisplayToUse ( ) ;
if ( ! display ) return None ;
switch ( mouseCursor ) {
case NoCursor :
2007-01-02 20:50:57 +08:00
{
2007-06-02 03:43:28 +08:00
// create an empty mouse cursor, note that it is safe to destroy the Pixmap just past cursor creation
// since the resource in the x server is reference counted.
char buff [ 2 ] = { 0 , 0 } ;
XColor ncol = { 0 , 0 , 0 , 0 , DoRed | DoGreen | DoBlue , 0 } ;
Pixmap pixmap = XCreateBitmapFromData ( display , _parent , buff , 1 , 1 ) ;
_mouseCursorMap [ mouseCursor ] = XCreatePixmapCursor ( display , pixmap , pixmap , & ncol , & ncol , 0 , 0 ) ;
XFreePixmap ( display , pixmap ) ;
// Important to have the pixmap and the buffer still available when the request is sent to the server ...
2007-02-09 21:51:28 +08:00
XFlush ( display ) ;
2007-06-02 03:43:28 +08:00
XSync ( display , 0 ) ;
break ;
2007-01-02 20:50:57 +08:00
}
2007-06-02 03:43:28 +08:00
case RightArrowCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_left_ptr ) ;
break ;
case LeftArrowCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_top_left_arrow ) ;
break ;
case InfoCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_hand1 ) ;
break ;
case DestroyCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_pirate ) ;
break ;
case HelpCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_question_arrow ) ;
break ;
case CycleCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_exchange ) ;
break ;
case SprayCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_spraycan ) ;
break ;
case WaitCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_watch ) ;
break ;
case TextCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_xterm ) ;
break ;
case CrosshairCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_crosshair ) ;
break ;
case UpDownCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_sb_v_double_arrow ) ;
break ;
case LeftRightCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_sb_h_double_arrow ) ;
break ;
case TopSideCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_top_side ) ;
break ;
case BottomSideCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_bottom_side ) ;
break ;
case LeftSideCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_left_side ) ;
break ;
case RightSideCursor :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_right_side ) ;
break ;
case TopLeftCorner :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_top_left_corner ) ;
break ;
case TopRightCorner :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_top_right_corner ) ;
break ;
case BottomRightCorner :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_bottom_right_corner ) ;
break ;
case BottomLeftCorner :
_mouseCursorMap [ mouseCursor ] = XCreateFontCursor ( display , XC_bottom_left_corner ) ;
break ;
case InheritCursor :
default :
_mouseCursorMap [ mouseCursor ] = None ;
break ;
} ;
return _mouseCursorMap [ mouseCursor ] ;
2007-01-02 20:50:57 +08:00
}
2007-03-27 00:28:26 +08:00
void GraphicsWindowX11 : : init ( )
2006-12-21 20:19:14 +08:00
{
2006-12-25 00:40:19 +08:00
if ( _initialized ) return ;
if ( ! _traits )
{
_valid = false ;
return ;
}
2007-09-26 17:50:32 +08:00
2007-07-13 19:17:41 +08:00
getEventQueue ( ) - > setCurrentEventState ( osgGA : : GUIEventAdapter : : getAccumulatedEventState ( ) . get ( ) ) ;
2007-09-26 17:50:32 +08:00
WindowData * inheritedWindowData = dynamic_cast < WindowData * > ( _traits - > inheritedWindowData . get ( ) ) ;
Window windowHandle = inheritedWindowData ? inheritedWindowData - > _window : 0 ;
_ownsWindow = windowHandle = = 0 ;
2006-12-21 20:19:14 +08:00
2006-12-23 05:53:44 +08:00
_display = XOpenDisplay ( _traits - > displayName ( ) . c_str ( ) ) ;
2006-12-21 20:19:14 +08:00
if ( ! _display )
{
2006-12-25 00:40:19 +08:00
osg : : notify ( osg : : NOTICE ) < < " Error: Unable to open display \" " < < XDisplayName ( _traits - > displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
_valid = false ;
return ;
2006-12-21 20:19:14 +08:00
}
2007-09-26 17:50:32 +08:00
// Query for GLX extension
2006-12-21 20:19:14 +08:00
int errorBase , eventBase ;
if ( glXQueryExtension ( _display , & errorBase , & eventBase ) = = False )
{
2006-12-23 05:53:44 +08:00
osg : : notify ( osg : : NOTICE ) < < " Error: " < < XDisplayName ( _traits - > displayName ( ) . c_str ( ) ) < < " has no GLX extension. " < < std : : endl ;
2006-12-21 20:19:14 +08:00
XCloseDisplay ( _display ) ;
_display = 0 ;
2006-12-25 00:40:19 +08:00
_valid = false ;
2006-12-21 20:19:14 +08:00
return ;
}
2007-09-26 17:50:32 +08:00
2006-12-21 20:19:14 +08:00
// osg::notify(osg::NOTICE)<<"GLX extension, errorBase="<<errorBase<<" eventBase="<<eventBase<<std::endl;
if ( ! createVisualInfo ( ) )
{
2007-01-29 01:32:41 +08:00
_traits - > red / = 2 ;
_traits - > green / = 2 ;
_traits - > blue / = 2 ;
_traits - > alpha / = 2 ;
_traits - > depth / = 2 ;
osg : : notify ( osg : : INFO ) < < " Relaxing traits " < < std : : endl ;
if ( ! createVisualInfo ( ) )
{
osg : : notify ( osg : : NOTICE ) < < " Error: Not able to create requested visual. " < < std : : endl ;
XCloseDisplay ( _display ) ;
_display = 0 ;
_valid = false ;
return ;
}
2006-12-21 20:19:14 +08:00
}
2007-09-26 17:50:32 +08:00
2007-06-20 01:12:05 +08:00
GLXContext sharedContextGLX = NULL ;
// get any shared GLX contexts
GraphicsWindowX11 * graphicsWindowX11 = dynamic_cast < GraphicsWindowX11 * > ( _traits - > sharedContext ) ;
if ( graphicsWindowX11 )
2007-02-15 20:24:04 +08:00
{
2007-06-20 01:12:05 +08:00
sharedContextGLX = graphicsWindowX11 - > getGLXContext ( ) ;
2007-02-15 20:24:04 +08:00
}
else
{
2007-06-20 01:12:05 +08:00
PixelBufferX11 * pixelBufferX11 = dynamic_cast < PixelBufferX11 * > ( _traits - > sharedContext ) ;
2007-09-13 01:01:47 +08:00
if ( pixelBufferX11 & & pixelBufferX11 - > valid ( ) )
2007-06-20 01:12:05 +08:00
{
sharedContextGLX = pixelBufferX11 - > getGLXContext ( ) ;
}
2007-02-15 20:24:04 +08:00
}
2006-12-21 20:19:14 +08:00
2007-06-20 01:12:05 +08:00
_glxContext = glXCreateContext ( _display , _visualInfo , sharedContextGLX , True ) ;
2006-12-21 20:19:14 +08:00
if ( ! _glxContext )
{
osg : : notify ( osg : : NOTICE ) < < " Error: Unable to create OpenGL graphics context. " < < std : : endl ;
2006-12-25 00:40:19 +08:00
XCloseDisplay ( _display ) ;
_display = 0 ;
_valid = false ;
2006-12-21 20:19:14 +08:00
return ;
}
2007-09-26 17:50:32 +08:00
_initialized = _ownsWindow ? createWindow ( ) : setWindow ( windowHandle ) ;
_valid = _initialized ;
if ( _valid = = false )
{
XCloseDisplay ( _display ) ;
2007-10-01 19:02:02 +08:00
_display = 0 ;
2007-09-26 17:50:32 +08:00
}
}
bool GraphicsWindowX11 : : createWindow ( )
{
unsigned int screen = _traits - > screenNum ;
2007-04-13 21:22:52 +08:00
_eventDisplay = XOpenDisplay ( _traits - > displayName ( ) . c_str ( ) ) ;
2006-12-21 20:19:14 +08:00
_parent = RootWindow ( _display , screen ) ;
XWindowAttributes watt ;
XGetWindowAttributes ( _display , _parent , & watt ) ;
// unsigned int parentWindowHeight = watt.height;
XSetWindowAttributes swatt ;
swatt . colormap = XCreateColormap ( _display , _parent , _visualInfo - > visual , AllocNone ) ;
//swatt.colormap = DefaultColormap( _dpy, 10 );
swatt . background_pixel = 0 ;
swatt . border_pixel = 0 ;
swatt . event_mask = 0 ;
unsigned long mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap ;
bool overrideRedirect = false ;
if ( overrideRedirect )
{
swatt . override_redirect = true ;
mask | = CWOverrideRedirect ;
}
_window = XCreateWindow ( _display , _parent ,
2006-12-23 05:53:44 +08:00
_traits - > x ,
_traits - > y ,
_traits - > width , _traits - > height , 0 ,
2006-12-21 20:19:14 +08:00
_visualInfo - > depth , InputOutput ,
_visualInfo - > visual , mask , & swatt ) ;
if ( ! _window )
{
osg : : notify ( osg : : NOTICE ) < < " Error: Unable to create Window. " < < std : : endl ;
2006-12-25 00:40:19 +08:00
_glxContext = 0 ;
2007-09-26 17:50:32 +08:00
return false ;
2006-12-21 20:19:14 +08:00
}
2007-02-09 21:51:28 +08:00
2006-12-21 20:19:14 +08:00
// This positions the window at _windowX, _windowY
XSizeHints sh ;
sh . flags = 0 ;
sh . flags | = USSize ;
sh . flags & = 0x7 ;
sh . flags | = USPosition ;
sh . flags & = 0xB ;
2006-12-23 05:53:44 +08:00
sh . x = _traits - > x ;
sh . y = _traits - > y ;
sh . width = _traits - > width ;
sh . height = _traits - > height ;
XSetStandardProperties ( _display , _window , _traits - > windowName . c_str ( ) , _traits - > windowName . c_str ( ) , None , 0 , 0 , & sh ) ;
2006-12-21 20:19:14 +08:00
2006-12-23 05:53:44 +08:00
setWindowDecoration ( _traits - > windowDecoration ) ;
2007-04-13 21:22:52 +08:00
2007-01-18 05:11:57 +08:00
useCursor ( _traits - > useCursor ) ;
2006-12-21 20:19:14 +08:00
2007-02-09 21:51:28 +08:00
_deleteWindow = XInternAtom ( _display , " WM_DELETE_WINDOW " , False ) ;
XSetWMProtocols ( _display , _window , & _deleteWindow , 1 ) ;
2006-12-21 20:19:14 +08:00
XFlush ( _display ) ;
XSync ( _display , 0 ) ;
// now update the window dimensions to account for any size changes made by the window manager,
XGetWindowAttributes ( _display , _window , & watt ) ;
2007-01-02 02:20:10 +08:00
if ( _traits - > width ! = watt . width & & _traits - > height ! = watt . height )
{
resized ( _traits - > x , _traits - > y , _traits - > width , _traits - > height ) ;
}
2006-12-21 20:19:14 +08:00
//osg::notify(osg::NOTICE)<<"After sync apply.x = "<<watt.x<<" watt.y="<<watt.y<<" width="<<watt.width<<" height="<<watt.height<<std::endl;
2007-02-09 21:51:28 +08:00
XSelectInput ( _eventDisplay , _window , ExposureMask | StructureNotifyMask |
KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask ) ;
XFlush ( _eventDisplay ) ;
XSync ( _eventDisplay , 0 ) ;
2007-01-04 07:00:05 +08:00
2007-09-26 17:50:32 +08:00
return true ;
}
bool GraphicsWindowX11 : : setWindow ( Window window )
{
if ( _initialized )
{
osg : : notify ( osg : : NOTICE ) < < " GraphicsWindowX11::setWindow() - Window already created; it cannot be changed " ;
return false ;
}
if ( window = = 0 )
{
osg : : notify ( osg : : NOTICE ) < < " GraphicsWindowX11::setWindow() - Invalid window handle passed " ;
return false ;
}
_window = window ;
if ( _window = = 0 )
{
osg : : notify ( osg : : NOTICE ) < < " GraphicsWindowX11::setWindow() - Unable to retrieve native window handle " ;
return false ;
}
XWindowAttributes watt ;
XGetWindowAttributes ( _display , _window , & watt ) ;
_traits - > x = watt . x ;
_traits - > y = watt . y ;
_traits - > width = watt . width ;
_traits - > height = watt . height ;
_parent = DefaultRootWindow ( _display ) ;
//_traits->supportsResize = false;
_traits - > windowDecoration = false ;
2007-10-01 19:02:02 +08:00
if ( _traits - > windowName . size ( ) ) setWindowName ( _traits - > windowName ) ;
2007-09-26 17:50:32 +08:00
_eventDisplay = XOpenDisplay ( _traits - > displayName ( ) . c_str ( ) ) ;
XFlush ( _eventDisplay ) ;
XSync ( _eventDisplay , 0 ) ;
return true ;
2006-12-21 20:19:14 +08:00
}
bool GraphicsWindowX11 : : realizeImplementation ( )
{
2006-12-23 01:46:21 +08:00
if ( _realized )
{
osg : : notify ( osg : : NOTICE ) < < " GraphicsWindowX11::realizeImplementation() Already realized " < < std : : endl ;
return true ;
}
2006-12-21 20:19:14 +08:00
if ( ! _initialized ) init ( ) ;
if ( ! _initialized ) return false ;
XMapWindow ( _display , _window ) ;
2006-12-27 01:38:47 +08:00
// Window temp = _window;
// XSetWMColormapWindows( _display, _window, &temp, 1);
2006-12-21 20:19:14 +08:00
_realized = true ;
return true ;
}
2007-01-09 03:29:59 +08:00
bool GraphicsWindowX11 : : makeCurrentImplementation ( )
2006-12-21 20:19:14 +08:00
{
2007-01-04 00:06:12 +08:00
if ( ! _realized )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: GraphicsWindow not realized, cannot do makeCurrent. " < < std : : endl ;
2007-01-09 03:29:59 +08:00
return false ;
2007-01-04 00:06:12 +08:00
}
2006-12-25 00:40:19 +08:00
2007-06-20 01:12:05 +08:00
// osg::notify(osg::NOTICE)<<"GraphicsWindowX11::makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
2006-12-23 01:46:21 +08:00
// osg::notify(osg::NOTICE)<<" glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
2007-01-09 03:29:59 +08:00
return glXMakeCurrent ( _display , _window , _glxContext ) = = True ;
}
2007-01-04 00:06:12 +08:00
2007-01-09 03:29:59 +08:00
bool GraphicsWindowX11 : : releaseContextImplementation ( )
{
if ( ! _realized )
{
2007-10-01 19:02:02 +08:00
osg : : notify ( osg : : NOTICE ) < < " Warning: GraphicsWindow not realized, cannot do release context. " < < std : : endl ;
2007-01-09 03:29:59 +08:00
return false ;
2007-01-04 00:06:12 +08:00
}
2007-06-20 01:12:05 +08:00
// osg::notify(osg::NOTICE)<<"GraphicsWindowX11::releaseContextImplementation() "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
// osg::notify(osg::NOTICE)<<" glXMakeCurrent ("<<_display<<std::endl;
2007-01-09 03:29:59 +08:00
return glXMakeCurrent ( _display , None , NULL ) = = True ;
2006-12-21 20:19:14 +08:00
}
void GraphicsWindowX11 : : closeImplementation ( )
{
2007-01-04 00:06:12 +08:00
// osg::notify(osg::NOTICE)<<"Closing GraphicsWindowX11"<<std::endl;
2007-02-09 21:51:28 +08:00
if ( _eventDisplay )
2006-12-25 00:40:19 +08:00
{
2007-02-09 21:51:28 +08:00
XCloseDisplay ( _eventDisplay ) ;
_eventDisplay = 0 ;
}
if ( _display )
{
if ( _glxContext )
{
glXDestroyContext ( _display , _glxContext ) ;
}
2007-10-01 19:02:02 +08:00
if ( _window & & _ownsWindow )
2007-02-09 21:51:28 +08:00
{
XDestroyWindow ( _display , _window ) ;
}
2006-12-25 00:40:19 +08:00
XFlush ( _display ) ;
XSync ( _display , 0 ) ;
}
2007-02-08 19:30:57 +08:00
2006-12-21 20:19:14 +08:00
_window = 0 ;
_parent = 0 ;
2007-01-04 22:34:53 +08:00
_glxContext = 0 ;
2006-12-25 00:40:19 +08:00
2007-02-08 19:30:57 +08:00
if ( _visualInfo )
2006-12-21 20:19:14 +08:00
{
XFree ( _visualInfo ) ;
_visualInfo = 0 ;
}
2007-02-09 21:51:28 +08:00
2007-02-08 19:30:57 +08:00
if ( _display )
{
XCloseDisplay ( _display ) ;
_display = 0 ;
}
2006-12-21 20:19:14 +08:00
_initialized = false ;
_realized = false ;
2007-01-04 19:49:15 +08:00
_valid = false ;
2006-12-21 20:19:14 +08:00
}
void GraphicsWindowX11 : : swapBuffersImplementation ( )
{
2006-12-25 00:40:19 +08:00
if ( ! _realized ) return ;
2006-12-23 01:46:21 +08:00
// osg::notify(osg::NOTICE)<<"swapBuffersImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
2007-09-26 17:50:32 +08:00
glXSwapBuffers ( _display , _window ) ;
2007-02-09 21:51:28 +08:00
while ( XPending ( _display ) )
{
XEvent ev ;
XNextEvent ( _display , & ev ) ;
switch ( ev . type )
{
case ClientMessage :
{
if ( static_cast < Atom > ( ev . xclient . data . l [ 0 ] ) = = _deleteWindow )
{
osg : : notify ( osg : : INFO ) < < " DeleteWindow event recieved " < < std : : endl ;
getEventQueue ( ) - > closeWindow ( ) ;
}
}
}
}
2006-12-21 20:19:14 +08:00
}
void GraphicsWindowX11 : : checkEvents ( )
{
2006-12-25 00:40:19 +08:00
if ( ! _realized ) return ;
2007-04-16 04:53:09 +08:00
Display * display = _eventDisplay ;
2007-02-09 21:51:28 +08:00
2007-01-05 21:01:08 +08:00
double baseTime = _timeOfLastCheckEvents ;
double eventTime = baseTime ;
double resizeTime = eventTime ;
_timeOfLastCheckEvents = getEventQueue ( ) - > getTime ( ) ;
2007-01-02 02:20:10 +08:00
int windowX = _traits - > x ;
int windowY = _traits - > y ;
int windowWidth = _traits - > width ;
int windowHeight = _traits - > height ;
2007-01-05 00:49:58 +08:00
bool destroyWindowRequested = false ;
2007-01-05 21:01:08 +08:00
Time firstEventTime = 0 ;
2007-01-04 07:00:05 +08:00
// osg::notify(osg::NOTICE)<<"Check events"<<std::endl;
2007-02-09 21:51:28 +08:00
while ( XPending ( display ) )
2006-12-21 20:19:14 +08:00
{
XEvent ev ;
2007-02-09 21:51:28 +08:00
XNextEvent ( display , & ev ) ;
2006-12-21 20:19:14 +08:00
switch ( ev . type )
{
2007-01-04 07:00:05 +08:00
case ClientMessage :
{
2007-02-09 21:51:28 +08:00
osg : : notify ( osg : : NOTICE ) < < " ClientMessage event recieved " < < std : : endl ;
2007-01-04 19:49:15 +08:00
if ( static_cast < Atom > ( ev . xclient . data . l [ 0 ] ) = = _deleteWindow )
2007-01-04 07:00:05 +08:00
{
2007-02-09 21:51:28 +08:00
osg : : notify ( osg : : NOTICE ) < < " DeleteWindow event recieved " < < std : : endl ;
2007-09-26 17:50:32 +08:00
// FIXME only do if _ownsWindow ?
2007-01-05 00:49:58 +08:00
destroyWindowRequested = true ;
2007-01-09 03:29:59 +08:00
getEventQueue ( ) - > closeWindow ( eventTime ) ;
2007-01-04 07:00:05 +08:00
}
}
2006-12-21 20:19:14 +08:00
case Expose :
2006-12-22 00:56:20 +08:00
osg : : notify ( osg : : INFO ) < < " Expose x= " < < ev . xexpose . x < < " y= " < < ev . xexpose . y < < " width= " < < ev . xexpose . width < < " , height= " < < ev . xexpose . height < < std : : endl ;
2006-12-21 20:19:14 +08:00
break ;
case GravityNotify :
2007-01-04 19:49:15 +08:00
osg : : notify ( osg : : INFO ) < < " GravityNotify event recieved " < < std : : endl ;
2006-12-21 20:19:14 +08:00
break ;
case UnmapNotify :
2007-01-04 19:49:15 +08:00
osg : : notify ( osg : : INFO ) < < " UnmapNotify event recieved " < < std : : endl ;
2006-12-21 20:19:14 +08:00
break ;
case ReparentNotify :
2007-01-04 19:49:15 +08:00
osg : : notify ( osg : : INFO ) < < " ReparentNotify event recieved " < < std : : endl ;
2006-12-21 20:19:14 +08:00
break ;
case DestroyNotify :
2007-02-09 21:51:28 +08:00
osg : : notify ( osg : : NOTICE ) < < " DestroyNotify event recieved " < < std : : endl ;
2006-12-21 20:19:14 +08:00
_realized = false ;
2007-01-04 19:49:15 +08:00
_valid = false ;
2006-12-21 20:19:14 +08:00
break ;
case ConfigureNotify :
{
2006-12-22 00:56:20 +08:00
osg : : notify ( osg : : INFO ) < < " ConfigureNotify x= " < < ev . xconfigure . x < < " y= " < < ev . xconfigure . y < < " width= " < < ev . xconfigure . width < < " , height= " < < ev . xconfigure . height < < std : : endl ;
2006-12-21 20:19:14 +08:00
2007-01-02 02:20:10 +08:00
if ( windowX ! = ev . xconfigure . x | |
windowX ! = ev . xconfigure . y | |
windowWidth ! = ev . xconfigure . width | |
windowHeight ! = ev . xconfigure . height )
{
2007-01-05 21:01:08 +08:00
resizeTime = eventTime ;
2007-01-02 02:20:10 +08:00
windowX = ev . xconfigure . x ;
windowY = ev . xconfigure . y ;
windowWidth = ev . xconfigure . width ;
windowHeight = ev . xconfigure . height ;
}
2006-12-21 20:19:14 +08:00
break ;
}
case MapNotify :
{
2006-12-23 01:46:21 +08:00
osg : : notify ( osg : : INFO ) < < " MapNotify " < < std : : endl ;
2006-12-21 20:19:14 +08:00
XWindowAttributes watt ;
do
2007-02-09 21:51:28 +08:00
XGetWindowAttributes ( display , _window , & watt ) ;
2006-12-21 20:19:14 +08:00
while ( watt . map_state ! = IsViewable ) ;
2006-12-23 01:46:21 +08:00
osg : : notify ( osg : : INFO ) < < " MapNotify x= " < < watt . x < < " y= " < < watt . y < < " width= " < < watt . width < < " , height= " < < watt . height < < std : : endl ;
2007-01-02 02:20:10 +08:00
if ( windowWidth ! = watt . width | | windowHeight ! = watt . height )
{
2007-01-05 21:01:08 +08:00
resizeTime = eventTime ;
2007-01-02 02:20:10 +08:00
windowWidth = watt . width ;
windowHeight = watt . height ;
}
2006-12-21 20:19:14 +08:00
break ;
}
case MotionNotify :
{
2007-01-05 21:01:08 +08:00
if ( firstEventTime = = 0 ) firstEventTime = ev . xmotion . time ;
Time relativeTime = ev . xmotion . time - firstEventTime ;
eventTime = baseTime + static_cast < double > ( relativeTime ) * 0.001 ;
2006-12-27 01:38:47 +08:00
2006-12-21 20:19:14 +08:00
int wx , wy ;
Window win = 0L ;
if ( ev . xmotion . same_screen )
{
wx = ev . xmotion . x ;
wy = ev . xmotion . y ;
}
else
{
// the mouse in on another screen so need to compute the
// coordinates of the mouse position relative to an absolute position
// then take away the position of the original window/screen to get
// the coordinates relative to the original position.
Window root ;
int rx , ry ;
unsigned int buttons ;
int screenOrigin_x = 0 ;
int screenOrigin_y = 0 ;
int i ;
2007-02-09 21:51:28 +08:00
for ( i = 0 ; i < ScreenCount ( display ) ; i + + )
2006-12-21 20:19:14 +08:00
{
2007-02-09 21:51:28 +08:00
if ( XQueryPointer ( display , RootWindow ( display , i ) ,
2006-12-21 20:19:14 +08:00
& root , & win , & rx , & ry , & wx , & wy , & buttons ) )
{
break ;
}
2007-02-09 21:51:28 +08:00
screenOrigin_x + = DisplayWidth ( display , i ) ;
2006-12-21 20:19:14 +08:00
}
2006-12-23 05:53:44 +08:00
for ( i = 0 ; i < static_cast < int > ( _traits - > screenNum ) ; i + + )
2006-12-21 20:19:14 +08:00
{
2007-02-09 21:51:28 +08:00
screenOrigin_x - = DisplayWidth ( display , i ) ;
2006-12-21 20:19:14 +08:00
}
int dest_x_return , dest_y_return ;
Window child_return ;
2007-02-09 21:51:28 +08:00
XTranslateCoordinates ( display , _window , _parent , 0 , 0 , & dest_x_return , & dest_y_return , & child_return ) ;
2006-12-21 20:19:14 +08:00
wx + = ( screenOrigin_x - dest_x_return ) ;
wy + = ( screenOrigin_y - dest_y_return ) ;
}
float mx = wx ;
float my = wy ;
transformMouseXY ( mx , my ) ;
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseMotion ( mx , my , eventTime ) ;
2006-12-21 20:19:14 +08:00
// osg::notify(osg::NOTICE)<<"MotionNotify wx="<<wx<<" wy="<<wy<<" mx="<<mx<<" my="<<my<<std::endl;
break ;
}
case ButtonPress :
{
2007-01-05 21:01:08 +08:00
if ( firstEventTime = = 0 ) firstEventTime = ev . xmotion . time ;
Time relativeTime = ev . xmotion . time - firstEventTime ;
eventTime = baseTime + static_cast < double > ( relativeTime ) * 0.001 ;
2006-12-21 20:19:14 +08:00
if ( ev . xbutton . button = = Button4 )
{
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseScroll ( osgGA : : GUIEventAdapter : : SCROLL_UP , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
else if ( ev . xbutton . button = = Button5 )
{
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseScroll ( osgGA : : GUIEventAdapter : : SCROLL_DOWN , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
else
{
float mx = ev . xbutton . x ;
float my = ev . xmotion . y ;
transformMouseXY ( mx , my ) ;
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseButtonPress ( mx , my , ev . xbutton . button , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
break ;
}
case ButtonRelease :
{
2007-01-05 21:01:08 +08:00
if ( firstEventTime = = 0 ) firstEventTime = ev . xmotion . time ;
Time relativeTime = ev . xmotion . time - firstEventTime ;
eventTime = baseTime + static_cast < double > ( relativeTime ) * 0.001 ;
2006-12-21 20:19:14 +08:00
if ( ev . xbutton . button = = Button4 )
{
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseScroll ( osgGA : : GUIEventAdapter : : SCROLL_UP , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
else if ( ev . xbutton . button = = Button5 )
{
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseScroll ( osgGA : : GUIEventAdapter : : SCROLL_DOWN , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
else
{
float mx = ev . xbutton . x ;
float my = ev . xmotion . y ;
transformMouseXY ( mx , my ) ;
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > mouseButtonRelease ( mx , my , ev . xbutton . button , eventTime ) ;
2006-12-21 20:19:14 +08:00
}
break ;
}
case KeyPress :
{
2007-01-05 21:01:08 +08:00
if ( firstEventTime = = 0 ) firstEventTime = ev . xmotion . time ;
Time relativeTime = ev . xmotion . time - firstEventTime ;
eventTime = baseTime + static_cast < double > ( relativeTime ) * 0.001 ;
2006-12-21 20:19:14 +08:00
int keySymbol = 0 ;
unsigned int modifierMask = 0 ;
adaptKey ( ev . xkey , keySymbol , modifierMask ) ;
2007-07-05 18:51:47 +08:00
//getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2007-04-25 17:32:12 +08:00
getEventQueue ( ) - > keyPress ( keySymbol , eventTime ) ;
2006-12-21 20:19:14 +08:00
break ;
}
case KeyRelease :
{
2007-01-05 21:01:08 +08:00
if ( firstEventTime = = 0 ) firstEventTime = ev . xmotion . time ;
Time relativeTime = ev . xmotion . time - firstEventTime ;
eventTime = baseTime + static_cast < double > ( relativeTime ) * 0.001 ;
2007-08-05 22:59:17 +08:00
# if 1
// Check for following KeyPress events and see if
// the pair are the result of auto-repeat. If so, drop
// this one on the floor, to be consistent with
// Windows and Mac ports. The idea comes from libSDL sources.
XEvent nextev ;
if ( XPending ( display ) )
{
XPeekEvent ( display , & nextev ) ;
if ( ( nextev . type = = KeyPress )
& & ( nextev . xkey . keycode = = ev . xkey . keycode )
& & ( nextev . xmotion . time - ev . xmotion . time < 2 ) )
{
break ;
}
}
# endif
2006-12-21 20:19:14 +08:00
int keySymbol = 0 ;
unsigned int modifierMask = 0 ;
adaptKey ( ev . xkey , keySymbol , modifierMask ) ;
2007-07-05 18:51:47 +08:00
//getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2007-04-25 17:32:12 +08:00
getEventQueue ( ) - > keyRelease ( keySymbol , eventTime ) ;
2006-12-21 20:19:14 +08:00
break ;
}
default :
osg : : notify ( osg : : NOTICE ) < < " Other event " < < std : : endl ;
break ;
}
}
2007-01-02 02:20:10 +08:00
if ( windowX ! = _traits - > x | |
windowY ! = _traits - > y | |
windowWidth ! = _traits - > width | |
windowHeight ! = _traits - > height )
{
resized ( windowX , windowY , windowWidth , windowHeight ) ;
2007-01-05 21:01:08 +08:00
getEventQueue ( ) - > windowResize ( windowX , windowY , windowWidth , windowHeight , resizeTime ) ;
2007-01-02 02:20:10 +08:00
}
2007-01-09 03:29:59 +08:00
#if 0
2007-01-05 00:49:58 +08:00
if ( destroyWindowRequested )
{
close ( ) ;
}
2007-01-09 03:29:59 +08:00
# endif
2006-12-21 20:19:14 +08:00
}
void GraphicsWindowX11 : : grabFocus ( )
{
2007-04-13 21:22:52 +08:00
Display * display = getDisplayToUse ( ) ;
XSetInputFocus ( display , _window , RevertToNone , CurrentTime ) ;
XFlush ( display ) ;
XSync ( display , 0 ) ;
2006-12-21 20:19:14 +08:00
}
void GraphicsWindowX11 : : grabFocusIfPointerInWindow ( )
{
Window win , root ;
int wx , wy , rx , ry ;
unsigned int buttons ;
2007-04-13 21:22:52 +08:00
Display * display = getDisplayToUse ( ) ;
if ( XQueryPointer ( display , _window ,
2006-12-21 20:19:14 +08:00
& root , & win , & rx , & ry , & wx , & wy , & buttons ) )
{
2007-02-09 21:51:28 +08:00
#if 0
if ( wx > = 0 & & wx < _traits - > width & &
wy > = 0 & & wy < _traits - > height )
{
grabFocus ( ) ;
}
# else
2006-12-21 20:19:14 +08:00
grabFocus ( ) ;
2007-02-09 21:51:28 +08:00
# endif
2006-12-21 20:19:14 +08:00
}
}
void GraphicsWindowX11 : : transformMouseXY ( float & x , float & y )
{
if ( getEventQueue ( ) - > getUseFixedMouseInputRange ( ) )
{
osgGA : : GUIEventAdapter * eventState = getEventQueue ( ) - > getCurrentEventState ( ) ;
2006-12-23 05:53:44 +08:00
x = eventState - > getXmin ( ) + ( eventState - > getXmax ( ) - eventState - > getXmin ( ) ) * x / float ( _traits - > width ) ;
y = eventState - > getYmin ( ) + ( eventState - > getYmax ( ) - eventState - > getYmin ( ) ) * y / float ( _traits - > height ) ;
2006-12-21 20:19:14 +08:00
}
}
void GraphicsWindowX11 : : adaptKey ( XKeyEvent & keyevent , int & keySymbol , unsigned int & modifierMask )
{
2007-04-16 04:53:09 +08:00
Display * display = _eventDisplay ;
2007-01-02 02:20:10 +08:00
2006-12-21 20:19:14 +08:00
static XComposeStatus state ;
unsigned char keybuf [ 32 ] ;
XLookupString ( & keyevent , ( char * ) keybuf , sizeof ( keybuf ) , NULL , & state ) ;
modifierMask = 0 ;
if ( keyevent . state & ShiftMask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_SHIFT ;
}
if ( keyevent . state & LockMask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_CAPS_LOCK ;
}
if ( keyevent . state & ControlMask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_CTRL ;
}
if ( keyevent . state & Mod1Mask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_ALT ;
}
if ( keyevent . state & Mod2Mask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_NUM_LOCK ;
}
if ( keyevent . state & Mod4Mask )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_META ;
}
keySymbol = keybuf [ 0 ] ;
2007-01-02 02:20:10 +08:00
2007-04-13 21:22:52 +08:00
KeySym ks = XKeycodeToKeysym ( display , keyevent . keycode , 0 ) ;
2007-01-02 02:20:10 +08:00
int remappedKey = remapX11Key ( ks ) ;
if ( remappedKey & 0xff00 )
{
// special keyboard character
keySymbol = remappedKey ;
}
else
{
// normal ascii key
keySymbol = keybuf [ 0 ] ;
}
}
void GraphicsWindowX11 : : requestWarpPointer ( float x , float y )
{
2007-10-01 17:41:05 +08:00
Display * display = _eventDisplay ; // getDisplayToUse();
2007-04-13 21:22:52 +08:00
XWarpPointer ( display ,
2007-01-02 02:20:10 +08:00
None ,
_window ,
0 , 0 , 0 , 0 ,
static_cast < int > ( x ) , static_cast < int > ( y ) ) ;
2007-04-13 21:22:52 +08:00
XFlush ( display ) ;
XSync ( display , 0 ) ;
2007-01-02 04:01:45 +08:00
getEventQueue ( ) - > mouseWarped ( x , y ) ;
2006-12-21 20:19:14 +08:00
}
2007-04-14 16:31:40 +08:00
extern " C "
{
2007-01-04 00:06:12 +08:00
int X11ErrorHandling ( Display * display , XErrorEvent * event )
{
2007-01-04 19:49:15 +08:00
osg : : notify ( osg : : NOTICE ) < < " Got an X11ErrorHandling call display= " < < display < < " event= " < < event < < std : : endl ;
2007-02-08 19:26:04 +08:00
char buffer [ 256 ] ;
XGetErrorText ( display , event - > error_code , buffer , 256 ) ;
osg : : notify ( osg : : NOTICE ) < < buffer < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Major opcode: " < < ( int ) event - > request_code < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Minor opcode: " < < ( int ) event - > minor_code < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Error code: " < < ( int ) event - > error_code < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Request serial: " < < event - > serial < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Current serial: " < < NextRequest ( display ) - 1 < < std : : endl ;
switch ( event - > error_code )
{
case BadValue :
osg : : notify ( osg : : NOTICE ) < < " Value: " < < event - > resourceid < < std : : endl ;
break ;
case BadAtom :
osg : : notify ( osg : : NOTICE ) < < " AtomID: " < < event - > resourceid < < std : : endl ;
break ;
default :
osg : : notify ( osg : : NOTICE ) < < " ResourceID: " < < event - > resourceid < < std : : endl ;
break ;
}
2007-01-04 19:49:15 +08:00
return 0 ;
2007-01-04 00:06:12 +08:00
}
2007-04-14 16:31:40 +08:00
}
2007-01-04 00:06:12 +08:00
2007-12-21 21:32:13 +08:00
class X11WindowingSystemInterface : public osg : : GraphicsContext : : WindowingSystemInterface
2006-12-21 20:19:14 +08:00
{
2007-12-21 21:32:13 +08:00
# ifdef OSGVIEWER_USE_XRANDR
// TODO: Investigate whether or not Robert thinks we should store/restore the original
// resolution in the destructor; I'm not sure the other ones do this, and it may be the
// responsibility of the user.
bool _setScreen ( const osg : : GraphicsContext : : ScreenIdentifier & si , unsigned int width , unsigned height , double rate ) {
Display * display = XOpenDisplay ( si . displayName ( ) . c_str ( ) ) ;
if ( display )
{
XRRScreenConfiguration * sc = XRRGetScreenInfo ( display , RootWindow ( display , si . screenNum ) ) ;
if ( ! sc )
{
osg : : notify ( osg : : NOTICE ) < < " Unable to create XRRScreenConfiguration on display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
return false ;
}
int numScreens = 0 ;
int numRates = 0 ;
Rotation currentRot = 0 ;
bool okay = false ;
XRRConfigRotations ( sc , & currentRot ) ;
// If the width or height are zero, use our defaults.
if ( ! width | | ! height )
{
getScreenResolution ( si , width , height ) ;
}
// If this somehow fails, okay will still be false, no iteration will take place below,
// and the sc pointer will still be freed later on.
XRRScreenSize * ss = XRRConfigSizes ( sc , & numScreens ) ;
for ( int i = 0 ; i < numScreens ; i + + )
{
if ( ss [ i ] . width = = static_cast < int > ( width ) & & ss [ i ] . height = = static_cast < int > ( height ) )
{
short * rates = XRRConfigRates ( sc , i , & numRates ) ;
bool rateFound = false ;
// Search for our rate in the list of acceptable rates given to us by Xrandr.
// If it's not found, rateFound will still be false and the call will never
// be made to XRRSetScreenConfigAndRate since the rate will be invalid.
for ( int r = 0 ; r < numRates ; r + + )
{
if ( rates [ r ] = = static_cast < short > ( rate ) )
{
rateFound = true ;
break ;
}
}
if ( rate > 0.0f & & ! rateFound )
{
osg : : notify ( osg : : NOTICE ) < < " Unable to find valid refresh rate " < < rate < < " on display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
}
else if ( XRRSetScreenConfigAndRate ( display , sc , DefaultRootWindow ( display ) , i , currentRot , static_cast < short > ( rate ) , CurrentTime ) ! = RRSetConfigSuccess )
{
osg : : notify ( osg : : NOTICE ) < < " Unable to set resolution to " < < width < < " x " < < height < < " on display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
}
else
{
okay = true ;
break ;
}
}
}
XRRFreeScreenConfigInfo ( sc ) ;
return okay ;
}
else
{
osg : : notify ( osg : : NOTICE ) < < " Unable to open display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
return false ;
}
}
# endif
2006-12-21 20:19:14 +08:00
2007-12-21 21:32:13 +08:00
public :
2006-12-21 20:19:14 +08:00
X11WindowingSystemInterface ( )
{
2007-05-25 23:26:13 +08:00
osg : : notify ( osg : : INFO ) < < " X11WindowingSystemInterface() " < < std : : endl ;
2007-01-04 00:06:12 +08:00
XSetErrorHandler ( X11ErrorHandling ) ;
2007-02-09 21:51:28 +08:00
#if 0
2006-12-23 01:46:21 +08:00
if ( XInitThreads ( ) = = 0 )
{
osg : : notify ( osg : : NOTICE ) < < " Error: XInitThreads() failed. Aborting. " < < std : : endl ;
exit ( 1 ) ;
}
else
{
osg : : notify ( osg : : INFO ) < < " X11WindowingSystemInterface, xInitThreads() multi-threaded X support initialized. \n " ;
}
# endif
2006-12-21 20:19:14 +08:00
}
2007-01-04 00:06:12 +08:00
~ X11WindowingSystemInterface ( )
{
2007-07-06 21:08:51 +08:00
if ( osg : : Referenced : : getDeleteHandler ( ) )
{
osg : : Referenced : : getDeleteHandler ( ) - > setNumFramesToRetainObjects ( 0 ) ;
osg : : Referenced : : getDeleteHandler ( ) - > flushAll ( ) ;
}
2007-07-06 02:33:20 +08:00
//osg::notify(osg::NOTICE)<<"~X11WindowingSystemInterface()"<<std::endl;
2007-01-04 00:06:12 +08:00
XSetErrorHandler ( 0 ) ;
}
2006-12-21 20:19:14 +08:00
virtual unsigned int getNumScreens ( const osg : : GraphicsContext : : ScreenIdentifier & si )
{
2006-12-23 05:53:44 +08:00
Display * display = XOpenDisplay ( si . displayName ( ) . c_str ( ) ) ;
2006-12-21 20:19:14 +08:00
if ( display )
{
unsigned int numScreens = ScreenCount ( display ) ;
XCloseDisplay ( display ) ;
return numScreens ;
}
else
{
2006-12-25 00:40:19 +08:00
osg : : notify ( osg : : NOTICE ) < < " A Unable to open display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" " < < std : : endl ;
2006-12-21 20:19:14 +08:00
return 0 ;
}
}
virtual void getScreenResolution ( const osg : : GraphicsContext : : ScreenIdentifier & si , unsigned int & width , unsigned int & height )
{
2006-12-25 00:40:19 +08:00
Display * display = XOpenDisplay ( si . displayName ( ) . c_str ( ) ) ;
2006-12-21 20:19:14 +08:00
if ( display )
{
2006-12-23 05:53:44 +08:00
width = DisplayWidth ( display , si . screenNum ) ;
height = DisplayHeight ( display , si . screenNum ) ;
2006-12-21 20:19:14 +08:00
XCloseDisplay ( display ) ;
}
else
{
2006-12-25 00:40:19 +08:00
osg : : notify ( osg : : NOTICE ) < < " Unable to open display \" " < < XDisplayName ( si . displayName ( ) . c_str ( ) ) < < " \" . " < < std : : endl ;
2006-12-21 20:19:14 +08:00
width = 0 ;
height = 0 ;
}
}
2007-12-21 21:32:13 +08:00
virtual bool setScreenResolution ( const osg : : GraphicsContext : : ScreenIdentifier & si , unsigned int width , unsigned int height )
{
# ifdef OSGVIEWER_USE_XRANDR
return _setScreen ( si , width , height , 0.0f ) ;
# else
osg : : notify ( osg : : NOTICE ) < < " You must build osgViewer with Xrandr 1.2 or higher for setScreenResolution support! " < < std : : endl ;
return false ;
# endif
}
virtual bool setScreenRefreshRate ( const osg : : GraphicsContext : : ScreenIdentifier & si , double rate )
{
# ifdef OSGVIEWER_USE_XRANDR
return _setScreen ( si , 0 , 0 , rate ) ;
# else
osg : : notify ( osg : : NOTICE ) < < " You must build osgViewer with Xrandr 1.2 or higher for setScreenRefreshRate support! " < < std : : endl ;
return false ;
# endif
}
2006-12-21 20:19:14 +08:00
virtual osg : : GraphicsContext * createGraphicsContext ( osg : : GraphicsContext : : Traits * traits )
{
2006-12-23 05:53:44 +08:00
if ( traits - > pbuffer )
2006-12-21 20:19:14 +08:00
{
2007-06-20 01:12:05 +08:00
# if 1
osg : : ref_ptr < osgViewer : : PixelBufferX11 > pbuffer = new PixelBufferX11 ( traits ) ;
2006-12-25 00:40:19 +08:00
if ( pbuffer - > valid ( ) ) return pbuffer . release ( ) ;
else return 0 ;
2007-06-20 01:12:05 +08:00
# else
osg : : ref_ptr < osgViewer : : GraphicsWindowX11 > window = new GraphicsWindowX11 ( traits ) ;
if ( window - > valid ( ) ) return window . release ( ) ;
else return 0 ;
# endif
2006-12-21 20:19:14 +08:00
}
else
{
2006-12-25 00:40:19 +08:00
osg : : ref_ptr < osgViewer : : GraphicsWindowX11 > window = new GraphicsWindowX11 ( traits ) ;
if ( window - > valid ( ) ) return window . release ( ) ;
else return 0 ;
2006-12-21 20:19:14 +08:00
}
}
} ;
struct RegisterWindowingSystemInterfaceProxy
{
RegisterWindowingSystemInterfaceProxy ( )
{
2007-05-25 23:26:13 +08:00
osg : : notify ( osg : : INFO ) < < " RegisterWindowingSystemInterfaceProxy() " < < std : : endl ;
2006-12-21 20:19:14 +08:00
osg : : GraphicsContext : : setWindowingSystemInterface ( new X11WindowingSystemInterface ) ;
}
~ RegisterWindowingSystemInterfaceProxy ( )
{
2007-05-25 23:26:13 +08:00
osg : : notify ( osg : : INFO ) < < " ~RegisterWindowingSystemInterfaceProxy() " < < std : : endl ;
2007-07-06 21:08:51 +08:00
if ( osg : : Referenced : : getDeleteHandler ( ) )
{
osg : : Referenced : : getDeleteHandler ( ) - > setNumFramesToRetainObjects ( 0 ) ;
osg : : Referenced : : getDeleteHandler ( ) - > flushAll ( ) ;
}
2006-12-21 20:19:14 +08:00
osg : : GraphicsContext : : setWindowingSystemInterface ( 0 ) ;
2007-07-06 21:08:51 +08:00
2006-12-21 20:19:14 +08:00
}
} ;
RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy ;
2007-05-25 23:26:13 +08:00
// declare C entry point for static compilation.
2007-06-11 03:53:18 +08:00
extern " C " void graphicswindow_X11 ( void )
{
osg : : GraphicsContext : : setWindowingSystemInterface ( new X11WindowingSystemInterface ) ;
}