platform.cpp 21.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3, as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

T
Thomas Voß 已提交
18 19
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-default"
20
#include "anbox/platform/sdl/platform.h"
21 22
#include "anbox/input/device.h"
#include "anbox/input/manager.h"
23
#include "anbox/logger.h"
24 25 26
#include "anbox/platform/sdl/keycode_converter.h"
#include "anbox/platform/sdl/window.h"
#include "anbox/platform/sdl/audio_sink.h"
27
#include "anbox/platform/alsa/audio_source.h"
28
#include "anbox/system_configuration.h"
29

30
#include "anbox/wm/manager.h"
31 32 33

#include <boost/throw_exception.hpp>

S
Simon Fels 已提交
34
#include <signal.h>
35
#include <sys/types.h>
T
Thomas Voß 已提交
36
#pragma GCC diagnostic pop
S
Simon Fels 已提交
37

38
namespace anbox {
39 40 41
namespace platform {
namespace sdl {
Platform::Platform(
42
    const std::shared_ptr<input::Manager> &input_manager,
43
    const Configuration &config)
44
    : input_manager_(input_manager),
45
      event_thread_running_(false),
46
      ime_socket_file_(utils::string_format("%s/ime_socket", SystemConfiguration::instance().socket_dir())),
47
      config_(config) {
48 49 50 51 52 53
  // Don't block the screensaver from kicking in. It will be blocked
  // by the desktop shell already and we don't have to do this again.
  // If we would leave this enabled it will prevent systems from
  // suspending correctly.
  SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");

A
Awakening 已提交
54 55 56 57 58 59
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
  // Don't disable compositing
  // Available since SDL 2.0.8
  SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif

60 61 62 63
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) {
    const auto message = utils::string_format("Failed to initialize SDL: %s", SDL_GetError());
    BOOST_THROW_EXCEPTION(std::runtime_error(message));
  }
64

65
  auto display_frame = graphics::Rect::Invalid;
66
  if (config_.display_frame == graphics::Rect::Invalid) {
67 68 69
    for (auto n = 0; n < SDL_GetNumVideoDisplays(); n++) {
      SDL_Rect r;
      if (SDL_GetDisplayBounds(n, &r) != 0) continue;
70

71 72 73 74 75 76 77
      graphics::Rect frame{r.x, r.y, r.x + r.w, r.y + r.h};

      if (display_frame == graphics::Rect::Invalid)
        display_frame = frame;
      else
        display_frame.merge(frame);
    }
78

79
    if (display_frame == graphics::Rect::Invalid)
80 81 82
      BOOST_THROW_EXCEPTION(
          std::runtime_error("No valid display configuration found"));
  } else {
83
    display_frame = config_.display_frame;
84
    window_size_immutable_ = true;
85 86
  }

87
  graphics::emugl::DisplayInfo::get()->set_resolution(display_frame.width(), display_frame.height());
M
Marius Gripsgard 已提交
88
  display_frame_ = display_frame;
89

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  pointer_ = input_manager->create_device();
  pointer_->set_name("anbox-pointer");
  pointer_->set_driver_version(1);
  pointer_->set_input_id({BUS_VIRTUAL, 2, 2, 2});
  pointer_->set_physical_location("none");
  pointer_->set_key_bit(BTN_MOUSE);
  // NOTE: We don't use REL_X/REL_Y in reality but have to specify them here
  // to allow InputFlinger to detect we're a cursor device.
  pointer_->set_rel_bit(REL_X);
  pointer_->set_rel_bit(REL_Y);
  pointer_->set_rel_bit(REL_HWHEEL);
  pointer_->set_rel_bit(REL_WHEEL);
  pointer_->set_prop_bit(INPUT_PROP_POINTER);

