diff --git a/kcmkwin/kwinrules/Makefile.am b/kcmkwin/kwinrules/Makefile.am index dd68b263ad..18ac989b47 100644 --- a/kcmkwin/kwinrules/Makefile.am +++ b/kcmkwin/kwinrules/Makefile.am @@ -3,8 +3,8 @@ AM_CPPFLAGS = $(all_includes) -DKCMRULES kde_module_LTLIBRARIES = kcm_kwinrules.la -kcm_kwinrules_la_SOURCES = main.cpp ruleswidget.cpp ruleslist.cpp kwinsrc.cpp \ - ruleswidgetbase.ui ruleslistbase.ui +kcm_kwinrules_la_SOURCES = main.cpp ruleswidget.cpp ruleslist.cpp kwinsrc.cpp detectwidget.cpp \ + ruleswidgetbase.ui ruleslistbase.ui detectwidgetbase.ui kcm_kwinrules_la_LDFLAGS = -module -avoid-version $(all_libraries) -no-undefined kcm_kwinrules_la_LIBADD = $(LIB_KDEUI) diff --git a/kcmkwin/kwinrules/detectwidget.cpp b/kcmkwin/kwinrules/detectwidget.cpp new file mode 100644 index 0000000000..b1b05b944e --- /dev/null +++ b/kcmkwin/kwinrules/detectwidget.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004 Lubos Lunak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "detectwidget.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace KWinInternal +{ + +DetectWidget::DetectWidget( QWidget* parent, const char* name ) +: DetectWidgetBase( parent, name ) + { + } + +DetectDialog::DetectDialog( QWidget* parent, const char* name ) +: KDialogBase( parent, name, true, "", Ok /*| Cancel*/ ) +, grabber( NULL ) + { + widget = new DetectWidget( this ); + setMainWidget( widget ); + } + +void DetectDialog::detect( WId window ) + { + if( window == 0 ) + selectWindow(); + else + readWindow( window ); + } + +static QCString getStringProperty(WId w, Atom prop, char separator=0) + { + Atom type; + int format, status; + unsigned long nitems = 0; + unsigned long extra = 0; + unsigned char *data = 0; + QCString result = ""; + status = XGetWindowProperty( qt_xdisplay(), w, prop, 0, 10000, + FALSE, XA_STRING, &type, &format, + &nitems, &extra, &data ); + if ( status == Success) + { + if (data && separator) + { + for (int i=0; i<(int)nitems; i++) + if (!data[i] && i+1<(int)nitems) + data[i] = separator; + } + if (data) + result = (const char*) data; + XFree(data); + } + return result; + } + +void DetectDialog::readWindow( WId w ) + { + if( w == 0 ) + { + emit detectionDone( false ); + return; + } + KXErrorHandler err; + XClassHint hint; + XGetClassHint( qt_xdisplay(), w, &hint ); + Atom wm_role = XInternAtom( qt_xdisplay(), "WM_WINDOW_ROLE", False ); + KWin::WindowInfo info = KWin::windowInfo( w ); + if( !info.valid()) + { + emit detectionDone( false ); + return; + } + wmclass_class = hint.res_class; + wmclass_name = hint.res_name; + role = getStringProperty( w, wm_role ); + type = info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask + | NET::UtilityMask | NET::SplashMask ); + title = info.name(); + extrarole = ""; // TODO + machine = getStringProperty( w, XA_WM_CLIENT_MACHINE ); + if( err.error( true )) + { + emit detectionDone( false ); + return; + } + executeDialog(); + } + +void DetectDialog::executeDialog() + { + static const char* const types[] = + { + I18N_NOOP( "Normal Window" ), + I18N_NOOP( "Desktop" ), + I18N_NOOP( "Dock (panel)" ), + I18N_NOOP( "Toolbar" ), + I18N_NOOP( "Torn Off Menu" ), + I18N_NOOP( "Dialog Window" ), + I18N_NOOP( "Override Type" ), + I18N_NOOP( "Standalone Menubar" ), + I18N_NOOP( "Utility Window" ), + I18N_NOOP( "Splashscreen" ) + }; + widget->class_label->setText( wmclass_class + " (" + wmclass_name + ' ' + wmclass_class + ")" ); + widget->role_label->setText( role ); + if( type == NET::Unknown ) + widget->type_label->setText( i18n( "Unknown - will be treated as Normal Window" )); + else + widget->type_label->setText( i18n( types[ type ] )); + widget->title_label->setText( title ); + widget->extrarole_label->setText( extrarole ); + widget->machine_label->setText( machine ); + emit detectionDone( exec() == QDialog::Accepted ); + } + +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 QDialog( NULL, NULL, true, WX11BypassWM ); + grabber->move( -1000, -1000 ); + grabber->show(); + grabber->grabMouse( crossCursor ); + grabber->installEventFilter( this ); + } + +bool DetectDialog::eventFilter( QObject* o, QEvent* e ) + { + if( o != grabber ) + return false; + if( e->type() != QEvent::MouseButtonRelease ) + return false; + delete grabber; + grabber = NULL; + readWindow( findWindow()); + return true; + } + +WId DetectDialog::findWindow() + { + Window root; + Window child; + uint mask; + int rootX, rootY, x, y; + Window parent = qt_xrootwin(); + Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); + for( int i = 0; + i < 10; + ++i ) + { + XQueryPointer( qt_xdisplay(), 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( qt_xdisplay(), 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; + } + +} // namespace + +#include "detectwidget.moc" diff --git a/kcmkwin/kwinrules/detectwidget.h b/kcmkwin/kwinrules/detectwidget.h new file mode 100644 index 0000000000..509082a52c --- /dev/null +++ b/kcmkwin/kwinrules/detectwidget.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 Lubos Lunak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __DETECTWIDGET_H__ +#define __DETECTWIDGET_H__ + +#include "detectwidgetbase.h" + +#include +#include + +namespace KWinInternal +{ + +class DetectWidget + : public DetectWidgetBase + { + Q_OBJECT + public: + DetectWidget( QWidget* parent = NULL, const char* name = NULL ); + }; + +class DetectDialog + : public KDialogBase + { + Q_OBJECT + public: + DetectDialog( QWidget* parent = NULL, const char* name = NULL ); + void detect( WId window ); + signals: + void detectionDone( bool ); + protected: + virtual bool eventFilter( QObject* o, QEvent* e ); + private: + void selectWindow(); + void readWindow( WId window ); + void executeDialog(); + WId findWindow(); + QCString wmclass_class; + QCString wmclass_name; + QCString role; + NET::WindowType type; + QString title; + QCString extrarole; + QCString machine; + DetectWidget* widget; + QDialog* grabber; + }; + +} // namespace + +#endif diff --git a/kcmkwin/kwinrules/detectwidgetbase.ui b/kcmkwin/kwinrules/detectwidgetbase.ui new file mode 100644 index 0000000000..c110a18f95 --- /dev/null +++ b/kcmkwin/kwinrules/detectwidgetbase.ui @@ -0,0 +1,156 @@ + +KWinInternal::DetectWidgetBase + + + Form3 + + + + 0 + 0 + 600 + 480 + + + + Form1 + + + + unnamed + + + + textLabel9 + + + Information about the selected window: + + + + + layout1 + + + + unnamed + + + + textLabel1 + + + Class: + + + + + textLabel13 + + + Machine: + + + + + textLabel4 + + + Type: + + + + + textLabel11 + + + Extra role: + + + + + title_label + + + + + + + + class_label + + + + + + + + extrarole_label + + + + + + + + textLabel8 + + + Title: + + + + + machine_label + + + + + + + + type_label + + + + + + + + textLabel3 + + + Role: + + + + + role_label + + + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp index 0bfbd3f03e..a77662cf14 100644 --- a/kcmkwin/kwinrules/ruleswidget.cpp +++ b/kcmkwin/kwinrules/ruleswidget.cpp @@ -28,9 +28,12 @@ #include #include #include +#include #include "../../rules.h" +#include "detectwidget.h" + namespace KWinInternal { @@ -43,6 +46,7 @@ namespace KWinInternal RulesWidget::RulesWidget( QWidget* parent, const char* name ) : RulesWidgetBase( parent, name ) +, detect_dlg( NULL ) { QString enableDesc = i18n( "Enable this checkbox to alter this window property for the specified window(s)." ); @@ -459,6 +463,20 @@ Rules* RulesWidget::rules() const #undef LINEEDIT_FORCE_RULE #undef COMBOBOX_FORCE_RULE +void RulesWidget::detectClicked() + { + assert( detect_dlg == NULL ); + detect_dlg = new DetectDialog; + connect( detect_dlg, SIGNAL( detectionDone( bool )), this, SLOT( detected( bool ))); + detect_dlg->detect( 0 ); + } + +void RulesWidget::detected( bool ok ) + { + delete detect_dlg; + detect_dlg = NULL; + } + RulesDialog::RulesDialog( QWidget* parent, const char* name ) : KDialogBase( parent, name, true, "", Ok | Cancel ) { diff --git a/kcmkwin/kwinrules/ruleswidget.h b/kcmkwin/kwinrules/ruleswidget.h index 10e36e9310..507a1872a8 100644 --- a/kcmkwin/kwinrules/ruleswidget.h +++ b/kcmkwin/kwinrules/ruleswidget.h @@ -28,6 +28,7 @@ namespace KWinInternal { class Rules; +class DetectDialog; class RulesWidget : public RulesWidgetBase @@ -39,6 +40,8 @@ class RulesWidget Rules* rules() const; signals: void changed( bool state ); + protected slots: + virtual void detectClicked(); private slots: // geometry tab void updateEnableposition(); @@ -65,6 +68,10 @@ class RulesWidget void updateEnableignoreposition(); void updateEnableminsize(); void updateEnablemaxsize(); + // internal + void detected( bool ); + private: + DetectDialog* detect_dlg; }; class RulesDialog diff --git a/kcmkwin/kwinrules/ruleswidgetbase.ui b/kcmkwin/kwinrules/ruleswidgetbase.ui index 51ec528dee..d27025f2c9 100644 --- a/kcmkwin/kwinrules/ruleswidgetbase.ui +++ b/kcmkwin/kwinrules/ruleswidgetbase.ui @@ -12,6 +12,9 @@ 477 + + Form1 + unnamed @@ -275,7 +278,10 @@ detect1 - Detect (bad luck, this one doesn't work yet) + &Detect + + + Alt+D @@ -2125,6 +2131,12 @@ edit_reg_wmclass setEnabled(bool) + + detect1 + clicked() + Form2 + detectClicked() + tabWidget2 @@ -2213,6 +2225,9 @@ rule_maxsize maxsize + + detectClicked() +