diff --git a/CMakeLists.txt b/CMakeLists.txt index 68b0f148..3fb07ba7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,11 @@ if(APPLE) include_directories(${COCOA}) endif() -#if(UNIX) -# find_package(X11 REQUIRED) -# link_libraries(${X11_LIBRARIES}) -# include_directories(${X11_INCLUDE_DIR}) -#endif() +if(UNIX) + find_package(X11 REQUIRED) + link_libraries(${X11_LIBRARIES}) + include_directories(${X11_INCLUDE_DIR}) +endif() set(advanced-scene-switcher_HEADERS ${advanced-scene-switcher_HEADERS} @@ -50,9 +50,11 @@ elseif(APPLE) set(advanced-scene-switcher_PLATFORM_LIBS ${COCOA}) -#else() -# set(advanced-scene-switcher_PLATFORM_SOURCES -# advanced-scene-switcher-nix.cpp) +else() + set(advanced-scene-switcher_PLATFORM_SOURCES + advanced-scene-switcher-nix.cpp) + set(advanced-scene-switcher_PLATFORM_LIBS + Xss) endif() qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS diff --git a/advanced-scene-switcher-nix.cpp b/advanced-scene-switcher-nix.cpp new file mode 100644 index 00000000..a679491b --- /dev/null +++ b/advanced-scene-switcher-nix.cpp @@ -0,0 +1,322 @@ +#include +#include +#include +#include +#undef Bool +#undef CursorShape +#undef Expose +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef FontChange +#undef None +#undef Status +#undef Unsorted +#include +#include "advanced-scene-switcher.hpp" + +using namespace std; + +static Display* xdisplay = 0; + +Display *disp() +{ + if (!xdisplay) + xdisplay = XOpenDisplay(NULL); + + return xdisplay; +} + +void cleanupDisplay() +{ + if (!xdisplay) + return; + + XCloseDisplay(xdisplay); + xdisplay = 0; +} + +static bool ewmhIsSupported() +{ + Display *display = disp(); + Atom netSupportingWmCheck = XInternAtom(display, + "_NET_SUPPORTING_WM_CHECK", true); + Atom actualType; + int format = 0; + unsigned long num = 0, bytes = 0; + unsigned char *data = NULL; + Window ewmh_window = 0; + + int status = XGetWindowProperty( + display, + DefaultRootWindow(display), + netSupportingWmCheck, + 0L, + 1L, + false, + XA_WINDOW, + &actualType, + &format, + &num, + &bytes, + &data); + + if (status == Success) { + if (num > 0) { + ewmh_window = ((Window*)data)[0]; + } + if (data) { + XFree(data); + data = NULL; + } + } + + if (ewmh_window) { + status = XGetWindowProperty( + display, + ewmh_window, + netSupportingWmCheck, + 0L, + 1L, + false, + XA_WINDOW, + &actualType, + &format, + &num, + &bytes, + &data); + if (status != Success || num == 0 || + ewmh_window != ((Window*)data)[0]) { + ewmh_window = 0; + } + if (status == Success && data) { + XFree(data); + } + } + + return ewmh_window != 0; +} + +static std::vector getTopLevelWindows() +{ + std::vector res; + + res.resize(0); + + if (!ewmhIsSupported()) { + return res; + } + + Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true); + Atom actualType; + int format; + unsigned long num, bytes; + Window* data = 0; + + for (int i = 0; i < ScreenCount(disp()); ++i) { + Window rootWin = RootWindow(disp(), i); + + int status = XGetWindowProperty( + disp(), + rootWin, + netClList, + 0L, + ~0L, + false, + AnyPropertyType, + &actualType, + &format, + &num, + &bytes, + (uint8_t**)&data); + + if (status != Success) { + continue; + } + + for (unsigned long i = 0; i < num; ++i) + res.emplace_back(data[i]); + + XFree(data); + } + + return res; +} + +static std::string GetWindowTitle(size_t i) +{ + Window w = getTopLevelWindows().at(i); + std::string windowTitle; + char* name; + + int status = XFetchName(disp(), w, &name); + if (status >= Success && name != nullptr) + { + std::string str(name); + windowTitle = str; + } + + XFree(name); + + return windowTitle; +} + +void GetWindowList(vector &windows) +{ + windows.resize(0); + + for (size_t i = 0; i < getTopLevelWindows().size(); ++i){ + if (GetWindowTitle(i) != "") + windows.emplace_back(GetWindowTitle(i)); + } +} + +void GetCurrentWindowTitle(string &title) +{ + if (!ewmhIsSupported()) { + return; + } + + Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true); + Atom actualType; + int format; + unsigned long num, bytes; + Window* data = 0; + char* name; + + Window rootWin = RootWindow(disp(), 0); + + XGetWindowProperty( + disp(), + rootWin, + active, + 0L, + ~0L, + false, + AnyPropertyType, + &actualType, + &format, + &num, + &bytes, + (uint8_t**)&data); + + int status = XFetchName(disp(), data[0], &name); + + if (status >= Success && name != nullptr) { + std::string str(name); + title = str; + } + + XFree(name); +} + +pair getCursorPos() +{ + pair pos(0, 0); + Display *dpy; + Window root; + Window ret_root; + Window ret_child; + int root_x; + int root_y; + int win_x; + int win_y; + unsigned int mask; + + dpy = XOpenDisplay(NULL); + root = XDefaultRootWindow(dpy); + + if(XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y, + &win_x, &win_y, &mask)) + { + pos = pair (root_x,root_y); + } + return pos; +} + +bool isFullscreen() +{ + if (!ewmhIsSupported()) { + return false; + } + + Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true); + Atom actualType; + int format; + unsigned long num, bytes; + Window* data = 0; + + Window rootWin = RootWindow(disp(), 0); + XGetWindowProperty( + disp(), + rootWin, + active, + 0L, + ~0L, + false, + AnyPropertyType, + &actualType, + &format, + &num, + &bytes, + (uint8_t**)&data); + + + XWindowAttributes window_attributes_return; + XWindowAttributes screen_attributes_return; + + XGetWindowAttributes(disp(), rootWin, &screen_attributes_return); + XGetWindowAttributes(disp(), data[0], &window_attributes_return); + + //menu bar is always 24 pixels in height + return (window_attributes_return.width >= screen_attributes_return.width && + window_attributes_return.height + 24 >= screen_attributes_return.height) ? true : false; +} + +//exe switch is not quite what is expected but it works for now +void GetProcessList(QStringList &processes) +{ + processes.clear(); + for (size_t i = 0; i < getTopLevelWindows().size(); ++i){ + string s = GetWindowTitle(i); + if (s != "") + processes << QString::fromStdString(s); + } +} + +bool isInFocus(const QString &exeToCheck) +{ + string curWindow; + GetCurrentWindowTitle(curWindow); + + return (QString::compare( + QString::fromStdString(curWindow), + exeToCheck, + Qt::CaseInsensitive) == 0) ? true : false; +} + + +int secondsSinceLastInput() +{ + time_t idle_time; + static XScreenSaverInfo *mit_info; + Display *display; + int screen; + + mit_info = XScreenSaverAllocInfo(); + + if((display=XOpenDisplay(NULL)) == NULL) + { + return(-1); + } + screen = DefaultScreen(display); + XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info); + idle_time = (mit_info->idle) / 1000; + XFree(mit_info); + XCloseDisplay(display); + + return idle_time; +} + + diff --git a/scene-transitions.cpp b/scene-transitions.cpp index d210592e..37fcb99b 100644 --- a/scene-transitions.cpp +++ b/scene-transitions.cpp @@ -1,18 +1,4 @@ #include "advanced-scene-switcher.hpp" -#if 1 -#include -std::wstring s2ws(const std::string& s) -{ - int len; - int slength = (int)s.length() + 1; - len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); - wchar_t* buf = new wchar_t[len]; - MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); - std::wstring r(buf); - delete[] buf; - return r; -} -#endif void SceneSwitcher::on_transitionsAdd_clicked() { diff --git a/utility.hpp b/utility.hpp index d8a1e2dd..5627a78a 100644 --- a/utility.hpp +++ b/utility.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include "switcher-data-structs.hpp" using namespace std;