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;
70 sasprintf(&filename,
"%s/i3-backtrace.%d.%d.txt", tmpdir, pid_parent, suffix);
72 }
while (stat(filename, &bt) == 0);
74 pid_t pid_gdb = fork();
76 DLOG(
"Failed to fork for GDB\n");
78 }
else if (pid_gdb == 0) {
83 if (pipe(stdin_pipe) == -1) {
84 ELOG(
"Failed to init stdin_pipe\n");
87 if (pipe(stdout_pipe) == -1) {
88 ELOG(
"Failed to init stdout_pipe\n");
102 dup2(stdin_pipe[0], STDIN_FILENO);
103 dup2(stdout_pipe[1], STDOUT_FILENO);
105 char *pid_s, *gdb_log_cmd;
107 sasprintf(&gdb_log_cmd,
"set logging file %s", filename);
117 "-ex",
"set logging on",
121 execvp(args[0], args);
122 DLOG(
"Failed to exec GDB\n");
127 waitpid(pid_gdb, &status, 0);
130 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
131 DLOG(
"GDB did not run properly\n");
133 }
else if (stat(filename, &bt) == -1) {
134 DLOG(
"GDB executed successfully, but no backtrace was generated\n");
145 message_intro =
i3string_from_utf8(
"i3 has just crashed. Please report a bug for this.");
146 message_intro2 =
i3string_from_utf8(
"To debug this problem, you can either attach gdb or choose from the following options:");
147 message_option_backtrace =
i3string_from_utf8(
"- 'b' to save a backtrace (requires gdb)");
149 message_option_forget =
i3string_from_utf8(
"- 'f' to forget the previous layout and restart i3");
153 dialog_width = width_longest_message + 2 * border_width + 2 * margin;
154 dialog_height = num_lines *
config.
font.
height + 2 * border_width + 2 * margin;
169 xcb_create_colormap(
conn, XCB_COLORMAP_ALLOC_NONE, dialog->
colormap,
root, visual);
176 mask |= XCB_CW_BACK_PIXEL;
180 mask |= XCB_CW_BORDER_PIXEL;
183 mask |= XCB_CW_OVERRIDE_REDIRECT;
187 mask |= XCB_CW_COLORMAP;
206 xcb_grab_keyboard(
conn,
false, dialog->
id, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
209 xcb_grab_pointer(
conn,
false, dialog->
id, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, dialog->
id,
210 XCB_NONE, XCB_CURRENT_TIME);
223 xcb_destroy_window(
conn, dialog->
id);
251 int y = border_width + margin;
252 const int x = border_width + margin;
253 const int max_width = dialog->
dims.
width - 2 *
x;
261 char *bt_color =
"#FFFFFF";
262 if (backtrace_done < 0) {
263 bt_color =
"#AA0000";
264 }
else if (backtrace_done > 0) {
265 bt_color =
"#00AA00";
278 uint16_t
state =
event->state;
285 xcb_keysym_t sym = xcb_key_press_lookup_keysym(
keysyms, event, state);
288 DLOG(
"User issued core-dump command.\n");
292 backtrace_done = sighandler_backtrace();
294 }
else if (sym ==
'r') {
297 }
else if (sym ==
'f') {
304 DLOG(
"i3 crashed. SIG: %d\n", sig);
306 struct sigaction action;
307 action.sa_handler = SIG_DFL;
309 sigemptyset(&action.sa_mask);
310 sigaction(sig, &action, NULL);
316 xcb_generic_event_t *event;
318 while ((event = xcb_wait_for_event(
conn))) {
320 int type = (
event->response_type & 0x7F);
326 if (((xcb_expose_event_t *)event)->count == 0) {
343 struct sigaction action;
346 action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
347 sigemptyset(&action.sa_mask);
350 if (sigaction(SIGQUIT, &action, NULL) == -1 ||
351 sigaction(SIGILL, &action, NULL) == -1 ||
352 sigaction(SIGABRT, &action, NULL) == -1 ||
353 sigaction(SIGFPE, &action, NULL) == -1 ||
354 sigaction(SIGSEGV, &action, NULL) == -1)
355 ELOG(
"Could not setup signal handler.\n");
struct _i3String i3String
Opaque data structure for storing strings.
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...
struct outputs_head outputs
#define TAILQ_HEAD_INITIALIZER(head)
color_t draw_util_hex_to_color(const char *color)
Parses the given color in hex format to an internal color representation.
static void sighandler_draw_dialog(dialog_t *dialog)
#define TAILQ_EMPTY(head)
i3String * i3string_from_utf8(const char *from_utf8)
Build an i3String from an UTF-8 encoded string.
xcb_connection_t * conn
XCB connection and root screen.
#define TAILQ_INSERT_TAIL(head, elm, field)
void draw_util_clear_surface(surface_t *surface, color_t color)
Clears a surface with the given color.
xcb_screen_t * root_screen
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...
int predict_text_width(i3String *text)
Predict the text width in pixels for the given text.
int height
The height of the font, built from font_ascent + font_descent.
xcb_visualid_t get_visualid_by_depth(uint16_t depth)
Get visualid with specified depth.
xcb_visualtype_t * get_visualtype_by_id(xcb_visualid_t visual_id)
Get visual type specified by visualid.
static void sighandler_handle_key_press(xcb_key_press_event_t *event)
static void sighandler_destroy_dialogs(void)
#define TAILQ_FOREACH(var, head, field)
#define TAILQ_FIRST(head)
void handle_signal(int sig, siginfo_t *info, void *data)
static TAILQ_HEAD(dialogs_head, dialog_t)
#define TAILQ_REMOVE(head, elm, field)
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
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...
void draw_util_surface_free(xcb_connection_t *conn, surface_t *surface)
Destroys the surface.
An Output is a physical output on your graphics driver.
int logical_px(const int logical)
Convert a logical amount of pixels (e.g.
static void sighandler_create_dialogs(void)
void i3_restart(bool forget_layout)
Restart i3 in-place appends -a to argument list to disable autostart.
unsigned int xcb_numlock_mask
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.
static void sighandler_handle_expose(void)
#define TAILQ_ENTRY(type)
Rect rect
x, y, width, height
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.
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)