1 // Created on: 2013-04-06
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Xw_Window.hxx>
18 #include <Aspect_Convert.hxx>
19 #include <Aspect_ScrollDelta.hxx>
20 #include <Aspect_WindowDefinitionError.hxx>
21 #include <Aspect_WindowInputListener.hxx>
22 #include <Message.hxx>
23 #include <Message_Messenger.hxx>
24 #include <Standard_NotImplemented.hxx>
26 #if defined(HAVE_XLIB)
28 #include <X11/Xutil.h>
29 //#include <X11/XF86keysym.h>
32 #include <Aspect_DisplayConnection.hxx>
34 IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window)
36 // =======================================================================
37 // function : Xw_Window
39 // =======================================================================
40 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
41 const Standard_CString theTitle,
42 const Standard_Integer thePxLeft,
43 const Standard_Integer thePxTop,
44 const Standard_Integer thePxWidth,
45 const Standard_Integer thePxHeight)
47 myDisplay (theXDisplay),
52 myXRight (thePxLeft + thePxWidth),
53 myYBottom (thePxTop + thePxHeight),
54 myIsOwnWin (Standard_True)
56 if (thePxWidth <= 0 || thePxHeight <= 0)
58 throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range");
60 else if (theXDisplay.IsNull())
62 throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
65 #if defined(HAVE_XLIB)
66 myFBConfig = theXDisplay->GetDefaultFBConfig();
67 XVisualInfo* aVisInfo = theXDisplay->GetDefaultVisualInfoX();
69 Display* aDisp = myDisplay->GetDisplay();
70 int aScreen = DefaultScreen(aDisp);
71 Window aParent = RootWindow (aDisp, aScreen);
73 unsigned long aMask = 0;
74 XSetWindowAttributes aWinAttr;
75 memset (&aWinAttr, 0, sizeof(aWinAttr));
76 aWinAttr.event_mask = ExposureMask | StructureNotifyMask;
80 aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
82 aWinAttr.border_pixel = 0;
83 aWinAttr.override_redirect = False;
85 myXWindow = (Window )XCreateWindow (aDisp, aParent,
86 myXLeft, myYTop, thePxWidth, thePxHeight,
87 0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent,
89 aVisInfo != NULL ? aVisInfo->visual : CopyFromParent,
90 CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr);
93 throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window");
96 // if parent - desktop
97 XSizeHints aSizeHints;
98 aSizeHints.x = myXLeft;
99 aSizeHints.y = myYTop;
100 aSizeHints.flags = PPosition;
101 aSizeHints.width = thePxWidth;
102 aSizeHints.height = thePxHeight;
103 aSizeHints.flags |= PSize;
104 XSetStandardProperties (aDisp, (Window )myXWindow, theTitle, theTitle, None,
105 NULL, 0, &aSizeHints);
107 /*XTextProperty aTitleProperty;
108 aTitleProperty.encoding = None;
109 char* aTitle = (char* )theTitle;
110 Xutf8TextListToTextProperty(aDisp, &aTitle, 1, XUTF8StringStyle, &aTitleProperty);
111 XSetWMName (aDisp, (Window )myXWindow, &aTitleProperty);
112 XSetWMProperties(aDisp, (Window )myXWindow, &aTitleProperty, &aTitleProperty, NULL, 0, NULL, NULL, NULL);*/
119 throw Aspect_WindowDefinitionError ("Xw_Window, Unable to create window - not implemented");
124 // =======================================================================
125 // function : Xw_Window
127 // =======================================================================
128 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
129 const Aspect_Drawable theXWin,
130 const Aspect_FBConfig theFBConfig)
132 myDisplay (theXDisplay),
134 myFBConfig (theFBConfig),
139 myIsOwnWin (Standard_False)
143 throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window");
145 else if (theXDisplay.IsNull())
147 throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
150 #if defined(HAVE_XLIB)
151 Display* aDisp = myDisplay->GetDisplay();
153 XWindowAttributes aWinAttr;
154 XGetWindowAttributes (aDisp, (Window )myXWindow, &aWinAttr);
155 XVisualInfo aVisInfoTmp;
156 aVisInfoTmp.visualid = aWinAttr.visual->visualid;
157 aVisInfoTmp.screen = DefaultScreen (aDisp);
159 XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems);
160 if (aVisInfo == NULL)
162 throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable");
168 //throw Standard_NotImplemented("Xw_Window, not implemented");
172 // =======================================================================
173 // function : ~Xw_Window
175 // =======================================================================
176 Xw_Window::~Xw_Window()
178 if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull())
180 #if defined(HAVE_XLIB)
181 XDestroyWindow (myDisplay->GetDisplay(), (Window )myXWindow);
186 // =======================================================================
187 // function : IsMapped
189 // =======================================================================
190 Standard_Boolean Xw_Window::IsMapped() const
196 else if (IsVirtual())
198 return Standard_True;
201 #if defined(HAVE_XLIB)
202 XFlush (myDisplay->GetDisplay());
203 XWindowAttributes aWinAttr;
204 XGetWindowAttributes (myDisplay->GetDisplay(), (Window )myXWindow, &aWinAttr);
205 return aWinAttr.map_state == IsUnviewable
206 || aWinAttr.map_state == IsViewable;
208 return Standard_False;
212 // =======================================================================
215 // =======================================================================
216 void Xw_Window::Map() const
218 if (IsVirtual() || myXWindow == 0)
223 #if defined(HAVE_XLIB)
224 XMapWindow (myDisplay->GetDisplay(), (Window )myXWindow);
225 XFlush (myDisplay->GetDisplay());
229 // =======================================================================
232 // =======================================================================
233 void Xw_Window::Unmap() const
235 if (IsVirtual() || myXWindow == 0)
240 #if defined(HAVE_XLIB)
241 XIconifyWindow (myDisplay->GetDisplay(), (Window )myXWindow, DefaultScreen(myDisplay->GetDisplay()));
245 // =======================================================================
246 // function : DoResize
248 // =======================================================================
249 Aspect_TypeOfResize Xw_Window::DoResize()
251 if (IsVirtual() || myXWindow == 0)
253 return Aspect_TOR_UNKNOWN;
256 #if defined(HAVE_XLIB)
257 XFlush (myDisplay->GetDisplay());
258 XWindowAttributes aWinAttr;
259 memset (&aWinAttr, 0, sizeof(aWinAttr));
260 XGetWindowAttributes (myDisplay->GetDisplay(), (Window )myXWindow, &aWinAttr);
261 if (aWinAttr.map_state == IsUnmapped)
263 return Aspect_TOR_UNKNOWN;
266 Standard_Integer aMask = 0;
267 Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
269 if (Abs (aWinAttr.x - myXLeft ) > 2) aMask |= 1;
270 if (Abs ((aWinAttr.x + aWinAttr.width) - myXRight ) > 2) aMask |= 2;
271 if (Abs (aWinAttr.y - myYTop ) > 2) aMask |= 4;
272 if (Abs ((aWinAttr.y + aWinAttr.height) - myYBottom) > 2) aMask |= 8;
275 case 0: aMode = Aspect_TOR_NO_BORDER; break;
276 case 1: aMode = Aspect_TOR_LEFT_BORDER; break;
277 case 2: aMode = Aspect_TOR_RIGHT_BORDER; break;
278 case 4: aMode = Aspect_TOR_TOP_BORDER; break;
279 case 5: aMode = Aspect_TOR_LEFT_AND_TOP_BORDER; break;
280 case 6: aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER; break;
281 case 8: aMode = Aspect_TOR_BOTTOM_BORDER; break;
282 case 9: aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER; break;
283 case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
287 myXLeft = aWinAttr.x;
288 myXRight = aWinAttr.x + aWinAttr.width;
290 myYBottom = aWinAttr.y + aWinAttr.height;
293 return Aspect_TOR_UNKNOWN;
297 // =======================================================================
300 // =======================================================================
301 Standard_Real Xw_Window::Ratio() const
303 if (IsVirtual() || myXWindow == 0)
305 return Standard_Real(myXRight - myXLeft) / Standard_Real(myYBottom - myYTop);
308 #if defined(HAVE_XLIB)
309 XFlush (myDisplay->GetDisplay());
310 XWindowAttributes aWinAttr;
311 memset (&aWinAttr, 0, sizeof(aWinAttr));
312 XGetWindowAttributes (myDisplay->GetDisplay(), (Window )myXWindow, &aWinAttr);
313 return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height);
319 // =======================================================================
320 // function : Position
322 // =======================================================================
323 void Xw_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
324 Standard_Integer& theX2, Standard_Integer& theY2) const
326 if (IsVirtual() || myXWindow == 0)
335 #if defined(HAVE_XLIB)
336 XFlush (myDisplay->GetDisplay());
337 XWindowAttributes anAttributes;
338 memset (&anAttributes, 0, sizeof(anAttributes));
339 XGetWindowAttributes (myDisplay->GetDisplay(), (Window )myXWindow, &anAttributes);
341 XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, (Window )myXWindow,
342 0, 0, &anAttributes.x, &anAttributes.y, &aChild);
344 theX1 = -anAttributes.x;
345 theX2 = theX1 + anAttributes.width;
346 theY1 = -anAttributes.y;
347 theY2 = theY1 + anAttributes.height;
351 // =======================================================================
354 // =======================================================================
355 void Xw_Window::Size (Standard_Integer& theWidth,
356 Standard_Integer& theHeight) const
358 if (IsVirtual() || myXWindow == 0)
360 theWidth = myXRight - myXLeft;
361 theHeight = myYBottom - myYTop;
365 #if defined(HAVE_XLIB)
366 XFlush (myDisplay->GetDisplay());
367 XWindowAttributes aWinAttr;
368 memset (&aWinAttr, 0, sizeof(aWinAttr));
369 XGetWindowAttributes (myDisplay->GetDisplay(), (Window )myXWindow, &aWinAttr);
370 theWidth = aWinAttr.width;
371 theHeight = aWinAttr.height;
375 // =======================================================================
376 // function : SetTitle
378 // =======================================================================
379 void Xw_Window::SetTitle (const TCollection_AsciiString& theTitle)
383 #if defined(HAVE_XLIB)
384 XStoreName (myDisplay->GetDisplay(), (Window )myXWindow, theTitle.ToCString());
391 // =======================================================================
392 // function : InvalidateContent
394 // =======================================================================
395 void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp)
402 #if defined(HAVE_XLIB)
403 const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay;
404 Display* aDispX = aDisp->GetDisplay();
407 memset (&anEvent, 0, sizeof(anEvent));
408 anEvent.type = Expose;
409 anEvent.xexpose.window = (Window )myXWindow;
410 XSendEvent (aDispX, (Window )myXWindow, False, ExposureMask, &anEvent);
417 // =======================================================================
418 // function : VirtualKeyFromNative
420 // =======================================================================
421 Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey)
423 #if defined(HAVE_XLIB)
427 return Aspect_VKey(theKey - XK_0 + Aspect_VKey_0);
433 return Aspect_VKey(theKey - XK_A + Aspect_VKey_A);
439 return Aspect_VKey(theKey - XK_a + Aspect_VKey_A);
445 if (theKey <= XK_F12)
447 return Aspect_VKey(theKey - XK_F1 + Aspect_VKey_F1);
449 return Aspect_VKey_UNKNOWN;
455 return Aspect_VKey_Space;
457 return Aspect_VKey_Apostrophe;
459 return Aspect_VKey_Comma;
461 return Aspect_VKey_Minus;
463 return Aspect_VKey_Period;
465 return Aspect_VKey_Semicolon;
467 return Aspect_VKey_Equal;
469 return Aspect_VKey_BracketLeft;
471 return Aspect_VKey_Backslash;
472 case XK_bracketright:
473 return Aspect_VKey_BracketRight;
475 return Aspect_VKey_Backspace;
477 return Aspect_VKey_Tab;
481 return Aspect_VKey_Enter;
483 // return Aspect_VKey_Pause;
485 return Aspect_VKey_Escape;
487 return Aspect_VKey_Home;
489 return Aspect_VKey_Left;
491 return Aspect_VKey_Up;
493 return Aspect_VKey_Right;
495 return Aspect_VKey_Down;
497 return Aspect_VKey_PageUp;
499 return Aspect_VKey_PageDown;
501 return Aspect_VKey_End;
503 // return Aspect_VKey_Insert;
505 return Aspect_VKey_Menu;
507 return Aspect_VKey_Numlock;
509 // return Aspect_VKey_NumDelete;
511 return Aspect_VKey_NumpadMultiply;
513 return Aspect_VKey_NumpadAdd;
514 //case XK_KP_Separator:
515 // return Aspect_VKey_Separator;
517 return Aspect_VKey_NumpadSubtract;
518 //case XK_KP_Decimal:
519 // return Aspect_VKey_Decimal;
521 return Aspect_VKey_NumpadDivide;
524 return Aspect_VKey_Shift;
527 return Aspect_VKey_Control;
529 // return Aspect_VKey_CapsLock;
532 return Aspect_VKey_Alt;
535 // return Aspect_VKey_Super;
537 return Aspect_VKey_Delete;
539 case 0x1008FF11: // XF86AudioLowerVolume
540 return Aspect_VKey_VolumeDown;
541 case 0x1008FF12: // XF86AudioMute
542 return Aspect_VKey_VolumeMute;
543 case 0x1008FF13: // XF86AudioRaiseVolume
544 return Aspect_VKey_VolumeUp;
546 case 0x1008FF14: // XF86AudioPlay
547 return Aspect_VKey_MediaPlayPause;
548 case 0x1008FF15: // XF86AudioStop
549 return Aspect_VKey_MediaStop;
550 case 0x1008FF16: // XF86AudioPrev
551 return Aspect_VKey_MediaPreviousTrack;
552 case 0x1008FF17: // XF86AudioNext
553 return Aspect_VKey_MediaNextTrack;
555 case 0x1008FF18: // XF86HomePage
556 return Aspect_VKey_BrowserHome;
557 case 0x1008FF26: // XF86Back
558 return Aspect_VKey_BrowserBack;
559 case 0x1008FF27: // XF86Forward
560 return Aspect_VKey_BrowserForward;
561 case 0x1008FF28: // XF86Stop
562 return Aspect_VKey_BrowserStop;
563 case 0x1008FF29: // XF86Refresh
564 return Aspect_VKey_BrowserRefresh;
569 return Aspect_VKey_UNKNOWN;
572 // =======================================================================
573 // function : ProcessMessage
575 // =======================================================================
576 bool Xw_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
578 #if defined(HAVE_XLIB) // msvc before VS2015 had problems with (void )theMsg
583 #if defined(HAVE_XLIB)
584 Display* aDisplay = myDisplay->GetDisplay();
586 // Handle event for the chosen display connection
591 if ((Atom)theMsg.xclient.data.l[0] == myDisplay->GetAtom (Aspect_XA_DELETE_WINDOW)
592 && theMsg.xclient.window == (Window )myXWindow)
594 theListener.ProcessClose();
602 if (theMsg.xfocus.window == (Window )myXWindow)
604 theListener.ProcessFocus (theMsg.type == FocusIn);
610 if (theMsg.xexpose.window == (Window )myXWindow)
612 theListener.ProcessExpose();
615 // remove all the ExposureMask and process them at once
616 for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
618 if (!XCheckWindowEvent (aDisplay, (Window )myXWindow, ExposureMask, &theMsg))
626 case ConfigureNotify:
628 // remove all the StructureNotifyMask and process them at once
629 for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
631 if (!XCheckWindowEvent (aDisplay, (Window )myXWindow, StructureNotifyMask, &theMsg))
637 if (theMsg.xconfigure.window == (Window )myXWindow)
639 theListener.ProcessConfigure (true);
646 XKeyEvent* aKeyEvent = (XKeyEvent* )&theMsg;
647 const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
648 const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
649 if (aVKey != Aspect_VKey_UNKNOWN)
651 const double aTimeStamp = theListener.EventTime();
652 if (theMsg.type == KeyPress)
654 theListener.KeyDown (aVKey, aTimeStamp);
658 theListener.KeyUp (aVKey, aTimeStamp);
660 theListener.ProcessInput();
667 const Graphic3d_Vec2i aPos (theMsg.xbutton.x, theMsg.xbutton.y);
668 Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
669 Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
670 if (theMsg.xbutton.button == Button1) { aButton = Aspect_VKeyMouse_LeftButton; }
671 if (theMsg.xbutton.button == Button2) { aButton = Aspect_VKeyMouse_MiddleButton; }
672 if (theMsg.xbutton.button == Button3) { aButton = Aspect_VKeyMouse_RightButton; }
674 if ((theMsg.xbutton.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
675 if ((theMsg.xbutton.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
676 if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
678 aFlags |= Aspect_VKeyFlags_ALT;
681 if (theMsg.xbutton.button == Button4
682 || theMsg.xbutton.button == Button5)
684 if (theMsg.type != ButtonPress)
689 const double aDeltaF = (theMsg.xbutton.button == Button4 ? 1.0 : -1.0);
690 theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
692 else if (theMsg.type == ButtonPress)
694 theListener.PressMouseButton (aPos, aButton, aFlags, false);
698 theListener.ReleaseMouseButton (aPos, aButton, aFlags, false);
700 theListener.ProcessInput();
705 if (theMsg.xmotion.window != (Window )myXWindow)
710 // remove all the ButtonMotionMask and process them at once
711 for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
713 if (!XCheckWindowEvent (aDisplay, (Window )myXWindow, ButtonMotionMask | PointerMotionMask, &theMsg))
719 Graphic3d_Vec2i aPos (theMsg.xmotion.x, theMsg.xmotion.y);
720 Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
721 Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
722 if ((theMsg.xmotion.state & Button1Mask) != 0) { aButtons |= Aspect_VKeyMouse_LeftButton; }
723 if ((theMsg.xmotion.state & Button2Mask) != 0) { aButtons |= Aspect_VKeyMouse_MiddleButton; }
724 if ((theMsg.xmotion.state & Button3Mask) != 0) { aButtons |= Aspect_VKeyMouse_RightButton; }
726 if ((theMsg.xmotion.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
727 if ((theMsg.xmotion.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
728 if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
730 aFlags |= Aspect_VKeyFlags_ALT;
733 theListener.UpdateMousePosition (aPos, aButtons, aFlags, false);
734 theListener.ProcessInput();