  keyboard_ = input_manager->create_device();
  keyboard_->set_name("anbox-keyboard");
  keyboard_->set_driver_version(1);
  keyboard_->set_input_id({BUS_VIRTUAL, 3, 3, 3});
  keyboard_->set_physical_location("none");
  keyboard_->set_key_bit(BTN_MISC);
  keyboard_->set_key_bit(KEY_OK);
111

M
Marius Gripsgard 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
  touch_ = input_manager->create_device();
  touch_->set_name("anbox-touch");
  touch_->set_driver_version(1);
  touch_->set_input_id({BUS_VIRTUAL, 4, 4, 4});
  touch_->set_physical_location("none");
  touch_->set_abs_bit(ABS_MT_SLOT);
  touch_->set_abs_max(ABS_MT_SLOT, 10);
  touch_->set_abs_bit(ABS_MT_TOUCH_MAJOR);
  touch_->set_abs_max(ABS_MT_TOUCH_MAJOR, 127);
  touch_->set_abs_bit(ABS_MT_TOUCH_MINOR);
  touch_->set_abs_max(ABS_MT_TOUCH_MINOR, 127);
  touch_->set_abs_bit(ABS_MT_POSITION_X);
  touch_->set_abs_max(ABS_MT_POSITION_X, display_frame.width());
  touch_->set_abs_bit(ABS_MT_POSITION_Y);
  touch_->set_abs_max(ABS_MT_POSITION_Y, display_frame.height());
  touch_->set_abs_bit(ABS_MT_TRACKING_ID);
P
Pavel Andrejs 已提交
128
  touch_->set_abs_max(ABS_MT_TRACKING_ID, MAX_TRACKING_ID);
M
Marius Gripsgard 已提交
129 130
  touch_->set_prop_bit(INPUT_PROP_DIRECT);

P
Pavel Andrejs 已提交
131 132
  for (int i = 0; i < MAX_FINGERS; i++)
      touch_slots[i] = -1;
P
Pavel Andrejs 已提交
133

134
  event_thread_ = std::thread(&Platform::process_events, this);
135
  ime_thread_ = std::thread(&Platform::create_ime_socket, this);
136

137 138 139 140
  user_window_event = SDL_RegisterEvents(1);
  if (user_window_event < 0) {
    FATAL("SDL_RegisterEvents failed and can not recover,please restart service!!");
  }
141 142
}

143
Platform::~Platform() {
144 145 146 147
  if (event_thread_running_) {
    event_thread_running_ = false;
    event_thread_.join();
  }
148
  ime_thread_.join();
149 150 151
  if (ime_socket_ != -1) {
    close(ime_socket_);
  }
152 153
}

154
void Platform::set_renderer(const std::shared_ptr<Renderer> &renderer) {
S
Simon Fels 已提交
155 156 157
  renderer_ = renderer;
}

158
void Platform::set_window_manager(const std::shared_ptr<wm::Manager> &window_manager) {
159 160 161
  window_manager_ = window_manager;
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
// Added for Chinese input anbox begin
void Platform::create_ime_socket() {
  int ime_socket = -1;
  int client_socket = -1;
  int rc = -1;
  int len = 0;
  struct sockaddr_un socket_addr, client_addr;
  memset(&socket_addr, 0, sizeof(socket_addr));
  DEBUG("Starting create_ime_socket thread");
  ime_socket = socket(AF_UNIX, SOCK_STREAM, 0);
  if (ime_socket == -1) {
    ERROR("Create ime socket failed");
    return;
  }
  socket_addr.sun_family = AF_UNIX;
177 178 179 180
  if (ime_socket_file_.length() >= strlen(socket_addr.sun_path) - 1) {
    ERROR("Create ime failed, socket path too long");
    return;
  }
181 182
  strcpy(socket_addr.sun_path, ime_socket_file_.c_str());
  unlink(ime_socket_file_.c_str());
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  rc = bind(ime_socket, reinterpret_cast<struct sockaddr *>(&socket_addr), sizeof(socket_addr));
  if (rc == -1) {
    ERROR("bind ime socket failed");
    close(ime_socket);
    return;
  }
  rc = listen(ime_socket, 1);
  if (rc == -1) {
    ERROR("Listen ime socket failed");
    close(ime_socket);
    return;
  }
  DEBUG("Before ime socket accept");
  client_socket = accept(ime_socket, reinterpret_cast<struct sockaddr*>(&client_addr), 
      reinterpret_cast<socklen_t*>(&len));
  if (client_socket == -1) {
    ERROR("Accept ime socket failed");
    close(ime_socket);
    return;
  }
  ime_fd_ = client_socket;
  ime_socket_ = ime_socket;
  DEBUG("accept ime socket successful");
}
// Added for Chinese input anbox end

209
void Platform::process_events() {
210 211 212 213 214 215 216 217 218 219 220 221 222
  event_thread_running_ = true;

  while (event_thread_running_) {
    SDL_Event event;
    while (SDL_WaitEventTimeout(&event, 100)) {
      switch (event.type) {
        case SDL_QUIT:
          break;
        case SDL_WINDOWEVENT:
          for (auto &iter : windows_) {
            if (auto w = iter.second.lock()) {
              if (w->window_id() == event.window.windowID) {
                w->process_event(event);
223
                break;
224
              }
225
            }
226 227
          }
          break;
M
Marius Gripsgard 已提交
228
        case SDL_KEYDOWN:
229
          input_flag = 1;
230 231 232
          if (keyboard_)
            process_input_event(event);
          break;
M
Marius Gripsgard 已提交
233
        case SDL_KEYUP:
234
          input_flag = 0;
M
Marius Gripsgard 已提交
235 236 237
          if (keyboard_)
            process_input_event(event);
          break;
238 239 240 241
        case SDL_MOUSEMOTION:
        case SDL_MOUSEBUTTONDOWN:
        case SDL_MOUSEBUTTONUP:
        case SDL_MOUSEWHEEL:
M
Marius Gripsgard 已提交
242 243 244
        case SDL_FINGERDOWN:
        case SDL_FINGERUP:
        case SDL_FINGERMOTION:
245 246
          process_input_event(event);
          break;
247 248
        case SDL_TEXTINPUT:
          WARNING("Input Event TEXT=%s TYPE=%d WINDOWID=%d", event.text.text, event.type, event.text.windowID);
249
          if (text_input_fliter(event.text.text)) {
250 251 252
            send(ime_fd_, event.text.text, strlen(event.text.text), 0);
          }
          break;
T
Thomas Voß 已提交
253
        default:
254
          user_event_function(event);
T
Thomas Voß 已提交
255
          break;
256
      }
257
    }
258
  }
259 260
}

261 262 263 264 265
bool Platform::text_input_fliter(const char* text) {
  return text[0] > 0x7f || (input_flag == 0 &&
          ((text[0] <= 'Z' && text[0] >= 'A') || (text[0] <= 'z' && text[0] >= 'a')));
}

266 267 268 269 270 271
void Platform::user_event_function(const SDL_Event &event) {
  if (event.type == user_window_event) {
    int event_type = event.user.code;
    manager_window_param* param = (manager_window_param*) event.user.data1;
    if (param) {
      if (event_type == USER_CREATE_WINDOW) {
272
        if (tasks_.find(param->taskId) != tasks_.end()) {
N
night_xiaoye 已提交
273
          delete param;
274 275
          return;
        }
276
        auto w = create_window(param->taskId, param->rect, param->title);
277 278
        if (w) {
          w->attach();
279
          window_manager_->insert_task(param->taskId, w);
280 281
        } else {
          WARNING("create window failed! remove task on android!");
282
          window_manager_->remove_task(param->taskId);
283 284
        }
      } else if (event_type == USER_DESTROY_WINDOW) {
285 286 287 288 289 290
        window_manager_->erase_task(param->taskId);
        auto it = tasks_.find(param->taskId);
        if (it != tasks_.end()) {
            windows_.erase(it->second);
            tasks_.erase(it);
        }
291 292 293 294 295 296 297 298 299
      }
      delete param;
      param = nullptr;
    } else {
      ERROR("null point param!!");
    }
  }
}

300 301 302 303 304 305 306
void Platform::input_key_event(const SDL_Scancode &scan_code, std::int32_t down_or_up) {  // down_or_up: 1-down,0-up
  std::vector<input::Event> keyboard_events;
  std::uint16_t code = KeycodeConverter::convert(scan_code);
  keyboard_events.push_back({EV_KEY, code, down_or_up});
  keyboard_->send_events(keyboard_events);
}

307
void Platform::process_input_event(const SDL_Event &event) {
308 309
  std::vector<input::Event> mouse_events;
  std::vector<input::Event> keyboard_events;
M
Marius Gripsgard 已提交
310
  std::vector<input::Event> touch_events;
311

312 313
  std::int32_t x = 0;
  std::int32_t y = 0;
M
Marius Gripsgard 已提交
314

315
  switch (event.type) {
M
Marius Gripsgard 已提交
316
    // Mouse
317
    case SDL_MOUSEBUTTONDOWN:
318 319 320 321 322 323 324 325
      for (auto &iter : windows_) {
        if (auto w = iter.second.lock()) {
          if (w->window_id() == event.window.windowID &&
                  w->title_event_filter(event.button.y)) {
            return;
          }
        }
      }
326
      if (config_.no_touch_emulation) {
327 328 329 330 331 332
        mouse_events.push_back({EV_KEY, BTN_LEFT, 1});
      } else {
        x = event.button.x;
        y = event.button.y;
        if (!adjust_coordinates(x, y))
          break;
P
p-an 已提交
333
        push_finger_down(x, y, emulated_touch_id_, touch_events);
334
      }
335
      break;
336
    case SDL_MOUSEBUTTONUP:
337
      if (config_.no_touch_emulation) {
338 339
        mouse_events.push_back({EV_KEY, BTN_LEFT, 0});
      } else {
P
Pavel Andrejs 已提交
340
        push_finger_up(emulated_touch_id_, touch_events);
341
      }
342
      break;
343
    case SDL_MOUSEMOTION:
344 345 346 347 348
      x = event.motion.x;
      y = event.motion.y;
      if (!adjust_coordinates(x, y))
        break;

349
      if (config_.no_touch_emulation) {
350 351 352 353 354 355 356 357 358 359 360
        // NOTE: Sending relative move events doesn't really work and we have
        // changes in libinputflinger to take ABS_X/ABS_Y instead for absolute
        // position events.
        mouse_events.push_back({EV_ABS, ABS_X, x});
        mouse_events.push_back({EV_ABS, ABS_Y, y});
        // We're sending relative position updates here too but they will be only
        // used by the Android side EventHub/InputReader to determine if the cursor
        // was moved. They are not used to find out the exact position.
        mouse_events.push_back({EV_REL, REL_X, event.motion.xrel});
        mouse_events.push_back({EV_REL, REL_Y, event.motion.yrel});
      } else {
P
Pavel Andrejs 已提交
361
        push_finger_motion(x, y, emulated_touch_id_, touch_events);
362
      }
363
      break;
364
    case SDL_MOUSEWHEEL:
365
      if (!config_.no_touch_emulation) {
366 367 368
        SDL_GetMouseState(&x, &y);
        if (!adjust_coordinates(x, y))
          break;
369

370 371 372
        mouse_events.push_back({EV_ABS, ABS_X, x});
        mouse_events.push_back({EV_ABS, ABS_Y, y});
      }
373 374 375
      mouse_events.push_back(
          {EV_REL, REL_WHEEL, static_cast<std::int32_t>(event.wheel.y)});
      break;
M
Marius Gripsgard 已提交
376
    // Keyboard
377
    case SDL_KEYDOWN: {
378
      const auto code = KeycodeConverter::convert(event.key.keysym.scancode);
Y
yu_qinfei 已提交
379 380 381 382 383
      if (code == KEY_RESERVED) break;
      if (code == KEY_ESC) {
        input_key_event(SDL_SCANCODE_AC_BACK, 1);
        break;
      }
384 385
      keyboard_events.push_back({EV_KEY, code, 1});
      break;
386 387
    }
    case SDL_KEYUP: {
388
      const auto code = KeycodeConverter::convert(event.key.keysym.scancode);
Y
yu_qinfei 已提交
389 390 391 392 393
      if (code == KEY_RESERVED) break;
      if (code == KEY_ESC) {
        input_key_event(SDL_SCANCODE_AC_BACK, 0);
        break;
      }
394 395 396 397 398 399
      if (code == KEY_CAPSLOCK) {
        key_mod_ ^= KMOD_CAPS;
      }
      if (code == KEY_NUMLOCK) {
        key_mod_ ^= KMOD_NUM;
      }
400 401
      keyboard_events.push_back({EV_KEY, code, 0});
      break;
402
    }
M
Marius Gripsgard 已提交
403 404
    // Touch screen
    case SDL_FINGERDOWN: {
405 406
      if (!calculate_touch_coordinates(event, x, y))
        break;
P
Pavel Andrejs 已提交
407
      push_finger_down(x, y, event.tfinger.fingerId, touch_events);
M
Marius Gripsgard 已提交
408 409 410

      break;
    }
P
Pavel Andrejs 已提交
411
    case SDL_FINGERUP: {
P
Pavel Andrejs 已提交
412
      push_finger_up(event.tfinger.fingerId, touch_events);
M
Marius Gripsgard 已提交
413 414
      break;
    }
415
    case SDL_FINGERMOTION: {
416 417
      if (!calculate_touch_coordinates(event, x, y))
        break;
P
p-an 已提交
418
      push_finger_motion(x, y, event.tfinger.fingerId, touch_events);
M
Marius Gripsgard 已提交
419 420
      break;
    }
421
    default:
422 423
      break;
  }
424

425
  if (mouse_events.size() > 0) {
426
    mouse_events.push_back({EV_SYN, SYN_REPORT, 0});
427
    pointer_->send_events(mouse_events);
428
  }
429 430 431 432 433 434

  if (keyboard_events.size() > 0)
    keyboard_->send_events(keyboard_events);

  if (touch_events.size() > 0)
    touch_->send_events(touch_events);
435 436
}

437
int Platform::find_touch_slot(int id) {
438 439 440 441 442
  for (int i = 0; i < MAX_FINGERS; i++) {
    if (touch_slots[i] == id)
      return i;
  }
  return -1;
P
Pavel Andrejs 已提交
443 444
}

445
void Platform::push_slot(std::vector<input::Event> &touch_events, int slot) {
446 447 448 449
  if (last_slot != slot) {
    touch_events.push_back({EV_ABS, ABS_MT_SLOT, slot});
    last_slot = slot;
  }
P
Pavel Andrejs 已提交
450 451
}

452
void Platform::push_finger_down(int x, int y, int finger_id, std::vector<input::Event> &touch_events) {
453 454 455 456 457 458 459 460 461 462 463
  int slot = find_touch_slot(-1);
  if (slot == -1) {
    DEBUG("no free slot!");
    return;
  }
  touch_slots[slot] = finger_id;
  push_slot(touch_events, slot);
  touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, static_cast<std::int32_t>(finger_id % MAX_TRACKING_ID + 1)});
  touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x});
  touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y});
  touch_events.push_back({EV_SYN, SYN_REPORT, 0});
