blob: e4eb077e38642f47ba1a524d7e1cb59ea98ab713 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS 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 <unistd.h>
#include <cmath>
#include <cstdlib>
#include <ctime>
extern "C" {
#include <X11/Xlib.h>
}
#include <gflags/gflags.h>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "window_manager/callback.h"
#include "window_manager/compositor/real_compositor.h"
#if defined(COMPOSITOR_OPENGL)
#include "window_manager/compositor/gl/real_gl_interface.h"
#elif defined(COMPOSITOR_OPENGLES)
#include "window_manager/compositor/gles/real_gles2_interface.h"
#endif
#include "window_manager/event_loop.h"
#include "window_manager/profiler.h"
#include "window_manager/real_dbus_interface.h"
#include "window_manager/util.h"
#include "window_manager/window_manager.h"
#include "window_manager/x11/real_x_connection.h"
DEFINE_string(display, "",
"X Display to connect to (overrides DISPLAY env var).");
DEFINE_bool(logtostderr, false,
"Log to stderr (see --logged_{in,out}_log_dir otherwise)");
DEFINE_int32(pause_at_start, 0,
"Specify this to pause for N seconds at startup");
DEFINE_string(profile_dir, "./profile",
"Directory where profiles should be written; created if it "
"doesn't exist.");
DEFINE_int32(profile_max_samples, 200,
"Maximum number of samples (buffer size) for profiler.");
DEFINE_bool(start_profiler, false, "Start profiler at window manager startup.");
using std::string;
using window_manager::EventLoop;
using window_manager::RealCompositor;
using window_manager::RealDBusInterface;
#if defined(COMPOSITOR_OPENGL)
using window_manager::RealGLInterface;
#elif defined(COMPOSITOR_OPENGLES)
using window_manager::RealGles2Interface;
#else
#error COMPOSITOR_OPENGL or COMPOSITOR_OPENGLES must be defined
#endif
using window_manager::RealXConnection;
using window_manager::WindowManager;
using window_manager::util::GetTimeAsString;
using window_manager::util::SetUpLogSymlink;
// This should be adjusted according to number of PROFILER_MARKER_*
static const int kMaxNumProfilerSymbols = 100;
// Handler called by Chrome logging code on failed asserts.
static void HandleLogAssert(const string& str) {
abort();
}
// Handler called in response to Xlib I/O errors. We install this so we won't
// generate a window manager crash dump whenever the X server crashes.
static int HandleXIOError(Display* display) {
LOG(ERROR) << "Got X I/O error (probably lost connection to server); exiting";
_exit(EXIT_FAILURE);
}
int main(int argc, char** argv) {
base::AtExitManager exit_manager; // needed by base::Singleton
google::ParseCommandLineFlags(&argc, &argv, true);
if (!FLAGS_display.empty())
setenv("DISPLAY", FLAGS_display.c_str(), 1);
CommandLine::Init(argc, argv);
if (FLAGS_pause_at_start > 0)
sleep(FLAGS_pause_at_start);
// Just log to stderr initially; WindowManager will re-initialize to
// switch to a file once we know whether we're logged in or not if
// --logtostderr is false.
logging::InitLogging(NULL,
logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
logging::DONT_LOCK_LOG_FILE,
logging::APPEND_TO_OLD_LOG_FILE);
logging::SetLogItems(false, // enable_process_id
false, // enable_thread_id
true, // enable_timestamp
true); // enable_tickcount
// Chrome's logging code uses int3 to send SIGTRAP in response to failed
// asserts, but Breakpad only installs signal handlers for SEGV, ABRT,
// FPE, ILL, and BUS. Use our own function to send ABRT instead.
logging::SetLogAssertHandler(HandleLogAssert);
#if defined(PROFILE_BUILD)
const string profile_basename = StringPrintf(
"prof_%s.%s", WindowManager::GetWmName(),
GetTimeAsString(::time(NULL)).c_str());
if (!file_util::CreateDirectory(FilePath(FLAGS_profile_dir))) {
LOG(ERROR) << "Unable to create profiling directory " << FLAGS_profile_dir;
} else {
SetUpLogSymlink(StringPrintf("%s/prof_%s.LATEST",
FLAGS_profile_dir.c_str(),
WindowManager::GetWmName()),
profile_basename);
}
const string profile_path = FLAGS_profile_dir + "/" + profile_basename;
Singleton<window_manager::Profiler>()->Start(
new window_manager::ProfilerWriter(FilePath(profile_path)),
kMaxNumProfilerSymbols, FLAGS_profile_max_samples);
Singleton<window_manager::DynamicMarker>()->set_profiler(
Singleton<window_manager::Profiler>::get());
if (!FLAGS_start_profiler) {
Singleton<window_manager::Profiler>()->Pause();
}
#endif
const char* display_name = getenv("DISPLAY");
Display* display = XOpenDisplay(display_name);
if (!display) {
LOG(ERROR) << "Unable to open "
<< (display_name ? display_name : "default display");
return EXIT_FAILURE;
}
XSetIOErrorHandler(HandleXIOError);
RealXConnection xconn(display);
EventLoop event_loop;
#if defined(COMPOSITOR_OPENGL)
RealGLInterface gl_interface(&xconn);
#elif defined(COMPOSITOR_OPENGLES)
RealGles2Interface gl_interface(&xconn);
#endif
RealCompositor compositor(&event_loop, &xconn, &gl_interface);
RealDBusInterface dbus;
dbus.Init();
WindowManager wm(&event_loop, &xconn, &compositor, &dbus);
wm.set_initialize_logging(!FLAGS_logtostderr);
wm.Init();
// TODO: Need to also use XAddConnectionWatch()?
const int x11_fd = xconn.GetConnectionFileDescriptor();
LOG(INFO) << "X11 connection is on fd " << x11_fd;
event_loop.AddFileDescriptor(
x11_fd, NewPermanentCallback(&wm, &WindowManager::ProcessPendingEvents));
event_loop.AddPrePollCallback(
NewPermanentCallback(&wm, &WindowManager::ProcessPendingEvents));
event_loop.Run();
return EXIT_SUCCESS;
}