2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "WinSystemX11.h"
11 #include "CompileInfo.h"
12 #include "OSScreenSaverX11.h"
13 #include "ServiceBroker.h"
14 #include "WinEventsX11.h"
16 #include "guilib/DispResource.h"
17 #include "guilib/Texture.h"
18 #include "input/InputManager.h"
19 #include "messaging/ApplicationMessenger.h"
20 #include "settings/DisplaySettings.h"
21 #include "settings/Settings.h"
22 #include "settings/SettingsComponent.h"
23 #include "settings/lib/Setting.h"
24 #include "utils/StringUtils.h"
25 #include "utils/TimeUtils.h"
26 #include "utils/log.h"
27 #include "windowing/GraphicContext.h"
34 #include <X11/Xatom.h>
35 #include <X11/extensions/Xrandr.h>
37 using namespace KODI::WINDOWING::X11
;
39 using namespace std::chrono_literals
;
41 #define EGL_NO_CONFIG (EGLConfig)0
43 CWinSystemX11::CWinSystemX11() : CWinSystemBase()
46 m_bWasFullScreenBeforeMinimize
= false;
48 m_bIgnoreNextFocusMessage
= false;
49 m_bIsInternalXrr
= false;
50 m_delayDispReset
= false;
52 XSetErrorHandler(XErrorHandler
);
54 m_winEventsX11
= new CWinEventsX11(*this);
55 m_winEvents
.reset(m_winEventsX11
);
58 CWinSystemX11::~CWinSystemX11() = default;
60 bool CWinSystemX11::InitWindowSystem()
62 const char* env
= getenv("DISPLAY");
65 CLog::Log(LOGDEBUG
, "CWinSystemX11::{} - DISPLAY env not set", __FUNCTION__
);
69 if ((m_dpy
= XOpenDisplay(NULL
)))
71 bool ret
= CWinSystemBase::InitWindowSystem();
73 CServiceBroker::GetSettingsComponent()
75 ->GetSetting(CSettings::SETTING_VIDEOSCREEN_LIMITEDRANGE
)
81 CLog::Log(LOGERROR
, "X11 Error: No Display found");
86 bool CWinSystemX11::DestroyWindowSystem()
88 //restore desktop resolution on exit
93 out
.name
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).strOutput
;
94 mode
.w
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).iWidth
;
95 mode
.h
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).iHeight
;
96 mode
.hz
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).fRefreshRate
;
97 mode
.id
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).strId
;
98 g_xrandr
.SetMode(out
, mode
);
104 bool CWinSystemX11::CreateNewWindow(const std::string
& name
, bool fullScreen
, RESOLUTION_INFO
& res
)
106 if(!SetFullScreen(fullScreen
, res
, false))
109 m_bWindowCreated
= true;
113 bool CWinSystemX11::DestroyWindow()
118 if (m_invisibleCursor
)
120 XUndefineCursor(m_dpy
, m_mainWindow
);
121 XFreeCursor(m_dpy
, m_invisibleCursor
);
122 m_invisibleCursor
= 0;
125 m_winEventsX11
->Quit();
127 XUnmapWindow(m_dpy
, m_mainWindow
);
128 XDestroyWindow(m_dpy
, m_glWindow
);
129 XDestroyWindow(m_dpy
, m_mainWindow
);
134 XFreePixmap(m_dpy
, m_icon
);
139 bool CWinSystemX11::ResizeWindow(int newWidth
, int newHeight
, int newLeft
, int newTop
)
141 m_userOutput
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
);
143 if (m_userOutput
.compare("Default") != 0)
145 out
= g_xrandr
.GetOutput(m_userOutput
);
148 XMode mode
= g_xrandr
.GetCurrentMode(m_userOutput
);
157 std::vector
<XOutput
> outputs
= g_xrandr
.GetModes();
158 if (!outputs
.empty())
160 m_userOutput
= outputs
[0].name
;
164 if (!SetWindow(newWidth
, newHeight
, false, m_userOutput
))
170 m_nHeight
= newHeight
;
171 m_bFullScreen
= false;
172 m_currentOutput
= m_userOutput
;
177 void CWinSystemX11::FinishWindowResize(int newWidth
, int newHeight
)
179 m_userOutput
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
);
181 if (m_userOutput
.compare("Default") != 0)
183 out
= g_xrandr
.GetOutput(m_userOutput
);
186 XMode mode
= g_xrandr
.GetCurrentMode(m_userOutput
);
195 std::vector
<XOutput
> outputs
= g_xrandr
.GetModes();
196 if (!outputs
.empty())
198 m_userOutput
= outputs
[0].name
;
202 XResizeWindow(m_dpy
, m_glWindow
, newWidth
, newHeight
);
205 if (m_userOutput
.compare(m_currentOutput
) != 0)
207 SetWindow(newWidth
, newHeight
, false, m_userOutput
);
211 m_nHeight
= newHeight
;
214 bool CWinSystemX11::SetFullScreen(bool fullScreen
, RESOLUTION_INFO
& res
, bool blankOtherDisplays
)
221 out
.name
= res
.strOutput
;
223 mode
.h
= res
.iHeight
;
224 mode
.hz
= res
.fRefreshRate
;
229 out
.name
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).strOutput
;
230 mode
.w
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).iWidth
;
231 mode
.h
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).iHeight
;
232 mode
.hz
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).fRefreshRate
;
233 mode
.id
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).strId
;
236 XMode currmode
= g_xrandr
.GetCurrentMode(out
.name
);
237 if (!currmode
.name
.empty())
239 // flip h/w when rotated
247 // only call xrandr if mode changes
250 if (currmode
.w
!= mode
.w
|| currmode
.h
!= mode
.h
||
251 currmode
.hz
!= mode
.hz
|| currmode
.id
!= mode
.id
)
253 CLog::Log(LOGINFO
, "CWinSystemX11::SetFullScreen - calling xrandr");
255 // remember last position of mouse
256 Window root_return
, child_return
;
257 int root_x_return
, root_y_return
;
258 int win_x_return
, win_y_return
;
259 unsigned int mask_return
;
260 bool isInWin
= XQueryPointer(m_dpy
, m_mainWindow
, &root_return
, &child_return
,
261 &root_x_return
, &root_y_return
,
262 &win_x_return
, &win_y_return
,
267 m_MouseX
= win_x_return
;
268 m_MouseY
= win_y_return
;
277 m_bIsInternalXrr
= true;
278 g_xrandr
.SetMode(out
, mode
);
280 std::chrono::milliseconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
281 "videoscreen.delayrefreshchange") *
285 m_delayDispReset
= true;
286 m_dispResetTimer
.Set(delay
);
293 if (!SetWindow(res
.iWidth
, res
.iHeight
, fullScreen
, m_userOutput
))
296 m_nWidth
= res
.iWidth
;
297 m_nHeight
= res
.iHeight
;
298 m_bFullScreen
= fullScreen
;
299 m_currentOutput
= m_userOutput
;
304 void CWinSystemX11::UpdateResolutions()
306 CWinSystemBase::UpdateResolutions();
308 int numScreens
= XScreenCount(m_dpy
);
309 g_xrandr
.SetNumScreens(numScreens
);
311 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
312 bool switchOnOff
= settings
->GetBool(CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS
);
313 m_userOutput
= settings
->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
);
314 if (m_userOutput
.compare("Default") == 0)
317 if(g_xrandr
.Query(true, !switchOnOff
))
320 if (m_userOutput
.compare("Default") != 0)
322 out
= g_xrandr
.GetOutput(m_userOutput
);
325 XMode mode
= g_xrandr
.GetCurrentMode(m_userOutput
);
326 if (!mode
.isCurrent
&& !switchOnOff
)
334 m_userOutput
= g_xrandr
.GetModes()[0].name
;
335 out
= g_xrandr
.GetOutput(m_userOutput
);
341 g_xrandr
.TurnOnOutput(m_userOutput
);
343 // switch off other outputs
344 std::vector
<XOutput
> outputs
= g_xrandr
.GetModes();
345 for (size_t i
=0; i
<outputs
.size(); i
++)
347 if (StringUtils::EqualsNoCase(outputs
[i
].name
, m_userOutput
))
349 g_xrandr
.TurnOffOutput(outputs
[i
].name
);
353 XMode mode
= g_xrandr
.GetCurrentMode(m_userOutput
);
355 mode
= g_xrandr
.GetPreferredMode(m_userOutput
);
356 m_bIsRotated
= out
->isRotated
;
358 UpdateDesktopResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
), out
->name
, mode
.w
, mode
.h
, mode
.hz
, 0);
360 UpdateDesktopResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
), out
->name
, mode
.h
, mode
.w
, mode
.hz
, 0);
361 CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
).strId
= mode
.id
;
365 m_userOutput
= "No Output";
366 m_screen
= DefaultScreen(m_dpy
);
367 int w
= DisplayWidth(m_dpy
, m_screen
);
368 int h
= DisplayHeight(m_dpy
, m_screen
);
369 UpdateDesktopResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
), m_userOutput
, w
, h
, 0.0, 0);
372 // erase previous stored modes
373 CDisplaySettings::GetInstance().ClearCustomResolutions();
375 CLog::Log(LOGINFO
, "Available videomodes (xrandr):");
377 XOutput
*out
= g_xrandr
.GetOutput(m_userOutput
);
380 CLog::Log(LOGINFO
, "Output '{}' has {} modes", out
->name
, out
->modes
.size());
382 for (auto mode
: out
->modes
)
384 CLog::Log(LOGINFO
, "ID:{} Name:{} Refresh:{:f} Width:{} Height:{}", mode
.id
, mode
.name
,
385 mode
.hz
, mode
.w
, mode
.h
);
389 if (mode
.IsInterlaced())
390 res
.dwFlags
|= D3DPRESENTFLAG_INTERLACED
;
395 res
.iHeight
= mode
.h
;
396 res
.iScreenWidth
= mode
.w
;
397 res
.iScreenHeight
= mode
.h
;
402 res
.iHeight
= mode
.w
;
403 res
.iScreenWidth
= mode
.h
;
404 res
.iScreenHeight
= mode
.w
;
407 if (mode
.h
> 0 && mode
.w
> 0 && out
->hmm
> 0 && out
->wmm
> 0)
408 res
.fPixelRatio
= ((float)out
->wmm
/(float)mode
.w
) / (((float)out
->hmm
/(float)mode
.h
));
410 res
.fPixelRatio
= 1.0f
;
412 CLog::Log(LOGINFO
, "Pixel Ratio: {:f}", res
.fPixelRatio
);
414 res
.strMode
= StringUtils::Format("{}: {} @ {:.2f}Hz", out
->name
, mode
.name
, mode
.hz
);
415 res
.strOutput
= out
->name
;
417 res
.iSubtitles
= mode
.h
;
418 res
.fRefreshRate
= mode
.hz
;
419 res
.bFullScreen
= true;
421 CServiceBroker::GetWinSystem()->GetGfxContext().ResetOverscan(res
);
422 CDisplaySettings::GetInstance().AddResolutionInfo(res
);
425 CDisplaySettings::GetInstance().ApplyCalibrations();
428 bool CWinSystemX11::HasCalibration(const RESOLUTION_INFO
&resInfo
)
430 XOutput
*out
= g_xrandr
.GetOutput(m_currentOutput
);
432 // keep calibrations done on a not connected output
433 if (!StringUtils::EqualsNoCase(out
->name
, resInfo
.strOutput
))
436 // keep calibrations not updated with resolution data
437 if (resInfo
.iWidth
== 0)
441 if (resInfo
.iHeight
>0 && resInfo
.iWidth
>0 && out
->hmm
>0 && out
->wmm
>0)
442 fPixRatio
= ((float)out
->wmm
/(float)resInfo
.iWidth
) / (((float)out
->hmm
/(float)resInfo
.iHeight
));
446 if (resInfo
.Overscan
.left
!= 0)
448 if (resInfo
.Overscan
.top
!= 0)
450 if (resInfo
.Overscan
.right
!= resInfo
.iWidth
)
452 if (resInfo
.Overscan
.bottom
!= resInfo
.iHeight
)
454 if (resInfo
.fPixelRatio
!= fPixRatio
)
456 if (resInfo
.iSubtitles
!= resInfo
.iHeight
)
462 bool CWinSystemX11::UseLimitedColor()
464 return CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOSCREEN_LIMITEDRANGE
);
467 std::vector
<std::string
> CWinSystemX11::GetConnectedOutputs()
469 std::vector
<std::string
> outputs
;
470 std::vector
<XOutput
> outs
;
471 g_xrandr
.Query(true);
472 outs
= g_xrandr
.GetModes();
473 outputs
.emplace_back("Default");
474 for(unsigned int i
=0; i
<outs
.size(); ++i
)
476 outputs
.emplace_back(outs
[i
].name
);
482 bool CWinSystemX11::IsCurrentOutput(const std::string
& output
)
484 return (StringUtils::EqualsNoCase(output
, "Default")) || (m_currentOutput
.compare(output
.c_str()) == 0);
487 void CWinSystemX11::ShowOSMouse(bool show
)
490 XUndefineCursor(m_dpy
,m_mainWindow
);
491 else if (m_invisibleCursor
)
492 XDefineCursor(m_dpy
,m_mainWindow
, m_invisibleCursor
);
495 std::unique_ptr
<KODI::WINDOWING::IOSScreenSaver
> CWinSystemX11::GetOSScreenSaverImpl()
497 std::unique_ptr
<IOSScreenSaver
> ret
;
500 ret
= std::make_unique
<COSScreenSaverX11
>(m_dpy
);
505 void CWinSystemX11::NotifyAppActiveChange(bool bActivated
)
507 if (bActivated
&& m_bWasFullScreenBeforeMinimize
&& !m_bFullScreen
)
509 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_TOGGLEFULLSCREEN
);
511 m_bWasFullScreenBeforeMinimize
= false;
513 m_minimized
= !bActivated
;
516 void CWinSystemX11::NotifyAppFocusChange(bool bGaining
)
518 if (bGaining
&& m_bWasFullScreenBeforeMinimize
&& !m_bIgnoreNextFocusMessage
&&
521 m_bWasFullScreenBeforeMinimize
= false;
522 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_TOGGLEFULLSCREEN
);
526 m_bIgnoreNextFocusMessage
= false;
529 bool CWinSystemX11::Minimize()
531 m_bWasFullScreenBeforeMinimize
= m_bFullScreen
;
532 if (m_bWasFullScreenBeforeMinimize
)
534 m_bIgnoreNextFocusMessage
= true;
535 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_TOGGLEFULLSCREEN
);
538 XIconifyWindow(m_dpy
, m_mainWindow
, m_screen
);
543 bool CWinSystemX11::Restore()
547 bool CWinSystemX11::Hide()
549 XUnmapWindow(m_dpy
, m_mainWindow
);
553 bool CWinSystemX11::Show(bool raise
)
555 XMapWindow(m_dpy
, m_mainWindow
);
561 void CWinSystemX11::NotifyXRREvent()
563 CLog::Log(LOGDEBUG
, "{} - notify display reset event", __FUNCTION__
);
565 std::unique_lock
<CCriticalSection
> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
567 if (!g_xrandr
.Query(true))
569 CLog::Log(LOGERROR
, "WinSystemX11::RefreshWindow - failed to query xrandr");
573 // if external event update resolutions
574 if (!m_bIsInternalXrr
)
582 void CWinSystemX11::RecreateWindow()
584 m_windowDirty
= true;
586 std::unique_lock
<CCriticalSection
> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
588 XOutput
*out
= g_xrandr
.GetOutput(m_userOutput
);
589 XMode mode
= g_xrandr
.GetCurrentMode(m_userOutput
);
592 CLog::Log(LOGDEBUG
, "{} - current output: {}, mode: {}, refresh: {:.3f}", __FUNCTION__
,
593 out
->name
, mode
.id
, mode
.hz
);
595 CLog::Log(LOGWARNING
, "{} - output name not set", __FUNCTION__
);
600 for (i
= RES_DESKTOP
; i
< CDisplaySettings::GetInstance().ResolutionInfoSize(); ++i
)
602 res
= CDisplaySettings::GetInstance().GetResolutionInfo(i
);
603 if (StringUtils::EqualsNoCase(CDisplaySettings::GetInstance().GetResolutionInfo(i
).strId
, mode
.id
))
612 CLog::Log(LOGERROR
, "CWinSystemX11::RecreateWindow - could not find resolution");
616 if (CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot())
617 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution((RESOLUTION
)i
, true);
619 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(RES_WINDOW
, true);
622 void CWinSystemX11::OnLostDevice()
624 CLog::Log(LOGDEBUG
, "{} - notify display change event", __FUNCTION__
);
627 std::unique_lock
<CCriticalSection
> lock(m_resourceSection
);
628 for (std::vector
<IDispResource
*>::iterator i
= m_resources
.begin(); i
!= m_resources
.end(); ++i
)
629 (*i
)->OnLostDisplay();
632 m_winEventsX11
->SetXRRFailSafeTimer(3s
);
635 void CWinSystemX11::Register(IDispResource
*resource
)
637 std::unique_lock
<CCriticalSection
> lock(m_resourceSection
);
638 m_resources
.push_back(resource
);
641 void CWinSystemX11::Unregister(IDispResource
* resource
)
643 std::unique_lock
<CCriticalSection
> lock(m_resourceSection
);
644 std::vector
<IDispResource
*>::iterator i
= find(m_resources
.begin(), m_resources
.end(), resource
);
645 if (i
!= m_resources
.end())
646 m_resources
.erase(i
);
649 int CWinSystemX11::XErrorHandler(Display
* dpy
, XErrorEvent
* error
)
652 XGetErrorText(error
->display
, error
->error_code
, buf
, sizeof(buf
));
654 "CWinSystemX11::XErrorHandler: {}, type:{}, serial:{}, error_code:{}, request_code:{} "
656 buf
, error
->type
, error
->serial
, (int)error
->error_code
, (int)error
->request_code
,
657 (int)error
->minor_code
);
662 bool CWinSystemX11::SetWindow(int width
, int height
, bool fullscreen
, const std::string
&output
, int *winstate
)
664 bool changeWindow
= false;
665 bool changeSize
= false;
671 CServiceBroker::GetInputManager().SetMouseActive(false);
674 if (m_mainWindow
&& ((m_bFullScreen
!= fullscreen
) || m_currentOutput
.compare(output
) != 0 || m_windowDirty
))
676 // set mouse to last known position
677 // we can't trust values after an xrr event
678 if (m_bIsInternalXrr
&& m_MouseX
>= 0 && m_MouseY
>= 0)
680 mouseX
= (float)m_MouseX
/m_nWidth
;
681 mouseY
= (float)m_MouseY
/m_nHeight
;
683 else if (!m_windowDirty
)
685 Window root_return
, child_return
;
686 int root_x_return
, root_y_return
;
687 int win_x_return
, win_y_return
;
688 unsigned int mask_return
;
689 bool isInWin
= XQueryPointer(m_dpy
, m_mainWindow
, &root_return
, &child_return
,
690 &root_x_return
, &root_y_return
,
691 &win_x_return
, &win_y_return
,
696 mouseX
= (float)win_x_return
/m_nWidth
;
697 mouseY
= (float)win_y_return
/m_nHeight
;
701 CServiceBroker::GetInputManager().SetMouseActive(false);
704 m_windowDirty
= true;
707 // create main window
711 XSetWindowAttributes swa
;
716 XOutput
*out
= g_xrandr
.GetOutput(output
);
718 out
= g_xrandr
.GetOutput(m_currentOutput
);
721 m_screen
= out
->screen
;
729 CLog::Log(LOGERROR
, "Failed to find matching visual");
733 cmap
= XCreateColormap(m_dpy
, RootWindow(m_dpy
, vi
->screen
), vi
->visual
, AllocNone
);
735 bool hasWM
= HasWindowManager();
737 int def_vis
= (vi
->visual
== DefaultVisual(m_dpy
, vi
->screen
));
738 swa
.override_redirect
= hasWM
? False
: True
;
739 swa
.border_pixel
= fullscreen
? 0 : 5;
740 swa
.background_pixel
= def_vis
? BlackPixel(m_dpy
, vi
->screen
) : 0;
742 swa
.event_mask
= FocusChangeMask
| KeyPressMask
| KeyReleaseMask
|
743 ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
|
744 PropertyChangeMask
| StructureNotifyMask
| KeymapStateMask
|
745 EnterWindowMask
| LeaveWindowMask
| ExposureMask
;
746 unsigned long mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWOverrideRedirect
| CWEventMask
;
748 m_mainWindow
= XCreateWindow(m_dpy
, RootWindow(m_dpy
, vi
->screen
),
749 x0
, y0
, width
, height
, 0, vi
->depth
,
750 InputOutput
, vi
->visual
,
753 swa
.override_redirect
= False
;
754 swa
.border_pixel
= 0;
755 swa
.event_mask
= ExposureMask
;
756 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWOverrideRedirect
| CWColormap
| CWEventMask
;
758 m_glWindow
= XCreateWindow(m_dpy
, m_mainWindow
,
759 0, 0, width
, height
, 0, vi
->depth
,
760 InputOutput
, vi
->visual
,
763 if (fullscreen
&& hasWM
)
765 Atom fs
= XInternAtom(m_dpy
, "_NET_WM_STATE_FULLSCREEN", True
);
766 XChangeProperty(m_dpy
, m_mainWindow
, XInternAtom(m_dpy
, "_NET_WM_STATE", True
), XA_ATOM
, 32, PropModeReplace
, (unsigned char *) &fs
, 1);
767 // disable desktop compositing for KDE, when Kodi is in full-screen mode
769 Atom composite
= XInternAtom(m_dpy
, "_KDE_NET_WM_BLOCK_COMPOSITING", True
);
770 if (composite
!= None
)
772 XChangeProperty(m_dpy
, m_mainWindow
, XInternAtom(m_dpy
, "_KDE_NET_WM_BLOCK_COMPOSITING", True
), XA_CARDINAL
, 32,
773 PropModeReplace
, (unsigned char*) &one
, 1);
775 composite
= XInternAtom(m_dpy
, "_NET_WM_BYPASS_COMPOSITOR", True
);
776 if (composite
!= None
)
778 // standard way for Gnome 3
779 XChangeProperty(m_dpy
, m_mainWindow
, XInternAtom(m_dpy
, "_NET_WM_BYPASS_COMPOSITOR", True
), XA_CARDINAL
, 32,
780 PropModeReplace
, (unsigned char*) &one
, 1);
784 // define invisible cursor
787 static char noData
[] = { 0,0,0,0,0,0,0,0 };
788 black
.red
= black
.green
= black
.blue
= 0;
790 bitmapNoData
= XCreateBitmapFromData(m_dpy
, m_mainWindow
, noData
, 8, 8);
791 m_invisibleCursor
= XCreatePixmapCursor(m_dpy
, bitmapNoData
, bitmapNoData
,
792 &black
, &black
, 0, 0);
793 XFreePixmap(m_dpy
, bitmapNoData
);
794 XDefineCursor(m_dpy
,m_mainWindow
, m_invisibleCursor
);
798 m_winEventsX11
->Init(m_dpy
, m_mainWindow
);
804 if (!m_winEventsX11
->HasStructureChanged() && ((width
!= m_nWidth
) || (height
!= m_nHeight
)))
809 if (changeSize
|| changeWindow
)
811 XResizeWindow(m_dpy
, m_mainWindow
, width
, height
);
814 if ((width
!= m_nWidth
) || (height
!= m_nHeight
) || changeWindow
)
816 XResizeWindow(m_dpy
, m_glWindow
, width
, height
);
825 XClassHint
*class_hints
;
826 XTextProperty windowName
, iconName
;
828 std::string titleString
= CCompileInfo::GetAppName();
829 const std::string
& classString
= titleString
;
830 char *title
= const_cast<char*>(titleString
.c_str());
832 XStringListToTextProperty(&title
, 1, &windowName
);
833 XStringListToTextProperty(&title
, 1, &iconName
);
835 wm_hints
= XAllocWMHints();
836 wm_hints
->initial_state
= NormalState
;
837 wm_hints
->icon_pixmap
= m_icon
;
838 wm_hints
->flags
= StateHint
| IconPixmapHint
;
840 class_hints
= XAllocClassHint();
841 class_hints
->res_class
= const_cast<char*>(classString
.c_str());
842 class_hints
->res_name
= const_cast<char*>(classString
.c_str());
844 XSetWMProperties(m_dpy
, m_mainWindow
, &windowName
, &iconName
,
845 NULL
, 0, NULL
, wm_hints
,
849 XFree(iconName
.value
);
850 XFree(windowName
.value
);
852 // register interest in the delete window message
853 Atom wmDeleteMessage
= XInternAtom(m_dpy
, "WM_DELETE_WINDOW", False
);
854 XSetWMProtocols(m_dpy
, m_mainWindow
, &wmDeleteMessage
, 1);
857 // placement of window may follow mouse
858 XWarpPointer(m_dpy
, None
, m_mainWindow
, 0, 0, 0, 0, mouseX
*width
, mouseY
*height
);
860 XMapRaised(m_dpy
, m_glWindow
);
861 XMapRaised(m_dpy
, m_mainWindow
);
863 // discard events generated by creating the window, i.e. xrr events
875 bool CWinSystemX11::CreateIconPixmap()
880 XWindowAttributes wndattribs
;
888 uint32_t *newBuf
= 0;
889 size_t numNewBufBytes
;
892 XGetWindowAttributes(m_dpy
, m_glWindow
, &wndattribs
);
893 visInfo
.visualid
= wndattribs
.visual
->visualid
;
895 XVisualInfo
* visuals
= XGetVisualInfo(m_dpy
, VisualIDMask
, &visInfo
, &nvisuals
);
898 CLog::Log(LOGERROR
, "CWinSystemX11::CreateIconPixmap - could not find visual");
901 visInfo
= visuals
[0];
904 depth
= visInfo
.depth
;
905 vis
= visInfo
.visual
;
909 CLog::Log(LOGERROR
, "CWinSystemX11::CreateIconPixmap - no suitable depth");
913 rRatio
= vis
->red_mask
/ 255.0;
914 gRatio
= vis
->green_mask
/ 255.0;
915 bRatio
= vis
->blue_mask
/ 255.0;
917 std::unique_ptr
<CTexture
> iconTexture
=
918 CTexture::LoadFromFile("special://xbmc/media/icon256x256.png");
923 buf
= iconTexture
->GetPixels();
926 numNewBufBytes
= (4 * (iconTexture
->GetWidth() * iconTexture
->GetHeight()));
928 numNewBufBytes
= (2 * (iconTexture
->GetWidth() * iconTexture
->GetHeight()));
930 newBuf
= (uint32_t*)malloc(numNewBufBytes
);
933 CLog::Log(LOGERROR
, "CWinSystemX11::CreateIconPixmap - malloc failed");
937 for (i
=0; i
<iconTexture
->GetHeight();++i
)
939 for (j
=0; j
<iconTexture
->GetWidth();++j
)
941 unsigned int pos
= i
*iconTexture
->GetPitch()+j
*4;
942 unsigned int r
, g
, b
;
943 r
= (buf
[pos
+2] * rRatio
);
944 g
= (buf
[pos
+1] * gRatio
);
945 b
= (buf
[pos
+0] * bRatio
);
947 g
&= vis
->green_mask
;
949 newBuf
[outIndex
] = r
| g
| b
;
953 img
= XCreateImage(m_dpy
, vis
, depth
,ZPixmap
, 0, (char *)newBuf
,
954 iconTexture
->GetWidth(), iconTexture
->GetHeight(),
955 (depth
>=24)?32:16, 0);
958 CLog::Log(LOGERROR
, "CWinSystemX11::CreateIconPixmap - could not create image");
962 if (!XInitImage(img
))
964 CLog::Log(LOGERROR
, "CWinSystemX11::CreateIconPixmap - init image failed");
972 char c
[sizeof(short)];
976 if ((1 == order
.c
[0]))
978 img
->byte_order
= LSBFirst
;
982 img
->byte_order
= MSBFirst
;
985 // create icon pixmap from image
986 m_icon
= XCreatePixmap(m_dpy
, m_glWindow
, img
->width
, img
->height
, depth
);
987 GC gc
= XCreateGC(m_dpy
, m_glWindow
, 0, NULL
);
988 XPutImage(m_dpy
, m_icon
, gc
, img
, 0, 0, 0, 0, img
->width
, img
->height
);
990 XDestroyImage(img
); // this also frees newBuf
995 bool CWinSystemX11::HasWindowManager()
999 int status
, real_format
;
1000 Atom real_type
, prop
;
1001 unsigned long items_read
, items_left
;
1003 prop
= XInternAtom(m_dpy
, "_NET_SUPPORTING_WM_CHECK", True
);
1006 status
= XGetWindowProperty(m_dpy
, DefaultRootWindow(m_dpy
), prop
,
1007 0L, 1L, False
, XA_WINDOW
, &real_type
, &real_format
,
1008 &items_read
, &items_left
, &data
);
1009 if(status
!= Success
|| ! items_read
)
1011 if(status
== Success
)
1016 wm_check
= ((Window
*)data
)[0];
1019 status
= XGetWindowProperty(m_dpy
, wm_check
, prop
,
1020 0L, 1L, False
, XA_WINDOW
, &real_type
, &real_format
,
1021 &items_read
, &items_left
, &data
);
1023 if(status
!= Success
|| !items_read
)
1025 if(status
== Success
)
1030 if(wm_check
!= ((Window
*)data
)[0])
1038 prop
= XInternAtom(m_dpy
, "_NET_WM_NAME", True
);
1041 CLog::Log(LOGDEBUG
,"Window Manager Name: ");
1045 status
= XGetWindowProperty(m_dpy
, wm_check
, prop
,
1046 0L, (~0L), False
, AnyPropertyType
, &real_type
, &real_format
,
1047 &items_read
, &items_left
, &data
);
1049 if(status
== Success
&& items_read
)
1053 s
= reinterpret_cast<const char*>(data
);
1054 CLog::Log(LOGDEBUG
, "Window Manager Name: {}", s
);
1057 CLog::Log(LOGDEBUG
,"Window Manager Name: ");
1059 if(status
== Success
)
1065 void CWinSystemX11::UpdateCrtc()
1067 XWindowAttributes winattr
;
1071 XGetWindowAttributes(m_dpy
, m_mainWindow
, &winattr
);
1072 XTranslateCoordinates(m_dpy
, m_mainWindow
, RootWindow(m_dpy
, m_screen
), winattr
.x
, winattr
.y
,
1073 &posx
, &posy
, &child
);
1075 m_crtc
= g_xrandr
.GetCrtc(posx
+winattr
.width
/2, posy
+winattr
.height
/2, fps
);
1076 CServiceBroker::GetWinSystem()->GetGfxContext().SetFPS(fps
);
1079 bool CWinSystemX11::MessagePump()
1081 return m_winEvents
->MessagePump();