gimp but for windows: a wayland compositor
git clone https://github.com/m-col/wimp
Files | Refs | Readme

-rw-r--r-- src/config.c


      1 #include <cairo/cairo.h>
      2 #include <drm_fourcc.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <wordexp.h>
      7 #include <wayland-server-core.h>
      8 #include <wlr/render/wlr_texture.h>
      9 #include <unistd.h>
     10 
     11 #include "action.h"
     12 #include "config.h"
     13 #include "desk.h"
     14 #include "keybind.h"
     15 #include "output.h"
     16 #include "scratchpad.h"
     17 #include "types.h"
     18 
     19 #define CONFIG_HOME "$HOME/.config/wimp/startup"
     20 #define CONFIG_HOME_XDG "$XDG_CONFIG_HOME/wimp/startup"
     21 
     22 
     23 void assign_colour(char *hex, float dest[4]) {
     24     if (!hex) {
     25 	return;
     26     }
     27     if (hex[0] == '#') {
     28 	hex++;
     29     }
     30 
     31     char c[2];
     32     int copy;
     33     if (strlen(hex) == 6) {
     34 	dest[3] = 1;
     35 	copy = 3;
     36     } else if (strlen(hex) == 8) {
     37 	copy = 4;
     38     } else {
     39 	wlr_log(WLR_INFO, "Invalid colour: %s. Should be in the form #rrggbb.", hex);
     40 	return;
     41     }
     42 
     43     for (int i = 0; i < copy; i++) {
     44 	strncpy(c, &hex[i * 2], 2);
     45 	dest[i] = (float)strtol(c, NULL, 16) / 255;
     46     }
     47 }
     48 
     49 
     50 static void load_wallpaper(struct desk *desk, char *path) {
     51     cairo_surface_t *image = cairo_image_surface_create_from_png(path);
     52 
     53     if (!image || cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
     54 	wlr_log(WLR_INFO, "Could not load image: %s", path);
     55 	return;
     56     }
     57 
     58     struct wallpaper *wallpaper = calloc(1, sizeof(struct wallpaper));
     59     wallpaper->width = cairo_image_surface_get_width(image);
     60     wallpaper->height = cairo_image_surface_get_height(image);
     61     int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, wallpaper->width);
     62 
     63     // we copy the image to a second surface to ensure the pixel format is
     64     // compatible with wlr_texture_from_pixels
     65     cairo_surface_t *canvas = cairo_image_surface_create(
     66 	CAIRO_FORMAT_ARGB32, wallpaper->width, wallpaper->height);
     67     cairo_t *cr = cairo_create(canvas);
     68     cairo_set_source_surface(cr, image, 0, 0);
     69     cairo_paint(cr);
     70 
     71     wallpaper->texture = wlr_texture_from_pixels(
     72 	wimp.renderer, DRM_FORMAT_ARGB8888, stride, wallpaper->width,
     73 	wallpaper->height, cairo_image_surface_get_data(canvas)
     74     );
     75     desk->wallpaper = wallpaper;
     76     damage_all_outputs();
     77     cairo_destroy(cr);
     78     cairo_surface_destroy(image);
     79     cairo_surface_destroy(canvas);
     80 }
     81 
     82 
     83 static void set_wallpaper(struct desk *desk, char *wallpaper) {
     84     // wallpaper is a colour
     85     if (strlen(wallpaper) == 7 && wallpaper[0] == '#') {
     86 	assign_colour(wallpaper, desk->background);
     87 	return;
     88     }
     89 
     90     // wallpaper is a path to an image
     91     wordexp_t p;
     92     wordexp(wallpaper, &p, WRDE_NOCMD | WRDE_UNDEF);
     93     load_wallpaper(desk, p.we_wordv[0]);
     94     wordfree(&p);
     95 }
     96 
     97 
     98 static void disable_vt_switching() {
     99     struct binding *kb, *tmp;
    100     wl_list_for_each_safe(kb, tmp, &wimp.key_bindings, link) {
    101 	if (kb->action == &change_vt) {
    102 	    free_binding(kb);
    103 	}
    104     }
    105 }
    106 
    107 
    108 static void setup_vt_switching() {
    109     uint32_t func_keys[] = {
    110 	XKB_KEY_F1,
    111 	XKB_KEY_F2,
    112 	XKB_KEY_F3,
    113 	XKB_KEY_F4,
    114 	XKB_KEY_F5,
    115 	XKB_KEY_F6,
    116     };
    117     struct binding *kb;
    118 
    119     for (unsigned i = 0; i < 6; i++) {
    120 	kb = calloc(1, sizeof(struct binding));
    121 	kb->mods = WLR_MODIFIER_CTRL;
    122 	kb->key = func_keys[i];
    123 	kb->action = &change_vt;
    124 	kb->data = calloc(1, sizeof(unsigned));
    125 	*(unsigned *)(kb->data) = i + 1;
    126 	wl_list_insert(wimp.key_bindings.prev, &kb->link);
    127     }
    128 }
    129 
    130 
    131 void set_configurable(char *message, char *response) {
    132     char *s;
    133     if (!(s = strtok(NULL, " \t\n\r"))) {
    134 	sprintf(response, "What do you want to set?.");
    135 	return;
    136     }
    137 
    138     // desks <int>
    139     if (!strcasecmp(s, "desks")) {
    140 	if ((s = strtok(NULL, " \t\n\r")) && is_number(s)) {
    141 	    configure_desks(strtod(s, NULL));
    142 	}
    143     }
    144 
    145     // desk ...
    146     else if (!strcasecmp(s, "desk")) {
    147 	if ((s = strtok(NULL, " \t\n\r")) && is_number(s)) {
    148 	    int index = strtod(s, NULL) - 1;
    149 	    s = strtok(NULL, " \t\n\r");
    150 	    struct desk *desk;
    151 	    bool found = false;
    152 	    wl_list_for_each(desk, &wimp.desks, link) {
    153 		if (desk->index == index) {
    154 		    found = true;
    155 		    break;
    156 		}
    157 	    }
    158 	    if (!found) {
    159 		return;
    160 	    }
    161 
    162 	    // desk <index> background #rrggbb
    163 	    // desk <index> background ~/path/to/image.png
    164 	    if (!strcasecmp(s, "background")) {
    165 		if ((s = strtok(NULL, " \t\n\r"))) {
    166 		    set_wallpaper(desk, s);
    167 		}
    168 	    }
    169 
    170 	    // desk <index> borders [focus|normal] <#rrggbb>
    171 	    // desk <index> borders width <int>
    172 	    else if (!strcasecmp(s, "borders")) {
    173 		s = strtok(NULL, " \t\n\r");
    174 		if (!strcasecmp(s, "normal")) {
    175 		    assign_colour(strtok(NULL, " \t\n\r"), desk->border_normal);
    176 		}
    177 		else if (!strcasecmp(s, "focus")) {
    178 		    assign_colour(strtok(NULL, " \t\n\r"), desk->border_focus);
    179 		}
    180 		else if (!strcasecmp(s, "width")) {
    181 		    if ((s = strtok(NULL, " \t\n\r")) && is_number(s)) {
    182 			desk->border_width = strtod(s, NULL);
    183 		    }
    184 		}
    185 	    }
    186 
    187 	    // desk <index> corners [focus|normal] <#rrggbb>
    188 	    else if (!strcasecmp(s, "corners")) {
    189 		s = strtok(NULL, " \t\n\r");
    190 		if (!strcasecmp(s, "normal")) {
    191 		    assign_colour(strtok(NULL, " \t\n\r"), desk->corner_normal);
    192 		}
    193 		else if (!strcasecmp(s, "focus")) {
    194 		    assign_colour(strtok(NULL, " \t\n\r"), desk->corner_focus);
    195 		}
    196 	    }
    197 	}
    198     }
    199 
    200     // zoom_min <float>
    201     else if (!strcasecmp(s, "zoom_min")) {
    202 	if ((s = strtok(NULL, " \t\n\r")) && is_number(s)) {
    203 	    wimp.zoom_min = strtod(s, NULL);
    204 	}
    205     }
    206 
    207     // zoom_max <float>
    208     else if (!strcasecmp(s, "zoom_max")) {
    209 	if ((s = strtok(NULL, " \t\n\r")) && is_number(s)) {
    210 	    wimp.zoom_max = strtod(s, NULL);
    211 	}
    212     }
    213 
    214     // mark_indicator #rrggbb
    215     else if (!strcasecmp(s, "mark_indicator")) {
    216 	assign_colour(strtok(NULL, " \t\n\r"), wimp.mark_indicator.colour);
    217 	wimp.mark_indicator.box.x = 0;
    218 	wimp.mark_indicator.box.y = 0;
    219     }
    220 
    221     // snap_box #rrggbb
    222     else if (!strcasecmp(s, "snap_box")) {
    223 	assign_colour(strtok(NULL, " \t\n\r"), wimp.snapbox_colour);
    224     }
    225 
    226     // vt_switching [off|on]
    227     else if (!strcasecmp(s, "vt_switching")) {
    228 	s = strtok(NULL, " \t\n\r");
    229 	if (!strcasecmp(s, "off"))
    230 	    disable_vt_switching();
    231 	else if (!strcasecmp(s, "on"))
    232 	    setup_vt_switching();
    233     }
    234 
    235     // scroll_direction [natural|reverse]
    236     else if (!strcasecmp(s, "scroll_direction")) {
    237 	s = strtok(NULL, " \t\n\r");
    238 	if (!strcasecmp(s, "natural"))
    239 	    wimp.reverse_scrolling = false;
    240 	else if (!strcasecmp(s, "reverse"))
    241 	    wimp.reverse_scrolling = true;
    242     }
    243 
    244     // mod <modifier>
    245     else if (!strcasecmp(s, "mod")) {
    246 	set_mod(message, response);
    247     }
    248 
    249     // bind_marks [on|off]
    250     else if (!strcasecmp(s, "bind_marks")) {
    251 	s = strtok(NULL, " \t\n\r");
    252 	if (!strcasecmp(s, "off"))
    253 	    wimp.bind_marks = false;
    254 	else if (!strcasecmp(s, "on"))
    255 	    wimp.bind_marks = true;
    256     }
    257 
    258     // auto_focus [on|off]
    259     else if (!strcasecmp(s, "auto_focus")) {
    260 	s = strtok(NULL, " \t\n\r");
    261 	if (!strcasecmp(s, "off")) {
    262 	    wimp.auto_focus = false;
    263 	} else if (!strcasecmp(s, "on")) {
    264 	    wimp.auto_focus = true;
    265 	}
    266     }
    267 }
    268 
    269 
    270 struct startup_data {
    271     struct wl_event_source *wl_event_source;
    272     char *script;
    273 };
    274 
    275 
    276 static int _startup(void *vdata) {
    277     struct startup_data *data = vdata;
    278     wl_event_source_remove(data->wl_event_source);
    279     if (fork() == 0) {
    280 	if (execl(data->script, data->script, (void *)NULL) == -1) {
    281 	    exit(EXIT_FAILURE);
    282 	}
    283     } else {
    284 	wlr_log(WLR_DEBUG, "Running startup script: %s", data->script);
    285     }
    286     free(data->script);
    287     free(data);
    288     return 0;
    289 }
    290 
    291 
    292 void schedule_startup() {
    293     char *xdg_config = getenv("XDG_CONFIG_HOME");
    294     char *config_dir = (xdg_config && *xdg_config) ? CONFIG_HOME_XDG : CONFIG_HOME;
    295     struct startup_data *data = calloc(1, sizeof(struct startup_data));
    296     wordexp_t p;
    297     wordexp(config_dir, &p, WRDE_NOCMD | WRDE_UNDEF);
    298     data->script = strdup(p.we_wordv[0]);
    299     wordfree(&p);
    300 
    301     if (is_executable(data->script)) {
    302 	struct wl_event_loop *event_loop = wl_display_get_event_loop(wimp.display);
    303 	data->wl_event_source = wl_event_loop_add_timer(event_loop, _startup, data);
    304 	wl_event_source_timer_update(data->wl_event_source, 1);
    305     } else {
    306 	wlr_log(WLR_ERROR, "Cannot run startup script: %s", data->script);
    307 	free(data->script);
    308 	free(data);
    309     }
    310 
    311 }
    312