Changeset View
Changeset View
Standalone View
Standalone View
backends/xrandr/xrandroutput.cpp
Show All 34 Lines | |||||
35 | xcb_render_fixed_t fZero = DOUBLE_TO_FIXED(0); | 35 | xcb_render_fixed_t fZero = DOUBLE_TO_FIXED(0); | ||
36 | 36 | | |||
37 | XRandROutput::XRandROutput(xcb_randr_output_t id, XRandRConfig *config) | 37 | XRandROutput::XRandROutput(xcb_randr_output_t id, XRandRConfig *config) | ||
38 | : QObject(config) | 38 | : QObject(config) | ||
39 | , m_config(config) | 39 | , m_config(config) | ||
40 | , m_id(id) | 40 | , m_id(id) | ||
41 | , m_primary(false) | 41 | , m_primary(false) | ||
42 | , m_type(KScreen::Output::Unknown) | 42 | , m_type(KScreen::Output::Unknown) | ||
43 | , m_replicationSource(XCB_NONE) | | |||
44 | , m_crtc(nullptr) | 43 | , m_crtc(nullptr) | ||
45 | { | 44 | { | ||
46 | init(); | 45 | init(); | ||
47 | } | 46 | } | ||
48 | 47 | | |||
49 | XRandROutput::~XRandROutput() | 48 | XRandROutput::~XRandROutput() | ||
50 | { | 49 | { | ||
51 | } | 50 | } | ||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | 119 | { | |||
124 | return m_edid; | 123 | return m_edid; | ||
125 | } | 124 | } | ||
126 | 125 | | |||
127 | XRandRCrtc* XRandROutput::crtc() const | 126 | XRandRCrtc* XRandROutput::crtc() const | ||
128 | { | 127 | { | ||
129 | return m_crtc; | 128 | return m_crtc; | ||
130 | } | 129 | } | ||
131 | 130 | | |||
132 | xcb_randr_output_t XRandROutput::replicationSource() const | | |||
133 | { | | |||
134 | return m_replicationSource; | | |||
135 | } | | |||
136 | | ||||
137 | void XRandROutput::update() | 131 | void XRandROutput::update() | ||
138 | { | 132 | { | ||
139 | init(); | 133 | init(); | ||
140 | } | 134 | } | ||
141 | 135 | | |||
142 | void XRandROutput::update(xcb_randr_crtc_t crtc, xcb_randr_mode_t mode, xcb_randr_connection_t conn, | 136 | void XRandROutput::update(xcb_randr_crtc_t crtc, xcb_randr_mode_t mode, xcb_randr_connection_t conn, | ||
143 | bool primary) | 137 | bool primary) | ||
144 | { | 138 | { | ||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Line(s) | |||||
322 | 316 | | |||
323 | bool isScaling(const xcb_render_transform_t &tr) | 317 | bool isScaling(const xcb_render_transform_t &tr) | ||
324 | { | 318 | { | ||
325 | return tr.matrix11 != fZero && tr.matrix12 == fZero && tr.matrix13 == fZero && | 319 | return tr.matrix11 != fZero && tr.matrix12 == fZero && tr.matrix13 == fZero && | ||
326 | tr.matrix21 == fZero && tr.matrix22 != fZero && tr.matrix23 == fZero && | 320 | tr.matrix21 == fZero && tr.matrix22 != fZero && tr.matrix23 == fZero && | ||
327 | tr.matrix31 == fZero && tr.matrix32 == fZero && tr.matrix33 == fOne; | 321 | tr.matrix31 == fZero && tr.matrix32 == fZero && tr.matrix33 == fOne; | ||
328 | } | 322 | } | ||
329 | 323 | | |||
330 | xcb_render_transform_t zeroMatrix() | 324 | xcb_render_transform_t zeroTransform() | ||
331 | { | 325 | { | ||
332 | return { DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | 326 | return { DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | ||
333 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | 327 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | ||
334 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0) }; | 328 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0) }; | ||
335 | } | 329 | } | ||
336 | 330 | | |||
331 | xcb_render_transform_t unityTransform() | ||||
332 | { | ||||
333 | return { DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | ||||
334 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), | ||||
335 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1) }; | ||||
336 | } | ||||
337 | | ||||
337 | xcb_render_transform_t XRandROutput::currentTransform() const | 338 | xcb_render_transform_t XRandROutput::currentTransform() const | ||
338 | { | 339 | { | ||
339 | auto cookie = xcb_randr_get_crtc_transform(XCB::connection(), m_crtc->crtc()); | 340 | auto cookie = xcb_randr_get_crtc_transform(XCB::connection(), m_crtc->crtc()); | ||
340 | xcb_generic_error_t *error = nullptr; | 341 | xcb_generic_error_t *error = nullptr; | ||
341 | auto *reply = xcb_randr_get_crtc_transform_reply(XCB::connection(), cookie, &error); | 342 | auto *reply = xcb_randr_get_crtc_transform_reply(XCB::connection(), cookie, &error); | ||
342 | if (error) { | 343 | if (error) { | ||
343 | return zeroMatrix(); | 344 | return zeroTransform(); | ||
344 | } | 345 | } | ||
345 | 346 | | |||
346 | const xcb_render_transform_t transform = reply->pending_transform; | 347 | const xcb_render_transform_t transform = reply->pending_transform; | ||
347 | free(reply); | 348 | free(reply); | ||
348 | return transform; | 349 | return transform; | ||
349 | } | 350 | } | ||
350 | 351 | | |||
351 | QSizeF XRandROutput::scaledSize(xcb_render_transform_t transform) const | 352 | QSizeF XRandROutput::logicalSize() const | ||
352 | { | 353 | { | ||
353 | const QSize ownSize = size(); | 354 | const QSize modeSize = size(); | ||
354 | if (!ownSize.isValid()) { | 355 | if (!modeSize.isValid()) { | ||
355 | return QSize(); | 356 | return QSize(); | ||
356 | } | 357 | } | ||
357 | 358 | | |||
358 | const qreal width = FIXED_TO_DOUBLE(transform.matrix11) * ownSize.width(); | 359 | const xcb_render_transform_t transform = currentTransform(); | ||
359 | const qreal height = FIXED_TO_DOUBLE(transform.matrix22) * ownSize.height(); | 360 | const qreal width = FIXED_TO_DOUBLE(transform.matrix11) * modeSize.width(); | ||
361 | const qreal height = FIXED_TO_DOUBLE(transform.matrix22) * modeSize.height(); | ||||
360 | 362 | | |||
361 | return QSizeF(width, height); | 363 | return QSizeF(width, height); | ||
362 | } | 364 | } | ||
363 | 365 | | |||
364 | bool XRandROutput::isReplicaOf(XRandROutput *output, xcb_render_transform_t ownTransform) const | 366 | void XRandROutput::updateLogicalSize(const KScreen::OutputPtr &output) | ||
365 | { | | |||
366 | if (output->id() == m_id) { | | |||
367 | return false; | | |||
368 | } | | |||
369 | if (output->position() != position()) { | | |||
370 | return false; | | |||
371 | } | | |||
372 | if (output->replicationSource() != XCB_NONE) { | | |||
373 | return false; | | |||
374 | } | | |||
375 | | ||||
376 | const QSizeF sSize = scaledSize(ownTransform); | | |||
377 | if (!sSize.isValid()) { | | |||
378 | return false; | | |||
379 | } | | |||
380 | | ||||
381 | const auto outputTransform = output->currentTransform(); | | |||
382 | if (!isScaling(outputTransform)) { | | |||
383 | return false; | | |||
384 | } | | |||
385 | | ||||
386 | if (sSize != output->scaledSize(outputTransform)) { | | |||
387 | return false; | | |||
388 | } | | |||
389 | | ||||
390 | return true; | | |||
391 | } | | |||
392 | | ||||
393 | xcb_render_transform_t unityTransform() | | |||
394 | { | 367 | { | ||
395 | return { DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | 368 | const QSizeF logicalSize = output->explicitLogicalSize(); | ||
396 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), | 369 | xcb_render_transform_t transform = unityTransform(); | ||
397 | DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1) }; | | |||
398 | } | | |||
399 | | ||||
400 | xcb_render_transform_t XRandROutput::getReplicationTransform(XRandROutput *source) | | |||
401 | { | | |||
402 | if (!source) { | | |||
403 | return unityTransform(); | | |||
404 | } | | |||
405 | | ||||
406 | const auto *sourceMode = source->currentMode(); | | |||
407 | const auto *ownMode = currentMode(); | | |||
408 | if (!sourceMode || !ownMode) { | | |||
409 | return unityTransform(); | | |||
410 | } | | |||
411 | | ||||
412 | QSize sourceSize = sourceMode->size(); | | |||
413 | QSize size = ownMode->size(); | | |||
414 | 370 | | |||
415 | if (isHorizontal()) { | 371 | KScreen::ModePtr mode = output->currentMode() ? output->currentMode() : output->preferredMode(); | ||
416 | if (!source->isHorizontal()) { | 372 | if(mode && logicalSize.isValid()) { | ||
417 | sourceSize.transpose(); | 373 | QSize modeSize = mode->size(); | ||
418 | } | 374 | if (!output->isHorizontal()) { | ||
419 | } else if (source->isHorizontal()) { | 375 | modeSize.transpose(); | ||
420 | size.transpose(); | | |||
421 | } | 376 | } | ||
422 | 377 | | |||
423 | const qreal widthFactor = sourceSize.width() / (qreal)size.width(); | 378 | const qreal widthFactor = logicalSize.width() / (qreal)modeSize.width(); | ||
424 | const qreal heightFactor = sourceSize.height() / (qreal)size.height(); | 379 | const qreal heightFactor = logicalSize.height() / (qreal)modeSize.height(); | ||
425 | | ||||
426 | xcb_render_transform_t transform = unityTransform(); | | |||
427 | transform.matrix11 = DOUBLE_TO_FIXED(widthFactor); | 380 | transform.matrix11 = DOUBLE_TO_FIXED(widthFactor); | ||
428 | transform.matrix22 = DOUBLE_TO_FIXED(heightFactor); | 381 | transform.matrix22 = DOUBLE_TO_FIXED(heightFactor); | ||
429 | | ||||
430 | return transform; | | |||
431 | } | | |||
432 | | ||||
433 | bool XRandROutput::updateReplication() | | |||
434 | { | | |||
435 | XRandROutput *source = m_config->output(m_replicationSource); | | |||
436 | if (source && (!source->isEnabled() || !source->isConnected())) { | | |||
437 | return false; | | |||
438 | } | 382 | } | ||
439 | 383 | | |||
440 | xcb_render_transform_t transform = getReplicationTransform(source); | | |||
441 | QByteArray filterName(isScaling(transform) ? "bilinear" : "nearest"); | 384 | QByteArray filterName(isScaling(transform) ? "bilinear" : "nearest"); | ||
442 | 385 | | |||
443 | auto cookie = xcb_randr_set_crtc_transform_checked(XCB::connection(), | 386 | auto cookie = xcb_randr_set_crtc_transform_checked(XCB::connection(), | ||
444 | m_crtc->crtc(), | 387 | m_crtc->crtc(), | ||
445 | transform, | 388 | transform, | ||
446 | filterName.size(), filterName.data(), | 389 | filterName.size(), filterName.data(), | ||
447 | 0, nullptr); | 390 | 0, nullptr); | ||
448 | xcb_generic_error_t *error = xcb_request_check(XCB::connection(), cookie); | 391 | xcb_generic_error_t *error = xcb_request_check(XCB::connection(), cookie); | ||
449 | if (error) { | 392 | if (error) { | ||
450 | qCDebug(KSCREEN_XRANDR) << "Error on replication transformation!"; | 393 | qCDebug(KSCREEN_XRANDR) << "Error on logical size transformation!"; | ||
451 | free(error); | | |||
452 | return false; | | |||
453 | } | | |||
454 | free(error); | 394 | free(error); | ||
455 | return true; | | |||
456 | } | | |||
457 | | ||||
458 | bool XRandROutput::setReplicationSource(xcb_randr_output_t source) | | |||
459 | { | | |||
460 | if (!m_crtc) { | | |||
461 | return false; | | |||
462 | } | | |||
463 | if (m_replicationSource == source) { | | |||
464 | return true; | | |||
465 | } | | |||
466 | xcb_randr_output_t oldSource = m_replicationSource; | | |||
467 | m_replicationSource = source; | | |||
468 | if (!updateReplication()) { | | |||
469 | m_replicationSource = oldSource; | | |||
470 | return false; | | |||
471 | } | 395 | } | ||
472 | return true; | | |||
473 | } | 396 | } | ||
474 | 397 | | |||
475 | KScreen::OutputPtr XRandROutput::toKScreenOutput() const | 398 | KScreen::OutputPtr XRandROutput::toKScreenOutput() const | ||
476 | { | 399 | { | ||
477 | KScreen::OutputPtr kscreenOutput(new KScreen::Output); | 400 | KScreen::OutputPtr kscreenOutput(new KScreen::Output); | ||
478 | 401 | | |||
479 | const bool signalsBlocked = kscreenOutput->signalsBlocked(); | 402 | const bool signalsBlocked = kscreenOutput->signalsBlocked(); | ||
480 | kscreenOutput->blockSignals(true); | 403 | kscreenOutput->blockSignals(true); | ||
Show All 27 Lines | 415 | if (isConnected()) { | |||
508 | }(m_clones)); | 431 | }(m_clones)); | ||
509 | kscreenOutput->setEnabled(isEnabled()); | 432 | kscreenOutput->setEnabled(isEnabled()); | ||
510 | if (isEnabled()) { | 433 | if (isEnabled()) { | ||
511 | kscreenOutput->setSize(size()); | 434 | kscreenOutput->setSize(size()); | ||
512 | kscreenOutput->setPos(position()); | 435 | kscreenOutput->setPos(position()); | ||
513 | kscreenOutput->setRotation(rotation()); | 436 | kscreenOutput->setRotation(rotation()); | ||
514 | kscreenOutput->setCurrentModeId(currentModeId()); | 437 | kscreenOutput->setCurrentModeId(currentModeId()); | ||
515 | } | 438 | } | ||
516 | kscreenOutput->setReplicationSource(m_replicationSource); | 439 | // TODO: set logical size? | ||
517 | } | 440 | } | ||
518 | 441 | | |||
519 | kscreenOutput->blockSignals(signalsBlocked); | 442 | kscreenOutput->blockSignals(signalsBlocked); | ||
520 | return kscreenOutput; | 443 | return kscreenOutput; | ||
521 | } | 444 | } |