Enable cve-check in CI jobs for additional cve log files
[AGL/meta-agl.git] / meta-agl-flutter / recipes-graphics / toyota / files / 0002-display-Add-support-for-agl_shell-version-8.patch
1 From d44f07a0c2cc410414bfd7b338ee071c17422a0a Mon Sep 17 00:00:00 2001
2 From: Marius Vlad <marius.vlad@collabora.com>
3 Date: Mon, 4 Dec 2023 18:17:00 +0200
4 Subject: [PATCH 2/2] display: Add support for agl_shell version 8
5
6 Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
7 ---
8  shell/wayland/display.cc               | 156 ++++++++++++++++++++++--
9  shell/wayland/display.h                |  58 +++++++++
10  third_party/agl/protocol/agl-shell.xml | 160 ++++++++++++++++++++++++-
11  3 files changed, 366 insertions(+), 8 deletions(-)
12
13 diff --git a/shell/wayland/display.cc b/shell/wayland/display.cc
14 index 3ee814a..aba050a 100644
15 --- a/shell/wayland/display.cc
16 +++ b/shell/wayland/display.cc
17 @@ -220,7 +220,7 @@ void Display::registry_handle_global(void* data,
18      if (version >= 2) {
19        d->m_agl.shell = static_cast<struct agl_shell*>(
20            wl_registry_bind(registry, name, &agl_shell_interface,
21 -                           std::min(static_cast<uint32_t>(4), version)));
22 +                           std::min(static_cast<uint32_t>(8), version)));
23        agl_shell_add_listener(d->m_agl.shell, &agl_shell_listener, data);
24      } else {
25        d->m_agl.shell = static_cast<struct agl_shell*>(
26 @@ -980,6 +980,148 @@ void Display::agl_shell_bound_fail(void* data, struct agl_shell* shell) {
27    d->m_agl.bound_ok = false;
28  }
29  
30 +void Display::addAppToStack(std::string app_id) {
31 +  if (app_id == "homescreen")
32 +    return;
33 +
34 +  bool found_app = false;
35 +  for (auto& i : apps_stack) {
36 +    if (i == app_id) {
37 +      found_app = true;
38 +      break;
39 +    }
40 +  }
41 +
42 +  if (!found_app) {
43 +    apps_stack.push_back(app_id);
44 +  } else {
45 +    // fixme
46 +  }
47 +}
48 +
49 +int Display::find_output_by_name(std::string output_name) {
50 +  int index = 0;
51 +  for (auto& i : m_all_outputs) {
52 +    if (i->name == output_name) {
53 +      return index;
54 +    }
55 +    index++;
56 +  }
57 +
58 +  return -1;
59 +}
60 +
61 +void Display::activateApp(std::string app_id) {
62 +  int default_output_index = 0;
63 +
64 +  FML_LOG(INFO) << "got app_id " << app_id;
65 +
66 +  // search for a pending application which might have a different output
67 +  auto iter = pending_app_list.begin();
68 +  bool found_pending_app = false;
69 +  while (iter != pending_app_list.end()) {
70 +    auto app_to_search = iter->first;
71 +    FML_LOG(INFO) << "searching for " << app_to_search;
72 +
73 +    if (app_to_search == app_id) {
74 +      found_pending_app = true;
75 +      break;
76 +    }
77 +
78 +    iter++;
79 +  }
80 +
81 +  if (found_pending_app) {
82 +    auto output_name = iter->second;
83 +    default_output_index = find_output_by_name(output_name);
84 +
85 +    FML_LOG(INFO) << "Found app_id " << app_id << " at all";
86 +
87 +    if (default_output_index < 0) {
88 +      // try with remoting-remote-X which is the streaming
89 +      std::string new_remote_output = "remoting-" + output_name;
90 +
91 +      default_output_index = find_output_by_name(new_remote_output);
92 +      if (default_output_index < 0) {
93 +        FML_LOG(INFO) << "Not activating app_id " << app_id << " at all";
94 +        return;
95 +      }
96 +    }
97 +
98 +    pending_app_list.erase(iter);
99 +  }
100 +
101 +  FML_LOG(INFO) << "Activating app_id " << app_id << " on output "
102 +                << default_output_index;
103 +  agl_shell_activate_app(m_agl.shell, app_id.c_str(),
104 +                         m_all_outputs[default_output_index]->output);
105 +  wl_display_flush(m_display);
106 +}
107 +
108 +void Display::deactivateApp(std::string app_id) {
109 +  for (auto& i : apps_stack) {
110 +    if (i == app_id) {
111 +      // remove it from apps_stack
112 +      apps_stack.remove(i);
113 +      if (!apps_stack.empty())
114 +        activateApp(apps_stack.back());
115 +      break;
116 +    }
117 +  }
118 +}
119 +
120 +void Display::processAppStatusEvent(const char* app_id,
121 +                                    const std::string event_type) {
122 +  if (!m_agl.shell)
123 +    return;
124 +
125 +  if (event_type == "started") {
126 +    activateApp(std::string(app_id));
127 +  } else if (event_type == "terminated") {
128 +    deactivateApp(std::string(app_id));
129 +  } else if (event_type == "deactivated") {
130 +    // not handled
131 +  }
132 +}
133 +
134 +void Display::agl_shell_app_on_output(void* data,
135 +                                      struct agl_shell* agl_shell,
136 +                                      const char* app_id,
137 +                                      const char* output_name) {
138 +  auto* d = static_cast<Display*>(data);
139 +
140 +  FML_LOG(INFO) << "Gove event app_on_out app_id " << app_id << " output name "
141 +                << output_name;
142 +
143 +  // a couple of use-cases, if there is no app_id in the app_list then it
144 +  // means this is a request to map the application, from the start to a
145 +  // different output that the default one. We'd get an
146 +  // AGL_SHELL_APP_STATE_STARTED which will handle activation.
147 +  //
148 +  // if there's an app_id then it means we might have gotten an event to
149 +  // move the application to another output; so we'd need to process it
150 +  // by explicitly calling processAppStatusEvent() which would ultimately
151 +  // activate the application on other output. We'd have to pick-up the
152 +  // last activated window and activate the default output.
153 +  //
154 +  // finally if the outputs are identical probably that's an user-error -
155 +  // but the compositor won't activate it again, so we don't handle that.
156 +  std::pair new_pending_app =
157 +      std::pair(std::string(app_id), std::string(output_name));
158 +  d->pending_app_list.push_back(new_pending_app);
159 +
160 +  auto iter = d->apps_stack.begin();
161 +  while (iter != d->apps_stack.end()) {
162 +    if (*iter == std::string(app_id)) {
163 +      FML_LOG(INFO) << "Gove event to move " << app_id << " to another output "
164 +                    << output_name;
165 +      d->processAppStatusEvent(app_id, std::string("started"));
166 +      break;
167 +    }
168 +    iter++;
169 +  }
170 +}
171 +
172  void Display::agl_shell_app_state(void* data,
173                                    struct agl_shell* /* agl_shell */,
174                                    const char* app_id,
175 @@ -991,12 +1133,7 @@ void Display::agl_shell_app_state(void* data,
176        FML_DLOG(INFO) << "Got AGL_SHELL_APP_STATE_STARTED for app_id " << app_id;
177  
178        if (d->m_agl.shell) {
179 -        // we always assume the first output advertised by the wl_output
180 -        // interface
181 -        unsigned int default_output_index = 0;
182 -
183 -        agl_shell_activate_app(d->m_agl.shell, app_id,
184 -                               d->m_all_outputs[default_output_index]->output);
185 +        d->processAppStatusEvent(app_id, std::string("started"));
186        }
187  
188        break;
189 @@ -1007,6 +1144,10 @@ void Display::agl_shell_app_state(void* data,
190      case AGL_SHELL_APP_STATE_ACTIVATED:
191        FML_DLOG(INFO) << "Got AGL_SHELL_APP_STATE_ACTIVATED for app_id "
192                       << app_id;
193 +      d->addAppToStack(std::string(app_id));
194 +      break;
195 +    case AGL_SHELL_APP_STATE_DEACTIVATED:
196 +      d->processAppStatusEvent(app_id, std::string("deactivated"));
197        break;
198      default:
199        break;
200 @@ -1017,6 +1158,7 @@ const struct agl_shell_listener Display::agl_shell_listener = {
201      .bound_ok = agl_shell_bound_ok,
202      .bound_fail = agl_shell_bound_fail,
203      .app_state = agl_shell_app_state,
204 +    .app_on_output = agl_shell_app_on_output,
205  };
206  
207  void Display::ivi_wm_surface_visibility(void* /* data */,
208 diff --git a/shell/wayland/display.h b/shell/wayland/display.h
209 index a0756f0..b919047 100644
210 --- a/shell/wayland/display.h
211 +++ b/shell/wayland/display.h
212 @@ -18,6 +18,7 @@
213  #pragma once
214  
215  #include <chrono>
216 +#include <list>
217  #include <memory>
218  #include <mutex>
219  #include <string>
220 @@ -271,6 +272,44 @@ class Display {
221     */
222    std::pair<int32_t, int32_t> GetVideoModeSize(uint32_t index);
223  
224 +  /**
225 +   * @brief deactivate/hide the application pointed by app_id
226 +   * @param[in] app_id the app_id
227 +   * @relation
228 +   * agl_shell
229 +   */
230 +  void deactivateApp(std::string app_id);
231 +  /**
232 +   * @brief activate/show the application pointed by app_id
233 +   * @param[in] app_id the app_id
234 +   * @relation
235 +   * agl_shell
236 +   */
237 +  void activateApp(std::string app_id);
238 +  /**
239 +   * @brief Add app_id to a list of list applications
240 +   * @param[in] app_id the app_id
241 +   * @relation
242 +   * agl_shell
243 +   */
244 +  void addAppToStack(std::string app_id);
245 +  /**
246 +   * @brief Helper to retrieve the output using its output_name
247 +   * @param[in] output_name a std::string representing the output
248 +   * @retval an integer that can used to get the proper output
249 +   * @relation
250 +   * agl_sell
251 +   */
252 +  int find_output_by_name(std::string output_name);
253 +  /**
254 +   * @brief helper to process the application status
255 +   * @param[in] app_id an array of char
256 +   * @param[in] event_type a std::string representing the type of event (started/stopped/terminated)
257 +   * @relation
258 +   * agl_shell
259 +   */
260 +  void processAppStatusEvent(const char* app_id, const std::string event_type);
261 +
262   private:
263    std::shared_ptr<Engine> m_flutter_engine;
264  
265 @@ -300,6 +339,9 @@ class Display {
266      uint32_t version = 0;
267    } m_agl;
268  
269 +  std::list<std::string> apps_stack;
270 +  std::list<std::pair<const std::string, const std::string>> pending_app_list;
271 +
272    struct ivi_shell {
273      struct ivi_application* application = nullptr;
274      struct ivi_wm* ivi_wm = nullptr;
275 @@ -982,6 +1024,22 @@ class Display {
276                                    const char* app_id,
277                                    uint32_t state);
278  
279 +  /**
280 +   * @brief AGL app_app_on_output event
281 +   * @param[in,out] data Data of type Display
282 +   * @param[in] shell No use
283 +   * @param[in] app_id the application id for which this event was sent
284 +   * @param[in] state the state: CREATED/TERMINATED/ACTIVATED/DEACTIVATED
285 +   * @return void
286 +   * @relation
287 +   * wayland, agl-shell
288 +   * @note Do nothing
289 +   */
290 +  static void agl_shell_app_on_output(void* data,
291 +                                      struct agl_shell* agl_shell,
292 +                                      const char* app_id,
293 +                                      const char* output_name);
294 +
295    static const struct agl_shell_listener agl_shell_listener;
296  
297    /**
298 diff --git a/third_party/agl/protocol/agl-shell.xml b/third_party/agl/protocol/agl-shell.xml
299 index bf5ab02..e010a80 100644
300 --- a/third_party/agl/protocol/agl-shell.xml
301 +++ b/third_party/agl/protocol/agl-shell.xml
302 @@ -22,7 +22,7 @@
303      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
304      DEALINGS IN THE SOFTWARE.
305    </copyright>
306 -  <interface name="agl_shell" version="4">
307 +  <interface name="agl_shell" version="8">
308      <description summary="user interface for Automotive Grade Linux platform">
309        Starting with version 2 of the protocol, the client is required to wait
310        for the 'bound_ok' or 'bound_fail' events in order to proceed further.
311 @@ -200,5 +200,163 @@
312        <arg name="width" type="int" summary="width of rectangle"/>
313        <arg name="height" type="int" summary="height of rectangle"/>
314      </request>
315 +
316 +    <request name="deactivate_app" since="5">
317 +      <description summary="de-activate/hide window identified by app_id">
318 +        Ask the compositor to hide the toplevel window for window
319 +        management purposes. Depending on the window role, this request
320 +        will either display the previously active window (or the background
321 +        in case there's no previously active surface) or temporarily (or
322 +        until a 'activate_app' is called upon) hide the surface.
323 +
324 +        All the surfaces are identifiable by using the app_id, and no actions
325 +        are taken in case the app_id is not/was not present.
326 +
327 +        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
328 +        description of app_id.
329 +      </description>
330 +      <arg name="app_id" type="string"/>
331 +    </request>
332 +
333 +    <request name="set_app_float" since="6">
334 +      <description summary="set the window identified by app_id as float">
335 +        Makes the application identified by app_id as floating. If the
336 +        application's window is already mapped, in a maximized, normal state,
337 +        it would transition to the float state.
338 +
339 +        For applications that want to modify their own state, this request
340 +        must be done before the initial surface commit in order to take effect.
341 +
342 +        If the application is already in floating state, this request wouldn't
343 +        do anything.
344 +
345 +        There's no persistence of this request, once the application terminated
346 +        you'll to issue this request again for that particular app_id.
347 +
348 +        The x, and y values would be initial position of the window where the
349 +        window surface will be placed.
350 +
351 +        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
352 +        description of app_id.
353 +      </description>
354 +      <arg name="app_id" type="string"/>
355 +      <arg name="x" type="int" summary="x position"/>
356 +      <arg name="y" type="int" summary="y position"/>
357 +    </request>
358 +
359 +    <request name="set_app_normal" since="6">
360 +      <description summary="set the window identified by app_id as normally started">
361 +      Returns the application identified by app_id as it was in the normal state.
362 +      This is useful to come back from other states to the maximized state, the
363 +      normal state applications are started.
364 +      </description>
365 +      <arg name="app_id" type="string"/>
366 +    </request>
367 +
368 +    <request name="set_app_fullscreen" since="7">
369 +      <description summary="">
370 +        Makes the application identified by app_id as fullscreen. If the
371 +        application's window is already mapped, in a maximized, normal state,
372 +        it would transition to the fullscreen state.
373 +
374 +        For applications that want to modify their own state, this request
375 +        must be done before the initial surface commit in order to take effect.
376 +
377 +        If the application is already in fullscreen state, this request wouldn't
378 +        do anything.
379 +
380 +        There's no persistence of this request, once the application terminated
381 +        you'll to issue this request again for that particular app_id.
382 +
383 +        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
384 +        description of app_id.
385 +      </description>
386 +      <arg name="app_id" type="string"/>
387 +    </request>
388 +
389 +    <request name="set_app_output" since="8">
390 +      <description summary="Assign an application to a particular output">
391 +        This would allow the compositor to place an application on a particular
392 +        output, if that output is indeed available. This can happen before
393 +        application is started which would make the application start on that
394 +        particular output. If the application is already started it would
395 +        move the application to that output.
396 +
397 +        There's no persistence of this request, once the application terminated
398 +        you'll need to issue this request again for that particular app_id.
399 +
400 +        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
401 +        description of app_id.
402 +      </description>
403 +      <arg name="app_id" type="string"/>
404 +      <arg name="output" type="object" interface="wl_output"/>
405 +    </request>
406 +
407 +    <event name="app_on_output" since="8">
408 +      <description summary="Event sent as a reponse to set_app_output">
409 +        Clients can use this event to be notified when an application
410 +        wants to be displayed on a certain output. This event is sent in
411 +        response to the set_app_output request.
412 +
413 +        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
414 +        description of app_id.
415 +      </description>
416 +      <arg name="app_id" type="string"/>
417 +      <arg name="output_name" type="string"/>
418 +    </event>
419 +  </interface>
420 +
421 +  <interface name="agl_shell_ext" version="1">
422 +    <description summary="extended user interface for Automotive Grade Linux platform">
423 +      This interface allows another client bind to the agl_shell interface,
424 +      while there's another shell client already present.
425 +
426 +      The client should first bind to this interface and then inform the
427 +      compositor with the 'doas_shell_client' request and it wants to bind to
428 +      the agl_shell interface. The client is still expected, if using a new
429 +      version of the agl_shell interface, to wait for the 'bound_ok' and
430 +      'bound_fail' events before issueing any other requests/events.
431 +
432 +      Note that this interface has its limitations, and the compositor would
433 +      still refuse the act for 'set_panel' or 'set_background' requests
434 +      of the agl_shell interface if there's already a client that used them.
435 +
436 +      Any other requests or events should be delievered and handled as it would
437 +      a client bound to the agl_shell interface.
438 +    </description>
439 +
440 +    <enum name="doas_shell_client_status">
441 +      <entry name="success" value="0"/>
442 +      <entry name="failed" value="1"/>
443 +    </enum>
444 +
445 +    <request name="destroy" type="destructor">
446 +      <description summary="destroys the factory object">
447 +        Call the destructor once you're ready with agl_shell_ext interface.
448 +        This would reset the state and would make any requests made
449 +        on the agl_shell interface be terminated. The client would need 
450 +        to bind again the agl_shell_ext and issue a 'doas_shell_client'
451 +        request.
452 +      </description>
453 +    </request>
454 +
455 +    <request name="doas_shell_client">
456 +      <description summary="Informs the compositor it wants to bind to the
457 +      agl_shell interface">
458 +        Prior to binding to agl_shell interface, this request would inform
459 +        the compositor that it wants to gain access the agl_shell interface.
460 +        The client is expected to wait for 'doas_shell_client_done' event and 
461 +        check for a successful status before going further with binding to
462 +        the agl_shell interface.
463 +      </description>
464 +    </request>
465 +
466 +    <event name="doas_done">
467 +      <description summary="event sent as a reply to doas_shell_client">
468 +        The client should check the status event to verify that the
469 +        compositor was able to handle the request.
470 +      </description>
471 +      <arg name="status" type="uint" enum="doas_shell_client_status"/>
472 +    </event>
473    </interface>
474  </protocol>
475 -- 
476 2.35.1
477