diff options
-rw-r--r-- | src-qt5/core/libLumina/LuminaX11.cpp | 12 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LuminaX11.h | 1 | ||||
-rw-r--r-- | src-qt5/core/libLumina/NativeWindow.h | 23 | ||||
-rw-r--r-- | src-qt5/core/libLumina/NativeWindowSystem.cpp | 221 | ||||
-rw-r--r-- | src-qt5/core/libLumina/NativeWindowSystem.h | 92 | ||||
-rw-r--r-- | src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp | 13 |
6 files changed, 354 insertions, 8 deletions
diff --git a/src-qt5/core/libLumina/LuminaX11.cpp b/src-qt5/core/libLumina/LuminaX11.cpp index ee882f7f..e9eb4b7c 100644 --- a/src-qt5/core/libLumina/LuminaX11.cpp +++ b/src-qt5/core/libLumina/LuminaX11.cpp @@ -1470,7 +1470,17 @@ void LXCB::WM_ICCCM_SetProtocols(WId win, LXCB::ICCCM_PROTOCOLS flags){ // _NET_SUPPORTED (Root) void LXCB::WM_Set_Root_Supported(){ //NET_WM standards (ICCCM implied - no standard way to list those) - xcb_atom_t list[] = {}; + xcb_atom_t list[] = {EWMH._NET_WM_NAME, + EWMH._NET_WM_ICON, + EWMH._NET_WM_ICON_NAME, + EWMH._NET_WM_DESKTOP, + /*_NET_WINDOW_TYPE (and all the various types)*/ + EWMH._NET_WM_WINDOW_TYPE, EWMH._NET_WM_WINDOW_TYPE_DESKTOP, EWMH._NET_WM_WINDOW_TYPE_DOCK, + EWMH._NET_WM_WINDOW_TYPE_TOOLBAR, EWMH._NET_WM_WINDOW_TYPE_MENU, EWMH._NET_WM_WINDOW_TYPE_UTILITY, + EWMH._NET_WM_WINDOW_TYPE_SPLASH, EWMH._NET_WM_WINDOW_TYPE_DIALOG, EWMH._NET_WM_WINDOW_TYPE_NORMAL, + EWMH._NET_WM_WINDOW_TYPE_DROPDOWN_MENU, EWMH._NET_WM_WINDOW_TYPE_POPUP_MENU, EWMH._NET_WM_WINDOW_TYPE_TOOLTIP, + EWMH._NET_WM_WINDOW_TYPE_NOTIFICATION, EWMH._NET_WM_WINDOW_TYPE_COMBO, EWMH._NET_WM_WINDOW_TYPE_DND, + }; xcb_ewmh_set_supported(&EWMH, QX11Info::appScreen(), 0,list); } diff --git a/src-qt5/core/libLumina/LuminaX11.h b/src-qt5/core/libLumina/LuminaX11.h index dd9f8213..2f66ce06 100644 --- a/src-qt5/core/libLumina/LuminaX11.h +++ b/src-qt5/core/libLumina/LuminaX11.h @@ -23,7 +23,6 @@ #include <QObject> #include <QFlags> - #include <xcb/xcb_ewmh.h> //SYSTEM TRAY STANDARD DEFINITIONS diff --git a/src-qt5/core/libLumina/NativeWindow.h b/src-qt5/core/libLumina/NativeWindow.h index c4fdbb47..59b955c3 100644 --- a/src-qt5/core/libLumina/NativeWindow.h +++ b/src-qt5/core/libLumina/NativeWindow.h @@ -24,21 +24,29 @@ class NativeWindow : public QObject{ Q_OBJECT public: + enum State{ S_MODAL, S_STICKY, S_MAX_VERT, S_MAX_HORZ, S_SHADED, S_SKIP_TASKBAR, S_SKIP_PAGER, S_HIDDEN, S_FULLSCREEN, S_ABOVE, S_BELOW, S_ATTENTION }; + enum Type{T_DESKTOP, T_DOCK, T_TOOLBAR, T_MENU, T_UTILITY, T_SPLASH, T_DIALOG, T_DROPDOWN_MENU, T_POPUP_MENU, T_TOOLTIP, T_NOTIFICATION, T_COMBO, T_DND, T_NORMAL }; + enum Action {A_MOVE, A_RESIZE, A_MINIMIZE, A_SHADE, A_STICK, A_MAX_VERT, A_MAX_HORZ, A_FULLSCREEN, A_CHANGE_DESKTOP, A_CLOSE, A_ABOVE, A_BELOW}; + enum Property{ /*QVariant Type*/ None, /*null*/ MinSize, /*QSize*/ MaxSize, /*QSize*/ - Size, /*int*/ + Size, /*QSize*/ + GlobalPos, /*QPoint*/ Title, /*QString*/ ShortTitle, /*QString*/ Icon, /*QIcon*/ Name, /*QString*/ Workspace, /*int*/ - WindowFlags, /*Qt::WindowFlags*/ + States, /*QList<NativeWindow::State> : Current state of the window */ + WinTypes, /*QList<NativeWindow::Type> : Current type of window (typically does not change)*/ + WinActions, /*QList<NativeWindow::Action> : Current actions that the window allows (Managed/set by the WM)*/ Active, /*bool*/ Visible /*bool*/ }; + NativeWindow(WId id); ~NativeWindow(); @@ -58,11 +66,14 @@ signals: void PropertyChanged(NativeWindow::Property, QVariant); void WindowClosed(WId); - //Action Requests (not automatically emitted) + //Action Requests (not automatically emitted - typically used to ask the WM to do something) //Note: "WId" should be the NativeWindow id() - void RequestActivate(WId); - void RequestClose(WId); - + void RequestActivate(WId); //Activate the window + void RequestClose(WId); //Close the window + void RequestSetVisible(WId, bool); //Minimize/restore visiblility + void RequestSetGeometry(WId, QRect); //Register the location/size of the window + void RequestSetFrameExtents(WId, QList<int>); //Register the size of the frame around the window [Left,Right, Top,Bottom] in pixels + // System Tray Icon Embed/Unembed Requests //void RequestEmbed(WId, QWidget*); //void RequestUnEmbed(WId, QWidget*); diff --git a/src-qt5/core/libLumina/NativeWindowSystem.cpp b/src-qt5/core/libLumina/NativeWindowSystem.cpp new file mode 100644 index 00000000..c8e6d483 --- /dev/null +++ b/src-qt5/core/libLumina/NativeWindowSystem.cpp @@ -0,0 +1,221 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is the XCB version of the NativeWindowSystem class, +// used for interacting with the X11 display system on BSD/Linux/Unix systems +//=========================================== +#include "NativeWindowSystem.h" + +//Additional Qt includes +#include <QX11Info> +#include <QDebug> + +//XCB Library functions +#include <xcb/xcb_ewmh.h> + +//XCB Library includes +#include <xcb/xcb.h> +#include <xcb/xcb_atom.h> +#include <xcb/xproto.h> +#include <xcb/xcb_ewmh.h> +#include <xcb/xcb_icccm.h> +#include <xcb/xcb_image.h> +#include <xcb/xcb_aux.h> +#include <xcb/composite.h> +#include <xcb/damage.h> + +//XLib includes (XCB Damage lib does not appear to register for damage events properly) +#include <X11/extensions/Xdamage.h> + +//SYSTEM TRAY STANDARD DEFINITIONS +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 +#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1 +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +#define URGENCYHINT (1L << 8) //For window urgency detection + +#define ROOT_WIN_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ + XCB_EVENT_MASK_BUTTON_PRESS | \ + XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \ + XCB_EVENT_MASK_POINTER_MOTION | \ + XCB_EVENT_MASK_PROPERTY_CHANGE | \ + XCB_EVENT_MASK_FOCUS_CHANGE | \ + XCB_EVENT_MASK_ENTER_WINDOW) + +//Internal XCB private objects class +class NativeWindowSystem::p_objects{ +public: + xcb_ewmh_connection_t EWMH; //This is where all the screen info and atoms are located + QHash<QString, xcb_atom_t> ATOMS; + xcb_screen_t *root_screen; + xcb_window_t root_window, wm_window, tray_window; + + //Functions for setting up these objects as needed + bool init_ATOMS(){ + QStringList atoms; + atoms << "WM_TAKE_FOCUS" << "WM_DELETE_WINDOW" << "WM_PROTOCOLS" << "WM_CHANGE_STATE" << "_NET_SYSTEM_TRAY_OPCODE" << "_NET_SYSTEM_TRAY_ORIENTATION" << "_NET_SYSTEM_TRAY_VISUAL" << QString("_NET_SYSTEM_TRAY_S%1").arg(QString::number(QX11Info::appScreen())); + //Create all the requests for the atoms + QList<xcb_intern_atom_reply_t*> reply; + for(int i=0; i<atoms.length(); i++){ + reply << xcb_intern_atom_reply(QX11Info::connection(), \ + xcb_intern_atom(QX11Info::connection(), 0, atoms[i].length(), atoms[i].toLocal8Bit()), NULL); + } + //Now evaluate all the requests and save the atoms + for(int i=0; i<reply.length(); i++){ //NOTE: this will always be the same length as the "atoms" list + if(reply[i]!=0){ + obj->ATOMS.insert(atoms[i], reply[i]->atom); + free(reply[i]); //done with this reply + }else{ + //Invalid atom - could not be created + qDebug() << "Could not initialize XCB atom:" << atoms[i]; + } + } //loop over reply + return (obj->ATOMS.keys.length() == atoms.length()); + } + + bool register_wm(){ + uint32_t value_list[1] = {ROOT_WIN_EVENT_MASK}; + xcb_generic_error_t *status = xcb_request_check( QX11Info::connection(), xcb_change_window_attributes_checked(QX11Info::connection(), root_window, XCB_CW_EVENT_MASK, value_list)); + if(status!=0){ return false; } + uint32_t params[] = {1}; + wm_window = xcb_generate_id(QX11Info::connection()); //need a new ID + xcb_create_window(QX11Info::connection(), root_screen->root_depth, \ + win, root_window, -1, -1, 1, 1, 0, \ + XCB_WINDOW_CLASS_INPUT_OUTPUT, root_screen->root_visual, \ + XCB_CW_OVERRIDE_REDIRECT, params); + if(wm_window==0){ return false; } + //Set the _NET_SUPPORTING_WM property on the root window first + xcb_ewmh_set_supporting_wm_check(&EWMH, root_window, wm_window); + //Also set this property on the child window (pointing to itself) + xcb_ewmh_set_supporting_wm_check(&EWMH, wm_window, wm_window); + //Now also setup the root event mask on the wm_window + status = xcb_request_check( QX11Info::connection(), xcb_change_window_attributes_checked(QX11Info::connection(), wm_window, XCB_CW_EVENT_MASK, value_list)); + if(status!=0){ return false; } + return true; + } + + bool startSystemTray{ + xcb_atom_t _NET_SYSTEM_TRAY_S = ATOMS.value(QString("_NET_SYSTEM_TRAY_S%1").arg(QString::number(QX11Info::appScreen())) ); + //Make sure that there is no other system tray running + xcb_get_selection_owner_reply_t *ownreply = xcb_get_selection_owner_reply(QX11Info::connection(), \ + xcb_get_selection_owner_unchecked(QX11Info::connection(), _NET_SYSTEM_TRAY_S), NULL); + if(ownreply==0){ + qWarning() << " - Could not get owner selection reply"; + return false; + }else if(ownreply->owner != 0){ + free(ownreply); + qWarning() << " - An alternate system tray is currently in use"; + return false; + } + free(ownreply); + //Now create the window to use (just offscreen) + //TODO + } + +}; //end private objects class + + +//inline functions for setting up the internal objects + + +// === PUBLIC === +NativeWindowSystem::NativeWindowSystem() : QObject(){ + obj = 0; +} + +NativeWindowSystem::~NativeWindowSystem(){ + xcb_ewmh_connection_wipe(obj->EWMH); + free(obj); +} + +//Overarching start/stop functions +bool NativeWindowSystem::start(){ + //Initialize the XCB/EWMH objects + if(obj==0){ + obj = new p_objects(); } //instantiate the private objects + obj->wm_window = 0; + obj->tray_window = 0; + xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(QX11Info::connection(), &obj->EWMH); + if(!xcb_ewmh_init_atoms_replies(&obj->EWMH, cookie, NULL) ){ + qDebug() << "Error with XCB atom initializations"; + return false; + } + obj->root_screen = xcb_aux_get_screen(QX11Info::connection(), QX11Info::appScreen()); + obj->root_window = obj->root_screen->root; //simplification for later - minor duplication of memory (unsigned int) + //Initialize all the extra atoms that the EWMH object does not have + if( !obj->init_ATOMS() ){ return false; } + } //Done with private object init + + return true; +} + +void NativeWindowSystem::stop(){ + +} + +// === PRIVATE === +void NativeWindowSystem::UpdateWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props){ + +} + +// === PUBLIC SLOTS === +//These are the slots which are only used by the desktop system itself or the NativeWindowEventFilter +void NativeWindowSystem::RegisterVirtualRoot(WId){ + +} + +//NativeWindowEventFilter interactions +void NativeWindowSystem::NewWindowDetected(WId){ + +} + +void NativeWindowSystem::WindowCloseDetected(WId){ + +} + +void NativeWindowSystem::WindowPropertyChanged(WId, NativeWindow::Property){ + +} + +void NativeWindowSystem::NewKeyPress(int keycode){ + +} + +void NativeWindowSystem::NewKeyRelease(int keycode){ + +} + +void NativeWindowSystem::NewMousePress(int buttoncode){ + +} + +void NativeWindowSystem::NewMouseRelease(int buttoncode){ + +} + +// === PRIVATE SLOTS === +//These are the slots which are built-in and automatically connected when a new NativeWindow is created +void NativeWindowSystem::RequestActivate(WId){ + +} +void NativeWindowSystem::RequestClose(WId){ + +} + +void NativeWindowSystem::RequestSetVisible(WId, bool){ + +} +void NativeWindowSystem::RequestSetGeometry(WId, QRect){ + +} +void NativeWindowSystem::RequestSetFrameExtents(WId, QList<int>){ + //[Left,Top,Right,Bottom] in pixels + +} diff --git a/src-qt5/core/libLumina/NativeWindowSystem.h b/src-qt5/core/libLumina/NativeWindowSystem.h new file mode 100644 index 00000000..ef169059 --- /dev/null +++ b/src-qt5/core/libLumina/NativeWindowSystem.h @@ -0,0 +1,92 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is a Qt5/Lumina wrapper around native graphics system calls +// It is primarily designed around the creation/modification of instances of +// the "NativeWindow" class for passing information around +//=========================================== +#ifndef _LUMINA_NATIVE_WINDOW_SYSTEM_H +#define _LUMINA_NATIVE_WINDOW_SYSTEM_H + +#include "NativeWindow.h" + +class NativeWindowSystem : public QObject{ + Q_OBJECT +private: + QList<NativeWindow*> NWindows; + QList<NativeWindow*> TWindows; + + //Simplifications to find an already-created window object + NativeWindow* findWindow(WId id){ + for(int i=0; i<NWindows.length(); i++){ + if(id==NWindows[i]->id()){ return NWindows[i]; } + } + } + + NativeWindow* findTrayWindow(WId id){ + for(int i=0; i<TWindows.length(); i++){ + if(id==TWindows[i]->id()){ return TWindows[i]; } + } + } + + //Now define a simple private_objects class so that each implementation + // has a storage container for placing private objects as needed + class p_objects; + p_objects* obj; + + // Since some properties may be easier to update in bulk + // let the native system interaction do them in whatever logical groups are best + void UpdateWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props); + +public: + NativeWindowSystem(); + ~NativeWindowSystem(); + + //Overarching start/stop functions + bool start(); + void stop(); + + //General-purpose listing functions + QList<NativeWindow*> currentWindows(){ return NWindows; } + +public slots: + //These are the slots which are typically only used by the desktop system itself or the NativeWindowEventFilter + + //RootWindow interactions + void RegisterVirtualRoot(WId); + //void GoToWorkspace(int); + //void RegisterWorkspaces(QStringList); //Names of workspaces, in ascending order + //void RegisterKnownInteractions(); + + + //NativeWindowEventFilter interactions + void NewWindowDetected(WId); //will automatically create the new NativeWindow object + void WindowCloseDetected(WId); //will update the lists and make changes if needed + void WindowPropertyChanged(WId, NativeWindow::Property); //will rescan the window and update the object as needed + void NewKeyPress(int keycode); + void NewKeyRelease(int keycode); + void NewMousePress(int buttoncode); + void NewMouseRelease(int buttoncode); + void CheckDamageID(WId); + +private slots: + //These are the slots which are built-in and automatically connected when a new NativeWindow is created + void RequestActivate(WId); + void RequestClose(WId); + void RequestSetVisible(WId, bool); + void RequestSetGeometry(WId, QRect); + void RequestSetFrameExtents(WId, QList<int>); //[Left,Right,Top,Bottom] in pixels + +signals: + void NewWindowAvailable(NativeWindow*); + void NewInputEvent(); //a mouse or keypress was detected (lock-state independent); + void NewKeyPress(int); //only emitted if lockstate = false + void NewKeyRelease(int); //only emitted if lockstate = false + void NewMousePress(Qt::MouseButton); //only emitted if lockstate = false + +}; + +#endif diff --git a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp index 27e94737..7031f3df 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp @@ -53,6 +53,7 @@ void EventFilter::start(){ XCB->setupEventsForRoot(WMFlag); XCB->WM_Set_Supporting_WM(WMFlag); + XCB->WM_Set_Root_Supported(); //announce all the various options that the WM supports static_cast<XCBEventFilter*>(EF)->startSystemTray(); QCoreApplication::instance()->flush(); @@ -482,6 +483,18 @@ void XCBEventFilter::ParsePropertyEvent(xcb_property_notify_event_t *ev){ }else if(ev->atom == obj->XCB->EWMH._NET_WM_ICON){ qDebug() << " - Found _NET_WM_ICON atom"; nwin->setProperty(NativeWindow::Icon, obj->XCB->WM_Get_Icon(nwin->id())); + }else if(ev->atom == obj->XCB->EWMH._NET_WM_ICON_NAME){ + qDebug() << " - Found _NET_WM_ICON_NAME atom"; + nwin->setProperty(NativeWindow::ShortTitle, obj->XCB->WM_Get_Icon_Name(nwin->id())); + }else if(ev->atom == obj->XCB->EWMH._NET_WM_DESKTOP){ + qDebug() << " - Found _NET_WM_DESKTOP atom"; + nwin->setProperty(NativeWindow::Workspace, obj->XCB->WM_Get_Desktop(nwin->id())); + }else if(ev->atom == obj->XCB->EWMH._NET_WM_WINDOW_TYPE ){ + qDebug() << " - Found _NET_WM_WINDOW_TYPE atom"; + + }else if( ev->atom == obj->XCB->EWMH._NET_WM_STATE){ + qDebug() << " - Found _NET_WM_STATE atom"; + } } |