📄 scrollview.cpp
字号:
///////////////////////////////////////////////////////////////////////// File: scrollview.cc// Description: ScrollView// Author: Joern Wanke// Created: Thu Nov 29 2007//// (C) Copyright 2007, Google Inc.// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.///////////////////////////////////////////////////////////////////////////// This class contains the main ScrollView-logic,// e.g. parsing & sending messages, images etc.#ifdef WIN32#pragma warning(disable:4786) // Don't give stupid warnings for stl#endifconst int kSvPort = 8461;const int kMaxMsgSize = 4096;const int kMaxIntPairSize = 45; // Holds %d,%d, for upto 64 bit.#include "scrollview.h"#include <stdarg.h>#include <map>#include <utility>#include <algorithm>#include <vector>#include <string>#include "svutil.h"#ifdef HAVE_LIBLEPT#include "allheaders.h"#endifstruct SVPolyLineBuffer { bool empty; // Independent indicator to allow SendMsg to call SendPolygon. std::vector<int> xcoords; std::vector<int> ycoords;};// A map between the window IDs and their corresponding pointers.static std::map<int, ScrollView*> svmap;// A map of all semaphores waiting for a specific event on a specific window.static std::map<std::pair<ScrollView*, SVEventType>, std::pair<SVSemaphore*, SVEvent*> > waiting_for_events;SVMutex* mutex_waiting;SVEvent* SVEvent::copy() { SVEvent* any = new SVEvent; any->command_id = command_id; any->counter = counter; any->parameter = new char[strlen(parameter) + 1]; strncpy(any->parameter, parameter, strlen(parameter)); any->parameter[strlen(parameter)] = '\0'; any->type = type; any->x = x; any->y = y; any->x_size = x_size; any->y_size = y_size; any->window = window; return any;}// 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 = NULL; // Wait until a new message appears in the input stream_. do { message = ScrollView::GetStream()->Receive(); } while (message == NULL);// 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 (strlen(message) != -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); cur->window = svmap[window_id]; if (cur->window != NULL) { cur->parameter = new char[strlen(p) + 1]; strncpy(cur->parameter, p, strlen(p) + 1); if (strlen(p) > 0) { // remove the last \n cur->parameter[strlen(p)] = '\0'; } cur->type = static_cast<SVEventType>(ev_type); cur->y = cur->window->TranslateYCoordinate(cur->y); 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(NULL, SVET_ANY); mutex_waiting->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; } mutex_waiting->Unlock(); // Signal the corresponding semaphore twice (for both copies). ScrollView* sv = svmap[window_id]; if (sv != NULL) { sv->Signal(); sv->Signal(); } } // Wait until a new message appears in the input stream_. do { message = ScrollView::GetStream()->Receive(); } while (message == NULL); } return 0;}// Table to implement the color index values in the old system.int table_colors[ScrollView::GREEN_YELLOW+1][4]= { {0, 0, 0, 0}, // NONE (transparent) {0, 0, 0, 255}, // BLACK. {255, 255, 255, 255}, // WHITE. {255, 0, 0, 255}, // RED. {255, 255, 0, 255}, // YELLOW. {0, 255, 0, 255}, // GREEN. {0, 255, 255, 255}, // CYAN. {0, 0, 255, 255}, // BLUE. {255, 0, 255, 255}, // MAGENTA. {0, 128, 255, 255}, // AQUAMARINE. {0, 0, 64, 255}, // DARK_SLATE_BLUE. {128, 128, 255, 255}, // LIGHT_BLUE. {64, 64, 255, 255}, // MEDIUM_BLUE. {0, 0, 32, 255}, // MIDNIGHT_BLUE. {0, 0, 128, 255}, // NAVY_BLUE. {192, 192, 255, 255}, // SKY_BLUE. {64, 64, 128, 255}, // SLATE_BLUE. {32, 32, 64, 255}, // STEEL_BLUE. {255, 128, 128, 255}, // CORAL. {128, 64, 0, 255}, // BROWN. {128, 128, 0, 255}, // SANDY_BROWN. {192, 192, 0, 255}, // GOLD. {192, 192, 128, 255}, // GOLDENROD. {0, 64, 0, 255}, // DARK_GREEN. {32, 64, 0, 255}, // DARK_OLIVE_GREEN. {64, 128, 0, 255}, // FOREST_GREEN. {128, 255, 0, 255}, // LIME_GREEN. {192, 255, 192, 255}, // PALE_GREEN. {192, 255, 0, 255}, // YELLOW_GREEN. {192, 192, 192, 255}, // LIGHT_GREY. {64, 64, 128, 255}, // DARK_SLATE_GREY. {64, 64, 64, 255}, // DIM_GREY. {128, 128, 128, 255}, // GREY. {64, 192, 0, 255}, // KHAKI. {255, 0, 192, 255}, // MAROON. {255, 128, 0, 255}, // ORANGE. {255, 128, 64, 255}, // ORCHID. {255, 192, 192, 255}, // PINK. {128, 0, 128, 255}, // PLUM. {255, 0, 64, 255}, // INDIAN_RED. {255, 64, 0, 255}, // ORANGE_RED. {255, 0, 192, 255}, // VIOLET_RED. {255, 192, 128, 255}, // SALMON. {128, 128, 0, 255}, // TAN. {0, 255, 255, 255}, // TURQUOISE. {0, 128, 128, 255}, // DARK_TURQUOISE. {192, 0, 255, 255}, // VIOLET. {128, 128, 0, 255}, // WHEAT. {128, 255, 0, 255} // GREEN_YELLOW};/******************************************************************************** Scrollview implementation.*******************************************************************************/SVNetwork* ScrollView::stream_ = NULL;int ScrollView::nr_created_windows_ = 0;// Calls Initialize with all arguments given.ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size, bool y_axis_reversed, const char* server_name) { Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed, server_name);}// Calls Initialize with default argument for server_name_.ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size, bool y_axis_reversed) { Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed, "localhost");}// Calls Initialize with default argument for server_name_ & y_axis_reversed.ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size) { Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, false, "localhost");}// Sets up a ScrollView window, depending on the constructor variables.void ScrollView::Initialize(const char* name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size, bool y_axis_reversed, const char* server_name) { // If this is the first ScrollView Window which gets created, there is no // network connection yet and we have to set it up in a different thread. if (stream_ == NULL) { nr_created_windows_ = 0; stream_ = new SVNetwork(server_name, kSvPort); mutex_waiting = new SVMutex(); SendRawMessage( "svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n"); SVSync::StartThread(MessageReceiver, NULL); } // Set up the variables on the clientside. nr_created_windows_++; event_handler_ = NULL; y_axis_is_reversed_ = y_axis_reversed; y_size_ = y_canvas_size; window_name_ = name; window_id_ = nr_created_windows_; // Set up polygon buffering. points_ = new SVPolyLineBuffer; points_->empty = true; svmap[window_id_] = this; for (int i = 0; i < SVET_COUNT; i++) { event_table_[i] = NULL; } mutex_ = new SVMutex(); semaphore_ = new SVSemaphore(); // Set up an actual Window on the client side. char message[kMaxMsgSize]; snprintf(message, sizeof(message), "w%u = luajava.newInstance('com.google.scrollview.ui" ".SVWindow','%s',%u,%u,%u,%u,%u,%u,%u)\n", window_id_, window_name_, window_id_, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size); SendRawMessage(message); SVSync::StartThread(StartEventHandler, this);}// Sits and waits for events on this window.void* ScrollView::StartEventHandler(void* a) { ScrollView* sv = reinterpret_cast<ScrollView*>(a); SVEvent* new_event; do { stream_->Flush(); sv->semaphore_->Wait(); new_event = NULL; int serial = INT_MAX; int k = -1; sv->mutex_->Lock(); // Check every table entry if he is is valid and not already processed. for (int i = 0; i < SVET_COUNT; i++) { if ((sv->event_table_[i] != NULL) && (sv->event_table_[i]->counter < serial)) { new_event = sv->event_table_[i]; serial = sv->event_table_[i]->counter; k = i; } } // If we didnt find anything we had an old alarm and just sleep again. if (new_event != NULL) { sv->event_table_[k] = NULL; sv->mutex_->Unlock(); if (sv->event_handler_ != NULL) { sv->event_handler_->Notify(new_event); } if (new_event->type == SVET_DESTROY) { sv = NULL; } delete new_event; // Delete the pointer after it has been processed. } else { sv->mutex_->Unlock(); } // The thread should run as long as its associated window is alive. } while (sv != NULL); return 0;}ScrollView::~ScrollView() { if (svmap[window_id_] != NULL) { // So the event handling thread can quit. SendMsg("destroy()"); SVEvent* sve = AwaitEvent(SVET_DESTROY); delete sve; } delete mutex_; delete semaphore_; delete points_; svmap.erase(window_id_);}// Send a message to the server, attaching the window id.void ScrollView::SendMsg(const char* format, ...) { if (!points_->empty) SendPolygon(); va_list args; char message[kMaxMsgSize]; va_start(args, format); // variable list vsnprintf(message, kMaxMsgSize, format, args); va_end(args); char form[kMaxMsgSize]; snprintf(form, kMaxMsgSize, "w%u:%s\n", window_id_, message); stream_->Send(form);}// Send a message to the server without a// window id. Used for global events like exit().void ScrollView::SendRawMessage(const char* msg) { stream_->Send(msg);}// Add an Event Listener to this ScrollView Windowvoid ScrollView::AddEventHandler(SVEventHandler* listener) { event_handler_ = listener;}void ScrollView::Signal() { semaphore_->Signal();}void ScrollView::SetEvent(SVEvent* svevent) {// Copy event SVEvent* any = svevent->copy(); SVEvent* specific = svevent->copy(); any->counter = specific->counter + 1;// Place both events into the queue. mutex_->Lock(); // Delete the old objects.. if (event_table_[specific->type] != NULL) { delete event_table_[specific->type]; } if (event_table_[SVET_ANY] != NULL) { delete event_table_[SVET_ANY]; } // ...and put the new ones in the table. event_table_[specific->type] = specific; event_table_[SVET_ANY] = any; mutex_->Unlock();}// Block until an event of the given type is received.// Note: The calling function is responsible for deleting the returned// SVEvent afterwards!SVEvent* ScrollView::AwaitEvent(SVEventType type) { // Initialize the waiting semaphore. SVSemaphore* sem = new SVSemaphore(); std::pair<ScrollView*, SVEventType> ea(this, type); mutex_waiting->Lock(); waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, NULL); mutex_waiting->Unlock(); // Wait on it, but first flush. stream_->Flush(); sem->Wait(); // Process the event we got woken up for (its in waiting_for_events pair). mutex_waiting->Lock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -