Ejemplo n.º 1
0
/// This is the main loop which handles the ScrollView-logic from the server
/// to the client. It basically loops through messages, parses them to events
/// and distributes it to the waiting handlers.
/// It is run from a different thread and synchronizes via SVSync.
void* ScrollView::MessageReceiver(void* a) {
  int counter_event_id = 0;  // ongoing counter
  char* message = nullptr;
  // Wait until a new message appears in the input stream_.
  do {
    message = ScrollView::GetStream()->Receive();
  } while (message == nullptr);

// This is the main loop which iterates until the server is dead (strlen = -1).
// It basically parses for 3 different messagetypes and then distributes the
// events accordingly.
  while (1) {
    // The new event we create.
    SVEvent* cur = new SVEvent;
    // The ID of the corresponding window.
    int window_id;

    int ev_type;

    int n;
    // Fill the new SVEvent properly.
    sscanf(message, "%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x,
           &cur->y, &cur->x_size, &cur->y_size, &cur->command_id, &n);
    char* p = (message + n);

    svmap_mu->Lock();
    cur->window = svmap[window_id];

    if (cur->window != nullptr) {
      cur->parameter = new char[strlen(p) + 1];
      strcpy(cur->parameter, p);
      if (strlen(p) > 0) {  // remove the last \n
        cur->parameter[strlen(p)] = '\0';
      }
      cur->type = static_cast<SVEventType>(ev_type);
      // Correct selection coordinates so x,y is the min pt and size is +ve.
      if (cur->x_size > 0)
        cur->x -= cur->x_size;
      else
        cur->x_size = -cur->x_size;
      if (cur->y_size > 0)
        cur->y -= cur->y_size;
      else
        cur->y_size = -cur->y_size;
      // Returned y will be the bottom-left if y is reversed.
      if (cur->window->y_axis_is_reversed_)
        cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
      cur->counter = counter_event_id;
      // Increase by 2 since we will also create an SVET_ANY event from cur,
      // which will have a counter_id of cur + 1 (and thus gets processed
      // after cur).
      counter_event_id += 2;

      // In case of an SVET_EXIT event, quit the whole application.
      if (ev_type == SVET_EXIT) { ScrollView::Exit(); }

      // Place two copies of it in the table for the window.
      cur->window->SetEvent(cur);

      // Check if any of the threads currently waiting want it.
      std::pair<ScrollView*, SVEventType> awaiting_list(cur->window,
                                                        cur->type);
      std::pair<ScrollView*, SVEventType> awaiting_list_any(cur->window,
                                                            SVET_ANY);
      std::pair<ScrollView*, SVEventType> awaiting_list_any_window((ScrollView*)nullptr,
                                                            SVET_ANY);
      waiting_for_events_mu->Lock();
      if (waiting_for_events.count(awaiting_list) > 0) {
        waiting_for_events[awaiting_list].second = cur;
        waiting_for_events[awaiting_list].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any) > 0) {
        waiting_for_events[awaiting_list_any].second = cur;
        waiting_for_events[awaiting_list_any].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
        waiting_for_events[awaiting_list_any_window].second = cur;
        waiting_for_events[awaiting_list_any_window].first->Signal();
      } else {
        // No one wanted it, so delete it.
        delete cur;
      }
      waiting_for_events_mu->Unlock();
      // Signal the corresponding semaphore twice (for both copies).
      ScrollView* sv = svmap[window_id];
      if (sv != nullptr) {
        sv->Signal();
        sv->Signal();
      }
    } else {
      delete cur;  // Applied to no window.
    }
    svmap_mu->Unlock();

    // Wait until a new message appears in the input stream_.
    do {
      message = ScrollView::GetStream()->Receive();
    } while (message == nullptr);
  }
  return nullptr;
}