2 * Copyright (c) 2023 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/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/integration-api/adaptor-framework/scene-holder.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/system/common/file-descriptor-monitor.h>
27 #include <dali/internal/system/common/system-factory.h>
28 #include <dali/internal/window-system/common/window-system.h>
31 #include <X11/XKBlib.h>
32 #include <X11/Xatom.h>
34 #include <X11/Xutil.h>
35 #include <X11/extensions/XInput2.h>
36 #include <X11/extensions/Xrender.h>
42 #include <unordered_map>
47 #include <sys/types.h>
57 const int MOUSE_SCROLL_WHEEL_UP{4};
58 const int MOUSE_SCROLL_WHEEL_DOWN{5};
59 const int MOUSE_SCROLL_WHEEL_LEFT{6};
60 const int MOUSE_SCROLL_WHEEL_RIGHT{7};
63 * @brief Get an XWindow property
65 * @tparam T - The type of data to return
66 * @param[in] display The display containing the window
67 * @param[in] window The window to get the property for
68 * @param[in] property The property to acquire
69 * @param[in] type The property type
70 * @param[out] data The property data
72 * @return true if the property was successfully retrieved
75 bool GetWindowProperty(::Display* display, ::Window window, ::Atom property, ::Atom type, std::vector<T>& data)
79 unsigned long numberOfItems = 0, bytesRemaining = 0;
80 unsigned char* propertyData{nullptr};
84 window = DefaultRootWindow(display);
87 XSync(display, false);
88 XGetWindowProperty(display, window, property, 0, LONG_MAX, False, type, &actualType, &actualFormat, &numberOfItems, &bytesRemaining, &propertyData);
90 if(actualFormat == 0 || numberOfItems == 0 || actualType != type)
100 if(sizeof(T) == sizeof(unsigned char))
102 data.resize(numberOfItems + 1); // Allow space for c-string terminator
103 for(int i = 0; i < numberOfItems + 1; ++i)
105 data[i] = static_cast<T>(propertyData[i]);
112 if(sizeof(T) == sizeof(unsigned short))
114 data.resize(numberOfItems);
115 for(int i = 0; i < numberOfItems; ++i)
117 data[i] = static_cast<T>(((unsigned short*)propertyData)[i]);
124 if(sizeof(T) == sizeof(unsigned long))
126 data.resize(numberOfItems);
127 for(unsigned long i = 0; i < numberOfItems; ++i)
129 // X returns native long type, regardless of whether it's actually 32 bits or not
130 data[i] = static_cast<T>(((unsigned long*)propertyData)[i]);
137 return data.size() != 0;
142 namespace WindowSystem
144 static WindowSystemX* gWindowSystem{nullptr};
145 static bool gGeometryHittest = false;
148 * Initialize the window system (currently run from the first window that gets created)
152 if(nullptr == gWindowSystem)
154 gWindowSystem = new WindowSystemX();
159 * Shutdown the window system (Currently run from the first window
163 if(nullptr != gWindowSystem)
165 delete gWindowSystem;
166 gWindowSystem = nullptr;
170 Atom WindowSystemX::ATOM_WM_PROTOCOLS{0};
171 Atom WindowSystemX::ATOM_WM_STATE{0};
172 Atom WindowSystemX::ATOM_WM_DELETE_WINDOW{0};
173 Atom WindowSystemX::ATOM_WM_TRANSIENT_FOR{0};
174 Atom WindowSystemX::ATOM_NET_ACTIVE_WINDOW{0};
175 Atom WindowSystemX::ATOM_NET_STARTUP_ID{0};
176 Atom WindowSystemX::ATOM_NET_WM_PID{0};
177 Atom WindowSystemX::ATOM_NET_WM_WINDOW_TYPE{0};
178 Atom WindowSystemX::ATOM_NET_WM_WINDOW_TYPE_NORMAL{0};
179 Atom WindowSystemX::ATOM_NET_WM_NAME{0};
180 Atom WindowSystemX::ATOM_UTF8_STRING{0};
188 const AtomItem atomItems[] =
190 {"UTF8_STRING", &WindowSystemX::ATOM_UTF8_STRING},
191 {"WM_DELETE_WINDOW", &WindowSystemX::ATOM_WM_DELETE_WINDOW},
192 {"WM_PROTOCOLS", &WindowSystemX::ATOM_WM_PROTOCOLS},
193 {"WM_STATE", &WindowSystemX::ATOM_WM_STATE},
194 {"WM_TRANSIENT_FOR", &WindowSystemX::ATOM_WM_TRANSIENT_FOR},
195 {"_NET_ACTIVE_WINDOW", &WindowSystemX::ATOM_NET_ACTIVE_WINDOW},
196 {"_NET_STARTUP_ID", &WindowSystemX::ATOM_NET_STARTUP_ID},
197 {"_NET_WM_NAME", &WindowSystemX::ATOM_NET_WM_NAME},
198 {"_NET_WM_PID", &WindowSystemX::ATOM_NET_WM_PID},
199 {"_NET_WM_WINDOW_TYPE", &WindowSystemX::ATOM_NET_WM_WINDOW_TYPE},
200 {"_NET_WM_WINDOW_TYPE_NORMAL", &WindowSystemX::ATOM_NET_WM_WINDOW_TYPE_NORMAL},
203 const int NUMBER_OF_ATOMS = sizeof(atomItems) / sizeof(AtomItem);
205 struct DeleteWindowRequest
210 void ConfigureNotifyEventHandler(const XEvent* xevent)
212 WindowSystemX::X11ConfigureNotifyEvent configureNotify;
213 configureNotify.window = xevent->xconfigure.window;
214 configureNotify.event = xevent;
216 configureNotify.x = xevent->xconfigure.x;
217 configureNotify.y = xevent->xconfigure.y;
218 configureNotify.width = xevent->xconfigure.width;
219 configureNotify.height = xevent->xconfigure.height;
221 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::CONFIGURE_NOTIFY, configureNotify);
224 void PropertyNotifyEventHandler(const XEvent* xevent)
226 WindowSystemX::X11PropertyNotifyEvent propertyNotifyEvent;
227 propertyNotifyEvent.window = xevent->xproperty.window;
228 propertyNotifyEvent.event = xevent;
229 propertyNotifyEvent.timestamp = xevent->xproperty.time;
230 propertyNotifyEvent.atom = xevent->xproperty.atom;
231 propertyNotifyEvent.state = xevent->xproperty.state;
232 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::PROPERTY_NOTIFY, propertyNotifyEvent);
235 void ClientMessageEventHandler(const XEvent* xevent)
237 if((xevent->xclient.message_type == WindowSystemX::ATOM_WM_PROTOCOLS) &&
238 (xevent->xclient.format == 32) &&
239 (static_cast<Atom>(xevent->xclient.data.l[0]) == WindowSystemX::ATOM_WM_DELETE_WINDOW))
241 WindowSystemX::X11Event x11Event;
242 x11Event.window = xevent->xclient.window;
243 x11Event.event = xevent;
245 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::DELETE_REQUEST, x11Event);
249 void FocusInEventHandler(const XEvent* xevent)
251 WindowSystemX::X11Event x11Event;
252 x11Event.window = xevent->xclient.window;
253 x11Event.event = xevent;
254 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::FOCUS_IN, x11Event);
257 void FocusOutEventHandler(const XEvent* xevent)
259 WindowSystemX::X11Event x11Event;
260 x11Event.window = xevent->xclient.window;
261 x11Event.event = xevent;
262 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::FOCUS_OUT, x11Event);
265 void ExposeEventHandler(const XEvent* xevent)
267 WindowSystemX::X11ExposeEvent x11ExposeEvent;
268 x11ExposeEvent.window = xevent->xclient.window;
269 x11ExposeEvent.event = xevent;
270 x11ExposeEvent.x = xevent->xexpose.x;
271 x11ExposeEvent.y = xevent->xexpose.y;
272 x11ExposeEvent.width = xevent->xexpose.width;
273 x11ExposeEvent.height = xevent->xexpose.height;
274 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::DAMAGE, x11ExposeEvent);
277 void HandlePointerMove(int x, int y, unsigned long timestamp, ::Window window)
279 WindowSystemX::X11MouseEvent mouseEvent;
280 mouseEvent.window = window;
281 mouseEvent.timestamp = timestamp;
284 mouseEvent.buttons = 0;
285 mouseEvent.device = 0;
286 mouseEvent.multi.pressure = 1.0f;
287 mouseEvent.multi.angle = 0.0f;
288 mouseEvent.multi.radius = 1;
289 mouseEvent.multi.radiusX = 1;
290 mouseEvent.multi.radiusY = 1;
291 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_MOVE, mouseEvent);
294 void ConvertButtonEvent(const XEvent* xevent, WindowSystemX::X11MouseEvent& mouseEvent)
296 mouseEvent.window = xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window;
297 mouseEvent.timestamp = xevent->xbutton.time;
298 mouseEvent.x = xevent->xbutton.x;
299 mouseEvent.y = xevent->xbutton.y;
300 mouseEvent.buttons = xevent->xbutton.button;
301 mouseEvent.device = 0;
302 mouseEvent.multi.pressure = 1.0f;
303 mouseEvent.multi.angle = 0.0f;
304 mouseEvent.multi.radius = 1;
305 mouseEvent.multi.radiusX = 1;
306 mouseEvent.multi.radiusY = 1;
309 void ButtonPressEventHandler(const XEvent* xevent)
311 if(xevent->xbutton.button < MOUSE_SCROLL_WHEEL_UP || xevent->xbutton.button > MOUSE_SCROLL_WHEEL_RIGHT)
313 HandlePointerMove(xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.time, xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
315 WindowSystemX::X11MouseEvent mouseEvent;
316 ConvertButtonEvent(xevent, mouseEvent);
317 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_BUTTON_DOWN, mouseEvent);
319 else // Otherwise, it's a mouse wheel event
321 WindowSystemX::X11MouseWheelEvent mouseWheelEvent;
322 mouseWheelEvent.x = xevent->xbutton.x;
323 mouseWheelEvent.y = xevent->xbutton.y;
324 mouseWheelEvent.window = (xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
325 mouseWheelEvent.timestamp = xevent->xbutton.time;
327 switch(xevent->xbutton.button)
329 case MOUSE_SCROLL_WHEEL_UP:
331 mouseWheelEvent.direction = 0;
332 mouseWheelEvent.z = -1;
335 case MOUSE_SCROLL_WHEEL_DOWN:
337 mouseWheelEvent.direction = 0;
338 mouseWheelEvent.z = 1;
341 case MOUSE_SCROLL_WHEEL_LEFT:
343 mouseWheelEvent.direction = 1;
344 mouseWheelEvent.z = -1;
347 case MOUSE_SCROLL_WHEEL_RIGHT:
349 mouseWheelEvent.direction = 1;
350 mouseWheelEvent.z = 1;
354 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_WHEEL, mouseWheelEvent);
358 void ButtonReleaseEventHandler(const XEvent* xevent)
360 // Check it's a normal button, not a mouse wheel button
361 if(xevent->xbutton.button < MOUSE_SCROLL_WHEEL_UP || xevent->xbutton.button > MOUSE_SCROLL_WHEEL_RIGHT)
363 HandlePointerMove(xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.time, xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->xbutton.window);
365 WindowSystemX::X11MouseEvent mouseEvent;
366 ConvertButtonEvent(xevent, mouseEvent);
367 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::MOUSE_BUTTON_UP, mouseEvent);
369 // ignore wheel release events, they are sent immediately prior to another press event
372 void MotionNotifyEventHandler(const XEvent* xevent)
374 HandlePointerMove(xevent->xmotion.x, xevent->xmotion.y, xevent->xmotion.time, xevent->xmotion.subwindow ? xevent->xmotion.subwindow : xevent->xmotion.window);
377 void EnterNotifyEventHandler(const XEvent* xevent)
379 HandlePointerMove(xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.time, xevent->xcrossing.subwindow ? xevent->xcrossing.subwindow : xevent->xcrossing.window);
381 void LeaveNotifyEventHandler(const XEvent* xevent)
383 HandlePointerMove(xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.time, xevent->xcrossing.subwindow ? xevent->xcrossing.subwindow : xevent->xcrossing.window);
386 void ConvertKeyEvent(const XEvent* xEvent, WindowSystemX::X11KeyEvent& keyEvent)
388 const XKeyEvent* xKeyEvent = &(xEvent->xkey);
390 keyEvent.keyCode = xKeyEvent->keycode;
392 KeySym keySymbol = XkbKeycodeToKeysym(xKeyEvent->display, xKeyEvent->keycode, 0, 0);
393 char* keyname = XKeysymToString(keySymbol);
396 asprintf(&keyname, "Keycode-%i", xKeyEvent->keycode);
397 keyEvent.keyname = keyname;
402 keyEvent.keyname = keyname;
405 keyEvent.timestamp = xKeyEvent->time;
406 keyEvent.modifiers = xKeyEvent->state; // @todo add own modifier list
407 keyEvent.window = xKeyEvent->window;
408 keyEvent.event = xEvent;
411 XComposeStatus composeStatus;
412 const int BUFFER_LENGTH{256};
413 char buffer[BUFFER_LENGTH];
414 int stringLength = XLookupString(const_cast<XKeyEvent*>(xKeyEvent), buffer, BUFFER_LENGTH, &keySymbol2, &composeStatus);
416 const char* key{nullptr};
417 if(keySymbol != keySymbol2)
419 key = XKeysymToString(keySymbol2);
423 key = keyEvent.keyname.c_str();
427 buffer[std::max(0, std::min(BUFFER_LENGTH - 1, stringLength))] = '\0';
429 keyEvent.compose = stringLength ? buffer : "";
432 void KeyPressEventHandler(const XEvent* xevent)
434 WindowSystemX::X11KeyEvent x11KeyEvent;
435 ConvertKeyEvent(xevent, x11KeyEvent);
436 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::KEY_DOWN, x11KeyEvent);
439 void KeyReleaseEventHandler(const XEvent* xevent)
441 WindowSystemX::X11KeyEvent x11KeyEvent;
442 ConvertKeyEvent(xevent, x11KeyEvent);
443 GetImplementation().TriggerEventHandler(WindowSystemBase::Event::KEY_UP, x11KeyEvent);
446 void SelectionClearEventHandler(const XEvent* xevent)
451 void SelectionNotifyEventHandler(const XEvent* xevent)
456 struct WindowSystemX::Impl
461 mDisplay = XOpenDisplay(nullptr); // Note, DisplayConnection now reads this var.
463 mXEventMonitor = Dali::Internal::Adaptor::GetSystemFactory()->CreateFileDescriptorMonitor(
464 ConnectionNumber(mDisplay),
465 MakeCallback(this, &WindowSystemX::Impl::XPollCallback),
466 FileDescriptorMonitor::FD_READABLE);
467 // libuv hacks: add FD_WRITABLE.
470 SetupEventHandlers();
476 // @todo Flush events, delete fd handlers, shutdown other X subsystems
477 XCloseDisplay(mDisplay);
480 ::Display* GetXDisplay()
485 void XPollCallback(FileDescriptorMonitor::EventType eventType)
487 if(eventType & (FileDescriptorMonitor::FD_READABLE | FileDescriptorMonitor::FD_WRITABLE))
489 while(XPending(mDisplay))
492 XNextEvent(mDisplay, &event);
498 void InitializeAtoms()
500 std::vector<Atom> atoms;
501 std::vector<const char*> names;
502 atoms.resize(NUMBER_OF_ATOMS);
503 names.resize(NUMBER_OF_ATOMS);
504 for(unsigned int i = 0; i < NUMBER_OF_ATOMS; ++i)
506 names[i] = atomItems[i].name.c_str();
508 Status status = XInternAtoms(mDisplay, const_cast<char**>(&names[0]), NUMBER_OF_ATOMS, false, &atoms[0]);
511 for(unsigned int i = 0; i < NUMBER_OF_ATOMS; ++i)
513 *(atomItems[i].atom) = atoms[i];
518 void SetupEventHandlers()
520 mXEventHandlers[PropertyNotify] = &PropertyNotifyEventHandler;
521 mXEventHandlers[ClientMessage] = &ClientMessageEventHandler;
522 mXEventHandlers[FocusIn] = &FocusInEventHandler;
523 mXEventHandlers[FocusOut] = &FocusOutEventHandler;
524 mXEventHandlers[Expose] = &ExposeEventHandler;
525 mXEventHandlers[ButtonPress] = &ButtonPressEventHandler;
526 mXEventHandlers[ButtonRelease] = &ButtonReleaseEventHandler;
527 mXEventHandlers[MotionNotify] = &MotionNotifyEventHandler;
528 mXEventHandlers[EnterNotify] = &EnterNotifyEventHandler;
529 mXEventHandlers[LeaveNotify] = &LeaveNotifyEventHandler;
530 mXEventHandlers[KeyPress] = &KeyPressEventHandler;
531 mXEventHandlers[KeyRelease] = &KeyReleaseEventHandler;
532 mXEventHandlers[SelectionClear] = &SelectionClearEventHandler;
533 mXEventHandlers[SelectionNotify] = &SelectionNotifyEventHandler;
534 mXEventHandlers[ConfigureNotify] = &ConfigureNotifyEventHandler;
537 void InitializeInput()
541 if(XQueryExtension(mDisplay, "XInputExtension", &mXi2OpCode, &event, &error))
543 // Extension is present
544 int majorVersion = XI_2_Major;
545 int minorVersion = XI_2_Minor;
547 Status status = XIQueryVersion(mDisplay, &majorVersion, &minorVersion);
548 if(status == Success)
550 // @todo May need to enable DeviceChanged, HierarchyChanged and PropertyEvent masks.
551 mXi2Devices = XIQueryDevice(mDisplay, XIAllDevices, &mXi2NumberOfDevices);
558 // @todo Clear any events set in InitializeInput()
561 XIFreeDeviceInfo(mXi2Devices);
562 mXi2Devices = nullptr;
564 mXi2NumberOfDevices = 0;
568 void InputMultiSelect(::Window window)
570 // NOT IMPLEMENTED. See ecore_x_input_multi_select(mEcoreWindow);
572 void EnableDragAndDrop(::Window window, bool enable)
574 // NOT IMPLEMENTED. See ecore_x_dnd_aware_set(mEcoreWindow, enable);
577 // Call the internal X11 event handler. This will call TriggerEventHandler which
578 // will call each registered handler's callback.
579 void HandleXEvent(const XEvent& event)
581 auto iter = mXEventHandlers.find(event.type);
582 if(iter != mXEventHandlers.end())
584 iter->second(&event);
588 WindowSystemBase::EventHandler* AddEventHandler(WindowSystemBase::Event event,
589 WindowSystemBase::EventHandlerCallback callback,
592 mHandlers.emplace_back(EventHandler{callback, data, event, ++mNextHandlerId});
593 return &mHandlers.back();
596 void DeleteEventHandler(WindowSystemBase::EventHandler* eventHandler)
598 int id = eventHandler->handlerId;
599 auto iter = std::find_if(mHandlers.begin(), mHandlers.end(), [id](const WindowSystemBase::EventHandler& eventHandler) { return eventHandler.handlerId == id; });
600 if(iter != mHandlers.end())
602 mHandlers.erase(iter);
606 void TriggerEventHandler(WindowSystemBase::Event eventType, WindowSystemX::X11Event& x11Event)
608 //@todo make this much more efficient!
609 for(auto& element : mHandlers)
611 if(element.event == eventType)
613 bool stop = element.callback(element.data, eventType, &x11Event);
622 void Move(::Window window, int x, int y)
624 XMoveWindow(mDisplay, window, x, y);
626 void Resize(::Window window, int width, int height)
628 XResizeWindow(mDisplay, window, std::max(1, width), std::max(1, height));
631 void MoveResize(::Window window, int x, int y, int width, int height)
633 XMoveResizeWindow(mDisplay, window, x, y, std::max(1, width), std::max(1, height));
636 void SetStringProperty(::Window window, Atom atom, const std::string& string)
638 XChangeProperty(mDisplay, window, atom, WindowSystemX::ATOM_UTF8_STRING, 8, PropModeReplace, (unsigned char*)string.c_str(), string.length());
641 void SetClass(::Window window, const std::string& name, const std::string& className)
643 char* list[] = {strdup(name.c_str())};
644 XTextProperty textProperty;
645 if(Xutf8TextListToTextProperty(mDisplay, list, 1, XUTF8StringStyle, &textProperty) >= Success)
647 XSetWMName(mDisplay, window, &textProperty);
648 if(textProperty.value)
650 XFree(textProperty.value);
654 SetStringProperty(window, WindowSystemX::ATOM_NET_WM_NAME, name);
656 XClassHint* classHint = XAllocClassHint();
657 classHint->res_name = list[0];
658 classHint->res_class = strdup(className.c_str());
659 XSetClassHint(mDisplay, window, classHint);
660 free(classHint->res_class);
666 int mNextHandlerId{0};
667 using EventHandlerFunctionPointer = void (*)(const XEvent*);
668 std::unordered_map<int, EventHandlerFunctionPointer> mXEventHandlers;
669 std::vector<WindowSystemBase::EventHandler> mHandlers;
670 std::unique_ptr<FileDescriptorMonitor> mXEventMonitor;
671 XIDeviceInfo* mXi2Devices{nullptr};
672 int mXi2NumberOfDevices{0};
676 WindowSystemX::WindowSystemX()
681 WindowSystemX::~WindowSystemX()
686 Dali::Any WindowSystemX::GetDisplay()
688 return Dali::Any(mImpl->mDisplay);
691 ::Display* WindowSystemX::GetXDisplay()
693 return mImpl->mDisplay;
696 void WindowSystemX::Sync()
698 XSync(mImpl->mDisplay, false);
701 void WindowSystemX::GetScreenSize(int& width, int& height)
703 ::Screen* screen = DefaultScreenOfDisplay(mImpl->mDisplay);
704 if(screen != nullptr)
706 width = screen->width;
707 height = screen->height;
711 WindowSystemBase::EventHandler* WindowSystemX::AddEventHandler(Event event, EventHandlerCallback callback, void* data)
713 return mImpl->AddEventHandler(event, callback, data);
716 void WindowSystemX::DeleteEventHandler(WindowSystemBase::EventHandler* eventHandler)
718 mImpl->DeleteEventHandler(eventHandler);
721 ::Window WindowSystemX::CreateWindow(int depth, int x, int y, int width, int height)
724 ::Window parent = DefaultRootWindow(mImpl->mDisplay);
726 XSetWindowAttributes attributes;
727 attributes.background_pixmap = None; /* background, None, or ParentRelative */
728 attributes.border_pixel = 0; /* border pixel value */
729 attributes.bit_gravity = NorthWestGravity; /* one of bit gravity values */
730 attributes.win_gravity = NorthWestGravity; /* one of the window gravity values */
731 attributes.backing_store = NotUseful; /* NotUseful, WhenMapped, Always */
732 attributes.save_under = false; /* should bits under be saved? (popups) */
733 attributes.event_mask = (KeyPressMask | /* set of events that should be saved */
740 StructureNotifyMask |
742 VisibilityChangeMask |
743 StructureNotifyMask |
747 attributes.do_not_propagate_mask = NoEventMask; /* set of events that should not propagate */
748 attributes.override_redirect = false; /* boolean value for override_redirect */
749 attributes.cursor = None; /* cursor to be displayed (or None) */
753 Visual* visual{nullptr};
755 XVisualInfo visualInfoRequest;
756 visualInfoRequest.screen = DefaultScreen(mImpl->mDisplay);
757 visualInfoRequest.depth = 32;
758 visualInfoRequest.c_class = TrueColor;
760 XVisualInfo* visualInfoList = XGetVisualInfo(mImpl->mDisplay,
761 (VisualScreenMask | VisualDepthMask | VisualClassMask),
764 for(int i = 0; i < visualInfoCount; ++i)
766 XRenderPictFormat* pictFormat = XRenderFindVisualFormat(mImpl->mDisplay, visualInfoList[i].visual);
768 if(pictFormat->type == PictTypeDirect && pictFormat->direct.alphaMask)
770 visual = visualInfoList[i].visual;
774 XFree(visualInfoList);
776 attributes.colormap = XCreateColormap(mImpl->mDisplay, parent, visual, AllocNone); /* color map to be associated with window */
778 window = XCreateWindow(mImpl->mDisplay, parent, x, y, width, height, 0, 32, InputOutput, visual, (CWBackingStore | CWOverrideRedirect | CWColormap | CWBorderPixel | CWBackPixmap | CWSaveUnder | CWDontPropagate | CWEventMask | CWBitGravity | CWWinGravity), &attributes);
782 window = XCreateWindow(mImpl->mDisplay, parent, x, y, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, (CWBackingStore | CWOverrideRedirect | CWBorderPixel | CWBackPixmap | CWSaveUnder | CWDontPropagate | CWEventMask | CWBitGravity | CWWinGravity), &attributes);
786 SetWindowDefaults(window);
790 void WindowSystemX::SetWindowDefaults(::Window window)
792 char hostnameBuffer[HOST_NAME_MAX + 1];
793 gethostname(hostnameBuffer, HOST_NAME_MAX);
794 hostnameBuffer[HOST_NAME_MAX] = '\0';
796 hostname[0] = hostnameBuffer;
798 XTextProperty xTextProperty;
800 if(XStringListToTextProperty(hostname, 1, &xTextProperty))
802 XSetWMClientMachine(mImpl->mDisplay, window, &xTextProperty);
803 XFree(xTextProperty.value);
807 XChangeProperty(mImpl->mDisplay, window, ATOM_NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&pid, 1);
810 Atom atom = ATOM_NET_WM_WINDOW_TYPE_NORMAL;
811 XChangeProperty(mImpl->mDisplay, window, ATOM_NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (uint8_t*)&atom, 1);
813 //ecore_app_args_get(&argc, &argv);
814 //ecore_x_icccm_command_set(win, argc, argv);
817 void WindowSystemX::SetTransientForHint(::Window window, ::Window forWindow)
819 XSetTransientForHint(mImpl->mDisplay, window, forWindow);
823 void WindowSystemX::UnsetTransientFor(::Window window)
825 XDeleteProperty(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_TRANSIENT_FOR);
829 void WindowSystemX::SetProtocol(::Window window, Atom protocol, bool value)
831 Atom* protocols{nullptr};
832 int protocolsCount = 0;
834 Status status = XGetWMProtocols(mImpl->mDisplay, window, &protocols, &protocolsCount);
838 XSync(mImpl->mDisplay, false);
842 for(; index < protocolsCount; ++index)
844 if(protocols[index] == protocol)
852 std::vector<Atom> newProtocols;
853 newProtocols.resize(protocolsCount + 1);
855 for(int i = 0; i < protocolsCount; ++i)
857 newProtocols[i] = protocols[i];
859 newProtocols.back() = protocol;
861 XSetWMProtocols(mImpl->mDisplay, window, &newProtocols[0], newProtocols.size());
864 else if(!value && found)
866 // Remove the protocol
868 if(protocolsCount > 0)
870 for(int i = index; i < protocolsCount; ++i)
872 protocols[i] = protocols[i + 1];
874 XSetWMProtocols(mImpl->mDisplay, window, protocols, protocolsCount);
878 XDeleteProperty(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_PROTOCOLS);
885 void WindowSystemX::SetWindowHints(::Window window, bool acceptsFocus)
887 XWMHints* hints = XAllocWMHints();
890 hints->flags = InputHint | StateHint;
891 hints->input = acceptsFocus;
892 hints->initial_state = NormalState;
893 XSetWMHints(mImpl->mDisplay, window, hints);
898 WindowSystemX::WindowState WindowSystemX::GetWindowState(::Window window)
900 std::vector<unsigned long> hints;
901 if(GetWindowProperty<unsigned long>(mImpl->mDisplay, window, WindowSystemX::ATOM_WM_STATE, WindowSystemX::ATOM_WM_STATE, hints))
903 if(hints.size() == 2)
909 return WindowSystemX::WindowState::WITHDRAWN;
913 return WindowSystemX::WindowState::NORMAL;
917 return WindowSystemX::WindowState::ICONIC;
922 return WindowSystemX::WindowState::NORMAL;
925 void WindowSystemX::Show(::Window window)
927 XMapWindow(mImpl->mDisplay, window);
931 void WindowSystemX::Hide(::Window window)
933 ::Window rootWindow = window;
935 unsigned int width, height, border, depth;
936 if(ScreenCount(mImpl->mDisplay) == 1)
938 rootWindow = DefaultRootWindow(mImpl->mDisplay);
942 // Need to get the root window in a different way
943 XGetGeometry(mImpl->mDisplay, window, &rootWindow, &x, &y, &width, &height, &border, &depth);
945 XUnmapWindow(mImpl->mDisplay, window);
947 event.xunmap.type = UnmapNotify;
948 event.xunmap.serial = 0;
949 event.xunmap.send_event = True;
950 event.xunmap.display = mImpl->mDisplay;
951 event.xunmap.window = window;
952 event.xunmap.from_configure = False;
954 XSendEvent(mImpl->mDisplay, rootWindow, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
958 void WindowSystemX::Activate(::Window window)
960 XWindowAttributes attributes;
961 Status status = XGetWindowAttributes(mImpl->mDisplay, window, &attributes);
962 ::Window root = (status > 0) ? attributes.root : DefaultRootWindow(mImpl->mDisplay);
965 event.xclient.type = ClientMessage;
966 event.xclient.display = mImpl->mDisplay;
967 event.xclient.window = window;
968 event.xclient.message_type = WindowSystemX::ATOM_NET_ACTIVE_WINDOW;
969 event.xclient.format = 32;
970 event.xclient.data.l[0] = 1;
971 event.xclient.data.l[1] = CurrentTime;
972 event.xclient.data.l[2] = 0;
973 event.xclient.data.l[3] = 0;
974 event.xclient.data.l[4] = 0;
975 XSendEvent(mImpl->mDisplay, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
978 void WindowSystemX::Raise(::Window window)
980 XRaiseWindow(mImpl->mDisplay, window);
984 void WindowSystemX::Lower(::Window window)
986 XLowerWindow(mImpl->mDisplay, window);
990 void WindowSystemX::TriggerEventHandler(WindowSystemBase::Event eventType, X11Event& event)
992 mImpl->TriggerEventHandler(eventType, event);
995 void WindowSystemX::GetDPI(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
997 Screen* screen = DefaultScreenOfDisplay(mImpl->mDisplay);
998 if(screen->mwidth <= 0)
1000 dpiHorizontal = dpiVertical = 75;
1004 dpiHorizontal = dpiVertical = (((screen->width * 254) / screen->mwidth) + 5) / 10;
1008 void WindowSystemX::Move(::Window window, int x, int y)
1010 mImpl->Move(window, x, y);
1014 void WindowSystemX::Resize(::Window window, int width, int height)
1016 mImpl->Resize(window, width, height);
1020 void WindowSystemX::MoveResize(::Window window, int x, int y, int width, int height)
1022 mImpl->MoveResize(window, x, y, width, height);
1026 void WindowSystemX::SetStringProperty(::Window window, Atom atom, const std::string& string)
1028 mImpl->SetStringProperty(window, atom, string);
1032 void WindowSystemX::SetClass(::Window window, const std::string& name, const std::string& className)
1034 mImpl->SetClass(window, name, className);
1038 void WindowSystemX::InputMultiSelect(::Window window)
1040 mImpl->InputMultiSelect(window);
1044 void WindowSystemX::EnableDragAndDrop(::Window window, bool enable)
1046 mImpl->EnableDragAndDrop(window, enable);
1050 WindowSystemX& GetImplementation()
1052 if(nullptr != gWindowSystem)
1056 return *gWindowSystem;
1059 void GetScreenSize(int& width, int& height)
1061 if(gWindowSystem != nullptr)
1063 gWindowSystem->GetScreenSize(width, height);
1067 void UpdateScreenSize()
1071 bool SetKeyboardRepeatInfo(float rate, float delay)
1076 bool GetKeyboardRepeatInfo(float& rate, float& delay)
1081 bool SetKeyboardHorizontalRepeatInfo(float rate, float delay)
1086 bool GetKeyboardHorizontalRepeatInfo(float& rate, float& delay)
1091 bool SetKeyboardVerticalRepeatInfo(float rate, float delay)
1096 bool GetKeyboardVerticalRepeatInfo(float& rate, float& delay)
1101 void SetGeometryHittestEnabled(bool enable)
1103 DALI_LOG_RELEASE_INFO("GeometryHittest : %d \n", enable);
1104 gGeometryHittest = enable;
1105 if(gGeometryHittest)
1107 Dali::SceneHolderList sceneHolders = Dali::Adaptor::Get().GetSceneHolders();
1108 for(auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter)
1112 (*iter).SetGeometryHittestEnabled(enable);
1118 bool IsGeometryHittestEnabled()
1120 return gGeometryHittest;
1123 } // namespace WindowSystem
1125 } // namespace Adaptor
1127 } // namespace Internal