diff --git a/atoms.cpp b/atoms.cpp index 41b16ea318..34559f3d61 100644 --- a/atoms.cpp +++ b/atoms.cpp @@ -9,48 +9,51 @@ Atoms::Atoms() char* names[max]; Atom atoms_return[max]; int n = 0; - + atoms[n] = &wm_protocols; names[n++] = "WM_PROTOCOLS"; - + atoms[n] = &wm_delete_window; names[n++] = "WM_DELETE_WINDOW"; - + atoms[n] = &wm_take_focus; names[n++] = "WM_TAKE_FOCUS"; - + atoms[n] = &wm_change_state; names[n++] = "WM_CHANGE_STATE"; - + // compatibility atoms[n] = &kwm_win_icon; names[n++] = "KWM_WIN_ICON"; - + // compatibility atoms[n] = &kwm_running; names[n++] = "KWM_RUNNING"; - + atoms[n] = &net_number_of_desktops; names[n++] = "_NET_NUMBER_OF_DESKTOPS"; - + atoms[n] = &net_current_desktop; names[n++] = "_NET_CURRENT_DESKTOP"; - + atoms[n] = &net_active_window; names[n++] = "_NET_ACTIVE_WINDOW"; + + atoms[n] = &net_wm_context_help; + names[n++] = "_NET_WM_CONTEXT_HELP"; atoms[n] = &net_client_list; names[n++] = "_NET_CLIENT_LIST"; - + atoms[n] = &net_client_list_stacking; names[n++] = "_NET_CLIENT_LIST_STACKING"; - + atoms[n] = &net_kde_docking_windows; names[n++] = "_NET_KDE_DOCKING_WINDOWS"; - + XInternAtoms( qt_xdisplay(), names, n, FALSE, atoms_return ); for (int i = 0; i < n; i++ ) *atoms[i] = atoms_return[i]; - - + + } diff --git a/atoms.h b/atoms.h index e901d6776c..f272f3376b 100644 --- a/atoms.h +++ b/atoms.h @@ -18,7 +18,7 @@ public: Atom net_active_window; Atom net_client_list; Atom net_client_list_stacking; - + Atom net_wm_context_help; Atom net_kde_docking_windows; }; diff --git a/client.cpp b/client.cpp index 0f819e7302..6bb524c36d 100644 --- a/client.cpp +++ b/client.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "workspace.h" #include "client.h" #include "atoms.h" @@ -1455,6 +1456,7 @@ void Client::getWindowProtocols(){ Pdeletewindow = 0; Ptakefocus = 0; + Pcontexthelp = 0; if (XGetWMProtocols(qt_xdisplay(), win, &p, &n)){ for (i = 0; i < n; i++) @@ -1462,6 +1464,8 @@ void Client::getWindowProtocols(){ Pdeletewindow = 1; else if (p[i] == atoms->wm_take_focus) Ptakefocus = 1; + else if (p[i] == atoms->net_wm_context_help) + Pcontexthelp = 1; if (n>0) XFree(p); } @@ -1509,6 +1513,33 @@ Client* Client::mainClient() } +/*! + Returns whether the window provides context help or not. If it does, + you should show a help menu item or a help button lie '?' and call + contextHelp() if this is invoked. + + \sa contextHelp() + */ +bool Client::providesContextHelp() const +{ + return Pcontexthelp; +} + + +/*! + Invokes context help on the window. Only works if the window + actually provides context help. + + \sa providesContextHelp() + */ +void Client::contextHelp() +{ + if ( Pcontexthelp ) { + sendClientMessage(win, atoms->wm_protocols, atoms->net_wm_context_help); + QWhatsThis::enterWhatsThisMode(); + } +} + bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos) { diff --git a/client.h b/client.h index ae278e8d05..a9600dbe4e 100644 --- a/client.h +++ b/client.h @@ -129,6 +129,8 @@ public: virtual bool wantsTabFocus() const { return TRUE;} //### just for now + + bool providesContextHelp() const; bool performMouseCommand( Options::MouseCommand, QPoint globalPos ); @@ -138,6 +140,7 @@ public slots: void maximize( MaximizeMode ); void maximize(); void toggleSticky(); + void contextHelp(); protected: void paintEvent( QPaintEvent * ); @@ -215,6 +218,7 @@ private: void getWindowProtocols(); uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol? uint Ptakefocus :1;// does the window understand the TakeFocus protocol? + uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol? uint input :1; // does the window want input in its wm_hints uint mapped :1; // keeps track of our visiblity within the asynchronous event flow QPixmap icon_pix; diff --git a/stdclient.cpp b/stdclient.cpp index d52776de00..a0a0310ca7 100644 --- a/stdclient.cpp +++ b/stdclient.cpp @@ -28,6 +28,34 @@ static QPixmap* dis_pinup_pix = 0; static QPixmap* dis_pindown_pix = 0; static QPixmap* dis_menu_pix = 0; +static QPixmap* question_mark_pix = 0; + +/* XPM */ +static const char *question_mark[] = { +/* width height ncolors chars_per_pixel */ +"16 16 2 1", +/* colors */ +" c #000000", +"X c None", +/* pixels */ +"XXXXXXXXXXXXXXXX", +"XXXXX XXX", +"XXXX XXXXX XX", +"XXX XXXXXXX XX", +"XXX XXXXXXX XX", +"XXXXXXXXXXX XX", +"XXXXXXXXXX XXX", +"XXXXXXXXX XXXX", +"XXXXXXXX XXXXXX", +"XXXXXXX XXXXXXX", +"XXXXXXX XXXXXXX", +"XXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXX", +"XXXXXXX XXXXXXX", +"XXXXXXX XXXXXXX", +"XXXXXXXXXXXXXXXX" +}; + static bool pixmaps_created = FALSE; @@ -183,6 +211,8 @@ static void create_pixmaps() bitmap = QBitmap(16, 16, pindown_mask_bits, true); pindown_pix->setMask(bitmap); dis_pindown_pix->setMask(bitmap); + question_mark_pix = new QPixmap(question_mark ); + } @@ -220,11 +250,22 @@ StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name ) QSizePolicy::Minimum ); hb->addItem( titlebar ); + button[6] = 0; + if ( providesContextHelp() ) { + button[6] = new QToolButton( this ); + hb->addWidget( button[6] ); // help button + hb->addItem( new QSpacerItem( 5, 0, QSizePolicy::Fixed, QSizePolicy::Expanding ) ); + button[6]->setIconSet( *question_mark_pix ); + connect( button[6], SIGNAL( clicked() ), this, ( SLOT( contextHelp() ) ) ); + } + hb->addWidget( button[3] ); hb->addWidget( button[4] ); hb->addWidget( button[5] ); - for ( int i = 0; i < 6; i++) { + for ( int i = 0; i < 7; i++) { + if ( !button[i] ) + continue; button[i]->setBackgroundMode( PaletteBackground ); button[i]->setMouseTracking( TRUE ); button[i]->setFixedSize( 20, 20 ); @@ -250,6 +291,10 @@ StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name ) connect( button[4], SIGNAL( clicked(int) ), this, ( SLOT( maxButtonClicked(int) ) ) ); button[5]->setIconSet(isActive() ? *close_pix : *dis_close_pix); connect( button[5], SIGNAL( clicked() ), this, ( SLOT( closeWindow() ) ) ); + + if ( button[6] ) { + } + if ( isTransient() ) { // lighter decoration for transient windows diff --git a/stdclient.h b/stdclient.h index 99068ac362..221c8085d4 100644 --- a/stdclient.h +++ b/stdclient.h @@ -28,14 +28,14 @@ private slots: void maxButtonClicked( int ); private: - QToolButton* button[6]; + QToolButton* button[7]; QSpacerItem* titlebar; }; /* - Like QToolButton, but provides a clicked(int) signals that + Like QToolButton, but provides a clicked(int) signals that has the last pressed mouse button as argument */ class ThreeButtonButton: public QToolButton @@ -47,12 +47,12 @@ public: { connect( this, SIGNAL( clicked() ), this, SLOT( handleClicked() ) ); } - ~ThreeButtonButton () + ~ThreeButtonButton () {} signals: void clicked( int ); - + protected: void mousePressEvent( QMouseEvent* e ) { @@ -60,7 +60,7 @@ protected: QMouseEvent me ( e->type(), e->pos(), e->globalPos(), LeftButton, e->state() ); QToolButton::mousePressEvent( &me ); } - + void mouseReleaseEvent( QMouseEvent* e ) { QMouseEvent me ( e->type(), e->pos(), e->globalPos(), LeftButton, e->state() ); @@ -72,10 +72,10 @@ private slots: { emit clicked( last_button ); } - + private: int last_button; - + }; diff --git a/workspace.cpp b/workspace.cpp index 08825d731b..8f3527dd46 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "workspace.h" @@ -305,6 +306,22 @@ bool Workspace::workspaceEvent( XEvent * e ) return result; } break; + case EnterNotify: + if ( !QWhatsThis::inWhatsThisMode() ) + break; + { + QWidget* w = QWidget::find( e->xcrossing.window ); + if ( w && w->inherits("WindowWrapper" ) ) + QWhatsThis::leaveWhatsThisMode(); + } + break; + case LeaveNotify: + if ( !QWhatsThis::inWhatsThisMode() ) + break; + c = findClientWidthId( e->xcrossing.window ); + if ( c && e->xcrossing.detail != NotifyInferior ) + QWhatsThis::leaveWhatsThisMode(); + break; case ConfigureRequest: c = findClient( e->xconfigurerequest.window ); if ( c )