Changeset View
Changeset View
Standalone View
Standalone View
killwindow.cpp
- This file was copied to plugins/platforms/x11/standalone/windowselector.cpp.
Show All 15 Lines | |||||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | 17 | GNU General Public License for more details. | ||
18 | 18 | | |||
19 | You should have received a copy of the GNU General Public License | 19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | *********************************************************************/ | 21 | *********************************************************************/ | ||
22 | #include "killwindow.h" | 22 | #include "killwindow.h" | ||
23 | #include "client.h" | 23 | #include "client.h" | ||
24 | #include "cursor.h" | 24 | #include "main.h" | ||
25 | #include "workspace.h" | 25 | #include "platform.h" | ||
26 | #include "xcbutils.h" | 26 | #include "unmanaged.h" | ||
27 | // XLib | | |||
28 | #include <X11/cursorfont.h> | | |||
29 | #include <X11/Xutil.h> | | |||
30 | #include <fixx11h.h> | | |||
31 | // XCB | | |||
32 | #include <xcb/xcb_keysyms.h> | | |||
33 | 27 | | |||
34 | namespace KWin | 28 | namespace KWin | ||
35 | { | 29 | { | ||
36 | 30 | | |||
37 | KillWindow::KillWindow() | 31 | KillWindow::KillWindow() | ||
38 | : X11EventFilter(QVector<int>{XCB_BUTTON_PRESS, | | |||
39 | XCB_BUTTON_RELEASE, | | |||
40 | XCB_MOTION_NOTIFY, | | |||
41 | XCB_ENTER_NOTIFY, | | |||
42 | XCB_LEAVE_NOTIFY, | | |||
43 | XCB_KEY_PRESS, | | |||
44 | XCB_KEY_RELEASE, | | |||
45 | XCB_FOCUS_IN, | | |||
46 | XCB_FOCUS_OUT | | |||
47 | }) | | |||
48 | , m_active(false) | | |||
49 | { | 32 | { | ||
50 | } | 33 | } | ||
51 | 34 | | |||
52 | KillWindow::~KillWindow() | 35 | KillWindow::~KillWindow() | ||
53 | { | 36 | { | ||
54 | } | 37 | } | ||
55 | 38 | | |||
56 | void KillWindow::start() | 39 | void KillWindow::start() | ||
57 | { | 40 | { | ||
58 | static xcb_cursor_t kill_cursor = XCB_CURSOR_NONE; | 41 | kwinApp()->platform()->startInteractiveWindowSelection( | ||
59 | if (kill_cursor == XCB_CURSOR_NONE) { | 42 | [] (KWin::Toplevel *t) { | ||
60 | kill_cursor = createCursor(); | 43 | if (!t) { | ||
61 | } | | |||
62 | if (m_active) { | | |||
63 | return; | | |||
64 | } | | |||
65 | | ||||
66 | xcb_connection_t *c = connection(); | | |||
67 | ScopedCPointer<xcb_grab_pointer_reply_t> grabPointer(xcb_grab_pointer_reply(c, xcb_grab_pointer_unchecked(c, false, rootWindow(), | | |||
68 | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | | | |||
69 | XCB_EVENT_MASK_POINTER_MOTION | | | |||
70 | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW, | | |||
71 | XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, | | |||
72 | kill_cursor, XCB_TIME_CURRENT_TIME), NULL)); | | |||
73 | if (grabPointer.isNull() || grabPointer->status != XCB_GRAB_STATUS_SUCCESS) { | | |||
74 | return; | 44 | return; | ||
75 | } | 45 | } | ||
76 | m_active = grabXKeyboard(); | 46 | if (Client *c = qobject_cast<Client*>(t)) { | ||
77 | if (!m_active) { | 47 | c->killWindow(); | ||
78 | xcb_ungrab_pointer(connection(), XCB_TIME_CURRENT_TIME); | 48 | } else if (Unmanaged *u = qobject_cast<Unmanaged*>(t)) { | ||
79 | return; | 49 | xcb_kill_client(connection(), u->window()); | ||
80 | } | | |||
81 | grabXServer(); | | |||
82 | } | | |||
83 | | ||||
84 | xcb_cursor_t KillWindow::createCursor() | | |||
85 | { | | |||
86 | xcb_cursor_t cursor = Cursor::x11Cursor(QByteArrayLiteral("pirate")); | | |||
87 | if (cursor != XCB_CURSOR_NONE) { | | |||
88 | return cursor; | | |||
89 | } | | |||
90 | // fallback on font | | |||
91 | xcb_connection_t *c = connection(); | | |||
92 | const xcb_font_t cursorFont = xcb_generate_id(c); | | |||
93 | xcb_open_font(c, cursorFont, strlen ("cursor"), "cursor"); | | |||
94 | cursor = xcb_generate_id(c); | | |||
95 | xcb_create_glyph_cursor(c, cursor, cursorFont, cursorFont, | | |||
96 | XC_pirate, /* source character glyph */ | | |||
97 | XC_pirate + 1, /* mask character glyph */ | | |||
98 | 0, 0, 0, 0, 0, 0); /* r b g r b g */ | | |||
99 | return cursor; | | |||
100 | } | | |||
101 | | ||||
102 | void KillWindow::processEvent(xcb_generic_event_t *event) | | |||
103 | { | | |||
104 | if (event->response_type == XCB_BUTTON_RELEASE) { | | |||
105 | xcb_button_release_event_t *buttonEvent = reinterpret_cast<xcb_button_release_event_t*>(event); | | |||
106 | handleButtonRelease(buttonEvent->detail, buttonEvent->child); | | |||
107 | } else if (event->response_type == XCB_KEY_PRESS) { | | |||
108 | xcb_key_press_event_t *keyEvent = reinterpret_cast<xcb_key_press_event_t*>(event); | | |||
109 | handleKeyPress(keyEvent->detail, keyEvent->state); | | |||
110 | } | | |||
111 | } | | |||
112 | | ||||
113 | bool KillWindow::event(xcb_generic_event_t *event) | | |||
114 | { | | |||
115 | if (!m_active) { | | |||
116 | return false; | | |||
117 | } | | |||
118 | processEvent(event); | | |||
119 | | ||||
120 | return true; | | |||
121 | } | | |||
122 | | ||||
123 | void KillWindow::handleButtonRelease(xcb_button_t button, xcb_window_t window) | | |||
124 | { | | |||
125 | if (button == XCB_BUTTON_INDEX_3) { | | |||
126 | release(); | | |||
127 | return; | | |||
128 | } | | |||
129 | if (button == XCB_BUTTON_INDEX_1 || button == XCB_BUTTON_INDEX_2) { | | |||
130 | killWindowId(window); | | |||
131 | release(); | | |||
132 | return; | | |||
133 | } | | |||
134 | } | | |||
135 | | ||||
136 | void KillWindow::handleKeyPress(xcb_keycode_t keycode, uint16_t state) | | |||
137 | { | | |||
138 | xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(connection()); | | |||
139 | xcb_keysym_t kc = xcb_key_symbols_get_keysym(symbols, keycode, 0); | | |||
140 | int mx = 0; | | |||
141 | int my = 0; | | |||
142 | const bool returnPressed = (kc == XK_Return) || (kc == XK_space); | | |||
143 | const bool escapePressed = (kc == XK_Escape); | | |||
144 | if (kc == XK_Left) { | | |||
145 | mx = -10; | | |||
146 | } | | |||
147 | if (kc == XK_Right) { | | |||
148 | mx = 10; | | |||
149 | } | | |||
150 | if (kc == XK_Up) { | | |||
151 | my = -10; | | |||
152 | } | | |||
153 | if (kc == XK_Down) { | | |||
154 | my = 10; | | |||
155 | } | | |||
156 | if (state & XCB_MOD_MASK_CONTROL) { | | |||
157 | mx /= 10; | | |||
158 | my /= 10; | | |||
159 | } | | |||
160 | Cursor::setPos(Cursor::pos() + QPoint(mx, my)); | | |||
161 | if (returnPressed) { | | |||
162 | performKill(); | | |||
163 | } | | |||
164 | if (returnPressed || escapePressed) { | | |||
165 | release(); | | |||
166 | } | | |||
167 | xcb_key_symbols_free(symbols); | | |||
168 | } | | |||
169 | | ||||
170 | void KillWindow::performKill() | | |||
171 | { | | |||
172 | Xcb::Pointer pointer(rootWindow()); | | |||
173 | if (!pointer.isNull() && pointer->child != XCB_WINDOW_NONE) { | | |||
174 | killWindowId(pointer->child); | | |||
175 | } | | |||
176 | } | | |||
177 | | ||||
178 | void KillWindow::release() | | |||
179 | { | | |||
180 | ungrabXKeyboard(); | | |||
181 | xcb_ungrab_pointer(connection(), XCB_TIME_CURRENT_TIME); | | |||
182 | ungrabXServer(); | | |||
183 | m_active = false; | | |||
184 | } | | |||
185 | | ||||
186 | void KillWindow::killWindowId(xcb_window_t window_to_kill) | | |||
187 | { | | |||
188 | if (window_to_kill == XCB_WINDOW_NONE) | | |||
189 | return; | | |||
190 | xcb_window_t window = window_to_kill; | | |||
191 | Client* client = NULL; | | |||
192 | while (true) { | | |||
193 | client = Workspace::self()->findClient(Predicate::FrameIdMatch, window); | | |||
194 | if (client) { | | |||
195 | break; // Found the client | | |||
196 | } | | |||
197 | Xcb::Tree tree(window); | | |||
198 | if (window == tree->root) { | | |||
199 | // We didn't find the client, probably an override-redirect window | | |||
200 | break; | | |||
201 | } | | |||
202 | window = tree->parent; // Go up | | |||
203 | } | 50 | } | ||
204 | if (client) | 51 | }, QByteArrayLiteral("pirate") | ||
205 | client->killWindow(); | 52 | ); | ||
206 | else | | |||
207 | xcb_kill_client(connection(), window_to_kill); | | |||
208 | } | 53 | } | ||
209 | 54 | | |||
210 | } // namespace | 55 | } // namespace |