diff options
Diffstat (limited to 'src-qt5/src-cpp')
-rw-r--r-- | src-qt5/src-cpp/NativeEventFilter.cpp | 300 | ||||
-rw-r--r-- | src-qt5/src-cpp/NativeEventFilter.h | 71 | ||||
-rw-r--r-- | src-qt5/src-cpp/NativeKeyToQt.cpp | 528 | ||||
-rw-r--r-- | src-qt5/src-cpp/NativeWindowSystem.cpp | 986 | ||||
-rw-r--r-- | src-qt5/src-cpp/NativeWindowSystem.h | 139 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp | 245 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface-template.cpp | 168 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface.h | 170 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface.pri | 15 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface_private.cpp | 605 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-base.h | 6 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-desktop.cpp | 36 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-desktop.h | 6 | ||||
-rw-r--r-- | src-qt5/src-cpp/tests/main.cpp | 3 |
14 files changed, 1103 insertions, 2175 deletions
diff --git a/src-qt5/src-cpp/NativeEventFilter.cpp b/src-qt5/src-cpp/NativeEventFilter.cpp deleted file mode 100644 index c13c1fc8..00000000 --- a/src-qt5/src-cpp/NativeEventFilter.cpp +++ /dev/null @@ -1,300 +0,0 @@ -//=========================================== -// Lumina-desktop source code -// Copyright (c) 2015-2017, Ken Moore -// Available under the 3-clause BSD license -// See the LICENSE file for full details -//=========================================== -#include "NativeEventFilter.h" -#include <QCoreApplication> -#include <QDebug> - -//#include <xcb/xcb_aux.h> -//#include <xcb/damage.h> - -//================================================== -// NOTE: All the XCB interactions and atoms are accessed via: -// obj->XCB->EWMH.(atom name) -// obj->XCB->(do something) -//================================================== - -/* -List of XCB response types (since almost impossible to find good docs on XCB) -switch (xcb_generic_event_t*->response_type & ~0x80) -case values: -XCB_KEY_[PRESS | RELEASE] -XCB_BUTTON_[PRESS | RELEASE] -XCB_MOTION_NOTIFY -XCB_ENTER_NOTIFY -XCB_LEAVE_NOTIFY -XCB_FOCUS_[IN | OUT] -XCB_KEYMAP_NOTIFY -XCB_EXPOSE -XCB_GRAPHICS_EXPOSURE -XCB_VISIBILITY_NOTIFY -XCB_CREATE_NOTIFY -XCB_DESTROY_NOTIFY -XCB_UNMAP_NOTIFY -XCB_MAP_[NOTIFY | REQUEST] -XCB_REPARENT_NOTIFY -XCB_CONFIGURE_[NOTIFY | REQUEST] -XCB_GRAVITY_NOTIFY -XCB_RESIZE_REQUEST -XCB_CIRCULATE_[NOTIFY | REQUEST] -XCB_PROPERTY_NOTIFY -XCB_SELECTION_[CLEAR | REQUEST | NOTIFY] -XCB_COLORMAP_NOTIFY -XCB_CLIENT_MESSAGE -*/ - -//SYSTEM TRAY STANDARD DEFINITIONS -#define SYSTEM_TRAY_REQUEST_DOCK 0 -#define SYSTEM_TRAY_BEGIN_MESSAGE 1 -#define SYSTEM_TRAY_CANCEL_MESSAGE 2 - -//#include <LuminaX11.h> -#include <QX11Info> -#include <xcb/xcb_ewmh.h> -#include <xcb/xcb_keysyms.h> -#include <xcb/damage.h> - -#define DEBUG 0 - -//Special objects/variables for XCB parsing -static xcb_ewmh_connection_t EWMH; -//static LXCB *XCB = 0; -static xcb_atom_t _NET_SYSTEM_TRAY_OPCODE = 0; - -inline void ParsePropertyEvent(xcb_property_notify_event_t *ev, NativeEventFilter *obj){ - //qDebug() << "Got Property Event:" << ev->window << ev->atom; - NativeWindow::Property prop = NativeWindow::None; - //Now determine which properties are getting changed, and update the native window as appropriate - if(ev->atom == EWMH._NET_WM_NAME){ prop = NativeWindow::Title; } - else if(ev->atom == EWMH._NET_WM_ICON){ prop = NativeWindow::Icon; } - else if(ev->atom == EWMH._NET_WM_ICON_NAME){ prop = NativeWindow::ShortTitle; } - else if(ev->atom == EWMH._NET_WM_DESKTOP){ prop = NativeWindow::Workspace; } - else if(ev->atom == EWMH._NET_WM_WINDOW_TYPE ){ prop = NativeWindow::WinTypes; } - else if( ev->atom == EWMH._NET_WM_STATE){ prop = NativeWindow::States; } - //Send out the signal if necessary - if(prop!=NativeWindow::None){ - //if(DEBUG){ - //qDebug() << "Detected Property Change:" << ev->window << prop; - //} - obj->emit WindowPropertyChanged(ev->window, prop); - }else{ - //Quick re-check of the simple properties (nothing like the icon or other graphics) - obj->emit WindowPropertiesChanged(ev->window, QList<NativeWindow::Property>() << NativeWindow::Title - << NativeWindow::ShortTitle << NativeWindow::Workspace ); - //qDebug() << "Unknown Property Change:" << ev->window << ev->atom; - } -} - -inline void ParseClientMessageEvent(xcb_client_message_event_t *ev, NativeEventFilter *obj){ - NativeWindow::Property prop = NativeWindow::None; - QVariant val; - if(ev->type==EWMH._NET_WM_NAME){ prop = NativeWindow::Title; } - else if(ev->type==EWMH._NET_WM_ICON){ prop = NativeWindow::Icon; } - else if(ev->type==EWMH._NET_WM_ICON_NAME){ prop = NativeWindow::ShortTitle; } - else if(ev->type==EWMH._NET_WM_DESKTOP){ - prop = NativeWindow::Workspace; - val = QVariant( (int) ev->data.data32[0] ); - }else if(ev->type==EWMH._NET_WM_WINDOW_TYPE){ prop = NativeWindow::WinTypes; } - else if(ev->type==EWMH._NET_WM_STATE){ prop = NativeWindow::States; } - - if(prop!=NativeWindow::None){ - //if(DEBUG){ - qDebug() << "Detected Property Change Request:" << ev->window << prop; //} - if(val.isNull()){ obj->emit WindowPropertyChanged(ev->window, prop); } - else{ obj->emit RequestWindowPropertyChange(ev->window, prop, val); } - } - -} - - -//Constructor for the Event Filter wrapper -NativeEventFilter::NativeEventFilter() : QObject(){ - EF = new EventFilter(this); - if(EWMH.nb_screens <=0){ - xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(QX11Info::connection(), &EWMH); - if(!xcb_ewmh_init_atoms_replies(&EWMH, cookie, NULL) ){ - qDebug() << "Error with XCB atom initializations"; - } - } - if(_NET_SYSTEM_TRAY_OPCODE==0){ - //_NET_SYSTEM_TRAY_OPCODE - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(QX11Info::connection(), 0, 23,"_NET_SYSTEM_TRAY_OPCODE"); - xcb_intern_atom_reply_t *r = xcb_intern_atom_reply(QX11Info::connection(), cookie, NULL); - if(r){ - _NET_SYSTEM_TRAY_OPCODE = r->atom; - free(r); - } - } -} - -void NativeEventFilter::start(){ - if(DEBUG){ qDebug() << " - Install event filter..."; } - QCoreApplication::instance()->installNativeEventFilter(EF); - if(DEBUG){ qDebug() << " - Run request check..."; } - -} - -void NativeEventFilter::stop(){ - QCoreApplication::instance()->installNativeEventFilter(0); -} - -//============================= -// EventFilter Class -//============================= - -//Constructor for the XCB event filter -EventFilter::EventFilter(NativeEventFilter *parent) : QAbstractNativeEventFilter(){ - obj = parent; -} - -//This function format taken directly from the Qt5.3 documentation -bool EventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *){ - //qDebug() << "New Event"; - if(eventType=="xcb_generic_event_t"){ - //Convert to known event type (for X11 systems) - xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message); - //Now parse the event and emit signals as necessary - switch( ev->response_type & ~0x80){ -//============================== -// INTERACTIVITY EVENTS -//============================== - case XCB_KEY_PRESS: - //This is a keyboard key press - //qDebug() << "Key Press Event" - obj->emit KeyPressed( ((xcb_key_press_event_t *) ev)->detail, ((xcb_key_press_event_t *) ev)->root ); - break; - case XCB_KEY_RELEASE: - //This is a keyboard key release - //qDebug() << "Key Release Event"; - obj->emit KeyReleased( ((xcb_key_release_event_t *) ev)->detail, ((xcb_key_release_event_t *) ev)->root ); - break; - case XCB_BUTTON_PRESS: - //This is a mouse button press - //qDebug() << "Button Press Event"; - obj->emit MousePressed( ((xcb_button_press_event_t *) ev)->detail, ((xcb_button_press_event_t *) ev)->root ); - break; - case XCB_BUTTON_RELEASE: - //This is a mouse button release - //qDebug() << "Button Release Event"; - obj->emit MouseReleased( ((xcb_button_release_event_t *) ev)->detail, ((xcb_button_release_event_t *) ev)->root ); - break; - case XCB_MOTION_NOTIFY: - //This is a mouse movement event - if(DEBUG){ qDebug() << "Motion Notify Event"; } - obj->emit MouseMovement(); - break; - case XCB_ENTER_NOTIFY: - //This is a mouse movement event when mouse goes over a new window - //qDebug() << "Enter Notify Event"; - obj->emit MouseEnterWindow( ((xcb_enter_notify_event_t *) ev)->root ); - break; - case XCB_LEAVE_NOTIFY: - //This is a mouse movement event when mouse goes leaves a window - //qDebug() << "Leave Notify Event"; - obj->emit MouseLeaveWindow( ((xcb_leave_notify_event_t *) ev)->root ); - break; -//============================== - case XCB_EXPOSE: - //qDebug() << "Expose Notify Event:"; - //qDebug() << " - Given Window:" << ((xcb_property_notify_event_t*)ev)->window; - break; -//============================== - case XCB_MAP_NOTIFY: - //qDebug() << "Window Map Event:" << ((xcb_map_notify_event_t *)ev)->window; - obj->emit WindowPropertyChanged( ((xcb_map_notify_event_t *)ev)->window, NativeWindow::Visible, true); - 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"; - obj->emit WindowCreated( ((xcb_map_request_event_t *) ev)->window ); - break; -//============================== - case XCB_CREATE_NOTIFY: - //qDebug() << "Window Create Event"; - break; -//============================== - case XCB_UNMAP_NOTIFY: - //qDebug() << "Window Unmap Event:" << ((xcb_unmap_notify_event_t *)ev)->window; - obj->emit WindowPropertyChanged( ((xcb_map_notify_event_t *)ev)->window, NativeWindow::Visible, false); - break; -//============================== - case XCB_DESTROY_NOTIFY: - //qDebug() << "Window Closed Event:" << ((xcb_destroy_notify_event_t *)ev)->window; - obj->emit WindowDestroyed( ((xcb_destroy_notify_event_t *) ev)->window ); - break; -//============================== - case XCB_FOCUS_IN: - //qDebug() << "Focus In Event:"; - break; -//============================== - case XCB_FOCUS_OUT: - //qDebug() << "Focus Out Event:"; - break; -//============================== - case XCB_PROPERTY_NOTIFY: - //qDebug() << "Property Notify Event:"; - ParsePropertyEvent((xcb_property_notify_event_t*)ev, obj); - break; -//============================== - case XCB_CLIENT_MESSAGE: - //qDebug() << "Client Message Event"; - //qDebug() << " - Given Window:" << ((xcb_client_message_event_t*)ev)->window; - if( ((xcb_client_message_event_t*)ev)->type == _NET_SYSTEM_TRAY_OPCODE && ((xcb_client_message_event_t*)ev)->format == 32){ - //data32[0] is timestamp, [1] is opcode, [2] is window handle - if(SYSTEM_TRAY_REQUEST_DOCK == ((xcb_client_message_event_t*)ev)->data.data32[1]){ - obj->emit TrayWindowCreated( ((xcb_client_message_event_t*)ev)->data.data32[2] ); - //addTrayApp( ((xcb_client_message_event_t*)ev)->data.data32[2] ); - } - //Ignore the System Tray messages at the moment - }else if(((xcb_client_message_event_t*)ev)->window != QX11Info::appRootWindow()){ - ParseClientMessageEvent((xcb_client_message_event_t*)ev, obj); - } - break; -//============================== - case XCB_CONFIGURE_NOTIFY: - //qDebug() << "Configure Notify Event"; - /*obj->emit WindowPropertiesChanged( ((xcb_configure_notify_event_t*)ev)->window, - QList<NativeWindow::Property>() << NativeWindow::GlobalPos << NativeWindow::Size, - QList<QVariant>() << QPoint(((xcb_configure_notify_event_t*)ev)->x, ((xcb_configure_notify_event_t*)ev)->y) << - QSize(((xcb_configure_notify_event_t*)ev)->width, ((xcb_configure_notify_event_t*)ev)->height) );*/ - obj->emit WindowPropertyChanged( ((xcb_configure_notify_event_t*)ev)->window, NativeWindow::Size, - QSize(((xcb_configure_notify_event_t*)ev)->width, ((xcb_configure_notify_event_t*)ev)->height) ); - break; -//============================== - case XCB_CONFIGURE_REQUEST: - //qDebug() << "Configure Request Event"; - obj->emit RequestWindowPropertiesChange( ((xcb_configure_request_event_t*)ev)->window, - QList<NativeWindow::Property>() << NativeWindow::GlobalPos << NativeWindow::Size, - QList<QVariant>() << QPoint(((xcb_configure_request_event_t*)ev)->x, ((xcb_configure_request_event_t*)ev)->y) << - QSize(((xcb_configure_request_event_t*)ev)->width, ((xcb_configure_request_event_t*)ev)->height) ); - break; -//============================== - case XCB_RESIZE_REQUEST: - //qDebug() << "Resize Request Event"; - obj->emit RequestWindowPropertyChange( ((xcb_resize_request_event_t*)ev)->window, - NativeWindow::Size, QSize(((xcb_resize_request_event_t*)ev)->width, ((xcb_resize_request_event_t*)ev)->height) ); - break; -//============================== - case XCB_SELECTION_CLEAR: - //qDebug() << "Selection Clear Event"; - break; -//============================== - case 85: //not sure what event this is - but it seems to come up very often (just hide the notice) - case 0: - case XCB_GE_GENERIC: - break; //generic event - don't do anything special - default: - //if( (ev->response_type & ~0x80)==TrayDmgID){ - obj->emit PossibleDamageEvent( ((xcb_damage_notify_event_t*)ev)->drawable ); - //checkDamageID( ((xcb_damage_notify_event_t*)ev)->drawable ); - //}else{ - //qDebug() << "Default Event:" << (ev->response_type & ~0x80); - //} -//============================== - } - } - return false; - //never stop event handling (this will not impact the X events themselves - just the internal Qt application) -} diff --git a/src-qt5/src-cpp/NativeEventFilter.h b/src-qt5/src-cpp/NativeEventFilter.h deleted file mode 100644 index a3be3ef1..00000000 --- a/src-qt5/src-cpp/NativeEventFilter.h +++ /dev/null @@ -1,71 +0,0 @@ -//=========================================== -// Lumina-DE source code -// Copyright (c) 2012-2017, Ken Moore -// Available under the 3-clause BSD license -// See the LICENSE file for full details -//=========================================== -// This class provides the XCB event handling/registrations that are needed -//=========================================== -#ifndef _LUMINA_DESKTOP_NATIVE_EVENT_FILTER_H -#define _LUMINA_DESKTOP_NATIVE_EVENT_FILTER_H - -#include <QAbstractNativeEventFilter> -#include <QObject> -#include <QByteArray> - -#include "NativeWindow.h" - - -class NativeEventFilter : public QObject{ - Q_OBJECT -private: - QAbstractNativeEventFilter* EF; - WId WMFlag; //used to flag a running WM process - -public: - NativeEventFilter(); - ~NativeEventFilter(){} - - void start(); - void stop(); - -signals: - //Window Signals - void WindowCreated(WId); - void WindowDestroyed(WId); - void WindowPropertyChanged(WId, NativeWindow::Property); - void WindowPropertiesChanged(WId, QList<NativeWindow::Property>); - void WindowPropertyChanged(WId, NativeWindow::Property, QVariant); - void WindowPropertiesChanged(WId, QList<NativeWindow::Property>, QList<QVariant>); - void RequestWindowPropertyChange(WId, NativeWindow::Property, QVariant); - void RequestWindowPropertiesChange(WId, QList<NativeWindow::Property>, QList<QVariant>); - - //System Tray Signals - void TrayWindowCreated(WId); - void TrayWindowDestroyed(WId); - - //Miscellaneos Signals - void PossibleDamageEvent(WId); - - //Input Event Signals - void KeyPressed(int, WId); - void KeyReleased(int, WId); - void MousePressed(int, WId); - void MouseReleased(int, WId); - void MouseMovement(); - void MouseEnterWindow(WId); - void MouseLeaveWindow(WId); -}; - -class EventFilter : public QAbstractNativeEventFilter{ -public: - EventFilter(NativeEventFilter *parent); - ~EventFilter(){} - - virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *); - -private: - NativeEventFilter *obj; -}; - -#endif diff --git a/src-qt5/src-cpp/NativeKeyToQt.cpp b/src-qt5/src-cpp/NativeKeyToQt.cpp deleted file mode 100644 index 06056be7..00000000 --- a/src-qt5/src-cpp/NativeKeyToQt.cpp +++ /dev/null @@ -1,528 +0,0 @@ - -#include <NativeWindowSystem.h> - -#include <QKeySequence> -#include <QX11Info> - -// XCB/X11 Includes -#define XK_MISCELLANY -#define XK_XKB_KEYS -#define XK_LATIN1 -#define XK_LATIN2 -#define XK_LATIN3 -#define XK_LATIN4 -#define XK_LATIN8 -#define XK_LATIN9 -//NOTE: Look at the keysymdef.h file for additional define/characters which we may need later -#include <X11/keysymdef.h> -#include <xcb/xcb_keysyms.h> - - -//Small simplification functions -Qt::Key NativeWindowSystem::KeycodeToQt(int keycode){ - static xcb_key_symbols_t *SYM = 0; - if(SYM==0){ SYM = xcb_key_symbols_alloc(QX11Info::connection()); } - xcb_keysym_t symbol = xcb_key_symbols_get_keysym(SYM, keycode,0); - //not sure about the "column" input - we want raw keys though so ignore the "modified" key states (columns) for now - //qDebug() << "Try to convert keycode to Qt::Key:" << keycode << symbol; - //Now map this symbol to the appropriate Qt::Key enumeration - switch(symbol){ - //FUNCTION KEYS - case XK_F1: return Qt::Key_F1; - case XK_F2: return Qt::Key_F2; - case XK_F3: return Qt::Key_F3; - case XK_F4: return Qt::Key_F4; - case XK_F5: return Qt::Key_F5; - case XK_F6: return Qt::Key_F6; - case XK_F7: return Qt::Key_F7; - case XK_F8: return Qt::Key_F8; - case XK_F9: return Qt::Key_F9; - case XK_F10: return Qt::Key_F10; - case XK_F11: return Qt::Key_F11; - case XK_F12: return Qt::Key_F12; - case XK_F13: return Qt::Key_F13; - case XK_F14: return Qt::Key_F14; - case XK_F15: return Qt::Key_F15; - case XK_F16: return Qt::Key_F16; - case XK_F17: return Qt::Key_F17; - case XK_F18: return Qt::Key_F18; - case XK_F19: return Qt::Key_F19; - case XK_F20: return Qt::Key_F20; - case XK_F21: return Qt::Key_F21; - case XK_F22: return Qt::Key_F22; - case XK_F23: return Qt::Key_F23; - case XK_F24: return Qt::Key_F24; - case XK_F25: return Qt::Key_F25; - case XK_F26: return Qt::Key_F26; - case XK_F27: return Qt::Key_F27; - case XK_F28: return Qt::Key_F28; - case XK_F29: return Qt::Key_F29; - case XK_F30: return Qt::Key_F30; - case XK_F31: return Qt::Key_F31; - case XK_F32: return Qt::Key_F32; - case XK_F33: return Qt::Key_F33; - case XK_F34: return Qt::Key_F34; - case XK_F35: return Qt::Key_F35; - //Miscellaneous Keys - case XK_BackSpace: return Qt::Key_Backspace; - case XK_Delete: return Qt::Key_Delete; - //case XK_LineFeed: return Qt::Key_Backspace; - case XK_Clear: return Qt::Key_Clear; - case XK_Return: return Qt::Key_Return; - case XK_Pause: return Qt::Key_Pause; - case XK_Scroll_Lock: return Qt::Key_ScrollLock; - case XK_Sys_Req: return Qt::Key_SysReq; - case XK_Escape: return Qt::Key_Escape; - case XK_Select: return Qt::Key_Select; - case XK_Print: return Qt::Key_Print; - //case XK_Execute: return Qt::Key_Execute; - case XK_Insert: return Qt::Key_Insert; - case XK_Undo: return Qt::Key_Undo; - case XK_Redo: return Qt::Key_Redo; - case XK_Menu: return Qt::Key_Menu; - case XK_Find: return Qt::Key_Find; - case XK_Cancel: return Qt::Key_Cancel; - case XK_Help: return Qt::Key_Help; - //case XK_Break: return Qt::Key_Break; - //case XK_Mode_switch: return Qt::Key_Backspace; - //case XK_script_switch: return Qt::Key_Backspace; - case XK_Num_Lock: return Qt::Key_NumLock; - //Cursor Controls - case XK_Home: return Qt::Key_Home; - case XK_Left: return Qt::Key_Left; - case XK_Up: return Qt::Key_Up; - case XK_Right: return Qt::Key_Right; - case XK_Down: return Qt::Key_Down; - //case XK_Prior: return Qt::Key_Backspace; - case XK_Page_Up: return Qt::Key_PageUp; - case XK_Page_Down: return Qt::Key_PageDown; - //case XK_Next: return Qt::Key_Backspace; - case XK_End: return Qt::Key_End; - //case XK_Begin: return Qt::Key_Backspace; - // Keypad Functions and numbers - case XK_KP_Space: return Qt::Key_Space; - case XK_KP_Tab: return Qt::Key_Tab; - case XK_KP_Enter: return Qt::Key_Enter; - case XK_KP_F1: return Qt::Key_F1; - case XK_KP_F2: return Qt::Key_F2; - case XK_KP_F3: return Qt::Key_F3; - case XK_KP_F4: return Qt::Key_F4; - case XK_KP_Home: return Qt::Key_Home; - case XK_KP_Left: return Qt::Key_Left; - case XK_KP_Up: return Qt::Key_Up; - case XK_KP_Right: return Qt::Key_Right; - case XK_KP_Down: return Qt::Key_Down; - //case XK_KP_Prior: return Qt::Key_ - case XK_KP_Page_Up: return Qt::Key_PageUp; - //case XK_KP_Next: return Qt::Key_ - case XK_KP_Page_Down: return Qt::Key_PageDown; - case XK_KP_End: return Qt::Key_End; - //case XK_KP_Begin: return Qt::Key_ - case XK_KP_Insert: return Qt::Key_Insert; - case XK_KP_Delete: return Qt::Key_Delete; - case XK_KP_Equal: return Qt::Key_Equal; - case XK_KP_Multiply: return Qt::Key_Asterisk; - case XK_KP_Add: return Qt::Key_Plus; - case XK_KP_Separator: return Qt::Key_Comma; //X11 definitions say this is often comma - case XK_KP_Subtract: return Qt::Key_Minus; - case XK_KP_Decimal: return Qt::Key_Period; - case XK_KP_Divide: return Qt::Key_Slash; - case XK_KP_0: return Qt::Key_0; - case XK_KP_1: return Qt::Key_1; - case XK_KP_2: return Qt::Key_2; - case XK_KP_3: return Qt::Key_3; - case XK_KP_4: return Qt::Key_4; - case XK_KP_5: return Qt::Key_5; - case XK_KP_6: return Qt::Key_6; - case XK_KP_7: return Qt::Key_7; - case XK_KP_8: return Qt::Key_8; - case XK_KP_9: return Qt::Key_9; - // Modifier Keys - case XK_Shift_L: return Qt::Key_Shift; - case XK_Shift_R: return Qt::Key_Shift; - case XK_Control_L: return Qt::Key_Control; - case XK_Control_R: return Qt::Key_Control; - case XK_Caps_Lock: return Qt::Key_CapsLock; - //case XK_Shift_Lock: return Qt::Key_ShiftLock; - case XK_Meta_L: return Qt::Key_Meta; - case XK_Meta_R: return Qt::Key_Meta; - case XK_Alt_L: return Qt::Key_Alt; - case XK_Alt_R: return Qt::Key_Alt; - case XK_Super_L: return Qt::Key_Super_L; - case XK_Super_R: return Qt::Key_Super_R; - case XK_Hyper_L: return Qt::Key_Hyper_L; - case XK_Hyper_R: return Qt::Key_Hyper_R; - case XK_space: return Qt::Key_Space; - case XK_exclam: return Qt::Key_Exclam; - case XK_quotedbl: return Qt::Key_QuoteDbl; - case XK_numbersign: return Qt::Key_NumberSign; - case XK_dollar: return Qt::Key_Dollar; - case XK_percent: return Qt::Key_Percent; - case XK_ampersand: return Qt::Key_Ampersand; - case XK_apostrophe: return Qt::Key_Apostrophe; - case XK_parenleft: return Qt::Key_ParenLeft; - case XK_parenright: return Qt::Key_ParenRight; - case XK_asterisk: return Qt::Key_Asterisk; - case XK_plus: return Qt::Key_Plus; - case XK_comma: return Qt::Key_Comma; - case XK_minus: return Qt::Key_Minus; - case XK_period: return Qt::Key_Period; - case XK_slash: return Qt::Key_Slash; - case XK_0: return Qt::Key_0; - case XK_1: return Qt::Key_1; - case XK_2: return Qt::Key_2; - case XK_3: return Qt::Key_3; - case XK_4: return Qt::Key_4; - case XK_5: return Qt::Key_5; - case XK_6: return Qt::Key_6; - case XK_7: return Qt::Key_7; - case XK_8: return Qt::Key_8; - case XK_9: return Qt::Key_9; - case XK_colon: return Qt::Key_Colon; - case XK_semicolon: return Qt::Key_Semicolon; - case XK_less: return Qt::Key_Less; - case XK_equal: return Qt::Key_Equal; - case XK_greater: return Qt::Key_Greater; - case XK_question: return Qt::Key_Question; - case XK_at: return Qt::Key_At; - case XK_A: return Qt::Key_A; - case XK_B: return Qt::Key_B; - case XK_C: return Qt::Key_C; - case XK_D: return Qt::Key_D; - case XK_E: return Qt::Key_E; - case XK_F: return Qt::Key_F; - case XK_G: return Qt::Key_G; - case XK_H: return Qt::Key_H; - case XK_I: return Qt::Key_I; - case XK_J: return Qt::Key_J; - case XK_K: return Qt::Key_K; - case XK_L: return Qt::Key_L; - case XK_M: return Qt::Key_M; - case XK_N: return Qt::Key_N; - case XK_O: return Qt::Key_O; - case XK_P: return Qt::Key_P; - case XK_Q: return Qt::Key_Q; - case XK_R: return Qt::Key_R; - case XK_S: return Qt::Key_S; - case XK_T: return Qt::Key_T; - case XK_U: return Qt::Key_U; - case XK_V: return Qt::Key_V; - case XK_W: return Qt::Key_W; - case XK_X: return Qt::Key_X; - case XK_Y : return Qt::Key_Y; - case XK_Z: return Qt::Key_Z; - case XK_bracketleft: return Qt::Key_BracketLeft; - case XK_backslash: return Qt::Key_Backslash; - case XK_bracketright: return Qt::Key_BracketRight; - case XK_asciicircum: return Qt::Key_AsciiCircum; - case XK_underscore: return Qt::Key_Underscore; - case XK_grave: return Qt::Key_Agrave; - case XK_a: return Qt::Key_A; - case XK_b: return Qt::Key_B; - case XK_c: return Qt::Key_C; - case XK_d: return Qt::Key_D; - case XK_e: return Qt::Key_E; - case XK_f : return Qt::Key_F; - case XK_g: return Qt::Key_G; - case XK_h: return Qt::Key_H; - case XK_i: return Qt::Key_I; - case XK_j: return Qt::Key_J; - case XK_k: return Qt::Key_K; - case XK_l: return Qt::Key_L; - case XK_m: return Qt::Key_M; - case XK_n: return Qt::Key_N; - case XK_o: return Qt::Key_O; - case XK_p: return Qt::Key_P; - case XK_q: return Qt::Key_Q; - case XK_r: return Qt::Key_R; - case XK_s: return Qt::Key_S; - case XK_t : return Qt::Key_T; - case XK_u: return Qt::Key_U; - case XK_v: return Qt::Key_V; - case XK_w: return Qt::Key_W; - case XK_x: return Qt::Key_X; - case XK_y: return Qt::Key_Y; - case XK_z: return Qt::Key_Z; - case XK_braceleft: return Qt::Key_BraceLeft; - case XK_bar: return Qt::Key_Bar; - case XK_braceright: return Qt::Key_BraceRight; - case XK_asciitilde: return Qt::Key_AsciiTilde; - - case XK_nobreakspace: return Qt::Key_nobreakspace; - case XK_exclamdown: return Qt::Key_exclamdown; - case XK_cent: return Qt::Key_cent; - case XK_sterling: return Qt::Key_sterling; - case XK_currency: return Qt::Key_currency; - case XK_yen: return Qt::Key_yen; - case XK_brokenbar: return Qt::Key_brokenbar; - case XK_section: return Qt::Key_section; - case XK_diaeresis: return Qt::Key_diaeresis; - case XK_copyright: return Qt::Key_copyright; - case XK_ordfeminine: return Qt::Key_ordfeminine; - case XK_guillemotleft: return Qt::Key_guillemotleft; - case XK_notsign: return Qt::Key_notsign; - case XK_hyphen: return Qt::Key_hyphen; - case XK_registered: return Qt::Key_registered; - case XK_macron: return Qt::Key_macron; - case XK_degree: return Qt::Key_degree; - case XK_plusminus: return Qt::Key_plusminus; - case XK_twosuperior: return Qt::Key_twosuperior; - case XK_threesuperior: return Qt::Key_threesuperior; - case XK_acute: return Qt::Key_acute; - case XK_mu: return Qt::Key_mu; - case XK_paragraph: return Qt::Key_paragraph; - case XK_periodcentered: return Qt::Key_periodcentered; - case XK_cedilla: return Qt::Key_cedilla; - case XK_onesuperior: return Qt::Key_onesuperior; - case XK_masculine: return Qt::Key_masculine; - case XK_guillemotright: return Qt::Key_guillemotright; - case XK_onequarter: return Qt::Key_onequarter; - case XK_onehalf: return Qt::Key_onehalf; - case XK_threequarters: return Qt::Key_threequarters; - case XK_questiondown: return Qt::Key_questiondown; - case XK_Agrave: return Qt::Key_Agrave; - case XK_Aacute: return Qt::Key_Aacute; - case XK_Acircumflex: return Qt::Key_Acircumflex; - case XK_Atilde: return Qt::Key_Atilde; - case XK_Adiaeresis: return Qt::Key_Adiaeresis; - case XK_Aring: return Qt::Key_Aring; - case XK_AE: return Qt::Key_AE; - case XK_Ccedilla: return Qt::Key_Ccedilla; - case XK_Egrave: return Qt::Key_Egrave; - case XK_Eacute: return Qt::Key_Eacute; - case XK_Ecircumflex: return Qt::Key_Ecircumflex; - case XK_Ediaeresis: return Qt::Key_Ediaeresis; - case XK_Igrave: return Qt::Key_Igrave; - case XK_Iacute: return Qt::Key_Iacute; - case XK_Icircumflex: return Qt::Key_Icircumflex; - case XK_Idiaeresis: return Qt::Key_Idiaeresis; - case XK_ETH: return Qt::Key_ETH; - //case XK_Eth: return Qt::Key_Eth; - case XK_Ntilde: return Qt::Key_Ntilde; - case XK_Ograve: return Qt::Key_Ograve; - case XK_Oacute: return Qt::Key_Oacute; - case XK_Ocircumflex: return Qt::Key_Ocircumflex; - case XK_Otilde: return Qt::Key_Otilde; - case XK_Odiaeresis: return Qt::Key_Odiaeresis; - case XK_multiply: return Qt::Key_multiply; - //case XK_Oslash: return Qt::Key_AsciiTilde; - case XK_Ooblique: return Qt::Key_Ooblique; - case XK_Ugrave: return Qt::Key_Ugrave; - case XK_Uacute: return Qt::Key_Uacute; - case XK_Ucircumflex: return Qt::Key_Ucircumflex; - case XK_Udiaeresis: return Qt::Key_Udiaeresis; - case XK_Yacute: return Qt::Key_Yacute; - case XK_THORN: return Qt::Key_THORN; - //case XK_Thorn: return Qt::Key_AsciiTilde; - case XK_ssharp: return Qt::Key_ssharp; - /*case XK_agrave: return Qt::Key_AsciiTilde; - case XK_aacute: return Qt::Key_AsciiTilde; - case XK_acircumflex: return Qt::Key_AsciiTilde; - case XK_atilde: return Qt::Key_AsciiTilde; - case XK_adiaeresis: return Qt::Key_AsciiTilde; - case XK_aring: return Qt::Key_AsciiTilde; - case XK_ae: return Qt::Key_AsciiTilde; - case XK_ccedilla: return Qt::Key_AsciiTilde; - case XK_egrave: return Qt::Key_AsciiTilde; - case XK_eacute: return Qt::Key_AsciiTilde; - case XK_ecircumflex: return Qt::Key_AsciiTilde; - case XK_ediaeresis: return Qt::Key_AsciiTilde; - case XK_igrave: return Qt::Key_AsciiTilde; - case XK_iacute: return Qt::Key_AsciiTilde; - case XK_icircumflex: return Qt::Key_AsciiTilde; - case XK_idiaeresis: return Qt::Key_AsciiTilde; - case XK_eth: return Qt::Key_AsciiTilde; - case XK_ntilde: return Qt::Key_AsciiTilde; - case XK_ograve: return Qt::Key_AsciiTilde; - case XK_oacute: return Qt::Key_AsciiTilde; - case XK_ocircumflex: return Qt::Key_AsciiTilde; - case XK_otilde: return Qt::Key_AsciiTilde; - case XK_odiaeresis: return Qt::Key_AsciiTilde; - case XK_division: return Qt::Key_AsciiTilde; - case XK_oslash: return Qt::Key_AsciiTilde; - case XK_ooblique: return Qt::Key_AsciiTilde; - case XK_ugrave: return Qt::Key_AsciiTilde; - case XK_uacute: return Qt::Key_AsciiTilde; - case XK_ucircumflex: return Qt::Key_AsciiTilde; - case XK_udiaeresis: return Qt::Key_AsciiTilde; - case XK_yacute: return Qt::Key_AsciiTilde; - case XK_thorn: return Qt::Key_AsciiTilde; - case XK_ydiaeresis: return Qt::Key_AsciiTilde; - - case: XK_Agonek: return Qt::Key_AsciiTilde; - case XK_breve: return Qt::Key_AsciiTilde; - case XK_Lstroke: return Qt::Key_AsciiTilde; - case XK_Lcaron: return Qt::Key_AsciiTilde; - case XK_Sacute: return Qt::Key_AsciiTilde; - case XK_Scaron: return Qt::Key_AsciiTilde; - case XK_Scedilla: return Qt::Key_AsciiTilde; - case XK_Tcaron: return Qt::Key_AsciiTilde; - case XK_Zacute: return Qt::Key_AsciiTilde; - case XK_Zcaron: return Qt::Key_AsciiTilde; - case XK_Zabovedot: return Qt::Key_AsciiTilde; - case XK_aogonek: return Qt::Key_AsciiTilde; - case XK_ogonek: return Qt::Key_AsciiTilde; - case XK_lstroke: return Qt::Key_AsciiTilde; - case XK_lcaron: return Qt::Key_AsciiTilde; - case XK_sacute: return Qt::Key_AsciiTilde; - case XK_caron: return Qt::Key_AsciiTilde; - case XK_scaron: return Qt::Key_AsciiTilde; - case XK_scedilla: return Qt::Key_AsciiTilde; - case XK_tcaron: return Qt::Key_AsciiTilde; - case XK_zacute: return Qt::Key_AsciiTilde; - case XK_doubleacute: return Qt::Key_AsciiTilde; - case XK_zcaron: return Qt::Key_AsciiTilde; - case XK_zabovedot: return Qt::Key_AsciiTilde; - case XK_Racute: return Qt::Key_AsciiTilde; - case XK_Abreve: return Qt::Key_AsciiTilde; - case XK_Lacute: return Qt::Key_AsciiTilde; - case XK_Cacute: return Qt::Key_AsciiTilde; - case XK_Ccaron: return Qt::Key_AsciiTilde; - case XK_Eogonek: return Qt::Key_AsciiTilde; - case XK_Ecaron: return Qt::Key_AsciiTilde; - case XK_Dcaron: return Qt::Key_AsciiTilde; - case XK_Dstroke: return Qt::Key_AsciiTilde; - case XK_Nacute: return Qt::Key_AsciiTilde; - case XK_Ncaron: return Qt::Key_AsciiTilde; - case XK_Odoubleacute: return Qt::Key_AsciiTilde; - case XK_Rcaron: return Qt::Key_AsciiTilde; - case XK_Uring: return Qt::Key_AsciiTilde; - case XK_Udoubleacute: return Qt::Key_AsciiTilde; - case XK_Tcedilla: return Qt::Key_AsciiTilde; - case XK_racute: return Qt::Key_AsciiTilde; - case XK_abreve: return Qt::Key_AsciiTilde; - case XK_lacute: return Qt::Key_AsciiTilde; - case XK_cacute: return Qt::Key_AsciiTilde; - case XK_ccaron: return Qt::Key_AsciiTilde; - case XK_eogonek: return Qt::Key_AsciiTilde; - case XK_ecaron: return Qt::Key_AsciiTilde; - case XK_dcaron: return Qt::Key_AsciiTilde; - case XK_dstroke: return Qt::Key_AsciiTilde; - case XK_nacute: return Qt::Key_AsciiTilde; - case XK_ncaron: return Qt::Key_AsciiTilde; - case XK_odoubleacute: return Qt::Key_AsciiTilde; - case XK_rcaron: return Qt::Key_AsciiTilde; - case XK_uring: return Qt::Key_AsciiTilde; - case XK_udoubleacute: return Qt::Key_AsciiTilde; - case XK_tcedilla: return Qt::Key_AsciiTilde; - case XK_abovedot: return Qt::Key_AsciiTilde; - case XK_Hstroke: return Qt::Key_AsciiTilde; - case XK_Hcircumflex: return Qt::Key_AsciiTilde; - case XK_Iabovedot: return Qt::Key_AsciiTilde; - case XK_Gbreve: return Qt::Key_AsciiTilde; - case XK_Jcircumflex: return Qt::Key_AsciiTilde; - case XK_hstroke: return Qt::Key_AsciiTilde; - case XK_hcircumflex: return Qt::Key_AsciiTilde; - case XK_idotless: return Qt::Key_AsciiTilde; - case XK_gbreve: return Qt::Key_AsciiTilde; - case XK_jcircumflex: return Qt::Key_AsciiTilde; - case XK_Cabovedot: return Qt::Key_AsciiTilde; - case XK_Ccircumflex: return Qt::Key_AsciiTilde; - case XK_Gabovedot: return Qt::Key_AsciiTilde; - case XK_Gcircumflex: return Qt::Key_AsciiTilde; - case XK_Ubreve: return Qt::Key_AsciiTilde; - case XK_Scircumflex: return Qt::Key_AsciiTilde; - case XK_cabovedot: return Qt::Key_AsciiTilde; - case XK_ccircumflex: return Qt::Key_AsciiTilde; - case XK_gabovedot: return Qt::Key_AsciiTilde; - case XK_gcircumflex: return Qt::Key_AsciiTilde; - case XK_ubreve: return Qt::Key_AsciiTilde; - case XK_scircumflex: return Qt::Key_AsciiTilde; - case XK_kra: return Qt::Key_AsciiTilde; - case XK_kappa: return Qt::Key_AsciiTilde; - case XK_Rcedilla: return Qt::Key_AsciiTilde; - case XK_Itilde: return Qt::Key_AsciiTilde; - case XK_Lcedilla: return Qt::Key_AsciiTilde; - case XK_Emacron: return Qt::Key_AsciiTilde; - case XK_Gcedilla: return Qt::Key_AsciiTilde; - case XK_Tslash: return Qt::Key_AsciiTilde; - case XK_rcedilla: return Qt::Key_AsciiTilde; - case XK_itilde: return Qt::Key_AsciiTilde; - case XK_lcedilla: return Qt::Key_AsciiTilde; - case XK_emacron: return Qt::Key_AsciiTilde; - case XK_gcedilla: return Qt::Key_AsciiTilde; - case XK_tslash: return Qt::Key_AsciiTilde; - case XK_ENG: return Qt::Key_AsciiTilde; - case XK_eng: return Qt::Key_AsciiTilde; - case XK_Amacron: return Qt::Key_AsciiTilde; - case XK_Iogonek: return Qt::Key_AsciiTilde; - case XK_Eabovedot: return Qt::Key_AsciiTilde; - case XK_Imacron: return Qt::Key_AsciiTilde; - case XK_Ncedilla: return Qt::Key_AsciiTilde; - case XK_Omacron: return Qt::Key_AsciiTilde; - case XK_Kcedilla: return Qt::Key_AsciiTilde; - case XK_Uogonek: return Qt::Key_AsciiTilde; - case XK_Utilde: return Qt::Key_AsciiTilde; - case XK_Umacron: return Qt::Key_AsciiTilde; - case XK_amacron: return Qt::Key_AsciiTilde; - case XK_iogonek: return Qt::Key_AsciiTilde; - case XK_eabovedot: return Qt::Key_AsciiTilde; - case XK_imacron: return Qt::Key_AsciiTilde; - case XK_ncedilla: return Qt::Key_AsciiTilde; - case XK_omacron: return Qt::Key_AsciiTilde; - case XK_kcedilla: return Qt::Key_AsciiTilde; - case XK_uogonek: return Qt::Key_AsciiTilde; - case XK_utilde: return Qt::Key_AsciiTilde; - case XK_umacron: return Qt::Key_AsciiTilde; - case XK_Wcircumflex: return Qt::Key_AsciiTilde; - case XK_wcircumflex: return Qt::Key_AsciiTilde; - case XK_Ycircumflex: return Qt::Key_AsciiTilde; - case XK_ycircumflex: return Qt::Key_AsciiTilde; - case XK_Babovedot: return Qt::Key_AsciiTilde; - case XK_babovedot: return Qt::Key_AsciiTilde; - case XK_Dabovedot: return Qt::Key_AsciiTilde; - case XK_dabovedot: return Qt::Key_AsciiTilde; - case XK_Fabovedot: return Qt::Key_AsciiTilde; - case XK_fabovedot: return Qt::Key_AsciiTilde; - case XK_Mabovedot: return Qt::Key_AsciiTilde; - case XK_mabovedot: return Qt::Key_AsciiTilde; - case XK_Pabovedot: return Qt::Key_AsciiTilde; - case XK_pabovedot: return Qt::Key_AsciiTilde; - case XK_Sabovedot: return Qt::Key_AsciiTilde; - case XK_sabovedot: return Qt::Key_AsciiTilde; - case XK_Tabovedot: return Qt::Key_AsciiTilde; - case XK_tabovedot: return Qt::Key_AsciiTilde; - case XK_Wgrave: return Qt::Key_AsciiTilde; - case XK_wgrave: return Qt::Key_AsciiTilde; - case XK_Wacute: return Qt::Key_AsciiTilde; - case XK_wacute: return Qt::Key_AsciiTilde; - case XK_Wdiaeresis: return Qt::Key_AsciiTilde; - case XK_wdiaeresis: return Qt::Key_AsciiTilde; - case XK_Ygrave: return Qt::Key_AsciiTilde; - case XK_ygrave: return Qt::Key_AsciiTilde; - case XK_OE: return Qt::Key_AsciiTilde; - case XK_oe: return Qt::Key_AsciiTilde; - case XK_Ydiaeresis: return Qt::Key_AsciiTilde;*/ - default: - qDebug() << "Unknown Key"; - } - qDebug() << " -- Simple Qt Map:" << (Qt::Key)(symbol); - qDebug() << " -- Key Sequence Map:" << QKeySequence(symbol); - qDebug() << " - Not implemented yet"; - return Qt::Key_unknown; -} - -NativeWindowSystem::MouseButton NativeWindowSystem::MouseToQt(int keycode){ - switch(keycode){ - case 1: - return NativeWindowSystem::LeftButton; - case 3: - return NativeWindowSystem::RightButton; - case 2: - return NativeWindowSystem::MidButton; - case 4: - return NativeWindowSystem::WheelUp; - case 5: - return NativeWindowSystem::WheelDown; - case 6: - return NativeWindowSystem::WheelLeft; - case 7: - return NativeWindowSystem::WheelRight; - case 8: - return NativeWindowSystem::BackButton; //Not sure if this is correct yet (1/27/17) - case 9: - return NativeWindowSystem::ForwardButton; //Not sure if this is correct yet (1/27/17) - default: - return NativeWindowSystem::NoButton; - } -} diff --git a/src-qt5/src-cpp/NativeWindowSystem.cpp b/src-qt5/src-cpp/NativeWindowSystem.cpp deleted file mode 100644 index e8e9655a..00000000 --- a/src-qt5/src-cpp/NativeWindowSystem.cpp +++ /dev/null @@ -1,986 +0,0 @@ -//=========================================== -// 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> -#include <QApplication> -#include <QScreen> -#include <QFont> -#include <QFontMetrics> -#include <QKeySequence> - - -//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_NOTIFY | \ - XCB_EVENT_MASK_POINTER_MOTION | \ - XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_FOCUS_CHANGE | \ - XCB_EVENT_MASK_ENTER_WINDOW) - -#define NORMAL_WIN_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | \ - XCB_EVENT_MASK_BUTTON_RELEASE | \ - XCB_EVENT_MASK_POINTER_MOTION | \ - XCB_EVENT_MASK_BUTTON_MOTION | \ - XCB_EVENT_MASK_EXPOSURE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_ENTER_WINDOW | \ - XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_FOCUS_CHANGE) - -#define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_FOCUS_CHANGE | \ - XCB_EVENT_MASK_POINTER_MOTION) - -#define FRAME_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | \ - XCB_EVENT_MASK_BUTTON_RELEASE | \ - XCB_EVENT_MASK_POINTER_MOTION | \ - XCB_EVENT_MASK_EXPOSURE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_ENTER_WINDOW) - -inline void registerClientEvents(WId id, bool client = true){ - uint32_t values[] = {XCB_NONE}; - values[0] = client ? CLIENT_EVENT_MASK : FRAME_EVENT_MASK ; - /*{ (XCB_EVENT_MASK_PROPERTY_CHANGE - | XCB_EVENT_MASK_BUTTON_PRESS - | XCB_EVENT_MASK_BUTTON_RELEASE - | XCB_EVENT_MASK_POINTER_MOTION - | XCB_EVENT_MASK_BUTTON_MOTION - | XCB_EVENT_MASK_EXPOSURE - | XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT - | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY - | XCB_EVENT_MASK_ENTER_WINDOW) - };*/ - xcb_change_window_attributes(QX11Info::connection(), id, XCB_CW_EVENT_MASK, values); -} - -/*inline void registerClientEvents(WId id){ - uint32_t value_list[1] = {NORMAL_WIN_EVENT_MASK}; - xcb_change_window_attributes(QX11Info::connection(), id, XCB_CW_EVENT_MASK, value_list); -}*/ - -//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(){ - xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(QX11Info::connection(), &EWMH); - if(!xcb_ewmh_init_atoms_replies(&EWMH, cookie, NULL) ){ - qDebug() << "Error with XCB atom initializations"; - return false; - } - - QStringList atoms; - atoms << "WM_TAKE_FOCUS" << "WM_DELETE_WINDOW" << "WM_PROTOCOLS" << "_NET_WM_WINDOW_OPACITY" - << "WM_CHANGE_STATE" << "_NET_SYSTEM_TRAY_OPCODE" << "_NET_SYSTEM_TRAY_ORIENTATION" << "_XEMBED" - << "_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){ - 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 (ATOMS.keys().length() == atoms.length()); - } - - WId getTransientFor(WId win){ - xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for_unchecked(QX11Info::connection(), win); - xcb_window_t trans; - if(1!= xcb_icccm_get_wm_transient_for_reply(QX11Info::connection(), cookie, &trans, NULL) ){ - return win; //error in fetching transient window ID (or none found) - }else{ - return trans; - } -} - - 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, \ - wm_window, 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 start_system_tray(){ - 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) - tray_window = xcb_generate_id(QX11Info::connection()); //need a new ID - uint32_t params[] = {1}; - xcb_create_window(QX11Info::connection(), root_screen->root_depth, \ - tray_window, root_screen->root, -1, -1, 1, 1, 0, \ - XCB_WINDOW_CLASS_INPUT_OUTPUT, root_screen->root_visual, \ - XCB_CW_OVERRIDE_REDIRECT, params); - //Now register this widget as the system tray - xcb_set_selection_owner(QX11Info::connection(), tray_window, _NET_SYSTEM_TRAY_S, XCB_CURRENT_TIME); - //Make sure that it was registered properly - ownreply = xcb_get_selection_owner_reply(QX11Info::connection(), \ - xcb_get_selection_owner_unchecked(QX11Info::connection(), _NET_SYSTEM_TRAY_S), NULL); - if(ownreply==0 || ownreply->owner != tray_window){ - if(ownreply!=0){ free(ownreply); } - qWarning() << " - Could not register the system tray"; - xcb_destroy_window(QX11Info::connection(), tray_window); - return false; - } - free(ownreply); //done with structure - //Now register the orientation of the system tray - uint32_t orient = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; - xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, tray_window, \ - ATOMS.value("_NET_SYSTEM_TRAY_ORIENTATION"), XCB_ATOM_CARDINAL, 32, 1, &orient); - - //Now set the visual ID for the system tray (same as the root window, but TrueColor) - xcb_visualtype_t *type = xcb_aux_find_visual_by_attrs(root_screen, XCB_VISUAL_CLASS_TRUE_COLOR, 32); - if(type!=0){ - xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, tray_window, \ - ATOMS.value("_NET_SYSTEM_TRAY_VISUAL"), XCB_ATOM_VISUALID, 32, 1, &type->visual_id); - }else{ - qWarning() << " - Could not set TrueColor visual for system tray"; - } - - //Finally, send out an X event letting others know that the system tray is up and running - xcb_client_message_event_t event; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.window = root_screen->root; - event.type = EWMH.MANAGER; //MANAGER atom - event.data.data32[0] = XCB_TIME_CURRENT_TIME; //CurrentTime; - event.data.data32[1] = _NET_SYSTEM_TRAY_S; //_NET_SYSTEM_TRAY_S atom - event.data.data32[2] = tray_window; - event.data.data32[3] = 0; - event.data.data32[4] = 0; - - xcb_send_event(QX11Info::connection(), 0, root_screen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); - return true; - } - -}; //end private objects class - - -//inline functions for setting up the internal objects - - -// === PUBLIC === -NativeWindowSystem::NativeWindowSystem() : QObject(){ - obj = 0; - pingTimer = 0; - screenLocked = false; -} - -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 - bool ok = obj->register_wm(); - if(ok){ - setRoot_supportedActions(); - ok = obj->start_system_tray(); - }else{ - qWarning() << "Could not register the WM"; - } - return ok; -} - -void NativeWindowSystem::stop(){ - -} - -// === PRIVATE === -NativeWindow* NativeWindowSystem::findWindow(WId id, bool checkRelated){ - //qDebug() << "Find Window:" << id; - for(int i=0; i<NWindows.length(); i++){ - if(id==NWindows[i]->id() ){ return NWindows[i]; } - else if(id==NWindows[i]->frameId() ){ return NWindows[i]; } - //if(checkRelated && NWindows[i]->isRelatedTo(id)){ return NWindows[i]; } - //else if(!checkRelated && id==NWindows[i]->id()){ return NWindows[i]; } - } - //Check to see if this is a transient for some other window - if(checkRelated){ - //WId tid = obj->getTransientFor(id); - //if(tid!=id){ return findWindow(tid, checkRelated); } //call it recursively as needed - //qDebug() << " -- Could not find Window!"; - } - return 0; -} - -NativeWindow* NativeWindowSystem::findTrayWindow(WId id){ - for(int i=0; i<TWindows.length(); i++){ - if(TWindows[i]->isRelatedTo(id)){ return TWindows[i]; } - } - return 0; -} - -void NativeWindowSystem::UpdateWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props){ - //Put the properties in logical groups as appropriate (some XCB calls return multiple properties) - if(props.contains(NativeWindow::Title)){ - //Try the EWMH standards first - // _NET_WM_NAME - QString name; - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name_unchecked(&obj->EWMH, win->id()); - if(cookie.sequence != 0){ - xcb_ewmh_get_utf8_strings_reply_t data; - if( 1 == xcb_ewmh_get_wm_name_reply(&obj->EWMH, cookie, &data, NULL) ){ - name = QString::fromUtf8(data.strings, data.strings_len); - } - } - if(name.isEmpty()){ - //_NET_WM_VISIBLE_NAME - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_visible_name_unchecked(&obj->EWMH, win->id()); - if(cookie.sequence != 0){ - xcb_ewmh_get_utf8_strings_reply_t data; - if( 1 == xcb_ewmh_get_wm_visible_name_reply(&obj->EWMH, cookie, &data, NULL) ){ - name = QString::fromUtf8(data.strings, data.strings_len); - } - } - } - if(name.isEmpty()){ - //Now try the ICCCM standard - xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_name_unchecked(QX11Info::connection(), win->id()); - xcb_icccm_get_text_property_reply_t reply; - if(1 == xcb_icccm_get_wm_name_reply(QX11Info::connection(), cookie, &reply, NULL) ){ - name = QString::fromLocal8Bit(reply.name, reply.name_len); - xcb_icccm_get_text_property_reply_wipe(&reply); - } - } - win->setProperty(NativeWindow::Title, name); - } //end TITLE property - - if(props.contains(NativeWindow::ShortTitle)){ - //Try the EWMH standards first - // _NET_WM_ICON_NAME - QString name; - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon_name_unchecked(&obj->EWMH, win->id()); - if(cookie.sequence != 0){ - xcb_ewmh_get_utf8_strings_reply_t data; - if( 1 == xcb_ewmh_get_wm_icon_name_reply(&obj->EWMH, cookie, &data, NULL) ){ - name = QString::fromUtf8(data.strings, data.strings_len); - } - } - if(name.isEmpty()){ - //_NET_WM_VISIBLE_ICON_NAME - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_visible_icon_name_unchecked(&obj->EWMH, win->id()); - if(cookie.sequence != 0){ - xcb_ewmh_get_utf8_strings_reply_t data; - if( 1 == xcb_ewmh_get_wm_visible_icon_name_reply(&obj->EWMH, cookie, &data, NULL) ){ - name = QString::fromUtf8(data.strings, data.strings_len); - } - } - } - if(name.isEmpty()){ - //Now try the ICCCM standard - xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_icon_name_unchecked(QX11Info::connection(), win->id()); - xcb_icccm_get_text_property_reply_t reply; - if(1 == xcb_icccm_get_wm_icon_name_reply(QX11Info::connection(), cookie, &reply, NULL) ){ - name = QString::fromLocal8Bit(reply.name, reply.name_len); - xcb_icccm_get_text_property_reply_wipe(&reply); - } - } - win->setProperty(NativeWindow::ShortTitle, name); - } //end SHORTTITLE property - - if(props.contains(NativeWindow::Icon)){ - //See if this is a tray icon first (different routine - entire app window is the icon) - QIcon icon; - if(win == findTrayWindow(win->id())){ - //Tray Icon Window - QPixmap pix; - //Get the current QScreen (for XCB->Qt conversion) - QList<QScreen*> scrnlist = QApplication::screens(); - //Try to grab the given window directly with Qt - for(int i=0; i<scrnlist.length() && pix.isNull(); i++){ - pix = scrnlist[i]->grabWindow(win->id()); - } - icon.addPixmap(pix); - }else{ - //Standard window - //Fetch the _NET_WM_ICON for the window and return it as a QIcon - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon_unchecked(&obj->EWMH, win->id()); - xcb_ewmh_get_wm_icon_reply_t reply; - if(1 == xcb_ewmh_get_wm_icon_reply(&obj->EWMH, cookie, &reply, NULL)){ - xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply); - //Just use the first - bool done =false; - while(!done){ - //Now convert the current data into a Qt image - // - first 2 elements are width and height (removed via XCB functions) - // - data in rows from left to right and top to bottom - QImage image(iter.width, iter.height, QImage::Format_ARGB32); //initial setup - uint* dat = iter.data; - //dat+=2; //remember the first 2 element offset - for(int i=0; i<image.byteCount()/4; ++i, ++dat){ - ((uint*)image.bits())[i] = *dat; - } - icon.addPixmap(QPixmap::fromImage(image)); //layer this pixmap onto the icon - //Now see if there are any more icons available - done = (iter.rem<1); //number of icons remaining - if(!done){ xcb_ewmh_get_wm_icon_next(&iter); } //get the next icon data - } - xcb_ewmh_get_wm_icon_reply_wipe(&reply); - } - } //end type of window - win->setProperty(NativeWindow::Icon, icon); - } //end ICON property - - if(props.contains(NativeWindow::MinSize) || props.contains(NativeWindow::MaxSize) - || props.contains(NativeWindow::Size) || props.contains(NativeWindow::GlobalPos) ){ - //Try the ICCCM "Normal Hints" structure first (newer spec?) - xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints_unchecked(QX11Info::connection(), win->id()); - xcb_size_hints_t reply; - bool ok = false; - if(1==xcb_icccm_get_wm_normal_hints_reply(QX11Info::connection(), cookie, &reply, NULL) ){ ok = true; } - else{ - //Could not find normal hints, try the older "size hints" instead - cookie = xcb_icccm_get_wm_size_hints_unchecked(QX11Info::connection(), win->id(), XCB_ATOM_WM_SIZE_HINTS); - if(1==xcb_icccm_get_wm_size_hints_reply(QX11Info::connection(), cookie, &reply, NULL) ){ ok = true; } - } - if(ok){ - bool initsize = win->property(NativeWindow::Size).isNull(); //initial window size - if( (reply.flags&XCB_ICCCM_SIZE_HINT_US_POSITION)==XCB_ICCCM_SIZE_HINT_US_POSITION ){ win->setProperty(NativeWindow::GlobalPos, QPoint(reply.x,reply.y)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_US_SIZE)==XCB_ICCCM_SIZE_HINT_US_SIZE ){ win->setProperty(NativeWindow::Size, QSize(reply.width, reply.height)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_POSITION)==XCB_ICCCM_SIZE_HINT_P_POSITION ){ win->setProperty(NativeWindow::GlobalPos, QPoint(reply.x,reply.y)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_SIZE)==XCB_ICCCM_SIZE_HINT_P_SIZE ){ win->setProperty(NativeWindow::Size, QSize(reply.width, reply.height)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)==XCB_ICCCM_SIZE_HINT_P_MIN_SIZE ){ win->setProperty(NativeWindow::MinSize, QSize(reply.min_width, reply.min_height)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)==XCB_ICCCM_SIZE_HINT_P_MAX_SIZE ){ win->setProperty(NativeWindow::MaxSize, QSize(reply.max_width, reply.max_height)); } - if( (reply.flags&XCB_ICCCM_SIZE_HINT_BASE_SIZE)==XCB_ICCCM_SIZE_HINT_BASE_SIZE && initsize ){ win->setProperty(NativeWindow::Size, QSize(reply.base_width, reply.base_height)); } - //if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)==XCB_ICCCM_SIZE_HINT_P_RESIZE_INC ){ hints.width_inc=reply.width_inc; hints.height_inc=reply.height_inc; } - //if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_ASPECT)==XCB_ICCCM_SIZE_HINT_P_ASPECT ){ hints.min_aspect_num=reply.min_aspect_num; hints.min_aspect_den=reply.min_aspect_den; hints.max_aspect_num=reply.max_aspect_num; hints.max_aspect_den=reply.max_aspect_den;} - //if( (reply.flags&XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY)==XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY ){ hints.win_gravity=reply.win_gravity; } - } - } //end of geometry properties - - if(props.contains(NativeWindow::Name)){ - //Put the app/class name here (much more static than the "Title" properties - xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_class_unchecked(QX11Info::connection(), win->id()); - xcb_icccm_get_wm_class_reply_t reply; - if(1 == xcb_icccm_get_wm_class_reply(QX11Info::connection(), cookie, &reply, NULL) ){ - //Returns: "<instance name>::::<class name>" - win->setProperty(NativeWindow::Name, ( QString::fromLocal8Bit(reply.instance_name)+"::::"+QString::fromLocal8Bit(reply.class_name) )); - xcb_icccm_get_wm_class_reply_wipe(&reply); - } - } //end NAME property - - if(props.contains(NativeWindow::Workspace)){ - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_desktop_unchecked(&obj->EWMH, win->id()); - uint32_t num = 0; - int wkspace = -1; - if(1==xcb_ewmh_get_wm_desktop_reply(&obj->EWMH, cookie, &num, NULL) ){ - if(num!=0xFFFFFFFF){ wkspace = num; } - }/*else{ - //Error in fetching property (not set?) - // - put it on the current screen - out = WM_Get_Current_Desktop(); - }*/ - win->setProperty(NativeWindow::Workspace, wkspace); - } - if(props.contains(NativeWindow::FrameExtents)){ - //Just assign default values to this - need to automate it later - //win->setProperty(NativeWindow::FrameExtents, QVariant::fromValue<QList<int> >(QList<int>() << 5 << 5 << 5+QFontMetrics(QFont()).height() << 5) ); - } - if(props.contains(NativeWindow::RelatedWindows)){ - WId orig = win->id(); - WId tid = obj->getTransientFor(orig); - QList<WId> list; - while(tid != orig){ - list << tid; - orig = tid; - tid = obj->getTransientFor(orig); - } - win->setProperty(NativeWindow::RelatedWindows, QVariant::fromValue(list)); - } - if(props.contains(NativeWindow::Visible)){ - xcb_get_window_attributes_reply_t *attr = xcb_get_window_attributes_reply(QX11Info::connection(), xcb_get_window_attributes(QX11Info::connection(), win->id()) , NULL); - if(attr != 0){ - win->setProperty(NativeWindow::Visible, attr->map_state == XCB_MAP_STATE_VIEWABLE); - free(attr); - } - } - if(props.contains(NativeWindow::WinTypes)){ - QList< NativeWindow::Type> types; - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type_unchecked(&obj->EWMH, win->id()); - xcb_ewmh_get_atoms_reply_t reply; - if(1==xcb_ewmh_get_wm_window_type_reply(&obj->EWMH, cookie, &reply, NULL) ){ - for(unsigned int i=0; i<reply.atoms_len; i++){ - if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_DESKTOP){ types << NativeWindow::T_DESKTOP; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_DOCK){ types << NativeWindow::T_DOCK; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_TOOLBAR){ types << NativeWindow::T_TOOLBAR; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_MENU){ types << NativeWindow::T_MENU; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_UTILITY){ types << NativeWindow::T_UTILITY; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_SPLASH){ types << NativeWindow::T_SPLASH; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_DIALOG){ types << NativeWindow::T_DIALOG; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_DROPDOWN_MENU){ types << NativeWindow::T_DROPDOWN_MENU; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_POPUP_MENU){ types << NativeWindow::T_POPUP_MENU; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_TOOLTIP){ types << NativeWindow::T_TOOLTIP; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_NOTIFICATION){ types << NativeWindow::T_NOTIFICATION; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_COMBO){ types << NativeWindow::T_COMBO; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_DND){ types << NativeWindow::T_DND; } - else if(reply.atoms[i]==obj->EWMH._NET_WM_WINDOW_TYPE_NORMAL){ types << NativeWindow::T_NORMAL; } - } - } - if(types.isEmpty()){ types << NativeWindow::T_NORMAL; } - win->setProperty(NativeWindow::WinTypes, QVariant::fromValue< QList<NativeWindow::Type> >(types) ); - } -} - -void NativeWindowSystem::ChangeWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props, QList<QVariant> vals){ - if(props.length() == 0 || vals.length()!=props.length() || win ==0 ){ return; } - //qDebug() << "Change Window Properties:" << props << vals; - if(props.contains(NativeWindow::Title)){ - - } - if(props.contains(NativeWindow::ShortTitle)){ - - } - if(props.contains(NativeWindow::Icon)){ - - } - if(props.contains(NativeWindow::Size) || props.contains(NativeWindow::GlobalPos) ){ - /*xcb_configure_window_value_list_t valList; - //valList.x = 0; //Note that this is the relative position - should always be 0,0 relative to the embed widget - //valList.y = 0; - QSize sz = win->property(NativeWindow::Size).toSize(); - if(props.contains(NativeWindow::Size)){ - sz = vals[ props.indexOf(NativeWindow::Size) ] .toSize(); - } - valList.width = sz.width(); - valList.height = sz.height(); - if(props.contains(NativeWindow::GlobalPos)){ - QPoint pt = vals[ props.indexOf(NativeWindow::GlobalPos) ] .toPoint(); - valList.x = pt.x(); - valList.y = pt.y(); - }else{ - valList.x = win->property(NativeWindow::GlobalPos).toPoint().x(); - valList.y = win->property(NativeWindow::GlobalPos).toPoint().y(); - } - uint16_t mask = 0; - mask = mask | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; - //qDebug() << "Configure window Geometry:" << sz; - xcb_configure_window_aux(QX11Info::connection(), win->id(), mask, &valList);*/ - } - if(props.contains(NativeWindow::Name)){ - - } - if(props.contains(NativeWindow::Workspace)){ - int num = vals[ props.indexOf(NativeWindow::Workspace) ].toInt(); - xcb_ewmh_set_wm_desktop(&obj->EWMH, win->id(), (num<0 ? 0xFFFFFFFF : qAbs(num) ) ); - } - if(props.contains(NativeWindow::RelatedWindows)){ - - } - if(props.contains(NativeWindow::Visible)){ - //qDebug() << "Check Window Visibility:" << vals[ props.indexOf(NativeWindow::Visible) ]; - if( vals[ props.indexOf(NativeWindow::Visible) ].toBool() ){ - //qDebug() << " - Map it!"; - xcb_map_window(QX11Info::connection(), win->id()); - }else{ - //qDebug() << " - Unmap it!"; - xcb_unmap_window(QX11Info::connection(), win->id()); - } - } - if(props.contains(NativeWindow::Active)){ - //Only one window can be "Active" at a time - so only do anything if this window wants to be active - if(vals[props.indexOf(NativeWindow::Active)].toBool() ){ - //Lower the currently active window (invisible window) to the bottom of the stack - xcb_window_t cactive; - if( 1 == xcb_ewmh_get_active_window_reply( &obj->EWMH, - xcb_ewmh_get_active_window_unchecked(&obj->EWMH, QX11Info::appScreen()), - &cactive, NULL) ){ - uint32_t val = XCB_STACK_MODE_BELOW; - xcb_configure_window(QX11Info::connection(), cactive, XCB_CONFIG_WINDOW_STACK_MODE, &val); - } - - xcb_ewmh_set_active_window(&obj->EWMH, QX11Info::appScreen(), win->id() ); - //Also send the active window a message to take input focus - xcb_set_input_focus(QX11Info::connection(), XCB_INPUT_FOCUS_PARENT, win->id(), XCB_CURRENT_TIME); - //Send the window a WM_TAKE_FOCUS message -/* xcb_client_message_event_t event; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.window = win->id(); - event.type = obj->ATOMS["WM_PROTOCOLS"]; - event.data.data32[0] = obj->ATOMS["WM_TAKE_FOCUS"]; - event.data.data32[1] = XCB_TIME_CURRENT_TIME; //CurrentTime; - event.data.data32[2] = 0; - event.data.data32[3] = 0; - event.data.data32[4] = 0; - - xcb_send_event(QX11Info::connection(), 0, win->id(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); - xcb_flush(QX11Info::connection()); -*/ - } - } - -} - -// === PUBLIC SLOTS === -//These are the slots which are typically only used by the desktop system itself or the NativeEventFilter -void NativeWindowSystem::RegisterVirtualRoot(WId id){ - //Convert to XCB array - xcb_window_t array[1]; - array[0] = id; - //Set the property - xcb_ewmh_set_virtual_roots(&obj->EWMH, QX11Info::appScreen(), 1, array); - //Now also enable automatic compositing for children of this window - //xcb_composite_redirect_window(QX11Info::connection(), id, XCB_COMPOSITE_REDIRECT_AUTOMATIC); - //xcb_composite_redirect_subwindows(QX11Info::connection(), id, XCB_COMPOSITE_REDIRECT_AUTOMATIC); -} - -void NativeWindowSystem::setRoot_supportedActions(){ -//NET_WM standards (ICCCM implied - no standard way to list those) - xcb_atom_t list[] = {obj->EWMH._NET_WM_NAME, - obj->EWMH._NET_WM_ICON, - obj->EWMH._NET_WM_ICON_NAME, - obj->EWMH._NET_WM_DESKTOP, - /*obj->ATOMS["_NET_WM_WINDOW_OPACITY"],*/ - /*_NET_WINDOW_TYPE (and all the various types - 15 in total*/ - obj->EWMH._NET_WM_WINDOW_TYPE, obj->EWMH._NET_WM_WINDOW_TYPE_DESKTOP, obj->EWMH._NET_WM_WINDOW_TYPE_DOCK, - obj->EWMH._NET_WM_WINDOW_TYPE_TOOLBAR, obj->EWMH._NET_WM_WINDOW_TYPE_MENU, obj->EWMH._NET_WM_WINDOW_TYPE_UTILITY, - obj->EWMH._NET_WM_WINDOW_TYPE_SPLASH, obj->EWMH._NET_WM_WINDOW_TYPE_DIALOG, obj->EWMH._NET_WM_WINDOW_TYPE_NORMAL, - obj->EWMH._NET_WM_WINDOW_TYPE_DROPDOWN_MENU, obj->EWMH._NET_WM_WINDOW_TYPE_POPUP_MENU, obj->EWMH._NET_WM_WINDOW_TYPE_TOOLTIP, - obj->EWMH._NET_WM_WINDOW_TYPE_NOTIFICATION, obj->EWMH._NET_WM_WINDOW_TYPE_COMBO, obj->EWMH._NET_WM_WINDOW_TYPE_DND, - }; - xcb_ewmh_set_supported(&obj->EWMH, QX11Info::appScreen(), 20,list); -} - -void NativeWindowSystem::setRoot_numberOfWorkspaces(QStringList names){ - if(names.isEmpty()){ names << "one"; } - //First set the overall number of workspaces - xcb_ewmh_set_number_of_desktops(&obj->EWMH, QX11Info::appScreen(), names.length()); - //Now set the names for the workspaces - //EWMH LIBRARY BROKEN - appears to be a mismatch in the function header (looking for a single char array, instead of a list of char arrays) - // Ken Moore - 6/27/17 - /* - char *array[ names.length() ]; - for(int i=0; i<names.length(); i++){array[i] = names[i].toUtf8().data(); } //Convert to an array of char arrays - xcb_ewmh_set_desktop_names(&obj->EWMH, QX11Info::appScreen(), names.length(), array); - */ -} - -void NativeWindowSystem::setRoot_currentWorkspace(int num){ - xcb_ewmh_set_current_desktop(&obj->EWMH, QX11Info::appScreen(), num); -} - -void NativeWindowSystem::setRoot_clientList(QList<WId> list, bool stackorder){ - //convert the QList into a generic array - xcb_window_t array[list.length()]; - for(int i=0; i<list.length(); i++){ array[i] = list[i]; } - if(stackorder){ - xcb_ewmh_set_client_list_stacking(&obj->EWMH, QX11Info::appScreen(), list.length(), array); - }else{ - xcb_ewmh_set_client_list(&obj->EWMH, QX11Info::appScreen(), list.length(), array); - } -} - -void NativeWindowSystem::setRoot_desktopGeometry(QRect geom){ - //This one is a combo function - // This will set the "DESKTOP_VIEWPORT" property (point) - // as well as the "DESKTOP_GEOMETRY" property (size) - //Turn the QList into xcb_ewmh_coordinates_t* - xcb_ewmh_coordinates_t array[1]; - array[0].x=geom.x(); array[0].y=geom.y(); - //Now set the property - xcb_ewmh_set_desktop_viewport(&obj->EWMH, QX11Info::appScreen(), 1, array); - xcb_ewmh_set_desktop_geometry(&obj->EWMH, QX11Info::appScreen(), geom.width(), geom.height()); -} - -void NativeWindowSystem::setRoot_desktopWorkarea(QList<QRect> list){ - //Convert to the XCB/EWMH data structures - xcb_ewmh_geometry_t array[list.length()]; - for(int i=0; i<list.length(); i++){ - array[i].x = list[i].x(); array[i].y = list[i].y(); - array[i].width = list[i].width(); array[i].height = list[i].height(); - } - //Now set the property - xcb_ewmh_set_workarea(&obj->EWMH, QX11Info::appScreen(), list.length(), array); -} - -void NativeWindowSystem::setRoot_activeWindow(WId win){ - /*xcb_ewmh_set_active_window(&obj->EWMH, QX11Info::appScreen(), win); - //Also send the active window a message to take input focus - //Send the window a WM_TAKE_FOCUS message - xcb_client_message_event_t event; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.window = win; - event.type = obj->ATOMS["WM_PROTOCOLS"]; - event.data.data32[0] = obj->ATOMS["WM_TAKE_FOCUS"]; - event.data.data32[1] = XCB_TIME_CURRENT_TIME; //CurrentTime; - 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); - xcb_flush(QX11Info::connection());*/ -} - -int NativeWindowSystem::currentWorkspace(){ - xcb_get_property_cookie_t cookie = xcb_ewmh_get_current_desktop_unchecked(&obj->EWMH, QX11Info::appScreen()); - uint32_t num = 0; - if(1==xcb_ewmh_get_current_desktop_reply(&obj->EWMH, cookie, &num, NULL) ){ - return num; - }else{ - return 0; - } -} - -//NativeWindowEventFilter interactions -void NativeWindowSystem::NewWindowDetected(WId id){ - //Make sure this can be managed first - if(findWindow(id, false) != 0){ findWindow(id,false)->setProperty(NativeWindow::Visible, true, true); return; } //already managed - xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(QX11Info::connection(), id); - xcb_get_window_attributes_reply_t *attr = xcb_get_window_attributes_reply(QX11Info::connection(), cookie, NULL); - if(attr == 0){ return; } //could not get attributes of window - if(attr->override_redirect){ free(attr); return; } //window has override redirect set (do not manage) - free(attr); - //Now go ahead and create/populate the container for this window - NativeWindow *win = new NativeWindow(id); - //Register for events from this window - registerClientEvents(win->id()); - NWindows << win; - UpdateWindowProperties(win, NativeWindow::allProperties()); - qDebug() << "New Window [& associated ID's]:" << win->id() << win->property(NativeWindow::Name).toString(); - //Now setup the connections with this window - connect(win, SIGNAL(RequestClose(WId)), this, SLOT(RequestClose(WId)) ); - connect(win, SIGNAL(RequestKill(WId)), this, SLOT(RequestKill(WId)) ); - connect(win, SIGNAL(RequestPing(WId)), this, SLOT(RequestPing(WId)) ); - connect(win, SIGNAL(RequestReparent(WId, WId, QPoint)), this, SLOT(RequestReparent(WId, WId, QPoint)) ); - connect(win, SIGNAL(RequestPropertiesChange(WId, QList<NativeWindow::Property>, QList<QVariant>)), this, SLOT(RequestPropertiesChange(WId, QList<NativeWindow::Property>, QList<QVariant>)) ); - emit NewWindowAvailable(win); -} - -void NativeWindowSystem::NewTrayWindowDetected(WId id){ - //Make sure this can be managed first - if(findTrayWindow(id) != 0){ return; } //already managed - xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(QX11Info::connection(), id); - xcb_get_window_attributes_reply_t *attr = xcb_get_window_attributes_reply(QX11Info::connection(), cookie, NULL); - if(attr == 0){ return; } //could not get attributes of window - if(attr->override_redirect){ free(attr); return; } //window has override redirect set (do not manage) - free(attr); - //Register for events from this window - #define TRAY_WIN_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | \ - XCB_EVENT_MASK_BUTTON_RELEASE | \ - XCB_EVENT_MASK_POINTER_MOTION | \ - XCB_EVENT_MASK_BUTTON_MOTION | \ - XCB_EVENT_MASK_EXPOSURE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_ENTER_WINDOW) - - uint32_t value_list[1] = {TRAY_WIN_EVENT_MASK}; - xcb_change_window_attributes(QX11Info::connection(), id, XCB_CW_EVENT_MASK, value_list); - //Now go ahead and create/populate the container for this window - NativeWindow *win = new NativeWindow(id); - TWindows << win; - UpdateWindowProperties(win, NativeWindow::allProperties()); - emit NewTrayWindowAvailable(win); -} - -void NativeWindowSystem::WindowCloseDetected(WId id){ - NativeWindow *win = findWindow(id, false); - //qDebug() << "Got Window Closed" << id << win; - //qDebug() << "Old Window List:" << NWindows.length(); - if(win!=0){ - NWindows.removeAll(win); - //RequestReparent(id, QX11Info::appRootWindow(), QPoint(0,0)); - win->emit WindowClosed(id); - //qDebug() << "Visible Window Closed!!!"; - //win->deleteLater(); - }else{ - win = findTrayWindow(id); - if(win!=0){ - TWindows.removeAll(win); - win->emit WindowClosed(id); - win->deleteLater(); - } - } - //qDebug() << " - Now:" << NWindows.length(); -} - -void NativeWindowSystem::WindowPropertyChanged(WId id, NativeWindow::Property prop){ - //NOTE: This is triggered by the NativeEventFilter - not by changes to the NativeWindow objects themselves - NativeWindow *win = findWindow(id, prop!=NativeWindow::Visible); - if(win==0){ win = findTrayWindow(id); } - if(win!=0){ - UpdateWindowProperties(win, QList<NativeWindow::Property>() << prop); - }else if(prop != 0){ - //Could not find the window for a specific property with an undefined value - // - update this property for all the windows just in case - for(int i=0; i<NWindows.length(); i++){ - UpdateWindowProperties( NWindows[i], QList<NativeWindow::Property>() << prop); - } - } -} - -void NativeWindowSystem::WindowPropertiesChanged(WId id, QList<NativeWindow::Property> props){ - //NOTE: This is triggered by the NativeEventFilter - not by changes to the NativeWindow objects themselves - NativeWindow *win = findWindow(id); - if(win==0){ win = findTrayWindow(id); } - if(win!=0){ - UpdateWindowProperties(win, props); - }else{ - //Could not find the window for a specific property with an undefined value - // - update this property for all the windows just in case - for(int i=0; i<NWindows.length(); i++){ - UpdateWindowProperties( NWindows[i], props); - } - } -} - -void NativeWindowSystem::WindowPropertyChanged(WId id, NativeWindow::Property prop, QVariant val){ - NativeWindow *win = findWindow(id,prop!=NativeWindow::Visible); - if(win==0){ win = findTrayWindow(id); } - if(win!=0){ - win->setProperty(prop, val); - } -} - -void NativeWindowSystem::WindowPropertiesChanged(WId id, QList<NativeWindow::Property> props, QList<QVariant> vals){ - NativeWindow *win = findWindow(id); - if(win==0){ win = findTrayWindow(id); } - if(win!=0){ - for(int i=0; i<props.length() && i<vals.length(); i++){ win->setProperty(props[i], vals[i]); } - } -} - -void NativeWindowSystem::RequestPropertyChange(WId id, NativeWindow::Property prop, QVariant val){ - //This is just a simplified version of the multiple-property function - RequestPropertiesChange(id, QList<NativeWindow::Property>() << prop, QList<QVariant>() << val); -} - -void NativeWindowSystem::RequestPropertiesChange(WId win, QList<NativeWindow::Property> props, QList<QVariant> vals){ - //Find the window object associated with this id - bool istraywin = false; //just in case we care later if it is a tray window or a regular window - NativeWindow *WIN = findWindow(win); - if(WIN==0){ istraywin = true; WIN = findTrayWindow(win); } - if(WIN==0){ return; } //invalid window ID - no longer available - //Now make any changes as needed - ChangeWindowProperties(WIN, props, vals); -} - -void NativeWindowSystem::GotPong(WId id){ - if(waitingForPong.contains(id)){ - waitingForPong.remove(id); - } - if(waitingForPong.isEmpty() && pingTimer!=0){ pingTimer->stop(); } -} - -void NativeWindowSystem::NewKeyPress(int keycode, WId win){ - emit NewInputEvent(); - if(screenLocked){ return; } - Qt::Key key = KeycodeToQt(keycode); - if(key!=Qt::Key_unknown){ emit KeyPressDetected(win, key); } -} - -void NativeWindowSystem::NewKeyRelease(int keycode, WId win){ - emit NewInputEvent(); - if(screenLocked){ return; } - Qt::Key key = KeycodeToQt(keycode); - if(key!=Qt::Key_unknown){ emit KeyReleaseDetected(win, key); } -} - -void NativeWindowSystem::NewMousePress(int buttoncode, WId win){ - emit NewInputEvent(); - if(screenLocked){ return; } - emit MousePressDetected(win, MouseToQt(buttoncode)); -} - -void NativeWindowSystem::NewMouseRelease(int buttoncode, WId win){ - emit NewInputEvent(); - if(screenLocked){ return; } - emit MouseReleaseDetected(win, MouseToQt(buttoncode)); -} - -void NativeWindowSystem::CheckDamageID(WId win){ - for(int i=0; i<NWindows.length(); i++){ - if(NWindows[i]->damageId() == win || NWindows[i]->id() == win || NWindows[i]->frameId()==win){ - NWindows[i]->emit VisualChanged(); - //qDebug() << "Got DAMAGE Event"; - return; - } - } - NativeWindow *WIN = findTrayWindow(win); - if(WIN!=0){ - UpdateWindowProperties(WIN, QList<NativeWindow::Property>() << NativeWindow::Icon); - } -} - -// === PRIVATE SLOTS === -//These are the slots which are built-in and automatically connected when a new NativeWindow is created - -void NativeWindowSystem::RequestClose(WId win){ - //Send the window a WM_DELETE_WINDOW message - xcb_client_message_event_t event; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.window = win; - event.type = obj->ATOMS.value("WM_PROTOCOLS"); - event.data.data32[0] = obj->ATOMS.value("WM_DELETE_WINDOW"); - event.data.data32[1] = XCB_TIME_CURRENT_TIME; //CurrentTime; - 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); - xcb_flush(QX11Info::connection()); -} - -void NativeWindowSystem::RequestKill(WId win){ - xcb_kill_client(QX11Info::connection(), win); -} - -void NativeWindowSystem::RequestPing(WId win){ - waitingForPong.insert(win, QDateTime::currentDateTime().addSecs(5) ); - xcb_ewmh_send_wm_ping(&obj->EWMH, win, XCB_CURRENT_TIME); - if(pingTimer==0){ - pingTimer = new QTimer(this); - pingTimer->setInterval(2000); //2seconds - connect(pingTimer, SIGNAL(timeout()), this, SLOT(checkPings()) ); - } - pingTimer->start(); -} - -void NativeWindowSystem::RequestReparent(WId win, WId container, QPoint relorigin){ - NativeWindow *WIN = findWindow(win); - if(WIN==0){ return; } //could not find corresponding window structure -//Reparent the window into the container - xcb_reparent_window(QX11Info::connection(), win, container, relorigin.x(), relorigin.y()); - //xcb_map_window(QX11Info::connection(), win); - - //Now send the embed event to the app - //qDebug() << " - send _XEMBED event"; - xcb_client_message_event_t event; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.window = win; - event.type = obj->ATOMS["_XEMBED"]; //_XEMBED - event.data.data32[0] = XCB_TIME_CURRENT_TIME; //CurrentTime; - event.data.data32[1] = 0; //XEMBED_EMBEDDED_NOTIFY - event.data.data32[2] = 0; - event.data.data32[3] = container; //WID of the container - 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); - - //Now setup any redirects and return - //this->SelectInput(win, true); //Notify of structure changes - registerClientEvents(win); - //xcb_composite_redirect_window(QX11Info::connection(), win, XCB_COMPOSITE_REDIRECT_MANUAL); //XCB_COMPOSITE_REDIRECT_[MANUAL/AUTOMATIC]); - - //Now map the window (will be a transparent child of the container) - xcb_map_window(QX11Info::connection(), win); - xcb_map_window(QX11Info::connection(), container); - //Now create/register the damage handler - // -- XCB (Note: The XCB damage registration is completely broken at the moment - 9/15/15, Ken Moore) - // -- Retested 6/29/17 (no change) Ken Moore - //xcb_damage_damage_t dmgID = xcb_generate_id(QX11Info::connection()); //This is a typedef for a 32-bit unsigned integer - //xcb_damage_create(QX11Info::connection(), dmgID, win, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES); - // -- XLib (Note: This is only used because the XCB routine above does not work - needs to be fixed upstream in XCB itself). - Damage dmgID = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles); - WIN->addDamageID( (uint) dmgID); //save this for later - //qDebug() << " - Done"; - //return ( (uint) dmgID ); -} -/* - xcb_reparent_window(QX11Info::connection(), client, parent, relorigin.x(), relorigin.y()); - - //Now ensure that we still get event for these windows - registerClientEvents(client); //make sure we re-do this after reparenting - registerClientEvents(parent); - xcb_map_window(QX11Info::connection(), parent); -}*/ diff --git a/src-qt5/src-cpp/NativeWindowSystem.h b/src-qt5/src-cpp/NativeWindowSystem.h deleted file mode 100644 index b67ecc94..00000000 --- a/src-qt5/src-cpp/NativeWindowSystem.h +++ /dev/null @@ -1,139 +0,0 @@ -//=========================================== -// 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" -#include <QDateTime> -#include <QTimer> -#include <QDebug> - -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, bool checkRelated = true); - - NativeWindow* findTrayWindow(WId id); - - //Now define a simple private_objects class so that each implementation - // has a storage container for defining/placing private objects as needed - class p_objects; - p_objects* obj; - - //Internal timers/variables for managing pings - QTimer *pingTimer; - QHash<WId, QDateTime> waitingForPong; - void checkPings(){ - QDateTime cur = QDateTime::currentDateTime(); - QList<WId> waiting = waitingForPong.keys(); - for(int i=0; i<waiting.length(); i++){ - if(waitingForPong.value(waiting[i]) < cur){ - waitingForPong.remove(waiting[i]); //Timeout on this window - if(waitingForPong.isEmpty() && pingTimer!=0){ pingTimer->stop(); } - NativeWindow *win = findWindow(waiting[i]); - if(win==0){ win = findTrayWindow(waiting[i]); } - if(win!=0){ win->emit WindowNotResponding(waiting[i]); } - } - } - } - - // 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); - void ChangeWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props, QList<QVariant> vals); - - //Generic private variables - bool screenLocked; - -public: - //enum Property{ None, CurrentWorkspace, Workspaces, VirtualRoots, WorkAreas }; - enum MouseButton{NoButton, LeftButton, RightButton, MidButton, BackButton, ForwardButton, TaskButton, WheelUp, WheelDown, WheelLeft, WheelRight}; - - NativeWindowSystem(); - ~NativeWindowSystem(); - - //Overarching start/stop functions - bool start(); - void stop(); - - //General-purpose listing functions - QList<NativeWindow*> currentWindows(){ return NWindows; } - QList<NativeWindow*> currentTrayWindows(){ return TWindows; } - - //Small simplification functions - static Qt::Key KeycodeToQt(int keycode); - static NativeWindowSystem::MouseButton MouseToQt(int button); - -public slots: - //These are the slots which are typically only used by the desktop system itself or the NativeWindowEventFilter - - //This is called by the lock screen to keep the NWS aware of the current status - // it is **NOT** the function to call for the user to actually lock the session (that is in the screensaver/lockscreen class) - void ScreenLockChanged(bool lock){ - screenLocked = lock; - } - - //Root Window property registrations - void RegisterVirtualRoot(WId); - void setRoot_supportedActions(); - void setRoot_numberOfWorkspaces(QStringList names); - void setRoot_currentWorkspace(int); - void setRoot_clientList(QList<WId>, bool stackorder = false); - void setRoot_desktopGeometry(QRect); - void setRoot_desktopWorkarea(QList<QRect>); - void setRoot_activeWindow(WId); - - // - Workspaces - int currentWorkspace(); - //void GoToWorkspace(int); - - - //NativeWindowEventFilter interactions - void NewWindowDetected(WId); //will automatically create the new NativeWindow object - void NewTrayWindowDetected(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 WindowPropertiesChanged(WId, QList<NativeWindow::Property>); - void WindowPropertyChanged(WId, NativeWindow::Property, QVariant); //will save that property/value to the right object - void WindowPropertiesChanged(WId, QList<NativeWindow::Property>, QList<QVariant>); - void RequestPropertyChange(WId, NativeWindow::Property, QVariant); - void RequestPropertiesChange(WId, QList<NativeWindow::Property>, QList<QVariant>); - void GotPong(WId); - - void NewKeyPress(int keycode, WId win = 0); - void NewKeyRelease(int keycode, WId win = 0); - void NewMousePress(int buttoncode, WId win = 0); - void NewMouseRelease(int buttoncode, WId win = 0); - void CheckDamageID(WId); - -private slots: - //These are the slots which are built-in and automatically connected when a new NativeWindow is created - void RequestClose(WId); - void RequestKill(WId); - void RequestPing(WId); - void RequestReparent(WId, WId, QPoint); //client, parent, relative origin point in parent - -signals: - void NewWindowAvailable(NativeWindow*); - void NewTrayWindowAvailable(NativeWindow*); - void NewInputEvent(); //a mouse or keypress was detected (lock-state independent); - void KeyPressDetected(WId, Qt::Key); //only emitted if lockstate = false - void KeyReleaseDetected(WId, Qt::Key); //only emitted if lockstate = false - void MousePressDetected(WId, NativeWindowSystem::MouseButton); //only emitted if lockstate = false - void MouseReleaseDetected(WId, NativeWindowSystem::MouseButton); //only emitted if lockstate = false - -}; - -#endif diff --git a/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp b/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp new file mode 100644 index 00000000..247b1bdb --- /dev/null +++ b/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp @@ -0,0 +1,245 @@ +//=========================================== +// Lumina desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// FreeBSD/TrueOS specific OS Interactions +//=========================================== +// USEFUL INTERNAL FUNCTIONS: +//---------------------------------------------- +// bool verifyAppOrBin(QString chk) +//=========================================== +#include <framework-OSInterface.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/unistd.h> + +// = Battery = +bool OSInterface::OS_batteryAvailable(){ + static int bat_avail = -1; //this will not change during a single session - keep later calls fast + if(bat_avail < 0){ + int val = getCmdOutput("apm -l").join("").toInt(); + bat_avail = ((val >= 0 && val <= 100) ? 1 : 0 ); + } + return (bat_avail==1); +} + +float OSInterface::OS_batteryCharge(){ + int charge = getCmdOutput("apm -l").join("").toInt(); + if(charge > 100){ charge = -1; } //invalid charge + return charge; +} + +bool OSInterface::OS_batteryCharging(){ + return (getCmdOutput("apm -a").join("").simplified() == "1"); +} + +double OSInterface::OS_batterySecondsLeft(){ //Returns: estimated number of seconds remaining + return getCmdOutput("apm -t").join("").toDouble(); +} + +// = Volume = +bool OSInterface::OS_volumeSupported(){ return true; } +int OSInterface::OS_volume(){ + int out = -1; + /*bool remoteSession = !QString(getenv("PICO_CLIENT_LOGIN")).isEmpty(); + if(remoteSession){ + QStringList info = getCmdOutput("pactl list short sinks"); + qDebug() << "Got PA sinks:" << info; + out = 50; //TEMPORARY - still need to write up the info parsing + }else{*/ + //probe the system for the current volume (other utils could be changing it) + QString info = getCmdOutput("mixer -S vol").join(":").simplified(); //ignores any other lines + if(!info.isEmpty()){ + int L = info.section(":",1,1).toInt(); + int R = info.section(":",2,2).toInt(); + if(L>R){ out = L; } + else{ out = R; } + } + //} //end of Remote Session check + return out; +} + +bool OSInterface::OS_setVolume(int percent){ + if(percent<0){percent=0;} + else if(percent>100){percent=100;} + /*bool remoteSession = !QString(getenv("PICO_CLIENT_LOGIN")).isEmpty(); + if(remoteSession){ + runCmd(QString("pactl set-sink-volume @DEFAULT_SINK@ ")+QString::number(percent)+"%"); + }else{*/ + QString info = getCmdOutput("mixer -S vol").join(":").simplified(); //ignores any other lines + if(!info.isEmpty()){ + int L = info.section(":",1,1).toInt(); + int R = info.section(":",2,2).toInt(); + int diff = L-R; + if((percent == L) && (L==R)){ return false; } //already set to that volume + if(diff<0){ R=percent; L=percent+diff; } //R Greater + else{ L=percent; R=percent-diff; } //L Greater or equal + //Check bounds + if(L<0){L=0;}else if(L>100){L=100;} + if(R<0){R=0;}else if(R>100){R=100;} + //Run Command + return (0==runCmd("mixer vol "+QString::number(L)+":"+QString::number(R)) ); + } + //} //end of Remote Session check + return false; +} + +// = Network Information = +QString OSInterface::OS_networkTypeFromDeviceName(QString name){ + //Return options: wifi, wired, cell, cell-2G, cell-3G, cell-4G + QString type = "wired"; + if(name.startsWith("wlan")){ type = "wifi"; } + //Not sure about cell connections . Probably still treated as wifi devices (wlan*) + return type; +} + +float OSInterface::OS_networkStrengthFromDeviceName(QString name){ + //NOTE: This will only run for non-wired devices (wifi, cell[-*]) + // Step 1 : Figure out which access point is currently connected + QStringList info = getCmdOutput("ifconfig", QStringList() << name).filter("bssid"); + if(info.isEmpty()){ return -1; } + QString bssid = info.first().section("bssid ",1,-1).section(" ",0,0); + // Step 2: Scan access point to get signal/noise + info = getCmdOutput("ifconfig", QStringList() << name << "list" << "scan").filter(bssid); + if(info.isEmpty()){ return -1; } + QString signoise =info.first().section(" ", 4,4, QString::SectionSkipEmpty).simplified(); + int sig = signoise.section(":",0,0).toInt(); + int noise = signoise.section(":",1,1).toInt(); + // Step 3: Turn signal/noise ratio into a percentage + int perc = qAbs(sig - noise) * 4; + return perc; //percentage +} + +// = Media Shortcuts = +QStringList OSInterface::OS_mediaDirectories(){ return QStringList() << "/media"; } //directory where XDG shortcuts are placed for interacting with media (local/remote) + +// = Updates = +bool OSInterface::OS_updatesSupported(){ return verifyAppOrBin("pc-updatemanager"); } + +bool OSInterface::OS_updatesAvailable(){ return QFile::exists("/tmp/.trueos-update-staged"); } +QString OSInterface::OS_updateDetails(){ return readFile("/tmp/.trueos-update-staged"); } //Information about any available updates + +bool OSInterface::OS_updatesRunning(){ return (runCmd("pgrep -F /tmp/.updateInProgress")==0); } +QString OSInterface::OS_updateLog(){ return QString(); } //Information about any currently-running update + +//Note: Because the second-stage updates on TrueOS actually happen on reboot, we never see a "finished" update +bool OSInterface::OS_updatesFinished(){ return false; } +QString OSInterface::OS_updateResults(){ return QString(); } //Information about any finished update + +void OSInterface::OS_startUpdates(){ runCmd("pc-updatemanager", QStringList() << "startupdate"); } //start stage 2 on reboot +bool OSInterface::OS_updateOnlyOnReboot(){ return true; } //Should the startUpdates function be called only when rebooting the system? +bool OSInterface::OS_updateCausesReboot(){ return true; } + +QDateTime OSInterface::OS_lastUpdate(){ return QDateTime(); } //The date/time of the previous updates +QString OSInterface::OS_lastUpdateResults(){ return QString(); } //Information about the previously-finished update + +// = System Power = +bool OSInterface::OS_canReboot(){ + int ret = eaccess("/sbin/shutdown", X_OK); + return (ret==0); +} +void OSInterface::OS_startReboot(){ runCmd("/sbin/shutdown", QStringList() << "-ro" << "now"); } + +bool OSInterface::OS_canShutdown(){ + int ret = eaccess("/sbin/shutdown", X_OK); + return (ret==0); +} +void OSInterface::OS_startShutdown(){ runCmd("/sbin/shutdown", QStringList() << "-po" << "now"); } + +bool OSInterface::OS_canSuspend(){ + int ret = eaccess("/usr/sbin/acpiconf", X_OK); + return (ret==0); +} +void OSInterface::OS_startSuspend(){ runCmd("zzz"); } //zzz runs "acpiconf -s <suspend state>" + +// = Screen Brightness = +bool OSInterface::OS_brightnessSupported(){ +//First run a quick check to ensure this is not a VirtualBox VM (no brightness control) + static int goodsys = -1; //This will not change over time - only check/set once + if(goodsys<0){ + //Make sure we are not running in VirtualBox (does not work in a VM) + QStringList info = getCmdOutput("pciconf -lv"); + if( info.filter("VirtualBox", Qt::CaseInsensitive).isEmpty() ){ goodsys = 1; } + else{ goodsys = 0; } //not a good system + } + if(goodsys!=1){ return false; } //go ahead and stop here - not a good system + QStringList tools; tools << "intel_backlight" << "xbrightness"; + bool ok = false; + for(int i=0; i<tools.length() && !ok; i++){ ok = verifyAppOrBin(tools[i]); } + return ok; +} + +int OSInterface::OS_brightness(){ + //return percentage: 0-100 with -1 for errors + QStringList tools; tools << "intel_backlight" << "xbrightness"; + //NOTE: xbacklight does not have a way to return the current brightness + int num = -1; + for(int i=0; i<tools.length() && num<0; i++){ + if(!verifyAppOrBin(tools[i])){ continue; } + switch(i){ + case 0: //intel_backlight + num = getCmdOutput("intel_backlight").join("").section("%",0,0).section(":",1,1).simplified().toInt(); + break; + default: + num = -1; + } + } + if(num>100){ num=100; } //quick verification of upper limit + else if(num<-1){ num = -1; } //something really messed up - return the error code + return num; +} + +bool OSInterface::OS_setBrightness(int percent){ + QStringList tools; tools << "intel_backlight" << "xbrightness"; + for(int i=0; i<tools.length(); i++){ + if(!verifyAppOrBin(tools[i])){ continue; } + QStringList args; + switch(i){ + case 0: //intel_backlight + args << QString::number(percent); + break; + case 1: //xbrightness + args << QString::number( qRound( (percent/100.0)*65535) ); //xbrightness has a scale of 0-65535 + break; + } + return (0 == runCmd(tools[i], args) ); + } + return false; +} + +// = System Status Monitoring +bool OSInterface::OS_cpuSupported(){ return false; } +QList<int> OSInterface::OS_cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors +QStringList OSInterface::OS_cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example) + +bool OSInterface::OS_memorySupported(){ return false; } +int OSInterface::OS_memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors +QString OSInterface::OS_memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session +QStringList OSInterface::OS_diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device + +bool OSInterface::OS_diskSupported(){ return false; } +int OSInterface::OS_fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors +QString OSInterface::OS_fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity + +// = OS-Specific Utilities = +QString OSInterface::controlPanelShortcut(){ return "pccontrol.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop") +QString OSInterface::audioMixerShortcut(){ return "pc-mixer -notray"; } //relative *.desktop shortcut name (Example: "some_utility.desktop") +QString OSInterface::appStoreShortcut(){ return "appcafe.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop") +QString OSInterface::networkManagerUtility(){ return "pc-netmanager.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop") + +//FileSystemWatcher slots (optional - re-implement only if needed/used by this OS) +void OSInterface::watcherFileChanged(QString){} //any additional parsing for files that are watched +void OSInterface::watcherDirChanged(QString dir){ //any additional parsing for watched directories + if(handleMediaDirChange(dir)){ return; } //auto-handled media directories +} + +//IO Device slots (optional - implement only if needed/used by this OS) +void OSInterface::iodeviceReadyRead(){} +void OSInterface::iodeviceAboutToClose(){} + +void OSInterface::netRequestFinished(QNetworkReply*){} +void OSInterface::netSslErrors(QNetworkReply*, const QList<QSslError>&){} diff --git a/src-qt5/src-cpp/framework-OSInterface-template.cpp b/src-qt5/src-cpp/framework-OSInterface-template.cpp index 972e02e0..c9c7775a 100644 --- a/src-qt5/src-cpp/framework-OSInterface-template.cpp +++ b/src-qt5/src-cpp/framework-OSInterface-template.cpp @@ -4,147 +4,95 @@ // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== +// USEFUL INTERNAL FUNCTIONS: (See framework-OSInterface.h for all possibilities); +//---------------------------------------------- +// bool verifyAppOrBin(QString chk) : Returns true is the check is a valid binary or application (*.desktop) +// int runCmd(QString command, QStringList arguments) : return code of command is returned +// QStringList getCmdOutput(QString command, QStringList arguments) : returns standard output of command +//=========================================== #include <framework-OSInterface.h> -#include <QNetworkConfiguration> -#include <QNetworkInterface> - -//Start/stop interface watchers/notifications -void OSInterface::start(){ - setupMediaWatcher(); //will create/connect the filesystem watcher automatically - setupNetworkManager(); -} - -void OSInterface::stop(){ - if(isRunning()){ - watcher->deleteLater(); - watcher = 0; - } -} - -bool OSInterface::isRunning(){ return (watcher!=0); } //status of the object - whether it has been started yet // = Battery = -bool OSInterface::batteryAvailable(){ return false; } -float OSInterface::batteryCharge(){ return -1; } -bool OSInterface::batteryCharging(){ return false; } -double OSInterface::batterySecondsLeft(){ return -1; } +bool OSInterface::OS_batteryAvailable(){ return false; } +float OSInterface::OS_batteryCharge(){ return -1; } +bool OSInterface::OS_batteryCharging(){ return false; } +double OSInterface::OS_batterySecondsLeft(){ return -1; } // = Volume = -bool OSInterface::volumeAvailable(){ return false; } -int OSInterface::volume(){ return -1; } -void OSInterface::setVolume(int){} +bool OSInterface::OS_volumeSupported(){ return false; } +int OSInterface::OS_volume(){ return -1; } +bool OSInterface::OS_setVolume(int){ return false;} // = Network Information = -bool OSInterface::networkAvailable(){ - if(INFO.contains("netaccess/available")){ return INFO.value("netaccess/available").toBool(); } - return false; -} - -QString OSInterface::networkType(){ - if(INFO.contains("netaccess/type")){ return INFO.value("netaccess/type").toString(); } //"wifi", "wired", or "cell" +QString OSInterface::OS_networkTypeFromDeviceName(QString name){ + //Return options: wifi, wired, cell, cell-2G, cell-3G, cell-4G return ""; } -float OSInterface::networkStrength(){ return -1; } //percentage. ("wired" type should always be 100%) - -QString OSInterface::networkHostname(){ - return QHostInfo::localHostName(); -} - -QHostAddress OSInterface::networkAddress(){ - QString addr; - if(INFO.contains("netaccess/address")){ addr = INFO.value("netaccess/address").toString(); } - return QHostAddress(addr); +float OSInterface::OS_networkStrengthFromDeviceName(QString name){ + //NOTE: This will only run for non-wired devices (wifi, cell[-*]) + return -1; //percentage } -// = Network Modification = // = Media Shortcuts = -QStringList OSInterface::mediaDirectories(){ return QStringList() << "/media"; } //directory where XDG shortcuts are placed for interacting with media (local/remote) -QStringList OSInterface::mediaShortcuts(){ return autoHandledMediaFiles(); } //List of currently-available XDG shortcut file paths +QStringList OSInterface::OS_mediaDirectories(){ return QStringList() << "/media"; } //directory where XDG shortcuts are placed for interacting with media (local/remote) // = Updates = -bool OSInterface::updatesAvailable(){ return false; } -QString OSInterface::updateDetails(){ return QString(); } //Information about any available updates -bool OSInterface::updatesRunning(){ return false; } -QString OSInterface::updateLog(){ return QString(); } //Information about any currently-running update -bool OSInterface::updatesFinished(){ return false; } -QString OSInterface::updateResults(){ return QString(); } //Information about any finished update -void OSInterface::startUpdates(){} -bool OSInterface::updateOnlyOnReboot(){ return false; } //Should the startUpdates function be called only when rebooting the system? -QDateTime OSInterface::lastUpdate(){ return QDateTime(); } //The date/time of the previous updates -QString OSInterface::lastUpdateResults(){ return QString(); } //Information about the previously-finished update +bool OSInterface::OS_updatesSupported(){ return false; } +bool OSInterface::OS_updatesAvailable(){ return false; } +QString OSInterface::OS_updateDetails(){ return QString(); } //Information about any available updates +bool OSInterface::OS_updatesRunning(){ return false; } +QString OSInterface::OS_updateLog(){ return QString(); } //Information about any currently-running update +bool OSInterface::OS_updatesFinished(){ return false; } +QString OSInterface::OS_updateResults(){ return QString(); } //Information about any finished update +void OSInterface::OS_startUpdates(){} +bool OSInterface::OS_updateOnlyOnReboot(){ return false; } //Should the startUpdates function be called only when rebooting the system? +bool OSInterface::OS_updateCausesReboot(){ return false; } +QDateTime OSInterface::OS_lastUpdate(){ return QDateTime(); } //The date/time of the previous updates +QString OSInterface::OS_lastUpdateResults(){ return QString(); } //Information about the previously-finished update // = System Power = -bool OSInterface::canReboot(){ return false; } -void OSInterface::startReboot(){} -bool OSInterface::canShutdown(){ return false; } -void OSInterface::startShutdown(){} -bool OSInterface::canSuspend(){ return false; } -void OSInterface::startSuspend(){} +bool OSInterface::OS_canReboot(){ return false; } +void OSInterface::OS_startReboot(){} +bool OSInterface::OS_canShutdown(){ return false; } +void OSInterface::OS_startShutdown(){} +bool OSInterface::OS_canSuspend(){ return false; } +void OSInterface::OS_startSuspend(){} // = Screen Brightness = -int OSInterface::brightness(){ return -1; } //percentage: 0-100 with -1 for errors -void OSInterface::setBrightness(int){} +bool OSInterface::OS_brightnessSupported(){ return false; } +int OSInterface::OS_brightness(){ return -1; } //percentage: 0-100 with -1 for errors +bool OSInterface::OS_setBrightness(int){ return false; } // = System Status Monitoring -QList<int> OSInterface::cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors -QStringList OSInterface::cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example) -int OSInterface::memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors -QString OSInterface::memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session -QStringList OSInterface::diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device -int OSInterface::fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors -QString OSInterface::fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity +bool OSInterface::OS_cpuSupported(){ return false; } +QList<int> OSInterface::OS_cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors +QStringList OSInterface::OS_cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example) + +bool OSInterface::OS_memorySupported(){ return false; } +int OSInterface::OS_memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors +QString OSInterface::OS_memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session +QStringList OSInterface::OS_diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device + +bool OSInterface::OS_diskSupported(){ return false; } +int OSInterface::OS_fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors +QString OSInterface::OS_fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity // = OS-Specific Utilities = -bool OSInterface::hasControlPanel(){ return false; } QString OSInterface::controlPanelShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") -bool OSInterface::hasAudioMixer(){ return false; } QString OSInterface::audioMixerShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") -bool OSInterface::hasAppStore(){ return false; } QString OSInterface::appStoreShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") +QString OSInterface::networkManagerUtility(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") -//FileSystemWatcher slots -void OSInterface::watcherFileChanged(QString){} -void OSInterface::watcherDirChanged(QString dir){ - if(handleMediaDirChange(dir)){ return; } +//FileSystemWatcher slots (optional - re-implement only if needed/used by this OS) +void OSInterface::watcherFileChanged(QString){} //any additional parsing for files that are watched +void OSInterface::watcherDirChanged(QString dir){ //any additional parsing for watched directories + if(handleMediaDirChange(dir)){ return; } //auto-handled media directories } -//IO Device slots +//IO Device slots (optional - implement only if needed/used by this OS) void OSInterface::iodeviceReadyRead(){} void OSInterface::iodeviceAboutToClose(){} -//NetworkAccessManager slots -void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility stat){ - INFO.insert("netaccess/available", stat== QNetworkAccessManager::Accessible); - //Update all the other network status info at the same time - QNetworkConfiguration active = netman->activeConfiguration(); - //Type of connection - QString type; - switch(active.bearerTypeFamily()){ - case QNetworkConfiguration::BearerEthernet: type="wired"; break; - case QNetworkConfiguration::BearerWLAN: type="wifi"; break; - case QNetworkConfiguration::Bearer2G: type="cell-2G"; break; - case QNetworkConfiguration::Bearer3G: type="cell-3G"; break; - case QNetworkConfiguration::Bearer4G: type="cell-4G"; break; - default: type=""; - } - INFO.insert("netaccess/type", type); - qDebug() << "Detected Device Status:" << active.identifier() << type << stat; - QNetworkInterface iface = QNetworkInterface::interfaceFromName(active.name()); - qDebug() << " - Configuration: Name:" << active.name() << active.bearerTypeName() << active.identifier(); - qDebug() << " - Interface: MAC Address:" << iface.hardwareAddress() << "Name:" << iface.name() << iface.humanReadableName() << iface.isValid(); - QList<QNetworkAddressEntry> addressList = iface.addressEntries(); - QStringList address; - //NOTE: There are often 2 addresses, IPv4 and IPv6 - for(int i=0; i<addressList.length(); i++){ - address << addressList[i].ip().toString(); - } - qDebug() << " - IP Address:" << address; - qDebug() << " - Hostname:" << networkHostname(); - INFO.insert("netaccess/address", address.join(", ")); - emit networkStatusChanged(); -} - void OSInterface::netRequestFinished(QNetworkReply*){} void OSInterface::netSslErrors(QNetworkReply*, const QList<QSslError>&){} -void OSInterface::timerUpdate(){} diff --git a/src-qt5/src-cpp/framework-OSInterface.h b/src-qt5/src-cpp/framework-OSInterface.h index a173ad5a..7f51764b 100644 --- a/src-qt5/src-cpp/framework-OSInterface.h +++ b/src-qt5/src-cpp/framework-OSInterface.h @@ -18,6 +18,9 @@ #include <QVariant> #include <QHash> #include <QTimer> +#include <QFile> +#include <QDir> +#include <QVariant> #include <QIODevice> #include <QFileSystemWatcher> @@ -26,28 +29,39 @@ #include <QSslError> #include <QHostInfo> #include <QHostAddress> +#include <QNetworkConfiguration> +#include <QNetworkInterface> + +//Lumina Utils class +//#include <LUtils.h> class OSInterface : public QObject{ Q_OBJECT // == QML ACCESSIBLE PROPERTIES == //Battery - Q_PROPERTY( float batteryCharge READ batteryCharge NOTIFY batteryChargeChanged) - Q_PROPERTY( bool batteryCharging READ batteryCharging NOTIFY batteryChargingChanged) - Q_PROPERTY( double batterySecondsLeft READ batterySecondsLeft NOTIFY batterySecondsLeftChanged) + Q_PROPERTY( float batteryCharge READ batteryCharge NOTIFY batteryChanged) + Q_PROPERTY( bool batteryCharging READ batteryCharging NOTIFY batteryChanged) + Q_PROPERTY( QString batteryRemaining READ batteryRemaining NOTIFY batteryChanged) + Q_PROPERTY( QString batteryIcon READ batteryIcon NOTIFY batteryChanged) + Q_PROPERTY( QString batteryStatus READ batteryStatus NOTIFY batteryChanged) //Volume Q_PROPERTY( int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY( QString volumeIcon READ volumeIcon NOTIFY volumeChanged) //Network Q_PROPERTY( bool networkAvailable READ networkAvailable NOTIFY networkStatusChanged) Q_PROPERTY( QString networkType READ networkType NOTIFY networkStatusChanged) Q_PROPERTY( float networkStrength READ networkStrength NOTIFY networkStatusChanged) Q_PROPERTY( QString networkHostname READ networkHostname NOTIFY networkStatusChanged) - Q_PROPERTY( QHostAddress networkAddress READ networkAddress NOTIFY networkStatusChanged) + Q_PROPERTY( QStringList networkAddress READ networkAddress NOTIFY networkStatusChanged) + Q_PROPERTY( QString networkIcon READ networkIcon NOTIFY networkStatusChanged); + Q_PROPERTY( QString networkStatus READ networkStatus NOTIFY networkStatusChanged); //Media Q_PROPERTY( QStringList mediaShortcuts READ mediaShortcuts NOTIFY mediaShortcutsChanged) //Updates - Q_PROPERTY( bool updatesAvailable READ updatesAvailable NOTIFY updateStatusChanged) - Q_PROPERTY( bool updatesRunning READ updatesRunning NOTIFY updateStatusChanged) - Q_PROPERTY( bool updatesFinished READ updatesFinished NOTIFY updateStatusChanged) + Q_PROPERTY( QString updateStatus READ updateStatus NOTIFY updateStatusChanged) + Q_PROPERTY( QString updateIcon READ updateIcon NOTIFY updateStatusChanged) + Q_PROPERTY( bool updateInfoAvailable READ updateInfoAvailable NOTIFY updateStatusChanged) + //Power options Q_PROPERTY( bool canReboot READ canReboot NOTIFY powerAvailableChanged) Q_PROPERTY( bool canShutdown READ canShutdown NOTIFY powerAvailableChanged) @@ -68,33 +82,48 @@ public: Q_INVOKABLE bool batteryAvailable(); Q_INVOKABLE float batteryCharge(); Q_INVOKABLE bool batteryCharging(); - Q_INVOKABLE double batterySecondsLeft(); + Q_INVOKABLE QString batteryRemaining(); + Q_INVOKABLE QString batteryIcon(); + Q_INVOKABLE QString batteryStatus(); + // = Volume = - Q_INVOKABLE bool volumeAvailable(); + Q_INVOKABLE bool volumeSupported(); Q_INVOKABLE int volume(); Q_INVOKABLE void setVolume(int); + Q_INVOKABLE QString volumeIcon(); + // = Network Information = Q_INVOKABLE bool networkAvailable(); Q_INVOKABLE QString networkType(); //"wifi", "wired", "cell", "cell-2G", "cell-3G", "cell-4G" Q_INVOKABLE float networkStrength(); //percentage. ("wired" type should always be 100%) + Q_INVOKABLE QString networkIcon(); Q_INVOKABLE QString networkHostname(); - Q_INVOKABLE QHostAddress networkAddress(); + Q_INVOKABLE QStringList networkAddress(); + Q_INVOKABLE QString networkStatus(); //combines a bunch of the above info into a single string + // = Network Modification = + Q_INVOKABLE bool hasNetworkManager(); + Q_INVOKABLE QString networkManagerUtility(); //binary name or *.desktop filename (if registered on the system) // = Media Shortcuts = Q_INVOKABLE QStringList mediaDirectories(); //directory where XDG shortcuts are placed for interacting with media (local/remote) Q_INVOKABLE QStringList mediaShortcuts(); //List of currently-available XDG shortcut file paths + // = Updates = - Q_INVOKABLE bool updatesAvailable(); + Q_INVOKABLE bool updatesSupported(); //is thie subsystem supported for the OS? + Q_INVOKABLE QString updateStatus(); //Current status ["","available","running","finished"] + Q_INVOKABLE bool updateInfoAvailable(); + Q_INVOKABLE QString updateIcon(); + Q_INVOKABLE QString updateStatusInfo(); //Extra information corresponding to the current status Q_INVOKABLE QString updateDetails(); //Information about any available updates - Q_INVOKABLE bool updatesRunning(); Q_INVOKABLE QString updateLog(); //Information about any currently-running update - Q_INVOKABLE bool updatesFinished(); Q_INVOKABLE QString updateResults(); //Information about any finished update Q_INVOKABLE void startUpdates(); Q_INVOKABLE bool updateOnlyOnReboot(); //Should the startUpdates function be called only when rebooting the system? + Q_INVOKABLE bool updateCausesReboot(); //Does the update power-cycle the system? Q_INVOKABLE QDateTime lastUpdate(); //The date/time of the previous updates Q_INVOKABLE QString lastUpdateResults(); //Information about the previously-finished update + // = System Power = Q_INVOKABLE bool canReboot(); Q_INVOKABLE void startReboot(); @@ -102,17 +131,26 @@ public: Q_INVOKABLE void startShutdown(); Q_INVOKABLE bool canSuspend(); Q_INVOKABLE void startSuspend(); + // = Screen Brightness = + Q_INVOKABLE bool brightnessSupported(); //is this subsystem available for the OS? Q_INVOKABLE int brightness(); //percentage: 0-100 with -1 for errors Q_INVOKABLE void setBrightness(int); + // = System Status Monitoring + Q_INVOKABLE bool cpuSupported(); //is this subsystem available for the OS? Q_INVOKABLE QList<int> cpuPercentage(); // (one per CPU) percentage: 0-100 with -1 for errors Q_INVOKABLE QStringList cpuTemperatures(); // (one per CPU) Temperature of CPU ("50C" for example) + + Q_INVOKABLE bool memorySupported(); //is this subsystem available for the OS? Q_INVOKABLE int memoryUsedPercentage(); //percentage: 0-100 with -1 for errors Q_INVOKABLE QString memoryTotal(); //human-readable form - does not tend to change within a session Q_INVOKABLE QStringList diskIO(); //Returns list of current read/write stats for each device + + Q_INVOKABLE bool diskSupported(); //is this subsystem available for the OS? Q_INVOKABLE int fileSystemPercentage(QString dir); //percentage of capacity used: 0-100 with -1 for errors Q_INVOKABLE QString fileSystemCapacity(QString dir); //human-readable form - total capacity + // = OS-Specific Utilities = Q_INVOKABLE bool hasControlPanel(); Q_INVOKABLE QString controlPanelShortcut(); //relative *.desktop shortcut name (Example: "some_utility.desktop") @@ -121,10 +159,63 @@ public: Q_INVOKABLE bool hasAppStore(); Q_INVOKABLE QString appStoreShortcut(); //relative *.desktop shortcut name (Example: "some_utility.desktop") + + // = DIRECT OS INTERACTIONS = (properties above are cached/gated) + // = Battery = + bool OS_batteryAvailable(); + float OS_batteryCharge(); + bool OS_batteryCharging(); + double OS_batterySecondsLeft(); + // = Volume = + bool OS_volumeSupported(); + int OS_volume(); + bool OS_setVolume(int); + // = Network Information = + QString OS_networkTypeFromDeviceName(QString name); + float OS_networkStrengthFromDeviceName(QString name); + // = Media Shortcuts = + QStringList OS_mediaDirectories(); + // = Updates = + bool OS_updatesSupported(); + bool OS_updatesAvailable(); + QString OS_updateDetails(); + bool OS_updatesRunning(); + QString OS_updateLog(); + bool OS_updatesFinished(); + QString OS_updateResults(); + void OS_startUpdates(); + bool OS_updateOnlyOnReboot(); + bool OS_updateCausesReboot(); + QDateTime OS_lastUpdate(); + QString OS_lastUpdateResults(); + // = System Power = + bool OS_canReboot(); + void OS_startReboot(); + bool OS_canShutdown(); + void OS_startShutdown(); + bool OS_canSuspend(); + void OS_startSuspend(); + // = Screen Brightness = + bool OS_brightnessSupported(); + int OS_brightness(); + bool OS_setBrightness(int); + // = System Status Monitoring + bool OS_cpuSupported(); + QList<int> OS_cpuPercentage(); + QStringList OS_cpuTemperatures(); + bool OS_memorySupported(); + int OS_memoryUsedPercentage(); + QString OS_memoryTotal(); + QStringList OS_diskIO(); + bool OS_diskSupported(); + int OS_fileSystemPercentage(QString dir); + QString OS_fileSystemCapacity(QString dir); + private slots: // ================ // SEMI-VIRTUAL FUNCTIONS - NEED TO BE DEFINED IN THE OS-SPECIFIC FILES // ================ + //FileSystemWatcher slots void watcherFileChanged(QString); void watcherDirChanged(QString); @@ -132,16 +223,20 @@ private slots: void iodeviceReadyRead(); void iodeviceAboutToClose(); //NetworkAccessManager slots - void netAccessChanged(QNetworkAccessManager::NetworkAccessibility); void netRequestFinished(QNetworkReply*); void netSslErrors(QNetworkReply*, const QList<QSslError>&); //Timer slots - void timerUpdate(); + void NetworkTimerUpdate(); + void BatteryTimerUpdate(); + void UpdateTimerUpdate(); + void BrightnessTimerUpdate(); + void VolumeTimerUpdate(); + void CpuTimerUpdate(); + void MemTimerUpdate(); + void DiskTimerUpdate(); signals: - void batteryChargeChanged(); - void batteryChargingChanged(); - void batterySecondsLeftChanged(); + void batteryChanged(); void volumeChanged(); void networkStatusChanged(); void mediaShortcutsChanged(); @@ -149,9 +244,14 @@ signals: void powerAvailableChanged(); void brightnessChanged(); + //Internal alert signals + void BatteryFullAlert(); + void BatteryEmptyAlert(); + private: //Internal persistant data storage, OS-specific usage implementation QHash< QString, QVariant> INFO; + bool _started; // ============ // Internal possibilities for watching the system (OS-Specific usage/implementation) @@ -163,28 +263,52 @@ private: //Network Access Manager (check network connectivity, etc) QNetworkAccessManager *netman; //Timer for regular probes/updates - QTimer *timer; + QTimer *networkTimer, *batteryTimer, *updateTimer, *brightnessTimer, *volumeTimer, *cpuTimer, *memTimer, *diskTimer; // Internal implifications for connecting the various watcher objects to their respective slots // (OS-agnostic - defined in the "OSInterface_private.cpp" file) void connectWatcher(); //setup the internal connections *only* void connectIodevice(); //setup the internal connections *only* void connectNetman(); //setup the internal connections *only* - void connectTimer(); //setup the internal connections *only* + + //Internal simplification routines + bool verifyAppOrBin(QString chk); + QString runProcess(int &retcode, QString command, QStringList arguments, QString workdir = "", QStringList env = QStringList()); + int runCmd(QString command, QStringList args = QStringList()); + QStringList getCmdOutput(QString command, QStringList args = QStringList()); + bool findInDirectory(QString file, QString dirpath, bool recursive=true); + QString readFile(QString path); // External Media Management (if system uses *.desktop shortcuts only) void setupMediaWatcher(); bool handleMediaDirChange(QString dir); //returns true if directory was handled QStringList autoHandledMediaFiles(); - // Qt-based NetworkAccessManager usage - void setupNetworkManager(); + // Timer-based setups + void setupNetworkManager(int update_ms, int delay_ms); + void setupBatteryMonitor(int update_ms, int delay_ms); + void setupUpdateMonitor(int update_ms, int delay_ms); + void setupBrightnessMonitor(int update_ms, int delay_ms); + void setupVolumeMonitor(int update_ms, int delay_ms); + void setupCpuMonitor(int update_ms, int delay_ms); + void setupMemoryMonitor(int update_ms, int delay_ms); + void setupDiskMonitor(int update_ms, int delay_ms); + + // Timer-based monitor update routines (NOTE: these are all run in a separate thread!!) + void syncNetworkInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncBatteryInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncUpdateInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncBrightnessInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncVolumeInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncCpuInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncMemoryInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); + void syncDiskInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer); public: OSInterface(QObject *parent = 0); ~OSInterface(); static OSInterface* instance(); //Get the currently-active instance of this class (or make a new one) - + static void RegisterType(); //Register this object for QML access }; #endif diff --git a/src-qt5/src-cpp/framework-OSInterface.pri b/src-qt5/src-cpp/framework-OSInterface.pri index be705e44..3a456382 100644 --- a/src-qt5/src-cpp/framework-OSInterface.pri +++ b/src-qt5/src-cpp/framework-OSInterface.pri @@ -1,9 +1,18 @@ -QT *= core network +QT *= core network quick concurrent + +#include(../core/libLumina/LUtils.pri) +#include(../core/libLumina/LuminaXDG.pri) HEADERS *= $${PWD}/framework-OSInterface.h SOURCES *= $${PWD}/framework-OSInterface_private.cpp -_os=template -SOURCES *= $${PWD}/framework-OSInterface-$${_os}.cpp +#Load the proper OS *.cpp file +exists($${PWD}/framework-OSInterface-$${LINUX_DISTRO}.cpp){ + SOURCES *= $${PWD}/framework-OSInterface-$${LINUX_DISTRO}.cpp +}else:exists($${PWD}/framework-OSInterface-$${OS}.cpp){ + SOURCES *= $${PWD}/framework-OSInterface-$${OS}.cpp +}else{ + SOURCES *= $${PWD}/framework-OSInterface-template.cpp +} INCLUDEPATH *= $${PWD} diff --git a/src-qt5/src-cpp/framework-OSInterface_private.cpp b/src-qt5/src-cpp/framework-OSInterface_private.cpp index d15d9be8..15ee6f8e 100644 --- a/src-qt5/src-cpp/framework-OSInterface_private.cpp +++ b/src-qt5/src-cpp/framework-OSInterface_private.cpp @@ -7,9 +7,9 @@ // Internal, OS-agnostic functionality for managing the object itself //=========================================== #include <framework-OSInterface.h> -#include <QFile> -#include <QDir> -#include <QVariant> +#include <QtConcurrent> + +#include <QQmlEngine> OSInterface::OSInterface(QObject *parent) : QObject(parent){ watcher = 0; @@ -40,6 +40,40 @@ OSInterface* OSInterface::instance(){ return m_os_object; } +void OSInterface::RegisterType(){ + static bool done = false; + if(done){ return; } + done=true; + qmlRegisterType<OSInterface>("Lumina.Backend.OSInterface", 2, 0, "OSInterface"); +} + +//Start/stop interface systems +void OSInterface::start(){ + if(!mediaDirectories().isEmpty()){ setupMediaWatcher(); }//will create/connect the filesystem watcher automatically + setupNetworkManager(60000, 1); //will create/connect the network monitor automatically + if(batteryAvailable()){ setupBatteryMonitor(30000, 1); } //30 second updates, 1 ms init delay + if(brightnessSupported()){ setupBrightnessMonitor(60000, 1); } //1 minute updates, 1 ms init delay + if(volumeSupported()){ setupVolumeMonitor(60000, 2); } //1 minute updates, 2 ms init delay + if(updatesSupported()){ setupUpdateMonitor(12*60*60*1000, 5*60*1000); } //12-hour updates, 5 minute delay + if(cpuSupported()){ setupCpuMonitor(2000, 20); } //2 second updates, 20 ms init delay + if(memorySupported()){ setupMemoryMonitor(2000, 21); } //2 second updates, 21 ms init delay + if(diskSupported()){ setupDiskMonitor(60000, 25); } //1 minute updates, 25 ms init delay +} + +void OSInterface::stop(){ + if(watcher!=0){ watcher->deleteLater(); watcher=0; } + if(batteryTimer!=0){ batteryTimer->stop(); disconnect(batteryTimer); } + if(brightnessTimer!=0){ brightnessTimer->stop(); disconnect(brightnessTimer); } + if(volumeTimer!=0){ volumeTimer->stop(); disconnect(volumeTimer); } + if(updateTimer!=0){ updateTimer->stop(); disconnect(updateTimer); } + if(cpuTimer!=0){ cpuTimer->stop(); disconnect(cpuTimer); } + if(memTimer!=0){ memTimer->stop(); disconnect(memTimer); } + if(diskTimer!=0){ diskTimer->stop(); disconnect(diskTimer); } + if(netman!=0){ disconnect(netman); netman->deleteLater(); netman = 0; } +} + +bool OSInterface::isRunning(){ return _started; } //status of the object - whether it has been started yet + void OSInterface::connectWatcher(){ if(watcher==0){ return; } connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(watcherFileChanged(QString)) ); @@ -53,16 +87,119 @@ void OSInterface::connectIodevice(){ void OSInterface::connectNetman(){ if(netman==0){ return; } - connect(netman, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(netAccessChanged(QNetworkAccessManager::NetworkAccessibility)) ); + connect(netman, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(NetworkTimerUpdate()) ); connect(netman, SIGNAL(finished(QNetworkReply*)), this, SLOT(netRequestFinished(QNetworkReply*)) ); connect(netman, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(netSslErrors(QNetworkReply*, const QList<QSslError>&)) ); } -void OSInterface::connectTimer(){ - if(timer==0){ return; } - connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()) ); +bool OSInterface::verifyAppOrBin(QString chk){ + bool valid = !chk.isEmpty(); + if(chk.contains(" ")){ chk = chk.section(" ",0,0); } + if(valid && chk.endsWith(".desktop")){ + if(chk.startsWith("/")){ return QFile::exists(chk); } + valid = false; + QStringList paths; + paths << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":"); + for(int i=0; i<paths.length() && !valid; i++){ + if(QFile::exists(paths[i]+"/applications")){ valid = findInDirectory(chk, paths[i]+"/applications", true); } + } + }else if(valid){ + //Find the absolute path for this binary + if(!chk.startsWith("/")){ + QStringList paths = QString(getenv("PATH")).split(":"); + for(int i=0; i<paths.length(); i++){ + if(QFile::exists(paths[i]+"/"+chk)){ chk = paths[i]+"/"+chk; break; } + } + if(!chk.startsWith("/")){ return false; } //could not find the file + }else if(!QFile::exists(chk)){ + return false; //file does not exist + } + //Make sure it is executable by the user + valid = QFileInfo(chk).isExecutable(); + } + return valid; } +QString OSInterface::runProcess(int &retcode, QString command, QStringList arguments, QString workdir, QStringList env){ + QProcess proc; + proc.setProcessChannelMode(QProcess::MergedChannels); //need output + //First setup the process environment as necessary + QProcessEnvironment PE = QProcessEnvironment::systemEnvironment(); + if(!env.isEmpty()){ + for(int i=0; i<env.length(); i++){ + if(!env[i].contains("=")){ continue; } + PE.insert(env[i].section("=",0,0), env[i].section("=",1,100)); + } + } + proc.setProcessEnvironment(PE); + //if a working directory is specified, check it and use it + if(!workdir.isEmpty()){ + proc.setWorkingDirectory(workdir); + } + //Now run the command (with any optional arguments) + if(arguments.isEmpty()){ proc.start(command); } + else{ proc.start(command, arguments); } + //Wait for the process to finish (but don't block the event loop) + for(int i=0; i<10 && !proc.waitForFinished(500); i++){ //maximum of 5 seconds for command to finish + if(proc.state() == QProcess::NotRunning){ break; } //somehow missed the finished signal - go ahead and stop now + } + if(proc.state() != QProcess::NotRunning){ proc.terminate(); } //just in case - make sure to kill off the process + QString info = proc.readAllStandardOutput(); + retcode = proc.exitCode(); //return success/failure + return info; +} + +int OSInterface::runCmd(QString command, QStringList args){ + int retcode; + runProcess(retcode, command, args); + return retcode; +} + +QStringList OSInterface::getCmdOutput(QString command, QStringList args){ + int retcode; + return runProcess(retcode, command, args).split("\n"); +} + +bool OSInterface::findInDirectory(QString file, QString dirpath, bool recursive){ + bool found = QFile::exists(dirpath+"/"+file); + if(!found && recursive){ + QDir dir(dirpath); + QStringList dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for(int i=0; i<dirs.length() && !found; i++){ found = findInDirectory(file, dir.absoluteFilePath(dirs[i]), recursive); } + } + return found; +} + +QString OSInterface::readFile(QString path){ + QFile file(path); + QString info; + if(file.open(QIODevice::ReadOnly)){ + QTextStream out(&file); + info = out.readAll(); + file.close(); + } + return info; +} + +// =========================== +// OS SPECIFIC EXISTANCE CHECKS +// =========================== +bool OSInterface::hasControlPanel(){ + return verifyAppOrBin(controlPanelShortcut()); +} + +bool OSInterface::hasAudioMixer(){ + return verifyAppOrBin(audioMixerShortcut()); +} + +bool OSInterface::hasAppStore(){ + return verifyAppOrBin(appStoreShortcut()); +} + +// ======================== +// MEDIA DIRECTORIES +// ======================== + // External Media Management (if system uses *.desktop shortcuts) void OSInterface::setupMediaWatcher(){ //Create/connect the watcher if needed @@ -99,12 +236,460 @@ QStringList OSInterface::autoHandledMediaFiles(){ return files; } +// ============================= +// NETWORK INTERFACE FUNCTIONS +// ============================= // Qt-based NetworkAccessManager usage -void OSInterface::setupNetworkManager(){ +void OSInterface::setupNetworkManager(int update_ms, int delay_ms){ if(netman==0){ netman = new QNetworkAccessManager(this); connectNetman(); } - //Load the initial state of the network accessibility - netAccessChanged(netman->networkAccessible()); + networkTimer = new QTimer(this); + networkTimer->setSingleShot(true); + networkTimer->setInterval(update_ms); + connect(networkTimer, SIGNAL(timeout()), this, SLOT(NetworkTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(NetworkTimerUpdate()) ); +} + +bool OSInterface::networkAvailable(){ + if(INFO.contains("netaccess/available")){ return INFO.value("netaccess/available").toBool(); } + return false; +} + +QString OSInterface::networkType(){ + if(INFO.contains("netaccess/type")){ return INFO.value("netaccess/type").toString(); } //"wifi", "wired", or "cell" + return ""; +} + +float OSInterface::networkStrength(){ + if(INFO.contains("netaccess/strength")){ return INFO.value("netaccess/strength").toFloat(); } //percentage + return -1; +} + +QString OSInterface::networkIcon(){ + if(INFO.contains("netaccess/icon")){ return INFO.value("netaccess/icon").toString(); } + return ""; +} + +QString OSInterface::networkHostname(){ + return QHostInfo::localHostName(); +} + +QStringList OSInterface::networkAddress(){ + QString addr; + if(INFO.contains("netaccess/address")){ addr = INFO.value("netaccess/address").toString(); } + return addr.split(", "); +} + +bool OSInterface::hasNetworkManager(){ + return verifyAppOrBin(networkManagerUtility()); +} + +QString OSInterface::networkStatus(){ + QString stat = "<b>%1</b><br>%2<br>%3"; + return stat.arg(networkHostname(), networkType(), networkAddress().join("<br>")); +} + +//NetworkAccessManager slots +void OSInterface::syncNetworkInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + //qDebug() << "[DEBUG] Got Net Access Changed"; + hash->insert("netaccess/available", netman->networkAccessible()== QNetworkAccessManager::Accessible); + //Update all the other network status info at the same time + QNetworkConfiguration active; + QList<QNetworkConfiguration> netconfigL = netman->configuration().children(); + for(int i=0; i<netconfigL.length(); i++){ + if(!netconfigL[i].state().testFlag(QNetworkConfiguration::Discovered) ){ continue; } //skip this interface + QList<QNetworkAddressEntry> addressList = QNetworkInterface::interfaceFromName(netconfigL[i].name()).addressEntries(); + //NOTE: There are often 2 addresses, IPv4 and IPv6 + bool ok = false; + for(int j=0; j<addressList.length() && !ok; j++){ + if( addressList[j].ip().isLoopback() ){ continue; } + addressList[j].ip().toIPv4Address(&ok); + } + if(ok){ active = netconfigL[i]; break; } //found a good one with a valid IPv4 + //else if(!active.isValid()){ + } + if(!active.isValid()){ active = netman->activeConfiguration(); } //use the default Qt-detected interface + //Type of connection + QString type; + switch(active.bearerTypeFamily()){ + case QNetworkConfiguration::BearerEthernet: type="wired"; break; + case QNetworkConfiguration::BearerWLAN: type="wifi"; break; + case QNetworkConfiguration::Bearer2G: type="cell-2G"; break; + case QNetworkConfiguration::Bearer3G: type="cell-3G"; break; + case QNetworkConfiguration::Bearer4G: type="cell-4G"; break; + default: type=OS_networkTypeFromDeviceName(active.name()); //could not be auto-determined - run the OS-specific routine + } + hash->insert("netaccess/type", type); + float strength = 100; + if(type!="wired"){ strength = OS_networkStrengthFromDeviceName(active.name()); } + hash->insert("netaccess/strength", strength); + + //qDebug() << "Detected Device Status:" << active.identifier() << type << stat; + QNetworkInterface iface = QNetworkInterface::interfaceFromName(active.name()); + //qDebug() << " - Configuration: Name:" << active.name() << active.bearerTypeName() << active.identifier(); + //qDebug() << " - Interface: MAC Address:" << iface.hardwareAddress() << "Name:" << iface.name() << iface.humanReadableName() << iface.isValid(); + QList<QNetworkAddressEntry> addressList = iface.addressEntries(); + QStringList address; + //NOTE: There are often 2 addresses, IPv4 and IPv6 + for(int i=0; i<addressList.length(); i++){ + address << addressList[i].ip().toString(); + } + //qDebug() << " - IP Address:" << address; + //qDebug() << " - Hostname:" << networkHostname(); + hash->insert("netaccess/address", address.join(", ")); + + //Figure out the icon used for this type/strnegth + QString icon; + if(type.startsWith("cell")){ + if(address.isEmpty()){ icon = "network-cell-off"; } + else if(strength>80){ icon = "network-cell-connected-100"; } + else if(strength>60){ icon = "network-cell-connected-75"; } + else if(strength>40){ icon = "network-cell-connected-50"; } + else if(strength>10){ icon = "network-cell-connected-25"; } + else if(strength >=0){ icon = "network-cell-connected-00"; } + else{ icon = "network-cell"; } //unknown strength - just use generic icon so we at least get off/on visibility + }else if(type=="wifi"){ + if(address.isEmpty()){ icon = "network-wireless-off"; } + else if(strength>80){ icon = "network-wireless-100"; } + else if(strength>60){ icon = "network-wireless-75"; } + else if(strength>40){ icon = "network-wireless-50"; } + else if(strength>10){ icon = "network-wireless-25"; } + else if(strength >=0){ icon = "network-wireless-00"; } + else{ icon = "network-wireless"; } //unknown strength - just use generic icon so we at least get off/on visibility + }else if(type=="wired"){ + if(strength==100 && !address.isEmpty()){ icon = "network-wired-connected"; } + else if(strength==100){ icon = "network-wired-pending"; } + else{ icon = "network-wired-disconnected"; } + }else{ + icon = "network-workgroup"; //failover to a generic "network" icon + } + hash->insert("netaccess/icon",icon); + //qDebug() << "[DEBUG] Emit NetworkStatusChanged"; + os->emit networkStatusChanged(); + QTimer::singleShot(0, timer, SLOT(start())); +} + + +// ======================== +// TIMER-BASED MONITORS +// ======================== +//Timer slots + +void OSInterface::NetworkTimerUpdate(){ + if(networkTimer->isActive()){ networkTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncNetworkInfo, this, &INFO, networkTimer); +} + +void OSInterface::BatteryTimerUpdate(){ + if(batteryTimer->isActive()){ batteryTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncBatteryInfo, this, &INFO, batteryTimer); +} + +void OSInterface::UpdateTimerUpdate(){ + if(updateTimer->isActive()){ updateTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncUpdateInfo, this, &INFO, updateTimer); +} + +void OSInterface::BrightnessTimerUpdate(){ + if(brightnessTimer->isActive()){ brightnessTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncBrightnessInfo, this, &INFO, brightnessTimer); +} + +void OSInterface::VolumeTimerUpdate(){ + if(volumeTimer->isActive()){ volumeTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncVolumeInfo, this, &INFO, volumeTimer); +} + +void OSInterface::CpuTimerUpdate(){ + if(cpuTimer->isActive()){ cpuTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncCpuInfo, this, &INFO, cpuTimer); +} + +void OSInterface::MemTimerUpdate(){ + if(memTimer->isActive()){ memTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncMemoryInfo, this, &INFO, memTimer); +} + +void OSInterface::DiskTimerUpdate(){ + if(diskTimer->isActive()){ diskTimer->stop(); } //just in case this was manually triggered + QtConcurrent::run(this, &OSInterface::syncDiskInfo, this, &INFO, diskTimer); +} + +// Timer Setup functions +void OSInterface::setupBatteryMonitor(int update_ms, int delay_ms){ + batteryTimer = new QTimer(this); + batteryTimer->setSingleShot(true); + batteryTimer->setInterval(update_ms); + connect(batteryTimer, SIGNAL(timeout()), this, SLOT(BatteryTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(BatteryTimerUpdate()) ); +} +void OSInterface::setupUpdateMonitor(int update_ms, int delay_ms){ + updateTimer = new QTimer(this); + updateTimer->setSingleShot(true); + updateTimer->setInterval(update_ms); + connect(updateTimer, SIGNAL(timeout()), this, SLOT(UpdateTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(UpdateTimerUpdate()) ); +} +void OSInterface::setupBrightnessMonitor(int update_ms, int delay_ms){ + brightnessTimer = new QTimer(this); + brightnessTimer->setSingleShot(true); + brightnessTimer->setInterval(update_ms); + connect(brightnessTimer, SIGNAL(timeout()), this, SLOT(BrightnessTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(BrightnessTimerUpdate()) ); +} +void OSInterface::setupVolumeMonitor(int update_ms, int delay_ms){ + volumeTimer = new QTimer(this); + volumeTimer->setSingleShot(true); + volumeTimer->setInterval(update_ms); + connect(volumeTimer, SIGNAL(timeout()), this, SLOT(VolumeTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(VolumeTimerUpdate()) ); +} +void OSInterface::setupCpuMonitor(int update_ms, int delay_ms){ + cpuTimer = new QTimer(this); + cpuTimer->setSingleShot(true); + cpuTimer->setInterval(update_ms); + connect(cpuTimer, SIGNAL(timeout()), this, SLOT(CpuTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(CpuTimerUpdate()) ); +} +void OSInterface::setupMemoryMonitor(int update_ms, int delay_ms){ + memTimer = new QTimer(this); + memTimer->setSingleShot(true); + memTimer->setInterval(update_ms); + connect(memTimer, SIGNAL(timeout()), this, SLOT(MemTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(MemTimerUpdate()) ); +} +void OSInterface::setupDiskMonitor(int update_ms, int delay_ms){ + diskTimer = new QTimer(this); + diskTimer->setSingleShot(true); + diskTimer->setInterval(update_ms); + connect(diskTimer, SIGNAL(timeout()), this, SLOT(DiskTimerUpdate()) ); + QTimer::singleShot(delay_ms, this, SLOT(DiskTimerUpdate()) ); +} + +// Timer-based monitor update routines (NOTE: these are all run in a separate thread!!) +void OSInterface::syncBatteryInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + float charge = OS_batteryCharge(); + bool charging = OS_batteryCharging(); + double secs = OS_batterySecondsLeft(); + //Check for any alert generations + if(charging && hash->value("battery/percent",100).toFloat() <= 99 && charge>99){ os->emit BatteryFullAlert(); } + else if(!charging && hash->value("battery/percent", 50).toFloat()>10 && charge<10){ os->emit BatteryEmptyAlert(); } + + hash->insert("battery/percent",charge); + hash->insert("battery/charging",charging); + //Convert the seconds to human-readable + QString time; + if(secs>3600){ + time = QString::number( qRound(secs/360.0)/10.0 )+" h"; + }else if(secs>60){ + time = QString::number( qRound(secs/6.0)/10.0 )+" m"; + }else if(secs>0){ + time = QString::number(secs)+" s"; + } + hash->insert("battery/time", time); + //Determine the icon which should be used for this status + QString icon; + if(charging){ + if(charge>=99){ icon="battery-charging"; } + else if(charge>80){ icon="battery-charging-80"; } + else if(charge >60){ icon="battery-charging-60"; } + else if(charge >30){ icon="battery-charging-40"; } + else if(charge >0){ icon="battery-charging-20"; } + else{ icon="battery-unknown"; } + }else{ + if(charge>90){ icon="battery"; } + else if(charge>80){ icon="battery-80"; } + else if(charge >60){ icon="battery-60"; } + else if(charge >30){ icon="battery-40"; } + else if(charge >10){ icon="battery-20"; } + else if(charge >0){ icon="battery-alert"; } + else{ icon="battery-unknown"; } + } + hash->insert("battery/icon",icon); + //Now emit the change signal and restart the timer + os->emit batteryChanged(); + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncUpdateInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + //Get the current status + QString status, icon; + if(OS_updatesRunning()){ + status="running"; icon="sync"; + }else if(OS_updatesFinished()){ + status="finished"; icon="security-high"; + }else if(OS_updatesAvailable()){ + status="available"; icon="security-medium"; + } + //Save the current info into the hash (if different) + if(status != updateStatus()){ + hash->insert("updates/status", status); + hash->insert("updates/icon", icon); + os->emit updateStatusChanged(); + } + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncBrightnessInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncVolumeInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + int oldvol = volume(); + int newvol = OS_volume(); + if(oldvol!=newvol && newvol>=0){ + hash->insert("volume/current",newvol); + QString icon; + if(newvol>66){ icon = "audio-volume-high"; } + else if(newvol>33){ icon = "audio-volume-medium"; } + else if(newvol>0){ icon = "audio-volume-low"; } + else{ icon = "audio-volume-muted"; } + hash->insert("volume/icon",icon); + os->emit volumeChanged(); + } + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncCpuInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncMemoryInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + + QTimer::singleShot(0, timer, SLOT(start())); +} + +void OSInterface::syncDiskInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){ + + QTimer::singleShot(0, timer, SLOT(start())); +} + +// = Battery = +bool OSInterface::batteryAvailable(){ return OS_batteryAvailable(); } +float OSInterface::batteryCharge(){ + if(INFO.contains("battery/percent")){ return INFO.value("battery/percent").toFloat(); } + return -1; } +bool OSInterface::batteryCharging(){ + if(INFO.contains("battery/charging")){ return INFO.value("battery/charging").toBool(); } + return false; +} +QString OSInterface::batteryRemaining(){ + if(INFO.contains("battery/time")){ return INFO.value("battery/time").toString(); } + return ""; +} +QString OSInterface::batteryIcon(){ + if(INFO.contains("battery/icon")){ return INFO.value("battery/icon").toString(); } + return ""; +} + +QString OSInterface::batteryStatus(){ + QString text = QString::number(batteryCharge())+"%"; + if(!batteryCharging()){ + QString time = batteryRemaining(); + if(!time.isEmpty()){ + text.append(" ("+time+")"); + } + } + return text; +} + +// = Volume = +bool OSInterface::volumeSupported(){ return OS_volumeSupported(); } +int OSInterface::volume(){ + if(INFO.contains("volume/current")){ return INFO.value("volume/current").toInt(); } + return 0; +} + +void OSInterface::setVolume(int vol){ + OS_setVolume(vol); + VolumeTimerUpdate(); //update the internal cache +} + +QString OSInterface::volumeIcon(){ + if(INFO.contains("volume/icon")){ return INFO.value("volume/icon").toString(); } + return ""; +} + +// = Media = +QStringList OSInterface::mediaDirectories(){ return OS_mediaDirectories(); } +QStringList OSInterface::mediaShortcuts(){ return autoHandledMediaFiles(); } //List of currently-available XDG shortcut file paths + +// = Updates = +bool OSInterface::updatesSupported(){ return OS_updatesSupported(); } +QString OSInterface::updateStatus(){ + if(INFO.contains("updates/status")){ return INFO.value("updates/status").toString(); } + return ""; +} +bool OSInterface::updateInfoAvailable(){ + return !updateStatus().isEmpty(); +} + +QString OSInterface::updateIcon(){ + if(INFO.contains("updates/icon")){ return INFO.value("updates/icon").toString(); } + return ""; +} + +QString OSInterface::updateStatusInfo(){ + QString status = updateStatus(); + if(status=="available"){ return updateDetails(); } + else if(status=="running"){ return updateLog(); } + else if(status=="finished"){ return updateResults(); } + return ""; +} + +QString OSInterface::updateDetails(){ + return OS_updateDetails(); //don't cache these types of logs - too large +} + +QString OSInterface::updateLog(){ + return OS_updateLog(); //don't cache these types of logs - too large and change too often +} + +QString OSInterface::updateResults(){ + return OS_updateResults(); //don't cache these types of logs - too large +} + +void OSInterface::startUpdates(){ OS_startUpdates(); } +bool OSInterface::updateOnlyOnReboot(){ return OS_updateOnlyOnReboot(); } +bool OSInterface::updateCausesReboot(){ return OS_updateCausesReboot(); } + +QDateTime OSInterface::lastUpdate(){ return OS_lastUpdate(); } +QString OSInterface::lastUpdateResults(){ return OS_lastUpdateResults(); } + +// = System Power = +bool OSInterface::canReboot(){ return OS_canReboot(); } +void OSInterface::startReboot(){ OS_startReboot(); } +bool OSInterface::canShutdown(){ return OS_canShutdown(); } +void OSInterface::startShutdown(){ OS_startShutdown(); } +bool OSInterface::canSuspend(){ return OS_canSuspend(); } +void OSInterface::startSuspend(){ OS_startSuspend(); } + +// = Screen Brightness = +bool OSInterface::brightnessSupported(){ return OS_brightnessSupported(); } +int OSInterface::brightness(){ + if(INFO.contains("brightness/percent")){ return INFO.value("brightness/percent").toInt(); } + return 100; +} +void OSInterface::setBrightness(int percent){ + OS_setBrightness(percent); + BrightnessTimerUpdate(); //update internal cache ASAP +} + +// = System Status Monitoring +bool OSInterface::cpuSupported(){ return OS_cpuSupported(); } +QList<int> OSInterface::cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors +QStringList OSInterface::cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example) + +bool OSInterface::memorySupported(){ return false; } +int OSInterface::memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors +QString OSInterface::memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session +QStringList OSInterface::diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device + +bool OSInterface::diskSupported(){ return false; } +int OSInterface::fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors +QString OSInterface::fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity diff --git a/src-qt5/src-cpp/plugins-base.h b/src-qt5/src-cpp/plugins-base.h index 26b0eacc..eb54e40d 100644 --- a/src-qt5/src-cpp/plugins-base.h +++ b/src-qt5/src-cpp/plugins-base.h @@ -35,12 +35,12 @@ public: virtual void loadFile(QString path); bool isLoaded() { return !data.isEmpty(); }; - bool containsDefault(QString obj) { return data.value(obj).toObject().contains("default"); } + bool containsDefault(QString obj) { return data.value(obj).toObject().contains("default"); } /** * Check if the plugin is valid as long as the JSON is not empty, * it contains at least a "name", "qml", and "description" object, - * and the "name" and "description" objects contain a "default" key. + * and the "name" and "description" objects contain a "default" key. **/ virtual bool isValid() = 0; @@ -48,7 +48,7 @@ public: virtual QUrl scriptURL(); QJsonObject data; //Hazardous to manually modify - QString relDir; + QString relDir; }; class PluginSystem{ diff --git a/src-qt5/src-cpp/plugins-desktop.cpp b/src-qt5/src-cpp/plugins-desktop.cpp index fdbd676d..19c49942 100644 --- a/src-qt5/src-cpp/plugins-desktop.cpp +++ b/src-qt5/src-cpp/plugins-desktop.cpp @@ -6,15 +6,15 @@ //=========================================== #include "plugins-desktop.h" +#include <LuminaXDG.h> + // ============ // DT PLUGIN // ============ DTPlugin::DTPlugin(){ - } DTPlugin::~DTPlugin(){ - } bool DTPlugin::isValid(){ @@ -22,8 +22,10 @@ bool DTPlugin::isValid(){ bool ok = data.contains("name") && data.contains("qml") && data.contains("description"); ok &= containsDefault("name"); ok &= containsDefault("description"); + ok &= containsDefault("data"); if(ok) { QJsonObject tmp = data.value("qml").toObject(); + QStringList mustexist; QString exec = tmp.value("exec").toString(); if(exec.isEmpty() || !exec.endsWith(".qml")){ return false; } @@ -38,3 +40,33 @@ bool DTPlugin::isValid(){ } return ok; } + +QSize DTPlugin::getSize(){ + QString gridS = data.value("data").toObject().value("grid_size").toString(); + QSize gridSize(0,0); + if(!gridS.isEmpty()) { + QStringList gridList = gridS.split("x"); + if(gridList.size() == 2) { + int width = gridList[0].toInt(); + int height = gridList[1].toInt(); + if(width > 0 && height > 0) + gridSize = QSize(width, height); + } + } + return gridSize; +} + +bool DTPlugin::supportsPanel(){ + QString possibleS = data.value("data").toObject().value("panel_possible").toString().toLower(); + bool panelPossible = false; + if(!possibleS.isEmpty() && (possibleS == "yes" || possibleS == "true")){ + panelPossible = true; + } + return panelPossible; +} + +QString DTPlugin::getIcon(){ + QString iconS = data.value("data").toObject().value("plugin_icon").toString(); + if(iconS.isEmpty()){ iconS = "preferences-plugin"; } + return iconS; +} diff --git a/src-qt5/src-cpp/plugins-desktop.h b/src-qt5/src-cpp/plugins-desktop.h index ed576db1..260f9070 100644 --- a/src-qt5/src-cpp/plugins-desktop.h +++ b/src-qt5/src-cpp/plugins-desktop.h @@ -17,13 +17,19 @@ #include <QFile> #include <QDir> #include <QDebug> +#include <QIcon> class DTPlugin : public BasePlugin{ + public: DTPlugin(); ~DTPlugin(); virtual bool isValid() Q_DECL_OVERRIDE; + + QSize getSize(); + bool supportsPanel(); + QString getIcon(); }; #endif diff --git a/src-qt5/src-cpp/tests/main.cpp b/src-qt5/src-cpp/tests/main.cpp index 682c318a..215d1620 100644 --- a/src-qt5/src-cpp/tests/main.cpp +++ b/src-qt5/src-cpp/tests/main.cpp @@ -34,5 +34,8 @@ int main(int argc, char** argv){ timer->start(); int ret = A.exec(); qDebug() << " - Finished"; + qDebug() << "Ending Status:"; + qDebug() << "OS.networkAvailable:" << OS.networkAvailable(); + qDebug() << " - " << OS.networkType() << OS.networkStrength() << OS.networkIcon() << OS.networkHostname() << OS.networkAddress(); return ret; } |