#include <Xw_Window.hxx>
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
#include <Aspect_Convert.hxx>
+#include <Aspect_ScrollDelta.hxx>
#include <Aspect_WindowDefinitionError.hxx>
+#include <Aspect_WindowInputListener.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
-#include <GL/glx.h>
-
-namespace
-{
-
- //! Search for RGBA double-buffered visual with stencil buffer.
- //! Each size property should be a nonnegative minimum specification.
- static int TheDoubleBuff[] =
- {
- GLX_RGBA,
- GLX_DEPTH_SIZE, 16,
- GLX_STENCIL_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None
- };
-
-};
+//#include <X11/XF86keysym.h>
+IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window)
// =======================================================================
// function : Xw_Window
: Aspect_Window(),
myDisplay (theXDisplay),
myXWindow (0),
+ myFBConfig (NULL),
myXLeft (thePxLeft),
myYTop (thePxTop),
myXRight (thePxLeft + thePxWidth),
myYBottom (thePxTop + thePxHeight),
myIsOwnWin (Standard_True)
{
- int aDummy = 0;
if (thePxWidth <= 0 || thePxHeight <= 0)
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, Coordinate(s) out of range");
+ throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range");
}
else if (theXDisplay.IsNull())
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, X Display connection is undefined");
- return;
- }
- else if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
- {
- Aspect_WindowDefinitionError::Raise ("Xw_Window, GLX extension is unavailable");
- return;
+ throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
}
+ myFBConfig = theXDisplay->GetDefaultFBConfig();
+ XVisualInfo* aVisInfo = theXDisplay->GetDefaultVisualInfo();
+
Display* aDisp = myDisplay->GetDisplay();
int aScreen = DefaultScreen(aDisp);
Window aParent = RootWindow (aDisp, aScreen);
- XVisualInfo* aVisInfo = glXChooseVisual (aDisp, aScreen, TheDoubleBuff);
- if (aVisInfo == NULL)
- {
- Aspect_WindowDefinitionError::Raise ("Xw_Window, couldn't find compatible Visual (RGBA, double-buffered)");
- return;
- }
unsigned long aMask = 0;
XSetWindowAttributes aWinAttr;
memset(&aWinAttr, 0, sizeof(XSetWindowAttributes));
aWinAttr.event_mask = ExposureMask | StructureNotifyMask;
aMask |= CWEventMask;
- aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
+ if (aVisInfo != NULL)
+ {
+ aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
+ }
aWinAttr.border_pixel = 0;
aWinAttr.override_redirect = False;
myXWindow = XCreateWindow(aDisp, aParent,
myXLeft, myYTop, thePxWidth, thePxHeight,
- 0, aVisInfo->depth,
+ 0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent,
InputOutput,
- aVisInfo->visual,
+ aVisInfo != NULL ? aVisInfo->visual : CopyFromParent,
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr);
- XFree (aVisInfo); aVisInfo = NULL;
if (myXWindow == 0)
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, Unable to create window");
- return;
+ throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window");
}
// if parent - desktop
// purpose :
// =======================================================================
Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
- const Window theXWin)
+ const Window theXWin,
+ const Aspect_FBConfig theFBConfig)
: Aspect_Window(),
myDisplay (theXDisplay),
myXWindow (theXWin),
+ myFBConfig (theFBConfig),
myXLeft (0),
myYTop (0),
myXRight (512),
myYBottom (512),
myIsOwnWin (Standard_False)
{
- int aDummy = 0;
if (theXWin == 0)
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, given invalid X window");
- return;
+ throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window");
}
else if (theXDisplay.IsNull())
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, X Display connection is undefined");
- return;
- }
- else if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
- {
- myXWindow = 0;
- Aspect_WindowDefinitionError::Raise ("Xw_Window, GLX extension is unavailable");
- return;
+ throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
}
Display* aDisp = myDisplay->GetDisplay();
XWindowAttributes aWinAttr;
XGetWindowAttributes (aDisp, myXWindow, &aWinAttr);
- const int aScreen = DefaultScreen (aDisp);
- const long aVisInfoMask = VisualIDMask | VisualScreenMask;
XVisualInfo aVisInfoTmp;
aVisInfoTmp.visualid = aWinAttr.visual->visualid;
- aVisInfoTmp.screen = aScreen;
+ aVisInfoTmp.screen = DefaultScreen (aDisp);
int aNbItems = 0;
- XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, aVisInfoMask, &aVisInfoTmp, &aNbItems);
+ XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems);
if (aVisInfo == NULL)
{
- Aspect_WindowDefinitionError::Raise ("Xw_Window, Visual is unavailable");
- return;
+ throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable");
}
XFree (aVisInfo);
}
// =======================================================================
-// function : Destroy
+// function : ~Xw_Window
// purpose :
// =======================================================================
-void Xw_Window::Destroy()
+Xw_Window::~Xw_Window()
{
if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull())
{
// function : DoResize
// purpose :
// =======================================================================
-Aspect_TypeOfResize Xw_Window::DoResize() const
+Aspect_TypeOfResize Xw_Window::DoResize()
{
- if (myXWindow == 0)
+ if (IsVirtual() || myXWindow == 0)
{
return Aspect_TOR_UNKNOWN;
}
default: break;
}
- *((Standard_Integer* )&myXLeft ) = aWinAttr.x;
- *((Standard_Integer* )&myXRight ) = aWinAttr.x + aWinAttr.width;
- *((Standard_Integer* )&myYTop ) = aWinAttr.y;
- *((Standard_Integer* )&myYBottom ) = aWinAttr.y + aWinAttr.height;
+ myXLeft = aWinAttr.x;
+ myXRight = aWinAttr.x + aWinAttr.width;
+ myYTop = aWinAttr.y;
+ myYBottom = aWinAttr.y + aWinAttr.height;
return aMode;
}
// function : Ratio
// purpose :
// =======================================================================
-Quantity_Ratio Xw_Window::Ratio() const
+Standard_Real Xw_Window::Ratio() const
{
- if (myXWindow == 0)
+ if (IsVirtual() || myXWindow == 0)
{
- return 1.0;
+ return Standard_Real(myXRight - myXLeft) / Standard_Real(myYBottom - myYTop);
}
XFlush (myDisplay->GetDisplay());
XWindowAttributes aWinAttr;
XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
- return Quantity_Ratio(aWinAttr.width) / Quantity_Ratio(aWinAttr.height);
+ return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height);
}
// =======================================================================
// function : Position
// purpose :
// =======================================================================
-void Xw_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
- Standard_Integer& X2, Standard_Integer& Y2) const
+void Xw_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
+ Standard_Integer& theX2, Standard_Integer& theY2) const
{
- if (myXWindow == 0)
+ if (IsVirtual() || myXWindow == 0)
{
+ theX1 = myXLeft;
+ theX2 = myXRight;
+ theY1 = myYTop;
+ theY2 = myYBottom;
return;
}
XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, myXWindow,
0, 0, &anAttributes.x, &anAttributes.y, &aChild);
- X1 = -anAttributes.x;
- X2 = X1 + anAttributes.width;
- Y1 = -anAttributes.y;
- Y2 = Y1 + anAttributes.height;
+ theX1 = -anAttributes.x;
+ theX2 = theX1 + anAttributes.width;
+ theY1 = -anAttributes.y;
+ theY2 = theY1 + anAttributes.height;
}
// =======================================================================
void Xw_Window::Size (Standard_Integer& theWidth,
Standard_Integer& theHeight) const
{
- if (myXWindow == 0)
+ if (IsVirtual() || myXWindow == 0)
{
+ theWidth = myXRight - myXLeft;
+ theHeight = myYBottom - myYTop;
return;
}
theHeight = aWinAttr.height;
}
+// =======================================================================
+// function : SetTitle
+// purpose :
+// =======================================================================
+void Xw_Window::SetTitle (const TCollection_AsciiString& theTitle)
+{
+ if (myXWindow != 0)
+ {
+ XStoreName (myDisplay->GetDisplay(), myXWindow, theTitle.ToCString());
+ }
+}
+
+// =======================================================================
+// function : InvalidateContent
+// purpose :
+// =======================================================================
+void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp)
+{
+ if (myXWindow == 0)
+ {
+ return;
+ }
+
+ const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay;
+ Display* aDispX = aDisp->GetDisplay();
+
+ XEvent anEvent;
+ memset (&anEvent, 0, sizeof(anEvent));
+ anEvent.type = Expose;
+ anEvent.xexpose.window = myXWindow;
+ XSendEvent (aDispX, myXWindow, False, ExposureMask, &anEvent);
+ XFlush (aDispX);
+}
+
+// =======================================================================
+// function : VirtualKeyFromNative
+// purpose :
+// =======================================================================
+Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey)
+{
+ if (theKey >= XK_0
+ && theKey <= XK_9)
+ {
+ return Aspect_VKey(theKey - XK_0 + Aspect_VKey_0);
+ }
+
+ if (theKey >= XK_A
+ && theKey <= XK_Z)
+ {
+ return Aspect_VKey(theKey - XK_A + Aspect_VKey_A);
+ }
+
+ if (theKey >= XK_a
+ && theKey <= XK_z)
+ {
+ return Aspect_VKey(theKey - XK_a + Aspect_VKey_A);
+ }
+
+ if (theKey >= XK_F1
+ && theKey <= XK_F24)
+ {
+ if (theKey <= XK_F12)
+ {
+ return Aspect_VKey(theKey - XK_F1 + Aspect_VKey_F1);
+ }
+ return Aspect_VKey_UNKNOWN;
+ }
+
+ switch (theKey)
+ {
+ case XK_space:
+ return Aspect_VKey_Space;
+ case XK_apostrophe:
+ return Aspect_VKey_Apostrophe;
+ case XK_comma:
+ return Aspect_VKey_Comma;
+ case XK_minus:
+ return Aspect_VKey_Minus;
+ case XK_period:
+ return Aspect_VKey_Period;
+ case XK_semicolon:
+ return Aspect_VKey_Semicolon;
+ case XK_equal:
+ return Aspect_VKey_Equal;
+ case XK_bracketleft:
+ return Aspect_VKey_BracketLeft;
+ case XK_backslash:
+ return Aspect_VKey_Backslash;
+ case XK_bracketright:
+ return Aspect_VKey_BracketRight;
+ case XK_BackSpace:
+ return Aspect_VKey_Backspace;
+ case XK_Tab:
+ return Aspect_VKey_Tab;
+ //case XK_Linefeed:
+ case XK_Return:
+ case XK_KP_Enter:
+ return Aspect_VKey_Enter;
+ //case XK_Pause:
+ // return Aspect_VKey_Pause;
+ case XK_Escape:
+ return Aspect_VKey_Escape;
+ case XK_Home:
+ return Aspect_VKey_Home;
+ case XK_Left:
+ return Aspect_VKey_Left;
+ case XK_Up:
+ return Aspect_VKey_Up;
+ case XK_Right:
+ return Aspect_VKey_Right;
+ case XK_Down:
+ return Aspect_VKey_Down;
+ case XK_Prior:
+ return Aspect_VKey_PageUp;
+ case XK_Next:
+ return Aspect_VKey_PageDown;
+ case XK_End:
+ return Aspect_VKey_End;
+ //case XK_Insert:
+ // return Aspect_VKey_Insert;
+ case XK_Menu:
+ return Aspect_VKey_Menu;
+ case XK_Num_Lock:
+ return Aspect_VKey_Numlock;
+ //case XK_KP_Delete:
+ // return Aspect_VKey_NumDelete;
+ case XK_KP_Multiply:
+ return Aspect_VKey_NumpadMultiply;
+ case XK_KP_Add:
+ return Aspect_VKey_NumpadAdd;
+ //case XK_KP_Separator:
+ // return Aspect_VKey_Separator;
+ case XK_KP_Subtract:
+ return Aspect_VKey_NumpadSubtract;
+ //case XK_KP_Decimal:
+ // return Aspect_VKey_Decimal;
+ case XK_KP_Divide:
+ return Aspect_VKey_NumpadDivide;
+ case XK_Shift_L:
+ case XK_Shift_R:
+ return Aspect_VKey_Shift;
+ case XK_Control_L:
+ case XK_Control_R:
+ return Aspect_VKey_Control;
+ //case XK_Caps_Lock:
+ // return Aspect_VKey_CapsLock;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ return Aspect_VKey_Alt;
+ //case XK_Super_L:
+ //case XK_Super_R:
+ // return Aspect_VKey_Super;
+ case XK_Delete:
+ return Aspect_VKey_Delete;
+
+ case 0x1008FF11: // XF86AudioLowerVolume
+ return Aspect_VKey_VolumeDown;
+ case 0x1008FF12: // XF86AudioMute
+ return Aspect_VKey_VolumeMute;
+ case 0x1008FF13: // XF86AudioRaiseVolume
+ return Aspect_VKey_VolumeUp;
+
+ case 0x1008FF14: // XF86AudioPlay
+ return Aspect_VKey_MediaPlayPause;
+ case 0x1008FF15: // XF86AudioStop
+ return Aspect_VKey_MediaStop;
+ case 0x1008FF16: // XF86AudioPrev
+ return Aspect_VKey_MediaPreviousTrack;
+ case 0x1008FF17: // XF86AudioNext
+ return Aspect_VKey_MediaNextTrack;
+
+ case 0x1008FF18: // XF86HomePage
+ return Aspect_VKey_BrowserHome;
+ case 0x1008FF26: // XF86Back
+ return Aspect_VKey_BrowserBack;
+ case 0x1008FF27: // XF86Forward
+ return Aspect_VKey_BrowserForward;
+ case 0x1008FF28: // XF86Stop
+ return Aspect_VKey_BrowserStop;
+ case 0x1008FF29: // XF86Refresh
+ return Aspect_VKey_BrowserRefresh;
+ }
+ return Aspect_VKey_UNKNOWN;
+}
+
+// =======================================================================
+// function : ProcessMessage
+// purpose :
+// =======================================================================
+bool Xw_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
+ XEvent& theMsg)
+{
+ Display* aDisplay = myDisplay->GetDisplay();
+
+ // Handle event for the chosen display connection
+ switch (theMsg.type)
+ {
+ case ClientMessage:
+ {
+ if ((Atom)theMsg.xclient.data.l[0] == myDisplay->GetAtom (Aspect_XA_DELETE_WINDOW)
+ && theMsg.xclient.window == myXWindow)
+ {
+ theListener.ProcessClose();
+ return true;
+ }
+ return false;
+ }
+ case FocusIn:
+ case FocusOut:
+ {
+ if (theMsg.xfocus.window == myXWindow)
+ {
+ theListener.ProcessFocus (theMsg.type == FocusIn);
+ }
+ return true;
+ }
+ case Expose:
+ {
+ if (theMsg.xexpose.window == myXWindow)
+ {
+ theListener.ProcessExpose();
+ }
+
+ // remove all the ExposureMask and process them at once
+ for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+ {
+ if (!XCheckWindowEvent (aDisplay, myXWindow, ExposureMask, &theMsg))
+ {
+ break;
+ }
+ }
+
+ return true;
+ }
+ case ConfigureNotify:
+ {
+ // remove all the StructureNotifyMask and process them at once
+ for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+ {
+ if (!XCheckWindowEvent (aDisplay, myXWindow, StructureNotifyMask, &theMsg))
+ {
+ break;
+ }
+ }
+
+ if (theMsg.xconfigure.window == myXWindow)
+ {
+ theListener.ProcessConfigure (true);
+ }
+ return true;
+ }
+ case KeyPress:
+ case KeyRelease:
+ {
+ XKeyEvent* aKeyEvent = (XKeyEvent* )&theMsg;
+ const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
+ const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
+ if (aVKey != Aspect_VKey_UNKNOWN)
+ {
+ const double aTimeStamp = theListener.EventTime();
+ if (theMsg.type == KeyPress)
+ {
+ theListener.KeyDown (aVKey, aTimeStamp);
+ }
+ else
+ {
+ theListener.KeyUp (aVKey, aTimeStamp);
+ }
+ theListener.ProcessInput();
+ }
+ return true;
+ }
+ case ButtonPress:
+ case ButtonRelease:
+ {
+ const Graphic3d_Vec2i aPos (theMsg.xbutton.x, theMsg.xbutton.y);
+ Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
+ Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
+ if (theMsg.xbutton.button == Button1) { aButton = Aspect_VKeyMouse_LeftButton; }
+ if (theMsg.xbutton.button == Button2) { aButton = Aspect_VKeyMouse_MiddleButton; }
+ if (theMsg.xbutton.button == Button3) { aButton = Aspect_VKeyMouse_RightButton; }
+
+ if ((theMsg.xbutton.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
+ if ((theMsg.xbutton.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
+ if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
+ {
+ aFlags |= Aspect_VKeyFlags_ALT;
+ }
+
+ if (theMsg.xbutton.button == Button4
+ || theMsg.xbutton.button == Button5)
+ {
+ if (theMsg.type != ButtonPress)
+ {
+ return true;
+ }
+
+ const double aDeltaF = (theMsg.xbutton.button == Button4 ? 1.0 : -1.0);
+ theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
+ }
+ else if (theMsg.type == ButtonPress)
+ {
+ theListener.PressMouseButton (aPos, aButton, aFlags, false);
+ }
+ else
+ {
+ theListener.ReleaseMouseButton (aPos, aButton, aFlags, false);
+ }
+ theListener.ProcessInput();
+ return true;
+ }
+ case MotionNotify:
+ {
+ if (theMsg.xmotion.window != myXWindow)
+ {
+ return false;
+ }
+
+ // remove all the ButtonMotionMask and process them at once
+ for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+ {
+ if (!XCheckWindowEvent (aDisplay, myXWindow, ButtonMotionMask | PointerMotionMask, &theMsg))
+ {
+ break;
+ }
+ }
+
+ Graphic3d_Vec2i aPos (theMsg.xmotion.x, theMsg.xmotion.y);
+ Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
+ Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
+ if ((theMsg.xmotion.state & Button1Mask) != 0) { aButtons |= Aspect_VKeyMouse_LeftButton; }
+ if ((theMsg.xmotion.state & Button2Mask) != 0) { aButtons |= Aspect_VKeyMouse_MiddleButton; }
+ if ((theMsg.xmotion.state & Button3Mask) != 0) { aButtons |= Aspect_VKeyMouse_RightButton; }
+
+ if ((theMsg.xmotion.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
+ if ((theMsg.xmotion.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
+ if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
+ {
+ aFlags |= Aspect_VKeyFlags_ALT;
+ }
+
+ theListener.UpdateMousePosition (aPos, aButtons, aFlags, false);
+ theListener.ProcessInput();
+ return true;
+ }
+ }
+ return false;
+}
+
#endif // Win32 or Mac OS X