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