Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / braille_display_private / brlapi_connection.cc
blob88f4c0249b52bb2fa0f1d8219182028e00d15e97
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/braille_display_private/brlapi_connection.h"
7 #include <errno.h>
9 #include "base/message_loop/message_loop.h"
10 #include "base/sys_info.h"
12 namespace extensions {
13 using base::MessageLoopForIO;
14 namespace api {
15 namespace braille_display_private {
17 namespace {
18 // Default virtual terminal. This can be overriden by setting the
19 // WINDOWPATH environment variable. This is only used when not running
20 // under Crhome OS (that is in aura for a Linux desktop).
21 // TODO(plundblad): Find a way to detect the controlling terminal of the
22 // X server.
23 static const int kDefaultTtyLinux = 7;
24 #if defined(OS_CHROMEOS)
25 // The GUI is always running on vt1 in Chrome OS.
26 static const int kDefaultTtyChromeOS = 1;
27 #endif
28 } // namespace
30 class BrlapiConnectionImpl : public BrlapiConnection,
31 MessageLoopForIO::Watcher {
32 public:
33 explicit BrlapiConnectionImpl(LibBrlapiLoader* loader) :
34 libbrlapi_loader_(loader) {}
36 ~BrlapiConnectionImpl() override { Disconnect(); }
38 ConnectResult Connect(const OnDataReadyCallback& on_data_ready) override;
39 void Disconnect() override;
40 bool Connected() override { return handle_; }
41 brlapi_error_t* BrlapiError() override;
42 std::string BrlapiStrError() override;
43 bool GetDisplaySize(size_t* size) override;
44 bool WriteDots(const unsigned char* cells) override;
45 int ReadKey(brlapi_keyCode_t* keyCode) override;
47 // MessageLoopForIO::Watcher
48 void OnFileCanReadWithoutBlocking(int fd) override { on_data_ready_.Run(); }
50 void OnFileCanWriteWithoutBlocking(int fd) override {}
52 private:
53 bool CheckConnected();
54 ConnectResult ConnectResultForError();
56 LibBrlapiLoader* libbrlapi_loader_;
57 scoped_ptr<brlapi_handle_t, base::FreeDeleter> handle_;
58 MessageLoopForIO::FileDescriptorWatcher fd_controller_;
59 OnDataReadyCallback on_data_ready_;
61 DISALLOW_COPY_AND_ASSIGN(BrlapiConnectionImpl);
64 BrlapiConnection::BrlapiConnection() {
67 BrlapiConnection::~BrlapiConnection() {
70 scoped_ptr<BrlapiConnection> BrlapiConnection::Create(
71 LibBrlapiLoader* loader) {
72 DCHECK(loader->loaded());
73 return scoped_ptr<BrlapiConnection>(new BrlapiConnectionImpl(loader));
76 BrlapiConnection::ConnectResult BrlapiConnectionImpl::Connect(
77 const OnDataReadyCallback& on_data_ready) {
78 DCHECK(!handle_);
79 handle_.reset((brlapi_handle_t*) malloc(
80 libbrlapi_loader_->brlapi_getHandleSize()));
81 int fd = libbrlapi_loader_->brlapi__openConnection(handle_.get(), NULL, NULL);
82 if (fd < 0) {
83 handle_.reset();
84 VLOG(1) << "Error connecting to brlapi: " << BrlapiStrError();
85 return ConnectResultForError();
87 int path[2] = {0, 0};
88 int pathElements = 0;
89 #if defined(OS_CHROMEOS)
90 if (base::SysInfo::IsRunningOnChromeOS())
91 path[pathElements++] = kDefaultTtyChromeOS;
92 #endif
93 if (pathElements == 0 && getenv("WINDOWPATH") == NULL)
94 path[pathElements++] = kDefaultTtyLinux;
95 if (libbrlapi_loader_->brlapi__enterTtyModeWithPath(
96 handle_.get(), path, pathElements, NULL) < 0) {
97 LOG(ERROR) << "brlapi: couldn't enter tty mode: " << BrlapiStrError();
98 Disconnect();
99 return CONNECT_ERROR_RETRY;
102 size_t size;
103 if (!GetDisplaySize(&size)) {
104 // Error already logged.
105 Disconnect();
106 return CONNECT_ERROR_RETRY;
109 // A display size of 0 means no display connected. We can't reliably
110 // detect when a display gets connected, so fail and let the caller
111 // retry connecting.
112 if (size == 0) {
113 VLOG(1) << "No braille display connected";
114 Disconnect();
115 return CONNECT_ERROR_RETRY;
118 const brlapi_keyCode_t extraKeys[] = {
119 BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_OFFLINE,
120 // brltty 5.1 converts dot input to Unicode characters unless we
121 // explicitly accept this command.
122 BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_PASSDOTS,
124 if (libbrlapi_loader_->brlapi__acceptKeys(
125 handle_.get(), brlapi_rangeType_command, extraKeys,
126 arraysize(extraKeys)) < 0) {
127 LOG(ERROR) << "Couldn't acceptKeys: " << BrlapiStrError();
128 Disconnect();
129 return CONNECT_ERROR_RETRY;
132 if (!MessageLoopForIO::current()->WatchFileDescriptor(
133 fd, true, MessageLoopForIO::WATCH_READ, &fd_controller_, this)) {
134 LOG(ERROR) << "Couldn't watch file descriptor " << fd;
135 Disconnect();
136 return CONNECT_ERROR_RETRY;
139 on_data_ready_ = on_data_ready;
141 return CONNECT_SUCCESS;
144 void BrlapiConnectionImpl::Disconnect() {
145 if (!handle_) {
146 return;
148 fd_controller_.StopWatchingFileDescriptor();
149 libbrlapi_loader_->brlapi__closeConnection(
150 handle_.get());
151 handle_.reset();
154 brlapi_error_t* BrlapiConnectionImpl::BrlapiError() {
155 return libbrlapi_loader_->brlapi_error_location();
158 std::string BrlapiConnectionImpl::BrlapiStrError() {
159 return libbrlapi_loader_->brlapi_strerror(BrlapiError());
162 bool BrlapiConnectionImpl::GetDisplaySize(size_t* size) {
163 if (!CheckConnected()) {
164 return false;
166 unsigned int columns, rows;
167 if (libbrlapi_loader_->brlapi__getDisplaySize(
168 handle_.get(), &columns, &rows) < 0) {
169 LOG(ERROR) << "Couldn't get braille display size " << BrlapiStrError();
170 return false;
172 *size = columns * rows;
173 return true;
176 bool BrlapiConnectionImpl::WriteDots(const unsigned char* cells) {
177 if (!CheckConnected())
178 return false;
179 if (libbrlapi_loader_->brlapi__writeDots(handle_.get(), cells) < 0) {
180 VLOG(1) << "Couldn't write to brlapi: " << BrlapiStrError();
181 return false;
183 return true;
186 int BrlapiConnectionImpl::ReadKey(brlapi_keyCode_t* key_code) {
187 if (!CheckConnected())
188 return -1;
189 return libbrlapi_loader_->brlapi__readKey(
190 handle_.get(), 0 /*wait*/, key_code);
193 bool BrlapiConnectionImpl::CheckConnected() {
194 if (!handle_) {
195 BrlapiError()->brlerrno = BRLAPI_ERROR_ILLEGAL_INSTRUCTION;
196 return false;
198 return true;
201 BrlapiConnection::ConnectResult BrlapiConnectionImpl::ConnectResultForError() {
202 const brlapi_error_t* error = BrlapiError();
203 // For the majority of users, the socket file will never exist because
204 // the daemon is never run. Avoid retrying in this case, relying on
205 // the socket directory to change and trigger further tries if the
206 // daemon comes up later on.
207 if (error->brlerrno == BRLAPI_ERROR_LIBCERR
208 && error->libcerrno == ENOENT) {
209 return CONNECT_ERROR_NO_RETRY;
211 return CONNECT_ERROR_RETRY;
214 } // namespace braille_display_private
215 } // namespace api
216 } // namespace extensions