380{
381 if (!_enabled)
382 return true;
383
384 std::unique_lock lock(_windowsLock);
385
386
387 if (_sentWorkArea.w == 0)
388 {
389 SDL_Rect usable{};
390 if (SDL_GetDisplayUsableBounds(SDL_GetPrimaryDisplay(), &usable))
391 sendWorkArea(usable);
392 }
393
394
395 for (auto& [wid, win] : _windows)
396 {
397 if (win.isDeleted() || !win.window())
398 continue;
399 for (SDL_Window* p = SDL_GetWindowParent(win.window()); p; p = SDL_GetWindowParent(p))
400 {
401 auto* owner = getWindowBySdlId(SDL_GetWindowID(p));
402 if (!owner || owner->isDeleted())
403 {
404 win.markDeleted();
405 break;
406 }
407 }
408 }
409
410
411 std::vector<std::pair<size_t, uint64_t>> dead;
412 for (auto& [wid, win] : _windows)
413 {
414 if (!win.isDeleted())
415 continue;
416 size_t depth = 0;
417 for (SDL_Window* p = win.window() ? SDL_GetWindowParent(win.window()) : nullptr; p;
418 p = SDL_GetWindowParent(p))
419 depth++;
420 dead.emplace_back(depth, wid);
421 }
422 std::sort(dead.begin(), dead.end(),
423 [](const auto& a, const auto& b) { return a.first > b.first; });
424 for (const auto& [depth, wid] : dead)
425 _windows.erase(wid);
426
427 _deadWindows.clear();
428
429
430 for (auto& it : _windows)
431 {
432 auto& win = it.second;
433 if (win.isPopup())
434 continue;
435
436 SDL_Window* parent = nullptr;
437 SDL_Rect parentRect{};
438 auto* owner = resolveParent(win.owner());
439 if (owner && (owner != &win))
440 {
441 parent = owner->window();
442 parentRect = owner->outerRect();
443 }
444 win.paint(primary, fallbackFormat, damage, parent, parentRect);
445
446 SDL_Rect refusedOuter{};
447 if (win.takeWmOverride(refusedOuter))
448 {
449 const SDL_Rect rect = win.serverRect(refusedOuter);
450 const SDL_Rect cur = win.windowRect();
451 WLog_DBG(TAG,
452 "wm-refused adopt id=0x%08" PRIx32
453 " outer=%dx%d -> srv=%d,%d %dx%d (was %dx%d)",
454 static_cast<uint32_t>(win.id()), refusedOuter.w, refusedOuter.h, rect.x,
455 rect.y, rect.w, rect.h, cur.w, cur.h);
456 if (!SDL_RectsEqual(&rect, &cur))
457 sendClientWindowMove(&win, rect);
458 win.adoptLocalGeometry(rect);
459 }
460 }
461
462
463 if (!_refreshSent)
464 {
465 for (auto& it : _windows)
466 {
467 if (it.second.isPopup() || !it.second.window())
468 continue;
469 auto* ctx = &_context->common()->context;
470 const auto dw = static_cast<UINT16>(
472 const auto dh = static_cast<UINT16>(
475 if (ctx->update && ctx->update->RefreshRect)
476 (void)ctx->update->RefreshRect(ctx, 1, &all);
477 _refreshSent = true;
478 WLog_DBG(TAG, "refresh-rect sent (first app window realized)");
479 break;
480 }
481 }
482
483 for (auto& it : _windows)
484 {
485 auto& popup = it.second;
486 if (!popup.isPopup())
487 continue;
488
489
490 if (!popup.isFrame() && isShadowFrame(popup))
491 popup.setFrame(true);
492
493
494 if (popup.isLayered())
495 {
496 constexpr int reach = 48;
497 const SDL_Rect sr = popup.windowRect();
498 bool anchored = false;
499 for (auto& other : _windows)
500 {
501 auto& cand = other.second;
502 if ((&cand == &popup) || !cand.isPopup() || cand.isLayered() || !cand.window() ||
503 ((SDL_GetWindowFlags(cand.window()) & SDL_WINDOW_HIDDEN) != 0))
504 continue;
505 SDL_Rect zone = cand.windowRect();
506 zone.x -= reach;
507 zone.y -= reach;
508 zone.w += 2 * reach;
509 zone.h += 2 * reach;
510
511
512 const bool inside = (sr.x >= zone.x) && (sr.y >= zone.y) &&
513 (sr.x + sr.w <= zone.x + zone.w) &&
514 (sr.y + sr.h <= zone.y + zone.h);
515 if (inside)
516 {
517 anchored = true;
518 break;
519 }
520 }
521 popup.setShadowAnchored(anchored);
522 }
523
525
526 if (auto* pw = popup.window())
527 {
528 SDL_Window* p = SDL_GetWindowParent(pw);
529 chosen = p ? getWindowBySdlId(SDL_GetWindowID(p)) : nullptr;
530 }
531 else
532 {
533 chosen = resolvePopupParent(popup);
534 if (!chosen)
535 WLog_DBG(TAG, "popup id=0x%08" PRIx32 " has no parent app window",
536 static_cast<UINT32>(popup.id()));
537 }
538
539 SDL_Window* parent = nullptr;
540 SDL_Rect parentRect{};
541 if (chosen)
542 {
543 parent = chosen->window();
544 parentRect = chosen->outerRect();
545 }
546 popup.paint(primary, fallbackFormat, damage, parent, parentRect);
547 }
548
549
550 applyZOrder();
551 return true;
552}