diff --git a/CHANGELOG.md b/CHANGELOG.md index 7469d224..98241f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed - Dragging a tiled window to another display using the mouse will cause the window to be warped to that display upon release [#103](https://github.com/koekeishiya/yabai/issues/103) - Make loading scripting-addition more robust - validating version and functionality [#108](https://github.com/koekeishiya/yabai/issues/108) +- Escape quotes in window titles returned through query commands [#114](https://github.com/koekeishiya/yabai/issues/114) ## [1.0.6] - 2019-07-09 ### Changed diff --git a/src/misc/helpers.h b/src/misc/helpers.h index 63ceba0e..0b44427c 100644 --- a/src/misc/helpers.h +++ b/src/misc/helpers.h @@ -51,6 +51,33 @@ static inline bool string_equals(const char *a, const char *b) return a && b && strcmp(a, b) == 0; } +static inline char *string_escape_quote(char *s) +{ + if (!s) return NULL; + + bool found_quote = false; + for (char *cursor = s; *cursor; ++cursor) { + if (*cursor == '"') { + found_quote = true; + break; + } + } + + if (!found_quote) return NULL; + + int size = sizeof(char) * (2*strlen(s)); + char *result = malloc(size); + char *dst = result; + memset(result, 0, size); + + for (char *cursor = s; *cursor; ++cursor) { + if (*cursor == '"') *dst++ = '\\'; + *dst++ = *cursor; + } + + return result; +} + static CFArrayRef cfarray_of_cfnumbers(void *values, size_t size, int count, CFNumberType type) { CFNumberRef *temp = malloc(sizeof(CFNumberRef) * count); diff --git a/src/window.c b/src/window.c index d981b44c..a7eb8d88 100644 --- a/src/window.c +++ b/src/window.c @@ -108,11 +108,13 @@ uint64_t *window_space_list(struct window *window, int *count) void window_serialize(struct window *window, FILE *rsp) { - CGRect frame = window_frame(window); char *title = window_title(window); + char *escaped_title = string_escape_quote(title); + CGRect frame = window_frame(window); char *role = NULL; char *subrole = NULL; + CFStringRef cfrole = window_role(window); if (cfrole) { role = cfstring_copy(cfrole); @@ -156,7 +158,7 @@ void window_serialize(struct window *window, FILE *rsp) window->id, window->application->pid, window->application->name, - title ? title : "", + escaped_title ? escaped_title : title ? title : "", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, window_level(window), @@ -175,6 +177,7 @@ void window_serialize(struct window *window, FILE *rsp) if (subrole) free(subrole); if (role) free(role); if (title) free(title); + if (escaped_title) free(escaped_title); } char *window_title(struct window *window)