P
Pavel Andrejs 已提交
464 465
}

466
void Platform::push_finger_up(int finger_id, std::vector<input::Event> &touch_events) {
467 468 469 470 471 472 473
  int slot = find_touch_slot(finger_id);
  if (slot == -1)
    return;
  push_slot(touch_events, slot);
  touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, -1});
  touch_events.push_back({EV_SYN, SYN_REPORT, 0});
  touch_slots[slot] = -1;
P
Pavel Andrejs 已提交
474 475
}

476
void Platform::push_finger_motion(int x, int y, int finger_id, std::vector<input::Event> &touch_events) {
477 478 479 480 481 482 483
  int slot = find_touch_slot(finger_id);
  if (slot == -1)
    return;
  push_slot(touch_events, slot);
  touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x});
  touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y});
  touch_events.push_back({EV_SYN, SYN_REPORT, 0});
P
Pavel Andrejs 已提交
484 485 486
}


487 488 489
bool Platform::adjust_coordinates(std::int32_t &x, std::int32_t &y) {
  SDL_Window *window = nullptr;

490
  if (!config_.single_window) {
491 492 493 494 495 496 497 498 499 500 501
    window = SDL_GetWindowFromID(focused_sdl_window_id_);
    return adjust_coordinates(window, x, y);
  } else {
    // When running the whole Android system in a single window we don't
    // need to reacalculate and the pointer position as they are already
    // relative to our window.
    return true;
  }
}

