1
/********************************************************************
2
KWin - the KDE window manager
3
This file is part of the KDE project.
5
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
*********************************************************************/
24
This file is for (very) small utility functions/classes.
34
#include <QVBoxLayout>
35
#include <kxerrorhandler.h>
38
#include <kglobalaccel.h>
40
#include <kshortcut.h>
41
#include <kkeyserver.h>
42
#include <KPushButton>
45
#include <X11/extensions/shape.h>
46
#include <X11/Xatom.h>
48
#include <QtGui/QKeySequence>
53
#include "notifications.h"
54
#include "workspace.h"
63
//************************************
65
//************************************
67
StrutRect::StrutRect(QRect rect, StrutArea area)
73
StrutRect::StrutRect(const StrutRect& other)
75
, m_area(other.area())
79
//************************************
81
//************************************
83
void Motif::readFlags(WId w, bool& got_noborder, bool& noborder,
84
bool& resize, bool& move, bool& minimize, bool& maximize, bool& close)
88
unsigned long length, after;
91
if (XGetWindowProperty(display(), w, atoms->motif_wm_hints, 0, 5,
92
false, atoms->motif_wm_hints, &type, &format,
93
&length, &after, &data) == Success) {
95
hints = (MwmHints*) data;
105
// To quote from Metacity 'We support those MWM hints deemed non-stupid'
106
if (hints->flags & MWM_HINTS_FUNCTIONS) {
107
// if MWM_FUNC_ALL is set, other flags say what to turn _off_
108
bool set_value = ((hints->functions & MWM_FUNC_ALL) == 0);
109
resize = move = minimize = maximize = close = !set_value;
110
if (hints->functions & MWM_FUNC_RESIZE)
112
if (hints->functions & MWM_FUNC_MOVE)
114
if (hints->functions & MWM_FUNC_MINIMIZE)
115
minimize = set_value;
116
if (hints->functions & MWM_FUNC_MAXIMIZE)
117
maximize = set_value;
118
if (hints->functions & MWM_FUNC_CLOSE)
121
if (hints->flags & MWM_HINTS_DECORATIONS) {
123
noborder = !hints->decorations;
129
//************************************
130
// KWinSelectionOwner
131
//************************************
133
KWinSelectionOwner::KWinSelectionOwner(int screen_P)
134
: KSelectionOwner(make_selection_atom(screen_P), screen_P)
138
Atom KWinSelectionOwner::make_selection_atom(int screen_P)
141
screen_P = DefaultScreen(display());
143
sprintf(tmp, "WM_S%d", screen_P);
144
return XInternAtom(display(), tmp, False);
147
void KWinSelectionOwner::getAtoms()
149
KSelectionOwner::getAtoms();
150
if (xa_version == None) {
152
const char* const names[] =
154
XInternAtoms(display(), const_cast< char** >(names), 1, False, atoms);
155
xa_version = atoms[ 0 ];
159
void KWinSelectionOwner::replyTargets(Atom property_P, Window requestor_P)
161
KSelectionOwner::replyTargets(property_P, requestor_P);
162
Atom atoms[ 1 ] = { xa_version };
164
XChangeProperty(display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend,
165
reinterpret_cast< unsigned char* >(atoms), 1);
168
bool KWinSelectionOwner::genericReply(Atom target_P, Atom property_P, Window requestor_P)
170
if (target_P == xa_version) {
171
long version[] = { 2, 0 };
172
XChangeProperty(display(), requestor_P, property_P, XA_INTEGER, 32,
173
PropModeReplace, reinterpret_cast< unsigned char* >(&version), 2);
175
return KSelectionOwner::genericReply(target_P, property_P, requestor_P);
179
Atom KWinSelectionOwner::xa_version = None;
182
QByteArray getStringProperty(WId w, Atom prop, char separator)
186
unsigned long nitems = 0;
187
unsigned long extra = 0;
188
unsigned char *data = 0;
189
QByteArray result = "";
190
KXErrorHandler handler; // ignore errors
191
status = XGetWindowProperty(display(), w, prop, 0, 10000,
192
false, XA_STRING, &type, &format,
193
&nitems, &extra, &data);
194
if (status == Success) {
195
if (data && separator) {
196
for (int i = 0; i < (int)nitems; i++)
197
if (!data[i] && i + 1 < (int)nitems)
201
result = (const char*) data;
207
static Time next_x_time;
208
static Bool update_x_time_predicate(Display*, XEvent* event, XPointer)
210
if (next_x_time != CurrentTime)
212
// from qapplication_x11.cpp
213
switch(event->type) {
215
// fallthrough intended
217
next_x_time = event->xbutton.time;
220
next_x_time = event->xmotion.time;
223
// fallthrough intended
225
next_x_time = event->xkey.time;
228
next_x_time = event->xproperty.time;
232
next_x_time = event->xcrossing.time;
235
next_x_time = event->xselectionclear.time;
244
Updates xTime(). This used to simply fetch current timestamp from the server,
245
but that can cause xTime() to be newer than timestamp of events that are
246
still in our events queue, thus e.g. making XSetInputFocus() caused by such
247
event to be ignored. Therefore events queue is searched for first
248
event with timestamp, and extra PropertyNotify is generated in order to make
249
sure such event is found.
253
static QWidget* w = 0;
257
XChangeProperty(display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
258
PropModeAppend, (unsigned char*) &data, 1);
259
next_x_time = CurrentTime;
261
XCheckIfEvent(display(), &dummy, update_x_time_predicate, NULL);
262
if (next_x_time == CurrentTime) {
263
XSync(display(), False);
264
XCheckIfEvent(display(), &dummy, update_x_time_predicate, NULL);
266
assert(next_x_time != CurrentTime);
267
QX11Info::setAppTime(next_x_time);
268
XEvent ev; // remove the PropertyNotify event from the events queue
269
XWindowEvent(display(), w->winId(), PropertyChangeMask, &ev);
272
static int server_grab_count = 0;
276
if (++server_grab_count == 1)
277
XGrabServer(display());
282
assert(server_grab_count > 0);
283
if (--server_grab_count == 0) {
284
XUngrabServer(display());
286
Notify::sendPendingEvents();
290
bool grabbedXServer()
292
return server_grab_count > 0;
295
static bool keyboard_grabbed = false;
297
bool grabXKeyboard(Window w)
299
if (QWidget::keyboardGrabber() != NULL)
301
if (keyboard_grabbed)
303
if (qApp->activePopupWidget() != NULL)
307
if (XGrabKeyboard(display(), w, False,
308
GrabModeAsync, GrabModeAsync, xTime()) != GrabSuccess)
310
keyboard_grabbed = true;
314
void ungrabXKeyboard()
316
if (!keyboard_grabbed) {
317
// grabXKeyboard() may fail sometimes, so don't fail, but at least warn anyway
318
kDebug(1212) << "ungrabXKeyboard() called but keyboard not grabbed!";
320
keyboard_grabbed = false;
321
XUngrabKeyboard(display(), CurrentTime);
326
return Workspace::self()->cursorPos();
329
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states
331
int qtToX11Button(Qt::MouseButton button)
333
if (button == Qt::LeftButton)
335
else if (button == Qt::MidButton)
337
else if (button == Qt::RightButton)
339
return AnyButton; // 0
342
Qt::MouseButton x11ToQtMouseButton(int button)
344
if (button == Button1)
345
return Qt::LeftButton;
346
if (button == Button2)
347
return Qt::MidButton;
348
if (button == Button3)
349
return Qt::RightButton;
350
if (button == Button4)
352
if (button == Button5)
357
int qtToX11State(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
360
if (buttons & Qt::LeftButton)
362
if (buttons & Qt::MidButton)
364
if (buttons & Qt::RightButton)
366
if (modifiers & Qt::ShiftModifier)
368
if (modifiers & Qt::ControlModifier)
370
if (modifiers & Qt::AltModifier)
371
ret |= KKeyServer::modXAlt();
372
if (modifiers & Qt::MetaModifier)
373
ret |= KKeyServer::modXMeta();
377
Qt::MouseButtons x11ToQtMouseButtons(int state)
379
Qt::MouseButtons ret = 0;
380
if (state & Button1Mask)
381
ret |= Qt::LeftButton;
382
if (state & Button2Mask)
383
ret |= Qt::MidButton;
384
if (state & Button3Mask)
385
ret |= Qt::RightButton;
386
if (state & Button4Mask)
388
if (state & Button5Mask)
393
Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state)
395
Qt::KeyboardModifiers ret = 0;
396
if (state & ShiftMask)
397
ret |= Qt::ShiftModifier;
398
if (state & ControlMask)
399
ret |= Qt::ControlModifier;
400
if (state & KKeyServer::modXAlt())
401
ret |= Qt::AltModifier;
402
if (state & KKeyServer::modXMeta())
403
ret |= Qt::MetaModifier;
409
bool isLocalMachine(const QByteArray& host)
412
char hostnamebuf[HOST_NAME_MAX];
414
char hostnamebuf[256];
416
if (gethostname(hostnamebuf, sizeof hostnamebuf) >= 0) {
417
hostnamebuf[sizeof(hostnamebuf)-1] = 0;
418
if (host == hostnamebuf)
420
if (char *dot = strchr(hostnamebuf, '.')) {
422
if (host == hostnamebuf)
424
} else { // e.g. LibreOffice likes to give FQDN, even if gethostname() doesn't include domain
425
QByteArray h = hostnamebuf;
426
if( getdomainname( hostnamebuf, sizeof hostnamebuf ) >= 0 ) {
427
hostnamebuf[sizeof(hostnamebuf)-1] = 0;
428
if( host == h + '.' + QByteArray( hostnamebuf ))
437
ShortcutDialog::ShortcutDialog(const QKeySequence& cut)
440
QWidget *vBoxContainer = new QWidget(this);
441
vBoxContainer->setLayout(new QVBoxLayout(vBoxContainer));
442
vBoxContainer->layout()->addWidget(widget = new KKeySequenceWidget(vBoxContainer));
443
vBoxContainer->layout()->addWidget(warning = new QLabel(vBoxContainer));
445
widget->setKeySequence(cut);
447
// To not check for conflicting shortcuts. The widget would use a message
448
// box which brings down kwin.
449
widget->setCheckForConflictsAgainst(KKeySequenceWidget::None);
450
// It's a global shortcut so don't allow multikey shortcuts
451
widget->setMultiKeyShortcutsAllowed(false);
453
// Listen to changed shortcuts
455
widget, SIGNAL(keySequenceChanged(const QKeySequence&)),
456
SLOT(keySequenceChanged(const QKeySequence&)));
458
setMainWidget(vBoxContainer);
461
// make it a popup, so that it has the grab
462
XSetWindowAttributes attrs;
463
attrs.override_redirect = True;
464
XChangeWindowAttributes(display(), winId(), CWOverrideRedirect, &attrs);
465
setWindowFlags(Qt::Popup);
468
void ShortcutDialog::accept()
470
QKeySequence seq = shortcut();
471
if (!seq.isEmpty()) {
472
if (seq[0] == Qt::Key_Escape) {
476
if (seq[0] == Qt::Key_Space
477
|| (seq[0] & Qt::KeyboardModifierMask) == 0) {
479
widget->clearKeySequence();
487
void ShortcutDialog::done(int r)
490
emit dialogDone(r == Accepted);
493
void ShortcutDialog::keySequenceChanged(const QKeySequence &seq)
495
activateWindow(); // where is the kbd focus lost? cause of popup state?
496
if (_shortcut == seq)
497
return; // don't try to update the same
499
// Check if the key sequence is used currently
500
QString sc = seq.toString();
501
// NOTICE - seq.toString() & the entries in "conflicting" randomly get invalidated after the next call (if no sc has been set & conflicting isn't empty?!)
502
QList<KGlobalShortcutInfo> conflicting = KGlobalAccel::getGlobalShortcutsByKey(seq);
503
if (!conflicting.isEmpty()) {
504
const KGlobalShortcutInfo &conflict = conflicting.at(0);
505
warning->setText(i18nc("'%1' is a keyboard shortcut like 'ctrl+w'",
506
"<b>%1</b> is already in use", sc));
507
warning->setToolTip(i18nc("keyboard shortcut '%1' is used by action '%2' in application '%3'",
508
"<b>%1</b> is used by %2 in %3", sc, conflict.friendlyName(), conflict.componentFriendlyName()));
510
widget->setKeySequence(shortcut());
511
} else if (seq != _shortcut) {
513
if (KPushButton *ok = button(KDialog::Ok))
520
QKeySequence ShortcutDialog::shortcut() const