File indexing completed on 2024-03-24 17:02:13

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-only
0003     SPDX-FileCopyrightText: 1999-2001 Lubos Lunak <l.lunak@kde.org>
0004  */
0005 
0006 #define _WINDOWS_CPP_
0007 
0008 #include "windows_handler.h"
0009 
0010 #include "windows_helper/window_selection_list.h"
0011 #include "windows_helper/window_selection_rules.h"
0012 
0013 #include <QRegExp>
0014 
0015 #include <QDebug>
0016 #include <kconfig.h>
0017 #include <kconfiggroup.h>
0018 #include <klocale.h>
0019 #include <kwindowsystem.h>
0020 
0021 #include "khotkeysglobal.h"
0022 
0023 #include <QX11Info>
0024 #include <X11/Xlib.h>
0025 #include <X11/Xutil.h>
0026 
0027 namespace KHotKeys
0028 {
0029 // WindowsHandler
0030 
0031 WindowsHandler::WindowsHandler(bool enable_signal_P, QObject *parent_P)
0032     : QObject(parent_P)
0033     , signals_enabled(enable_signal_P)
0034     , _action_window(0)
0035     , m_isX11(QX11Info::isPlatformX11())
0036 {
0037     if (signals_enabled) {
0038         connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)), SLOT(window_added_slot(WId)));
0039         connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), SLOT(window_removed_slot(WId)));
0040         connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), SLOT(active_window_changed_slot(WId)));
0041     }
0042 }
0043 
0044 WindowsHandler::~WindowsHandler()
0045 {
0046 }
0047 
0048 void WindowsHandler::window_added_slot(WId window_P)
0049 {
0050     if (signals_enabled)
0051         emit window_added(window_P);
0052     // CHECKME tyhle i dalsi by asi mely jit nastavit, jestli aktivuji vsechny, nebo jen jeden
0053     // pripojeny slot ( stejne jako u Kdb, kde by to take melo jit nastavit )
0054 }
0055 
0056 void WindowsHandler::window_removed_slot(WId window_P)
0057 {
0058     if (signals_enabled)
0059         emit window_removed(window_P);
0060     if (window_P == _action_window)
0061         _action_window = 0;
0062 }
0063 
0064 void WindowsHandler::active_window_changed_slot(WId window_P)
0065 {
0066     if (signals_enabled)
0067         emit active_window_changed(window_P);
0068 }
0069 
0070 void WindowsHandler::window_changed_slot(WId window_P)
0071 {
0072     if (signals_enabled)
0073         emit window_changed(window_P);
0074 }
0075 
0076 void WindowsHandler::window_changed_slot(WId window_P, unsigned int flags_P)
0077 {
0078     if (signals_enabled)
0079         emit window_changed(window_P, flags_P);
0080 }
0081 
0082 QString WindowsHandler::get_window_role(WId id_P)
0083 {
0084     // TODO this is probably just a hack
0085     return KWindowInfo(id_P, {}, NET::WM2WindowRole).windowRole();
0086 }
0087 
0088 QString WindowsHandler::get_window_class(WId id_P)
0089 {
0090     if (!m_isX11) {
0091         return QString();
0092     }
0093     XClassHint hints_ret;
0094     if (XGetClassHint(QX11Info::display(), id_P, &hints_ret) == 0) // 0 means error
0095         return "";
0096     QString ret(hints_ret.res_name);
0097     ret += ' ';
0098     ret += hints_ret.res_class;
0099     XFree(hints_ret.res_name);
0100     XFree(hints_ret.res_class);
0101     return ret;
0102 }
0103 
0104 WId WindowsHandler::active_window()
0105 {
0106     return KWindowSystem::activeWindow();
0107 }
0108 
0109 WId WindowsHandler::action_window()
0110 {
0111     return _action_window;
0112 }
0113 
0114 void WindowsHandler::set_action_window(WId window_P)
0115 {
0116     _action_window = window_P;
0117 }
0118 
0119 WId WindowsHandler::find_window(const Windowdef_list *window_P)
0120 {
0121     const QList<WId> windows = KWindowSystem::windows();
0122     for (auto it = windows.begin(); it != windows.end(); ++it) {
0123         Window_data tmp(*it);
0124         if (window_P->match(tmp))
0125             return *it;
0126     }
0127     return None;
0128 }
0129 
0130 WId WindowsHandler::window_at_position(int x, int y)
0131 {
0132     if (!QX11Info::isPlatformX11()) {
0133         return 0;
0134     }
0135     Window child, dummy;
0136     Window parent = QX11Info::appRootWindow();
0137     Atom wm_state = XInternAtom(QX11Info::display(), "WM_STATE", False);
0138     for (int i = 0; i < 10; ++i) {
0139         int destx, desty;
0140         // find child at that position
0141         if (!XTranslateCoordinates(QX11Info::display(), parent, parent, x, y, &destx, &desty, &child) || child == None)
0142             return 0;
0143         // and now transform coordinates to the child
0144         if (!XTranslateCoordinates(QX11Info::display(), parent, child, x, y, &destx, &desty, &dummy))
0145             return 0;
0146         x = destx;
0147         y = desty;
0148         Atom type;
0149         int format;
0150         unsigned long nitems, after;
0151         unsigned char *prop;
0152         if (XGetWindowProperty(QX11Info::display(), child, wm_state, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &prop) == Success) {
0153             if (prop != nullptr)
0154                 XFree(prop);
0155             if (type != None)
0156                 return child;
0157         }
0158         parent = child;
0159     }
0160     return 0;
0161 }
0162 
0163 void WindowsHandler::activate_window(WId id_P)
0164 {
0165     KWindowSystem::forceActiveWindow(id_P);
0166 }
0167 
0168 // Window_data
0169 
0170 Window_data::Window_data(WId id_P)
0171     : type(NET::Unknown)
0172 {
0173     KWindowInfo kwin_info(id_P, NET::WMName | NET::WMWindowType); // TODO optimize
0174     if (kwin_info.valid()) {
0175         title = kwin_info.name();
0176         role = windows_handler->get_window_role(id_P);
0177         wclass = windows_handler->get_window_class(id_P);
0178         type = kwin_info.windowType(SUPPORTED_WINDOW_TYPES_MASK);
0179         if (type == NET::Override) // HACK consider non-NETWM fullscreens to be normal too
0180             type = NET::Normal;
0181         if (type == NET::Unknown)
0182             type = NET::Normal;
0183     }
0184 }
0185 
0186 } // namespace KHotKeys
0187 
0188 #include "moc_windows_handler.cpp"