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
*********************************************************************/
23
#include "config-kwin.h"
30
#include <kapplication.h>
33
#include <kglobalsettings.h>
36
#include <QDesktopWidget>
39
#include "compositingprefs.h"
40
#include <kwinglplatform.h>
42
#include <kephal/screens.h>
45
#include <X11/extensions/Xrandr.h>
56
int currentRefreshRate()
59
if (options->refreshRate > 0) // use manually configured refresh rate
60
rate = options->refreshRate;
61
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
62
#ifndef KWIN_HAVE_OPENGLES
63
else if (GLPlatform::instance()->driver() == Driver_NVidia) {
64
QProcess nvidia_settings;
65
nvidia_settings.start("nvidia-settings", QStringList() << "-t" << "-q" << "RefreshRate", QIODevice::ReadOnly);
66
nvidia_settings.waitForFinished();
67
if (nvidia_settings.exitStatus() == QProcess::NormalExit) {
68
QString reply = QString::fromLocal8Bit(nvidia_settings.readAllStandardOutput());
70
const float frate = reply.split(' ').first().toFloat(&ok);
80
else if (Extensions::randrAvailable()) {
81
XRRScreenConfiguration *config = XRRGetScreenInfo(display(), rootWindow());
82
rate = XRRConfigCurrentRate(config);
83
XRRFreeScreenConfigInfo(config);
87
// 0Hz or less is invalid, so we fallback to a default rate
90
// QTimer gives us 1msec (1000Hz) at best, so we ignore anything higher;
91
// however, additional throttling prevents very high rates from taking place anyway
94
kDebug(1212) << "Refresh rate " << rate << "Hz";
100
, electric_border_delay(0)
102
compositingInitialized = false;
110
unsigned long Options::updateSettings()
112
KSharedConfig::Ptr _config = KGlobal::config();
113
unsigned long changed = 0;
114
changed |= KDecorationOptions::updateSettings(_config.data()); // read decoration settings
116
KConfigGroup config(_config, "Windows");
117
moveMode = stringToMoveResizeMode(config.readEntry("MoveMode", "Opaque"));
118
resizeMode = stringToMoveResizeMode(config.readEntry("ResizeMode", "Opaque"));
119
show_geometry_tip = config.readEntry("GeometryTip", false);
123
val = config.readEntry("FocusPolicy", "ClickToFocus");
124
focusPolicy = ClickToFocus; // what a default :-)
125
if (val == "FocusFollowsMouse")
126
focusPolicy = FocusFollowsMouse;
127
else if (val == "FocusUnderMouse")
128
focusPolicy = FocusUnderMouse;
129
else if (val == "FocusStrictlyUnderMouse")
130
focusPolicy = FocusStrictlyUnderMouse;
132
separateScreenFocus = config.readEntry("SeparateScreenFocus", false);
133
activeMouseScreen = config.readEntry("ActiveMouseScreen", focusPolicy != ClickToFocus);
135
rollOverDesktops = config.readEntry("RollOverDesktops", true);
137
legacyFullscreenSupport = config.readEntry("LegacyFullscreenSupport", false);
139
// focusStealingPreventionLevel = config.readEntry( "FocusStealingPreventionLevel", 2 );
140
// TODO use low level for now
141
focusStealingPreventionLevel = config.readEntry("FocusStealingPreventionLevel", 1);
142
focusStealingPreventionLevel = qMax(0, qMin(4, focusStealingPreventionLevel));
143
if (!focusPolicyIsReasonable()) // #48786, comments #7 and later
144
focusStealingPreventionLevel = 0;
146
xineramaEnabled = config.readEntry("XineramaEnabled", true);
147
xineramaPlacementEnabled = config.readEntry("XineramaPlacementEnabled", true);
148
xineramaMovementEnabled = config.readEntry("XineramaMovementEnabled", true);
149
xineramaMaximizeEnabled = config.readEntry("XineramaMaximizeEnabled", true);
150
xineramaFullscreenEnabled = config.readEntry("XineramaFullscreenEnabled", true);
152
#ifdef KWIN_BUILD_DECORATIONS
153
placement = Placement::policyFromString(config.readEntry("Placement"), true);
155
placement = Placement::Maximizing;
157
xineramaPlacementScreen = qBound(-1, config.readEntry("XineramaPlacementScreen", -1),
158
Kephal::ScreenUtils::numScreens() - 1);
160
if (focusPolicy == ClickToFocus) {
162
autoRaiseInterval = 0;
164
delayFocusInterval = 0;
166
autoRaise = config.readEntry("AutoRaise", false);
167
autoRaiseInterval = config.readEntry("AutoRaiseInterval", 0);
168
delayFocus = config.readEntry("DelayFocus", false);
169
delayFocusInterval = config.readEntry("DelayFocusInterval", 0);
172
shadeHover = config.readEntry("ShadeHover", false);
173
shadeHoverInterval = config.readEntry("ShadeHoverInterval", 250);
175
tilingOn = config.readEntry("TilingOn", false);
176
tilingLayout = static_cast<TilingLayoutFactory::Layouts>(config.readEntry("TilingDefaultLayout", 0));
177
tilingRaisePolicy = config.readEntry("TilingRaisePolicy", 0);
179
// important: autoRaise implies ClickRaise
180
clickRaise = autoRaise || config.readEntry("ClickRaise", true);
182
borderSnapZone = config.readEntry("BorderSnapZone", 10);
183
windowSnapZone = config.readEntry("WindowSnapZone", 10);
184
centerSnapZone = config.readEntry("CenterSnapZone", 0);
185
snapOnlyWhenOverlapping = config.readEntry("SnapOnlyWhenOverlapping", false);
188
KConfigGroup borderConfig(_config, "ElectricBorders");
189
electric_border_top = electricBorderAction(borderConfig.readEntry("Top", "None"));
190
electric_border_top_right = electricBorderAction(borderConfig.readEntry("TopRight", "None"));
191
electric_border_right = electricBorderAction(borderConfig.readEntry("Right", "None"));
192
electric_border_bottom_right = electricBorderAction(borderConfig.readEntry("BottomRight", "None"));
193
electric_border_bottom = electricBorderAction(borderConfig.readEntry("Bottom", "None"));
194
electric_border_bottom_left = electricBorderAction(borderConfig.readEntry("BottomLeft", "None"));
195
electric_border_left = electricBorderAction(borderConfig.readEntry("Left", "None"));
196
electric_border_top_left = electricBorderAction(borderConfig.readEntry("TopLeft", "None"));
197
electric_borders = config.readEntry("ElectricBorders", 0);
198
electric_border_delay = config.readEntry("ElectricBorderDelay", 150);
199
electric_border_cooldown = config.readEntry("ElectricBorderCooldown", 350);
200
electric_border_pushback_pixels = config.readEntry("ElectricBorderPushbackPixels", 1);
201
electric_border_maximize = config.readEntry("ElectricBorderMaximize", true);
202
electric_border_tiling = config.readEntry("ElectricBorderTiling", true);
204
OpTitlebarDblClick = windowOperation(config.readEntry("TitlebarDoubleClickCommand", "Maximize"), true);
205
setOpMaxButtonLeftClick(windowOperation(config.readEntry("MaximizeButtonLeftClickCommand", "Maximize"), true));
206
setOpMaxButtonMiddleClick(windowOperation(config.readEntry("MaximizeButtonMiddleClickCommand", "Maximize (vertical only)"), true));
207
setOpMaxButtonRightClick(windowOperation(config.readEntry("MaximizeButtonRightClickCommand", "Maximize (horizontal only)"), true));
209
ignorePositionClasses = config.readEntry("IgnorePositionClasses", QStringList());
210
ignoreFocusStealingClasses = config.readEntry("IgnoreFocusStealingClasses", QStringList());
211
// Qt3.2 and older had resource class all lowercase, but Qt3.3 has it capitalized
212
// therefore Client::resourceClass() forces lowercase, force here lowercase as well
213
for (QStringList::Iterator it = ignorePositionClasses.begin();
214
it != ignorePositionClasses.end();
216
(*it) = (*it).toLower();
217
for (QStringList::Iterator it = ignoreFocusStealingClasses.begin();
218
it != ignoreFocusStealingClasses.end();
220
(*it) = (*it).toLower();
222
killPingTimeout = config.readEntry("KillPingTimeout", 5000);
223
hideUtilityWindowsForInactive = config.readEntry("HideUtilityWindowsForInactive", true);
224
inactiveTabsSkipTaskbar = config.readEntry("InactiveTabsSkipTaskbar", false);
225
autogroupSimilarWindows = config.readEntry("AutogroupSimilarWindows", false);
226
autogroupInForeground = config.readEntry("AutogroupInForeground", true);
227
showDesktopIsMinimizeAll = config.readEntry("ShowDesktopIsMinimizeAll", false);
229
borderless_maximized_windows = config.readEntry("BorderlessMaximizedWindows", false);
232
config = KConfigGroup(_config, "MouseBindings");
233
CmdActiveTitlebar1 = mouseCommand(config.readEntry("CommandActiveTitlebar1", "Raise"), true);
234
CmdActiveTitlebar2 = mouseCommand(config.readEntry("CommandActiveTitlebar2", "Start Window Tab Drag"), true);
235
CmdActiveTitlebar3 = mouseCommand(config.readEntry("CommandActiveTitlebar3", "Operations menu"), true);
236
CmdInactiveTitlebar1 = mouseCommand(config.readEntry("CommandInactiveTitlebar1", "Activate and raise"), true);
237
CmdInactiveTitlebar2 = mouseCommand(config.readEntry("CommandInactiveTitlebar2", "Start Window Tab Drag"), true);
238
CmdInactiveTitlebar3 = mouseCommand(config.readEntry("CommandInactiveTitlebar3", "Operations menu"), true);
239
CmdTitlebarWheel = mouseWheelCommand(config.readEntry("CommandTitlebarWheel", "Switch to Window Tab to the Left/Right"));
240
CmdWindow1 = mouseCommand(config.readEntry("CommandWindow1", "Activate, raise and pass click"), false);
241
CmdWindow2 = mouseCommand(config.readEntry("CommandWindow2", "Activate and pass click"), false);
242
CmdWindow3 = mouseCommand(config.readEntry("CommandWindow3", "Activate and pass click"), false);
243
CmdWindowWheel = mouseCommand(config.readEntry("CommandWindowWheel", "Scroll"), false);
244
CmdAllModKey = (config.readEntry("CommandAllKey", "Alt") == "Meta") ? Qt::Key_Meta : Qt::Key_Alt;
245
CmdAll1 = mouseCommand(config.readEntry("CommandAll1", "Move"), false);
246
CmdAll2 = mouseCommand(config.readEntry("CommandAll2", "Toggle raise and lower"), false);
247
CmdAll3 = mouseCommand(config.readEntry("CommandAll3", "Resize"), false);
248
CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel", "Nothing"));
250
config = KConfigGroup(_config, "Compositing");
251
maxFpsInterval = qRound(1000.0 / config.readEntry("MaxFPS", 60));
252
refreshRate = config.readEntry("RefreshRate", 0);
254
// Read button tooltip animation effect from kdeglobals
255
// Since we want to allow users to enable window decoration tooltips
256
// and not kstyle tooltips and vise-versa, we don't read the
257
// "EffectNoTooltip" setting from kdeglobals.
260
FIXME: we have no mac style menu implementation in kwin anymore, so this just breaks
262
KConfig _globalConfig("kdeglobals");
263
KConfigGroup globalConfig(&_globalConfig, "KDE");
264
topmenus = globalConfig.readEntry("macStyle", false);
269
// QToolTip::setGloballyEnabled( d->show_tooltips );
270
// KDE4 this probably needs to be done manually in clients
272
// Driver-specific config detection
273
compositingInitialized = false;
274
reloadCompositingSettings();
279
void Options::reloadCompositingSettings(bool force)
281
KSharedConfig::Ptr _config = KGlobal::config();
282
KConfigGroup config(_config, "Compositing");
284
QString compositingBackend = config.readEntry("Backend", "OpenGL");
285
if (compositingBackend == "XRender")
286
compositingMode = XRenderCompositing;
288
compositingMode = OpenGLCompositing;
290
useCompositing = false;
291
if (const char *c = getenv("KWIN_COMPOSE")) {
294
kDebug(1212) << "Compositing forced to OpenGL mode by environment variable";
295
compositingMode = OpenGLCompositing;
296
useCompositing = true;
299
kDebug(1212) << "Compositing forced to XRender mode by environment variable";
300
compositingMode = XRenderCompositing;
301
useCompositing = true;
304
if (getenv("KDE_FAILSAFE"))
305
kDebug(1212) << "Compositing disabled forcefully by KDE failsafe mode";
307
kDebug(1212) << "Compositing disabled forcefully by environment variable";
308
compositingMode = NoCompositing;
311
kDebug(1212) << "Unknown KWIN_COMPOSE mode set, ignoring";
316
if (compositingMode == NoCompositing)
317
return; // do not even detect compositing preferences if explicitly disabled
319
// it's either enforced by env or by initial resume from "suspend" or we check the settings
320
useCompositing = useCompositing || force || config.readEntry("Enabled", true);
323
return; // not enforced or necessary and not "enabled" by setting
325
// from now on we've an initial setup and don't have to reload settigns on compositing activation
326
// see Workspace::setupCompositing(), composite.cpp
327
compositingInitialized = true;
329
// Compositing settings
330
CompositingPrefs prefs;
333
useCompositing = config.readEntry("Enabled" , prefs.recommendCompositing());
334
disableCompositingChecks = config.readEntry("DisableChecks", false);
335
glDirect = config.readEntry("GLDirect", prefs.enableDirectRendering());
336
glVSync = config.readEntry("GLVSync", prefs.enableVSync());
337
glSmoothScale = qBound(-1, config.readEntry("GLTextureFilter", 2), 2);
338
glStrictBinding = config.readEntry("GLStrictBinding", prefs.strictBinding());
340
xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
342
hiddenPreviews = HiddenPreviewsShown;
343
// 4 - off, 5 - shown, 6 - always, other are old values
344
int hps = config.readEntry("HiddenPreviews", 5);
346
hiddenPreviews = HiddenPreviewsNever;
348
hiddenPreviews = HiddenPreviewsShown;
350
hiddenPreviews = HiddenPreviewsAlways;
352
unredirectFullscreen = config.readEntry("UnredirectFullscreen", false);
353
animationSpeed = qBound(0, config.readEntry("AnimationSpeed", 3), 6);
357
ElectricBorderAction Options::electricBorderAction(const QString& name)
359
QString lowerName = name.toLower();
360
if (lowerName == "dashboard") return ElectricActionDashboard;
361
else if (lowerName == "showdesktop") return ElectricActionShowDesktop;
362
else if (lowerName == "lockscreen") return ElectricActionLockScreen;
363
else if (lowerName == "preventscreenlocking") return ElectricActionPreventScreenLocking;
364
return ElectricActionNone;
367
// restricted should be true for operations that the user may not be able to repeat
368
// if the window is moved out of the workspace (e.g. if the user moves a window
369
// by the titlebar, and moves it too high beneath Kicker at the top edge, they
370
// may not be able to move it back, unless they know about Alt+LMB)
371
Options::WindowOperation Options::windowOperation(const QString &name, bool restricted)
374
return restricted ? MoveOp : UnrestrictedMoveOp;
375
else if (name == "Resize")
376
return restricted ? ResizeOp : UnrestrictedResizeOp;
377
else if (name == "Maximize")
379
else if (name == "Minimize")
381
else if (name == "Close")
383
else if (name == "OnAllDesktops")
384
return OnAllDesktopsOp;
385
else if (name == "Shade")
387
else if (name == "Operations")
389
else if (name == "Maximize (vertical only)")
391
else if (name == "Maximize (horizontal only)")
393
else if (name == "Lower")
398
Options::MouseCommand Options::mouseCommand(const QString &name, bool restricted)
400
QString lowerName = name.toLower();
401
if (lowerName == "raise") return MouseRaise;
402
if (lowerName == "lower") return MouseLower;
403
if (lowerName == "operations menu") return MouseOperationsMenu;
404
if (lowerName == "toggle raise and lower") return MouseToggleRaiseAndLower;
405
if (lowerName == "activate and raise") return MouseActivateAndRaise;
406
if (lowerName == "activate and lower") return MouseActivateAndLower;
407
if (lowerName == "activate") return MouseActivate;
408
if (lowerName == "activate, raise and pass click") return MouseActivateRaiseAndPassClick;
409
if (lowerName == "activate and pass click") return MouseActivateAndPassClick;
410
if (lowerName == "scroll") return MouseNothing;
411
if (lowerName == "activate and scroll") return MouseActivateAndPassClick;
412
if (lowerName == "activate, raise and scroll") return MouseActivateRaiseAndPassClick;
413
if (lowerName == "activate, raise and move")
414
return restricted ? MouseActivateRaiseAndMove : MouseActivateRaiseAndUnrestrictedMove;
415
if (lowerName == "move") return restricted ? MouseMove : MouseUnrestrictedMove;
416
if (lowerName == "resize") return restricted ? MouseResize : MouseUnrestrictedResize;
417
if (lowerName == "shade") return MouseShade;
418
if (lowerName == "minimize") return MouseMinimize;
419
if (lowerName == "start window tab drag") return MouseClientGroupDrag;
420
if (lowerName == "close") return MouseClose;
421
if (lowerName == "nothing") return MouseNothing;
425
Options::MouseWheelCommand Options::mouseWheelCommand(const QString &name)
427
QString lowerName = name.toLower();
428
if (lowerName == "raise/lower") return MouseWheelRaiseLower;
429
if (lowerName == "shade/unshade") return MouseWheelShadeUnshade;
430
if (lowerName == "maximize/restore") return MouseWheelMaximizeRestore;
431
if (lowerName == "above/below") return MouseWheelAboveBelow;
432
if (lowerName == "previous/next desktop") return MouseWheelPreviousNextDesktop;
433
if (lowerName == "change opacity") return MouseWheelChangeOpacity;
434
if (lowerName == "switch to window tab to the left/right") return MouseWheelChangeGroupWindow;
435
if (lowerName == "nothing") return MouseWheelNothing;
436
return MouseWheelChangeGroupWindow;
439
bool Options::showGeometryTip()
441
return show_geometry_tip;
444
ElectricBorderAction Options::electricBorderAction(ElectricBorder edge)
448
return electric_border_top;
449
case ElectricTopRight:
450
return electric_border_top_right;
452
return electric_border_right;
453
case ElectricBottomRight:
454
return electric_border_bottom_right;
456
return electric_border_bottom;
457
case ElectricBottomLeft:
458
return electric_border_bottom_left;
460
return electric_border_left;
461
case ElectricTopLeft:
462
return electric_border_top_left;
467
return ElectricActionNone;
470
int Options::electricBorders()
472
return electric_borders;
475
int Options::electricBorderDelay()
477
return electric_border_delay;
480
int Options::electricBorderCooldown()
482
return electric_border_cooldown;
485
bool Options::checkIgnoreFocusStealing(const Client* c)
487
return ignoreFocusStealingClasses.contains(QString::fromLatin1(c->resourceClass()));
490
Options::MouseCommand Options::wheelToMouseCommand(MouseWheelCommand com, int delta)
493
case MouseWheelRaiseLower:
494
return delta > 0 ? MouseRaise : MouseLower;
495
case MouseWheelShadeUnshade:
496
return delta > 0 ? MouseSetShade : MouseUnsetShade;
497
case MouseWheelMaximizeRestore:
498
return delta > 0 ? MouseMaximize : MouseRestore;
499
case MouseWheelAboveBelow:
500
return delta > 0 ? MouseAbove : MouseBelow;
501
case MouseWheelPreviousNextDesktop:
502
return delta > 0 ? MousePreviousDesktop : MouseNextDesktop;
503
case MouseWheelChangeOpacity:
504
return delta > 0 ? MouseOpacityMore : MouseOpacityLess;
505
case MouseWheelChangeGroupWindow:
506
return delta > 0 ? MouseLeftGroupWindow : MouseRightGroupWindow;
513
Options::MoveResizeMode Options::stringToMoveResizeMode(const QString& s)
515
return s == "Opaque" ? Opaque : Transparent;
518
const char* Options::moveResizeModeToString(MoveResizeMode mode)
520
return mode == Opaque ? "Opaque" : "Transparent";
523
double Options::animationTimeFactor() const
525
const double factors[] = { 0, 0.2, 0.5, 1, 2, 4, 20 };
526
return factors[ animationSpeed ];