diff options
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | common/list.c (renamed from sway/list.c) | 0 | ||||
| -rw-r--r-- | common/log.c (renamed from sway/log.c) | 88 | ||||
| -rw-r--r-- | include/client.h | 43 | ||||
| -rw-r--r-- | sway/debug_log.c | 102 | ||||
| -rw-r--r-- | swaybg/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | swaybg/main.c | 23 | ||||
| -rw-r--r-- | wayland/client.c | 192 | 
8 files changed, 370 insertions, 92 deletions
| diff --git a/CMakeLists.txt b/CMakeLists.txt index d446c2b3..b75e8737 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_C_FLAGS "-g")  set(CMAKE_C_STANDARD 99)  SET(CMAKE_C_EXTENSIONS OFF)  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") -add_definitions("-Wall -Wextra -Wno-unused-parameter") +add_definitions("-Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE")  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake)  add_subdirectory(swaybg swaybg) @@ -44,6 +44,7 @@ find_package(PCRE REQUIRED)  find_package(JsonC REQUIRED)  FILE(GLOB sources ${PROJECT_SOURCE_DIR}/sway/*.c) +FILE(GLOB common ${PROJECT_SOURCE_DIR}/common/*.c)  include_directories(     ${WLC_INCLUDE_DIRS} @@ -55,6 +56,7 @@ include_directories(  add_executable(sway      ${sources} +    ${common}  )  target_link_libraries(sway diff --git a/sway/list.c b/common/list.c index 45efc16f..45efc16f 100644 --- a/sway/list.c +++ b/common/list.c diff --git a/sway/log.c b/common/log.c index f2b828f9..02aac4c1 100644 --- a/sway/log.c +++ b/common/log.c @@ -157,91 +157,3 @@ void error_handler(int sig) {  	}  	exit(1);  } - -#include "workspace.h" - -/* XXX:DEBUG:XXX */ -static void container_log(const swayc_t *c) { -	fprintf(stderr, "focus:%c|", -			c == get_focused_view(&root_container) ? 'K': -			c == get_focused_container(&root_container) ? 'F' : // Focused -			c == swayc_active_workspace() ? 'W' : // active workspace -			c == &root_container  ? 'R' : // root -			'X');// not any others -	fprintf(stderr,"(%p)",c); -	fprintf(stderr,"(p:%p)",c->parent); -	fprintf(stderr,"(f:%p)",c->focused); -	fprintf(stderr,"(h:%ld)",c->handle); -	fprintf(stderr,"Type:"); -	fprintf(stderr, -			c->type == C_ROOT   ? "Root|" : -			c->type == C_OUTPUT ? "Output|" : -			c->type == C_WORKSPACE ? "Workspace|" : -			c->type == C_CONTAINER ? "Container|" : -			c->type == C_VIEW   ? "View|" : "Unknown|"); -	fprintf(stderr,"layout:"); -	fprintf(stderr, -			c->layout == L_NONE ? "NONE|" : -			c->layout == L_HORIZ ? "Horiz|": -			c->layout == L_VERT ? "Vert|": -			c->layout == L_STACKED  ? "Stacked|": -			c->layout == L_FLOATING ? "Floating|": -			"Unknown|"); -	fprintf(stderr, "w:%.f|h:%.f|", c->width, c->height); -	fprintf(stderr, "x:%.f|y:%.f|", c->x, c->y); -	fprintf(stderr, "g:%d|",c->gaps); -	fprintf(stderr, "vis:%c|", c->visible?'t':'f'); -	fprintf(stderr, "name:%.16s|", c->name); -	fprintf(stderr, "children:%d\n",c->children?c->children->length:0); -} -void layout_log(const swayc_t *c, int depth) { -	if (L_DEBUG > v) return; -	int i, d; -	int e = c->children ? c->children->length : 0; -	container_log(c); -	if (e) { -		for (i = 0; i < e; ++i) { -			fputc('|',stderr); -			for (d = 0; d < depth; ++d) fputc('-', stderr); -			layout_log(c->children->items[i], depth + 1); -		} -	} -	if (c->type == C_WORKSPACE) { -		e = c->floating?c->floating->length:0; -		if (e) { -			for (i = 0; i < e; ++i) { -				fputc('|',stderr); -				for (d = 0; d < depth; ++d) fputc('=', stderr); -				layout_log(c->floating->items[i], depth + 1); -			} -		} -	} -} - -const char *swayc_type_string(enum swayc_types type) { -	return type == C_ROOT ? "ROOT" : -		type == C_OUTPUT ? "OUTPUT" : -		type == C_WORKSPACE ? "WORKSPACE" : -		type == C_CONTAINER ? "CONTAINER" : -		type == C_VIEW   ? "VIEW" : -		"UNKNOWN"; -} - -// Like sway_log, but also appends some info about given container to log output. -void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) { -	sway_assert(cont, "swayc_log: no container ..."); -	va_list args; -	va_start(args, format); -	char *txt = malloc(128); -	vsprintf(txt, format, args); -	va_end(args); - -	char *debug_txt = malloc(32); -	snprintf(debug_txt, 32, "%s '%s'", swayc_type_string(cont->type), cont->name); - -	sway_log(verbosity, "%s (%s)", txt, debug_txt); -	free(txt); -	free(debug_txt); -} - -/* XXX:DEBUG:XXX */ diff --git a/include/client.h b/include/client.h new file mode 100644 index 00000000..ec3537ca --- /dev/null +++ b/include/client.h @@ -0,0 +1,43 @@ +#ifndef _CLIENT_H +#define _CLIENT_H + +#include <wayland-client.h> +#include <cairo/cairo.h> +#include <pango/pangocairo.h> +#include "list.h" + +struct output_state { +    struct wl_output *output; +    uint32_t flags; +    int width, height; +}; + +struct buffer { +    struct wl_buffer *buffer; +    struct wl_shm_pool *pool; +    uint32_t width, height; +}; + +struct client_state { +    struct wl_compositor *compositor; +    struct wl_display *display; +    struct wl_pointer *pointer; +    struct wl_seat *seat; +    struct wl_shell *shell; +    struct wl_shm *shm; +    struct buffer *buffer; +    struct wl_surface *surface; +    struct wl_shell_surface *shell_surface; +    cairo_t *cairo; +    cairo_surface_t *cairo_surface; +    PangoContext *pango; +    list_t *outputs; +}; + +struct client_state *client_setup(void); +void client_teardown(struct client_state *state); +struct buffer *create_memory_pool(struct client_state *state, int32_t width, int32_t height, uint32_t format); +int client_prerender(struct client_state *state); +int client_render(struct client_state *state); + +#endif diff --git a/sway/debug_log.c b/sway/debug_log.c new file mode 100644 index 00000000..4cb97561 --- /dev/null +++ b/sway/debug_log.c @@ -0,0 +1,102 @@ +#include "log.h" +#include "sway.h" +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <libgen.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <stringop.h> +#include <execinfo.h> +#include "workspace.h" + +extern log_importance_t v; + +/* XXX:DEBUG:XXX */ +static void container_log(const swayc_t *c) { +	fprintf(stderr, "focus:%c|", +			c == get_focused_view(&root_container) ? 'K': +			c == get_focused_container(&root_container) ? 'F' : // Focused +			c == swayc_active_workspace() ? 'W' : // active workspace +			c == &root_container  ? 'R' : // root +			'X');// not any others +	fprintf(stderr,"(%p)",c); +	fprintf(stderr,"(p:%p)",c->parent); +	fprintf(stderr,"(f:%p)",c->focused); +	fprintf(stderr,"(h:%ld)",c->handle); +	fprintf(stderr,"Type:"); +	fprintf(stderr, +			c->type == C_ROOT   ? "Root|" : +			c->type == C_OUTPUT ? "Output|" : +			c->type == C_WORKSPACE ? "Workspace|" : +			c->type == C_CONTAINER ? "Container|" : +			c->type == C_VIEW   ? "View|" : "Unknown|"); +	fprintf(stderr,"layout:"); +	fprintf(stderr, +			c->layout == L_NONE ? "NONE|" : +			c->layout == L_HORIZ ? "Horiz|": +			c->layout == L_VERT ? "Vert|": +			c->layout == L_STACKED  ? "Stacked|": +			c->layout == L_FLOATING ? "Floating|": +			"Unknown|"); +	fprintf(stderr, "w:%.f|h:%.f|", c->width, c->height); +	fprintf(stderr, "x:%.f|y:%.f|", c->x, c->y); +	fprintf(stderr, "g:%d|",c->gaps); +	fprintf(stderr, "vis:%c|", c->visible?'t':'f'); +	fprintf(stderr, "name:%.16s|", c->name); +	fprintf(stderr, "children:%d\n",c->children?c->children->length:0); +} +void layout_log(const swayc_t *c, int depth) { +	if (L_DEBUG > v) return; +	int i, d; +	int e = c->children ? c->children->length : 0; +	container_log(c); +	if (e) { +		for (i = 0; i < e; ++i) { +			fputc('|',stderr); +			for (d = 0; d < depth; ++d) fputc('-', stderr); +			layout_log(c->children->items[i], depth + 1); +		} +	} +	if (c->type == C_WORKSPACE) { +		e = c->floating?c->floating->length:0; +		if (e) { +			for (i = 0; i < e; ++i) { +				fputc('|',stderr); +				for (d = 0; d < depth; ++d) fputc('=', stderr); +				layout_log(c->floating->items[i], depth + 1); +			} +		} +	} +} + +const char *swayc_type_string(enum swayc_types type) { +	return type == C_ROOT ? "ROOT" : +		type == C_OUTPUT ? "OUTPUT" : +		type == C_WORKSPACE ? "WORKSPACE" : +		type == C_CONTAINER ? "CONTAINER" : +		type == C_VIEW   ? "VIEW" : +		"UNKNOWN"; +} + +// Like sway_log, but also appends some info about given container to log output. +void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) { +	sway_assert(cont, "swayc_log: no container ..."); +	va_list args; +	va_start(args, format); +	char *txt = malloc(128); +	vsprintf(txt, format, args); +	va_end(args); + +	char *debug_txt = malloc(32); +	snprintf(debug_txt, 32, "%s '%s'", swayc_type_string(cont->type), cont->name); + +	sway_log(verbosity, "%s (%s)", txt, debug_txt); +	free(txt); +	free(debug_txt); +} + +/* XXX:DEBUG:XXX */ diff --git a/swaybg/CMakeLists.txt b/swaybg/CMakeLists.txt index 89d8afde..9351441a 100644 --- a/swaybg/CMakeLists.txt +++ b/swaybg/CMakeLists.txt @@ -9,14 +9,20 @@ WAYLAND_ADD_PROTOCOL_CLIENT(proto-xdg-shell "xdg-shell.xml" xdg-shell)  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/")  include_directories( -  ${CMAKE_CURRENT_SOURCE_DIR}/include +  ${CMAKE_CURRENT_SOURCE_DIR}/../include    ${WAYLAND_CLIENT_INCLUDE_DIR}    ${CAIRO_INCLUDE_DIRS}    ${PANGO_INCLUDE_DIRS}  ) +FILE(GLOB sources ${PROJECT_SOURCE_DIR}/*.c) +FILE(GLOB wl_sources ${PROJECT_SOURCE_DIR}/../wayland/*.c) +FILE(GLOB common ${PROJECT_SOURCE_DIR}/../common/*.c) +  add_executable(swaybg -	main.c +  ${sources} +  ${wl_sources} +  ${common}  )  TARGET_LINK_LIBRARIES(swaybg ${WAYLAND_CLIENT_LIBRARIES} ${CAIRO_LIBRARIES} ${PANGO_LIBRARIES}) diff --git a/swaybg/main.c b/swaybg/main.c index 4a8ef522..1b4af550 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -1,6 +1,27 @@  #include <stdio.h> +#include <stdlib.h> +#include <wayland-client.h> +#include "client.h" +#include "log.h" + +struct client_state *state; + +void sway_terminate(void) { +	client_teardown(state); +	exit(1); +}  int main(int argc, char **argv) { -	printf("Hello world"); +	init_log(L_INFO); +	state = client_setup(); + +	do { +		if (!client_prerender(state)) continue; +		cairo_set_source_rgb(state->cairo, 255, 0, 0); +		cairo_rectangle(state->cairo, 0, 0, 100, 100); +		cairo_fill(state->cairo); +	} while (client_render(state)); + +	client_teardown(state);  	return 0;  } diff --git a/wayland/client.c b/wayland/client.c new file mode 100644 index 00000000..c62f92bd --- /dev/null +++ b/wayland/client.c @@ -0,0 +1,192 @@ +#include <wayland-client.h> +#include <cairo/cairo.h> +#include <pango/pangocairo.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> +#include "client.h" +#include "list.h" +#include "log.h" + +static void display_handle_mode(void *data, struct wl_output *wl_output, +		     uint32_t flags, int32_t width, int32_t height, int32_t refresh) { +	struct output_state *state = data; +	if (flags & WL_OUTPUT_MODE_CURRENT) { +		state->flags = flags; +		state->width = width; +		state->height = height; +	} +} + +static void display_handle_geometry(void *data, struct wl_output *wl_output, +			 int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, +			 int32_t subpixel, const char *make, const char *model, int32_t transform) { +	// this space intentionally left blank +} + +static void display_handle_done(void *data, struct wl_output *wl_output) { +	// this space intentionally left blank +} + +static void display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { +	// this space intentionally left blank +} + +static const struct wl_output_listener output_listener = { +	.mode = display_handle_mode, +	.geometry = display_handle_geometry, +	.done = display_handle_done, +	.scale = display_handle_scale +}; + +static void registry_global(void *data, struct wl_registry *registry, +		uint32_t name, const char *interface, uint32_t version) { +	struct client_state *state = data; + +	if (strcmp(interface, wl_compositor_interface.name) == 0) { +		state->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version); +	} else if (strcmp(interface, wl_shm_interface.name) == 0) { +		state->shm = wl_registry_bind(registry, name, &wl_shm_interface, version); +	} else if (strcmp(interface, wl_shell_interface.name) == 0) { +		state->shell = wl_registry_bind(registry, name, &wl_shell_interface, version); +	} else if (strcmp(interface, wl_seat_interface.name) == 0) { +		state->seat = wl_registry_bind(registry, name, &wl_seat_interface, version); +		state->pointer = wl_seat_get_pointer(state->seat); +	} else if (strcmp(interface, wl_output_interface.name) == 0) { +		struct wl_output *output = wl_registry_bind(registry, name, &wl_output_interface, version); +		struct output_state *ostate = malloc(sizeof(struct output_state)); +		ostate->output = output; +		wl_output_add_listener(output, &output_listener, ostate); +		list_add(state->outputs, ostate); +	} +} + +static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) { +	// this space intentionally left blank +} + +static const struct wl_registry_listener registry_listener = { +	.global = registry_global, +	.global_remove = registry_global_remove +}; + +static int create_pool_file(size_t size) { +    static const char template[] = "/swaybg-XXXXXX"; +    const char *path = getenv("XDG_RUNTIME_DIR"); +	if (!path) { +        return -1; +    } + +    int ts = (path[strlen(path) - 1] == '/'); + +    char *name = malloc( +		strlen(template) + +		strlen(path) + +		(ts ? 1 : 0) + 1); +	sprintf(name, "%s%s%s", path, ts ? "" : "/", template); + +    int fd = mkstemp(name); +    free(name); + +    if (fd < 0) { +        return -1; +	} + +    if (ftruncate(fd, size) < 0) { +        close(fd); +        return -1; +    } + +    return fd; +} + +struct buffer *create_buffer(struct client_state *state, +		int32_t width, int32_t height, uint32_t format) { + +	struct buffer *buf = malloc(sizeof(struct buffer)); +	memset(buf, 0, sizeof(struct buffer)); +	uint32_t stride = width * 4; +	uint32_t size = stride * height; + +	int fd = create_pool_file(size); +	void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +	buf->pool = wl_shm_create_pool(state->shm, fd, size); +	buf->buffer = wl_shm_pool_create_buffer(buf->pool, 0, width, height, stride, format); + +	state->cairo_surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, stride); +	state->cairo = cairo_create(state->cairo_surface); +	state->pango = pango_cairo_create_context(state->cairo); + +	sway_log(L_INFO, "%p %p", buf->pool, buf->buffer); +	return buf; +} + +struct client_state *client_setup(void) { +	struct client_state *state = malloc(sizeof(struct client_state)); +	memset(state, 0, sizeof(struct client_state)); +	state->outputs = create_list(); + +	state->display = wl_display_connect(NULL); +	if (!state->display) { +		sway_log(L_ERROR, "Error opening display"); +		client_teardown(state); +		return NULL; +	} + +	struct wl_registry *registry = wl_display_get_registry(state->display); +	wl_registry_add_listener(registry, ®istry_listener, state); +	wl_display_roundtrip(state->display); // globals +	wl_display_roundtrip(state->display); // listeners +	wl_registry_destroy(registry); + +	state->buffer = create_buffer(state, 100, 100, WL_SHM_FORMAT_ARGB8888); +	state->surface = wl_compositor_create_surface(state->compositor); +	state->shell_surface = wl_shell_get_shell_surface(state->shell, state->surface); +	wl_shell_surface_set_toplevel(state->shell_surface); + +	wl_surface_damage(state->surface, 0, 0, 100, 100); +	wl_surface_attach(state->surface, state->buffer->buffer, 0, 0); +	wl_surface_commit(state->surface); + +	return state; +} + +int client_prerender(struct client_state *state) { +	wl_display_dispatch_pending(state->display); +    if (wl_display_flush(state->display) < 0 && errno != EAGAIN) { +        return 0; +    } +	return 1; +} + +int client_render(struct client_state *state) { +	return wl_display_dispatch(state->display) != -1; +} + +void client_teardown(struct client_state *state) { +	if (state->pointer) { +		wl_pointer_destroy(state->pointer); +	} +	if (state->seat) { +		wl_seat_destroy(state->seat); +	} +	if (state->shell) { +		wl_shell_destroy(state->shell); +	} +	if (state->shm) { +		wl_shm_destroy(state->shm); +	} +	if (state->compositor) { +		wl_compositor_destroy(state->compositor); +	} +	if (state->display) { +		wl_display_disconnect(state->display); +	} +	if (state->outputs) { +		// TODO: Free the outputs themselves +		list_free(state->outputs); +	} +} | 
