mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Fire up the wlroots backend and run the event loop
This commit is contained in:
		
							parent
							
								
									6edc32848f
								
							
						
					
					
						commit
						7c448b4081
					
				
					 11 changed files with 160 additions and 904 deletions
				
			
		| 
						 | 
					@ -1,56 +0,0 @@
 | 
				
			||||||
#ifndef _SWAY_EXTENSIONS_H
 | 
					 | 
				
			||||||
#define _SWAY_EXTENSIONS_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wlc/wlc-wayland.h>
 | 
					 | 
				
			||||||
#include "wayland-desktop-shell-server-protocol.h"
 | 
					 | 
				
			||||||
#include "list.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct background_config {
 | 
					 | 
				
			||||||
	wlc_handle output;
 | 
					 | 
				
			||||||
	wlc_resource surface;
 | 
					 | 
				
			||||||
	// we need the wl_resource of the surface in the destructor
 | 
					 | 
				
			||||||
	struct wl_resource *wl_surface_res;
 | 
					 | 
				
			||||||
	struct wl_client *client;
 | 
					 | 
				
			||||||
    wlc_handle handle;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct panel_config {
 | 
					 | 
				
			||||||
	// wayland resource used in callbacks, is used to track this panel
 | 
					 | 
				
			||||||
	struct wl_resource *wl_resource;
 | 
					 | 
				
			||||||
	wlc_handle output;
 | 
					 | 
				
			||||||
	wlc_resource surface;
 | 
					 | 
				
			||||||
	// we need the wl_resource of the surface in the destructor
 | 
					 | 
				
			||||||
	struct wl_resource *wl_surface_res;
 | 
					 | 
				
			||||||
	enum desktop_shell_panel_position panel_position;
 | 
					 | 
				
			||||||
	// used to determine if client is a panel
 | 
					 | 
				
			||||||
	struct wl_client *client;
 | 
					 | 
				
			||||||
	// wlc handle for this panel's surface, not set until panel is created
 | 
					 | 
				
			||||||
	wlc_handle handle;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct desktop_shell_state {
 | 
					 | 
				
			||||||
	list_t *backgrounds;
 | 
					 | 
				
			||||||
	list_t *panels;
 | 
					 | 
				
			||||||
	list_t *lock_surfaces;
 | 
					 | 
				
			||||||
	bool is_locked;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct swaylock_state {
 | 
					 | 
				
			||||||
	bool active;
 | 
					 | 
				
			||||||
	wlc_handle output;
 | 
					 | 
				
			||||||
	wlc_resource surface;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct decoration_state {
 | 
					 | 
				
			||||||
	list_t *csd_resources;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern struct desktop_shell_state desktop_shell;
 | 
					 | 
				
			||||||
extern struct decoration_state decoration_state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void register_extensions(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void server_decoration_enable_csd(wlc_handle handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
							
								
								
									
										31
									
								
								include/sway/server.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								include/sway/server.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					#ifndef _SWAY_SERVER_H
 | 
				
			||||||
 | 
					#define _SWAY_SERVER_H
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_data_device_manager.h>
 | 
				
			||||||
 | 
					#include <wlr/render.h>
 | 
				
			||||||
 | 
					// TODO WLR: make Xwayland optional
 | 
				
			||||||
 | 
					#include <wlr/xwayland.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_server {
 | 
				
			||||||
 | 
						// TODO WLR
 | 
				
			||||||
 | 
						//struct roots_desktop *desktop;
 | 
				
			||||||
 | 
						//struct roots_input *input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_display *wl_display;
 | 
				
			||||||
 | 
						struct wl_event_loop *wl_event_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_backend *backend;
 | 
				
			||||||
 | 
						struct wlr_renderer *renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_data_device_manager *data_device_manager;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool server_init(struct sway_server *server);
 | 
				
			||||||
 | 
					void server_fini(struct sway_server *server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_server server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -25,9 +25,7 @@ add_executable(sway
 | 
				
			||||||
	container.c
 | 
						container.c
 | 
				
			||||||
	criteria.c
 | 
						criteria.c
 | 
				
			||||||
	debug_log.c
 | 
						debug_log.c
 | 
				
			||||||
	extensions.c
 | 
					 | 
				
			||||||
	focus.c
 | 
						focus.c
 | 
				
			||||||
	handlers.c
 | 
					 | 
				
			||||||
	input.c
 | 
						input.c
 | 
				
			||||||
	input_state.c
 | 
						input_state.c
 | 
				
			||||||
	ipc-json.c
 | 
						ipc-json.c
 | 
				
			||||||
| 
						 | 
					@ -38,6 +36,7 @@ add_executable(sway
 | 
				
			||||||
	workspace.c
 | 
						workspace.c
 | 
				
			||||||
	border.c
 | 
						border.c
 | 
				
			||||||
	security.c
 | 
						security.c
 | 
				
			||||||
 | 
					    server.c
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_definitions(
 | 
					add_definitions(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,6 +120,7 @@ void input_cmd_apply(struct input_config *input) {
 | 
				
			||||||
		// Try to find the input device and apply configuration now. If
 | 
							// Try to find the input device and apply configuration now. If
 | 
				
			||||||
		// this is during startup then there will be no container and config
 | 
							// this is during startup then there will be no container and config
 | 
				
			||||||
		// will be applied during normal "new input" event from wlc.
 | 
							// will be applied during normal "new input" event from wlc.
 | 
				
			||||||
 | 
							/* TODO WLR
 | 
				
			||||||
		struct libinput_device *device = NULL;
 | 
							struct libinput_device *device = NULL;
 | 
				
			||||||
		for (int i = 0; i < input_devices->length; ++i) {
 | 
							for (int i = 0; i < input_devices->length; ++i) {
 | 
				
			||||||
			device = input_devices->items[i];
 | 
								device = input_devices->items[i];
 | 
				
			||||||
| 
						 | 
					@ -134,6 +135,7 @@ void input_cmd_apply(struct input_config *input) {
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,407 +0,0 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <wlc/wlc.h>
 | 
					 | 
				
			||||||
#include <wlc/wlc-wayland.h>
 | 
					 | 
				
			||||||
#include <wlc/wlc-render.h>
 | 
					 | 
				
			||||||
#include "wayland-desktop-shell-server-protocol.h"
 | 
					 | 
				
			||||||
#include "wayland-swaylock-server-protocol.h"
 | 
					 | 
				
			||||||
#include "wayland-gamma-control-server-protocol.h"
 | 
					 | 
				
			||||||
#include "wayland-server-decoration-server-protocol.h"
 | 
					 | 
				
			||||||
#include "sway/layout.h"
 | 
					 | 
				
			||||||
#include "sway/input_state.h"
 | 
					 | 
				
			||||||
#include "sway/extensions.h"
 | 
					 | 
				
			||||||
#include "sway/security.h"
 | 
					 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					 | 
				
			||||||
#include "log.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct desktop_shell_state desktop_shell;
 | 
					 | 
				
			||||||
struct decoration_state decoration_state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct panel_config *find_or_create_panel_config(struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	for (int i = 0; i < desktop_shell.panels->length; i++) {
 | 
					 | 
				
			||||||
		struct panel_config *conf = desktop_shell.panels->items[i];
 | 
					 | 
				
			||||||
		if (conf->wl_resource == resource) {
 | 
					 | 
				
			||||||
			sway_log(L_DEBUG, "Found existing panel config for resource %p", resource);
 | 
					 | 
				
			||||||
			return conf;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Creating panel config for resource %p", resource);
 | 
					 | 
				
			||||||
	struct panel_config *config = calloc(1, sizeof(struct panel_config));
 | 
					 | 
				
			||||||
	if (!config) {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "Unable to create panel config");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	list_add(desktop_shell.panels, config);
 | 
					 | 
				
			||||||
	config->wl_resource = resource;
 | 
					 | 
				
			||||||
	return config;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void background_surface_destructor(struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Background surface killed");
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	for (i = 0; i < desktop_shell.backgrounds->length; ++i) {
 | 
					 | 
				
			||||||
		struct background_config *config = desktop_shell.backgrounds->items[i];
 | 
					 | 
				
			||||||
		if (config->wl_surface_res == resource) {
 | 
					 | 
				
			||||||
			list_del(desktop_shell.backgrounds, i);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void panel_surface_destructor(struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Panel surface killed");
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	for (i = 0; i < desktop_shell.panels->length; ++i) {
 | 
					 | 
				
			||||||
		struct panel_config *config = desktop_shell.panels->items[i];
 | 
					 | 
				
			||||||
		if (config->wl_surface_res == resource) {
 | 
					 | 
				
			||||||
			list_del(desktop_shell.panels, i);
 | 
					 | 
				
			||||||
			arrange_windows(&root_container, -1, -1);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void lock_surface_destructor(struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Lock surface killed");
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	for (i = 0; i < desktop_shell.lock_surfaces->length; ++i) {
 | 
					 | 
				
			||||||
		struct wl_resource *surface = desktop_shell.lock_surfaces->items[i];
 | 
					 | 
				
			||||||
		if (surface == resource) {
 | 
					 | 
				
			||||||
			list_del(desktop_shell.lock_surfaces, i);
 | 
					 | 
				
			||||||
			arrange_windows(&root_container, -1, -1);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (desktop_shell.lock_surfaces->length == 0) {
 | 
					 | 
				
			||||||
		sway_log(L_DEBUG, "Desktop shell unlocked");
 | 
					 | 
				
			||||||
		desktop_shell.is_locked = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We need to now give focus back to the focus which we internally
 | 
					 | 
				
			||||||
		// track, since when we lock sway we don't actually change our internal
 | 
					 | 
				
			||||||
		// focus tracking.
 | 
					 | 
				
			||||||
		swayc_t *focus = get_focused_container(swayc_active_workspace());
 | 
					 | 
				
			||||||
		set_focused_container(focus);
 | 
					 | 
				
			||||||
		wlc_view_focus(focus->handle);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void set_background(struct wl_client *client, struct wl_resource *resource,
 | 
					 | 
				
			||||||
		struct wl_resource *_output, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	wl_client_get_credentials(client, &pid, NULL, NULL);
 | 
					 | 
				
			||||||
	if (!(get_feature_policy_mask(pid) & FEATURE_BACKGROUND)) {
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "Denying background feature to %d", pid);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlc_handle output = wlc_handle_from_wl_output_resource(_output);
 | 
					 | 
				
			||||||
	if (!output) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Setting surface %p as background for output %d", surface, (int)output);
 | 
					 | 
				
			||||||
	struct background_config *config = malloc(sizeof(struct background_config));
 | 
					 | 
				
			||||||
	if (!config) {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "Unable to allocate background config");
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config->client = client;
 | 
					 | 
				
			||||||
	config->output = output;
 | 
					 | 
				
			||||||
	config->surface = wlc_resource_from_wl_surface_resource(surface);
 | 
					 | 
				
			||||||
	config->wl_surface_res = surface;
 | 
					 | 
				
			||||||
	list_add(desktop_shell.backgrounds, config);
 | 
					 | 
				
			||||||
	wl_resource_set_destructor(surface, background_surface_destructor);
 | 
					 | 
				
			||||||
	arrange_windows(swayc_by_handle(output), -1, -1);
 | 
					 | 
				
			||||||
	wlc_output_schedule_render(config->output);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void set_panel(struct wl_client *client, struct wl_resource *resource,
 | 
					 | 
				
			||||||
		struct wl_resource *_output, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	wl_client_get_credentials(client, &pid, NULL, NULL);
 | 
					 | 
				
			||||||
	if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) {
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "Denying panel feature to %d", pid);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlc_handle output = wlc_handle_from_wl_output_resource(_output);
 | 
					 | 
				
			||||||
	if (!output) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Setting surface %p as panel for output %d (wl_resource: %p)", surface, (int)output, resource);
 | 
					 | 
				
			||||||
	struct panel_config *config = find_or_create_panel_config(resource);
 | 
					 | 
				
			||||||
	config->output = output;
 | 
					 | 
				
			||||||
	config->client = client;
 | 
					 | 
				
			||||||
	config->surface = wlc_resource_from_wl_surface_resource(surface);
 | 
					 | 
				
			||||||
	config->wl_surface_res = surface;
 | 
					 | 
				
			||||||
	wl_resource_set_destructor(surface, panel_surface_destructor);
 | 
					 | 
				
			||||||
	arrange_windows(&root_container, -1, -1);
 | 
					 | 
				
			||||||
	wlc_output_schedule_render(config->output);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void desktop_set_lock_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	sway_log(L_ERROR, "desktop_set_lock_surface is not currently supported");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void desktop_unlock(struct wl_client *client, struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	sway_log(L_ERROR, "desktop_unlock is not currently supported");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void set_grab_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	sway_log(L_ERROR, "desktop_set_grab_surface is not currently supported");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void desktop_ready(struct wl_client *client, struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	// nop
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void set_panel_position(struct wl_client *client, struct wl_resource *resource, uint32_t position) {
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	wl_client_get_credentials(client, &pid, NULL, NULL);
 | 
					 | 
				
			||||||
	if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) {
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "Denying panel feature to %d", pid);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct panel_config *config = find_or_create_panel_config(resource);
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Panel position for wl_resource %p changed %d => %d", resource, config->panel_position, position);
 | 
					 | 
				
			||||||
	config->panel_position = position;
 | 
					 | 
				
			||||||
	arrange_windows(&root_container, -1, -1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct desktop_shell_interface desktop_shell_implementation = {
 | 
					 | 
				
			||||||
	.set_background = set_background,
 | 
					 | 
				
			||||||
	.set_panel = set_panel,
 | 
					 | 
				
			||||||
	.set_lock_surface = desktop_set_lock_surface,
 | 
					 | 
				
			||||||
	.unlock = desktop_unlock,
 | 
					 | 
				
			||||||
	.set_grab_surface = set_grab_surface,
 | 
					 | 
				
			||||||
	.desktop_ready = desktop_ready,
 | 
					 | 
				
			||||||
	.set_panel_position = set_panel_position
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void desktop_shell_bind(struct wl_client *client, void *data,
 | 
					 | 
				
			||||||
		uint32_t version, uint32_t id) {
 | 
					 | 
				
			||||||
	if (version > 3) {
 | 
					 | 
				
			||||||
		// Unsupported version
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_resource *resource = wl_resource_create(client, &desktop_shell_interface, version, id);
 | 
					 | 
				
			||||||
	if (!resource) {
 | 
					 | 
				
			||||||
		wl_client_post_no_memory(client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(resource, &desktop_shell_implementation, NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void set_lock_surface(struct wl_client *client, struct wl_resource *resource,
 | 
					 | 
				
			||||||
		struct wl_resource *_output, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	wl_client_get_credentials(client, &pid, NULL, NULL);
 | 
					 | 
				
			||||||
	if (!(get_feature_policy_mask(pid) & FEATURE_LOCK)) {
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "Denying lock feature to %d", pid);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	swayc_t *output = swayc_by_handle(wlc_handle_from_wl_output_resource(_output));
 | 
					 | 
				
			||||||
	swayc_t *view = swayc_by_handle(wlc_handle_from_wl_surface_resource(surface));
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Setting lock surface to %p", view);
 | 
					 | 
				
			||||||
	if (view && output) {
 | 
					 | 
				
			||||||
		swayc_t *workspace = output->focused;
 | 
					 | 
				
			||||||
		if (!swayc_is_child_of(view, workspace)) {
 | 
					 | 
				
			||||||
			move_container_to(view, workspace);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// make the view floating so it doesn't rearrange other siblings.
 | 
					 | 
				
			||||||
		if (!view->is_floating) {
 | 
					 | 
				
			||||||
			destroy_container(remove_child(view));
 | 
					 | 
				
			||||||
			add_floating(workspace, view);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		wlc_view_set_state(view->handle, WLC_BIT_FULLSCREEN, true);
 | 
					 | 
				
			||||||
		wlc_view_bring_to_front(view->handle);
 | 
					 | 
				
			||||||
		wlc_view_focus(view->handle);
 | 
					 | 
				
			||||||
		desktop_shell.is_locked = true;
 | 
					 | 
				
			||||||
		input_init();
 | 
					 | 
				
			||||||
		arrange_windows(workspace, -1, -1);
 | 
					 | 
				
			||||||
		list_add(desktop_shell.lock_surfaces, surface);
 | 
					 | 
				
			||||||
		wl_resource_set_destructor(surface, lock_surface_destructor);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "Attempted to set lock surface to non-view");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void unlock(struct wl_client *client, struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	sway_log(L_ERROR, "unlock is not currently supported");
 | 
					 | 
				
			||||||
	// This isn't really necessary, we just unlock when the client exits.
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct lock_interface swaylock_implementation = {
 | 
					 | 
				
			||||||
	.set_lock_surface = set_lock_surface,
 | 
					 | 
				
			||||||
	.unlock = unlock
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void swaylock_bind(struct wl_client *client, void *data,
 | 
					 | 
				
			||||||
		uint32_t version, uint32_t id) {
 | 
					 | 
				
			||||||
	if (version > 1) {
 | 
					 | 
				
			||||||
		// Unsupported version
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_resource *resource = wl_resource_create(client, &lock_interface, version, id);
 | 
					 | 
				
			||||||
	if (!resource) {
 | 
					 | 
				
			||||||
		wl_client_post_no_memory(client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(resource, &swaylock_implementation, NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_destroy(struct wl_client *client, struct wl_resource *res) {
 | 
					 | 
				
			||||||
	wl_resource_destroy(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_set_gamma(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *res, struct wl_array *red,
 | 
					 | 
				
			||||||
		struct wl_array *green, struct wl_array *blue) {
 | 
					 | 
				
			||||||
	if (red->size != green->size || red->size != blue->size) {
 | 
					 | 
				
			||||||
		wl_resource_post_error(res, GAMMA_CONTROL_ERROR_INVALID_GAMMA,
 | 
					 | 
				
			||||||
				"The gamma ramps don't have the same size");
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	uint16_t *r = (uint16_t *)red->data;
 | 
					 | 
				
			||||||
	uint16_t *g = (uint16_t *)green->data;
 | 
					 | 
				
			||||||
	uint16_t *b = (uint16_t *)blue->data;
 | 
					 | 
				
			||||||
	wlc_handle output = wlc_handle_from_wl_output_resource(
 | 
					 | 
				
			||||||
			wl_resource_get_user_data(res));
 | 
					 | 
				
			||||||
	if (!output) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Setting gamma for output");
 | 
					 | 
				
			||||||
	wlc_output_set_gamma(output, red->size / sizeof(uint16_t), r, g, b);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_reset_gamma(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	// This space intentionally left blank
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct gamma_control_interface gamma_control_implementation = {
 | 
					 | 
				
			||||||
	.destroy = gamma_control_destroy,
 | 
					 | 
				
			||||||
	.set_gamma = gamma_control_set_gamma,
 | 
					 | 
				
			||||||
	.reset_gamma = gamma_control_reset_gamma
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_manager_destroy(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *res) {
 | 
					 | 
				
			||||||
	wl_resource_destroy(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_manager_get(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *res, uint32_t id, struct wl_resource *_output) {
 | 
					 | 
				
			||||||
	struct wl_resource *manager_res = wl_resource_create(client,
 | 
					 | 
				
			||||||
			&gamma_control_interface, wl_resource_get_version(res), id);
 | 
					 | 
				
			||||||
	wlc_handle output = wlc_handle_from_wl_output_resource(_output);
 | 
					 | 
				
			||||||
	if (!output) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(manager_res, &gamma_control_implementation,
 | 
					 | 
				
			||||||
			_output, NULL);
 | 
					 | 
				
			||||||
	gamma_control_send_gamma_size(manager_res, wlc_output_get_gamma_size(output));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct gamma_control_manager_interface gamma_manager_implementation = {
 | 
					 | 
				
			||||||
	.destroy = gamma_control_manager_destroy,
 | 
					 | 
				
			||||||
	.get_gamma_control = gamma_control_manager_get
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void gamma_control_manager_bind(struct wl_client *client, void *data,
 | 
					 | 
				
			||||||
		uint32_t version, uint32_t id) {
 | 
					 | 
				
			||||||
	if (version > 1) {
 | 
					 | 
				
			||||||
		// Unsupported version
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct wl_resource *resource = wl_resource_create(client,
 | 
					 | 
				
			||||||
			&gamma_control_manager_interface, version, id);
 | 
					 | 
				
			||||||
	if (!resource) {
 | 
					 | 
				
			||||||
		wl_client_post_no_memory(client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(resource, &gamma_manager_implementation, NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_decoration_release(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	wl_resource_destroy(resource);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void server_decoration_enable_csd(wlc_handle handle) {
 | 
					 | 
				
			||||||
	swayc_t *view = swayc_by_handle(handle);
 | 
					 | 
				
			||||||
	if (!view) {
 | 
					 | 
				
			||||||
		sway_log(L_DEBUG, "view invalid");
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "%s requested client side decorations", view->name);
 | 
					 | 
				
			||||||
	view->border_type = B_NONE;
 | 
					 | 
				
			||||||
	update_geometry(view);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_decoration_request_mode(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *resource, uint32_t mode) {
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Client requested server decoration mode %d", mode);
 | 
					 | 
				
			||||||
	if (mode == ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct wl_resource *surface = wl_resource_get_user_data(resource);
 | 
					 | 
				
			||||||
	if (!surface) {
 | 
					 | 
				
			||||||
		sway_log(L_DEBUG, "surface invalid");
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlc_handle handle = wlc_handle_from_wl_surface_resource(surface);
 | 
					 | 
				
			||||||
	if (!handle) {
 | 
					 | 
				
			||||||
		list_add(decoration_state.csd_resources, surface);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	server_decoration_enable_csd(handle);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct org_kde_kwin_server_decoration_interface server_decoration_implementation = {
 | 
					 | 
				
			||||||
	.release = server_decoration_release,
 | 
					 | 
				
			||||||
	.request_mode = server_decoration_request_mode,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_decoration_manager_create(struct wl_client *client,
 | 
					 | 
				
			||||||
		struct wl_resource *resource, uint32_t id, struct wl_resource *surface) {
 | 
					 | 
				
			||||||
	sway_log(L_DEBUG, "Client requested server decoration manager");
 | 
					 | 
				
			||||||
	struct wl_resource *manager = wl_resource_create(client,
 | 
					 | 
				
			||||||
			&org_kde_kwin_server_decoration_interface, 1, id);
 | 
					 | 
				
			||||||
	if (!manager) {
 | 
					 | 
				
			||||||
		wl_client_post_no_memory(client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(manager, &server_decoration_implementation, surface, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Jesus christ KDE, these names are whack as hell
 | 
					 | 
				
			||||||
static struct org_kde_kwin_server_decoration_manager_interface server_decoration_manager_implementation = {
 | 
					 | 
				
			||||||
	.create = server_decoration_manager_create,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_decoration_manager_bind(struct wl_client *client, void *data,
 | 
					 | 
				
			||||||
		uint32_t version, uint32_t id) {
 | 
					 | 
				
			||||||
	if (version > 1) {
 | 
					 | 
				
			||||||
		// Unsupported version
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct wl_resource *resource = wl_resource_create(client,
 | 
					 | 
				
			||||||
			&org_kde_kwin_server_decoration_manager_interface, version, id);
 | 
					 | 
				
			||||||
	if (!resource) {
 | 
					 | 
				
			||||||
		wl_client_post_no_memory(client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wl_resource_set_implementation(resource, &server_decoration_manager_implementation, NULL, NULL);
 | 
					 | 
				
			||||||
	org_kde_kwin_server_decoration_manager_send_default_mode(resource,
 | 
					 | 
				
			||||||
			ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void register_extensions(void) {
 | 
					 | 
				
			||||||
	wl_global_create(wlc_get_wl_display(), &desktop_shell_interface, 3, NULL, desktop_shell_bind);
 | 
					 | 
				
			||||||
	desktop_shell.backgrounds = create_list();
 | 
					 | 
				
			||||||
	desktop_shell.panels = create_list();
 | 
					 | 
				
			||||||
	desktop_shell.lock_surfaces = create_list();
 | 
					 | 
				
			||||||
	desktop_shell.is_locked = false;
 | 
					 | 
				
			||||||
	decoration_state.csd_resources = create_list();
 | 
					 | 
				
			||||||
	wl_global_create(wlc_get_wl_display(), &lock_interface, 1, NULL, swaylock_bind);
 | 
					 | 
				
			||||||
	wl_global_create(wlc_get_wl_display(), &gamma_control_manager_interface, 1,
 | 
					 | 
				
			||||||
			NULL, gamma_control_manager_bind);
 | 
					 | 
				
			||||||
	wl_global_create(wlc_get_wl_display(), &org_kde_kwin_server_decoration_manager_interface ,
 | 
					 | 
				
			||||||
			1, NULL, server_decoration_manager_bind);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@
 | 
				
			||||||
#include "sway/workspace.h"
 | 
					#include "sway/workspace.h"
 | 
				
			||||||
#include "sway/layout.h"
 | 
					#include "sway/layout.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/extensions.h"
 | 
					 | 
				
			||||||
#include "sway/input_state.h"
 | 
					#include "sway/input_state.h"
 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "sway/border.h"
 | 
					#include "sway/border.h"
 | 
				
			||||||
| 
						 | 
					@ -163,12 +162,14 @@ bool set_focused_container(swayc_t *c) {
 | 
				
			||||||
		if (c->type == C_VIEW) {
 | 
							if (c->type == C_VIEW) {
 | 
				
			||||||
			wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true);
 | 
								wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							/* TODO WLR
 | 
				
			||||||
		if (!desktop_shell.is_locked) {
 | 
							if (!desktop_shell.is_locked) {
 | 
				
			||||||
			// If the system is locked, we do everything _but_ actually setting
 | 
								// If the system is locked, we do everything _but_ actually setting
 | 
				
			||||||
			// focus. This includes making our internals think that this view is
 | 
								// focus. This includes making our internals think that this view is
 | 
				
			||||||
			// focused.
 | 
								// focused.
 | 
				
			||||||
			wlc_view_focus(c->handle);
 | 
								wlc_view_focus(c->handle);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
		if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) {
 | 
							if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) {
 | 
				
			||||||
			update_container_border(c);
 | 
								update_container_border(c);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <sys/un.h>
 | 
					#include <sys/un.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <wlc/wlc-render.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <sys/ioctl.h>
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
| 
						 | 
					@ -31,21 +30,22 @@ struct ucred {
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input.h"
 | 
					#include "sway/input.h"
 | 
				
			||||||
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ipc_socket = -1;
 | 
					static int ipc_socket = -1;
 | 
				
			||||||
static struct wlc_event_source *ipc_event_source =  NULL;
 | 
					static struct wl_event_source *ipc_event_source =  NULL;
 | 
				
			||||||
static struct sockaddr_un *ipc_sockaddr = NULL;
 | 
					static struct sockaddr_un *ipc_sockaddr = NULL;
 | 
				
			||||||
static list_t *ipc_client_list = NULL;
 | 
					static list_t *ipc_client_list = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
 | 
					static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ipc_client {
 | 
					struct ipc_client {
 | 
				
			||||||
	struct wlc_event_source *event_source;
 | 
						struct wl_event_source *event_source;
 | 
				
			||||||
	struct wlc_event_source *writable_event_source;
 | 
						struct wl_event_source *writable_event_source;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	uint32_t payload_length;
 | 
						uint32_t payload_length;
 | 
				
			||||||
	uint32_t security_policy;
 | 
						uint32_t security_policy;
 | 
				
			||||||
| 
						 | 
					@ -58,25 +58,6 @@ struct ipc_client {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static list_t *ipc_get_pixel_requests = NULL;
 | 
					static list_t *ipc_get_pixel_requests = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct get_pixels_request {
 | 
					 | 
				
			||||||
	struct ipc_client *client;
 | 
					 | 
				
			||||||
	wlc_handle output;
 | 
					 | 
				
			||||||
	struct wlc_geometry geo;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct get_clipboard_request {
 | 
					 | 
				
			||||||
	struct ipc_client *client;
 | 
					 | 
				
			||||||
	json_object *json;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	struct wlc_event_source *fd_event_source;
 | 
					 | 
				
			||||||
	struct wlc_event_source *timer_event_source;
 | 
					 | 
				
			||||||
	char *type;
 | 
					 | 
				
			||||||
	unsigned int *pending;
 | 
					 | 
				
			||||||
	char *buf;
 | 
					 | 
				
			||||||
	size_t buf_size;
 | 
					 | 
				
			||||||
	size_t buf_position;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct sockaddr_un *ipc_user_sockaddr(void);
 | 
					struct sockaddr_un *ipc_user_sockaddr(void);
 | 
				
			||||||
int ipc_handle_connection(int fd, uint32_t mask, void *data);
 | 
					int ipc_handle_connection(int fd, uint32_t mask, void *data);
 | 
				
			||||||
int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
 | 
					int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
 | 
				
			||||||
| 
						 | 
					@ -118,12 +99,13 @@ void ipc_init(void) {
 | 
				
			||||||
	ipc_client_list = create_list();
 | 
						ipc_client_list = create_list();
 | 
				
			||||||
	ipc_get_pixel_requests = create_list();
 | 
						ipc_get_pixel_requests = create_list();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL);
 | 
						ipc_event_source = wl_event_loop_add_fd(server.wl_event_loop, ipc_socket,
 | 
				
			||||||
 | 
								WL_EVENT_READABLE, ipc_handle_connection, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ipc_terminate(void) {
 | 
					void ipc_terminate(void) {
 | 
				
			||||||
	if (ipc_event_source) {
 | 
						if (ipc_event_source) {
 | 
				
			||||||
		wlc_event_source_remove(ipc_event_source);
 | 
							wl_event_source_remove(ipc_event_source);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	close(ipc_socket);
 | 
						close(ipc_socket);
 | 
				
			||||||
	unlink(ipc_sockaddr->sun_path);
 | 
						unlink(ipc_sockaddr->sun_path);
 | 
				
			||||||
| 
						 | 
					@ -176,7 +158,7 @@ static pid_t get_client_pid(int client_fd) {
 | 
				
			||||||
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
 | 
					int ipc_handle_connection(int fd, uint32_t mask, void *data) {
 | 
				
			||||||
	(void) fd; (void) data;
 | 
						(void) fd; (void) data;
 | 
				
			||||||
	sway_log(L_DEBUG, "Event on IPC listening socket");
 | 
						sway_log(L_DEBUG, "Event on IPC listening socket");
 | 
				
			||||||
	assert(mask == WLC_EVENT_READABLE);
 | 
						assert(mask == WL_EVENT_READABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int client_fd = accept(ipc_socket, NULL, NULL);
 | 
						int client_fd = accept(ipc_socket, NULL, NULL);
 | 
				
			||||||
	if (client_fd == -1) {
 | 
						if (client_fd == -1) {
 | 
				
			||||||
| 
						 | 
					@ -207,7 +189,8 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
 | 
				
			||||||
	client->payload_length = 0;
 | 
						client->payload_length = 0;
 | 
				
			||||||
	client->fd = client_fd;
 | 
						client->fd = client_fd;
 | 
				
			||||||
	client->subscribed_events = 0;
 | 
						client->subscribed_events = 0;
 | 
				
			||||||
	client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
 | 
						client->event_source = wl_event_loop_add_fd(server.wl_event_loop, client_fd,
 | 
				
			||||||
 | 
								WL_EVENT_READABLE, ipc_client_handle_readable, client);
 | 
				
			||||||
	client->writable_event_source = NULL;
 | 
						client->writable_event_source = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client->write_buffer_size = 128;
 | 
						client->write_buffer_size = 128;
 | 
				
			||||||
| 
						 | 
					@ -234,13 +217,13 @@ static const int ipc_header_size = sizeof(ipc_magic)+8;
 | 
				
			||||||
int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
 | 
					int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
 | 
				
			||||||
	struct ipc_client *client = data;
 | 
						struct ipc_client *client = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask & WLC_EVENT_ERROR) {
 | 
						if (mask & WL_EVENT_ERROR) {
 | 
				
			||||||
		sway_log(L_ERROR, "IPC Client socket error, removing client");
 | 
							sway_log(L_ERROR, "IPC Client socket error, removing client");
 | 
				
			||||||
		ipc_client_disconnect(client);
 | 
							ipc_client_disconnect(client);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask & WLC_EVENT_HANGUP) {
 | 
						if (mask & WL_EVENT_HANGUP) {
 | 
				
			||||||
		sway_log(L_DEBUG, "Client %d hung up", client->fd);
 | 
							sway_log(L_DEBUG, "Client %d hung up", client->fd);
 | 
				
			||||||
		ipc_client_disconnect(client);
 | 
							ipc_client_disconnect(client);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					@ -296,13 +279,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
 | 
				
			||||||
int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
 | 
					int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
 | 
				
			||||||
	struct ipc_client *client = data;
 | 
						struct ipc_client *client = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask & WLC_EVENT_ERROR) {
 | 
						if (mask & WL_EVENT_ERROR) {
 | 
				
			||||||
		sway_log(L_ERROR, "IPC Client socket error, removing client");
 | 
							sway_log(L_ERROR, "IPC Client socket error, removing client");
 | 
				
			||||||
		ipc_client_disconnect(client);
 | 
							ipc_client_disconnect(client);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask & WLC_EVENT_HANGUP) {
 | 
						if (mask & WL_EVENT_HANGUP) {
 | 
				
			||||||
		sway_log(L_DEBUG, "Client %d hung up", client->fd);
 | 
							sway_log(L_DEBUG, "Client %d hung up", client->fd);
 | 
				
			||||||
		ipc_client_disconnect(client);
 | 
							ipc_client_disconnect(client);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					@ -328,7 +311,7 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
 | 
				
			||||||
	client->write_buffer_len -= written;
 | 
						client->write_buffer_len -= written;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (client->write_buffer_len == 0 && client->writable_event_source) {
 | 
						if (client->write_buffer_len == 0 && client->writable_event_source) {
 | 
				
			||||||
		wlc_event_source_remove(client->writable_event_source);
 | 
							wl_event_source_remove(client->writable_event_source);
 | 
				
			||||||
		client->writable_event_source = NULL;
 | 
							client->writable_event_source = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -345,9 +328,9 @@ void ipc_client_disconnect(struct ipc_client *client) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
 | 
						sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
 | 
				
			||||||
	wlc_event_source_remove(client->event_source);
 | 
						wl_event_source_remove(client->event_source);
 | 
				
			||||||
	if (client->writable_event_source) {
 | 
						if (client->writable_event_source) {
 | 
				
			||||||
		wlc_event_source_remove(client->writable_event_source);
 | 
							wl_event_source_remove(client->writable_event_source);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	int i = 0;
 | 
						int i = 0;
 | 
				
			||||||
	while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
 | 
						while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
 | 
				
			||||||
| 
						 | 
					@ -365,165 +348,6 @@ bool output_by_name_test(swayc_t *view, void *data) {
 | 
				
			||||||
	return !strcmp(name, view->name);
 | 
						return !strcmp(name, view->name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ipc_get_pixels(wlc_handle output) {
 | 
					 | 
				
			||||||
	if (ipc_get_pixel_requests->length == 0) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_t *unhandled = create_list();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct get_pixels_request *req;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	for (i = 0; i < ipc_get_pixel_requests->length; ++i) {
 | 
					 | 
				
			||||||
		req = ipc_get_pixel_requests->items[i];
 | 
					 | 
				
			||||||
		if (req->output != output) {
 | 
					 | 
				
			||||||
			list_add(unhandled, req);
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const struct wlc_size *size = &req->geo.size;
 | 
					 | 
				
			||||||
		struct wlc_geometry g_out;
 | 
					 | 
				
			||||||
		char response_header[9];
 | 
					 | 
				
			||||||
		memset(response_header, 0, sizeof(response_header));
 | 
					 | 
				
			||||||
		char *data = malloc(sizeof(response_header) + size->w * size->h * 4);
 | 
					 | 
				
			||||||
		if (!data) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "Unable to allocate pixels for get_pixels");
 | 
					 | 
				
			||||||
			ipc_client_disconnect(req->client);
 | 
					 | 
				
			||||||
			free(req);
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		wlc_pixels_read(WLC_RGBA8888, &req->geo, &g_out, data + sizeof(response_header));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		response_header[0] = 1;
 | 
					 | 
				
			||||||
		uint32_t *_size = (uint32_t *)(response_header + 1);
 | 
					 | 
				
			||||||
		_size[0] = g_out.size.w;
 | 
					 | 
				
			||||||
		_size[1] = g_out.size.h;
 | 
					 | 
				
			||||||
		size_t len = sizeof(response_header) + (g_out.size.w * g_out.size.h * 4);
 | 
					 | 
				
			||||||
		memcpy(data, response_header, sizeof(response_header));
 | 
					 | 
				
			||||||
		ipc_send_reply(req->client, data, len);
 | 
					 | 
				
			||||||
		free(data);
 | 
					 | 
				
			||||||
		// free the request since it has been handled
 | 
					 | 
				
			||||||
		free(req);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// free old list of pixel requests and set new list to all unhandled
 | 
					 | 
				
			||||||
	// requests (request for another output).
 | 
					 | 
				
			||||||
	list_free(ipc_get_pixel_requests);
 | 
					 | 
				
			||||||
	ipc_get_pixel_requests = unhandled;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool is_text_target(const char *target) {
 | 
					 | 
				
			||||||
	return (strncmp(target, "text/", 5) == 0
 | 
					 | 
				
			||||||
		|| strcmp(target, "UTF8_STRING") == 0
 | 
					 | 
				
			||||||
		|| strcmp(target, "STRING") == 0
 | 
					 | 
				
			||||||
		|| strcmp(target, "TEXT") == 0
 | 
					 | 
				
			||||||
		|| strcmp(target, "COMPOUND_TEXT") == 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void release_clipboard_request(struct get_clipboard_request *req) {
 | 
					 | 
				
			||||||
	if (--(*req->pending) == 0) {
 | 
					 | 
				
			||||||
		const char *str = json_object_to_json_string(req->json);
 | 
					 | 
				
			||||||
		ipc_send_reply(req->client, str, (uint32_t)strlen(str));
 | 
					 | 
				
			||||||
		json_object_put(req->json);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(req->type);
 | 
					 | 
				
			||||||
	free(req->buf);
 | 
					 | 
				
			||||||
	wlc_event_source_remove(req->fd_event_source);
 | 
					 | 
				
			||||||
	wlc_event_source_remove(req->timer_event_source);
 | 
					 | 
				
			||||||
	close(req->fd);
 | 
					 | 
				
			||||||
	free(req);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
 | 
					 | 
				
			||||||
	assert(data);
 | 
					 | 
				
			||||||
	struct get_clipboard_request *req = (struct get_clipboard_request *)data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mask & WLC_EVENT_ERROR) {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "Selection data fd error");
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mask & WLC_EVENT_READABLE) {
 | 
					 | 
				
			||||||
		static const unsigned int max_size = 8192 * 1024;
 | 
					 | 
				
			||||||
		int amt = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			int size = req->buf_size - req->buf_position;
 | 
					 | 
				
			||||||
			int amt = read(fd, req->buf + req->buf_position, size - 1);
 | 
					 | 
				
			||||||
			if (amt < 0) {
 | 
					 | 
				
			||||||
				if (errno == EAGAIN) {
 | 
					 | 
				
			||||||
					return 0;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				sway_log_errno(L_INFO, "Failed to read from clipboard data fd");
 | 
					 | 
				
			||||||
				goto release;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			req->buf_position += amt;
 | 
					 | 
				
			||||||
			if (req->buf_position >= req->buf_size - 1) {
 | 
					 | 
				
			||||||
				if (req->buf_size >= max_size) {
 | 
					 | 
				
			||||||
					sway_log(L_ERROR, "get_clipbard: selection data too large");
 | 
					 | 
				
			||||||
					goto error;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				char *next = realloc(req->buf, req->buf_size *= 2);
 | 
					 | 
				
			||||||
				if (!next) {
 | 
					 | 
				
			||||||
					sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed");
 | 
					 | 
				
			||||||
					goto error;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				req->buf = next;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} while(amt != 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		req->buf[req->buf_position] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		json_object *obj = json_object_new_object();
 | 
					 | 
				
			||||||
		json_object_object_add(obj, "success", json_object_new_boolean(true));
 | 
					 | 
				
			||||||
		if (is_text_target(req->type)) {
 | 
					 | 
				
			||||||
			json_object_object_add(obj, "content", json_object_new_string(req->buf));
 | 
					 | 
				
			||||||
			json_object_object_add(req->json, req->type, obj);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			size_t outlen;
 | 
					 | 
				
			||||||
			char *b64 = b64_encode(req->buf, req->buf_position, &outlen);
 | 
					 | 
				
			||||||
			json_object_object_add(obj, "content", json_object_new_string(b64));
 | 
					 | 
				
			||||||
			free(b64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			char *type = malloc(strlen(req->type) + 8);
 | 
					 | 
				
			||||||
			strcat(type, ";base64");
 | 
					 | 
				
			||||||
			json_object_object_add(req->json, type, obj);
 | 
					 | 
				
			||||||
			free(type);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	goto release;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:;
 | 
					 | 
				
			||||||
	json_object *obj = json_object_new_object();
 | 
					 | 
				
			||||||
	json_object_object_add(obj, "success", json_object_new_boolean(false));
 | 
					 | 
				
			||||||
	json_object_object_add(obj, "error",
 | 
					 | 
				
			||||||
		json_object_new_string("Failed to retrieve data"));
 | 
					 | 
				
			||||||
	json_object_object_add(req->json, req->type, obj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
release:
 | 
					 | 
				
			||||||
	release_clipboard_request(req);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ipc_selection_timer_cb(void *data) {
 | 
					 | 
				
			||||||
	assert(data);
 | 
					 | 
				
			||||||
	struct get_clipboard_request *req = (struct get_clipboard_request *)data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type);
 | 
					 | 
				
			||||||
	json_object *obj = json_object_new_object();
 | 
					 | 
				
			||||||
	json_object_object_add(obj, "success", json_object_new_boolean(false));
 | 
					 | 
				
			||||||
	json_object_object_add(obj, "error", json_object_new_string("Timeout"));
 | 
					 | 
				
			||||||
	json_object_object_add(req->json, req->type, obj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	release_clipboard_request(req);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// greedy wildcard (only "*") matching
 | 
					// greedy wildcard (only "*") matching
 | 
				
			||||||
bool mime_type_matches(const char *mime_type, const char *pattern) {
 | 
					bool mime_type_matches(const char *mime_type, const char *pattern) {
 | 
				
			||||||
	const char *wildcard = NULL;
 | 
						const char *wildcard = NULL;
 | 
				
			||||||
| 
						 | 
					@ -553,125 +377,6 @@ bool mime_type_matches(const char *mime_type, const char *pattern) {
 | 
				
			||||||
	return (*mime_type == *pattern);
 | 
						return (*mime_type == *pattern);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ipc_get_clipboard(struct ipc_client *client, char *buf) {
 | 
					 | 
				
			||||||
	size_t size;
 | 
					 | 
				
			||||||
	const char **types = wlc_get_selection_types(&size);
 | 
					 | 
				
			||||||
	if (client->payload_length == 0) {
 | 
					 | 
				
			||||||
		json_object *obj = json_object_new_array();
 | 
					 | 
				
			||||||
		for (size_t i = 0; i < size; ++i) {
 | 
					 | 
				
			||||||
			json_object_array_add(obj, json_object_new_string(types[i]));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const char *str = json_object_to_json_string(obj);
 | 
					 | 
				
			||||||
		ipc_send_reply(client, str, strlen(str));
 | 
					 | 
				
			||||||
		json_object_put(obj);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unescape_string(buf);
 | 
					 | 
				
			||||||
	strip_quotes(buf);
 | 
					 | 
				
			||||||
	list_t *requested = split_string(buf, " ");
 | 
					 | 
				
			||||||
	json_object *json = json_object_new_object();
 | 
					 | 
				
			||||||
	unsigned int *pending = malloc(sizeof(unsigned int));
 | 
					 | 
				
			||||||
	*pending = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t l = 0; l < (size_t) requested->length; ++l) {
 | 
					 | 
				
			||||||
		const char *pattern = requested->items[l];
 | 
					 | 
				
			||||||
		bool found = false;
 | 
					 | 
				
			||||||
		for (size_t i = 0; i < size; ++i) {
 | 
					 | 
				
			||||||
			if (!mime_type_matches(types[i], pattern)) {
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			found = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			struct get_clipboard_request *req = malloc(sizeof(*req));
 | 
					 | 
				
			||||||
			if (!req) {
 | 
					 | 
				
			||||||
				sway_log(L_ERROR, "get_clipboard: request malloc failed");
 | 
					 | 
				
			||||||
				goto data_error;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			int pipes[2];
 | 
					 | 
				
			||||||
			if (pipe(pipes) == -1) {
 | 
					 | 
				
			||||||
				sway_log_errno(L_ERROR, "get_clipboard: pipe call failed");
 | 
					 | 
				
			||||||
				free(req);
 | 
					 | 
				
			||||||
				goto data_error;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
 | 
					 | 
				
			||||||
			fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!wlc_get_selection_data(types[i], pipes[1])) {
 | 
					 | 
				
			||||||
				close(pipes[0]);
 | 
					 | 
				
			||||||
				close(pipes[1]);
 | 
					 | 
				
			||||||
				free(req);
 | 
					 | 
				
			||||||
				sway_log(L_ERROR, "get_clipboard: failed to retrieve "
 | 
					 | 
				
			||||||
					"selection data");
 | 
					 | 
				
			||||||
				goto data_error;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!(req->buf = malloc(512))) {
 | 
					 | 
				
			||||||
				close(pipes[0]);
 | 
					 | 
				
			||||||
				close(pipes[1]);
 | 
					 | 
				
			||||||
				free(req);
 | 
					 | 
				
			||||||
				sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed");
 | 
					 | 
				
			||||||
				goto data_error;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			(*pending)++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			req->client = client;
 | 
					 | 
				
			||||||
			req->type = strdup(types[i]);
 | 
					 | 
				
			||||||
			req->json = json;
 | 
					 | 
				
			||||||
			req->pending = pending;
 | 
					 | 
				
			||||||
			req->buf_position = 0;
 | 
					 | 
				
			||||||
			req->buf_size = 512;
 | 
					 | 
				
			||||||
			req->fd = pipes[0];
 | 
					 | 
				
			||||||
			req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req);
 | 
					 | 
				
			||||||
			req->fd_event_source = wlc_event_loop_add_fd(pipes[0],
 | 
					 | 
				
			||||||
				WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
 | 
					 | 
				
			||||||
				&ipc_selection_data_cb, req);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			wlc_event_source_timer_update(req->timer_event_source, 30000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// NOTE: remove this goto to enable retrieving multiple
 | 
					 | 
				
			||||||
			// targets at once. The whole implementation is already
 | 
					 | 
				
			||||||
			// made for it. The only reason it was disabled
 | 
					 | 
				
			||||||
			// at the time of writing is that neither wlc's xselection
 | 
					 | 
				
			||||||
			// implementation nor (apparently) gtk on wayland supports
 | 
					 | 
				
			||||||
			// multiple send requests at the same time which makes
 | 
					 | 
				
			||||||
			// every request except the last one fail (and therefore
 | 
					 | 
				
			||||||
			// return empty data)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!found) {
 | 
					 | 
				
			||||||
			sway_log(L_INFO, "Invalid clipboard type %s requested", pattern);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (*pending == 0) {
 | 
					 | 
				
			||||||
		static const char *error_empty = "{ \"success\": false, \"error\": "
 | 
					 | 
				
			||||||
			"\"No matching types found\" }";
 | 
					 | 
				
			||||||
		ipc_send_reply(client, error_empty, (uint32_t)strlen(error_empty));
 | 
					 | 
				
			||||||
		free(json);
 | 
					 | 
				
			||||||
		free(pending);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	goto cleanup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
data_error:;
 | 
					 | 
				
			||||||
	static const char *error_json = "{ \"success\": false, \"error\": "
 | 
					 | 
				
			||||||
		"\"Failed to create clipboard data request\" }";
 | 
					 | 
				
			||||||
	ipc_send_reply(client, error_json, (uint32_t)strlen(error_json));
 | 
					 | 
				
			||||||
	free(json);
 | 
					 | 
				
			||||||
	free(pending);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cleanup:
 | 
					 | 
				
			||||||
	list_free(requested);
 | 
					 | 
				
			||||||
	free(types);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ipc_client_handle_command(struct ipc_client *client) {
 | 
					void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
	if (!sway_assert(client != NULL, "client != NULL")) {
 | 
						if (!sway_assert(client != NULL, "client != NULL")) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -830,52 +535,6 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
		goto exit_cleanup;
 | 
							goto exit_cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPC_SWAY_GET_PIXELS:
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		char response_header[9];
 | 
					 | 
				
			||||||
		memset(response_header, 0, sizeof(response_header));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		json_object *obj = json_tokener_parse(buf);
 | 
					 | 
				
			||||||
		json_object *o, *x, *y, *w, *h;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		json_object_object_get_ex(obj, "output", &o);
 | 
					 | 
				
			||||||
		json_object_object_get_ex(obj, "x", &x);
 | 
					 | 
				
			||||||
		json_object_object_get_ex(obj, "y", &y);
 | 
					 | 
				
			||||||
		json_object_object_get_ex(obj, "w", &w);
 | 
					 | 
				
			||||||
		json_object_object_get_ex(obj, "h", &h);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct wlc_geometry g = {
 | 
					 | 
				
			||||||
			.origin = {
 | 
					 | 
				
			||||||
				.x = json_object_get_int(x),
 | 
					 | 
				
			||||||
				.y = json_object_get_int(y)
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			.size = {
 | 
					 | 
				
			||||||
				.w = json_object_get_int(w),
 | 
					 | 
				
			||||||
				.h = json_object_get_int(h)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		swayc_t *output = swayc_by_test(&root_container, output_by_name_test, (void *)json_object_get_string(o));
 | 
					 | 
				
			||||||
		json_object_put(obj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!output) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name");
 | 
					 | 
				
			||||||
			ipc_send_reply(client, response_header, sizeof(response_header));
 | 
					 | 
				
			||||||
			goto exit_cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request));
 | 
					 | 
				
			||||||
		if (!req) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "Unable to allocate get_pixels request");
 | 
					 | 
				
			||||||
			goto exit_cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		req->client = client;
 | 
					 | 
				
			||||||
		req->output = output->handle;
 | 
					 | 
				
			||||||
		req->geo = g;
 | 
					 | 
				
			||||||
		list_add(ipc_get_pixel_requests, req);
 | 
					 | 
				
			||||||
		wlc_output_schedule_render(output->handle);
 | 
					 | 
				
			||||||
		goto exit_cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case IPC_GET_BAR_CONFIG:
 | 
						case IPC_GET_BAR_CONFIG:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
 | 
							if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
 | 
				
			||||||
| 
						 | 
					@ -917,14 +576,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPC_GET_CLIPBOARD:
 | 
						case IPC_GET_CLIPBOARD:
 | 
				
			||||||
	{
 | 
							// TODO WLR
 | 
				
			||||||
		if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) {
 | 
							break;
 | 
				
			||||||
			goto exit_denied;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ipc_get_clipboard(client, buf);
 | 
					 | 
				
			||||||
		goto exit_cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
 | 
							sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
 | 
				
			||||||
| 
						 | 
					@ -977,7 +630,9 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
 | 
				
			||||||
	client->write_buffer_len += payload_length;
 | 
						client->write_buffer_len += payload_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!client->writable_event_source) {
 | 
						if (!client->writable_event_source) {
 | 
				
			||||||
		client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client);
 | 
							client->writable_event_source = wl_event_loop_add_fd(
 | 
				
			||||||
 | 
									server.wl_event_loop, client->fd, WL_EVENT_WRITABLE,
 | 
				
			||||||
 | 
									ipc_client_handle_writable, client);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
 | 
						sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
#include <wlc/wlc.h>
 | 
					#include <wlc/wlc.h>
 | 
				
			||||||
#include "sway/extensions.h"
 | 
					 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/container.h"
 | 
					#include "sway/container.h"
 | 
				
			||||||
#include "sway/workspace.h"
 | 
					#include "sway/workspace.h"
 | 
				
			||||||
| 
						 | 
					@ -1001,6 +1000,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
 | 
								swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
 | 
				
			||||||
			width = output->width, height = output->height;
 | 
								width = output->width, height = output->height;
 | 
				
			||||||
 | 
								/* TODO WLR
 | 
				
			||||||
			for (i = 0; i < desktop_shell.panels->length; ++i) {
 | 
								for (i = 0; i < desktop_shell.panels->length; ++i) {
 | 
				
			||||||
				struct panel_config *config = desktop_shell.panels->items[i];
 | 
									struct panel_config *config = desktop_shell.panels->items[i];
 | 
				
			||||||
				if (config->output == output->handle) {
 | 
									if (config->output == output->handle) {
 | 
				
			||||||
| 
						 | 
					@ -1022,6 +1022,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								*/
 | 
				
			||||||
			int gap = swayc_gap(container);
 | 
								int gap = swayc_gap(container);
 | 
				
			||||||
			x = container->x = x + gap;
 | 
								x = container->x = x + gap;
 | 
				
			||||||
			y = container->y = y + gap;
 | 
								y = container->y = y + gap;
 | 
				
			||||||
| 
						 | 
					@ -1380,11 +1381,13 @@ void arrange_windows(swayc_t *container, double width, double height) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arrange_backgrounds(void) {
 | 
					void arrange_backgrounds(void) {
 | 
				
			||||||
 | 
						/* TODO WLR
 | 
				
			||||||
	struct background_config *bg;
 | 
						struct background_config *bg;
 | 
				
			||||||
	for (int i = 0; i < desktop_shell.backgrounds->length; ++i) {
 | 
						for (int i = 0; i < desktop_shell.backgrounds->length; ++i) {
 | 
				
			||||||
		bg = desktop_shell.backgrounds->items[i];
 | 
							bg = desktop_shell.backgrounds->items[i];
 | 
				
			||||||
		wlc_view_send_to_back(bg->handle);
 | 
							wlc_view_send_to_back(bg->handle);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										113
									
								
								sway/main.c
									
										
									
									
									
								
							
							
						
						
									
										113
									
								
								sway/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -3,7 +3,6 @@
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <wlc/wlc.h>
 | 
					 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
| 
						 | 
					@ -15,13 +14,13 @@
 | 
				
			||||||
#include <sys/capability.h>
 | 
					#include <sys/capability.h>
 | 
				
			||||||
#include <sys/prctl.h>
 | 
					#include <sys/prctl.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include "sway/extensions.h"
 | 
					 | 
				
			||||||
#include "sway/layout.h"
 | 
					#include "sway/layout.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/security.h"
 | 
					#include "sway/security.h"
 | 
				
			||||||
#include "sway/handlers.h"
 | 
					#include "sway/handlers.h"
 | 
				
			||||||
#include "sway/input.h"
 | 
					#include "sway/input.h"
 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "ipc-client.h"
 | 
					#include "ipc-client.h"
 | 
				
			||||||
#include "readline.h"
 | 
					#include "readline.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
| 
						 | 
					@ -31,11 +30,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool terminate_request = false;
 | 
					static bool terminate_request = false;
 | 
				
			||||||
static int exit_value = 0;
 | 
					static int exit_value = 0;
 | 
				
			||||||
 | 
					struct sway_server server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sway_terminate(int exit_code) {
 | 
					void sway_terminate(int exit_code) {
 | 
				
			||||||
	terminate_request = true;
 | 
						terminate_request = true;
 | 
				
			||||||
	exit_value = exit_code;
 | 
						exit_value = exit_code;
 | 
				
			||||||
	wlc_terminate();
 | 
						wl_display_terminate(server.wl_display);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sig_handler(int signal) {
 | 
					void sig_handler(int signal) {
 | 
				
			||||||
| 
						 | 
					@ -43,16 +43,6 @@ void sig_handler(int signal) {
 | 
				
			||||||
	sway_terminate(EXIT_SUCCESS);
 | 
						sway_terminate(EXIT_SUCCESS);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlc_log_handler(enum wlc_log_type type, const char *str) {
 | 
					 | 
				
			||||||
	if (type == WLC_LOG_ERROR) {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "[wlc] %s", str);
 | 
					 | 
				
			||||||
	} else if (type == WLC_LOG_WARN) {
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "[wlc] %s", str);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sway_log(L_DEBUG, "[wlc] %s", str);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void detect_raspi() {
 | 
					void detect_raspi() {
 | 
				
			||||||
	bool raspi = false;
 | 
						bool raspi = false;
 | 
				
			||||||
	FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
 | 
						FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
 | 
				
			||||||
| 
						 | 
					@ -189,19 +179,7 @@ static void log_env() {
 | 
				
			||||||
		"LD_LIBRARY_PATH",
 | 
							"LD_LIBRARY_PATH",
 | 
				
			||||||
		"SWAY_CURSOR_THEME",
 | 
							"SWAY_CURSOR_THEME",
 | 
				
			||||||
		"SWAY_CURSOR_SIZE",
 | 
							"SWAY_CURSOR_SIZE",
 | 
				
			||||||
		"SWAYSOCK",
 | 
							"SWAYSOCK"
 | 
				
			||||||
		"WLC_DRM_DEVICE",
 | 
					 | 
				
			||||||
		"WLC_SHM",
 | 
					 | 
				
			||||||
		"WLC_OUTPUTS",
 | 
					 | 
				
			||||||
		"WLC_XWAYLAND",
 | 
					 | 
				
			||||||
		"WLC_LIBINPUT",
 | 
					 | 
				
			||||||
		"WLC_REPEAT_DELAY",
 | 
					 | 
				
			||||||
		"WLC_REPEAT_RATE",
 | 
					 | 
				
			||||||
		"XKB_DEFAULT_RULES",
 | 
					 | 
				
			||||||
		"XKB_DEFAULT_MODEL",
 | 
					 | 
				
			||||||
		"XKB_DEFAULT_LAYOUT",
 | 
					 | 
				
			||||||
		"XKB_DEFAULT_VARIANT",
 | 
					 | 
				
			||||||
		"XKB_DEFAULT_OPTIONS",
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
 | 
						for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
 | 
				
			||||||
		sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
 | 
							sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
 | 
				
			||||||
| 
						 | 
					@ -295,6 +273,37 @@ static void executable_sanity_check() {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void drop_permissions(bool keep_caps) {
 | 
				
			||||||
 | 
						if (getuid() != geteuid() || getgid() != getegid()) {
 | 
				
			||||||
 | 
							if (setgid(getgid()) != 0) {
 | 
				
			||||||
 | 
								sway_log(L_ERROR, "Unable to drop root");
 | 
				
			||||||
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (setuid(getuid()) != 0) {
 | 
				
			||||||
 | 
								sway_log(L_ERROR, "Unable to drop root");
 | 
				
			||||||
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (setuid(0) != -1) {
 | 
				
			||||||
 | 
							sway_log(L_ERROR, "Root privileges can be restored.");
 | 
				
			||||||
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
						if (keep_caps) {
 | 
				
			||||||
 | 
							// Drop every cap except CAP_SYS_PTRACE
 | 
				
			||||||
 | 
							cap_t caps = cap_init();
 | 
				
			||||||
 | 
							cap_value_t keep = CAP_SYS_PTRACE;
 | 
				
			||||||
 | 
							sway_log(L_INFO, "Dropping extra capabilities");
 | 
				
			||||||
 | 
							if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
 | 
				
			||||||
 | 
								cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
 | 
				
			||||||
 | 
								cap_set_proc(caps)) {
 | 
				
			||||||
 | 
								sway_log(L_ERROR, "Failed to drop extra capabilities");
 | 
				
			||||||
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
	static int verbose = 0, debug = 0, validate = 0;
 | 
						static int verbose = 0, debug = 0, validate = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -374,7 +383,7 @@ int main(int argc, char **argv) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// we need to setup logging before wlc_init in case it fails.
 | 
						// TODO: switch logging over to wlroots?
 | 
				
			||||||
	if (debug) {
 | 
						if (debug) {
 | 
				
			||||||
		init_log(L_DEBUG);
 | 
							init_log(L_DEBUG);
 | 
				
			||||||
	} else if (verbose || validate) {
 | 
						} else if (verbose || validate) {
 | 
				
			||||||
| 
						 | 
					@ -388,20 +397,7 @@ int main(int argc, char **argv) {
 | 
				
			||||||
			sway_log(L_ERROR, "Don't use options with the IPC client");
 | 
								sway_log(L_ERROR, "Don't use options with the IPC client");
 | 
				
			||||||
			exit(EXIT_FAILURE);
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (getuid() != geteuid() || getgid() != getegid()) {
 | 
							drop_permissions(false);
 | 
				
			||||||
			if (setgid(getgid()) != 0) {
 | 
					 | 
				
			||||||
				sway_log(L_ERROR, "Unable to drop root");
 | 
					 | 
				
			||||||
				exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (setuid(getuid()) != 0) {
 | 
					 | 
				
			||||||
				sway_log(L_ERROR, "Unable to drop root");
 | 
					 | 
				
			||||||
				exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (setuid(0) != -1) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "Root privileges can be restored.");
 | 
					 | 
				
			||||||
			exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		char *socket_path = getenv("SWAYSOCK");
 | 
							char *socket_path = getenv("SWAYSOCK");
 | 
				
			||||||
		if (!socket_path) {
 | 
							if (!socket_path) {
 | 
				
			||||||
			sway_log(L_ERROR, "Unable to retrieve socket path");
 | 
								sway_log(L_ERROR, "Unable to retrieve socket path");
 | 
				
			||||||
| 
						 | 
					@ -413,8 +409,8 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	executable_sanity_check();
 | 
						executable_sanity_check();
 | 
				
			||||||
#ifdef __linux__
 | 
					 | 
				
			||||||
	bool suid = false;
 | 
						bool suid = false;
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
	if (getuid() != geteuid() || getgid() != getegid()) {
 | 
						if (getuid() != geteuid() || getgid() != getegid()) {
 | 
				
			||||||
		// Retain capabilities after setuid()
 | 
							// Retain capabilities after setuid()
 | 
				
			||||||
		if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
 | 
							if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
 | 
				
			||||||
| 
						 | 
					@ -425,37 +421,14 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlc_log_set_handler(wlc_log_handler);
 | 
					 | 
				
			||||||
	log_kernel();
 | 
						log_kernel();
 | 
				
			||||||
	log_distro();
 | 
						log_distro();
 | 
				
			||||||
	log_env();
 | 
						log_env();
 | 
				
			||||||
	detect_proprietary();
 | 
						detect_proprietary();
 | 
				
			||||||
	detect_raspi();
 | 
						detect_raspi();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_devices = create_list();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Changing code earlier than this point requires detailed review */
 | 
					 | 
				
			||||||
	/* (That code runs as root on systems without logind, and wlc_init drops to
 | 
					 | 
				
			||||||
	 * another user.) */
 | 
					 | 
				
			||||||
	register_wlc_handlers();
 | 
					 | 
				
			||||||
	if (!wlc_init()) {
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	register_extensions();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
	if (suid) {
 | 
						drop_permissions(suid);
 | 
				
			||||||
		// Drop every cap except CAP_SYS_PTRACE
 | 
					 | 
				
			||||||
		cap_t caps = cap_init();
 | 
					 | 
				
			||||||
		cap_value_t keep = CAP_SYS_PTRACE;
 | 
					 | 
				
			||||||
		sway_log(L_INFO, "Dropping extra capabilities");
 | 
					 | 
				
			||||||
		if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
 | 
					 | 
				
			||||||
			cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
 | 
					 | 
				
			||||||
			cap_set_proc(caps)) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "Failed to drop extra capabilities");
 | 
					 | 
				
			||||||
			exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	// handle SIGTERM signals
 | 
						// handle SIGTERM signals
 | 
				
			||||||
	signal(SIGTERM, sig_handler);
 | 
						signal(SIGTERM, sig_handler);
 | 
				
			||||||
| 
						 | 
					@ -465,8 +438,10 @@ int main(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n");
 | 
						sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!server_init(&server)) {
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	init_layout();
 | 
						init_layout();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ipc_init();
 | 
						ipc_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (validate) {
 | 
						if (validate) {
 | 
				
			||||||
| 
						 | 
					@ -485,10 +460,10 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	security_sanity_check();
 | 
						security_sanity_check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!terminate_request) {
 | 
						if (!terminate_request) {
 | 
				
			||||||
		wlc_run();
 | 
							wl_display_run(server.wl_display);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_free(input_devices);
 | 
						server_fini(&server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipc_terminate();
 | 
						ipc_terminate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										54
									
								
								sway/server.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sway/server.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					#define _POSIX_C_SOURCE 200112L
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_data_device_manager.h>
 | 
				
			||||||
 | 
					#include <wlr/render.h>
 | 
				
			||||||
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
 | 
					// TODO WLR: make Xwayland optional
 | 
				
			||||||
 | 
					#include <wlr/xwayland.h>
 | 
				
			||||||
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool server_init(struct sway_server *server) {
 | 
				
			||||||
 | 
						sway_log(L_DEBUG, "Initializing Wayland server");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						server->wl_display = wl_display_create();
 | 
				
			||||||
 | 
						server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
 | 
				
			||||||
 | 
						server->backend = wlr_backend_autocreate(server->wl_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						server->renderer = wlr_gles2_renderer_create(server->backend);
 | 
				
			||||||
 | 
						wl_display_init_shm(server->wl_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO WLR
 | 
				
			||||||
 | 
						//server->desktop = desktop_create(server, server.config);
 | 
				
			||||||
 | 
						//server->input = input_create(&server, server.config);
 | 
				
			||||||
 | 
						server->data_device_manager =
 | 
				
			||||||
 | 
							wlr_data_device_manager_create(server->wl_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *socket = wl_display_add_socket_auto(server->wl_display);
 | 
				
			||||||
 | 
						if (!socket) {
 | 
				
			||||||
 | 
							sway_log_errno(L_ERROR, "Unable to open wayland socket");
 | 
				
			||||||
 | 
							wlr_backend_destroy(server->backend);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sway_log(L_INFO, "Running compositor on wayland display '%s'", socket);
 | 
				
			||||||
 | 
						setenv("_WAYLAND_DISPLAY", socket, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wlr_backend_start(server->backend)) {
 | 
				
			||||||
 | 
							sway_log(L_ERROR, "Failed to start backend");
 | 
				
			||||||
 | 
							wlr_backend_destroy(server->backend);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setenv("WAYLAND_DISPLAY", socket, true);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_fini(struct sway_server *server) {
 | 
				
			||||||
 | 
						// TODO WLR: tear down more stuff
 | 
				
			||||||
 | 
						wlr_backend_destroy(server->backend);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,6 @@
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "sway/extensions.h"
 | 
					 | 
				
			||||||
#include "sway/workspace.h"
 | 
					#include "sway/workspace.h"
 | 
				
			||||||
#include "sway/layout.h"
 | 
					#include "sway/layout.h"
 | 
				
			||||||
#include "sway/container.h"
 | 
					#include "sway/container.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue