00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <sys/wait.h>
00014 #include <stdarg.h>
00015 #include <iconv.h>
00016 #if defined(__OpenBSD__)
00017 #include <sys/cdefs.h>
00018 #endif
00019 #include <fcntl.h>
00020 #include <pwd.h>
00021 #include <yajl/yajl_version.h>
00022 #include <libgen.h>
00023
00024 #include "all.h"
00025
00026 static iconv_t conversion_descriptor = 0;
00027
00028 int min(int a, int b) {
00029 return (a < b ? a : b);
00030 }
00031
00032 int max(int a, int b) {
00033 return (a > b ? a : b);
00034 }
00035
00036 bool rect_contains(Rect rect, uint32_t x, uint32_t y) {
00037 return (x >= rect.x &&
00038 x <= (rect.x + rect.width) &&
00039 y >= rect.y &&
00040 y <= (rect.y + rect.height));
00041 }
00042
00043 Rect rect_add(Rect a, Rect b) {
00044 return (Rect){a.x + b.x,
00045 a.y + b.y,
00046 a.width + b.width,
00047 a.height + b.height};
00048 }
00049
00050
00051
00052
00053
00054
00055 bool update_if_necessary(uint32_t *destination, const uint32_t new_value) {
00056 uint32_t old_value = *destination;
00057
00058 return ((*destination = new_value) != old_value);
00059 }
00060
00061
00062
00063
00064
00065
00066 void *smalloc(size_t size) {
00067 void *result = malloc(size);
00068 exit_if_null(result, "Error: out of memory (malloc(%zd))\n", size);
00069 return result;
00070 }
00071
00072 void *scalloc(size_t size) {
00073 void *result = calloc(size, 1);
00074 exit_if_null(result, "Error: out of memory (calloc(%zd))\n", size);
00075 return result;
00076 }
00077
00078 void *srealloc(void *ptr, size_t size) {
00079 void *result = realloc(ptr, size);
00080 exit_if_null(result, "Error: out memory (realloc(%zd))\n", size);
00081 return result;
00082 }
00083
00084 char *sstrdup(const char *str) {
00085 char *result = strdup(str);
00086 exit_if_null(result, "Error: out of memory (strdup())\n");
00087 return result;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 void start_application(const char *command) {
00101 LOG("executing: %s\n", command);
00102 if (fork() == 0) {
00103
00104 setsid();
00105 if (fork() == 0) {
00106
00107 static const char *shell = NULL;
00108
00109 if (shell == NULL)
00110 if ((shell = getenv("SHELL")) == NULL)
00111 shell = "/bin/sh";
00112
00113
00114 execl(shell, shell, "-c", command, (void*)NULL);
00115
00116 }
00117 exit(0);
00118 }
00119 wait(0);
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 void exec_i3_utility(char *name, char *argv[]) {
00138
00139 char *migratepath = name;
00140 argv[0] = migratepath;
00141 execvp(migratepath, argv);
00142
00143
00144
00145
00146 char *pathbuf = strdup(start_argv[0]);
00147 char *dir = dirname(pathbuf);
00148 asprintf(&migratepath, "%s/%s", dir, name);
00149 argv[0] = migratepath;
00150 execvp(migratepath, argv);
00151
00152 #if defined(__linux__)
00153
00154 char buffer[BUFSIZ];
00155 if (readlink("/proc/self/exe", buffer, BUFSIZ) == -1) {
00156 warn("could not read /proc/self/exe");
00157 exit(1);
00158 }
00159 dir = dirname(buffer);
00160 asprintf(&migratepath, "%s/%s", dir, name);
00161 argv[0] = migratepath;
00162 execvp(migratepath, argv);
00163 #endif
00164
00165 warn("Could not start %s", name);
00166 exit(2);
00167 }
00168
00169
00170
00171
00172
00173
00174 void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_message) {
00175 xcb_generic_error_t *error = xcb_request_check(conn, cookie);
00176 if (error != NULL) {
00177 fprintf(stderr, "ERROR: %s (X error %d)\n", err_message , error->error_code);
00178 xcb_disconnect(conn);
00179 exit(-1);
00180 }
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190 char *convert_utf8_to_ucs2(char *input, int *real_strlen) {
00191 size_t input_size = strlen(input) + 1;
00192
00193 int buffer_size = input_size * 2;
00194
00195 char *buffer = smalloc(buffer_size);
00196 size_t output_size = buffer_size;
00197
00198 char *output = buffer;
00199
00200
00201 if (conversion_descriptor == 0) {
00202 conversion_descriptor = iconv_open("UCS-2BE", "UTF-8");
00203 if (conversion_descriptor == 0) {
00204 fprintf(stderr, "error opening the conversion context\n");
00205 exit(1);
00206 }
00207 }
00208
00209
00210 iconv(conversion_descriptor, NULL, NULL, NULL, NULL);
00211
00212
00213 int rc = iconv(conversion_descriptor, (void*)&input, &input_size, &output, &output_size);
00214 if (rc == (size_t)-1) {
00215 perror("Converting to UCS-2 failed");
00216 if (real_strlen != NULL)
00217 *real_strlen = 0;
00218 return NULL;
00219 }
00220
00221 if (real_strlen != NULL)
00222 *real_strlen = ((buffer_size - output_size) / 2) - 1;
00223
00224 return buffer;
00225 }
00226
00227
00228
00229
00230
00231
00232
00233 char *resolve_tilde(const char *path) {
00234 static glob_t globbuf;
00235 char *head, *tail, *result;
00236
00237 tail = strchr(path, '/');
00238 head = strndup(path, tail ? tail - path : strlen(path));
00239
00240 int res = glob(head, GLOB_TILDE, NULL, &globbuf);
00241 free(head);
00242
00243 if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
00244 result = sstrdup(path);
00245 else if (res != 0) {
00246 die("glob() failed");
00247 } else {
00248 head = globbuf.gl_pathv[0];
00249 result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
00250 strncpy(result, head, strlen(head));
00251 if (tail)
00252 strncat(result, tail, strlen(tail));
00253 }
00254 globfree(&globbuf);
00255
00256 return result;
00257 }
00258
00259
00260
00261
00262
00263 bool path_exists(const char *path) {
00264 struct stat buf;
00265 return (stat(path, &buf) == 0);
00266 }
00267
00268
00269
00270
00271
00272
00273
00274 static char **append_argument(char **original, char *argument) {
00275 int num_args;
00276 for (num_args = 0; original[num_args] != NULL; num_args++) {
00277 DLOG("original argument: \"%s\"\n", original[num_args]);
00278
00279 if (strcmp(original[num_args], argument) == 0)
00280 return original;
00281 }
00282
00283 char **result = smalloc((num_args+2) * sizeof(char*));
00284 memcpy(result, original, num_args * sizeof(char*));
00285 result[num_args] = argument;
00286 result[num_args+1] = NULL;
00287
00288 return result;
00289 }
00290
00291
00292
00293
00294
00295 char *get_process_filename(const char *prefix) {
00296 char *dir = getenv("XDG_RUNTIME_DIR");
00297 if (dir == NULL) {
00298 struct passwd *pw = getpwuid(getuid());
00299 const char *username = pw ? pw->pw_name : "unknown";
00300 if (asprintf(&dir, "/tmp/i3-%s", username) == -1) {
00301 perror("asprintf()");
00302 return NULL;
00303 }
00304 } else {
00305 char *tmp;
00306 if (asprintf(&tmp, "%s/i3", dir) == -1) {
00307 perror("asprintf()");
00308 return NULL;
00309 }
00310 dir = tmp;
00311 }
00312 if (!path_exists(dir)) {
00313 if (mkdir(dir, 0700) == -1) {
00314 perror("mkdir()");
00315 return NULL;
00316 }
00317 }
00318 char *filename;
00319 if (asprintf(&filename, "%s/%s.%d", dir, prefix, getpid()) == -1) {
00320 perror("asprintf()");
00321 filename = NULL;
00322 }
00323
00324 free(dir);
00325 return filename;
00326 }
00327
00328 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
00329 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
00330
00331 char *store_restart_layout() {
00332 setlocale(LC_NUMERIC, "C");
00333 #if YAJL_MAJOR >= 2
00334 yajl_gen gen = yajl_gen_alloc(NULL);
00335 #else
00336 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
00337 #endif
00338
00339 dump_node(gen, croot, true);
00340
00341 setlocale(LC_NUMERIC, "");
00342
00343 const unsigned char *payload;
00344 #if YAJL_MAJOR >= 2
00345 size_t length;
00346 #else
00347 unsigned int length;
00348 #endif
00349 y(get_buf, &payload, &length);
00350
00351
00352
00353 char *filename;
00354 if (config.restart_state_path == NULL) {
00355 filename = get_process_filename("restart-state");
00356 if (!filename)
00357 return NULL;
00358 } else {
00359 filename = resolve_tilde(config.restart_state_path);
00360 }
00361
00362 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
00363 if (fd == -1) {
00364 perror("open()");
00365 free(filename);
00366 return NULL;
00367 }
00368
00369 int written = 0;
00370 while (written < length) {
00371 int n = write(fd, payload + written, length - written);
00372
00373 if (n == -1) {
00374 perror("write()");
00375 free(filename);
00376 return NULL;
00377 }
00378 if (n == 0) {
00379 printf("write == 0?\n");
00380 free(filename);
00381 return NULL;
00382 }
00383 written += n;
00384 #if YAJL_MAJOR >= 2
00385 printf("written: %d of %zd\n", written, length);
00386 #else
00387 printf("written: %d of %d\n", written, length);
00388 #endif
00389 }
00390 close(fd);
00391
00392 if (length > 0) {
00393 printf("layout: %.*s\n", (int)length, payload);
00394 }
00395
00396 y(free);
00397
00398 return filename;
00399 }
00400
00401
00402
00403
00404
00405
00406 void i3_restart(bool forget_layout) {
00407 char *restart_filename = forget_layout ? NULL : store_restart_layout();
00408
00409 kill_configerror_nagbar(true);
00410
00411 restore_geometry();
00412
00413 ipc_shutdown();
00414
00415 LOG("restarting \"%s\"...\n", start_argv[0]);
00416
00417 start_argv = append_argument(start_argv, "-a");
00418
00419
00420 if (restart_filename != NULL) {
00421
00422 int num_args;
00423 for (num_args = 0; start_argv[num_args] != NULL; num_args++);
00424 char **new_argv = scalloc((num_args + 3) * sizeof(char*));
00425
00426
00427 int write_index = 0;
00428 bool skip_next = false;
00429 for (int i = 0; i < num_args; ++i) {
00430 if (skip_next)
00431 skip_next = false;
00432 else if (!strcmp(start_argv[i], "-r") ||
00433 !strcmp(start_argv[i], "--restart"))
00434 skip_next = true;
00435 else
00436 new_argv[write_index++] = start_argv[i];
00437 }
00438
00439
00440 new_argv[write_index++] = "--restart";
00441 new_argv[write_index] = restart_filename;
00442
00443
00444 start_argv = new_argv;
00445 }
00446
00447 execvp(start_argv[0], start_argv);
00448
00449 }
00450
00451 #if defined(__OpenBSD__) || defined(__APPLE__)
00452
00453
00454
00455
00456
00457
00458 void *memmem(const void *l, size_t l_len, const void *s, size_t s_len) {
00459 register char *cur, *last;
00460 const char *cl = (const char *)l;
00461 const char *cs = (const char *)s;
00462
00463
00464 if (l_len == 0 || s_len == 0)
00465 return NULL;
00466
00467
00468 if (l_len < s_len)
00469 return NULL;
00470
00471
00472 if (s_len == 1)
00473 return memchr(l, (int)*cs, l_len);
00474
00475
00476 last = (char *)cl + l_len - s_len;
00477
00478 for (cur = (char *)cl; cur <= last; cur++)
00479 if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
00480 return cur;
00481
00482 return NULL;
00483 }
00484
00485 #endif
00486
00487 #if defined(__APPLE__)
00488
00489
00490
00491
00492
00493
00494
00495 char *strndup(const char *str, size_t n) {
00496 size_t len;
00497 char *copy;
00498
00499 for (len = 0; len < n && str[len]; len++)
00500 continue;
00501
00502 if ((copy = malloc(len + 1)) == NULL)
00503 return (NULL);
00504 memcpy(copy, str, len);
00505 copy[len] = '\0';
00506 return (copy);
00507 }
00508
00509 #endif