2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/window-system/x11/window-system-x.h>
22 #include <dali/devel-api/adaptor-framework/keyboard.h>
23 #include <dali/internal/system/common/file-descriptor-monitor.h>
24 #include <dali/internal/window-system/common/window-system.h>
27 #include <X11/XKBlib.h>
28 #include <X11/Xatom.h>
30 #include <X11/Xutil.h>
31 #include <X11/extensions/XInput2.h>
32 #include <X11/extensions/Xrender.h>
38 #include <unordered_map>
43 #include <sys/types.h>
53 const int MOUSE_SCROLL_WHEEL_UP{4};
54 const int MOUSE_SCROLL_WHEEL_DOWN{5};
55 const int MOUSE_SCROLL_WHEEL_LEFT{6};
56 const int MOUSE_SCROLL_WHEEL_RIGHT{7};
59 * @brief Get an XWindow property
61 * @tparam T - The type of data to return
62 * @param[in] display The display containing the window
63 * @param[in] window The window to get the property for
64 * @param[in] property The property to acquire
65 * @param[in] type The property type
66 * @param[out] data The property data
68 * @return true if the property was successfully retrieved
71 bool GetWindowProperty(::Display* display, ::Window window, ::Atom property, ::Atom type, std::vector<T>& data)
75 unsigned long numberOfItems = 0, bytesRemaining = 0;
76 unsigned char* propertyData{nullptr};
80 window = DefaultRootWindow(display);
83 XSync(display, false);
84 XGetWindowProperty(display, window, property, 0, LONG_MAX, False, type, &actualType, &actualFormat, &numberOfItems, &bytesRemaining, &propertyData);
86 if(actualFormat == 0 || numberOfItems == 0 || actualType != type)
96 if(sizeof(T) == sizeof(unsigned char))
98 data.resize(numberOfItems + 1); // Allow space for c-string terminator
99 for(int i = 0; i < numberOfItems + 1; ++i)
101 data[i] = static_cast<T>(propertyData[i]);
108 if(sizeof(T) == sizeof(unsigned short))
110 data.resize(numberOfItems);
111 for(int i = 0; i < numberOfItems; ++i)
113 data[i] = static_cast<T>(((unsigned short*)propertyData)[i]);
120 if(sizeof(T) == sizeof(unsigned long))
122 data.resize(numberOfItems);
123 for(unsigned long i = 0; i < numberOfItems; ++i)
125 // X returns native long type, regardless of whether it's actually 32 bits or not
126 data[i] = static_cast<T>(((unsigned long*)propertyData)[i]);
133 return data.size() != 0;
138 namespace WindowSystem
140 static WindowSystemX* gWindowSystem{nullptr};
143 * Initialize the window system (currently run from the first window that gets created)
147 if(nullptr == gWindowSystem)
149 gWindowSystem = new WindowSystemX();
154 * Shutdown the window system (Currently run from the first window
158 if(nullptr != gWindowSystem)
160 delete gWindowSystem;
161 gWindowSystem = nullptr;
165 Atom WindowSystemX::ATOM_WM_PROTOCOLS{0};
166 Atom WindowSystemX::ATOM_WM_STATE{0};
167 Atom WindowSystemX::ATOM_WM_DELETE_WINDOW{0};
168 Atom WindowSystemX::ATOM_WM_TRANSIENT_FOR{0};
169 Atom WindowSystemX::ATOM_NET_ACTIVE_WINDOW{0};
170 Atom WindowSystemX::ATOM_NET_STARTUP_ID{0};
171 Atom WindowSystemX::ATOM_NET_WM_PID{0};
172 Atom WindowSystemX::ATOM_NET_WM_WINDOW_TYPE{0};
173 Atom WindowSystemX::ATOM_NET_WM_WINDOW_TYPE_NORMAL{0};
174 Atom WindowSystemX::ATOM_NET_WM_NAME{0};
175 Atom WindowSystemX::ATOM_UTF8_STRING{0};
183 const AtomItem atomItems[] =
185 {"UTF8_STRING", &WindowSystemX::ATOM_UTF8_STRING},
186 {"WM_DELETE_WINDOW", &WindowSystemX::ATOM_WM_DELETE_WINDOW},
187 {"WM_PROTOCOLS", &WindowSystemX::ATOM_WM_PROTOCOLS},
188 {"WM_STATE", &WindowSystemX::ATOM_WM_STATE},
189 {"WM_TRANSIENT_FOR", &WindowSystemX::ATOM_WM_TRANSIENT_FOR},
190 {"_NET_ACTIVE_WINDOW", &WindowSystemX::ATOM_NET_ACTIVE_WINDOW},
191 {"_NET_STARTUP_ID", &WindowSystemX::ATOM_NET_STARTUP_ID},
192 {"_NET_WM_NAME", &WindowSystemX::ATOM_NET_WM_NAME},
193 {"_NET_WM_PID", &WindowSystemX::ATOM_NET_WM_PID},
194 {"_NET_WM_WINDOW_TYPE", &WindowSystemX::ATOM_NET_WM_WINDOW_TYPE},
195 {"_NET_WM_WINDOW_TYPE_NORMAL", &WindowSystemX::ATOM_NET_WM_WINDOW_TYPE_NORMAL},
198 const int NUMBER_OF_ATOMS = sizeof(atomItems) / sizeof(AtomItem);
200 struct DeleteWindowRequest
205 void PropertyNotifyEventHandler(const XEvent* xevent)
207 WindowSystemX::X11PropertyNotifyEvent propertyNotifyEvent;
208 propertyNotifyEvent.window = xevent->xproperty.window;
209 propertyNotifyEvent.event = xevent;
210 propertyNotifyEvent.timestamp = xevent->xproperty.time;
211 propertyNotifyEvent.atom = xevent->xproperty.atom;
212 propertyNotifyEvent.state = xevent->xproperty.state;
213 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::PROPERTY_NOTIFY, propertyNotifyEvent);
216 void ClientMessageEventHandler(const XEvent* xevent)
218 if((xevent->xclient.message_type == WindowSystemX::ATOM_WM_PROTOCOLS) &&
219 (xevent->xclient.format == 32) &&
220 (static_cast<Atom>(xevent->xclient.data.l[0]) == WindowSystemX::ATOM_WM_DELETE_WINDOW))
222 WindowSystemX::X11Event x11Event;
223 x11Event.window = xevent->xclient.window;
224 x11Event.event = xevent;
226 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::DELETE_REQUEST, x11Event);
230 void FocusInEventHandler(const XEvent* xevent)
232 WindowSystemX::X11Event x11Event;
233 x11Event.window = xevent->xclient.window;
234 x11Event.event = xevent;
235 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::FOCUS_IN, x11Event);
238 void FocusOutEventHandler(const XEvent* xevent)
240 WindowSystemX::X11Event x11Event;
241 x11Event.window = xevent->xclient.window;
242 x11Event.event = xevent;
243 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::FOCUS_OUT, x11Event);
246 void ExposeEventHandler(const XEvent* xevent)
248 WindowSystemX::X11ExposeEvent x11ExposeEvent;
249 x11ExposeEvent.window = xevent->xclient.window;
250 x11ExposeEvent.event = xevent;
251 x11ExposeEvent.x = xevent->xexpose.x;
252 x11ExposeEvent.y = xevent->xexpose.y;
253 x11ExposeEvent.width = xevent->xexpose.width;
254 x11ExposeEvent.height = xevent->xexpose.height;
255 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::DAMAGE, x11ExposeEvent);
258 void HandlePointerMove(int x, int y, unsigned long timestamp, ::Window window)
260 WindowSystemX::X11MouseEvent mouseEvent;
261 mouseEvent.window = window;
262 mouseEvent.timestamp = timestamp;
265 mouseEvent.buttons = 0;
266 mouseEvent.device = 0;
267 mouseEvent.multi.pressure = 1.0f;
268 mouseEvent.multi.angle = 0.0f;
269 mouseEvent.multi.radius = 1;
270 mouseEvent.multi.radiusX = 1;
271 mouseEvent.multi.radiusY = 1;
272 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_MOVE, mouseEvent);
275 void ConvertButtonEvent(const XEvent* xevent, WindowSystemX::X11MouseEvent& mouseEvent)
277 mouseEvent.window = xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window;
278 mouseEvent.timestamp = xevent->xbutton.time;
279 mouseEvent.x = xevent->xbutton.x;
280 mouseEvent.y = xevent->xbutton.y;
281 mouseEvent.buttons = xevent->xbutton.button;
282 mouseEvent.device = 0;
283 mouseEvent.multi.pressure = 1.0f;
284 mouseEvent.multi.angle = 0.0f;
285 mouseEvent.multi.radius = 1;
286 mouseEvent.multi.radiusX = 1;
287 mouseEvent.multi.radiusY = 1;
290 void ButtonPressEventHandler(const XEvent* xevent)
292 if(xevent->xbutton.button < MOUSE_SCROLL_WHEEL_UP || xevent->xbutton.button > MOUSE_SCROLL_WHEEL_RIGHT)
294 HandlePointerMove(xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.time, xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
296 WindowSystemX::X11MouseEvent mouseEvent;
297 ConvertButtonEvent(xevent, mouseEvent);
298 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_BUTTON_DOWN, mouseEvent);
300 else // Otherwise, it's a mouse wheel event
302 WindowSystemX::X11MouseWheelEvent mouseWheelEvent;
303 mouseWheelEvent.x = xevent->xbutton.x;
304 mouseWheelEvent.y = xevent->xbutton.y;
305 mouseWheelEvent.window = (xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
306 mouseWheelEvent.timestamp = xevent->xbutton.time;
308 switch(xevent->xbutton.button)
310 case MOUSE_SCROLL_WHEEL_UP:
312 mouseWheelEvent.direction = 0;
313 mouseWheelEvent.z = -1;
316 case MOUSE_SCROLL_WHEEL_DOWN:
318 mouseWheelEvent.direction = 0;
319 mouseWheelEvent.z = 1;
322 case MOUSE_SCROLL_WHEEL_LEFT:
324 mouseWheelEvent.direction = 1;
325 mouseWheelEvent.z = -1;
328 case MOUSE_SCROLL_WHEEL_RIGHT:
330 mouseWheelEvent.direction = 1;
331 mouseWheelEvent.z = 1;
335 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_WHEEL, mouseWheelEvent);
339 void ButtonReleaseEventHandler(const XEvent* xevent)
341 // Check it's a normal button, not a mouse wheel button
342 if(xevent->xbutton.button < MOUSE_SCROLL_WHEEL_UP || xevent->xbutton.button > MOUSE_SCROLL_WHEEL_RIGHT)
344 HandlePointerMove(xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.time, xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
346 WindowSystemX::X11MouseEvent mouseEvent;
347 ConvertButtonEvent(xevent, mouseEvent);
348 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_BUTTON_UP, mouseEvent);
350 // ignore wheel release events, they are sent immediately prior to another press event
353 void MotionNotifyEventHandler(const XEvent* xevent)
355 HandlePointerMove(xevent->xmotion.x, xevent->xmotion.y, xevent->xmotion.time, xevent->xmotion.subwindow ? xevent->xmotion.subwindow : xevent->xmotion.window);
358 void EnterNotifyEventHandler(const XEvent* xevent)
360 HandlePointerMove(xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.time, xevent->xcrossing.subwindow ? xevent->xcrossing.subwindow : xevent->xcrossing.window);
362 void LeaveNotifyEventHandler(const XEvent* xevent)
364 HandlePointerMove(xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.time, xevent->xcrossing.subwindow ? xevent->xcrossing.subwindow : xevent->xcrossing.window);
367 void ConvertKeyEvent(const XEvent* xEvent, WindowSystemX::X11KeyEvent& keyEvent)
369 const XKeyEvent* xKeyEvent = &(xEvent->xkey);
371 keyEvent.keyCode = xKeyEvent->keycode;
373 KeySym keySymbol = XkbKeycodeToKeysym(xKeyEvent->display, xKeyEvent->keycode, 0, 0);
374 char* keyname = XKeysymToString(keySymbol);
377 asprintf(&keyname, "Keycode-%i", xKeyEvent->keycode);
378 keyEvent.keyname = keyname;
383 keyEvent.keyname = keyname;
386 keyEvent.timestamp = xKeyEvent->time;
387 keyEvent.modifiers = xKeyEvent->state; // @todo add own modifier list
388 keyEvent.window = xKeyEvent->window;
389 keyEvent.event = xEvent;
392 XComposeStatus composeStatus;
393 const int BUFFER_LENGTH{256};
394 char buffer[BUFFER_LENGTH];
395 int stringLength = XLookupString(const_cast<XKeyEvent*>(xKeyEvent), buffer, BUFFER_LENGTH, &keySymbol2, &composeStatus);
397 const char* key{nullptr};
398 if(keySymbol != keySymbol2)
400 key = XKeysymToString(keySymbol2);
404 key = keyEvent.keyname.c_str();
408 buffer[std::max(0, std::min(BUFFER_LENGTH - 1, stringLength))] = '\0';
410 keyEvent.compose = stringLength ? buffer : "";
413 void KeyPressEventHandler(const XEvent* xevent)
415 WindowSystemX::X11KeyEvent x11KeyEvent;
416 ConvertKeyEvent(xevent, x11KeyEvent);
417 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::KEY_DOWN, x11KeyEvent);
420 void KeyReleaseEventHandler(const XEvent* xevent)
422 WindowSystemX::X11KeyEvent x11KeyEvent;
423 ConvertKeyEvent(xevent, x11KeyEvent);
424 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::KEY_UP, x11KeyEvent);
427 void SelectionClearEventHandler(const XEvent* xevent)
432 void SelectionNotifyEventHandler(const XEvent* xevent)
437 struct WindowSystemX::Impl
442 mDisplay = XOpenDisplay(nullptr); // Note, DisplayConnection now reads this var.
444 mXEventMonitor = new FileDescriptorMonitor(
445 ConnectionNumber(mDisplay),
446 MakeCallback(this, &WindowSystemX::Impl::XPollCallback),
447 FileDescriptorMonitor::FD_READABLE);
448 // libuv hacks: add FD_WRITABLE.
451 SetupEventHandlers();
457 // @todo Flush events, delete fd handlers, shutdown other X subsystems
458 XCloseDisplay(mDisplay);
459 delete mXEventMonitor;
462 ::Display* GetXDisplay()
467 void XPollCallback(FileDescriptorMonitor::EventType eventType)
469 if(eventType & (FileDescriptorMonitor::FD_READABLE | FileDescriptorMonitor::FD_WRITABLE))
471 while(XPending(mDisplay))
474 XNextEvent(mDisplay, &event);
480 void InitializeAtoms()
482 std::vector<Atom> atoms;
483 std::vector<const char*> names;
484 atoms.resize(NUMBER_OF_ATOMS);
485 names.resize(NUMBER_OF_ATOMS);
486 for(unsigned int i = 0; i < NUMBER_OF_ATOMS; ++i)
488 names[i] = atomItems[i].name.c_str();
490 Status status = XInternAtoms(mDisplay, const_cast<char**>(&names[0]), NUMBER_OF_ATOMS, false, &atoms[0]);
493 for(unsigned int i = 0; i < NUMBER_OF_ATOMS; ++i)
495 *(atomItems[i].atom) = atoms[i];
500 void SetupEventHandlers()
502 mXEventHandlers[PropertyNotify] = &PropertyNotifyEventHandler;
503 mXEventHandlers[ClientMessage] = &ClientMessageEventHandler;
504 mXEventHandlers[FocusIn] = &FocusInEventHandler;
505 mXEventHandlers[FocusOut] = &FocusOutEventHandler;
506 mXEventHandlers[Expose] = &ExposeEventHandler;
507 mXEventHandlers[ButtonPress] = &ButtonPressEventHandler;
508 mXEventHandlers[ButtonRelease] = &ButtonReleaseEventHandler;
509 mXEventHandlers[MotionNotify] = &MotionNotifyEventHandler;
510 mXEventHandlers[EnterNotify] = &EnterNotifyEventHandler;
511 mXEventHandlers[LeaveNotify] = &LeaveNotifyEventHandler;
512 mXEventHandlers[KeyPress] = &KeyPressEventHandler;
513 mXEventHandlers[KeyRelease] = &KeyReleaseEventHandler;
514 mXEventHandlers[SelectionClear] = &SelectionClearEventHandler;
515 mXEventHandlers[SelectionNotify] = &SelectionNotifyEventHandler;
518 void InitializeInput()
522 if(XQueryExtension(mDisplay, "XInputExtension", &mXi2OpCode, &event, &error))
524 // Extension is present
525 int majorVersion = XI_2_Major;
526 int minorVersion = XI_2_Minor;
528 Status status = XIQueryVersion(mDisplay, &majorVersion, &minorVersion);
529 if(status == Success)
531 // @todo May need to enable DeviceChanged, HierarchyChanged and PropertyEvent masks.
532 mXi2Devices = XIQueryDevice(mDisplay, XIAllDevices, &mXi2NumberOfDevices);
539 // @todo Clear any events set in InitializeInput()
542 XIFreeDeviceInfo(mXi2Devices);
543 mXi2Devices = nullptr;
545 mXi2NumberOfDevices = 0;
549 void InputMultiSelect(::Window window)
551 // NOT IMPLEMENTED. See ecore_x_input_multi_select(mEcoreWindow);
553 void EnableDragAndDrop(::Window window, bool enable)
555 // NOT IMPLEMENTED. See ecore_x_dnd_aware_set(mEcoreWindow, enable);
558 // Call the internal X11 event handler. This will call TriggerEventHandler which
559 // will call each registered handler's callback.
560 void HandleXEvent(const XEvent& event)
562 auto iter = mXEventHandlers.find(event.type);
563 if(iter != mXEventHandlers.end())
565 iter->second(&event);
569 WindowSystemBase::EventHandler* AddEventHandler(WindowSystemBase::Event event,
570 WindowSystemBase::EventHandlerCallback callback,
573 mHandlers.emplace_back(EventHandler{callback, data, event, ++mNextHandlerId});
574 return &mHandlers.back();
577 void DeleteEventHandler(WindowSystemBase::EventHandler* eventHandler)
579 int id = eventHandler->handlerId;
580 auto iter = std::find_if(mHandlers.begin(), mHandlers.end(), [id](const WindowSystemBase::EventHandler& eventHandler) { return eventHandler.handlerId == id; });
581 if(iter != mHandlers.end())
583 mHandlers.erase(iter);
587 void TriggerEventHandler(WindowSystemBase::Event eventType, WindowSystemX::X11Event& x11Event)
589 //@todo make this much more efficient!
590 for(auto& element : mHandlers)
592 if(element.event == eventType)
594 bool stop = element.callback(element.data, eventType, &x11Event);
603 void Move(::Window window, int x, int y)
605 XMoveWindow(mDisplay, window, x, y);
607 void Resize(::Window window, int width, int height)
609 XResizeWindow(mDisplay, window, std::max(1, width), std::max(1, height));
612 void MoveResize(::Window window, int x, int y, int width, int height)
614 XMoveResizeWindow(mDisplay, window, x, y, std::max(1, width), std::max(1, height));
617 void SetStringProperty(::Window window, Atom atom, const std::string& string)
619 XChangeProperty(mDisplay, window, atom, WindowSystemX::ATOM_UTF8_STRING, 8, PropModeReplace, (unsigned char*)string.c_str(), string.length());
622 void SetClass(::Window window, const std::string& name, const std::string& className)
624 char* list[] = {strdup(name.c_str())};
625 XTextProperty textProperty;
626 if(Xutf8TextListToTextProperty(mDisplay, list, 1, XUTF8StringStyle, &textProperty) >= Success)
628 XSetWMName(mDisplay, window, &textProperty);
629 if(textProperty.value)
631 XFree(textProperty.value);
635 SetStringProperty(window, WindowSystemX::ATOM_NET_WM_NAME, name);
637 XClassHint* classHint = XAllocClassHint();
638 classHint->res_name = list[0];
639 classHint->res_class = strdup(className.c_str());
640 XSetClassHint(mDisplay, window, classHint);
641 free(classHint->res_class);
647 int mNextHandlerId{0};
648 using EventHandlerFunctionPointer = void (*)(const XEvent*);
649 std::unordered_map<int, EventHandlerFunctionPointer> mXEventHandlers;
650 std::vector<WindowSystemBase::EventHandler> mHandlers;
651 FileDescriptorMonitor* mXEventMonitor;
652 XIDeviceInfo* mXi2Devices{nullptr};
653 int mXi2NumberOfDevices{0};
657 WindowSystemX::WindowSystemX()
662 WindowSystemX::~WindowSystemX()
667 Dali::Any WindowSystemX::GetDisplay()
669 return Dali::Any(mImpl->mDisplay);
672 ::Display* WindowSystemX::GetXDisplay()
674 return mImpl->mDisplay;
677 void WindowSystemX::Sync()
679 XSync(mImpl->mDisplay, false);
682 void WindowSystemX::GetScreenSize(int& width, int& height)
684 ::Screen* screen = DefaultScreenOfDisplay(mImpl->mDisplay);
685 if(screen != nullptr)
687 width = screen->width;
688 height = screen->height;
692 WindowSystemBase::EventHandler* WindowSystemX::AddEventHandler(Event event, EventHandlerCallback callback, void* data)
694 return mImpl->AddEventHandler(event, callback, data);
697 void WindowSystemX::DeleteEventHandler(WindowSystemBase::EventHandler* eventHandler)
699 mImpl->DeleteEventHandler(eventHandler);
702 ::Window WindowSystemX::CreateWindow(int depth, int x, int y, int width, int height)
705 ::Window parent = DefaultRootWindow(mImpl->mDisplay);
707 XSetWindowAttributes attributes;
708 attributes.background_pixmap = None; /* background, None, or ParentRelative */
709 attributes.border_pixel = 0; /* border pixel value */
710 attributes.bit_gravity = NorthWestGravity; /* one of bit gravity values */
711 attributes.win_gravity = NorthWestGravity; /* one of the window gravity values */
712 attributes.backing_store = NotUseful; /* NotUseful, WhenMapped, Always */
713 attributes.save_under = false; /* should bits under be saved? (popups) */
714 attributes.event_mask = (KeyPressMask | /* set of events that should be saved */
722 VisibilityChangeMask |
723 StructureNotifyMask |
727 attributes.do_not_propagate_mask = NoEventMask; /* set of events that should not propagate */
728 attributes.override_redirect = false; /* boolean value for override_redirect */
729 attributes.cursor = None; /* cursor to be displayed (or None) */
733 Visual* visual{nullptr};
735 XVisualInfo visualInfoRequest;
736 visualInfoRequest.screen = DefaultScreen(mImpl->mDisplay);
737 visualInfoRequest.depth = 32;
738 visualInfoRequest.c_class = TrueColor;
740 XVisualInfo* visualInfoList = XGetVisualInfo(mImpl->mDisplay,
741 (VisualScreenMask | VisualDepthMask | VisualClassMask),
744 for(int i = 0; i < visualInfoCount; ++i)
746 XRenderPictFormat* pictFormat = XRenderFindVisualFormat(mImpl->mDisplay, visualInfoList[i].visual);
748 if(pictFormat->type == PictTypeDirect && pictFormat->direct.alphaMask)
750 visual = visualInfoList[i].visual;
754 XFree(visualInfoList);
756 attributes.colormap = XCreateColormap(mImpl->mDisplay, parent, visual, AllocNone); /* color map to be associated with window */
758 window = XCreateWindow(mImpl->mDisplay, parent, x, y, width, height, 0, 32, InputOutput, visual, (CWBackingStore | CWOverrideRedirect | CWColormap | CWBorderPixel | CWBackPixmap | CWSaveUnder | CWDontPropagate | CWEventMask | CWBitGravity | CWWinGravity), &attributes);
762 window = XCreateWindow(mImpl->mDisplay, parent, x, y, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, (CWBackingStore | CWOverrideRedirect | CWBorderPixel | CWBackPixmap | CWSaveUnder | CWDontPropagate | CWEventMask | CWBitGravity | CWWinGravity), &attributes);
766 SetWindowDefaults(window);
770 void WindowSystemX::SetWindowDefaults(::Window window)
772 char hostnameBuffer[HOST_NAME_MAX + 1];
773 gethostname(hostnameBuffer, HOST_NAME_MAX);
774 hostnameBuffer[HOST_NAME_MAX] = '\0';
776 hostname[0] = hostnameBuffer;
778 XTextProperty xTextProperty;
780 if(XStringListToTextProperty(hostname, 1, &xTextProperty))
782 XSetWMClientMachine(mImpl->mDisplay, window, &xTextProperty);
783 XFree(xTextProperty.value);
787 XChangeProperty(mImpl->mDisplay, window, ATOM_NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&pid, 1);
790 Atom atom = ATOM_NET_WM_WINDOW_TYPE_NORMAL;
791 XChangeProperty(mImpl->mDisplay, window, ATOM_NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (uint8_t*)&atom, 1);
793 //ecore_app_args_get(&argc, &argv);
794 //ecore_x_icccm_command_set(win, argc, argv);
797 void WindowSystemX::SetTransientForHint(::Window window, ::Window forWindow)
799 XSetTransientForHint(mImpl->mDisplay, window, forWindow);
803 void WindowSystemX::UnsetTransientFor(::Window window)
805 XDeleteProperty(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_TRANSIENT_FOR);
809 void WindowSystemX::SetProtocol(::Window window, Atom protocol, bool value)
811 Atom* protocols{nullptr};
812 int protocolsCount = 0;
814 Status status = XGetWMProtocols(mImpl->mDisplay, window, &protocols, &protocolsCount);
818 XSync(mImpl->mDisplay, false);
822 for(; index < protocolsCount; ++index)
824 if(protocols[index] == protocol)
832 std::vector<Atom> newProtocols;
833 newProtocols.resize(protocolsCount + 1);
835 for(int i = 0; i < protocolsCount; ++i)
837 newProtocols[i] = protocols[i];
839 newProtocols.back() = protocol;
841 XSetWMProtocols(mImpl->mDisplay, window, &newProtocols[0], newProtocols.size());
844 else if(!value && found)
846 // Remove the protocol
848 if(protocolsCount > 0)
850 for(int i = index; i < protocolsCount; ++i)
852 protocols[i] = protocols[i + 1];
854 XSetWMProtocols(mImpl->mDisplay, window, protocols, protocolsCount);
858 XDeleteProperty(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_PROTOCOLS);
865 void WindowSystemX::SetWindowHints(::Window window, bool acceptsFocus)
867 XWMHints* hints = XAllocWMHints();
870 hints->flags = InputHint | StateHint;
871 hints->input = acceptsFocus;
872 hints->initial_state = NormalState;
873 XSetWMHints(mImpl->mDisplay, window, hints);
878 WindowSystemX::WindowState WindowSystemX::GetWindowState(::Window window)
880 std::vector<unsigned long> hints;
881 if(GetWindowProperty<unsigned long>(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_STATE, WindowSystemX::ATOM_WM_STATE, hints))
883 if(hints.size() == 2)
889 return WindowSystemX::WindowState::WITHDRAWN;
893 return WindowSystemX::WindowState::NORMAL;
897 return WindowSystemX::WindowState::ICONIC;
902 return WindowSystemX::WindowState::NORMAL;
905 void WindowSystemX::Show(::Window window)
907 XMapWindow(mImpl->mDisplay, window);
911 void WindowSystemX::Hide(::Window window)
913 Window rootWindow = window;
915 unsigned int width, height, border, depth;
916 if(ScreenCount(mImpl->mDisplay) == 1)
918 rootWindow = DefaultRootWindow(mImpl->mDisplay);
922 // Need to get the root window in a different way
923 XGetGeometry(mImpl->mDisplay, window, &rootWindow, &x, &y, &width, &height, &border, &depth);
925 XUnmapWindow(mImpl->mDisplay, window);
927 event.xunmap.type = UnmapNotify;
928 event.xunmap.serial = 0;
929 event.xunmap.send_event = True;
930 event.xunmap.display = mImpl->mDisplay;
931 event.xunmap.window = window;
932 event.xunmap.from_configure = False;
934 XSendEvent(mImpl->mDisplay, rootWindow, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
938 void WindowSystemX::Activate(::Window window)
940 XWindowAttributes attributes;
941 Status status = XGetWindowAttributes(mImpl->mDisplay, window, &attributes);
942 ::Window root = (status > 0) ? attributes.root : DefaultRootWindow(mImpl->mDisplay);
945 event.xclient.type = ClientMessage;
946 event.xclient.display = mImpl->mDisplay;
947 event.xclient.window = window;
948 event.xclient.message_type = WindowSystemX::ATOM_NET_ACTIVE_WINDOW;
949 event.xclient.format = 32;
950 event.xclient.data.l[0] = 1;
951 event.xclient.data.l[1] = CurrentTime;
952 event.xclient.data.l[2] = 0;
953 event.xclient.data.l[3] = 0;
954 event.xclient.data.l[4] = 0;
955 XSendEvent(mImpl->mDisplay, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
958 void WindowSystemX::Raise(::Window window)
960 XRaiseWindow(mImpl->mDisplay, window);
964 void WindowSystemX::Lower(::Window window)
966 XLowerWindow(mImpl->mDisplay, window);
970 void WindowSystemX::TriggerEventHandler(WindowSystemBase::Event eventType, X11Event& event)
972 mImpl->TriggerEventHandler(eventType, event);
975 void WindowSystemX::GetDPI(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
977 Screen* screen = DefaultScreenOfDisplay(mImpl->mDisplay);
978 if(screen->mwidth <= 0)
980 dpiHorizontal = dpiVertical = 75;
984 dpiHorizontal = dpiVertical = (((screen->width * 254) / screen->mwidth) + 5) / 10;
988 void WindowSystemX::Move(::Window window, int x, int y)
990 mImpl->Move(window, x, y);
994 void WindowSystemX::Resize(::Window window, int width, int height)
996 mImpl->Resize(window, width, height);
1000 void WindowSystemX::MoveResize(::Window window, int x, int y, int width, int height)
1002 mImpl->MoveResize(window, x, y, width, height);
1006 void WindowSystemX::SetStringProperty(::Window window, Atom atom, const std::string& string)
1008 mImpl->SetStringProperty(window, atom, string);
1012 void WindowSystemX::SetClass(::Window window, const std::string& name, const std::string& className)
1014 mImpl->SetClass(window, name, className);
1018 void WindowSystemX::InputMultiSelect(::Window window)
1020 mImpl->InputMultiSelect(window);
1024 void WindowSystemX::EnableDragAndDrop(::Window window, bool enable)
1026 mImpl->EnableDragAndDrop(window, enable);
1030 WindowSystemX& GetImplementation()
1032 if(nullptr != gWindowSystem)
1036 return *gWindowSystem;
1039 void GetScreenSize(int& width, int& height)
1041 if(gWindowSystem != nullptr)
1043 gWindowSystem->GetScreenSize(width, height);
1047 bool SetKeyboardRepeatInfo(float rate, float delay)
1052 bool GetKeyboardRepeatInfo(float& rate, float& delay)
1057 } // namespace WindowSystem
1059 } // namespace Adaptor
1061 } // namespace Internal