blob: 2d1d23ff7143cda45165f625148fd40b03577ef6 [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"
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()
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)) {
if (ui::X11EventSource::HasInstance())
ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
x_root_window_events_ = std::make_unique<ui::XScopedEventSelector>(
x_root_window_, StructureNotifyMask | SubstructureNotifyMask);
}
X11MenuRegistrar::~X11MenuRegistrar() {
if (ui::X11EventSource::HasInstance())
ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
}
bool X11MenuRegistrar::DispatchXEvent(XEvent* event) {
if (event->type != CreateNotify && event->type != DestroyNotify) {
return false;
}
switch (event->type) {
case CreateNotify:
OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window);
break;
case DestroyNotify:
OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window);
break;
default:
NOTREACHED();
}
return false;
}
void X11MenuRegistrar::OnWindowCreatedOrDestroyed(int event_type, XID 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 (event_type == CreateNotify) {
// 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