Changeset View
Changeset View
Standalone View
Standalone View
composite.cpp
Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Line(s) | |||||
84 | 84 | | |||
85 | Compositor::Compositor(QObject* workspace) | 85 | Compositor::Compositor(QObject* workspace) | ||
86 | : QObject(workspace) | 86 | : QObject(workspace) | ||
87 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | 87 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | ||
88 | , cm_selection(NULL) | 88 | , cm_selection(NULL) | ||
89 | , vBlankInterval(0) | 89 | , vBlankInterval(0) | ||
90 | , fpsInterval(0) | 90 | , fpsInterval(0) | ||
91 | , m_xrrRefreshRate(0) | 91 | , m_xrrRefreshRate(0) | ||
92 | , forceUnredirectCheck(false) | | |||
93 | , m_finishing(false) | 92 | , m_finishing(false) | ||
94 | , m_timeSinceLastVBlank(0) | 93 | , m_timeSinceLastVBlank(0) | ||
95 | , m_scene(NULL) | 94 | , m_scene(NULL) | ||
96 | , m_bufferSwapPending(false) | 95 | , m_bufferSwapPending(false) | ||
97 | , m_composeAtSwapCompletion(false) | 96 | , m_composeAtSwapCompletion(false) | ||
98 | { | 97 | { | ||
99 | qRegisterMetaType<Compositor::SuspendReason>("Compositor::SuspendReason"); | 98 | qRegisterMetaType<Compositor::SuspendReason>("Compositor::SuspendReason"); | ||
100 | connect(&unredirectTimer, SIGNAL(timeout()), SLOT(delayedCheckUnredirect())); | | |||
101 | connect(&compositeResetTimer, SIGNAL(timeout()), SLOT(restart())); | 99 | connect(&compositeResetTimer, SIGNAL(timeout()), SLOT(restart())); | ||
102 | connect(options, &Options::configChanged, this, &Compositor::slotConfigChanged); | 100 | connect(options, &Options::configChanged, this, &Compositor::slotConfigChanged); | ||
103 | connect(options, SIGNAL(unredirectFullscreenChanged()), SLOT(delayedCheckUnredirect())); | | |||
104 | unredirectTimer.setSingleShot(true); | | |||
105 | compositeResetTimer.setSingleShot(true); | 101 | compositeResetTimer.setSingleShot(true); | ||
106 | nextPaintReference.invalidate(); // Initialize the timer | 102 | nextPaintReference.invalidate(); // Initialize the timer | ||
107 | 103 | | |||
108 | // 2 sec which should be enough to restart the compositor | 104 | // 2 sec which should be enough to restart the compositor | ||
109 | static const int compositorLostMessageDelay = 2000; | 105 | static const int compositorLostMessageDelay = 2000; | ||
110 | 106 | | |||
111 | m_releaseSelectionTimer.setSingleShot(true); | 107 | m_releaseSelectionTimer.setSingleShot(true); | ||
112 | m_releaseSelectionTimer.setInterval(compositorLostMessageDelay); | 108 | m_releaseSelectionTimer.setInterval(compositorLostMessageDelay); | ||
▲ Show 20 Lines • Show All 734 Lines • ▼ Show 20 Line(s) | 779 | { | |||
847 | compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum | 843 | compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum | ||
848 | } | 844 | } | ||
849 | 845 | | |||
850 | bool Compositor::isActive() | 846 | bool Compositor::isActive() | ||
851 | { | 847 | { | ||
852 | return !m_finishing && hasScene(); | 848 | return !m_finishing && hasScene(); | ||
853 | } | 849 | } | ||
854 | 850 | | |||
855 | void Compositor::checkUnredirect() | | |||
856 | { | | |||
857 | checkUnredirect(false); | | |||
858 | } | | |||
859 | | ||||
860 | // force is needed when the list of windows changes (e.g. a window goes away) | | |||
861 | void Compositor::checkUnredirect(bool force) | | |||
862 | { | | |||
863 | if (!hasScene() || !m_scene->overlayWindow() || m_scene->overlayWindow()->window() == None || !options->isUnredirectFullscreen()) | | |||
864 | return; | | |||
865 | if (force) | | |||
866 | forceUnredirectCheck = true; | | |||
867 | if (!unredirectTimer.isActive()) | | |||
868 | unredirectTimer.start(0); | | |||
869 | } | | |||
870 | | ||||
871 | void Compositor::delayedCheckUnredirect() | | |||
872 | { | | |||
873 | if (!hasScene() || !m_scene->overlayWindow() || m_scene->overlayWindow()->window() == None || !(options->isUnredirectFullscreen() || sender() == options)) | | |||
874 | return; | | |||
875 | ToplevelList list; | | |||
876 | bool changed = forceUnredirectCheck; | | |||
877 | foreach (Client * c, Workspace::self()->clientList()) | | |||
878 | list.append(c); | | |||
879 | foreach (Unmanaged * c, Workspace::self()->unmanagedList()) | | |||
880 | list.append(c); | | |||
881 | foreach (Toplevel * c, list) { | | |||
882 | if (c->updateUnredirectedState()) { | | |||
883 | changed = true; | | |||
884 | break; | | |||
885 | } | | |||
886 | } | | |||
887 | // no desktops, no Deleted ones | | |||
888 | if (!changed) | | |||
889 | return; | | |||
890 | forceUnredirectCheck = false; | | |||
891 | // Cut out parts from the overlay window where unredirected windows are, | | |||
892 | // so that they are actually visible. | | |||
893 | const QSize &s = screens()->size(); | | |||
894 | QRegion reg(0, 0, s.width(), s.height()); | | |||
895 | foreach (Toplevel * c, list) { | | |||
896 | if (c->unredirected()) | | |||
897 | reg -= c->geometry(); | | |||
898 | } | | |||
899 | m_scene->overlayWindow()->setShape(reg); | | |||
900 | addRepaint(reg); | | |||
901 | } | | |||
902 | | ||||
903 | bool Compositor::checkForOverlayWindow(WId w) const | 851 | bool Compositor::checkForOverlayWindow(WId w) const | ||
904 | { | 852 | { | ||
905 | if (!hasScene()) { | 853 | if (!hasScene()) { | ||
906 | // no scene, so it cannot be the overlay window | 854 | // no scene, so it cannot be the overlay window | ||
907 | return false; | 855 | return false; | ||
908 | } | 856 | } | ||
909 | if (!m_scene->overlayWindow()) { | 857 | if (!m_scene->overlayWindow()) { | ||
910 | // no overlay window, it cannot be the overlay | 858 | // no overlay window, it cannot be the overlay | ||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Line(s) | 908 | { | |||
966 | 914 | | |||
967 | if (kwinApp()->operationMode() == Application::OperationModeX11 && !surface()) { | 915 | if (kwinApp()->operationMode() == Application::OperationModeX11 && !surface()) { | ||
968 | damage_handle = xcb_generate_id(connection()); | 916 | damage_handle = xcb_generate_id(connection()); | ||
969 | xcb_damage_create(connection(), damage_handle, frameId(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); | 917 | xcb_damage_create(connection(), damage_handle, frameId(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); | ||
970 | } | 918 | } | ||
971 | 919 | | |||
972 | damage_region = QRegion(0, 0, width(), height()); | 920 | damage_region = QRegion(0, 0, width(), height()); | ||
973 | effect_window = new EffectWindowImpl(this); | 921 | effect_window = new EffectWindowImpl(this); | ||
974 | unredirect = false; | | |||
975 | 922 | | |||
976 | Compositor::self()->checkUnredirect(true); | | |||
977 | Compositor::self()->scene()->windowAdded(this); | 923 | Compositor::self()->scene()->windowAdded(this); | ||
978 | 924 | | |||
979 | // With unmanaged windows there is a race condition between the client painting the window | 925 | // With unmanaged windows there is a race condition between the client painting the window | ||
980 | // and us setting up damage tracking. If the client wins we won't get a damage event even | 926 | // and us setting up damage tracking. If the client wins we won't get a damage event even | ||
981 | // though the window has been painted. To avoid this we mark the whole window as damaged | 927 | // though the window has been painted. To avoid this we mark the whole window as damaged | ||
982 | // and schedule a repaint immediately after creating the damage object. | 928 | // and schedule a repaint immediately after creating the damage object. | ||
983 | if (dynamic_cast<Unmanaged*>(this)) | 929 | if (dynamic_cast<Unmanaged*>(this)) | ||
984 | addDamageFull(); | 930 | addDamageFull(); | ||
985 | 931 | | |||
986 | return true; | 932 | return true; | ||
987 | } | 933 | } | ||
988 | 934 | | |||
989 | void Toplevel::finishCompositing(ReleaseReason releaseReason) | 935 | void Toplevel::finishCompositing(ReleaseReason releaseReason) | ||
990 | { | 936 | { | ||
991 | if (kwinApp()->operationMode() == Application::OperationModeX11 && damage_handle == XCB_NONE) | 937 | if (kwinApp()->operationMode() == Application::OperationModeX11 && damage_handle == XCB_NONE) | ||
992 | return; | 938 | return; | ||
993 | Compositor::self()->checkUnredirect(true); | | |||
994 | if (effect_window->window() == this) { // otherwise it's already passed to Deleted, don't free data | 939 | if (effect_window->window() == this) { // otherwise it's already passed to Deleted, don't free data | ||
995 | discardWindowPixmap(); | 940 | discardWindowPixmap(); | ||
996 | delete effect_window; | 941 | delete effect_window; | ||
997 | } | 942 | } | ||
998 | 943 | | |||
999 | if (damage_handle != XCB_NONE && | 944 | if (damage_handle != XCB_NONE && | ||
1000 | releaseReason != ReleaseReason::Destroyed) { | 945 | releaseReason != ReleaseReason::Destroyed) { | ||
1001 | xcb_damage_destroy(connection(), damage_handle); | 946 | xcb_damage_destroy(connection(), damage_handle); | ||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Line(s) | |||||
1195 | 1140 | | |||
1196 | void Toplevel::addWorkspaceRepaint(const QRect& r2) | 1141 | void Toplevel::addWorkspaceRepaint(const QRect& r2) | ||
1197 | { | 1142 | { | ||
1198 | if (!compositing()) | 1143 | if (!compositing()) | ||
1199 | return; | 1144 | return; | ||
1200 | Compositor::self()->addRepaint(r2); | 1145 | Compositor::self()->addRepaint(r2); | ||
1201 | } | 1146 | } | ||
1202 | 1147 | | |||
1203 | bool Toplevel::updateUnredirectedState() | | |||
1204 | { | | |||
1205 | assert(compositing()); | | |||
1206 | bool should = options->isUnredirectFullscreen() && shouldUnredirect() && !unredirectSuspend && | | |||
1207 | !shape() && !hasAlpha() && opacity() == 1.0 && | | |||
1208 | !static_cast<EffectsHandlerImpl*>(effects)->activeFullScreenEffect(); | | |||
1209 | if (should == unredirect) | | |||
1210 | return false; | | |||
1211 | static QElapsedTimer lastUnredirect; | | |||
1212 | static const qint64 msecRedirectInterval = 100; | | |||
1213 | if (!lastUnredirect.hasExpired(msecRedirectInterval)) { | | |||
1214 | QTimer::singleShot(msecRedirectInterval, Compositor::self(), SLOT(checkUnredirect())); | | |||
1215 | return false; | | |||
1216 | } | | |||
1217 | lastUnredirect.start(); | | |||
1218 | unredirect = should; | | |||
1219 | if (unredirect) { | | |||
1220 | qCDebug(KWIN_CORE) << "Unredirecting:" << this; | | |||
1221 | xcb_composite_unredirect_window(connection(), frameId(), XCB_COMPOSITE_REDIRECT_MANUAL); | | |||
1222 | } else { | | |||
1223 | qCDebug(KWIN_CORE) << "Redirecting:" << this; | | |||
1224 | xcb_composite_redirect_window(connection(), frameId(), XCB_COMPOSITE_REDIRECT_MANUAL); | | |||
1225 | discardWindowPixmap(); | | |||
1226 | } | | |||
1227 | return true; | | |||
1228 | } | | |||
1229 | | ||||
1230 | void Toplevel::suspendUnredirect(bool suspend) | | |||
1231 | { | | |||
1232 | if (unredirectSuspend == suspend) | | |||
1233 | return; | | |||
1234 | unredirectSuspend = suspend; | | |||
1235 | Compositor::self()->checkUnredirect(); | | |||
1236 | } | | |||
1237 | | ||||
1238 | //**************************************** | 1148 | //**************************************** | ||
1239 | // Client | 1149 | // Client | ||
1240 | //**************************************** | 1150 | //**************************************** | ||
1241 | 1151 | | |||
1242 | bool Client::setupCompositing() | 1152 | bool Client::setupCompositing() | ||
1243 | { | 1153 | { | ||
1244 | if (!Toplevel::setupCompositing()){ | 1154 | if (!Toplevel::setupCompositing()){ | ||
1245 | return false; | 1155 | return false; | ||
Show All 13 Lines | 1168 | if (!deleting) { | |||
1259 | if (isDecorated()) { | 1169 | if (isDecorated()) { | ||
1260 | decoratedClient()->destroyRenderer(); | 1170 | decoratedClient()->destroyRenderer(); | ||
1261 | } | 1171 | } | ||
1262 | } | 1172 | } | ||
1263 | // for safety in case KWin is just resizing the window | 1173 | // for safety in case KWin is just resizing the window | ||
1264 | resetHaveResizeEffect(); | 1174 | resetHaveResizeEffect(); | ||
1265 | } | 1175 | } | ||
1266 | 1176 | | |||
1267 | bool Client::shouldUnredirect() const | | |||
1268 | { | | |||
1269 | if (isActiveFullScreen()) { | | |||
1270 | ToplevelList stacking = workspace()->xStackingOrder(); | | |||
1271 | for (int pos = stacking.count() - 1; | | |||
1272 | pos >= 0; | | |||
1273 | --pos) { | | |||
1274 | Toplevel* c = stacking.at(pos); | | |||
1275 | if (c == this) // is not covered by any other window, ok to unredirect | | |||
1276 | return true; | | |||
1277 | if (c->geometry().intersects(geometry())) | | |||
1278 | return false; | | |||
1279 | } | | |||
1280 | abort(); | | |||
1281 | } | | |||
1282 | return false; | | |||
1283 | } | | |||
1284 | | ||||
1285 | | ||||
1286 | //**************************************** | | |||
1287 | // Unmanaged | | |||
1288 | //**************************************** | | |||
1289 | | ||||
1290 | bool Unmanaged::shouldUnredirect() const | | |||
1291 | { | | |||
1292 | // the pixmap is needed for the login effect, a nicer solution would be the login effect increasing | | |||
1293 | // refcount for the window pixmap (which would prevent unredirect), avoiding this hack | | |||
1294 | if (resourceClass() == "ksplashx" | | |||
1295 | || resourceClass() == "ksplashsimple" | | |||
1296 | || resourceClass() == "ksplashqml" | | |||
1297 | ) | | |||
1298 | return false; | | |||
1299 | // it must cover whole display or one xinerama screen, and be the topmost there | | |||
1300 | const int desktop = VirtualDesktopManager::self()->current(); | | |||
1301 | if (geometry() == workspace()->clientArea(FullArea, geometry().center(), desktop) | | |||
1302 | || geometry() == workspace()->clientArea(ScreenArea, geometry().center(), desktop)) { | | |||
1303 | ToplevelList stacking = workspace()->xStackingOrder(); | | |||
1304 | for (int pos = stacking.count() - 1; | | |||
1305 | pos >= 0; | | |||
1306 | --pos) { | | |||
1307 | Toplevel* c = stacking.at(pos); | | |||
1308 | if (c == this) // is not covered by any other window, ok to unredirect | | |||
1309 | return true; | | |||
1310 | if (c->geometry().intersects(geometry())) | | |||
1311 | return false; | | |||
1312 | } | | |||
1313 | abort(); | | |||
1314 | } | | |||
1315 | return false; | | |||
1316 | } | | |||
1317 | | ||||
1318 | //**************************************** | | |||
1319 | // Deleted | | |||
1320 | //**************************************** | | |||
1321 | | ||||
1322 | bool Deleted::shouldUnredirect() const | | |||
1323 | { | | |||
1324 | return false; | | |||
1325 | } | | |||
1326 | | ||||
1327 | | ||||
1328 | } // namespace | 1177 | } // namespace |