1 /* Needed for pipe2 */
2 #ifndef _GNU_SOURCE
3     #define _GNU_SOURCE
4 #endif
5 
6 #include <sys/wait.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <float.h>
10 
11 #include <wayfire/img.hpp>
12 #include <wayfire/output.hpp>
13 #include <wayfire/util/log.hpp>
14 #include <wayfire/output-layout.hpp>
15 #include <wayfire/workspace-manager.hpp>
16 #include <wayfire/signal-definitions.hpp>
17 #include <wayfire/nonstd/wlroots-full.hpp>
18 
19 #include "seat/keyboard.hpp"
20 #include "opengl-priv.hpp"
21 #include "seat/input-manager.hpp"
22 #include "seat/input-method-relay.hpp"
23 #include "seat/touch.hpp"
24 #include "seat/pointer.hpp"
25 #include "seat/cursor.hpp"
26 #include "../view/view-impl.hpp"
27 #include "../output/wayfire-shell.hpp"
28 #include "../output/output-impl.hpp"
29 #include "../output/gtk-shell.hpp"
30 
31 #include "core-impl.hpp"
32 
33 /* decorations impl */
34 struct wf_server_decoration_t
35 {
36     wlr_server_decoration *decor;
37     wf::wl_listener_wrapper on_mode_set, on_destroy;
38 
39     std::function<void(void*)> mode_set = [&] (void*)
__anoncc7623b90102wf_server_decoration_t40     {
41         bool use_csd = decor->mode == WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
42         wf::get_core_impl().uses_csd[decor->surface] = use_csd;
43 
44         auto wf_surface = dynamic_cast<wf::wlr_view_t*>(
45             wf::wf_surface_from_void(decor->surface->data));
46 
47         if (wf_surface)
48         {
49             wf_surface->has_client_decoration = use_csd;
50         }
51     };
52 
wf_server_decoration_twf_server_decoration_t53     wf_server_decoration_t(wlr_server_decoration *_decor) :
54         decor(_decor)
55     {
56         on_mode_set.set_callback(mode_set);
57         on_destroy.set_callback([&] (void*)
58         {
59             wf::get_core_impl().uses_csd.erase(decor->surface);
60             delete this;
61         });
62 
63         on_mode_set.connect(&decor->events.mode);
64         on_destroy.connect(&decor->events.destroy);
65         /* Read initial decoration settings */
66         mode_set(NULL);
67     }
68 };
69 
70 struct wf_xdg_decoration_t
71 {
72     wlr_xdg_toplevel_decoration_v1 *decor;
73     wf::wl_listener_wrapper on_mode_request, on_commit, on_destroy;
74 
75     std::function<void(void*)> mode_request = [&] (void*)
__anoncc7623b90302wf_xdg_decoration_t76     {
77         wf::option_wrapper_t<std::string>
78         deco_mode{"core/preferred_decoration_mode"};
79         wlr_xdg_toplevel_decoration_v1_mode default_mode =
80             WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
81         if ((std::string)deco_mode == "server")
82         {
83             default_mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
84         }
85 
86         auto mode = decor->client_pending_mode;
87         if (mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE)
88         {
89             mode = default_mode;
90         }
91 
92         wlr_xdg_toplevel_decoration_v1_set_mode(decor, mode);
93     };
94 
95     std::function<void(void*)> commit = [&] (void*)
__anoncc7623b90402wf_xdg_decoration_t96     {
97         bool use_csd =
98             decor->current_mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
99         wf::get_core_impl().uses_csd[decor->surface->surface] = use_csd;
100 
101         auto wf_surface = dynamic_cast<wf::wlr_view_t*>(
102             wf::wf_surface_from_void(decor->surface->data));
103         if (wf_surface)
104         {
105             wf_surface->set_decoration_mode(use_csd);
106         }
107     };
108 
wf_xdg_decoration_twf_xdg_decoration_t109     wf_xdg_decoration_t(wlr_xdg_toplevel_decoration_v1 *_decor) :
110         decor(_decor)
111     {
112         on_mode_request.set_callback(mode_request);
113         on_commit.set_callback(commit);
114         on_destroy.set_callback([&] (void*)
115         {
116             wf::get_core_impl().uses_csd.erase(decor->surface->surface);
117             delete this;
118         });
119 
120         on_mode_request.connect(&decor->events.request_mode);
121         on_commit.connect(&decor->surface->surface->events.commit);
122         on_destroy.connect(&decor->events.destroy);
123         /* Read initial decoration settings */
124         mode_request(NULL);
125     }
126 };
127 
128 struct wf_pointer_constraint
129 {
130     wf::wl_listener_wrapper on_destroy;
131 
wf_pointer_constraintwf_pointer_constraint132     wf_pointer_constraint(wlr_pointer_constraint_v1 *constraint)
133     {
134         on_destroy.set_callback([=] (void*)
135         {
136             // reset constraint
137             auto& lpointer = wf::get_core_impl().seat->lpointer;
138             if (lpointer->get_active_pointer_constraint() == constraint)
139             {
140                 lpointer->set_pointer_constraint(nullptr, true);
141             }
142 
143             on_destroy.disconnect();
144             delete this;
145         });
146 
147         on_destroy.connect(&constraint->events.destroy);
148 
149         // set correct constraint
150         auto& lpointer = wf::get_core_impl().seat->lpointer;
151         auto focus     = lpointer->get_focus();
152         if (focus && (focus->priv->wsurface == constraint->surface))
153         {
154             lpointer->set_pointer_constraint(constraint);
155         }
156     }
157 };
158 
159 struct wlr_idle_inhibitor_t : public wf::idle_inhibitor_t
160 {
161     wf::wl_listener_wrapper on_destroy;
wlr_idle_inhibitor_twlr_idle_inhibitor_t162     wlr_idle_inhibitor_t(wlr_idle_inhibitor_v1 *wlri)
163     {
164         on_destroy.set_callback([&] (void*)
165         {
166             delete this;
167         });
168 
169         on_destroy.connect(&wlri->events.destroy);
170     }
171 };
172 
init()173 void wf::compositor_core_impl_t::init()
174 {
175     wlr_renderer_init_wl_display(renderer, display);
176 
177     /* Order here is important:
178      * 1. init_desktop_apis() must come after wlr_compositor_create(),
179      *    since Xwayland initialization depends on the compositor
180      * 2. input depends on output-layout
181      * 3. weston toy clients expect xdg-shell before wl_seat, i.e
182      * init_desktop_apis() should come before input.
183      * 4. GTK expects primary selection early. */
184     compositor = wlr_compositor_create(display, renderer);
185 
186     protocols.data_device = wlr_data_device_manager_create(display);
187     protocols.gtk_primary_selection =
188         wlr_gtk_primary_selection_device_manager_create(display);
189     protocols.primary_selection_v1 =
190         wlr_primary_selection_v1_device_manager_create(display);
191     protocols.data_control = wlr_data_control_manager_v1_create(display);
192 
193     output_layout = std::make_unique<wf::output_layout_t>(backend);
194     init_desktop_apis();
195 
196     /* Somehow GTK requires the tablet_v2 to be advertised pretty early */
197     protocols.tablet_v2 = wlr_tablet_v2_create(display);
198     input = std::make_unique<wf::input_manager_t>();
199     seat  = std::make_unique<wf::seat_t>();
200 
201     protocols.screencopy = wlr_screencopy_manager_v1_create(display);
202     protocols.gamma_v1   = wlr_gamma_control_manager_v1_create(display);
203     protocols.export_dmabuf  = wlr_export_dmabuf_manager_v1_create(display);
204     protocols.output_manager = wlr_xdg_output_manager_v1_create(display,
205         output_layout->get_handle());
206 
207     /* input-inhibit setup */
208     protocols.input_inhibit = wlr_input_inhibit_manager_create(display);
209     input_inhibit_activated.set_callback([&] (void*)
210     {
211         input->set_exclusive_focus(protocols.input_inhibit->active_client);
212     });
213     input_inhibit_activated.connect(&protocols.input_inhibit->events.activate);
214 
215     input_inhibit_deactivated.set_callback([&] (void*)
216     {
217         input->set_exclusive_focus(nullptr);
218     });
219     input_inhibit_deactivated.connect(&protocols.input_inhibit->events.deactivate);
220 
221     /* decoration_manager setup */
222     protocols.decorator_manager = wlr_server_decoration_manager_create(display);
223     wf::option_wrapper_t<std::string>
224     deco_mode{"core/preferred_decoration_mode"};
225     uint32_t default_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
226     if ((std::string)deco_mode == "server")
227     {
228         default_mode = WLR_SERVER_DECORATION_MANAGER_MODE_SERVER;
229     }
230 
231     wlr_server_decoration_manager_set_default_mode(protocols.decorator_manager,
232         default_mode);
233 
234     decoration_created.set_callback([&] (void *data)
235     {
236         /* will be freed by the destroy request */
237         new wf_server_decoration_t((wlr_server_decoration*)(data));
238     });
239     decoration_created.connect(&protocols.decorator_manager->events.new_decoration);
240 
241     protocols.xdg_decorator = wlr_xdg_decoration_manager_v1_create(display);
242 
243     xdg_decoration_created.set_callback([&] (void *data)
244     {
245         /* will be freed by the destroy request */
246         new wf_xdg_decoration_t((wlr_xdg_toplevel_decoration_v1*)(data));
247     });
248     xdg_decoration_created.connect(
249         &protocols.xdg_decorator->events.new_toplevel_decoration);
250 
251     protocols.vkbd_manager = wlr_virtual_keyboard_manager_v1_create(display);
252     vkbd_created.set_callback([&] (void *data)
253     {
254         auto kbd = (wlr_virtual_keyboard_v1*)data;
255         input->handle_new_input(&kbd->input_device);
256     });
257     vkbd_created.connect(&protocols.vkbd_manager->events.new_virtual_keyboard);
258 
259     protocols.vptr_manager = wlr_virtual_pointer_manager_v1_create(display);
260     vptr_created.set_callback([&] (void *data)
261     {
262         auto event = (wlr_virtual_pointer_v1_new_pointer_event*)data;
263         auto ptr   = event->new_pointer;
264         input->handle_new_input(&ptr->input_device);
265     });
266     vptr_created.connect(&protocols.vptr_manager->events.new_virtual_pointer);
267 
268     protocols.idle_inhibit = wlr_idle_inhibit_v1_create(display);
269     idle_inhibitor_created.set_callback([&] (void *data)
270     {
271         auto wlri = static_cast<wlr_idle_inhibitor_v1*>(data);
272         /* will be freed by the destroy request */
273         new wlr_idle_inhibitor_t(wlri);
274     });
275     idle_inhibitor_created.connect(
276         &protocols.idle_inhibit->events.new_inhibitor);
277 
278     protocols.idle = wlr_idle_create(display);
279     protocols.toplevel_manager = wlr_foreign_toplevel_manager_v1_create(display);
280     protocols.pointer_gestures = wlr_pointer_gestures_v1_create(display);
281     protocols.relative_pointer = wlr_relative_pointer_manager_v1_create(display);
282 
283     protocols.pointer_constraints = wlr_pointer_constraints_v1_create(display);
284     pointer_constraint_added.set_callback([&] (void *data)
285     {
286         // will delete itself when the constraint is destroyed
287         new wf_pointer_constraint((wlr_pointer_constraint_v1*)data);
288     });
289     pointer_constraint_added.connect(
290         &protocols.pointer_constraints->events.new_constraint);
291 
292     protocols.input_method = wlr_input_method_manager_v2_create(display);
293     protocols.text_input   = wlr_text_input_manager_v3_create(display);
294     im_relay = std::make_unique<input_method_relay>();
295 
296     protocols.presentation = wlr_presentation_create(display, backend);
297     protocols.viewporter   = wlr_viewporter_create(display);
298 
299     wf_shell  = wayfire_shell_create(display);
300     gtk_shell = wf_gtk_shell_create(display);
301 
302     image_io::init();
303     OpenGL::init();
304 
305     init_last_view_tracking();
306     this->state = compositor_state_t::START_BACKEND;
307 }
308 
init_last_view_tracking()309 void wf::compositor_core_impl_t::init_last_view_tracking()
310 {
311     on_new_output.set_callback([&] (wf::signal_data_t *data)
312     {
313         auto wo = get_signaled_output(data);
314         wo->connect_signal("view-unmapped", &on_view_unmap);
315     });
316     output_layout->connect_signal("output-added", &on_new_output);
317 
318     on_view_unmap.set_callback([&] (wf::signal_data_t *data)
319     {
320         auto view = get_signaled_view(data);
321         if (view == last_active_toplevel)
322         {
323             last_active_toplevel = nullptr;
324         }
325 
326         if (view == last_active_view)
327         {
328             last_active_view = nullptr;
329         }
330     });
331 }
332 
post_init()333 void wf::compositor_core_impl_t::post_init()
334 {
335     this->emit_signal("_backend_started", nullptr);
336     this->state = compositor_state_t::RUNNING;
337 
338     // Move pointer to the middle of the leftmost, topmost output
339     wf::pointf_t p;
340     wf::output_t *wo =
341         wf::get_core().output_layout->get_output_coords_at({FLT_MIN, FLT_MIN}, p);
342     // Output might be noop but guaranteed to not be null
343     wo->ensure_pointer(true);
344     focus_output(wo);
345 
346     // Refresh device mappings when we have all outputs and devices
347     input->refresh_device_mappings();
348 
349     // Start processing cursor events
350     seat->cursor->setup_listeners();
351 
352     this->emit_signal("startup-finished", nullptr);
353 }
354 
shutdown()355 void wf::compositor_core_impl_t::shutdown()
356 {
357     this->state = compositor_state_t::SHUTDOWN;
358     wf::get_core().emit_signal("shutdown", nullptr);
359     wl_display_terminate(wf::get_core().display);
360 }
361 
get_current_state()362 wf::compositor_state_t wf::compositor_core_impl_t::get_current_state()
363 {
364     return this->state;
365 }
366 
get_current_seat()367 wlr_seat*wf::compositor_core_impl_t::get_current_seat()
368 {
369     return seat->seat;
370 }
371 
get_keyboard_modifiers()372 uint32_t wf::compositor_core_impl_t::get_keyboard_modifiers()
373 {
374     return seat->get_modifiers();
375 }
376 
set_cursor(std::string name)377 void wf::compositor_core_impl_t::set_cursor(std::string name)
378 {
379     seat->cursor->set_cursor(name);
380 }
381 
unhide_cursor()382 void wf::compositor_core_impl_t::unhide_cursor()
383 {
384     seat->cursor->unhide_cursor();
385 }
386 
hide_cursor()387 void wf::compositor_core_impl_t::hide_cursor()
388 {
389     seat->cursor->hide_cursor();
390 }
391 
warp_cursor(wf::pointf_t pos)392 void wf::compositor_core_impl_t::warp_cursor(wf::pointf_t pos)
393 {
394     seat->cursor->warp_cursor(pos);
395 }
396 
get_cursor_position()397 wf::pointf_t wf::compositor_core_impl_t::get_cursor_position()
398 {
399     if (seat->cursor)
400     {
401         return seat->cursor->get_cursor_position();
402     } else
403     {
404         return {invalid_coordinate, invalid_coordinate};
405     }
406 }
407 
get_touch_position(int id)408 wf::pointf_t wf::compositor_core_impl_t::get_touch_position(int id)
409 {
410     const auto& state = seat->touch->get_state();
411     auto it = state.fingers.find(id);
412     if (it != state.fingers.end())
413     {
414         return {it->second.current.x, it->second.current.y};
415     }
416 
417     return {invalid_coordinate, invalid_coordinate};
418 }
419 
get_touch_state()420 const wf::touch::gesture_state_t& wf::compositor_core_impl_t::get_touch_state()
421 {
422     return seat->touch->get_state();
423 }
424 
get_cursor_focus()425 wf::surface_interface_t*wf::compositor_core_impl_t::get_cursor_focus()
426 {
427     return seat->lpointer->get_focus();
428 }
429 
get_cursor_focus_view()430 wayfire_view wf::compositor_core_t::get_cursor_focus_view()
431 {
432     auto focus = get_cursor_focus();
433     auto view  = dynamic_cast<wf::view_interface_t*>(
434         focus ? focus->get_main_surface() : nullptr);
435 
436     return view ? view->self() : nullptr;
437 }
438 
get_surface_at(wf::pointf_t point)439 wf::surface_interface_t*wf::compositor_core_impl_t::get_surface_at(
440     wf::pointf_t point)
441 {
442     wf::pointf_t local = {0.0, 0.0};
443 
444     return input->input_surface_at(point, local);
445 }
446 
get_view_at(wf::pointf_t point)447 wayfire_view wf::compositor_core_t::get_view_at(wf::pointf_t point)
448 {
449     auto surface = get_surface_at(point);
450     if (!surface)
451     {
452         return nullptr;
453     }
454 
455     auto view = dynamic_cast<wf::view_interface_t*>(surface->get_main_surface());
456 
457     return view ? view->self() : nullptr;
458 }
459 
get_touch_focus()460 wf::surface_interface_t*wf::compositor_core_impl_t::get_touch_focus()
461 {
462     return seat->touch->get_focus();
463 }
464 
get_touch_focus_view()465 wayfire_view wf::compositor_core_t::get_touch_focus_view()
466 {
467     auto focus = get_touch_focus();
468     auto view  = dynamic_cast<wf::view_interface_t*>(
469         focus ? focus->get_main_surface() : nullptr);
470 
471     return view ? view->self() : nullptr;
472 }
473 
add_touch_gesture(nonstd::observer_ptr<wf::touch::gesture_t> gesture)474 void wf::compositor_core_impl_t::add_touch_gesture(
475     nonstd::observer_ptr<wf::touch::gesture_t> gesture)
476 {
477     seat->touch->add_touch_gesture(gesture);
478 }
479 
rem_touch_gesture(nonstd::observer_ptr<wf::touch::gesture_t> gesture)480 void wf::compositor_core_impl_t::rem_touch_gesture(
481     nonstd::observer_ptr<wf::touch::gesture_t> gesture)
482 {
483     seat->touch->rem_touch_gesture(gesture);
484 }
485 
486 std::vector<nonstd::observer_ptr<wf::input_device_t>> wf::compositor_core_impl_t::
get_input_devices()487 get_input_devices()
488 {
489     std::vector<nonstd::observer_ptr<wf::input_device_t>> list;
490     for (auto& dev : input->input_devices)
491     {
492         list.push_back(nonstd::make_observer(dev.get()));
493     }
494 
495     return list;
496 }
497 
get_wlr_cursor()498 wlr_cursor*wf::compositor_core_impl_t::get_wlr_cursor()
499 {
500     return seat->cursor->cursor;
501 }
502 
focus_output(wf::output_t * wo)503 void wf::compositor_core_impl_t::focus_output(wf::output_t *wo)
504 {
505     if (active_output == wo)
506     {
507         return;
508     }
509 
510     if (wo)
511     {
512         LOGD("focus output: ", wo->handle->name);
513         /* Move to the middle of the output if this is the first output */
514         wo->ensure_pointer((active_output == nullptr));
515     }
516 
517     wf::plugin_grab_interface_t *old_grab = nullptr;
518     if (active_output)
519     {
520         auto output_impl = dynamic_cast<wf::output_impl_t*>(active_output);
521         old_grab = output_impl->get_input_grab_interface();
522         active_output->focus_view(nullptr);
523     }
524 
525     active_output = wo;
526 
527     /* invariant: input is grabbed only if the current output
528      * has an input grab */
529     if (input->input_grabbed())
530     {
531         assert(old_grab);
532         input->ungrab_input();
533     }
534 
535     /* On shutdown */
536     if (!active_output)
537     {
538         return;
539     }
540 
541     auto output_impl = dynamic_cast<wf::output_impl_t*>(wo);
542     wf::plugin_grab_interface_t *iface = output_impl->get_input_grab_interface();
543     if (!iface)
544     {
545         wo->refocus();
546     } else
547     {
548         input->grab_input(iface);
549     }
550 
551     wlr_output_schedule_frame(active_output->handle);
552 
553     wf::output_gain_focus_signal data;
554     data.output = active_output;
555     active_output->emit_signal("gain-focus", &data);
556     this->emit_signal("output-gain-focus", &data);
557 }
558 
get_active_output()559 wf::output_t*wf::compositor_core_impl_t::get_active_output()
560 {
561     return active_output;
562 }
563 
focus_layer(uint32_t layer,int32_t request_uid_hint)564 int wf::compositor_core_impl_t::focus_layer(uint32_t layer, int32_t request_uid_hint)
565 {
566     static int32_t last_request_uid = -1;
567     if (request_uid_hint >= 0)
568     {
569         /* Remove the old request, and insert the new one */
570         uint32_t old_layer = -1;
571         for (auto& req : layer_focus_requests)
572         {
573             if (req.second == request_uid_hint)
574             {
575                 old_layer = req.first;
576             }
577         }
578 
579         /* Request UID isn't valid */
580         if (old_layer == (uint32_t)-1)
581         {
582             return -1;
583         }
584 
585         layer_focus_requests.erase({old_layer, request_uid_hint});
586     }
587 
588     auto request_uid = request_uid_hint < 0 ?
589         ++last_request_uid : request_uid_hint;
590     layer_focus_requests.insert({layer, request_uid});
591     LOGD("focusing layer ", get_focused_layer());
592 
593     if (active_output)
594     {
595         active_output->refocus();
596     }
597 
598     return request_uid;
599 }
600 
get_focused_layer()601 uint32_t wf::compositor_core_impl_t::get_focused_layer()
602 {
603     if (layer_focus_requests.empty())
604     {
605         return 0;
606     }
607 
608     return (--layer_focus_requests.end())->first;
609 }
610 
unfocus_layer(int request)611 void wf::compositor_core_impl_t::unfocus_layer(int request)
612 {
613     for (auto& freq : layer_focus_requests)
614     {
615         if (freq.second == request)
616         {
617             layer_focus_requests.erase(freq);
618             LOGD("focusing layer ", get_focused_layer());
619 
620             active_output->refocus(nullptr);
621 
622             return;
623         }
624     }
625 }
626 
add_view(std::unique_ptr<wf::view_interface_t> view)627 void wf::compositor_core_impl_t::add_view(
628     std::unique_ptr<wf::view_interface_t> view)
629 {
630     auto v = view->self(); /* non-owning copy */
631     views.push_back(std::move(view));
632 
633     assert(active_output);
634     if (!v->get_output())
635     {
636         v->set_output(active_output);
637     }
638 
639     v->initialize();
640 }
641 
get_all_views()642 std::vector<wayfire_view> wf::compositor_core_impl_t::get_all_views()
643 {
644     std::vector<wayfire_view> result;
645     for (auto& view : this->views)
646     {
647         result.push_back({view});
648     }
649 
650     return result;
651 }
652 
653 /* sets the "active" view and gives it keyboard focus
654  *
655  * It maintains two different classes of "active views"
656  * 1. active_view -> the view which has the current keyboard focus
657  * 2. last_active_toplevel -> the toplevel view which last held the keyboard focus
658  *
659  * Because we don't want to deactivate views when for ex. a panel gets focus,
660  * we don't deactivate the current view when this is the case. However, when
661  * the focus goes back to the toplevel layer, we need to ensure the proper view
662  * is activated.
663  */
set_active_view(wayfire_view new_focus)664 void wf::compositor_core_impl_t::set_active_view(wayfire_view new_focus)
665 {
666     static wf::option_wrapper_t<bool>
667     all_dialogs_modal{"workarounds/all_dialogs_modal"};
668 
669     if (new_focus && !new_focus->is_mapped())
670     {
671         new_focus = nullptr;
672     }
673 
674     if (all_dialogs_modal && new_focus)
675     {
676         // Choose the frontmost view which has focus enabled.
677         auto all_views = new_focus->enumerate_views();
678         for (auto& view : all_views)
679         {
680             if (view->get_keyboard_focus_surface())
681             {
682                 new_focus = view;
683                 break;
684             }
685         }
686     }
687 
688     bool refocus = (last_active_view == new_focus);
689     /* don't deactivate view if the next focus is not a toplevel */
690     if ((new_focus == nullptr) || (new_focus->role == VIEW_ROLE_TOPLEVEL))
691     {
692         if (last_active_view && last_active_view->is_mapped() && !refocus)
693         {
694             last_active_view->set_activated(false);
695         }
696 
697         /* make sure to deactivate the last activated toplevel */
698         if (last_active_toplevel && (new_focus != last_active_toplevel))
699         {
700             last_active_toplevel->set_activated(false);
701         }
702     }
703 
704     if (new_focus)
705     {
706         seat->set_keyboard_focus(new_focus);
707         new_focus->set_activated(true);
708     } else
709     {
710         seat->set_keyboard_focus(nullptr);
711     }
712 
713     last_active_view = new_focus;
714     if (!new_focus || (new_focus->role == VIEW_ROLE_TOPLEVEL))
715     {
716         last_active_toplevel = new_focus;
717     }
718 }
719 
focus_view(wayfire_view v)720 void wf::compositor_core_impl_t::focus_view(wayfire_view v)
721 {
722     if (!v)
723     {
724         return;
725     }
726 
727     if (v->get_output() != active_output)
728     {
729         focus_output(v->get_output());
730     }
731 
732     active_output->focus_view(v, true);
733 }
734 
erase_view(wayfire_view v)735 void wf::compositor_core_impl_t::erase_view(wayfire_view v)
736 {
737     if (!v)
738     {
739         return;
740     }
741 
742     if (v->get_output())
743     {
744         v->set_output(nullptr);
745     }
746 
747     auto it = std::find_if(views.begin(), views.end(),
748         [&v] (const auto& view) { return view.get() == v.get(); });
749 
750     v->deinitialize();
751     views.erase(it);
752 }
753 
run(std::string command)754 pid_t wf::compositor_core_impl_t::run(std::string command)
755 {
756     static constexpr size_t READ_END  = 0;
757     static constexpr size_t WRITE_END = 1;
758     pid_t pid;
759     int pipe_fd[2];
760     pipe2(pipe_fd, O_CLOEXEC);
761 
762     /* The following is a "hack" for disowning the child processes,
763      * otherwise they will simply stay as zombie processes */
764     pid = fork();
765     if (!pid)
766     {
767         pid = fork();
768         if (!pid)
769         {
770             close(pipe_fd[READ_END]);
771             close(pipe_fd[WRITE_END]);
772 
773             setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
774             setenv("WAYLAND_DISPLAY", wayland_display.c_str(), 1);
775 #if WF_HAS_XWAYLAND
776             if (!xwayland_get_display().empty())
777             {
778                 setenv("DISPLAY", xwayland_get_display().c_str(), 1);
779             }
780 
781 #endif
782             int dev_null = open("/dev/null", O_WRONLY);
783             dup2(dev_null, 1);
784             dup2(dev_null, 2);
785 
786             _exit(execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL));
787         } else
788         {
789             close(pipe_fd[READ_END]);
790             write(pipe_fd[WRITE_END], (void*)(&pid), sizeof(pid));
791             close(pipe_fd[WRITE_END]);
792             _exit(0);
793         }
794     } else
795     {
796         close(pipe_fd[WRITE_END]);
797 
798         int status;
799         waitpid(pid, &status, 0);
800 
801         pid_t child_pid;
802         read(pipe_fd[READ_END], &child_pid, sizeof(child_pid));
803 
804         close(pipe_fd[READ_END]);
805 
806         return child_pid;
807     }
808 }
809 
get_xwayland_display()810 std::string wf::compositor_core_impl_t::get_xwayland_display()
811 {
812     return xwayland_get_display();
813 }
814 
move_view_to_output(wayfire_view v,wf::output_t * new_output,bool reconfigure)815 void wf::compositor_core_impl_t::move_view_to_output(wayfire_view v,
816     wf::output_t *new_output, bool reconfigure)
817 {
818     auto old_output = v->get_output();
819     wf::view_pre_moved_to_output_signal data;
820     data.view = v;
821     data.old_output = old_output;
822     data.new_output = new_output;
823     this->emit_signal("view-pre-moved-to-output", &data);
824 
825     uint32_t edges;
826     bool fullscreen;
827     wf::geometry_t view_g;
828     wf::geometry_t old_output_g;
829     wf::geometry_t new_output_g;
830 
831     if (reconfigure)
832     {
833         edges = v->tiled_edges;
834         fullscreen = v->fullscreen;
835         view_g     = v->get_wm_geometry();
836         old_output_g = old_output->get_relative_geometry();
837         new_output_g = new_output->get_relative_geometry();
838         auto ratio_x = (double)new_output_g.width / old_output_g.width;
839         auto ratio_y = (double)new_output_g.height / old_output_g.height;
840         view_g.x     *= ratio_x;
841         view_g.y     *= ratio_y;
842         view_g.width *= ratio_x;
843         view_g.height *= ratio_y;
844     }
845 
846     assert(new_output);
847     v->set_output(new_output);
848     new_output->workspace->add_view(v,
849         v->minimized ? wf::LAYER_MINIMIZED : wf::LAYER_WORKSPACE);
850     new_output->focus_view(v);
851 
852     if (reconfigure)
853     {
854         if (fullscreen)
855         {
856             v->fullscreen_request(new_output, true);
857         } else if (edges)
858         {
859             v->tile_request(edges);
860         } else
861         {
862             auto new_g = wf::clamp(view_g, new_output->workspace->get_workarea());
863             v->set_geometry(new_g);
864         }
865     }
866 
867     this->emit_signal("view-moved-to-output", &data);
868 }
869 
compositor_core_t()870 wf::compositor_core_t::compositor_core_t()
871 {}
~compositor_core_t()872 wf::compositor_core_t::~compositor_core_t()
873 {}
874 
compositor_core_impl_t()875 wf::compositor_core_impl_t::compositor_core_impl_t()
876 {}
~compositor_core_impl_t()877 wf::compositor_core_impl_t::~compositor_core_impl_t()
878 {
879     /* Unloading order is important. First we want to free any remaining views,
880      * then we destroy the input manager, and finally the rest is auto-freed */
881     views.clear();
882     input.reset();
883     output_layout.reset();
884 }
885 
get()886 wf::compositor_core_impl_t& wf::compositor_core_impl_t::get()
887 {
888     static compositor_core_impl_t instance;
889 
890     return instance;
891 }
892 
get()893 wf::compositor_core_t& wf::compositor_core_t::get()
894 {
895     return wf::compositor_core_impl_t::get();
896 }
897 
get_core()898 wf::compositor_core_t& wf::get_core()
899 {
900     return wf::compositor_core_t::get();
901 }
902 
get_core_impl()903 wf::compositor_core_impl_t& wf::get_core_impl()
904 {
905     return wf::compositor_core_impl_t::get();
906 }
907