aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Moore <ken@ixsystems.com>2017-02-01 16:13:52 -0500
committerKen Moore <ken@ixsystems.com>2017-02-01 16:13:52 -0500
commit014ce3d9363b15912a53cc8885358b0436b3bb27 (patch)
tree3fba59a0ffedadac98cb904db64c10ccc29417a0
parentAdd a new "NativeWindow" class to the library. This is a pure Qt container cl... (diff)
downloadlumina-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.cpp15
-rw-r--r--src-qt5/core/libLumina/LuminaX11.h12
-rw-r--r--src-qt5/core/libLumina/NativeWindow.cpp2
-rw-r--r--src-qt5/core/libLumina/NativeWindow.h1
-rw-r--r--src-qt5/core/libLumina/RootSubWindow.cpp1
-rw-r--r--src-qt5/core/lumina-desktop-unified/LSession.cpp6
-rw-r--r--src-qt5/core/lumina-desktop-unified/global-includes.h1
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp95
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h21
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();
bgstack15