From 3a0e22ebe32d9f40f20cee4079bf5b06948ba944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Wed, 8 Nov 2006 13:59:27 +0000 Subject: [PATCH] Ok, with a compositing manager running, VisibilityNotify no longer considers windows not visible just because a window is above them, so the code from r198017 no longer works. (#128648) svn path=/trunk/KDE/kdebase/workspace/; revision=603295 --- client.cpp | 1 - client.h | 146 ++++++++++++++++++++++++++++++++++++++------------ events.cpp | 140 +++++------------------------------------------ layers.cpp | 4 ++ workspace.cpp | 100 ++++++++++------------------------ 5 files changed, 156 insertions(+), 235 deletions(-) diff --git a/client.cpp b/client.cpp index b5492ad06f..705589c8e3 100644 --- a/client.cpp +++ b/client.cpp @@ -124,7 +124,6 @@ Client::Client( Workspace *ws ) modal = false; noborder = false; user_noborder = false; - not_obscured = false; urgency = false; ignore_focus_stealing = false; demands_attention = false; diff --git a/client.h b/client.h index 4488980755..3ce5563bb6 100644 --- a/client.h +++ b/client.h @@ -28,7 +28,6 @@ License. See the file "COPYING" for the exact licensing terms. #include "workspace.h" #include "kdecoration.h" #include "rules.h" -#include "toplevel.h" class QTimer; class KProcess; @@ -43,8 +42,7 @@ class WinInfo; class SessionInfo; class Bridge; -class Client - : public Toplevel +class Client : public QObject, public KDecorationDefines { Q_OBJECT public: @@ -54,6 +52,7 @@ class Client Window wrapperId() const; Window decorationId() const; + Workspace* workspace() const; const Client* transientFor() const; Client* transientFor(); bool isTransient() const; @@ -67,20 +66,23 @@ class Client const Group* group() const; Group* group(); void checkGroup( Group* gr = NULL, bool force = false ); + // prefer isXXX() instead + NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const; const WindowRules* rules() const; void removeRule( Rules* r ); void setupWindowRules( bool ignore_temporary ); void applyWindowRules(); - virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const; - // returns true for "special" windows and false for windows which are "normal" - // (normal=window which has a border, can be moved by the user, can be closed, etc.) - // true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now) - // false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO - bool isSpecialWindow() const; - bool hasNETSupport() const; + QRect geometry() const; + QSize size() const; QSize minSize() const; QSize maxSize() const; + QPoint pos() const; + QRect rect() const; + int x() const; + int y() const; + int width() const; + int height() const; QPoint clientPos() const; // inside of geometry() QSize clientSize() const; @@ -163,9 +165,24 @@ class Client // auxiliary functions, depend on the windowType bool wantsTabFocus() const; bool wantsInput() const; + bool hasNETSupport() const; + bool isMovable() const; + bool isDesktop() const; + bool isDock() const; + bool isToolbar() const; + bool isTopMenu() const; + bool isMenu() const; + bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient' + bool isDialog() const; + bool isSplash() const; + bool isUtility() const; + // returns true for "special" windows and false for windows which are "normal" + // (normal=window which has a border, can be moved by the user, can be closed, etc.) + // true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now) + // false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO + bool isSpecialWindow() const; bool isResizable() const; - bool isMovable() const; bool isCloseable() const; // may be closed by the user (may have a close button) void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h) @@ -178,10 +195,9 @@ class Client void updateDecoration( bool check_workspace_pos, bool force = false ); void checkBorderSizes(); + // shape extensions + bool shape() const; void updateShape(); - - virtual double opacity() const; - void setOpacity( double opacity ); void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet ); void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet ); @@ -271,15 +287,6 @@ class Client void checkActiveModal(); bool hasStrut() const; - bool isMove() const - { - return moveResizeMode && mode == PositionCenter; - } - bool isResize() const - { - return moveResizeMode && mode != PositionCenter; - } - private slots: void autoRaise(); void shadeHover(); @@ -313,7 +320,6 @@ class Client void clientMessageEvent( XClientMessageEvent* e ); void enterNotifyEvent( XCrossingEvent* e ); void leaveNotifyEvent( XCrossingEvent* e ); - void visibilityNotifyEvent( XVisibilityEvent* e ); void focusInEvent( XFocusInEvent* e ); void focusOutEvent( XFocusOutEvent* e ); @@ -323,9 +329,6 @@ class Client void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root ); - protected: - virtual void debug( kdbgstream& stream ) const; - private slots: void pingTimeout(); void processKillerExited(); @@ -396,10 +399,12 @@ class Client Time readUserCreationTime() const; static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack ); void startupIdChanged(); - + Window client; Window wrapper; + Window frame; KDecoration* decoration; + Workspace* wspace; Bridge* bridge; int desk; bool buttonDown; @@ -407,6 +412,14 @@ class Client bool move_faked_activity; Window move_resize_grab_window; bool unrestrictedMoveResize; + bool isMove() const + { + return moveResizeMode && mode == PositionCenter; + } + bool isResize() const + { + return moveResizeMode && mode != PositionCenter; + } Position mode; QPoint moveOffset; @@ -432,6 +445,7 @@ class Client uint active :1; uint deleting : 1; // true when doing cleanup and destroying the client uint keep_above : 1; // NET::KeepAbove (was stays_on_top) + uint is_shape :1; uint skip_taskbar :1; uint original_skip_taskbar :1; // unaffected by KWin uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol? @@ -451,7 +465,6 @@ class Client uint modal : 1; // NET::Modal uint noborder : 1; uint user_noborder : 1; - uint not_obscured : 1; uint urgency : 1; // XWMHints, UrgencyHint uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client uint demands_attention : 1; @@ -489,6 +502,7 @@ class Client Time ping_timestamp; Time user_time; unsigned long allowed_actions; + QRect frame_geometry; QSize client_size; int postpone_geometry_updates; // >0 - new geometry is remembered, but not actually set bool pending_geometry_update; @@ -541,7 +555,7 @@ inline Window Client::window() const inline Window Client::frameId() const { - return handle(); + return frame; } inline Window Client::wrapperId() const @@ -554,6 +568,11 @@ inline Window Client::decorationId() const return decoration != NULL ? decoration->widget()->winId() : None; } +inline Workspace* Client::workspace() const + { + return wspace; + } + inline const Client* Client::transientFor() const { return transient_for; @@ -709,6 +728,12 @@ inline bool Client::keepBelow() const return keep_below; } +inline bool Client::shape() const + { + return is_shape; + } + + inline bool Client::isFullScreen() const { return fullscreen_mode != FullScreenNone; @@ -764,6 +789,46 @@ inline QByteArray Client::windowRole() const return window_role; } +inline QRect Client::geometry() const + { + return frame_geometry; + } + +inline QSize Client::size() const + { + return frame_geometry.size(); + } + +inline QPoint Client::pos() const + { + return frame_geometry.topLeft(); + } + +inline int Client::x() const + { + return frame_geometry.x(); + } + +inline int Client::y() const + { + return frame_geometry.y(); + } + +inline int Client::width() const + { + return frame_geometry.width(); + } + +inline int Client::height() const + { + return frame_geometry.height(); + } + +inline QRect Client::rect() const + { + return QRect( 0, 0, width(), height()); + } + inline QPoint Client::clientPos() const { return QPoint( border_left, border_top ); @@ -809,7 +874,7 @@ inline const WindowRules* Client::rules() const return &client_rules; } -KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, Client, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl )); +KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl )); inline Window Client::moveResizeGrabWindow() const { @@ -826,9 +891,22 @@ inline void Client::removeRule( Rules* rule ) client_rules.remove( rule ); } -KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Client, Window, cl->window() == value ); -KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Client, Window, cl->frameId() == value ); -KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value ); +#ifdef NDEBUG +inline +kndbgstream& operator<<( kndbgstream& stream, const Client* ) { return stream; } +inline +kndbgstream& operator<<( kndbgstream& stream, const ClientList& ) { return stream; } +inline +kndbgstream& operator<<( kndbgstream& stream, const ConstClientList& ) { return stream; } +#else +kdbgstream& operator<<( kdbgstream& stream, const Client* ); +kdbgstream& operator<<( kdbgstream& stream, const ClientList& ); +kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& ); +#endif + +KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Window, cl->window() == value ); +KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Window, cl->frameId() == value ); +KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Window, cl->wrapperId() == value ); } // namespace diff --git a/events.cpp b/events.cpp index 3e7024c580..288398eab8 100644 --- a/events.cpp +++ b/events.cpp @@ -21,8 +21,6 @@ License. See the file "COPYING" for the exact licensing terms. #include "tabbox.h" #include "group.h" #include "rules.h" -#include "unmanaged.h" -#include "scene.h" #include #include @@ -264,11 +262,6 @@ bool Workspace::workspaceEvent( XEvent * e ) if( c->windowEvent( e )) return true; } - else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( e->xany.window ))) - { - if( c->windowEvent( e )) - return true; - } else { Window special = findSpecialEventWindow( e ); @@ -326,8 +319,13 @@ bool Workspace::workspaceEvent( XEvent * e ) } return true; } + return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt } + case MapNotify: + + return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt + case ReparentNotify: { //do not confuse Qt with these events. After all, _we_ are the @@ -377,19 +375,6 @@ bool Workspace::workspaceEvent( XEvent * e ) } break; } - case MapNotify: - { - if( e->xmap.override_redirect ) - { - Unmanaged* c = findUnmanaged( HandleMatchPredicate( e->xmap.window )); - if( c == NULL ) - c = createUnmanaged( e->xmap.window ); - if( c ) - return c->windowEvent( e ); - } - return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt - } - case EnterNotify: { if ( QWhatsThis::inWhatsThisMode() ) @@ -470,10 +455,6 @@ bool Workspace::workspaceEvent( XEvent * e ) XRefreshKeyboardMapping( &e->xmapping ); tab_box->updateKeyMapping(); break; - case Expose: - if( e->xexpose.window == rootWindow() && compositing()) // root window needs repainting - addDamage( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height ); - break; default: break; } @@ -570,19 +551,6 @@ bool Client::windowEvent( XEvent* e ) if( demandAttentionKNotifyTimer != NULL ) demandAttentionKNotify(); } - if( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2Opacity ) - { - if( compositing()) - { - addDamageFull(); - scene->windowOpacityChanged( this ); - } - else - { // forward to the frame if there's possibly another compositing manager running - NETWinInfo i( display(), frameId(), rootWindow(), 0 ); - i.setOpacity( info->opacity()); - } - } } // TODO move all focus handling stuff to separate file? @@ -663,23 +631,15 @@ bool Client::windowEvent( XEvent* e ) workspace()->updateColormap(); } break; - case VisibilityNotify: - visibilityNotifyEvent( &e->xvisibility ); - break; default: if( e->xany.window == window()) + { + if( e->type == Shape::shapeEvent() ) { - if( e->type == Extensions::shapeNotifyEvent() ) - { - detectShape( window()); // workaround for #19644 - updateShape(); - } - } - if( e->xany.window == frameId()) - { - if( e->type == Extensions::damageNotifyEvent()) - damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e )); + is_shape = Shape::hasShape( window()); // workaround for #19644 + updateShape(); } + } break; } return true; // eat all events @@ -1048,18 +1008,13 @@ void Client::ungrabButton( int modifier ) */ void Client::updateMouseGrab() { - if( workspace()->globalShortcutsDisabled()) - { - XUngrabButton( display(), AnyButton, AnyModifier, wrapperId()); - // keep grab for the simple click without modifiers if needed - if( !( !options->clickRaise || not_obscured )) - grabButton( None ); - return; - } if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab() { // remove the grab for no modifiers only if the window // is unobscured or if the user doesn't want click raise + // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is + // the most recently raised window) + bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true ) == this; if( !options->clickRaise || not_obscured ) ungrabButton( None ); else @@ -1494,17 +1449,6 @@ void Client::focusOutEvent( XFocusOutEvent* e ) setActive( false ); } -void Client::visibilityNotifyEvent( XVisibilityEvent * e) - { - if( e->window != frameId()) - return; // care only about the whole frame - bool new_not_obscured = e->state == VisibilityUnobscured; - if( not_obscured == new_not_obscured ) - return; - not_obscured = new_not_obscured; - updateMouseGrab(); - } - // performs _NET_WM_MOVERESIZE void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction ) { @@ -1599,64 +1543,6 @@ void Client::keyPressEvent( uint key_code ) QCursor::setPos( pos ); } -// **************************************** -// Unmanaged -// **************************************** - -bool Unmanaged::windowEvent( XEvent* e ) - { - unsigned long dirty[ 2 ]; - info->event( e, dirty, 2 ); // pass through the NET stuff - if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity ) - { - scene->windowOpacityChanged( this ); - addDamageFull(); - } - switch (e->type) - { - case UnmapNotify: - unmapNotifyEvent( &e->xunmap ); - break; - case MapNotify: - mapNotifyEvent( &e->xmap ); - break; - case ConfigureNotify: - configureNotifyEvent( &e->xconfigure ); - break; - default: - { - if( e->type == Extensions::shapeNotifyEvent() ) - { - detectShape( handle()); - if( scene != NULL ) - scene->windowGeometryShapeChanged( this ); - } - if( e->type == Extensions::damageNotifyEvent()) - damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e )); - break; - } - } - return false; // don't eat events, even our own unmanaged widgets are tracked - } - -void Unmanaged::mapNotifyEvent( XMapEvent* ) - { - } - -void Unmanaged::unmapNotifyEvent( XUnmapEvent* ) - { - release(); - } - -void Unmanaged::configureNotifyEvent( XConfigureEvent* e ) - { - // TODO add damage only if the window is not obscured - workspace()->addDamage( geometry()); - geom = QRect( e->x, e->y, e->width, e->height ); - // TODO maybe only damage changed area - addDamageFull(); - } - // **************************************** // Group // **************************************** diff --git a/layers.cpp b/layers.cpp index 5f4c7806e5..3bd0902f9c 100644 --- a/layers.cpp +++ b/layers.cpp @@ -116,7 +116,11 @@ void Workspace::updateStackingOrder( bool propagate_new_clients ) } #endif if( changed || propagate_new_clients ) + { propagateClients( propagate_new_clients ); + if( active_client ) + active_client->updateMouseGrab(); + } } /*! diff --git a/workspace.cpp b/workspace.cpp index 24a075d936..67860b12d0 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -42,9 +42,6 @@ License. See the file "COPYING" for the exact licensing terms. #include "group.h" #include "rules.h" #include "kwinadaptor.h" -#include "unmanaged.h" -#include "scene.h" -#include "effects.h" #include #include @@ -125,9 +122,7 @@ Workspace::Workspace( bool restore ) topmenu_space( NULL ), set_active_client_recursion( 0 ), block_stacking_updates( 0 ), - forced_global_mouse_grab( false ), - damage_region( None ), - overlay( None ) + forced_global_mouse_grab( false ) { new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this ); @@ -171,12 +166,10 @@ Workspace::Workspace( bool restore ) ColormapChangeMask | SubstructureRedirectMask | SubstructureNotifyMask | - FocusChangeMask | // for NotifyDetailNone - ExposureMask + FocusChangeMask // for NotifyDetailNone ); - Extensions::init(); - setupCompositing(); + Shape::init(); // compatibility long data = 1; @@ -325,7 +318,6 @@ void Workspace::init() connect(&reconfigureTimer, SIGNAL(timeout()), this, SLOT(slotReconfigure())); connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows())); - connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing())); connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this, SLOT(slotReconfigure())); @@ -363,11 +355,7 @@ void Workspace::init() XWindowAttributes attr; XGetWindowAttributes(display(), wins[i], &attr); if (attr.override_redirect ) - { - if( attr.map_state != IsUnmapped && attr.c_class != InputOnly && compositing()) - createUnmanaged( wins[ i ] ); continue; - } if( topmenu_space && topmenu_space->winId() == wins[ i ] ) continue; if (attr.map_state != IsUnmapped) @@ -430,7 +418,6 @@ void Workspace::init() Workspace::~Workspace() { - finishCompositing(); blockStackingUpdates( true ); // TODO grabXServer(); // use stacking_order, so that kwin --replace keeps stacking order @@ -442,10 +429,6 @@ Workspace::~Workspace() (*it)->releaseWindow( true ); // no removeClient() is called ! } - for( UnmanagedList::ConstIterator it = unmanaged.begin(); - it != unmanaged.end(); - ++it ) - (*it)->release(); delete desktop_widget; delete tab_box; delete popupinfo; @@ -489,28 +472,6 @@ Client* Workspace::createClient( Window w, bool is_mapped ) return NULL; } addClient( c, Allowed ); - if( scene ) - scene->windowAdded( c ); - if( effects ) - effects->windowAdded( c ); - return c; - } - -Unmanaged* Workspace::createUnmanaged( Window w ) - { - if( w == overlay ) - return NULL; - Unmanaged* c = new Unmanaged( this ); - if( !c->track( w )) - { - Unmanaged::deleteUnmanaged( c, Allowed ); - return NULL; - } - addUnmanaged( c, Allowed ); - if( scene ) - scene->windowAdded( c ); - if( effects ) - effects->windowAdded( c ); return c; } @@ -553,11 +514,6 @@ void Workspace::addClient( Client* c, allowed_t ) updateToolWindows( true ); } -void Workspace::addUnmanaged( Unmanaged* c, allowed_t ) - { - unmanaged.append( c ); - } - /* Destroys the client \a c */ @@ -577,10 +533,6 @@ void Workspace::removeClient( Client* c, allowed_t ) Notify::raise( Notify::Delete ); Q_ASSERT( clients.contains( c ) || desktops.contains( c )); - if( scene ) - scene->windowDeleted( c ); - if( effects ) - effects->windowDeleted( c ); clients.removeAll( c ); desktops.removeAll( c ); unconstrained_stacking_order.removeAll( c ); @@ -616,16 +568,6 @@ void Workspace::removeClient( Client* c, allowed_t ) updateClientArea(); } -void Workspace::removeUnmanaged( Unmanaged* c, allowed_t ) - { - assert( unmanaged.contains( c )); - if( scene ) - scene->windowDeleted( c ); - if( effects ) - effects->windowDeleted( c ); - unmanaged.removeAll( c ); - } - void Workspace::updateFocusChains( Client* c, FocusChainChange change ) { if( !c->wantsTabFocus()) // doesn't want tab focus, remove @@ -651,7 +593,13 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) focus_chain[ i ].prepend( c ); } else if( !focus_chain[ i ].contains( c )) - focus_chain[ i ].prepend( c ); // otherwise add as the last one + { // add it after the active one + if( active_client != NULL && active_client != c + && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client ) + focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c ); + else + focus_chain[ i ].append( c ); // otherwise add as the first one + } } } else //now only on desktop, remove it anywhere else @@ -671,7 +619,13 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) focus_chain[ i ].prepend( c ); } else if( !focus_chain[ i ].contains( c )) - focus_chain[ i ].prepend( c ); + { // add it after the active one + if( active_client != NULL && active_client != c + && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client ) + focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c ); + else + focus_chain[ i ].append( c ); // otherwise add as the first one + } } else focus_chain[ i ].removeAll( c ); @@ -688,7 +642,13 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) global_focus_chain.prepend( c ); } else if( !global_focus_chain.contains( c )) - global_focus_chain.prepend( c ); + { // add it after the active one + if( active_client != NULL && active_client != c + && !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client ) + global_focus_chain.insert( global_focus_chain.size() - 1, c ); + else + global_focus_chain.append( c ); // otherwise add as the first one + } } void Workspace::updateCurrentTopMenu() @@ -922,7 +882,7 @@ void Workspace::slotSettingsChanged(int category) /*! Reread settings */ -KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() ); +KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); void Workspace::slotReconfigure() { @@ -979,11 +939,6 @@ void Workspace::slotReconfigure() updateTopMenuGeometry(); updateCurrentTopMenu(); } - - if( options->useTranslucency ) - setupCompositing(); - else - finishCompositing(); loadWindowRules(); for( ClientList::Iterator it = clients.begin(); @@ -1685,7 +1640,7 @@ void Workspace::slotGrabWindow() QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() ); //No XShape - no work. - if( Extensions::shapeAvailable()) + if( Shape::available()) { //As the first step, get the mask from XShape. int count, order; @@ -2038,8 +1993,7 @@ void Workspace::createBorderWindows() XSetWindowAttributes attributes; unsigned long valuemask; attributes.override_redirect = True; - attributes.event_mask = (EnterWindowMask | LeaveWindowMask | - VisibilityChangeMask); + attributes.event_mask = ( EnterWindowMask | LeaveWindowMask ); valuemask= (CWOverrideRedirect | CWEventMask | CWCursor ); attributes.cursor = XCreateFontCursor(display(), XC_sb_up_arrow);