blob: a6574374a574a598fbe18e32ed08b4a08c75786e [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/x/x11_menu_registrar.h"
#include <memory>
#include <string>
#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_error_tracker.h"
#include "ui/gfx/x/xproto.h"
namespace {
// Our global instance. Deleted when our Env() is deleted.
ui::X11MenuRegistrar* g_handler = nullptr;
} // namespace
namespace ui {
// static
X11MenuRegistrar* X11MenuRegistrar::Get() {
if (!g_handler)
g_handler = new X11MenuRegistrar;
return g_handler;
}
X11MenuRegistrar::X11MenuRegistrar() {
if (ui::X11EventSource::HasInstance())
ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
x_root_window_events_ = std::make_unique<ui::XScopedEventSelector>(
ui::GetX11RootWindow(), StructureNotifyMask | SubstructureNotifyMask);
}
X11MenuRegistrar::~X11MenuRegistrar() {
if (ui::X11EventSource::HasInstance())
ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
}
bool X11MenuRegistrar::DispatchXEvent(x11::Event* xev) {
if (auto* create = xev->As<x11::CreateNotifyEvent>())
OnWindowCreatedOrDestroyed(true, create->window);
else if (auto* destroy = xev->As<x11::DestroyNotifyEvent>())
OnWindowCreatedOrDestroyed(false, destroy->window);
return false;
}
void X11MenuRegistrar::OnWindowCreatedOrDestroyed(bool created,
x11::Window window) {
// Menus created by Chrome can be drag and drop targets. Since they are
// direct children of the screen root window and have override_redirect
// we cannot use regular _NET_CLIENT_LIST_STACKING property to find them
// and use a separate cache to keep track of them.
// TODO(varkha): Implement caching of all top level X windows and their
// coordinates and stacking order to eliminate repeated calls to the X server
// during mouse movement, drag and shaping events.
if (created) {
// The window might be destroyed if the message pump did not get a chance to
// run but we can safely ignore the X error.
gfx::X11ErrorTracker error_tracker;
XMenuList::GetInstance()->MaybeRegisterMenu(window);
} else {
XMenuList::GetInstance()->MaybeUnregisterMenu(window);
}
}
} // namespace ui