diff options
Diffstat (limited to 'src/app.cpp')
-rw-r--r-- | src/app.cpp | 230 |
1 files changed, 203 insertions, 27 deletions
diff --git a/src/app.cpp b/src/app.cpp index 98db0b4..e42d05f 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -32,8 +32,9 @@ #include <bits/signum.h> #include <csignal> #include <fstream> -#include <thread> #include <json.hpp> +#include <regex> +#include <thread> namespace wm { @@ -82,7 +83,8 @@ App::App(wl::display *d) config(), layouts(), layers(), - id_alloc{} { + id_alloc{}, + pending_events(false) { assert(g_app == nullptr); g_app = this; @@ -120,7 +122,8 @@ int App::init() { this->display->add_global_handler( "ivi_controller", [this](wl_registry *r, uint32_t name, uint32_t v) { - this->controller = std::make_unique<struct genivi::controller>(r, name, v); + this->controller = + std::make_unique<struct genivi::controller>(r, name, v); // Init controller hooks this->controller->chooks = &this->chooks; @@ -144,6 +147,11 @@ int App::init() { } int App::dispatch_events() { + if (this->pending_events.load(std::memory_order_consume)) { + this->pending_events.store(false, std::memory_order_release); + return this->display->dispatch_pending(); + } + int ret = this->display->dispatch(); if (ret == -1) { logerror("wl_display_dipatch() returned error %d", @@ -153,7 +161,7 @@ int App::dispatch_events() { this->display->flush(); // execute pending tasks, that is layout changes etc. - //this->execute_pending(); + // this->execute_pending(); return 0; } @@ -198,8 +206,9 @@ int App::init_layers() { auto &l = layers[i.layer_id]; l->set_destination_rectangle(0, 0, o->width, o->height); l->set_visibility(1); - logdebug("Setting up layer %s (%d) for surfaces %d-%d", i.name.c_str(), - i.layer_id, i.id_min, i.id_max); + logdebug("Setting up layer %s (%d) for surfaces %d-%d and role match \"%s\"", i.name.c_str(), + i.layer_id, i.id_min, i.id_max, i.role.c_str()); + this->layouts[l->id] = LayoutState{}; } // Add layers to screen (XXX: are they sorted correctly?) @@ -215,8 +224,9 @@ int App::init_layers() { namespace { // This can fix the HomeScreen... -void redraw_fix(App *app, std::unique_ptr<genivi::surface> &s, int x, int y, int w, int h) { - { // XXX: Work around weston redraw issues +void redraw_fix(App *app, std::unique_ptr<genivi::surface> &s, int x, int y, + int w, int h) { + { // XXX: Work around weston redraw issues // trigger an update by changing the source dimensions! s->set_configuration(w + 1, h); s->set_source_rectangle(0, 0, w + 1, h); @@ -239,7 +249,7 @@ void redraw_fix(App *app, std::unique_ptr<genivi::surface> &s, int x, int y, int } // namespace -void App::surface_init_layout(uint32_t surface_id) { +void App::surface_set_layout_full(uint32_t surface_id) { if (!this->controller->surface_exists(surface_id)) { logerror("Surface %d does not exist", int(surface_id)); return; @@ -289,17 +299,90 @@ void App::surface_init_layout(uint32_t surface_id) { this->controller->commit_changes(); this->display->roundtrip(); - redraw_fix(this, s, x, y, w, h); + //redraw_fix(this, s, x, y, w, h); - this->controller->layers[layer_id]->add_surface(s.get()); + logdebug("Surface %u now with rect { %d, %d, %d, %d }", + surface_id, x, y, w, h); +} - // activate the main_surface right away - if (surface_id == static_cast<unsigned>(this->layers.main_surface)) { - logdebug("Activating main_surface (%d)", surface_id); +void App::surface_set_layout_split(uint32_t surface_id, uint32_t sub_surface_id) { + if (!this->controller->surface_exists(surface_id)) { + logerror("Surface %d does not exist", int(surface_id)); + return; + } + + auto o_layer_id = this->layers.get_layer_id(surface_id); + + if (!o_layer_id) { + logerror("Surface %d is not associated with any layer!", int(surface_id)); + return; + } + + uint32_t layer_id = o_layer_id.value(); + logdebug("surface_set_layout for surface %u on layer %u", surface_id, + layer_id); - this->activate_surface(this->lookup_name(surface_id).value_or("unknown-name").c_str()); + auto const &layer = this->layers.get_layer(layer_id); + auto rect = layer.value().rect; + auto &s = this->controller->surfaces[surface_id]; + auto &ss = this->controller->surfaces[sub_surface_id]; + + int x = rect.x; + int y = rect.y; + int w = rect.w; + int h = rect.h; + + this->state.main = surface_id; + this->state.sub = sub_surface_id; + this->state.state = LayoutState::LayoutSplit; + + // less-than-0 values refer to MAX + 1 - $VALUE + // e.g. MAX is either screen width or height + if (w < 0) { + w = this->controller->output_size.w + 1 + w; + } + if (h < 0) { + h = this->controller->output_size.h + 1 + h; } + int x_off = 0; + int y_off = 0; + + // split along major axis + if (w > h) { + w /= 2; + x_off = w; + } else { + h /= 2; + y_off = h; + } + + // configure surface to wxh dimensions + s->set_configuration(w, h); + // set source reactangle, even if we should not need to set it. + s->set_source_rectangle(0, 0, w, h); + // set destination to the display rectangle + s->set_destination_rectangle(x, y, w, h); + + s->set_visibility(1); + s->set_opacity(256); + + // configure surface to wxh dimensions + ss->set_configuration(w, h); + // set source reactangle, even if we should not need to set it. + ss->set_source_rectangle(0, 0, w, h); + // set destination to the display rectangle + ss->set_destination_rectangle(x+x_off, y+y_off, w, h); + + ss->set_visibility(1); + ss->set_opacity(256); + + this->controller->commit_changes(); + this->display->roundtrip(); + + //redraw_fix(this, s, x, y, w, h); + //redraw_fix(this, ss, x+x_off, y+y_off, w, h); + logdebug("Surface %u now on layer %u with rect { %d, %d, %d, %d }", surface_id, layer_id, x, y, w, h); } @@ -320,10 +403,34 @@ char const *App::activate_surface(char const *drawing_name) { return "Surface does not exist"; } + if (this->state.main == surface_id || this->state.sub == surface_id) { + return "Surface already active"; + } + // This should involve a policy check, but as we do not (yet) have // such a thing, we will just switch to this surface. // XXX: input focus missing!!1 + if (this->state != LayoutState{}) { + switch (this->state.state) { + case LayoutState::LayoutSingle: + if (this->can_split(surface_id)) { + this->surface_set_layout_split(this->state.main, surface_id); + return nullptr; + } + break; + + case LayoutState::LayoutSplit: + if (this->can_split(surface_id)) { + this->deactivate(this->state.sub); + this->surface_set_layout_split(this->state.main, surface_id); + } + + case LayoutState::LayoutNone: + break; + } + } + // Make it visible, no (or little effect) if already visible auto &s = this->controller->surfaces[surface_id]; @@ -341,6 +448,9 @@ char const *App::activate_surface(char const *drawing_name) { this->controller->commit_changes(); this->display->flush(); + this->state.main = surface_id; + this->state.state = LayoutState::LayoutSingle; + // no error return nullptr; } @@ -361,7 +471,40 @@ char const *App::deactivate_surface(char const *drawing_name) { return "Cannot deactivate main_surface"; } - this->deactivate(surface_id); + switch (this->state.state) { + case LayoutState::LayoutSplit: + if (surface_id == this->state.main) { + this->deactivate(surface_id); + this->surface_set_layout_full(this->state.main); + + this->deactivate(this->state.sub); + this->surface_set_layout_full(this->state.sub); + + this->state.main = -1; + this->state.sub = -1; + this->state.state = LayoutState::LayoutSingle; + } else if (surface_id == this->state.sub) { + this->deactivate(surface_id); + this->surface_set_layout_full(this->state.sub); + this->surface_set_layout_full(this->state.main); + + // XXX send syndraw events.... + + this->state.sub = -1; + this->state.state = LayoutState::LayoutSingle; + } + break; + + case LayoutState::LayoutSingle: + this->deactivate(surface_id); + this->state.main = -1; + this->state.sub = -1; + break; + + case LayoutState::LayoutNone: + break; + } + this->controller->commit_changes(); this->display->flush(); @@ -378,7 +521,18 @@ char const *App::deactivate_surface(char const *drawing_name) { void App::surface_created(uint32_t surface_id) { logdebug("surface_id is %u", surface_id); - this->surface_init_layout(surface_id); + this->surface_set_layout_full(surface_id); + + this->controller->layers[this->layers.get_layer_id(surface_id).value()] + ->add_surface(this->controller->surfaces[surface_id].get()); + + // activate the main_surface right away + if (surface_id == static_cast<unsigned>(this->layers.main_surface)) { + logdebug("Activating main_surface (%d)", surface_id); + + this->activate_surface( + this->lookup_name(surface_id).value_or("unknown-name").c_str()); + } } void App::surface_removed(uint32_t surface_id) { @@ -407,13 +561,9 @@ void App::emit_visible(char const *label, bool is_visible) { this->api.send_event(is_visible ? "visible" : "invisible", label); } -void App::emit_invisible(char const *label) { - return emit_visible(label, 0); -} +void App::emit_invisible(char const *label) { return emit_visible(label, 0); } -void App::emit_visible(char const *label) { - return emit_visible(label, 1); -} +void App::emit_visible(char const *label) { return emit_visible(label, 1); } result<int> App::request_surface(char const *drawing_name) { auto lid = this->layers.get_layer_id(std::string(drawing_name)); @@ -446,7 +596,8 @@ result<int> App::request_surface(char const *drawing_name) { void App::activate(unsigned id) { if (this->controller->sprops[id].visibility == 0) { this->controller->surfaces[id]->set_visibility(1); - char const *label = this->lookup_name(id).value_or("unknown-name").c_str(); + char const *label = + this->lookup_name(id).value_or("unknown-name").c_str(); this->emit_activated(label); this->emit_visible(label); } @@ -455,7 +606,8 @@ void App::activate(unsigned id) { void App::deactivate(unsigned id) { if (this->controller->sprops[id].visibility != 0) { this->controller->surfaces[id]->set_visibility(0); - char const *label = this->lookup_name(id).value_or("unknown-name").c_str(); + char const *label = + this->lookup_name(id).value_or("unknown-name").c_str(); this->emit_deactivated(label); this->emit_invisible(label); } @@ -464,17 +616,41 @@ void App::deactivate(unsigned id) { bool App::can_split(unsigned new_id) { if (this->state.state == LayoutState::LayoutSingle) { auto new_id_layer = this->layers.get_layer_id(new_id).value(); - auto current_id_layer = this->layers.get_layer_id(this->state.main).value(); + auto current_id_layer = + this->layers.get_layer_id(this->state.main).value(); + // surfaces are on separate layers, don't bother. if (new_id_layer != current_id_layer) { return false; } std::string const &new_id_str = this->lookup_name(new_id).value(); - std::string const &cur_id_str = this->lookup_name(this->state.main).value(); + std::string const &cur_id_str = + this->lookup_name(this->state.main).value(); + + auto const &layer = this->layers.get_layer(new_id_layer); + logdebug("layer info name: %s", layer->name.c_str()); + if (layer->layouts.empty()) { + return false; + } + + for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++) { + logdebug("%d main_match '%s'", new_id_layer, i->main_match.c_str()); + auto rem = std::regex(i->main_match); + if (std::regex_match(cur_id_str, rem)) { + // build the second one only if the first already matched + logdebug("%d sub_match '%s'", new_id_layer, i->sub_match.c_str()); + auto res = std::regex(i->sub_match); + if (std::regex_match(new_id_str, res)) { + return true; + } + } + } } + + return false; } // _ _ _ _ _ |