bool Platform::adjust_coordinates(SDL_Window *window, std::int32_t &x, std::int32_t &y) {
502 503 504
  std::int32_t rel_x = 0;
  std::int32_t rel_y = 0;

505 506 507 508 509 510 511 512 513 514 515 516 517 518
  if (!window) {
    return false;
  }
  // As we get only absolute coordindates relative to our window we have to
  // calculate the correct position based on the current focused window
  SDL_GetWindowPosition(window, &rel_x, &rel_y);
  x += rel_x;
  y += rel_y;
  return true;
}

bool Platform::calculate_touch_coordinates(const SDL_Event &event,
                                           std::int32_t &x,
                                           std::int32_t &y) {
519 520
  SDL_Window *window = nullptr;

521
  window = SDL_GetWindowFromID(focused_sdl_window_id_);
522 523
  // before SDL 2.0.7 on X11 tfinger coordinates are not normalized
  if (!SDL_VERSION_ATLEAST(2,0,7) && (event.tfinger.x > 1 || event.tfinger.y > 1)) {
524 525
    x = event.tfinger.x;
    y = event.tfinger.y;
526 527
  } else {
    if (window) {
528 529 530
      SDL_GetWindowSize(window, &x, &y);
      x *= event.tfinger.x;
      y *= event.tfinger.y;
531
    } else {
532 533
      x = display_frame_.width() * event.tfinger.x;
      y = display_frame_.height() * event.tfinger.y;
534 535 536
    }
  }

537
  if (config_.single_window) {
538 539 540
    // When running the whole Android system in a single window we don't
    // need to reacalculate and the pointer position as they are already
    // relative to our window.
541 542 543
    return true;
  } else {
    return adjust_coordinates(window, x, y);
544 545 546
  }
}

547
Window::Id Platform::next_window_id() {
548 549
  static Window::Id next_id = 0;
  return next_id++;
550
}
551

552
std::shared_ptr<wm::Window> Platform::create_window(
553
    const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame, const std::string &title) {
S
Simon Fels 已提交
554 555 556 557 558
  if (!renderer_) {
    ERROR("Can't create window without a renderer set");
    return nullptr;
  }

559
  auto id = next_window_id();
560
  auto w = std::make_shared<Window>(renderer_, id, task, shared_from_this(), frame, title, !window_size_immutable_);
561
  focused_sdl_window_id_ = w->window_id();
562
  windows_.insert({id, w});
563
  tasks_.insert({task, id});
564
  return w;
565 566
}

567
void Platform::window_deleted(const Window::Id &id) {
568 569 570 571 572
  auto w = windows_.find(id);
  if (w == windows_.end()) {
    WARNING("Got window removed event for unknown window (id %d)", id);
    return;
  }
573
  if (auto window = w->second.lock())
574 575
  {
    tasks_.erase(window->task());
576
    window_manager_->remove_task(window->task());
577
  }
578
  windows_.erase(w);
579
}
580

581
void Platform::window_wants_focus(const Window::Id &id) {
582
  auto w = windows_.find(id);
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  if (w == windows_.end()) {
    return;
  }

  // if window's modstate is not the same as android, send
  // capslock or numlock message to android to change it.
  auto mod_state = SDL_GetModState();
  if ((key_mod_ & KMOD_NUM) != (mod_state & KMOD_NUM)) {
    input_key_event(SDL_SCANCODE_NUMLOCKCLEAR, 1);
    input_key_event(SDL_SCANCODE_NUMLOCKCLEAR, 0);
    key_mod_ ^= KMOD_NUM;
  }
  if ((key_mod_ & KMOD_CAPS) != (mod_state & KMOD_CAPS)) {
    input_key_event(SDL_SCANCODE_CAPSLOCK, 1);
    input_key_event(SDL_SCANCODE_CAPSLOCK, 0);
    key_mod_ ^= KMOD_CAPS;
  }
S
Simon Fels 已提交
600

601
  if (auto window = w->second.lock()) {
602
    focused_sdl_window_id_ = window->window_id();
603
    window_manager_->set_focused_task(window->task());
604
  }
S
Simon Fels 已提交
605 606
}

