diff options
author | Ken Moore <ken@ixsystems.com> | 2017-02-01 16:13:52 -0500 |
---|---|---|
committer | Ken Moore <ken@ixsystems.com> | 2017-02-01 16:13:52 -0500 |
commit | 014ce3d9363b15912a53cc8885358b0436b3bb27 (patch) | |
tree | 3fba59a0ffedadac98cb904db64c10ccc29417a0 | |
parent | Add a new "NativeWindow" class to the library. This is a pure Qt container cl... (diff) | |
download | lumina-014ce3d9363b15912a53cc8885358b0436b3bb27.tar.gz lumina-014ce3d9363b15912a53cc8885358b0436b3bb27.tar.bz2 lumina-014ce3d9363b15912a53cc8885358b0436b3bb27.zip |
Another large batch of work on Lumina2:
The NativeWindow intermediary seems to be working really well, now just to start adding the the various event detection parsing in to modify that object on-demand.
There is still a window focus issue too - the setActive routine is not properly setting that window to have focus yet - need to examine further.
-rw-r--r-- | src-qt5/core/libLumina/LuminaX11.cpp | 15 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LuminaX11.h | 12 | ||||
-rw-r--r-- | src-qt5/core/libLumina/NativeWindow.cpp | 2 | ||||
-rw-r--r-- | src-qt5/core/libLumina/NativeWindow.h | 1 | ||||
-rw-r--r-- | src-qt5/core/libLumina/RootSubWindow.cpp | 1 | ||||
-rw-r--r-- | src-qt5/core/lumina-desktop-unified/LSession.cpp | 6 | ||||
-rw-r--r-- | src-qt5/core/lumina-desktop-unified/global-includes.h | 1 | ||||
-rw-r--r-- | src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp | 95 | ||||
-rw-r--r-- | src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h | 21 |
9 files changed, 129 insertions, 25 deletions
diff --git a/src-qt5/core/libLumina/LuminaX11.cpp b/src-qt5/core/libLumina/LuminaX11.cpp index a8016460..c586790b 100644 --- a/src-qt5/core/libLumina/LuminaX11.cpp +++ b/src-qt5/core/libLumina/LuminaX11.cpp @@ -1609,7 +1609,20 @@ WId LXCB::WM_Get_Active_Window(){ } void LXCB::WM_Set_Active_Window(WId win){ - xcb_ewmh_set_active_window(&EWMH, QX11Info::appScreen(), win); + xcb_ewmh_set_active_window(&EWMH, QX11Info::appScreen(), win); + //Also send the active window a message to take input focus + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = win; //window to activate + event.type = ATOMS[atoms.indexOf("WM_PROTOCOLS")]; + event.data.data32[0] = ATOMS[atoms.indexOf("WM_TAKE_FOCUS")]; + event.data.data32[1] = QX11Info::getTimestamp(); //current timestamp + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + xcb_send_event(QX11Info::connection(), 0, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); } // _NET_WORKAREA diff --git a/src-qt5/core/libLumina/LuminaX11.h b/src-qt5/core/libLumina/LuminaX11.h index 2c741111..dd9f8213 100644 --- a/src-qt5/core/libLumina/LuminaX11.h +++ b/src-qt5/core/libLumina/LuminaX11.h @@ -67,6 +67,18 @@ public: || width_inc>=0 || height_inc>=0 || min_aspect_num>=0 || min_aspect_den>=0 || max_aspect_num>=0 || max_aspect_den>=0 \ || base_width>=0 || base_height>=0 || win_gravity>0 ); } + bool validMaxSize(){ + return (max_width>0 && max_width>=min_width) && (max_height>0 && max_height>=min_height); + } + bool validMinSize(){ + return (min_width>0 && min_height>0); + } + bool validBaseSize(){ + return (base_width>0 && base_height>0); + } + bool validSize(){ //only check this if the base sizes are invalid (this is the old spec and should not be used any more) + return (x>0 && y>0); + } }; //simple data structure for passing around the XRANDR information diff --git a/src-qt5/core/libLumina/NativeWindow.cpp b/src-qt5/core/libLumina/NativeWindow.cpp index eb85e394..bd42ecaa 100644 --- a/src-qt5/core/libLumina/NativeWindow.cpp +++ b/src-qt5/core/libLumina/NativeWindow.cpp @@ -14,7 +14,7 @@ NativeWindow::NativeWindow(WId id) : QObject(){ NativeWindow::~NativeWindow(){ hash.clear(); - WIN->deleteLater(); + //WIN->deleteLater(); //This class only deals with Native windows which were created outside the app - they need to be cleaned up outside the app too } WId NativeWindow::id(){ diff --git a/src-qt5/core/libLumina/NativeWindow.h b/src-qt5/core/libLumina/NativeWindow.h index bcbe8b6c..c4fdbb47 100644 --- a/src-qt5/core/libLumina/NativeWindow.h +++ b/src-qt5/core/libLumina/NativeWindow.h @@ -30,6 +30,7 @@ public: MaxSize, /*QSize*/ Size, /*int*/ Title, /*QString*/ + ShortTitle, /*QString*/ Icon, /*QIcon*/ Name, /*QString*/ Workspace, /*int*/ diff --git a/src-qt5/core/libLumina/RootSubWindow.cpp b/src-qt5/core/libLumina/RootSubWindow.cpp index 93a49e6b..7be89f48 100644 --- a/src-qt5/core/libLumina/RootSubWindow.cpp +++ b/src-qt5/core/libLumina/RootSubWindow.cpp @@ -65,6 +65,7 @@ void RootSubWindow::aboutToActivate(){ void RootSubWindow::propertyChanged(NativeWindow::Property prop, QVariant val){ if(val.isNull()){ return; } //not the same as a default/empty value - the property has just not been set yet + qDebug() << "Set Window Property:" << prop << val; switch(prop){ case NativeWindow::Visible: if(val.toBool()){ clientShown(); } diff --git a/src-qt5/core/lumina-desktop-unified/LSession.cpp b/src-qt5/core/lumina-desktop-unified/LSession.cpp index ea72bc7b..1c8d3c45 100644 --- a/src-qt5/core/lumina-desktop-unified/LSession.cpp +++ b/src-qt5/core/lumina-desktop-unified/LSession.cpp @@ -29,6 +29,7 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu mediaObj = 0; //private object used for playing login/logout chimes if(this->isPrimaryProcess()){ //Setup the global registrations + qsrand(QDateTime::currentMSecsSinceEpoch()); this->setApplicationName("Lumina Desktop Environment"); this->setApplicationVersion( LDesktopUtils::LuminaDesktopVersion() ); this->setOrganizationName("LuminaDesktopEnvironment"); @@ -60,10 +61,7 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu //Setup the various connections between the global classes // NOTE: Most of these connections will only become "active" as the global objects get started during the setupSession routine connect(Lumina::ROOTWIN, SIGNAL(RegisterVirtualRoot(WId)), Lumina::EFILTER, SLOT(RegisterVirtualRoot(WId)) ); - connect(Lumina::EFILTER, SIGNAL(WindowCreated(WId)), Lumina::ROOTWIN, SLOT(NewWindow(WId)) ); - connect(Lumina::EFILTER, SIGNAL(WindowClosed(WId)), Lumina::ROOTWIN, SLOT(CloseWindow(WId)) ); - connect(Lumina::EFILTER, SIGNAL(WindowHidden(WId)), Lumina::ROOTWIN, SLOT(HideWindow(WId)) ); - connect(Lumina::EFILTER, SIGNAL(WindowShown(WId)), Lumina::ROOTWIN, SLOT(ShowWindow(WId)) ); + connect(Lumina::EFILTER, SIGNAL(WindowCreated(NativeWindow*)), Lumina::ROOTWIN, SLOT(NewWindow(NativeWindow*)) ); } //end check for primary process } diff --git a/src-qt5/core/lumina-desktop-unified/global-includes.h b/src-qt5/core/lumina-desktop-unified/global-includes.h index ed687917..867076db 100644 --- a/src-qt5/core/lumina-desktop-unified/global-includes.h +++ b/src-qt5/core/lumina-desktop-unified/global-includes.h @@ -58,6 +58,7 @@ #include <DesktopSettings.h> #include <RootWindow.h> #include <ExternalProcess.h> +#include <NativeWindow.h> // Standard C includes #include <unistd.h> 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 6660e41e..27e94737 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp @@ -71,11 +71,22 @@ unsigned int EventFilter::currentWorkspace(){ return XCB->CurrentWorkspace(); } +QList<NativeWindow*> EventFilter::currentWindows(){ + return static_cast<XCBEventFilter*>(EF)->windowList(); +} + // === PUBLIC SLOTS === void EventFilter::RegisterVirtualRoot(WId id){ XCB->WM_Set_Virtual_Roots( QList<WId>() << id ); } +void EventFilter::TryCloseWindow(WId id){ + XCB->WM_CloseWindow(id, false); //do not force close +} + +void EventFilter::TryActivateWindow(WId id){ + XCB->WM_Set_Active_Window(id); +} //============================= // XCBEventFilter Class //============================= @@ -183,11 +194,16 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag break; //============================== case XCB_MAP_NOTIFY: - qDebug() << "Window Map Event:" << ((xcb_map_notify_event_t *)ev)->window; - obj->emit WindowShown( ((xcb_map_notify_event_t *)ev)->window); + //qDebug() << "Window Map Event:" << ((xcb_map_notify_event_t *)ev)->window; + if(Lumina::SS->isLocked()){ waitingToShow << ((xcb_map_notify_event_t *)ev)->window ; } + else{ + for(int i=0; i<windows.length(); i++){ + if(windows[i]->id() == ((xcb_map_notify_event_t *)ev)->window){ windows[i]->setProperty(NativeWindow::Visible, true); break; } + } + } break; //This is just a notification that a window was mapped - nothing needs to change here case XCB_MAP_REQUEST: - qDebug() << "Window Map Request Event"; + //qDebug() << "Window Map Request Event"; SetupNewWindow( ((xcb_map_request_event_t *) ev) ); break; //============================== @@ -196,15 +212,24 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag break; //============================== case XCB_UNMAP_NOTIFY: - qDebug() << "Window Unmap Event:" << ((xcb_unmap_notify_event_t *)ev)->window; - obj->emit WindowHidden( ((xcb_unmap_notify_event_t *)ev)->window); + //qDebug() << "Window Unmap Event:" << ((xcb_unmap_notify_event_t *)ev)->window; + if(waitingToShow.contains(((xcb_unmap_notify_event_t *)ev)->window)){ waitingToShow.removeAll(((xcb_unmap_notify_event_t *)ev)->window); } + for(int i=0; i<windows.length(); i++){ + if(windows[i]->id() == ((xcb_unmap_notify_event_t *)ev)->window){ windows[i]->setProperty(NativeWindow::Visible, false); break; } + } break; //============================== case XCB_DESTROY_NOTIFY: - qDebug() << "Window Closed Event:" << ((xcb_destroy_notify_event_t *)ev)->window; + //qDebug() << "Window Closed Event:" << ((xcb_destroy_notify_event_t *)ev)->window; if( !rmTrayApp( ((xcb_destroy_notify_event_t *) ev)->window ) ){ - qDebug() <<" - Non-tray window"; - obj->emit WindowClosed( ((xcb_destroy_notify_event_t *) ev)->window ); + //qDebug() <<" - Non-tray window"; + for(int i=0; i<windows.length(); i++){ + if(windows[i]->id() == ((xcb_destroy_notify_event_t *)ev)->window){ + windows[i]->emit WindowClosed(windows[i]->id()); + QTimer::singleShot(500, windows.takeAt(i), SLOT(deleteLater()) ); //give a few moments first, then clean up the object + break; + } + } } break; //============================== @@ -218,7 +243,7 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag //============================== case XCB_PROPERTY_NOTIFY: //qDebug() << "Property Notify Event:"; - //qDebug() << " - Given Window:" << ((xcb_property_notify_event_t*)ev)->window; + ParsePropertyEvent((xcb_property_notify_event_t*)ev); break; //============================== case XCB_CLIENT_MESSAGE: @@ -308,6 +333,10 @@ bool XCBEventFilter::stopSystemTray(){ return true; } +QList<NativeWindow*> XCBEventFilter::windowList(){ + return windows; +} + //========= // PRIVATE //========= @@ -409,10 +438,50 @@ void XCBEventFilter::SetupNewWindow(xcb_map_request_event_t *ev){ qDebug() << "New Window:" << win << obj->XCB->WM_ICCCM_GetClass(win) << " Managed:" << ok; obj->XCB->WM_Set_Active_Window(win); //Determing the requested geometry/location/management within the event, - // and forward that on to the graphical embedding side of the WM + NativeWindow *nwin = new NativeWindow(win); + QObject::connect(nwin, SIGNAL(RequestClose(WId)), obj, SLOT(TryCloseWindow(WId)) ); + QObject::connect(nwin, SIGNAL(RequestActivate(WId)), obj, SLOT(TryActivateWindow(WId)) ); + windows << nwin; + bool show_now = !Lumina::SS->isLocked(); + if(!show_now){ waitingToShow << win; } //add to the list to get set visible later + //populate the native window settings as they are right now + nwin->setProperty(NativeWindow::Active, true); + nwin->setProperty(NativeWindow::Visible, show_now); + nwin->setProperty(NativeWindow::Workspace, obj->XCB->CurrentWorkspace()); + icccm_size_hints hints = obj->XCB->WM_ICCCM_GetNormalHints(win); + if(!hints.isValid()){ hints = obj->XCB->WM_ICCCM_GetSizeHints(win); } + if(hints.validMinSize()){ nwin->setProperty(NativeWindow::MinSize, QSize(hints.min_width,hints.min_height)); } + if(hints.validMaxSize()){ nwin->setProperty(NativeWindow::MaxSize, QSize(hints.max_width,hints.max_height)); } + if(hints.validBaseSize()){ nwin->setProperty(NativeWindow::Size, QSize(hints.base_width,hints.base_height)); } + else if(hints.validSize()){ nwin->setProperty(NativeWindow::Size, QSize(hints.width, hints.height)); } + nwin->setProperty(NativeWindow::Icon, obj->XCB->WM_Get_Icon(win)); + QString title = obj->XCB->WM_Get_Name(win); + if(title.isEmpty()){ title = obj->XCB->WM_Get_Visible_Name(win); } + if(title.isEmpty()){ title = obj->XCB->WM_ICCCM_GetName(win); } + nwin->setProperty(NativeWindow::Title, title); + title = obj->XCB->WM_Get_Icon_Name(win); + if(title.isEmpty()){ title = obj->XCB->WM_Get_Visible_Icon_Name(win); } + if(title.isEmpty()){ title = obj->XCB->WM_ICCCM_GetIconName(win); } + nwin->setProperty(NativeWindow::ShortTitle, title); + obj->emit WindowCreated(nwin); +} - obj->emit WindowCreated(win); - //TEMPORARY FOR DEBUGGING - //obj->XCB->WM_ShowWindow(win); +void XCBEventFilter::ParsePropertyEvent(xcb_property_notify_event_t *ev){ + //First find the NativeWindow associated with the event + NativeWindow *nwin = 0; + for(int i=0; i<windows.length() && nwin==0; i++){ + if(windows[i]->id() == ev->window){ nwin = windows[i]; } + } + if(nwin==0){ return; } //unmanaged window - ignore this event + qDebug() << "Got Property Event:" << ev->window << ev->atom; + //Now determine which properties are getting changed, and update the native window as appropriate + if(ev->atom == obj->XCB->EWMH._NET_WM_NAME){ + qDebug() << " - Found _NET_WM_NAME atom"; + nwin->setProperty(NativeWindow::Title, obj->XCB->WM_Get_Name(nwin->id())); + }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())); + } + } diff --git a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h index 30dc925d..9f2530e8 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h +++ b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h @@ -60,20 +60,21 @@ public: //Public Session Interaction Functions unsigned int currentWorkspace(); + + //Public Window Management Lists + QList<NativeWindow*> currentWindows(); //always returned in creation-order (oldest first) //Variables/Functions needed by the XCBEventFilter class only (not really needed by anything else) LXCB *XCB; //used to interact with the X11 graphics subsystem public slots: void RegisterVirtualRoot(WId); + void TryCloseWindow(WId); + void TryActivateWindow(WId); signals: void NewInputEvent(); - void WindowCreated(WId); - void WindowShown(WId); - void WindowHidden(WId); - void WindowClosed(WId); - void ModifyWindow(WId win, Lumina::WindowAction); + void WindowCreated(NativeWindow*); // Session Signals void WorkspaceChanged(unsigned int); @@ -101,6 +102,9 @@ public: bool startSystemTray(); bool stopSystemTray(); + //Window List Functions + QList<NativeWindow*> windowList(); + private: EventFilter *obj; QList<xcb_atom_t> WinNotifyAtoms, SysNotifyAtoms; @@ -121,14 +125,19 @@ private: bool rmTrayApp(WId); //returns "true" if the tray app was found and removed void checkDamageID(WId); + //Window List Variables + QList<NativeWindow*> windows; + QList<WId> waitingToShow; + //Longer Event handling functions void SetupNewWindow(xcb_map_request_event_t *ev); + //bool ParseKeyPressEvent(); //bool ParseKeyReleaseEvent(); //bool ParseButtonPressEvent(); //bool ParseButtonReleaseEvent(); //bool ParseMotionEvent(); - //bool ParsePropertyEvent(); + void ParsePropertyEvent(xcb_property_notify_event_t *ev); //bool ParseClientMessageEvent(); //bool ParseDestroyEvent(); //bool ParseConfigureEvent(); |