diff --git a/CMakeLists.txt b/CMakeLists.txt index 4962190ddd..84797e5a60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ qt4_add_dbus_interface( kwin_KDEINIT_SRCS qt4_add_resources( kwin_KDEINIT_SRCS resources.qrc ) -set(kwinLibs ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTDECLARATIVE_LIBRARY} ${KDECLARATIVE_LIBRARIES} kdecorations kwineffects ${X11_LIBRARIES} ${X11_Xrandr_LIB} ${X11_Xdamage_LIB} ${X11_Xrender_LIB} ${X11_Xfixes_LIB} ${XCB_XCB_LIBRARIES} ${X11_XCB_LIBRARIES} ${XCB_XFIXES_LIBRARIES} ${XCB_DAMAGE_LIBRARIES} ${XCB_COMPOSITE_LIBRARIES} ${XCB_SHAPE_LIBRARIES} ${XCB_SYNC_LIBRARIES} ${XCB_RENDER_LIBRARIES} ${XCB_RANDR_LIBRARIES}) +set(kwinLibs ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTDECLARATIVE_LIBRARY} ${KDECLARATIVE_LIBRARIES} kdecorations kwineffects ${X11_LIBRARIES} ${X11_Xcursor_LIB} ${X11_Xrandr_LIB} ${X11_Xdamage_LIB} ${X11_Xrender_LIB} ${X11_Xfixes_LIB} ${XCB_XCB_LIBRARIES} ${X11_XCB_LIBRARIES} ${XCB_XFIXES_LIBRARIES} ${XCB_DAMAGE_LIBRARIES} ${XCB_COMPOSITE_LIBRARIES} ${XCB_SHAPE_LIBRARIES} ${XCB_SYNC_LIBRARIES} ${XCB_RENDER_LIBRARIES} ${XCB_RANDR_LIBRARIES} ${XCB_KEYSYMS_LIBRARIES}) find_library(XF86VM_LIBRARY Xxf86vm) if (XF86VM_LIBRARY) diff --git a/events.cpp b/events.cpp index 825ccfed18..c960a0ccc1 100644 --- a/events.cpp +++ b/events.cpp @@ -57,6 +57,7 @@ along with this program. If not, see . #include #include "composite.h" +#include "killwindow.h" namespace KWin { @@ -233,6 +234,12 @@ bool Workspace::workspaceEvent(XEvent * e) && (e->type == KeyPress || e->type == KeyRelease)) return false; // let Qt process it, it'll be intercepted again in eventFilter() + if (!m_windowKiller.isNull() && m_windowKiller->isActive() && m_windowKiller->isResponsibleForEvent(e->type)) { + m_windowKiller->processEvent(e); + // filter out the event + return true; + } + if (e->type == PropertyNotify || e->type == ClientMessage) { unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ]; rootInfo->event(e, dirty, NETRootInfo::PROPERTIES_SIZE); diff --git a/killwindow.cpp b/killwindow.cpp index 57e15e525a..8aec222594 100644 --- a/killwindow.cpp +++ b/killwindow.cpp @@ -4,6 +4,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak +Copyright (C) 2012 Martin Gräßlin 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 @@ -18,23 +19,21 @@ 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, see . *********************************************************************/ - -//#ifndef QT_CLEAN_NAMESPACE -//#define QT_CLEAN_NAMESPACE -//#endif #include "killwindow.h" +#include "workspace.h" +// Qt #include -#include -#include -#include +// XLib #include -#include +#include +// XCB +#include namespace KWin { -KillWindow::KillWindow(Workspace* ws) - : workspace(ws) +KillWindow::KillWindow() + : m_active(false) { } @@ -44,71 +43,152 @@ KillWindow::~KillWindow() void KillWindow::start() { - static Cursor kill_cursor = 0; - if (!kill_cursor) - kill_cursor = XCreateFontCursor(display(), XC_pirate); + static xcb_cursor_t kill_cursor = XCB_CURSOR_NONE; + if (kill_cursor == XCB_CURSOR_NONE) { + kill_cursor = createCursor(); + } + if (m_active) { + return; + } + m_active = true; - if (XGrabPointer(display(), rootWindow(), False, - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | - EnterWindowMask | LeaveWindowMask, - GrabModeAsync, GrabModeAsync, None, - kill_cursor, CurrentTime) == GrabSuccess) { - grabXKeyboard(); + xcb_connection_t *c = connection(); + ScopedCPointer grabPointer(xcb_grab_pointer_reply(c, xcb_grab_pointer_unchecked(c, false, rootWindow(), + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_POINTER_MOTION | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, + kill_cursor, XCB_TIME_CURRENT_TIME), NULL)); + if (grabPointer.isNull() || grabPointer->status != XCB_GRAB_STATUS_SUCCESS) { + return; + } + grabXKeyboard(); + grabXServer(); +} - XEvent ev; - int return_pressed = 0; - int escape_pressed = 0; - int button_released = 0; +xcb_cursor_t KillWindow::createCursor() +{ + // XCursor is an XLib only lib + const char *theme = XcursorGetTheme(display()); + const int size = XcursorGetDefaultSize(display()); + XcursorImage *ximg = XcursorLibraryLoadImage("pirate", theme, size); + if (ximg) { + xcb_cursor_t cursor = XcursorImageLoadCursor(display(), ximg); + XcursorImageDestroy(ximg); + return cursor; + } + // fallback on font + xcb_connection_t *c = connection(); + const xcb_font_t cursorFont = xcb_generate_id(c); + xcb_open_font(c, cursorFont, strlen ("cursor"), "cursor"); + xcb_cursor_t cursor = xcb_generate_id(c); + xcb_create_glyph_cursor(c, cursor, cursorFont, cursorFont, + XC_pirate, /* source character glyph */ + XC_pirate + 1, /* mask character glyph */ + 0, 0, 0, 0, 0, 0); /* r b g r b g */ + return cursor; +} - grabXServer(); - - while (!return_pressed && !escape_pressed && !button_released) { - XMaskEvent(display(), KeyPressMask | ButtonPressMask | - ButtonReleaseMask | PointerMotionMask, &ev); - - if (ev.type == KeyPress) { - int kc = XKeycodeToKeysym(display(), ev.xkey.keycode, 0); - int mx = 0; - int my = 0; - return_pressed = (kc == XK_Return) || (kc == XK_space); - escape_pressed = (kc == XK_Escape); - if (kc == XK_Left) mx = -10; - if (kc == XK_Right) mx = 10; - if (kc == XK_Up) my = -10; - if (kc == XK_Down) my = 10; - if (ev.xkey.state & ControlMask) { - mx /= 10; - my /= 10; - } - QCursor::setPos(cursorPos() + QPoint(mx, my)); - } - - if (ev.type == ButtonRelease) { - button_released = (ev.xbutton.button == Button1); - if (ev.xbutton.button == Button3) { - escape_pressed = true; - break; - } - if (ev.xbutton.button == Button1 || ev.xbutton.button == Button2) - workspace->killWindowId(ev.xbutton.subwindow); - } - continue; - } - if (return_pressed) { - Window root, child; - int dummy1, dummy2, dummy3, dummy4; - unsigned int dummy5; - if (XQueryPointer(display(), rootWindow(), &root, &child, - &dummy1, &dummy2, &dummy3, &dummy4, &dummy5) == true - && child != None) - workspace->killWindowId(child); - } - - ungrabXServer(); - ungrabXKeyboard(); - XUngrabPointer(display(), CurrentTime); +bool KillWindow::isResponsibleForEvent(int eventType) const +{ + switch (eventType) { + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: + case XCB_MOTION_NOTIFY: + case XCB_ENTER_NOTIFY: + case XCB_LEAVE_NOTIFY: + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE: + case XCB_FOCUS_IN: + case XCB_FOCUS_OUT: + return true; + default: + return false; } } +void KillWindow::processEvent(XEvent *event) +{ + if (event->type == XCB_BUTTON_RELEASE) { + handleButtonRelease(event->xbutton.button, event->xbutton.subwindow); + } else if (event->type == XCB_KEY_PRESS) { + handleKeyPress(event->xkey.keycode, event->xkey.state); + } +} + +void KillWindow::processEvent(xcb_generic_event_t *event) +{ + if (event->response_type == XCB_BUTTON_RELEASE) { + xcb_button_release_event_t *buttonEvent = reinterpret_cast(event); + handleButtonRelease(buttonEvent->detail, buttonEvent->child); + } else if (event->response_type == XCB_KEY_PRESS) { + xcb_key_press_event_t *keyEvent = reinterpret_cast(event); + handleKeyPress(keyEvent->detail, keyEvent->state); + } +} + +void KillWindow::handleButtonRelease(xcb_button_t button, xcb_window_t window) +{ + if (button == XCB_BUTTON_INDEX_3) { + release(); + return; + } + if (button == XCB_BUTTON_INDEX_1 || button == XCB_BUTTON_INDEX_2) { + Workspace::self()->killWindowId(window); + release(); + return; + } +} + +void KillWindow::handleKeyPress(xcb_keycode_t keycode, uint16_t state) +{ + xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(connection()); + xcb_keysym_t kc = xcb_key_symbols_get_keysym(symbols, keycode, 0); + int mx = 0; + int my = 0; + const bool returnPressed = (kc == XK_Return) || (kc == XK_space); + const bool escapePressed = (kc == XK_Escape); + if (kc == XK_Left) { + mx = -10; + } + if (kc == XK_Right) { + mx = 10; + } + if (kc == XK_Up) { + my = -10; + } + if (kc == XK_Down) { + my = 10; + } + if (state & XCB_MOD_MASK_CONTROL) { + mx /= 10; + my /= 10; + } + QCursor::setPos(cursorPos() + QPoint(mx, my)); + if (returnPressed) { + performKill(); + } + if (returnPressed || escapePressed) { + release(); + } + xcb_key_symbols_free(symbols); +} + +void KillWindow::performKill() +{ + xcb_connection_t *c = connection(); + ScopedCPointer pointer(xcb_query_pointer_reply(c, xcb_query_pointer_unchecked(c, rootWindow()), NULL)); + if (!pointer.isNull() && pointer->child != XCB_WINDOW_NONE) { + Workspace::self()->killWindowId(pointer->child); + } +} + +void KillWindow::release() +{ + ungrabXKeyboard(); + xcb_ungrab_pointer(connection(), XCB_TIME_CURRENT_TIME); + ungrabXServer(); + m_active = false; +} + } // namespace diff --git a/killwindow.h b/killwindow.h index 585331ade4..0c09d84c98 100644 --- a/killwindow.h +++ b/killwindow.h @@ -4,6 +4,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak +Copyright (C) 2012 Martin Gräßlin 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 @@ -22,7 +23,9 @@ along with this program. If not, see . #ifndef KWIN_KILLWINDOW_H #define KWIN_KILLWINDOW_H -#include "workspace.h" +#include + +typedef union _XEvent XEvent; namespace KWin { @@ -31,13 +34,25 @@ class KillWindow { public: - KillWindow(Workspace* ws); + KillWindow(); ~KillWindow(); void start(); + bool isActive() const { + return m_active; + } + bool isResponsibleForEvent(int eventType) const; + // TODO: remove once event handling is ported to XCB + void processEvent(XEvent *event); + void processEvent(xcb_generic_event_t *event); private: - Workspace* workspace; + xcb_cursor_t createCursor(); + void release(); + void performKill(); + void handleKeyPress(xcb_keycode_t keycode, uint16_t state); + void handleButtonRelease(xcb_button_t button, xcb_window_t window); + bool m_active; }; } // namespace diff --git a/useractions.cpp b/useractions.cpp index 4824897e63..394be8f7f7 100755 --- a/useractions.cpp +++ b/useractions.cpp @@ -1562,8 +1562,10 @@ void Workspace::slotUntab() */ void Workspace::slotKillWindow() { - KillWindow kill(this); - kill.start(); + if (m_windowKiller.isNull()) { + m_windowKiller.reset(new KillWindow()); + } + m_windowKiller->start(); } /*! diff --git a/workspace.h b/workspace.h index 3c07569767..0269c0328e 100644 --- a/workspace.h +++ b/workspace.h @@ -42,6 +42,7 @@ along with this program. If not, see . #include "kdecoration.h" #include "kdecorationfactory.h" #include "sm.h" +#include "killwindow.h" #include @@ -726,6 +727,8 @@ private: Scripting *m_scripting; + QScopedPointer m_windowKiller; + private: friend bool performTransiencyCheck(); };