Changeset View
Changeset View
Standalone View
Standalone View
group.cpp
Show First 20 Lines • Show All 148 Lines • ▼ Show 20 Line(s) | |||||
149 | 149 | | |||
150 | //*************************************** | 150 | //*************************************** | ||
151 | // Workspace | 151 | // Workspace | ||
152 | //*************************************** | 152 | //*************************************** | ||
153 | 153 | | |||
154 | Group* Workspace::findGroup(xcb_window_t leader) const | 154 | Group* Workspace::findGroup(xcb_window_t leader) const | ||
155 | { | 155 | { | ||
156 | Q_ASSERT(leader != XCB_WINDOW_NONE); | 156 | Q_ASSERT(leader != XCB_WINDOW_NONE); | ||
157 | for (GroupList::ConstIterator it = groups.constBegin(); | 157 | for (auto it = groups.constBegin(); | ||
158 | it != groups.constEnd(); | 158 | it != groups.constEnd(); | ||
159 | ++it) | 159 | ++it) | ||
160 | if ((*it)->leader() == leader) | 160 | if ((*it)->leader() == leader) | ||
161 | return *it; | 161 | return *it; | ||
162 | return nullptr; | 162 | return nullptr; | ||
163 | } | 163 | } | ||
164 | 164 | | |||
165 | // Client is group transient, but has no group set. Try to find | 165 | // Client is group transient, but has no group set. Try to find | ||
166 | // group with windows with the same client leader. | 166 | // group with windows with the same client leader. | ||
167 | Group* Workspace::findClientLeaderGroup(const X11Client *c) const | 167 | Group* Workspace::findClientLeaderGroup(const X11Client *c) const | ||
168 | { | 168 | { | ||
169 | Group* ret = nullptr; | 169 | Group* ret = nullptr; | ||
170 | for (ClientList::ConstIterator it = clients.constBegin(); | 170 | for (auto it = clients.constBegin(); | ||
171 | it != clients.constEnd(); | 171 | it != clients.constEnd(); | ||
172 | ++it) { | 172 | ++it) { | ||
173 | if (*it == c) | 173 | if (*it == c) | ||
174 | continue; | 174 | continue; | ||
175 | if ((*it)->wmClientLeader() == c->wmClientLeader()) { | 175 | if ((*it)->wmClientLeader() == c->wmClientLeader()) { | ||
176 | if (ret == nullptr || ret == (*it)->group()) | 176 | if (ret == nullptr || ret == (*it)->group()) | ||
177 | ret = (*it)->group(); | 177 | ret = (*it)->group(); | ||
178 | else { | 178 | else { | ||
179 | // There are already two groups with the same client leader. | 179 | // There are already two groups with the same client leader. | ||
180 | // This most probably means the app uses group transients without | 180 | // This most probably means the app uses group transients without | ||
181 | // setting group for its windows. Merging the two groups is a bad | 181 | // setting group for its windows. Merging the two groups is a bad | ||
182 | // hack, but there's no really good solution for this case. | 182 | // hack, but there's no really good solution for this case. | ||
183 | ClientList old_group = (*it)->group()->members(); | 183 | QList<X11Client *> old_group = (*it)->group()->members(); | ||
184 | // old_group autodeletes when being empty | 184 | // old_group autodeletes when being empty | ||
185 | for (int pos = 0; | 185 | for (int pos = 0; | ||
186 | pos < old_group.count(); | 186 | pos < old_group.count(); | ||
187 | ++pos) { | 187 | ++pos) { | ||
188 | X11Client *tmp = old_group[ pos ]; | 188 | X11Client *tmp = old_group[ pos ]; | ||
189 | if (tmp != c) | 189 | if (tmp != c) | ||
190 | tmp->changeClientLeaderGroup(ret); | 190 | tmp->changeClientLeaderGroup(ret); | ||
191 | } | 191 | } | ||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | 240 | for (auto it = c->transients().constBegin(); | |||
243 | if ((*it)->isOnAllDesktops() != c->isOnAllDesktops()) | 243 | if ((*it)->isOnAllDesktops() != c->isOnAllDesktops()) | ||
244 | (*it)->setOnAllDesktops(c->isOnAllDesktops()); | 244 | (*it)->setOnAllDesktops(c->isOnAllDesktops()); | ||
245 | } | 245 | } | ||
246 | } | 246 | } | ||
247 | 247 | | |||
248 | // A new window has been mapped. Check if it's not a mainwindow for some already existing transient window. | 248 | // A new window has been mapped. Check if it's not a mainwindow for some already existing transient window. | ||
249 | void Workspace::checkTransients(xcb_window_t w) | 249 | void Workspace::checkTransients(xcb_window_t w) | ||
250 | { | 250 | { | ||
251 | for (ClientList::ConstIterator it = clients.constBegin(); | 251 | for (auto it = clients.constBegin(); | ||
252 | it != clients.constEnd(); | 252 | it != clients.constEnd(); | ||
253 | ++it) | 253 | ++it) | ||
254 | (*it)->checkTransient(w); | 254 | (*it)->checkTransient(w); | ||
255 | } | 255 | } | ||
256 | 256 | | |||
257 | 257 | | |||
258 | //**************************************** | 258 | //**************************************** | ||
259 | // Toplevel | 259 | // Toplevel | ||
▲ Show 20 Lines • Show All 187 Lines • ▼ Show 20 Line(s) | 432 | { | |||
447 | } | 447 | } | ||
448 | } | 448 | } | ||
449 | 449 | | |||
450 | void X11Client::removeFromMainClients() | 450 | void X11Client::removeFromMainClients() | ||
451 | { | 451 | { | ||
452 | if (transientFor()) | 452 | if (transientFor()) | ||
453 | transientFor()->removeTransient(this); | 453 | transientFor()->removeTransient(this); | ||
454 | if (groupTransient()) { | 454 | if (groupTransient()) { | ||
455 | for (ClientList::ConstIterator it = group()->members().constBegin(); | 455 | for (auto it = group()->members().constBegin(); | ||
456 | it != group()->members().constEnd(); | 456 | it != group()->members().constEnd(); | ||
457 | ++it) | 457 | ++it) | ||
458 | (*it)->removeTransient(this); | 458 | (*it)->removeTransient(this); | ||
459 | } | 459 | } | ||
460 | } | 460 | } | ||
461 | 461 | | |||
462 | // *sigh* this transiency handling is madness :( | 462 | // *sigh* this transiency handling is madness :( | ||
463 | // This one is called when destroying/releasing a window. | 463 | // This one is called when destroying/releasing a window. | ||
464 | // It makes sure this client is removed from all grouping | 464 | // It makes sure this client is removed from all grouping | ||
465 | // related lists. | 465 | // related lists. | ||
466 | void X11Client::cleanGrouping() | 466 | void X11Client::cleanGrouping() | ||
467 | { | 467 | { | ||
468 | // qDebug() << "CLEANGROUPING:" << this; | 468 | // qDebug() << "CLEANGROUPING:" << this; | ||
469 | // for ( ClientList::ConstIterator it = group()->members().begin(); | 469 | // for ( auto it = group()->members().begin(); | ||
470 | // it != group()->members().end(); | 470 | // it != group()->members().end(); | ||
471 | // ++it ) | 471 | // ++it ) | ||
472 | // qDebug() << "CL:" << *it; | 472 | // qDebug() << "CL:" << *it; | ||
473 | // ClientList mains; | 473 | // QList<X11Client *> mains; | ||
474 | // mains = mainClients(); | 474 | // mains = mainClients(); | ||
475 | // for ( ClientList::ConstIterator it = mains.begin(); | 475 | // for ( auto it = mains.begin(); | ||
476 | // it != mains.end(); | 476 | // it != mains.end(); | ||
477 | // ++it ) | 477 | // ++it ) | ||
478 | // qDebug() << "MN:" << *it; | 478 | // qDebug() << "MN:" << *it; | ||
479 | removeFromMainClients(); | 479 | removeFromMainClients(); | ||
480 | // qDebug() << "CLEANGROUPING2:" << this; | 480 | // qDebug() << "CLEANGROUPING2:" << this; | ||
481 | // for ( ClientList::ConstIterator it = group()->members().begin(); | 481 | // for ( auto it = group()->members().begin(); | ||
482 | // it != group()->members().end(); | 482 | // it != group()->members().end(); | ||
483 | // ++it ) | 483 | // ++it ) | ||
484 | // qDebug() << "CL2:" << *it; | 484 | // qDebug() << "CL2:" << *it; | ||
485 | // mains = mainClients(); | 485 | // mains = mainClients(); | ||
486 | // for ( ClientList::ConstIterator it = mains.begin(); | 486 | // for ( auto it = mains.begin(); | ||
487 | // it != mains.end(); | 487 | // it != mains.end(); | ||
488 | // ++it ) | 488 | // ++it ) | ||
489 | // qDebug() << "MN2:" << *it; | 489 | // qDebug() << "MN2:" << *it; | ||
490 | for (auto it = transients().constBegin(); | 490 | for (auto it = transients().constBegin(); | ||
491 | it != transients().constEnd(); | 491 | it != transients().constEnd(); | ||
492 | ) { | 492 | ) { | ||
493 | if ((*it)->transientFor() == this) { | 493 | if ((*it)->transientFor() == this) { | ||
494 | removeTransient(*it); | 494 | removeTransient(*it); | ||
495 | it = transients().constBegin(); // restart, just in case something more has changed with the list | 495 | it = transients().constBegin(); // restart, just in case something more has changed with the list | ||
496 | } else | 496 | } else | ||
497 | ++it; | 497 | ++it; | ||
498 | } | 498 | } | ||
499 | // qDebug() << "CLEANGROUPING3:" << this; | 499 | // qDebug() << "CLEANGROUPING3:" << this; | ||
500 | // for ( ClientList::ConstIterator it = group()->members().begin(); | 500 | // for ( auto it = group()->members().begin(); | ||
501 | // it != group()->members().end(); | 501 | // it != group()->members().end(); | ||
502 | // ++it ) | 502 | // ++it ) | ||
503 | // qDebug() << "CL3:" << *it; | 503 | // qDebug() << "CL3:" << *it; | ||
504 | // mains = mainClients(); | 504 | // mains = mainClients(); | ||
505 | // for ( ClientList::ConstIterator it = mains.begin(); | 505 | // for ( auto it = mains.begin(); | ||
506 | // it != mains.end(); | 506 | // it != mains.end(); | ||
507 | // ++it ) | 507 | // ++it ) | ||
508 | // qDebug() << "MN3:" << *it; | 508 | // qDebug() << "MN3:" << *it; | ||
509 | // HACK | 509 | // HACK | ||
510 | // removeFromMainClients() did remove 'this' from transient | 510 | // removeFromMainClients() did remove 'this' from transient | ||
511 | // lists of all group members, but then made windows that | 511 | // lists of all group members, but then made windows that | ||
512 | // were transient for 'this' group transient, which again | 512 | // were transient for 'this' group transient, which again | ||
513 | // added 'this' to those transient lists :( | 513 | // added 'this' to those transient lists :( | ||
514 | ClientList group_members = group()->members(); | 514 | QList<X11Client *> group_members = group()->members(); | ||
515 | group()->removeMember(this); | 515 | group()->removeMember(this); | ||
516 | in_group = nullptr; | 516 | in_group = nullptr; | ||
517 | for (ClientList::ConstIterator it = group_members.constBegin(); | 517 | for (auto it = group_members.constBegin(); | ||
518 | it != group_members.constEnd(); | 518 | it != group_members.constEnd(); | ||
519 | ++it) | 519 | ++it) | ||
520 | (*it)->removeTransient(this); | 520 | (*it)->removeTransient(this); | ||
521 | // qDebug() << "CLEANGROUPING4:" << this; | 521 | // qDebug() << "CLEANGROUPING4:" << this; | ||
522 | // for ( ClientList::ConstIterator it = group_members.begin(); | 522 | // for ( auto it = group_members.begin(); | ||
523 | // it != group_members.end(); | 523 | // it != group_members.end(); | ||
524 | // ++it ) | 524 | // ++it ) | ||
525 | // qDebug() << "CL4:" << *it; | 525 | // qDebug() << "CL4:" << *it; | ||
526 | m_transientForId = XCB_WINDOW_NONE; | 526 | m_transientForId = XCB_WINDOW_NONE; | ||
527 | } | 527 | } | ||
528 | 528 | | |||
529 | // Make sure that no group transient is considered transient | 529 | // Make sure that no group transient is considered transient | ||
530 | // for a window that is (directly or indirectly) transient for it | 530 | // for a window that is (directly or indirectly) transient for it | ||
531 | // (including another group transients). | 531 | // (including another group transients). | ||
532 | // Non-group transients not causing loops are checked in verifyTransientFor(). | 532 | // Non-group transients not causing loops are checked in verifyTransientFor(). | ||
533 | void X11Client::checkGroupTransients() | 533 | void X11Client::checkGroupTransients() | ||
534 | { | 534 | { | ||
535 | for (ClientList::ConstIterator it1 = group()->members().constBegin(); | 535 | for (auto it1 = group()->members().constBegin(); | ||
536 | it1 != group()->members().constEnd(); | 536 | it1 != group()->members().constEnd(); | ||
537 | ++it1) { | 537 | ++it1) { | ||
538 | if (!(*it1)->groupTransient()) // check all group transients in the group | 538 | if (!(*it1)->groupTransient()) // check all group transients in the group | ||
539 | continue; // TODO optimize to check only the changed ones? | 539 | continue; // TODO optimize to check only the changed ones? | ||
540 | for (ClientList::ConstIterator it2 = group()->members().constBegin(); | 540 | for (auto it2 = group()->members().constBegin(); | ||
541 | it2 != group()->members().constEnd(); | 541 | it2 != group()->members().constEnd(); | ||
542 | ++it2) { // group transients can be transient only for others in the group, | 542 | ++it2) { // group transients can be transient only for others in the group, | ||
543 | // so don't make them transient for the ones that are transient for it | 543 | // so don't make them transient for the ones that are transient for it | ||
544 | if (*it1 == *it2) | 544 | if (*it1 == *it2) | ||
545 | continue; | 545 | continue; | ||
546 | for (AbstractClient* cl = (*it2)->transientFor(); | 546 | for (AbstractClient* cl = (*it2)->transientFor(); | ||
547 | cl != nullptr; | 547 | cl != nullptr; | ||
548 | cl = cl->transientFor()) { | 548 | cl = cl->transientFor()) { | ||
Show All 9 Lines | |||||
558 | // TODO This could possibly be optimized, it also requires hasTransient() to check for loops. | 558 | // TODO This could possibly be optimized, it also requires hasTransient() to check for loops. | ||
559 | if ((*it2)->groupTransient() && (*it1)->hasTransient(*it2, true) && (*it2)->hasTransient(*it1, true)) | 559 | if ((*it2)->groupTransient() && (*it1)->hasTransient(*it2, true) && (*it2)->hasTransient(*it1, true)) | ||
560 | (*it2)->removeTransientFromList(*it1); | 560 | (*it2)->removeTransientFromList(*it1); | ||
561 | // if there are already windows W1 and W2, W2 being transient for W1, and group transient W3 | 561 | // if there are already windows W1 and W2, W2 being transient for W1, and group transient W3 | ||
562 | // is added, make it transient only for W2, not for W1, because it's already indirectly | 562 | // is added, make it transient only for W2, not for W1, because it's already indirectly | ||
563 | // transient for it - the indirect transiency actually shouldn't break anything, | 563 | // transient for it - the indirect transiency actually shouldn't break anything, | ||
564 | // but it can lead to exponentially expensive operations (#95231) | 564 | // but it can lead to exponentially expensive operations (#95231) | ||
565 | // TODO this is pretty slow as well | 565 | // TODO this is pretty slow as well | ||
566 | for (ClientList::ConstIterator it3 = group()->members().constBegin(); | 566 | for (auto it3 = group()->members().constBegin(); | ||
567 | it3 != group()->members().constEnd(); | 567 | it3 != group()->members().constEnd(); | ||
568 | ++it3) { | 568 | ++it3) { | ||
569 | if (*it1 == *it2 || *it2 == *it3 || *it1 == *it3) | 569 | if (*it1 == *it2 || *it2 == *it3 || *it1 == *it3) | ||
570 | continue; | 570 | continue; | ||
571 | if ((*it2)->hasTransient(*it1, false) && (*it3)->hasTransient(*it1, false)) { | 571 | if ((*it2)->hasTransient(*it1, false) && (*it3)->hasTransient(*it1, false)) { | ||
572 | if ((*it2)->hasTransient(*it3, true)) | 572 | if ((*it2)->hasTransient(*it3, true)) | ||
573 | (*it2)->removeTransientFromList(*it1); | 573 | (*it2)->removeTransientFromList(*it1); | ||
574 | if ((*it3)->hasTransient(*it2, true)) | 574 | if ((*it3)->hasTransient(*it2, true)) | ||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Line(s) | |||||
648 | 648 | | |||
649 | void X11Client::addTransient(AbstractClient* cl) | 649 | void X11Client::addTransient(AbstractClient* cl) | ||
650 | { | 650 | { | ||
651 | AbstractClient::addTransient(cl); | 651 | AbstractClient::addTransient(cl); | ||
652 | if (workspace()->mostRecentlyActivatedClient() == this && cl->isModal()) | 652 | if (workspace()->mostRecentlyActivatedClient() == this && cl->isModal()) | ||
653 | check_active_modal = true; | 653 | check_active_modal = true; | ||
654 | // qDebug() << "ADDTRANS:" << this << ":" << cl; | 654 | // qDebug() << "ADDTRANS:" << this << ":" << cl; | ||
655 | // qDebug() << kBacktrace(); | 655 | // qDebug() << kBacktrace(); | ||
656 | // for ( ClientList::ConstIterator it = transients_list.begin(); | 656 | // for ( auto it = transients_list.begin(); | ||
657 | // it != transients_list.end(); | 657 | // it != transients_list.end(); | ||
658 | // ++it ) | 658 | // ++it ) | ||
659 | // qDebug() << "AT:" << (*it); | 659 | // qDebug() << "AT:" << (*it); | ||
660 | } | 660 | } | ||
661 | 661 | | |||
662 | void X11Client::removeTransient(AbstractClient* cl) | 662 | void X11Client::removeTransient(AbstractClient* cl) | ||
663 | { | 663 | { | ||
664 | // qDebug() << "REMOVETRANS:" << this << ":" << cl; | 664 | // qDebug() << "REMOVETRANS:" << this << ":" << cl; | ||
Show All 21 Lines | |||||
686 | } | 686 | } | ||
687 | 687 | | |||
688 | // returns true if cl is the transient_for window for this client, | 688 | // returns true if cl is the transient_for window for this client, | ||
689 | // or recursively the transient_for window | 689 | // or recursively the transient_for window | ||
690 | bool X11Client::hasTransient(const AbstractClient* cl, bool indirect) const | 690 | bool X11Client::hasTransient(const AbstractClient* cl, bool indirect) const | ||
691 | { | 691 | { | ||
692 | if (const X11Client *c = dynamic_cast<const X11Client *>(cl)) { | 692 | if (const X11Client *c = dynamic_cast<const X11Client *>(cl)) { | ||
693 | // checkGroupTransients() uses this to break loops, so hasTransient() must detect them | 693 | // checkGroupTransients() uses this to break loops, so hasTransient() must detect them | ||
694 | ConstClientList set; | 694 | QList<const X11Client *> set; | ||
695 | return hasTransientInternal(c, indirect, set); | 695 | return hasTransientInternal(c, indirect, set); | ||
696 | } | 696 | } | ||
697 | return false; | 697 | return false; | ||
698 | } | 698 | } | ||
699 | 699 | | |||
700 | bool X11Client::hasTransientInternal(const X11Client *cl, bool indirect, ConstClientList& set) const | 700 | bool X11Client::hasTransientInternal(const X11Client *cl, bool indirect, QList<const X11Client *> &set) const | ||
701 | { | 701 | { | ||
702 | if (const X11Client *t = dynamic_cast<const X11Client *>(cl->transientFor())) { | 702 | if (const X11Client *t = dynamic_cast<const X11Client *>(cl->transientFor())) { | ||
703 | if (t == this) | 703 | if (t == this) | ||
704 | return true; | 704 | return true; | ||
705 | if (!indirect) | 705 | if (!indirect) | ||
706 | return false; | 706 | return false; | ||
707 | if (set.contains(cl)) | 707 | if (set.contains(cl)) | ||
708 | return false; | 708 | return false; | ||
Show All 28 Lines | |||||
737 | QList<AbstractClient*> X11Client::mainClients() const | 737 | QList<AbstractClient*> X11Client::mainClients() const | ||
738 | { | 738 | { | ||
739 | if (!isTransient()) | 739 | if (!isTransient()) | ||
740 | return QList<AbstractClient*>(); | 740 | return QList<AbstractClient*>(); | ||
741 | if (const AbstractClient *t = transientFor()) | 741 | if (const AbstractClient *t = transientFor()) | ||
742 | return QList<AbstractClient*>{const_cast< AbstractClient* >(t)}; | 742 | return QList<AbstractClient*>{const_cast< AbstractClient* >(t)}; | ||
743 | QList<AbstractClient*> result; | 743 | QList<AbstractClient*> result; | ||
744 | Q_ASSERT(group()); | 744 | Q_ASSERT(group()); | ||
745 | for (ClientList::ConstIterator it = group()->members().constBegin(); | 745 | for (auto it = group()->members().constBegin(); | ||
746 | it != group()->members().constEnd(); | 746 | it != group()->members().constEnd(); | ||
747 | ++it) | 747 | ++it) | ||
748 | if ((*it)->hasTransient(this, false)) | 748 | if ((*it)->hasTransient(this, false)) | ||
749 | result.append(*it); | 749 | result.append(*it); | ||
750 | return result; | 750 | return result; | ||
751 | } | 751 | } | ||
752 | 752 | | |||
753 | AbstractClient* X11Client::findModal(bool allow_itself) | 753 | AbstractClient* X11Client::findModal(bool allow_itself) | ||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Line(s) | 842 | if (c->groupTransient() && c->group() != group()) { | |||
843 | removeTransientFromList(c); | 843 | removeTransientFromList(c); | ||
844 | it = transients().constBegin(); // restart, just in case something more has changed with the list | 844 | it = transients().constBegin(); // restart, just in case something more has changed with the list | ||
845 | } else | 845 | } else | ||
846 | ++it; | 846 | ++it; | ||
847 | } | 847 | } | ||
848 | if (groupTransient()) { | 848 | if (groupTransient()) { | ||
849 | // no longer transient for ones in the old group | 849 | // no longer transient for ones in the old group | ||
850 | if (old_group != nullptr) { | 850 | if (old_group != nullptr) { | ||
851 | for (ClientList::ConstIterator it = old_group->members().constBegin(); | 851 | for (auto it = old_group->members().constBegin(); | ||
852 | it != old_group->members().constEnd(); | 852 | it != old_group->members().constEnd(); | ||
853 | ++it) | 853 | ++it) | ||
854 | (*it)->removeTransient(this); | 854 | (*it)->removeTransient(this); | ||
855 | } | 855 | } | ||
856 | // and make transient for all in the new group | 856 | // and make transient for all in the new group | ||
857 | for (ClientList::ConstIterator it = group()->members().constBegin(); | 857 | for (auto it = group()->members().constBegin(); | ||
858 | it != group()->members().constEnd(); | 858 | it != group()->members().constEnd(); | ||
859 | ++it) { | 859 | ++it) { | ||
860 | if (*it == this) | 860 | if (*it == this) | ||
861 | break; // this means the window is only transient for windows mapped before it | 861 | break; // this means the window is only transient for windows mapped before it | ||
862 | (*it)->addTransient(this); | 862 | (*it)->addTransient(this); | ||
863 | } | 863 | } | ||
864 | } | 864 | } | ||
865 | // group transient splashscreens should be transient even for windows | 865 | // group transient splashscreens should be transient even for windows | ||
866 | // in group mapped later | 866 | // in group mapped later | ||
867 | for (ClientList::ConstIterator it = group()->members().constBegin(); | 867 | for (auto it = group()->members().constBegin(); | ||
868 | it != group()->members().constEnd(); | 868 | it != group()->members().constEnd(); | ||
869 | ++it) { | 869 | ++it) { | ||
870 | if (!(*it)->isSplash()) | 870 | if (!(*it)->isSplash()) | ||
871 | continue; | 871 | continue; | ||
872 | if (!(*it)->groupTransient()) | 872 | if (!(*it)->groupTransient()) | ||
873 | continue; | 873 | continue; | ||
874 | if (*it == this || hasTransient(*it, true)) // TODO indirect? | 874 | if (*it == this || hasTransient(*it, true)) // TODO indirect? | ||
875 | continue; | 875 | continue; | ||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |