From cb7e8d9644d9385c9323d4650afa126ec532c00e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Sun, 13 Sep 2009 16:43:26 +0000 Subject: [PATCH] added button to detect properties (title and class) from window under mouse to build window-specifics override. Also removed unnecessary setMargin and setSpacing to use KDE/QT defaults in dialog design svn path=/trunk/KDE/kdebase/workspace/; revision=1022971 --- clients/nitrogen/config/CMakeLists.txt | 2 + .../config/nitrogenconfigurationui.cpp | 7 - .../nitrogen/config/nitrogendetectwidget.cpp | 221 ++++++++++++++++++ .../nitrogen/config/nitrogendetectwidget.h | 144 ++++++++++++ .../config/nitrogenexceptiondialog.cpp | 70 +++++- .../nitrogen/config/nitrogenexceptiondialog.h | 13 ++ 6 files changed, 442 insertions(+), 15 deletions(-) create mode 100644 clients/nitrogen/config/nitrogendetectwidget.cpp create mode 100644 clients/nitrogen/config/nitrogendetectwidget.h diff --git a/clients/nitrogen/config/CMakeLists.txt b/clients/nitrogen/config/CMakeLists.txt index c14aba53d7..fbf430ab62 100644 --- a/clients/nitrogen/config/CMakeLists.txt +++ b/clients/nitrogen/config/CMakeLists.txt @@ -8,6 +8,7 @@ set(kwin_nitrogen_config_PART_SRCS ../nitrogenexception.cpp ../nitrogenexceptionlist.cpp nitrogenconfigurationui.cpp + nitrogendetectwidget.cpp nitrogenexceptiondialog.cpp nitrogenexceptionlistwidget.cpp nitrogenexceptionmodel.cpp @@ -19,6 +20,7 @@ target_link_libraries( kwin_nitrogen_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY} + ${X11_X11_LIB} ) install(TARGETS kwin_nitrogen_config DESTINATION ${PLUGIN_INSTALL_DIR} ) diff --git a/clients/nitrogen/config/nitrogenconfigurationui.cpp b/clients/nitrogen/config/nitrogenconfigurationui.cpp index 33e36bfaba..169f3d741e 100644 --- a/clients/nitrogen/config/nitrogenconfigurationui.cpp +++ b/clients/nitrogen/config/nitrogenconfigurationui.cpp @@ -54,7 +54,6 @@ namespace Nitrogen { QVBoxLayout* mainLayout = new QVBoxLayout( this ); - mainLayout->setSpacing(6); mainLayout->setMargin(0); // tab widget for basic and advanced mode @@ -68,12 +67,9 @@ namespace Nitrogen tab->setTabToolTip( index, i18n( "Basic window decoration configuration options" ) ); QVBoxLayout* vboxLayout = new QVBoxLayout(); - vboxLayout->setMargin( 6 ); - vboxLayout->setSpacing( 6 ); basicWidget->setLayout( vboxLayout ); QGridLayout* gridLayout = new QGridLayout(); - gridLayout->setSpacing(6); gridLayout->setMargin(0); vboxLayout->addLayout( gridLayout ); @@ -138,12 +134,9 @@ namespace Nitrogen tab->setTabToolTip( index, i18n( "Additional window decoration configuration options" ) ); QVBoxLayout* vboxLayout = new QVBoxLayout(); - vboxLayout->setMargin( 6 ); - vboxLayout->setSpacing( 6 ); advancedWidget->setLayout( vboxLayout ); QGridLayout* gridLayout = new QGridLayout(); - gridLayout->setSpacing(6); gridLayout->setMargin(0); vboxLayout->addLayout( gridLayout ); diff --git a/clients/nitrogen/config/nitrogendetectwidget.cpp b/clients/nitrogen/config/nitrogendetectwidget.cpp new file mode 100644 index 0000000000..d8345c20eb --- /dev/null +++ b/clients/nitrogen/config/nitrogendetectwidget.cpp @@ -0,0 +1,221 @@ + +////////////////////////////////////////////////////////////////////////////// +// nitrogendetectwidget.cpp +// Note: this class is a stripped down version of +// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp +// Copyright (c) 2004 Lubos Lunak +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "nitrogendetectwidget.h" +#include "nitrogendetectwidget.moc" + +#include +#include +#include +#include +#include + +namespace Nitrogen +{ + + //_________________________________________________________ + DetectWidget::DetectWidget( QWidget* parent ): + QWidget( parent ) + { + + QVBoxLayout* vboxLayout = new QVBoxLayout(); + vboxLayout->setMargin( 0 ); + setLayout( vboxLayout ); + + QGroupBox* box( new QGroupBox( i18n( "Information about Selected Window" ), this ) ); + vboxLayout->addWidget( box ); + + // display layout + QGridLayout *gridLayout = new QGridLayout(); + box->setLayout( gridLayout ); + + // class + gridLayout->addWidget( new QLabel( i18n( "Class: " ), box ), 0, 0, 1, 1, Qt::AlignRight|Qt::AlignVCenter ); + gridLayout->addWidget( windowClass = new QLabel( box ), 0, 1, 1, 1 ); + + // title + gridLayout->addWidget( new QLabel( i18n( "Title: " ), box ), 1, 0, 1, 1, Qt::AlignRight|Qt::AlignVCenter ); + gridLayout->addWidget( windowTitle = new QLabel( box ), 1, 1, 1, 1 ); + + box = new QGroupBox( i18n( "Window Property Selection" ), this ); + QButtonGroup* group( new QButtonGroup( this ) ); + box->setLayout( new QVBoxLayout() ); + vboxLayout->addWidget( box ); + + QCheckBox* checkbox; + group->addButton( checkbox = new QCheckBox( i18n( "Use window class (whole application)" ) ) ); + checkboxes.insert( std::make_pair( checkbox, NitrogenException::WindowClassName ) ); + checkbox->setChecked( true ); + box->layout()->addWidget( checkbox ); + + group->addButton( checkbox = new QCheckBox( i18n( "Use window title" ) ) ); + checkboxes.insert( std::make_pair( checkbox, NitrogenException::WindowTitle ) ); + box->layout()->addWidget( checkbox ); + + } + + //_________________________________________________________ + NitrogenException::Type DetectWidget::exceptionType( void ) const + { + for( CheckBoxMap::const_iterator iter = checkboxes.begin(); iter != checkboxes.end(); iter++ ) + { if( iter->first->isChecked() ) return iter->second; } + + assert( false ); + return NitrogenException::WindowClassName; + } + + //_________________________________________________________ + DetectDialog::DetectDialog( QWidget* parent ): + KDialog( parent ), + grabber( 0 ) + { + + // define buttons + setButtons( Ok|Cancel ); + showButtonSeparator( false ); + + // central widget + setMainWidget( widget = new DetectWidget( this ) ); + + } + + //_________________________________________________________ + void DetectDialog::detect( WId window ) + { + if( window == 0 ) selectWindow(); + else readWindow( window ); + } + + //_________________________________________________________ + void DetectDialog::readWindow( WId window ) + { + + if( window == 0 ) + { + emit detectionDone( false ); + return; + } + + info = KWindowSystem::windowInfo( window, -1U, -1U ); + if( !info.valid()) + { + emit detectionDone( false ); + return; + } + + QString wmclass_class = info.windowClassClass(); + QString wmclass_name = info.windowClassName(); + QString title = info.name(); + + widget->setWindowClass( wmclass_class + " (" + wmclass_name + ' ' + wmclass_class + ')' ); + widget->setWindowTitle( title ); + emit detectionDone( exec() == KDialog::Accepted ); + + return; + + } + + //_________________________________________________________ + void DetectDialog::selectWindow() + { + + // use a dialog, so that all user input is blocked + // use WX11BypassWM and moving away so that it's not actually visible + // grab only mouse, so that keyboard can be used e.g. for switching windows + grabber = new KDialog( 0, Qt::X11BypassWindowManagerHint ); + grabber->move( -1000, -1000 ); + grabber->setModal( true ); + grabber->show(); + grabber->grabMouse( Qt::CrossCursor ); + grabber->installEventFilter( this ); + + } + + //_________________________________________________________ + bool DetectDialog::eventFilter( QObject* o, QEvent* e ) + { + // check object and event type + if( o != grabber ) return false; + if( e->type() != QEvent::MouseButtonRelease ) return false; + + // delete old grabber + delete grabber; + grabber = 0; + + // check button + if( static_cast< QMouseEvent* >( e )->button() != Qt::LeftButton ) return true; + + // read window information + readWindow( findWindow() ); + + return true; + } + + //_________________________________________________________ + WId DetectDialog::findWindow() + { + + Window root; + Window child; + uint mask; + int rootX, rootY, x, y; + Window parent = QX11Info::appRootWindow(); + Atom wm_state = XInternAtom( QX11Info::display(), "WM_STATE", False ); + + // why is there a loop of only 10 here + for( int i = 0; i < 10; ++i ) + { + XQueryPointer( QX11Info::display(), parent, &root, &child, &rootX, &rootY, &x, &y, &mask ); + if( child == None ) return 0; + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if( XGetWindowProperty( + QX11Info::display(), child, wm_state, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, &after, &prop ) == Success ) + { + if( prop != NULL ) XFree( prop ); + if( type != None ) return child; + } + parent = child; + } + + return 0; + + } + +} diff --git a/clients/nitrogen/config/nitrogendetectwidget.h b/clients/nitrogen/config/nitrogendetectwidget.h new file mode 100644 index 0000000000..b8230ee813 --- /dev/null +++ b/clients/nitrogen/config/nitrogendetectwidget.h @@ -0,0 +1,144 @@ +#ifndef nitrogendetectwidget_h +#define nitrogendetectwidget_h + +////////////////////////////////////////////////////////////////////////////// +// nitrogendetectwidget.h +// Note: this class is a stripped down version of +// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.h +// Copyright (c) 2004 Lubos Lunak + +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include + +#include "../nitrogenexception.h" + +namespace Nitrogen +{ + + class DetectWidget: public QWidget + { + + public: + + //! constructor + DetectWidget( QWidget* ); + + //! window class + void setWindowClass( QString value ) + { windowClass->setText( value ); } + + //! window title + void setWindowTitle( QString value ) + { windowTitle->setText( value ); } + + //! window machine + void setWindowMachine( QString value ) + { windowMachine->setText( value ); } + + //! type + NitrogenException::Type exceptionType( void ) const; + + private: + + QLabel* windowClass; + QLabel* windowTitle; + QLabel* windowMachine; + + // map checkboxes against exception type + typedef std::map CheckBoxMap; + CheckBoxMap checkboxes; + + }; + + class DetectDialog : public KDialog + { + + Q_OBJECT + + public: + + //! constructor + DetectDialog( QWidget* ); + + //! read window properties or select one from mouse grab + void detect( WId window ); + + //! selected class + QByteArray selectedClass() const; + + //! window information + const KWindowInfo& windowInfo() const + { return info; } + + //! exception type + NitrogenException::Type exceptionType() const + { return widget->exceptionType(); } + + signals: + + void detectionDone( bool ); + + protected: + + virtual bool eventFilter( QObject* o, QEvent* e ); + + private: + + //! select window from grab + void selectWindow(); + + //! read window properties + void readWindow( WId window ); + + //! find window under cursor + WId findWindow(); + + //! execute + void executeDialog( void ); + + //! window machine + QString machine; + + //! main widget + DetectWidget* widget; + + //! invisible dialog used to grab mouse + KDialog* grabber; + + //! current window information + KWindowInfo info; + + }; + +} // namespace + +#endif diff --git a/clients/nitrogen/config/nitrogenexceptiondialog.cpp b/clients/nitrogen/config/nitrogenexceptiondialog.cpp index 18c385a477..b92798f439 100644 --- a/clients/nitrogen/config/nitrogenexceptiondialog.cpp +++ b/clients/nitrogen/config/nitrogenexceptiondialog.cpp @@ -23,31 +23,35 @@ // IN THE SOFTWARE. ////////////////////////////////////////////////////////////////////////////// +#include #include #include #include #include +#include +#include "nitrogendetectwidget.h" #include "nitrogenexceptiondialog.h" +#include "nitrogenexceptiondialog.moc" namespace Nitrogen { //___________________________________________ NitrogenExceptionDialog::NitrogenExceptionDialog( QWidget* parent ): - KDialog( parent ) + KDialog( parent ), + detectDialog(0) { // define buttons setButtons( Ok|Cancel ); - showButtonSeparator( true ); + showButtonSeparator( false ); // main widget QWidget* widget = new QWidget( this ); setMainWidget( widget ); widget->setLayout( new QVBoxLayout() ); - widget->layout()->setSpacing(5); widget->layout()->setMargin(0); // exception definition @@ -55,8 +59,6 @@ namespace Nitrogen widget->layout()->addWidget( box = new QGroupBox( i18n( "Definition" ), widget ) ); QGridLayout* gridLayout = new QGridLayout(); - gridLayout->setSpacing(5); - gridLayout->setMargin(5); box->setLayout( gridLayout ); QLabel *label; @@ -66,13 +68,18 @@ namespace Nitrogen gridLayout->addWidget( exceptionType = new QComboBox(box), 0, 1, 1, 1 ); exceptionType->insertItems(0, QStringList() << NitrogenException::typeName( NitrogenException::WindowClassName, true ) - << NitrogenException::typeName( NitrogenException::WindowTitle, true ) ); + << NitrogenException::typeName( NitrogenException::WindowTitle, true ) + ); exceptionType->setToolTip( i18n( "Select here the window characteristic used to \n" "identify windows to which the exception apply." ) ); label->setAlignment( Qt::AlignRight ); + KPushButton* button = new KPushButton( i18n( "&Detect Window Properties" ), box ); + gridLayout->addWidget( button, 2, 0, 1, 2, Qt::AlignRight|Qt::AlignVCenter ); + connect( button, SIGNAL( clicked( void ) ), SLOT( selectWindowProperties() ) ); + // regular expression gridLayout->addWidget( label = new QLabel( i18n( "Regular expression to match: " ), box ), 1, 0, 1, 1 ); gridLayout->addWidget( exceptionEditor = new KLineEdit( box ), 1, 1, 1, 1 ); @@ -86,8 +93,6 @@ namespace Nitrogen // decoration flags widget->layout()->addWidget( box = new QGroupBox( i18n( "Decoration" ), widget ) ); gridLayout = new QGridLayout(); - gridLayout->setSpacing(5); - gridLayout->setMargin(5); box->setLayout( gridLayout ); QCheckBox* checkbox; @@ -205,6 +210,55 @@ namespace Nitrogen } + //___________________________________________ + void NitrogenExceptionDialog::selectWindowProperties( void ) + { + + // create widget + if( !detectDialog ) + { + detectDialog = new DetectDialog( this ); + connect( detectDialog, SIGNAL( detectionDone( bool ) ), SLOT( readWindowProperties( bool ) ) ); + } + + detectDialog->detect(0); + + } + + //___________________________________________ + void NitrogenExceptionDialog::readWindowProperties( bool valid ) + { + assert( detectDialog ); + if( valid ) + { + + // type + exceptionType->setCurrentIndex( exceptionType->findText( NitrogenException::typeName( detectDialog->exceptionType(), true ) ) ); + + // window info + const KWindowInfo& info( detectDialog->windowInfo() ); + + switch( detectDialog->exceptionType() ) + { + case NitrogenException::WindowClassName: + exceptionEditor->setText( info.windowClassClass() ); + break; + + case NitrogenException::WindowTitle: + exceptionEditor->setText( info.name() ); + break; + + default: assert( false ); + + } + + } + + delete detectDialog; + detectDialog = 0; + + } + //___________________________________________ const QString NitrogenExceptionDialog::ComboBox::Yes( i18n("Enabled") ); const QString NitrogenExceptionDialog::ComboBox::No( i18n("Disabled") ); diff --git a/clients/nitrogen/config/nitrogenexceptiondialog.h b/clients/nitrogen/config/nitrogenexceptiondialog.h index 1a62427be8..622a17d3a1 100644 --- a/clients/nitrogen/config/nitrogenexceptiondialog.h +++ b/clients/nitrogen/config/nitrogenexceptiondialog.h @@ -37,10 +37,14 @@ namespace Nitrogen { + class DetectDialog; + //! nitrogen exceptions list class NitrogenExceptionDialog: public KDialog { + Q_OBJECT + public: //! constructor @@ -52,6 +56,12 @@ namespace Nitrogen //! get exception NitrogenException exception( void ) const; + private slots: + + void selectWindowProperties( void ); + + void readWindowProperties( bool ); + private: //! line editor @@ -104,6 +114,9 @@ namespace Nitrogen //! draw separator ComboBox* drawSeparator; + //! detection dialog + DetectDialog* detectDialog; + }; }