15 #include <xcb/xcb_event.h> 17 #include <X11/keysym.h> 30 static
int raised_signal;
31 static
int backtrace_done = 0;
33 static
int sighandler_backtrace(
void);
43 static
i3String *message_option_backtrace;
44 static
i3String *message_option_restart;
45 static
i3String *message_option_forget;
46 static
int dialog_width;
47 static
int dialog_height;
49 static
int border_width = 2;
50 static
int margin = 4;
56 static
int sighandler_backtrace(
void) {
57 char *tmpdir = getenv(
"TMPDIR");
61 pid_t pid_parent = getpid();
63 char *filename = NULL;
69 sasprintf(&filename,
"%s/i3-backtrace.%d.%d.txt", tmpdir, pid_parent, suffix);
73 pid_t pid_gdb = fork();
75 DLOG(
"Failed to fork for GDB\n");
77 }
else if (pid_gdb == 0) {
82 if (pipe(stdin_pipe) == -1) {
83 ELOG(
"Failed to init stdin_pipe\n");
86 if (pipe(stdout_pipe) == -1) {
87 ELOG(
"Failed to init stdout_pipe\n");
101 dup2(stdin_pipe[0], STDIN_FILENO);
102 dup2(stdout_pipe[1], STDOUT_FILENO);
104 char *pid_s, *gdb_log_cmd;
106 sasprintf(&gdb_log_cmd,
"set logging file %s", filename);
116 "-ex",
"set logging on",
120 execvp(args[0], args);
121 DLOG(
"Failed to exec GDB\n");
126 waitpid(pid_gdb, &status, 0);
129 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
130 DLOG(
"GDB did not run properly\n");
133 DLOG(
"GDB executed successfully, but no backtrace was generated\n");
144 message_intro =
i3string_from_utf8(
"i3 has just crashed. Please report a bug for this.");
145 message_intro2 =
i3string_from_utf8(
"To debug this problem, you can either attach gdb or choose from the following options:");
146 message_option_backtrace =
i3string_from_utf8(
"- 'b' to save a backtrace (requires gdb)");
148 message_option_forget =
i3string_from_utf8(
"- 'f' to forget the previous layout and restart i3");
152 dialog_width = width_longest_message + 2 * border_width + 2 * margin;
153 dialog_height = num_lines *
config.
font.
height + 2 * border_width + 2 * margin;
168 xcb_create_colormap(
conn, XCB_COLORMAP_ALLOC_NONE, dialog->
colormap,
root, visual);
175 mask |= XCB_CW_BACK_PIXEL;
179 mask |= XCB_CW_BORDER_PIXEL;
182 mask |= XCB_CW_OVERRIDE_REDIRECT;
186 mask |= XCB_CW_COLORMAP;
205 xcb_grab_keyboard(
conn,
false, dialog->
id, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
208 xcb_grab_pointer(
conn,
false, dialog->
id, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, dialog->
id,
209 XCB_NONE, XCB_CURRENT_TIME);
222 xcb_destroy_window(
conn, dialog->
id);
250 int y = border_width + margin;
251 const int x = border_width + margin;
252 const int max_width = dialog->
dims.
width - 2 *
x;
260 char *bt_color =
"#FFFFFF";
261 if (backtrace_done < 0) {
262 bt_color =
"#AA0000";
263 }
else if (backtrace_done > 0) {
264 bt_color =
"#00AA00";
277 uint16_t
state =
event->state;
284 xcb_keysym_t sym = xcb_key_press_lookup_keysym(
keysyms, event,
state);
287 DLOG(
"User issued core-dump command.\n");
291 backtrace_done = sighandler_backtrace();
293 }
else if (sym ==
'r') {
296 }
else if (sym ==
'f') {
303 DLOG(
"i3 crashed. SIG: %d\n", sig);
305 struct sigaction action;
306 action.sa_handler = SIG_DFL;
308 sigemptyset(&action.sa_mask);
309 sigaction(sig, &action, NULL);
315 xcb_generic_event_t *event;
317 while ((event = xcb_wait_for_event(
conn))) {
319 int type = (
event->response_type & 0x7F);
325 if (((xcb_expose_event_t *)event)->count == 0) {
342 struct sigaction action;
345 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
346 sigemptyset(&action.sa_mask);
349 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
350 sigaction(SIGILL, &action, NULL) == -1 ||
351 sigaction(SIGABRT, &action, NULL) == -1 ||
352 sigaction(SIGFPE, &action, NULL) == -1 ||
353 sigaction(SIGSEGV, &action, NULL) == -1)
354 ELOG(
"Could not setup signal handler.\n");
struct outputs_head outputs
void draw_util_surface_free(xcb_connection_t *conn, surface_t *surface)
Destroys the surface.
int logical_px(const int logical)
Convert a logical amount of pixels (e.g.
static void sighandler_draw_dialog(dialog_t *dialog)
#define TAILQ_EMPTY(head)
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
xcb_connection_t * conn
XCB connection and root screen.
void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_t bg_color, int x, int y, int max_width)
Draw the given text using libi3.
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
xcb_screen_t * root_screen
Stores a rectangle, for example the size of a window, the child window etc.
void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable, xcb_visualtype_t *visual, int width, int height)
Initialize the surface to represent the given drawable.
void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h)
Draws a filled rectangle.
#define TAILQ_REMOVE(head, elm, field)
static void sighandler_handle_key_press(xcb_key_press_event_t *event)
#define TAILQ_FIRST(head)
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
static void sighandler_destroy_dialogs(void)
static void handle_signal(int sig, siginfo_t *info, void *data)
static TAILQ_HEAD(dialogs_head, dialog_t)
#define TAILQ_ENTRY(type)
static void sighandler_setup(void)
void setup_signal_handler(void)
Configured a signal handler to gracefully handle crashes and allow the user to generate a backtrace a...
xcb_key_symbols_t * keysyms
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)
xcb_visualid_t get_visualid_by_depth(uint16_t depth)
Get visualid with specified depth.
struct _i3String i3String
Opaque data structure for storing strings.
xcb_visualtype_t * get_visualtype_by_id(xcb_visualid_t visual_id)
Get visual type specified by visualid.
unsigned int xcb_numlock_mask
An Output is a physical output on your graphics driver.
color_t draw_util_hex_to_color(const char *color)
Parses the given color in hex format to an internal color representation.
void draw_util_clear_surface(surface_t *surface, color_t color)
Clears a surface with the given color.
static void sighandler_create_dialogs(void)
int height
The height of the font, built from font_ascent + font_descent.
i3String * i3string_from_utf8(const char *from_utf8)
Build an i3String from an UTF-8 encoded string.
void i3_restart(bool forget_layout)
Restart i3 in-place appends -a to argument list to disable autostart.
static void sighandler_handle_expose(void)
xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t depth, xcb_visualid_t visual, uint16_t window_class, enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values)
Convenience wrapper around xcb_create_window which takes care of depth, generating an ID and checking...
#define TAILQ_HEAD_INITIALIZER(head)
#define TAILQ_INSERT_TAIL(head, elm, field)
int predict_text_width(i3String *text)
Predict the text width in pixels for the given text.
#define TAILQ_FOREACH(var, head, field)
Rect rect
x, y, width, height