607
void Platform::window_moved(const Window::Id &id, const std::int32_t &x,
S
Simon Fels 已提交
608
                                  const std::int32_t &y) {
609 610 611 612 613 614
  auto w = windows_.find(id);
  if (w == windows_.end()) return;

  if (auto window = w->second.lock()) {
    auto new_frame = window->frame();
    new_frame.translate(x, y);
615
    window->update_frame(new_frame);
616
    window_manager_->resize_task(window->task(), new_frame, 3);
617 618 619
  }
}

620
void Platform::window_resized(const Window::Id &id,
S
Simon Fels 已提交
621 622
                                    const std::int32_t &width,
                                    const std::int32_t &height) {
623 624 625 626 627 628 629 630 631 632 633
  auto w = windows_.find(id);
  if (w == windows_.end()) return;

  if (auto window = w->second.lock()) {
    auto new_frame = window->frame();
    new_frame.resize(width, height);
    // We need to update the window frame in advance here as otherwise we may
    // get a movement event before we got an update of the actual layer
    // representing this window and then we're back to the original size of
    // the task.
    window->update_frame(new_frame);
634
    window_manager_->resize_task(window->task(), new_frame, 3);
635 636 637
  }
}

638
void Platform::set_clipboard_data(const ClipboardData &data) {
639 640 641 642 643
  if (data.text.empty())
    return;
  SDL_SetClipboardText(data.text.c_str());
}

644
Platform::ClipboardData Platform::get_clipboard_data() {
645 646 647 648 649 650 651 652 653 654 655 656
  if (!SDL_HasClipboardText())
    return ClipboardData{};

  auto text = SDL_GetClipboardText();
  if (!text)
    return ClipboardData{};

  auto data = ClipboardData{text};
  SDL_free(text);
  return data;
}

657
std::shared_ptr<audio::Sink> Platform::create_audio_sink() {
S
Simon Fels 已提交
658 659 660
  return std::make_shared<AudioSink>();
}

661
std::shared_ptr<audio::Source> Platform::create_audio_source() {
662
  return std::make_shared<AudioSource>();
S
Simon Fels 已提交
663
}
664 665 666 667

bool Platform::supports_multi_window() const {
  return true;
}
668 669 670 671 672 673 674

int Platform::get_user_window_event() const {
  if (user_window_event < 0) {
    FATAL("SDL_RegisterEvents failed and can not recover,please restart service!!");
  }
  return user_window_event;
}
675 676 677
} // namespace sdl
} // namespace platform
} // namespace anbox