void ipc_init(void) { ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (ipc_socket == -1) { sway_abort("Unable to create IPC socket"); } ipc_sockaddr = ipc_user_sockaddr(); // We want to use socket name set by user, not existing socket from another sway instance. if (getenv("SWAYSOCK") != NULL && access(getenv("SWAYSOCK"), F_OK) == -1) { strncpy(ipc_sockaddr->sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr->sun_path)); ipc_sockaddr->sun_path[sizeof(ipc_sockaddr->sun_path) - 1] = 0; } unlink(ipc_sockaddr->sun_path); if (bind(ipc_socket, (struct sockaddr *)ipc_sockaddr, sizeof(*ipc_sockaddr)) == -1) { sway_abort("Unable to bind IPC socket"); } if (listen(ipc_socket, 3) == -1) { sway_abort("Unable to listen on IPC socket"); } // Set i3 IPC socket path so that i3-msg works out of the box setenv("I3SOCK", ipc_sockaddr->sun_path, 1); setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1); ipc_client_list = 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); }
void ipc_init(void) { ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (ipc_socket == -1) { sway_abort("Unable to create IPC socket"); } ipc_sockaddr = ipc_user_sockaddr(); if (getenv("SWAYSOCK") != NULL) { strncpy(ipc_sockaddr->sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr->sun_path)); } unlink(ipc_sockaddr->sun_path); if (bind(ipc_socket, (struct sockaddr *)ipc_sockaddr, sizeof(*ipc_sockaddr)) == -1) { sway_abort("Unable to bind IPC socket"); } if (listen(ipc_socket, 3) == -1) { sway_abort("Unable to listen on IPC socket"); } // Set i3 IPC socket path so that i3-msg works out of the box setenv("I3SOCK", ipc_sockaddr->sun_path, 1); ipc_client_list = create_list(); ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); }
void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id, int desired_output) { /* initialize bar with default values */ bar_init(bar); bar->output->registry = registry_poll(); if (!bar->output->registry->desktop_shell) { sway_abort("swaybar requires the compositor to support the desktop-shell extension."); } /* connect to sway ipc */ bar->ipc_socketfd = ipc_open_socket(socket_path); bar->ipc_event_socketfd = ipc_open_socket(socket_path); ipc_bar_init(bar, desired_output, bar_id); struct output_state *output = bar->output->registry->outputs->items[desired_output]; bar->output->window = window_setup(bar->output->registry, output->width, 30, false); if (!bar->output->window) { sway_abort("Failed to create window."); } desktop_shell_set_panel(bar->output->registry->desktop_shell, output->output, bar->output->window->surface); desktop_shell_set_panel_position(bar->output->registry->desktop_shell, bar->config->position); /* set font */ bar->output->window->font = bar->config->font; /* set window height */ set_window_height(bar->output->window, bar->config->height); /* spawn status command */ spawn_status_cmd_proc(bar); }
int main(int argc, char **argv) { init_log(L_INFO); surfaces = create_list(); registry = registry_poll(); if (argc < 4) { sway_abort("Do not run this program manually. See man 5 sway and look for output options."); } if (!registry->desktop_shell) { sway_abort("swaybg requires the compositor to support the desktop-shell extension."); } int desired_output = atoi(argv[1]); sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length); int i; struct output_state *output = registry->outputs->items[desired_output]; struct window *window = window_setup(registry, 100, 100, false); if (!window) { sway_abort("Failed to create surfaces."); } window->width = output->width; window->height = output->height; desktop_shell_set_background(registry->desktop_shell, output->output, window->surface); list_add(surfaces, window); char *scaling_mode = argv[3]; cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]); double width = cairo_image_surface_get_width(image); double height = cairo_image_surface_get_height(image); for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; if (window_prerender(window) && window->cairo) { cairo_scale(window->cairo, window->width / width, window->height / height); cairo_set_source_surface(window->cairo, image, 0, 0); cairo_paint(window->cairo); window_render(window); } } while (wl_display_dispatch(registry->display) != -1); for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; window_teardown(window); } list_free(surfaces); registry_teardown(registry); return 0; }
void grab_and_apply_magick(const char *file, const char *output, int socketfd, int raw) { uint32_t len = strlen(output); char *pixels = ipc_single_command(socketfd, IPC_SWAY_GET_PIXELS, output, &len); uint32_t *u32pixels = (uint32_t *)(pixels + 1); uint32_t width = u32pixels[0]; uint32_t height = u32pixels[1]; len -= 9; pixels += 9; if (width == 0 || height == 0) { sway_abort("Unknown output %s.", output); } if (raw) { fwrite(pixels, 1, len, stdout); fflush(stdout); free(pixels - 9); return; } const char *fmt = "convert -depth 8 -size %dx%d+0 rgba:- -flip %s"; char *cmd = malloc(strlen(fmt) - 6 /*args*/ + numlen(width) + numlen(height) + strlen(file) + 1); sprintf(cmd, fmt, width, height, file); FILE *f = popen(cmd, "w"); fwrite(pixels, 1, len, f); fflush(f); fclose(f); free(pixels - 9); free(cmd); }
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { // Keyboard errors are abort-worthy because you wouldn't be able to unlock your screen otherwise. struct registry *registry = data; if (!data) { close(fd); return; } if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); sway_abort("Unknown keymap format %d, aborting", format); } char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) { close(fd); sway_abort("Unable to initialized shared keyboard memory, aborting"); } struct xkb_keymap *keymap = xkb_keymap_new_from_string(registry->input->xkb.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); if (!keymap) { sway_abort("Failed to compile keymap, aborting"); } struct xkb_state *state = xkb_state_new(keymap); if (!state) { xkb_keymap_unref(keymap); sway_abort("Failed to create xkb state, aborting"); } xkb_keymap_unref(registry->input->xkb.keymap); xkb_state_unref(registry->input->xkb.state); registry->input->xkb.keymap = keymap; registry->input->xkb.state = state; int i; for (i = 0; i < MASK_LAST; ++i) { registry->input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(registry->input->xkb.keymap, XKB_MASK_NAMES[i]); } }
struct sockaddr_un *ipc_user_sockaddr(void) { struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); if (ipc_sockaddr == NULL) { sway_abort("can't malloc ipc_sockaddr"); } ipc_sockaddr->sun_family = AF_UNIX; int path_size = sizeof(ipc_sockaddr->sun_path); // Without logind: int allocating_path_size = snprintf(ipc_sockaddr->sun_path, path_size, "/tmp/sway-ipc.%i.sock", getuid()); if (allocating_path_size >= path_size) { sway_abort("socket path won't fit into ipc_sockaddr->sun_path"); } return ipc_sockaddr; }
cairo_surface_t *load_image(char *image_path) { cairo_surface_t *image = NULL; #ifdef WITH_GDK_PIXBUF GError *err = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(image_path, &err); if (!pixbuf) { sway_abort("Failed to load background image: %s", err->message); } image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); g_object_unref(pixbuf); #else image = cairo_image_surface_create_from_png(image_path); #endif //WITH_GDK_PIXBUF if (!image) { sway_abort("Failed to read background image."); } return image; }
struct sockaddr_un *ipc_user_sockaddr(void) { struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); if (ipc_sockaddr == NULL) { sway_abort("can't malloc ipc_sockaddr"); } ipc_sockaddr->sun_family = AF_UNIX; int path_size = sizeof(ipc_sockaddr->sun_path); // Env var typically set by logind, e.g. "/run/user/<user-id>" const char *dir = getenv("XDG_RUNTIME_DIR"); if (!dir) { dir = "/tmp"; } if (path_size <= snprintf(ipc_sockaddr->sun_path, path_size, "%s/sway-ipc.%i.%i.sock", dir, getuid(), getpid())) { sway_abort("socket path won't fit into ipc_sockaddr->sun_path"); } return ipc_sockaddr; }
/** * Note: PAM will free() 'password' during the process */ bool verify_password() { struct passwd *passwd = getpwuid(getuid()); char *username = passwd->pw_name; const struct pam_conv local_conversation = { function_conversation, NULL }; pam_handle_t *local_auth_handle = NULL; int pam_err; if ((pam_err = pam_start("swaylock", username, &local_conversation, &local_auth_handle)) != PAM_SUCCESS) { sway_abort("PAM returned %d\n", pam_err); } if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) { return false; } if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) { return false; } return true; }
/** * password will be zeroed out. */ bool verify_password(char *password) { struct passwd *passwd = getpwuid(getuid()); char *username = passwd->pw_name; const struct pam_conv local_conversation = { function_conversation, NULL }; pam_handle_t *local_auth_handle = NULL; int pam_err; if ((pam_err = pam_start("swaylock", username, &local_conversation, &local_auth_handle)) != PAM_SUCCESS) { sway_abort("PAM returned %d\n", pam_err); } pam_reply = (struct pam_response *)malloc(sizeof(struct pam_response)); pam_reply[0].resp = password; pam_reply[0].resp_retcode = 0; if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) { memset(password, 0, strlen(password)); return false; } if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) { memset(password, 0, strlen(password)); return false; } memset(password, 0, strlen(password)); return true; }
int main(int argc, char **argv) { static int verbose = 0, debug = 0, validate = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"validate", no_argument, NULL, 'C'}, {"debug", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'V'}, {"get-socketpath", no_argument, NULL, 'p'}, {0, 0, 0, 0} }; char *config_path = NULL; const char* usage = "Usage: sway [options] [command]\n" "\n" " -h, --help Show help message and quit.\n" " -c, --config <config> Specify a config file.\n" " -C, --validate Check the validity of the config file, then exit.\n" " -d, --debug Enables full logging, including debug information.\n" " -v, --version Show the version number and quit.\n" " -V, --verbose Enables more verbose logging.\n" " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" "\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hCdvVpc:", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'h': // help fprintf(stdout, "%s", usage); exit(EXIT_SUCCESS); break; case 'c': // config config_path = strdup(optarg); break; case 'C': // validate validate = 1; break; case 'd': // debug debug = 1; break; case 'v': // version #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "sway version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; case 'V': // verbose verbose = 1; break; case 'p': ; // --get-socketpath if (getenv("SWAYSOCK")) { fprintf(stdout, "%s\n", getenv("SWAYSOCK")); exit(EXIT_SUCCESS); } else { fprintf(stderr, "sway socket not detected.\n"); exit(EXIT_FAILURE); } break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } if (optind < argc) { // Behave as IPC client if (getuid() != geteuid() || getgid() != getegid()) { if (setgid(getgid()) != 0 || setuid(getuid()) != 0) { sway_abort("Unable to drop root"); } } char *socket_path = getenv("SWAYSOCK"); if (!socket_path) { sway_abort("Unable to retrieve socket path"); } char *command = join_args(argv + optind, argc - optind); run_as_ipc_client(command, socket_path); return 0; } // we need to setup logging before wlc_init in case it fails. if (debug) { init_log(L_DEBUG); } else if (verbose || validate) { init_log(L_INFO); } else { init_log(L_ERROR); } setenv("WLC_DIM", "0", 0); wlc_log_set_handler(wlc_log_handler); detect_proprietary(); 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.) */ if (!wlc_init(&interface, argc, argv)) { return 1; } register_extensions(); // handle SIGTERM signals signal(SIGTERM, sig_handler); // prevent ipc from crashing sway signal(SIGPIPE, SIG_IGN); #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE sway_log(L_INFO, "Starting sway version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #endif init_layout(); if (validate) { bool valid = load_config(config_path); return valid ? 0 : 1; } if (!load_config(config_path)) { sway_log(L_ERROR, "Error(s) loading config!"); } if (config_path) { free(config_path); } ipc_init(); if (!terminate_request) { wlc_run(); } if (input_devices) { free(input_devices); } ipc_terminate(); return 0; }
int main(int argc, char **argv) { init_log(L_INFO); password = malloc(1024); // TODO: Let this grow password[0] = '\0'; surfaces = create_list(); registry = registry_poll(); if (!registry->swaylock) { sway_abort("swaylock requires the compositor to support the swaylock extension."); } int i; for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = window_setup(registry, output->width, output->height, true); if (!window) { sway_abort("Failed to create surfaces."); } list_add(surfaces, window); } registry->input->notify = notify_key; #ifdef WITH_GDK_PIXBUF GError *err = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[1], &err); // TODO: Parse i3lock arguments if (!pixbuf) { sway_abort("Failed to load background image."); } cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); g_object_unref(pixbuf); #else cairo_surface_t *image = cairo_image_surface_create_from_png(argv[1]); #endif //WITH_GDK_PIXBUF if (!image) { sway_abort("Failed to read background image."); } double width = cairo_image_surface_get_width(image); double height = cairo_image_surface_get_height(image); const char *scaling_mode_str = argv[2]; enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; if (strcmp(scaling_mode_str, "stretch") == 0) { scaling_mode = SCALING_MODE_STRETCH; } else if (strcmp(scaling_mode_str, "fill") == 0) { scaling_mode = SCALING_MODE_FILL; } else if (strcmp(scaling_mode_str, "fit") == 0) { scaling_mode = SCALING_MODE_FIT; } else if (strcmp(scaling_mode_str, "center") == 0) { scaling_mode = SCALING_MODE_CENTER; } else if (strcmp(scaling_mode_str, "tile") == 0) { scaling_mode = SCALING_MODE_TILE; } else { sway_abort("Unsupported scaling mode: %s", scaling_mode_str); } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; if (window_prerender(window) && window->cairo) { switch (scaling_mode) { case SCALING_MODE_STRETCH: cairo_scale(window->cairo, (double) window->width / width, (double) window->height / height); cairo_set_source_surface(window->cairo, image, 0, 0); break; case SCALING_MODE_FILL: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } else { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } break; } case SCALING_MODE_FIT: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } else { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } break; } case SCALING_MODE_CENTER: cairo_set_source_surface(window->cairo, image, (double) window->width/2 - width/2, (double) window->height/2 - height/2); break; case SCALING_MODE_TILE: { cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(window->cairo, pattern); break; } default: sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str); } cairo_paint(window->cairo); window_render(window); } } cairo_surface_destroy(image); bool locked = false; while (wl_display_dispatch(registry->display) != -1) { if (!locked) { for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = surfaces->items[i]; lock_set_lock_surface(registry->swaylock, output->output, window->surface); } locked = true; } } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; window_teardown(window); } list_free(surfaces); registry_teardown(registry); return 0; }
bool load_main_config(const char *file, bool is_active) { input_init(); char *path; if (file != NULL) { path = strdup(file); } else { path = get_config_path(); } struct sway_config *old_config = config; config = calloc(1, sizeof(struct sway_config)); if (!config) { sway_abort("Unable to allocate config"); } config_defaults(config); if (is_active) { sway_log(L_DEBUG, "Performing configuration file reload"); config->reloading = true; config->active = true; } config->current_config = path; list_add(config->config_chain, path); config->reading = true; // Read security configs bool success = true; DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); if (!dir) { sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" " and will probably be broken", SYSCONFDIR "/sway/security.d"); } else { list_t *secconfigs = create_list(); char *base = SYSCONFDIR "/sway/security.d/"; struct dirent *ent = readdir(dir); struct stat s; while (ent != NULL) { char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); strcpy(_path, base); strcat(_path, ent->d_name); lstat(_path, &s); if (S_ISREG(s.st_mode)) { list_add(secconfigs, _path); } ent = readdir(dir); } closedir(dir); list_qsort(secconfigs, qstrcmp); for (int i = 0; i < secconfigs->length; ++i) { char *_path = secconfigs->items[i]; if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); success = false; } else { success = success && load_config(_path, config); } } free_flat_list(secconfigs); } success = success && load_config(path, config); if (is_active) { config->reloading = false; } if (old_config) { free_config(old_config); } config->reading = false; if (success) { update_active_bar_modifiers(); } return success; }
static void config_defaults(struct sway_config *config) { if (!(config->symbols = create_list())) goto cleanup; if (!(config->modes = create_list())) goto cleanup; if (!(config->bars = create_list())) goto cleanup; if (!(config->workspace_outputs = create_list())) goto cleanup; if (!(config->pid_workspaces = create_list())) goto cleanup; if (!(config->criteria = create_list())) goto cleanup; if (!(config->input_configs = create_list())) goto cleanup; if (!(config->output_configs = create_list())) goto cleanup; if (!(config->cmd_queue = create_list())) goto cleanup; if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; strcpy(config->current_mode->name, "default"); if (!(config->current_mode->bindings = create_list())) goto cleanup; list_add(config->modes, config->current_mode); config->floating_mod = 0; config->dragging_key = M_LEFT_CLICK; config->resizing_key = M_RIGHT_CLICK; if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; config->default_layout = L_NONE; config->default_orientation = L_NONE; if (!(config->font = strdup("monospace 10"))) goto cleanup; config->font_height = get_font_text_height(config->font); // floating view config->floating_maximum_width = 0; config->floating_maximum_height = 0; config->floating_minimum_width = 75; config->floating_minimum_height = 50; // Flags config->focus_follows_mouse = true; config->mouse_warping = true; config->reloading = false; config->active = false; config->failed = false; config->auto_back_and_forth = false; config->seamless_mouse = true; config->reading = false; config->show_marks = true; config->edge_gaps = true; config->smart_gaps = false; config->gaps_inner = 0; config->gaps_outer = 0; if (!(config->active_bar_modifiers = create_list())) goto cleanup; if (!(config->config_chain = create_list())) goto cleanup; config->current_config = NULL; // borders config->border = B_NORMAL; config->floating_border = B_NORMAL; config->border_thickness = 2; config->floating_border_thickness = 2; config->hide_edge_borders = E_NONE; // border colors config->border_colors.focused.border = 0x4C7899FF; config->border_colors.focused.background = 0x285577FF; config->border_colors.focused.text = 0xFFFFFFFF; config->border_colors.focused.indicator = 0x2E9EF4FF; config->border_colors.focused.child_border = 0x285577FF; config->border_colors.focused_inactive.border = 0x333333FF; config->border_colors.focused_inactive.background = 0x5F676AFF; config->border_colors.focused_inactive.text = 0xFFFFFFFF; config->border_colors.focused_inactive.indicator = 0x484E50FF; config->border_colors.focused_inactive.child_border = 0x5F676AFF; config->border_colors.unfocused.border = 0x333333FF; config->border_colors.unfocused.background = 0x222222FF; config->border_colors.unfocused.text = 0x888888FF; config->border_colors.unfocused.indicator = 0x292D2EFF; config->border_colors.unfocused.child_border = 0x222222FF; config->border_colors.urgent.border = 0x2F343AFF; config->border_colors.urgent.background = 0x900000FF; config->border_colors.urgent.text = 0xFFFFFFFF; config->border_colors.urgent.indicator = 0x900000FF; config->border_colors.urgent.child_border = 0x900000FF; config->border_colors.placeholder.border = 0x000000FF; config->border_colors.placeholder.background = 0x0C0C0CFF; config->border_colors.placeholder.text = 0xFFFFFFFF; config->border_colors.placeholder.indicator = 0x000000FF; config->border_colors.placeholder.child_border = 0x0C0C0CFF; config->border_colors.background = 0xFFFFFFFF; // Security if (!(config->command_policies = create_list())) goto cleanup; if (!(config->feature_policies = create_list())) goto cleanup; if (!(config->ipc_policies = create_list())) goto cleanup; return; cleanup: sway_abort("Unable to allocate config structures"); }
void grab_and_apply_movie_magic(const char *file, const char *output, int socketfd, int raw, int framerate) { if (raw) { sway_log(L_ERROR, "Raw capture data is not yet supported. Proceeding with ffmpeg normally."); } uint32_t len = strlen(output); char *pixels = ipc_single_command(socketfd, IPC_SWAY_GET_PIXELS, output, &len); uint32_t *u32pixels = (uint32_t *)(pixels + 1); uint32_t width = u32pixels[0]; uint32_t height = u32pixels[1]; pixels += 9; if (width == 0 || height == 0) { sway_abort("Unknown output %s.", output); } const char *fmt = "ffmpeg -f rawvideo -framerate %d " "-video_size %dx%d -pixel_format argb " "-i pipe:0 -r %d -vf vflip %s"; char *cmd = malloc(strlen(fmt) - 8 /*args*/ + numlen(width) + numlen(height) + numlen(framerate) * 2 + strlen(file) + 1); sprintf(cmd, fmt, framerate, width, height, framerate, file); long ns = (long)(1000000000 * (1.0 / framerate)); struct timespec start, finish, ts; ts.tv_sec = 0; FILE *f = popen(cmd, "w"); fwrite(pixels, 1, len, f); free(pixels - 9); int sleep = 0; while (sleep != -1) { clock_gettime(CLOCK_MONOTONIC, &start); len = strlen(output); pixels = ipc_single_command(socketfd, IPC_SWAY_GET_PIXELS, output, &len); pixels += 9; len -= 9; fwrite(pixels, 1, len, f); free(pixels - 9); clock_gettime(CLOCK_MONOTONIC, &finish); ts.tv_nsec = ns; double fts = (double)finish.tv_sec + 1.0e-9*finish.tv_nsec; double sts = (double)start.tv_sec + 1.0e-9*start.tv_nsec; long diff = (fts - sts) * 1000000000; ts.tv_nsec = ns - diff; if (ts.tv_nsec < 0) { ts.tv_nsec = 0; } sleep = nanosleep(&ts, NULL); } fflush(f); fclose(f); free(cmd); }
int main(int argc, char **argv) { char *image_path = NULL; char *scaling_mode_str = "fit"; uint32_t color = 0xFFFFFFFF; init_log(L_INFO); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"color", required_argument, NULL, 'c'}, {"image", required_argument, NULL, 'i'}, {"scaling", required_argument, NULL, 's'}, {"tiling", no_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaylock [options...]\n" "\n" " -h, --help Show help message and quit.\n" " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" " -t, --tiling Same as --scaling=tile.\n" " -v, --version Show the version number and quit.\n" " -i, --image <path> Display the given image.\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hc:i:s:tv", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'c': { int colorlen = strlen(optarg); if (colorlen < 6 || colorlen == 7 || colorlen > 8) { fprintf(stderr, "color must be specified in 3 or 4 byte format, e.g. ff0000 or ff0000ff\n"); exit(EXIT_FAILURE); } color = strtol(optarg, NULL, 16); if (colorlen == 6) { color <<= 8; color |= 0xFF; } sway_log(L_DEBUG, "color: 0x%x", color); break; } case 'i': image_path = optarg; break; case 's': scaling_mode_str = optarg; break; case 't': scaling_mode_str = "tile"; break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; if (strcmp(scaling_mode_str, "stretch") == 0) { scaling_mode = SCALING_MODE_STRETCH; } else if (strcmp(scaling_mode_str, "fill") == 0) { scaling_mode = SCALING_MODE_FILL; } else if (strcmp(scaling_mode_str, "fit") == 0) { scaling_mode = SCALING_MODE_FIT; } else if (strcmp(scaling_mode_str, "center") == 0) { scaling_mode = SCALING_MODE_CENTER; } else if (strcmp(scaling_mode_str, "tile") == 0) { scaling_mode = SCALING_MODE_TILE; } else { sway_abort("Unsupported scaling mode: %s", scaling_mode_str); } password_size = 1024; password = malloc(password_size); password[0] = '\0'; surfaces = create_list(); registry = registry_poll(); if (!registry) { sway_abort("Unable to connect to wayland compositor"); } if (!registry->swaylock) { sway_abort("swaylock requires the compositor to support the swaylock extension."); } if (registry->pointer) { // We don't want swaylock to have a pointer wl_pointer_destroy(registry->pointer); registry->pointer = NULL; } int i; for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = window_setup(registry, output->width, output->height, true); if (!window) { sway_abort("Failed to create surfaces."); } list_add(surfaces, window); } registry->input->notify = notify_key; cairo_surface_t *image = NULL; if (image_path) { #ifdef WITH_GDK_PIXBUF GError *err = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(image_path, &err); if (!pixbuf) { sway_abort("Failed to load background image."); } image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); g_object_unref(pixbuf); #else cairo_surface_t *image = cairo_image_surface_create_from_png(argv[1]); #endif //WITH_GDK_PIXBUF if (!image) { sway_abort("Failed to read background image."); } } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; if (!window_prerender(window) || !window->cairo) { continue; } if (image) { render_image(window, image, scaling_mode); } else { render_color(window, color); } } if (image) { cairo_surface_destroy(image); } bool locked = false; while (wl_display_dispatch(registry->display) != -1) { if (!locked) { for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = surfaces->items[i]; lock_set_lock_surface(registry->swaylock, output->output, window->surface); } locked = true; } } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; window_teardown(window); } list_free(surfaces); registry_teardown(registry); return 0; }
int main(int argc, char **argv) { static int capture = 0, raw = 0; char *socket_path = NULL; char *output = NULL; int framerate = 30; init_log(L_INFO); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"capture", no_argument, NULL, 'c'}, {"output", required_argument, NULL, 'o'}, {"version", no_argument, NULL, 'v'}, {"socket", required_argument, NULL, 's'}, {"raw", no_argument, NULL, 'r'}, {"rate", required_argument, NULL, 'R'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaygrab [options] [file]\n" "\n" " -h, --help Show help message and quit.\n" " -c, --capture Capture video.\n" " -o, --output <output> Output source.\n" " -v, --version Show the version number and quit.\n" " -s, --socket <socket> Use the specified socket.\n" " -R, --rate <rate> Specify framerate (default: 30)\n" " -r, --raw Write raw rgba data to stdout.\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hco:vs:r", long_options, &option_index); if (c == -1) { break; } switch (c) { case 's': // Socket socket_path = strdup(optarg); break; case 'r': raw = 1; break; case 'o': // output output = strdup(optarg); break; case 'c': capture = 1; break; case 'R': // Frame rate framerate = atoi(optarg); break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "sway version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } if (!socket_path) { socket_path = get_socketpath(); if (!socket_path) { sway_abort("Unable to retrieve socket path"); } } char *file = NULL; if (raw) { if (optind >= argc + 1) { sway_abort("Invalid usage. See `man swaygrab` %d %d", argc, optind); } } else if (optind < argc) { file = strdup(argv[optind]); } int socketfd = ipc_open_socket(socket_path); free(socket_path); if (!output) { output = get_focused_output(socketfd); } if (!file) { if (!capture) { file = default_filename("png"); } else { file = default_filename("webm"); } } if (!capture) { grab_and_apply_magick(file, output, socketfd, raw); } else { grab_and_apply_movie_magic(file, output, socketfd, raw, framerate); } free(output); free(file); close(socketfd); return 0; }
int main(int argc, char **argv) { const char *scaling_mode_str = "fit", *socket_path = NULL; int i; void *images = NULL; render_data.num_images = 0; render_data.color_set = 0; render_data.color = 0xFFFFFFFF; render_data.auth_state = AUTH_STATE_IDLE; init_log(L_INFO); // Install SIGALARM handler (for hiding the typing indicator) signal(SIGALRM, sigalarm_handler); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"color", required_argument, NULL, 'c'}, {"image", required_argument, NULL, 'i'}, {"scaling", required_argument, NULL, 's'}, {"tiling", no_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, {"socket", required_argument, NULL, 'p'}, {"no-unlock-indicator", no_argument, NULL, 'u'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaylock [options...]\n" "\n" " -h, --help Show help message and quit.\n" " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" " -t, --tiling Same as --scaling=tile.\n" " -v, --version Show the version number and quit.\n" " -i, --image [<output>:]<path> Display the given image.\n" " -u, --no-unlock-indicator Disable the unlock indicator.\n" " --socket <socket> Use the specified socket.\n"; registry = registry_poll(); int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hc:i:s:tvu", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'c': { int colorlen = strlen(optarg); if (colorlen < 6 || colorlen == 7 || colorlen > 8) { sway_log(L_ERROR, "color must be specified in 3 or 4 byte format, i.e. rrggbb or rrggbbaa"); exit(EXIT_FAILURE); } render_data.color = strtol(optarg, NULL, 16); render_data.color_set = 1; if (colorlen == 6) { render_data.color <<= 8; render_data.color |= 0xFF; } break; } case 'i': { char *image_path = strchr(optarg, ':'); if (image_path == NULL) { if (render_data.num_images == 0) { // Provided image without output render_data.image = load_image(optarg); render_data.num_images = -1; } else { sway_log(L_ERROR, "output must be defined for all --images or no --images"); exit(EXIT_FAILURE); } } else { // Provided image for all outputs if (render_data.num_images == 0) { images = calloc(registry->outputs->length, sizeof(char*) * 2); } else if (render_data.num_images == -1) { sway_log(L_ERROR, "output must be defined for all --images or no --images"); exit(EXIT_FAILURE); } image_path[0] = '\0'; ((char**) images)[render_data.num_images * 2] = optarg; ((char**) images)[render_data.num_images++ * 2 + 1] = ++image_path; } break; } case 's': scaling_mode_str = optarg; break; case 't': scaling_mode_str = "tile"; break; case 'p': socket_path = optarg; break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; case 'u': show_indicator = false; break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } render_data.scaling_mode = SCALING_MODE_STRETCH; if (strcmp(scaling_mode_str, "stretch") == 0) { render_data.scaling_mode = SCALING_MODE_STRETCH; } else if (strcmp(scaling_mode_str, "fill") == 0) { render_data.scaling_mode = SCALING_MODE_FILL; } else if (strcmp(scaling_mode_str, "fit") == 0) { render_data.scaling_mode = SCALING_MODE_FIT; } else if (strcmp(scaling_mode_str, "center") == 0) { render_data.scaling_mode = SCALING_MODE_CENTER; } else if (strcmp(scaling_mode_str, "tile") == 0) { render_data.scaling_mode = SCALING_MODE_TILE; } else { sway_abort("Unsupported scaling mode: %s", scaling_mode_str); } password_size = 1024; password = malloc(password_size); password[0] = '\0'; render_data.surfaces = create_list(); if (!socket_path) { socket_path = get_socketpath(); if (!socket_path) { sway_abort("Unable to retrieve socket path"); } } if (!registry) { sway_abort("Unable to connect to wayland compositor"); } if (!registry->swaylock) { sway_abort("swaylock requires the compositor to support the swaylock extension."); } if (registry->pointer) { // We don't want swaylock to have a pointer wl_pointer_destroy(registry->pointer); registry->pointer = NULL; } for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = window_setup(registry, output->width, output->height, true); if (!window) { sway_abort("Failed to create surfaces."); } list_add(render_data.surfaces, window); } registry->input->notify = notify_key; // Different background for the output if (render_data.num_images >= 1) { char **displays_paths = images; render_data.images = calloc(registry->outputs->length, sizeof(cairo_surface_t*)); int socketfd = ipc_open_socket(socket_path); uint32_t len = 0; char *outputs = ipc_single_command(socketfd, IPC_GET_OUTPUTS, "", &len); struct json_object *json_outputs = json_tokener_parse(outputs); for (i = 0; i < registry->outputs->length; ++i) { if (displays_paths[i * 2] != NULL) { for (int j = 0;; ++j) { if (j >= json_object_array_length(json_outputs)) { sway_log(L_ERROR, "%s is not an extant output", displays_paths[i * 2]); exit(EXIT_FAILURE); } struct json_object *dsp_name, *at_j = json_object_array_get_idx(json_outputs, j); if (!json_object_object_get_ex(at_j, "name", &dsp_name)) { sway_abort("output doesn't have a name field"); } if (!strcmp(displays_paths[i * 2], json_object_get_string(dsp_name))) { render_data.images[j] = load_image(displays_paths[i * 2 + 1]); break; } } } } json_object_put(json_outputs); close(socketfd); free(displays_paths); } render(&render_data); bool locked = false; while (wl_display_dispatch(registry->display) != -1) { if (!locked) { for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = render_data.surfaces->items[i]; lock_set_lock_surface(registry->swaylock, output->output, window->surface); } locked = true; } } // Free surfaces if (render_data.num_images == -1) { cairo_surface_destroy(render_data.image); } else if (render_data.num_images >= 1) { for (i = 0; i < registry->outputs->length; ++i) { if (render_data.images[i] != NULL) { cairo_surface_destroy(render_data.images[i]); } } free(render_data.images); } for (i = 0; i < render_data.surfaces->length; ++i) { struct window *window = render_data.surfaces->items[i]; window_teardown(window); } list_free(render_data.surfaces); registry_teardown(registry); return 0; }
int main(int argc, char **argv) { static int quiet = 0; static int raw = 0; char *socket_path = NULL; char *cmdtype = NULL; init_log(L_INFO); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"quiet", no_argument, NULL, 'q'}, {"raw", no_argument, NULL, 'r'}, {"socket", required_argument, NULL, 's'}, {"type", required_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaymsg [options] [message]\n" "\n" " -h, --help Show help message and quit.\n" " -q, --quiet Be quiet.\n" " -r, --raw Use raw output even if using a tty\n" " -s, --socket <socket> Use the specified socket.\n" " -t, --type <type> Specify the message type.\n" " -v, --version Show the version number and quit.\n"; raw = !isatty(STDOUT_FILENO); int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hqrs:t:v", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'q': // Quiet quiet = 1; break; case 'r': // Raw raw = 1; break; case 's': // Socket socket_path = strdup(optarg); break; case 't': // Type cmdtype = strdup(optarg); break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "sway version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } if (!cmdtype) { cmdtype = strdup("command"); } if (!socket_path) { socket_path = get_socketpath(); if (!socket_path) { sway_abort("Unable to retrieve socket path"); } } uint32_t type = IPC_COMMAND; if (strcasecmp(cmdtype, "command") == 0) { type = IPC_COMMAND; } else if (strcasecmp(cmdtype, "get_workspaces") == 0) { type = IPC_GET_WORKSPACES; } else if (strcasecmp(cmdtype, "get_inputs") == 0) { type = IPC_GET_INPUTS; } else if (strcasecmp(cmdtype, "get_outputs") == 0) { type = IPC_GET_OUTPUTS; } else if (strcasecmp(cmdtype, "get_tree") == 0) { type = IPC_GET_TREE; } else if (strcasecmp(cmdtype, "get_marks") == 0) { type = IPC_GET_MARKS; } else if (strcasecmp(cmdtype, "get_bar_config") == 0) { type = IPC_GET_BAR_CONFIG; } else if (strcasecmp(cmdtype, "get_version") == 0) { type = IPC_GET_VERSION; } else { sway_abort("Unknown message type %s", cmdtype); } free(cmdtype); char *command = strdup(""); if (optind < argc) { command = join_args(argv + optind, argc - optind); } int ret = 0; int socketfd = ipc_open_socket(socket_path); uint32_t len = strlen(command); char *resp = ipc_single_command(socketfd, type, command, &len); if (!quiet) { // pretty print the json json_object *obj = json_tokener_parse(resp); if (obj == NULL) { fprintf(stderr, "ERROR: Could not parse json response from ipc. This is a bug in sway."); printf("%s\n", resp); ret = 1; } else { if (raw) { printf("%s\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); } else { pretty_print(type, obj); } free(obj); } } close(socketfd); free(command); free(resp); free(socket_path); return ret; }
int main(int argc, char **argv) { static int quiet = 0; char *socket_path = NULL; char *cmdtype = NULL; init_log(L_INFO); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"quiet", no_argument, NULL, 'q'}, {"version", no_argument, NULL, 'v'}, {"socket", required_argument, NULL, 's'}, {"type", required_argument, NULL, 't'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaymsg [options] [message]\n" "\n" " -h, --help Show help message and quit.\n" " -q, --quiet Be quiet.\n" " -v, --version Show the version number and quit.\n" " -s, --socket <socket> Use the specified socket.\n" " -t, --type <type> Specify the message type.\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hqvs:t:", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'q': // Quiet quiet = 1; break; case 's': // Socket socket_path = strdup(optarg); break; case 't': // Type cmdtype = strdup(optarg); break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "sway version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } if (!cmdtype) { cmdtype = strdup("command"); } if (!socket_path) { socket_path = get_socketpath(); if (!socket_path) { sway_abort("Unable to retrieve socket path"); } } uint32_t type = IPC_COMMAND; if (strcasecmp(cmdtype, "command") == 0) { type = IPC_COMMAND; } else if (strcasecmp(cmdtype, "get_workspaces") == 0) { type = IPC_GET_WORKSPACES; } else if (strcasecmp(cmdtype, "get_inputs") == 0) { type = IPC_GET_INPUTS; } else if (strcasecmp(cmdtype, "get_outputs") == 0) { type = IPC_GET_OUTPUTS; } else if (strcasecmp(cmdtype, "get_tree") == 0) { type = IPC_GET_TREE; } else if (strcasecmp(cmdtype, "get_marks") == 0) { type = IPC_GET_MARKS; } else if (strcasecmp(cmdtype, "get_bar_config") == 0) { type = IPC_GET_BAR_CONFIG; } else if (strcasecmp(cmdtype, "get_version") == 0) { type = IPC_GET_VERSION; } else { sway_abort("Unknown message type %s", cmdtype); } free(cmdtype); char *command = strdup(""); if (optind < argc) { command = join_args(argv + optind, argc - optind); } int socketfd = ipc_open_socket(socket_path); uint32_t len = strlen(command); char *resp = ipc_single_command(socketfd, type, command, &len); if (!quiet) { printf("%s\n", resp); } close(socketfd); free(command); free(resp); free(socket_path); return 0; }
swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir) { // TODO: This implementation is naïve: We assume all outputs are // perfectly aligned (ie. only a single output per edge which covers // the whole edge). if (!output) { output = swayc_active_output(); } swayc_t *adjacent = NULL; switch(dir) { case MOVE_LEFT: for(int i = 0; i < root_container.children->length; ++i) { swayc_t *c = root_container.children->items[i]; if (c == output || c->type != C_OUTPUT) { continue; } if (c->y == output->y && c->x + c->width == output->x) { sway_log(L_DEBUG, "%s is left of current output %s", c->name, output->name); adjacent = c; break; } } break; case MOVE_RIGHT: for(int i = 0; i < root_container.children->length; ++i) { swayc_t *c = root_container.children->items[i]; if (c == output || c->type != C_OUTPUT) { continue; } if (c->y == output->y && output->x + output->width == c->x) { sway_log(L_DEBUG, "%s is right of current output %s", c->name, output->name); adjacent = c; break; } } break; case MOVE_UP: for(int i = 0; i < root_container.children->length; ++i) { swayc_t *c = root_container.children->items[i]; if (c == output || c->type != C_OUTPUT) { continue; } if (output->x == c->x && c->y + c->height == output->y) { sway_log(L_DEBUG, "%s is above current output %s", c->name, output->name); adjacent = c; break; } } break; case MOVE_DOWN: for(int i = 0; i < root_container.children->length; ++i) { swayc_t *c = root_container.children->items[i]; if (c == output || c->type != C_OUTPUT) { continue; } if (output->x == c->x && output->y + output->height == c->y) { sway_log(L_DEBUG, "%s is below current output %s", c->name, output->name); adjacent = c; break; } } break; default: sway_abort("Function called with invalid argument."); break; } return adjacent; }
int main(int argc, char **argv) { char *image_path = NULL; char *scaling_mode_str = "fit"; init_log(L_INFO); static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"image", required_argument, NULL, 'i'}, {"scaling", required_argument, NULL, 's'}, {"tiling", no_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, {0, 0, 0, 0} }; const char *usage = "Usage: swaylock [options...]\n" "\n" " -h, --help Show help message and quit.\n" " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" " -t, --tiling Same as --scaling=tile.\n" " -v, --version Show the version number and quit.\n" " -i, --image <path> Display the given image.\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hi:s:tv", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'i': image_path = optarg; break; case 's': scaling_mode_str = optarg; break; case 't': scaling_mode_str = "tile"; break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); #else fprintf(stdout, "version not detected\n"); #endif exit(EXIT_SUCCESS); break; default: fprintf(stderr, "%s", usage); exit(EXIT_FAILURE); } } // TODO: support locking without image if (!image_path) { fprintf(stderr, "No image specified!\n"); exit(EXIT_FAILURE); } password = malloc(1024); // TODO: Let this grow password[0] = '\0'; surfaces = create_list(); registry = registry_poll(); if (!registry->swaylock) { sway_abort("swaylock requires the compositor to support the swaylock extension."); } int i; for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = window_setup(registry, output->width, output->height, true); if (!window) { sway_abort("Failed to create surfaces."); } list_add(surfaces, window); } registry->input->notify = notify_key; #ifdef WITH_GDK_PIXBUF GError *err = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(image_path, &err); if (!pixbuf) { sway_abort("Failed to load background image."); } cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); g_object_unref(pixbuf); #else cairo_surface_t *image = cairo_image_surface_create_from_png(argv[1]); #endif //WITH_GDK_PIXBUF if (!image) { sway_abort("Failed to read background image."); } double width = cairo_image_surface_get_width(image); double height = cairo_image_surface_get_height(image); enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; if (strcmp(scaling_mode_str, "stretch") == 0) { scaling_mode = SCALING_MODE_STRETCH; } else if (strcmp(scaling_mode_str, "fill") == 0) { scaling_mode = SCALING_MODE_FILL; } else if (strcmp(scaling_mode_str, "fit") == 0) { scaling_mode = SCALING_MODE_FIT; } else if (strcmp(scaling_mode_str, "center") == 0) { scaling_mode = SCALING_MODE_CENTER; } else if (strcmp(scaling_mode_str, "tile") == 0) { scaling_mode = SCALING_MODE_TILE; } else { sway_abort("Unsupported scaling mode: %s", scaling_mode_str); } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; if (window_prerender(window) && window->cairo) { switch (scaling_mode) { case SCALING_MODE_STRETCH: cairo_scale(window->cairo, (double) window->width / width, (double) window->height / height); cairo_set_source_surface(window->cairo, image, 0, 0); break; case SCALING_MODE_FILL: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } else { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } break; } case SCALING_MODE_FIT: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } else { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } break; } case SCALING_MODE_CENTER: cairo_set_source_surface(window->cairo, image, (double) window->width/2 - width/2, (double) window->height/2 - height/2); break; case SCALING_MODE_TILE: { cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(window->cairo, pattern); break; } default: sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str); } cairo_paint(window->cairo); window_render(window); } } cairo_surface_destroy(image); bool locked = false; while (wl_display_dispatch(registry->display) != -1) { if (!locked) { for (i = 0; i < registry->outputs->length; ++i) { struct output_state *output = registry->outputs->items[i]; struct window *window = surfaces->items[i]; lock_set_lock_surface(registry->swaylock, output->output, window->surface); } locked = true; } } for (i = 0; i < surfaces->length; ++i) { struct window *window = surfaces->items[i]; window_teardown(window); } list_free(surfaces); registry_teardown(registry); return 0; }