gri3-wm/src/ipc.c

1698 lines
44 KiB
C
Raw Normal View History

/*
2010-11-21 22:03:55 +01:00
* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
* © 2009 Michael Stapelberg and contributors (see also: LICENSE)
*
* ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
*
*/
#include "all.h"
#include "yajl_utils.h"
#include <ev.h>
#include <fcntl.h>
#include <libgen.h>
Remove some includes from all.h Also removes duplicates from other headers All used std* imports are included once in all.h for easy use - getopt: Only used in main.c and inject_randr1.5.c - glob: Not used in i3, only in i3bar & libi3 - inttypes: Only used in util.c - locale: A bit specific for all.h - math: Slow according to #4022 - unistd: I feel it's good to explicitly include per file that needs it - yajl: Specific to yajl_utils.h and ipc.h Related to #4022 Timing before: ``` Analyzing build trace from ... **** Time summary: Compilation (81 times): Parsing (frontend): 51.3 s Codegen & opts (backend): 7.7 s **** Files that took longest to parse (compiler frontend): 1254 ms: build/src/i3-commands.o 972 ms: build/src/i3-resize.o 945 ms: build/src/i3-con.o 921 ms: build/src/i3-scratchpad.o 907 ms: build/src/i3-main.o 904 ms: build/src/i3-handlers.o 904 ms: build/src/i3-config_directives.o 893 ms: build/src/i3-restore_layout.o 875 ms: build/src/i3-x.o 854 ms: build/src/i3-ipc.o **** Files that took longest to codegen (compiler backend): 863 ms: build/src/i3-commands.o 471 ms: build/i3bar/src/i3bar-xcb.o 377 ms: build/src/i3-con.o 360 ms: build/src/i3-ipc.o 306 ms: build/src/i3-x.o 290 ms: build/src/i3-main.o 238 ms: build/src/i3-config_parser.o 237 ms: build/src/i3-handlers.o 220 ms: build/i3-config-wizard/i3_config_wizard-main.o 214 ms: build/src/i3-bindings.o **** Functions that took longest to compile: 209 ms: main (../../i3/src/main.c) 95 ms: manage_window (../../i3/src/manage.c) 57 ms: reconfig_windows (../../i3/i3bar/src/xcb.c) 55 ms: x_draw_decoration (../../i3/src/x.c) 49 ms: x_push_node (../../i3/src/x.c) 48 ms: handle_client_message (../../i3/src/handlers.c) 48 ms: dump_node (../../i3/src/ipc.c) 47 ms: GENERATED_call (../../i3/src/config_parser.c) 45 ms: config_string_cb (../../i3/i3bar/src/config.c) 44 ms: GENERATED_call (../../i3/src/commands_parser.c) 42 ms: floating_check_size (../../i3/src/floating.c) 40 ms: con_swap (../../i3/src/con.c) 40 ms: parse_config (../../i3/src/config_parser.c) 39 ms: main (../../i3/i3-nagbar/main.c) 39 ms: cmd_rename_workspace (../../i3/src/commands.c) 38 ms: window_update_normal_hints (../../i3/src/window.c) 38 ms: cmd_swap (../../i3/src/commands.c) 37 ms: dump_bar_config (../../i3/src/ipc.c) 36 ms: translate_keysyms (../../i3/src/bindings.c) 35 ms: tree_close_internal (../../i3/src/tree.c) 34 ms: match_matches_window (../../i3/src/match.c) 34 ms: floating_enable (../../i3/src/floating.c) 34 ms: json_string (../../i3/src/load_layout.c) 33 ms: x_push_changes (../../i3/src/x.c) 33 ms: main (../../i3/i3-config-wizard/main.c) 31 ms: free_configuration (../../i3/src/config.c) 30 ms: parse_file (../../i3/src/config_parser.c) 28 ms: load_font (../../i3/libi3/font.c) 28 ms: handle_configure_request (../../i3/src/handlers.c) 28 ms: parse_command (../../i3/src/commands_parser.c) **** Function sets that took longest to compile / optimize: *** Expensive headers: 29287 ms: ../../i3/include/libi3.h (included 78 times, avg 375 ms), included via: i3-resize.o all.h data.h (576 ms) a-g_utf8_make_valid.o (491 ms) a-dpi.o (491 ms) a-get_colorpixel.o (483 ms) a-is_debug_build.o (478 ms) a-strndup.o (478 ms) ... 29221 ms: ../../i3/include/all.h (included 39 times, avg 749 ms), included via: i3-resize.o (946 ms) i3-scratchpad.o (895 ms) i3-restore_layout.o (865 ms) i3-handlers.o (839 ms) i3-drag.o (830 ms) i3-config_directives.o (793 ms) ... 5195 ms: /usr/include/xcb/xcb.h (included 79 times, avg 65 ms), included via: i3-handlers.o all.h (113 ms) i3-restore_layout.o all.h (108 ms) a-g_utf8_make_valid.o libi3.h (108 ms) i3bar-xcb.o common.h (105 ms) i3-scratchpad.o all.h (95 ms) a-get_colorpixel.o libi3.h (89 ms) ... 4100 ms: /usr/include/math.h (included 41 times, avg 100 ms), included via: i3-scratchpad.o all.h (180 ms) i3-fake_outputs.o all.h (138 ms) i3-regex.o all.h (130 ms) i3-restore_layout.o all.h (128 ms) i3-xcb.o all.h (121 ms) i3-move.o all.h (119 ms) ... 4046 ms: ../../i3/i3bar/include/common.h (included 9 times, avg 449 ms), included via: i3bar-main.o (503 ms) i3bar-xcb.o (501 ms) i3bar-workspaces.o (472 ms) i3bar-parse_json_header.o (446 ms) i3bar-child.o (438 ms) i3bar-ipc.o (434 ms) ... 2713 ms: ../../i3/include/i3.h (included 41 times, avg 66 ms), included via: i3-xcursor.o (450 ms) i3-config_directives.o all.h ipc.h configuration.h (87 ms) i3-config.o all.h ipc.h configuration.h (71 ms) i3-manage.o all.h ipc.h configuration.h (70 ms) i3-window.o all.h ipc.h configuration.h (68 ms) i3-x.o all.h ipc.h configuration.h (61 ms) ... 1492 ms: /usr/include/xcb/xkb.h (included 42 times, avg 35 ms), included via: i3-config_directives.o all.h ipc.h configuration.h i3.h (50 ms) i3-config.o all.h ipc.h configuration.h i3.h (45 ms) i3-window.o all.h ipc.h configuration.h i3.h (43 ms) i3-x.o all.h ipc.h configuration.h i3.h (42 ms) i3-manage.o all.h ipc.h configuration.h i3.h (41 ms) i3-config_parser.o all.h ipc.h configuration.h i3.h (38 ms) ... 1432 ms: /usr/include/stdlib.h (included 79 times, avg 18 ms), included via: i3-scratchpad.o all.h (48 ms) i3-restore_layout.o all.h (36 ms) i3-regex.o all.h (32 ms) i3-key_press.o all.h (28 ms) i3-commands.o all.h (28 ms) i3-bindings.o all.h (24 ms) ... 1349 ms: /usr/include/pthread.h (included 79 times, avg 17 ms), included via: i3bar-xcb.o common.h xcb.h (33 ms) a-ucs2_conversion.o libi3.h xcb.h (32 ms) i3-match.o all.h xcb.h (27 ms) i3-scratchpad.o all.h xcb.h (25 ms) a-g_utf8_make_valid.o libi3.h xcb.h (25 ms) i3_config_wizard-main.o xcb.h (24 ms) ... 1151 ms: /usr/include/X11/Xlib.h (included 45 times, avg 25 ms), included via: i3-output.o all.h data.h sn-launcher.h sn-common.h (50 ms) i3-config_parser.o all.h data.h sn-launcher.h sn-common.h (43 ms) i3-x.o all.h data.h sn-launcher.h sn-common.h (34 ms) i3-config_directives.o all.h data.h sn-launcher.h sn-common.h (32 ms) i3_config_wizard-main.o sn-launchee.h sn-common.h (30 ms) i3-drag.o all.h data.h sn-launcher.h sn-common.h (29 ms) ... ``` Timing after: ``` Analyzing build trace from ... **** Time summary: Compilation (81 times): Parsing (frontend): 47.6 s Codegen & opts (backend): 7.6 s **** Files that took longest to parse (compiler frontend): 1154 ms: build/src/i3-commands.o 929 ms: build/src/i3-display_version.o 852 ms: build/src/i3-bindings.o 847 ms: build/src/i3-con.o 806 ms: build/src/i3-ipc.o 801 ms: build/src/i3-floating.o 792 ms: build/src/i3-main.o 792 ms: build/src/i3-drag.o 792 ms: build/src/i3-window.o 776 ms: build/src/i3-config_directives.o **** Files that took longest to codegen (compiler backend): 885 ms: build/src/i3-commands.o 422 ms: build/i3bar/src/i3bar-xcb.o 382 ms: build/src/i3-con.o 348 ms: build/src/i3-x.o 288 ms: build/src/i3-ipc.o 268 ms: build/src/i3-handlers.o 254 ms: build/src/i3-main.o 251 ms: build/src/i3-floating.o 249 ms: build/src/i3-config_parser.o 194 ms: build/src/i3-randr.o **** Functions that took longest to compile: 186 ms: main (../../i3/src/main.c) 95 ms: manage_window (../../i3/src/manage.c) 65 ms: floating_check_size (../../i3/src/floating.c) 63 ms: x_draw_decoration (../../i3/src/x.c) 58 ms: handle_client_message (../../i3/src/handlers.c) 55 ms: x_push_node (../../i3/src/x.c) 54 ms: match_matches_window (../../i3/src/match.c) 51 ms: parse_config (../../i3/src/config_parser.c) 49 ms: dump_node (../../i3/src/ipc.c) 47 ms: reconfig_windows (../../i3/i3bar/src/xcb.c) 47 ms: config_string_cb (../../i3/i3bar/src/config.c) 45 ms: GENERATED_call (../../i3/src/config_parser.c) 45 ms: GENERATED_call (../../i3/src/commands_parser.c) 43 ms: floating_enable (../../i3/src/floating.c) 42 ms: handle_configure_request (../../i3/src/handlers.c) 40 ms: con_swap (../../i3/src/con.c) 36 ms: main (../../i3/i3-input/main.c) 36 ms: main (../../i3/i3-msg/main.c) 36 ms: main (../../i3/i3-nagbar/main.c) 36 ms: cmd_move_con_to_workspace_number (../../i3/src/commands.c) 35 ms: json_string (../../i3/src/load_layout.c) 35 ms: tree_restore (../../i3/src/tree.c) 35 ms: cmd_swap (../../i3/src/commands.c) 34 ms: x_push_changes (../../i3/src/x.c) 32 ms: main (../../i3/i3-config-wizard/main.c) 32 ms: ewmh_setup_hints (../../i3/src/ewmh.c) 31 ms: match_parse_property (../../i3/src/match.c) 30 ms: cmd_mark (../../i3/src/commands.c) 30 ms: translate_keysyms (../../i3/src/bindings.c) 30 ms: window_update_normal_hints (../../i3/src/window.c) **** Function sets that took longest to compile / optimize: *** Expensive headers: 29596 ms: ../../i3/include/libi3.h (included 78 times, avg 379 ms), included via: a-get_config_path.o (539 ms) i3_dump_log-main.o (522 ms) i3_config_wizard-main.o (501 ms) a-fake_configure_notify.o (500 ms) a-root_atom_contents.o (488 ms) i3-display_version.o all.h (466 ms) ... 26054 ms: ../../i3/include/all.h (included 41 times, avg 635 ms), included via: i3-display_version.o (901 ms) i3-drag.o (775 ms) i3-ewmh.o (703 ms) i3-startup.o (693 ms) i3-commands.o (687 ms) i3-xcb.o (680 ms) ... 5345 ms: /usr/include/xcb/xcb.h (included 79 times, avg 67 ms), included via: i3-display_version.o all.h (173 ms) i3_input-keysym2ucs.o keysym2ucs.h (106 ms) i3-ewmh.o all.h (106 ms) a-fake_configure_notify.o libi3.h (103 ms) a-get_config_path.o libi3.h (95 ms) i3bar-parse_json_header.o common.h (93 ms) ... 4127 ms: ../../i3/i3bar/include/common.h (included 9 times, avg 458 ms), included via: i3bar-child.o (524 ms) i3bar-mode.o (486 ms) i3bar-outputs.o (464 ms) i3bar-parse_json_header.o (463 ms) i3bar-config.o (457 ms) i3bar-ipc.o (448 ms) ... 1542 ms: /usr/include/xcb/xkb.h (included 42 times, avg 36 ms), included via: i3-con.o all.h ipc.h configuration.h i3.h (60 ms) i3-render.o all.h ipc.h configuration.h i3.h (56 ms) i3-bindings.o all.h ipc.h configuration.h i3.h (56 ms) i3-sighandler.o all.h ipc.h configuration.h i3.h (48 ms) i3-xcb.o all.h ipc.h configuration.h i3.h (47 ms) i3-resize.o all.h ipc.h configuration.h i3.h (39 ms) ... 1456 ms: /usr/include/stdlib.h (included 79 times, avg 18 ms), included via: i3-drag.o all.h (60 ms) i3-display_version.o all.h (55 ms) i3-fake_outputs.o all.h (39 ms) i3-config_directives.o all.h (33 ms) i3-xcursor.o all.h (30 ms) i3bar-mode.o common.h libi3.h pango.h pango-attributes.h pango-font.h pango-coverage.h glib-object.h gbinding.h glib.h gasyncqueue.h gthread.h gutils.h (29 ms) ... 1136 ms: /usr/include/X11/Xlib.h (included 44 times, avg 25 ms), included via: i3-con.o all.h data.h sn-launcher.h sn-common.h (35 ms) i3-resize.o all.h data.h sn-launcher.h sn-common.h (34 ms) i3-util.o all.h data.h sn-launcher.h sn-common.h (33 ms) i3-assignments.o all.h data.h sn-launcher.h sn-common.h (33 ms) i3-sighandler.o all.h data.h sn-launcher.h sn-common.h (31 ms) i3-xcb.o all.h data.h sn-launcher.h sn-common.h (31 ms) ... 808 ms: /usr/include/stdio.h (included 79 times, avg 10 ms), included via: i3-drag.o all.h (19 ms) i3-fake_outputs.o all.h (18 ms) a-font.o libi3.h (16 ms) i3bar-child.o common.h libi3.h (15 ms) a-safewrappers.o libi3.h (15 ms) a-ipc_send_message.o libi3.h (13 ms) ... 770 ms: /usr/include/xcb/randr.h (included 42 times, avg 18 ms), included via: i3-click.o all.h data.h (29 ms) i3-commands.o all.h data.h (27 ms) i3-assignments.o all.h data.h (25 ms) i3-xcb.o all.h data.h (21 ms) i3-resize.o all.h data.h (21 ms) i3-sighandler.o all.h data.h (20 ms) ... 688 ms: /usr/include/math.h (included 6 times, avg 114 ms), included via: a-dpi.o (145 ms) i3-render.o (127 ms) i3-floating.o (106 ms) a-root_atom_contents.o (106 ms) i3-window.o (102 ms) i3-bindings.o (99 ms) ... ```
2020-04-19 11:22:59 +02:00
#include <locale.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/un.h>
Remove some includes from all.h Also removes duplicates from other headers All used std* imports are included once in all.h for easy use - getopt: Only used in main.c and inject_randr1.5.c - glob: Not used in i3, only in i3bar & libi3 - inttypes: Only used in util.c - locale: A bit specific for all.h - math: Slow according to #4022 - unistd: I feel it's good to explicitly include per file that needs it - yajl: Specific to yajl_utils.h and ipc.h Related to #4022 Timing before: ``` Analyzing build trace from ... **** Time summary: Compilation (81 times): Parsing (frontend): 51.3 s Codegen & opts (backend): 7.7 s **** Files that took longest to parse (compiler frontend): 1254 ms: build/src/i3-commands.o 972 ms: build/src/i3-resize.o 945 ms: build/src/i3-con.o 921 ms: build/src/i3-scratchpad.o 907 ms: build/src/i3-main.o 904 ms: build/src/i3-handlers.o 904 ms: build/src/i3-config_directives.o 893 ms: build/src/i3-restore_layout.o 875 ms: build/src/i3-x.o 854 ms: build/src/i3-ipc.o **** Files that took longest to codegen (compiler backend): 863 ms: build/src/i3-commands.o 471 ms: build/i3bar/src/i3bar-xcb.o 377 ms: build/src/i3-con.o 360 ms: build/src/i3-ipc.o 306 ms: build/src/i3-x.o 290 ms: build/src/i3-main.o 238 ms: build/src/i3-config_parser.o 237 ms: build/src/i3-handlers.o 220 ms: build/i3-config-wizard/i3_config_wizard-main.o 214 ms: build/src/i3-bindings.o **** Functions that took longest to compile: 209 ms: main (../../i3/src/main.c) 95 ms: manage_window (../../i3/src/manage.c) 57 ms: reconfig_windows (../../i3/i3bar/src/xcb.c) 55 ms: x_draw_decoration (../../i3/src/x.c) 49 ms: x_push_node (../../i3/src/x.c) 48 ms: handle_client_message (../../i3/src/handlers.c) 48 ms: dump_node (../../i3/src/ipc.c) 47 ms: GENERATED_call (../../i3/src/config_parser.c) 45 ms: config_string_cb (../../i3/i3bar/src/config.c) 44 ms: GENERATED_call (../../i3/src/commands_parser.c) 42 ms: floating_check_size (../../i3/src/floating.c) 40 ms: con_swap (../../i3/src/con.c) 40 ms: parse_config (../../i3/src/config_parser.c) 39 ms: main (../../i3/i3-nagbar/main.c) 39 ms: cmd_rename_workspace (../../i3/src/commands.c) 38 ms: window_update_normal_hints (../../i3/src/window.c) 38 ms: cmd_swap (../../i3/src/commands.c) 37 ms: dump_bar_config (../../i3/src/ipc.c) 36 ms: translate_keysyms (../../i3/src/bindings.c) 35 ms: tree_close_internal (../../i3/src/tree.c) 34 ms: match_matches_window (../../i3/src/match.c) 34 ms: floating_enable (../../i3/src/floating.c) 34 ms: json_string (../../i3/src/load_layout.c) 33 ms: x_push_changes (../../i3/src/x.c) 33 ms: main (../../i3/i3-config-wizard/main.c) 31 ms: free_configuration (../../i3/src/config.c) 30 ms: parse_file (../../i3/src/config_parser.c) 28 ms: load_font (../../i3/libi3/font.c) 28 ms: handle_configure_request (../../i3/src/handlers.c) 28 ms: parse_command (../../i3/src/commands_parser.c) **** Function sets that took longest to compile / optimize: *** Expensive headers: 29287 ms: ../../i3/include/libi3.h (included 78 times, avg 375 ms), included via: i3-resize.o all.h data.h (576 ms) a-g_utf8_make_valid.o (491 ms) a-dpi.o (491 ms) a-get_colorpixel.o (483 ms) a-is_debug_build.o (478 ms) a-strndup.o (478 ms) ... 29221 ms: ../../i3/include/all.h (included 39 times, avg 749 ms), included via: i3-resize.o (946 ms) i3-scratchpad.o (895 ms) i3-restore_layout.o (865 ms) i3-handlers.o (839 ms) i3-drag.o (830 ms) i3-config_directives.o (793 ms) ... 5195 ms: /usr/include/xcb/xcb.h (included 79 times, avg 65 ms), included via: i3-handlers.o all.h (113 ms) i3-restore_layout.o all.h (108 ms) a-g_utf8_make_valid.o libi3.h (108 ms) i3bar-xcb.o common.h (105 ms) i3-scratchpad.o all.h (95 ms) a-get_colorpixel.o libi3.h (89 ms) ... 4100 ms: /usr/include/math.h (included 41 times, avg 100 ms), included via: i3-scratchpad.o all.h (180 ms) i3-fake_outputs.o all.h (138 ms) i3-regex.o all.h (130 ms) i3-restore_layout.o all.h (128 ms) i3-xcb.o all.h (121 ms) i3-move.o all.h (119 ms) ... 4046 ms: ../../i3/i3bar/include/common.h (included 9 times, avg 449 ms), included via: i3bar-main.o (503 ms) i3bar-xcb.o (501 ms) i3bar-workspaces.o (472 ms) i3bar-parse_json_header.o (446 ms) i3bar-child.o (438 ms) i3bar-ipc.o (434 ms) ... 2713 ms: ../../i3/include/i3.h (included 41 times, avg 66 ms), included via: i3-xcursor.o (450 ms) i3-config_directives.o all.h ipc.h configuration.h (87 ms) i3-config.o all.h ipc.h configuration.h (71 ms) i3-manage.o all.h ipc.h configuration.h (70 ms) i3-window.o all.h ipc.h configuration.h (68 ms) i3-x.o all.h ipc.h configuration.h (61 ms) ... 1492 ms: /usr/include/xcb/xkb.h (included 42 times, avg 35 ms), included via: i3-config_directives.o all.h ipc.h configuration.h i3.h (50 ms) i3-config.o all.h ipc.h configuration.h i3.h (45 ms) i3-window.o all.h ipc.h configuration.h i3.h (43 ms) i3-x.o all.h ipc.h configuration.h i3.h (42 ms) i3-manage.o all.h ipc.h configuration.h i3.h (41 ms) i3-config_parser.o all.h ipc.h configuration.h i3.h (38 ms) ... 1432 ms: /usr/include/stdlib.h (included 79 times, avg 18 ms), included via: i3-scratchpad.o all.h (48 ms) i3-restore_layout.o all.h (36 ms) i3-regex.o all.h (32 ms) i3-key_press.o all.h (28 ms) i3-commands.o all.h (28 ms) i3-bindings.o all.h (24 ms) ... 1349 ms: /usr/include/pthread.h (included 79 times, avg 17 ms), included via: i3bar-xcb.o common.h xcb.h (33 ms) a-ucs2_conversion.o libi3.h xcb.h (32 ms) i3-match.o all.h xcb.h (27 ms) i3-scratchpad.o all.h xcb.h (25 ms) a-g_utf8_make_valid.o libi3.h xcb.h (25 ms) i3_config_wizard-main.o xcb.h (24 ms) ... 1151 ms: /usr/include/X11/Xlib.h (included 45 times, avg 25 ms), included via: i3-output.o all.h data.h sn-launcher.h sn-common.h (50 ms) i3-config_parser.o all.h data.h sn-launcher.h sn-common.h (43 ms) i3-x.o all.h data.h sn-launcher.h sn-common.h (34 ms) i3-config_directives.o all.h data.h sn-launcher.h sn-common.h (32 ms) i3_config_wizard-main.o sn-launchee.h sn-common.h (30 ms) i3-drag.o all.h data.h sn-launcher.h sn-common.h (29 ms) ... ``` Timing after: ``` Analyzing build trace from ... **** Time summary: Compilation (81 times): Parsing (frontend): 47.6 s Codegen & opts (backend): 7.6 s **** Files that took longest to parse (compiler frontend): 1154 ms: build/src/i3-commands.o 929 ms: build/src/i3-display_version.o 852 ms: build/src/i3-bindings.o 847 ms: build/src/i3-con.o 806 ms: build/src/i3-ipc.o 801 ms: build/src/i3-floating.o 792 ms: build/src/i3-main.o 792 ms: build/src/i3-drag.o 792 ms: build/src/i3-window.o 776 ms: build/src/i3-config_directives.o **** Files that took longest to codegen (compiler backend): 885 ms: build/src/i3-commands.o 422 ms: build/i3bar/src/i3bar-xcb.o 382 ms: build/src/i3-con.o 348 ms: build/src/i3-x.o 288 ms: build/src/i3-ipc.o 268 ms: build/src/i3-handlers.o 254 ms: build/src/i3-main.o 251 ms: build/src/i3-floating.o 249 ms: build/src/i3-config_parser.o 194 ms: build/src/i3-randr.o **** Functions that took longest to compile: 186 ms: main (../../i3/src/main.c) 95 ms: manage_window (../../i3/src/manage.c) 65 ms: floating_check_size (../../i3/src/floating.c) 63 ms: x_draw_decoration (../../i3/src/x.c) 58 ms: handle_client_message (../../i3/src/handlers.c) 55 ms: x_push_node (../../i3/src/x.c) 54 ms: match_matches_window (../../i3/src/match.c) 51 ms: parse_config (../../i3/src/config_parser.c) 49 ms: dump_node (../../i3/src/ipc.c) 47 ms: reconfig_windows (../../i3/i3bar/src/xcb.c) 47 ms: config_string_cb (../../i3/i3bar/src/config.c) 45 ms: GENERATED_call (../../i3/src/config_parser.c) 45 ms: GENERATED_call (../../i3/src/commands_parser.c) 43 ms: floating_enable (../../i3/src/floating.c) 42 ms: handle_configure_request (../../i3/src/handlers.c) 40 ms: con_swap (../../i3/src/con.c) 36 ms: main (../../i3/i3-input/main.c) 36 ms: main (../../i3/i3-msg/main.c) 36 ms: main (../../i3/i3-nagbar/main.c) 36 ms: cmd_move_con_to_workspace_number (../../i3/src/commands.c) 35 ms: json_string (../../i3/src/load_layout.c) 35 ms: tree_restore (../../i3/src/tree.c) 35 ms: cmd_swap (../../i3/src/commands.c) 34 ms: x_push_changes (../../i3/src/x.c) 32 ms: main (../../i3/i3-config-wizard/main.c) 32 ms: ewmh_setup_hints (../../i3/src/ewmh.c) 31 ms: match_parse_property (../../i3/src/match.c) 30 ms: cmd_mark (../../i3/src/commands.c) 30 ms: translate_keysyms (../../i3/src/bindings.c) 30 ms: window_update_normal_hints (../../i3/src/window.c) **** Function sets that took longest to compile / optimize: *** Expensive headers: 29596 ms: ../../i3/include/libi3.h (included 78 times, avg 379 ms), included via: a-get_config_path.o (539 ms) i3_dump_log-main.o (522 ms) i3_config_wizard-main.o (501 ms) a-fake_configure_notify.o (500 ms) a-root_atom_contents.o (488 ms) i3-display_version.o all.h (466 ms) ... 26054 ms: ../../i3/include/all.h (included 41 times, avg 635 ms), included via: i3-display_version.o (901 ms) i3-drag.o (775 ms) i3-ewmh.o (703 ms) i3-startup.o (693 ms) i3-commands.o (687 ms) i3-xcb.o (680 ms) ... 5345 ms: /usr/include/xcb/xcb.h (included 79 times, avg 67 ms), included via: i3-display_version.o all.h (173 ms) i3_input-keysym2ucs.o keysym2ucs.h (106 ms) i3-ewmh.o all.h (106 ms) a-fake_configure_notify.o libi3.h (103 ms) a-get_config_path.o libi3.h (95 ms) i3bar-parse_json_header.o common.h (93 ms) ... 4127 ms: ../../i3/i3bar/include/common.h (included 9 times, avg 458 ms), included via: i3bar-child.o (524 ms) i3bar-mode.o (486 ms) i3bar-outputs.o (464 ms) i3bar-parse_json_header.o (463 ms) i3bar-config.o (457 ms) i3bar-ipc.o (448 ms) ... 1542 ms: /usr/include/xcb/xkb.h (included 42 times, avg 36 ms), included via: i3-con.o all.h ipc.h configuration.h i3.h (60 ms) i3-render.o all.h ipc.h configuration.h i3.h (56 ms) i3-bindings.o all.h ipc.h configuration.h i3.h (56 ms) i3-sighandler.o all.h ipc.h configuration.h i3.h (48 ms) i3-xcb.o all.h ipc.h configuration.h i3.h (47 ms) i3-resize.o all.h ipc.h configuration.h i3.h (39 ms) ... 1456 ms: /usr/include/stdlib.h (included 79 times, avg 18 ms), included via: i3-drag.o all.h (60 ms) i3-display_version.o all.h (55 ms) i3-fake_outputs.o all.h (39 ms) i3-config_directives.o all.h (33 ms) i3-xcursor.o all.h (30 ms) i3bar-mode.o common.h libi3.h pango.h pango-attributes.h pango-font.h pango-coverage.h glib-object.h gbinding.h glib.h gasyncqueue.h gthread.h gutils.h (29 ms) ... 1136 ms: /usr/include/X11/Xlib.h (included 44 times, avg 25 ms), included via: i3-con.o all.h data.h sn-launcher.h sn-common.h (35 ms) i3-resize.o all.h data.h sn-launcher.h sn-common.h (34 ms) i3-util.o all.h data.h sn-launcher.h sn-common.h (33 ms) i3-assignments.o all.h data.h sn-launcher.h sn-common.h (33 ms) i3-sighandler.o all.h data.h sn-launcher.h sn-common.h (31 ms) i3-xcb.o all.h data.h sn-launcher.h sn-common.h (31 ms) ... 808 ms: /usr/include/stdio.h (included 79 times, avg 10 ms), included via: i3-drag.o all.h (19 ms) i3-fake_outputs.o all.h (18 ms) a-font.o libi3.h (16 ms) i3bar-child.o common.h libi3.h (15 ms) a-safewrappers.o libi3.h (15 ms) a-ipc_send_message.o libi3.h (13 ms) ... 770 ms: /usr/include/xcb/randr.h (included 42 times, avg 18 ms), included via: i3-click.o all.h data.h (29 ms) i3-commands.o all.h data.h (27 ms) i3-assignments.o all.h data.h (25 ms) i3-xcb.o all.h data.h (21 ms) i3-resize.o all.h data.h (21 ms) i3-sighandler.o all.h data.h (20 ms) ... 688 ms: /usr/include/math.h (included 6 times, avg 114 ms), included via: a-dpi.o (145 ms) i3-render.o (127 ms) i3-floating.o (106 ms) a-root_atom_contents.o (106 ms) i3-window.o (102 ms) i3-bindings.o (99 ms) ... ```
2020-04-19 11:22:59 +02:00
#include <unistd.h>
#include <yajl/yajl_gen.h>
#include <yajl/yajl_parse.h>
char *current_socketpath = NULL;
TAILQ_HEAD(ipc_client_head, ipc_client)
all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
/*
* Puts the given socket file descriptor into non-blocking mode or dies if
* setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our
* IPC model because we should by no means block the window manager.
*
*/
static void set_nonblock(int sockfd) {
2010-11-21 22:03:55 +01:00
int flags = fcntl(sockfd, F_GETFL, 0);
if (flags & O_NONBLOCK) {
return;
}
2010-11-21 22:03:55 +01:00
flags |= O_NONBLOCK;
if (fcntl(sockfd, F_SETFL, flags) < 0)
err(-1, "Could not set O_NONBLOCK");
}
static void ipc_client_timeout(EV_P_ ev_timer *w, int revents);
static void ipc_socket_writeable_cb(EV_P_ struct ev_io *w, int revents);
static ev_tstamp kill_timeout = 10.0;
void ipc_set_kill_timeout(ev_tstamp new) {
kill_timeout = new;
}
/*
* Try to write the contents of the pending buffer to the client's subscription
* socket. Will set, reset or clear the timeout and io write callbacks depending
* on the result of the write operation.
*
*/
static void ipc_push_pending(ipc_client *client) {
const ssize_t result = writeall_nonblock(client->fd, client->buffer, client->buffer_size);
if (result < 0) {
return;
}
if ((size_t)result == client->buffer_size) {
/* Everything was written successfully: clear the timer and stop the io
* callback. */
FREE(client->buffer);
client->buffer_size = 0;
if (client->timeout) {
ev_timer_stop(main_loop, client->timeout);
FREE(client->timeout);
}
ev_io_stop(main_loop, client->write_callback);
return;
}
/* Otherwise, make sure that the io callback is enabled and create a new
* timer if needed. */
ev_io_start(main_loop, client->write_callback);
if (!client->timeout) {
struct ev_timer *timeout = scalloc(1, sizeof(struct ev_timer));
ev_timer_init(timeout, ipc_client_timeout, kill_timeout, 0.);
timeout->data = client;
client->timeout = timeout;
ev_set_priority(timeout, EV_MINPRI);
ev_timer_start(main_loop, client->timeout);
} else if (result > 0) {
/* Keep the old timeout when nothing is written. Otherwise, we would
* keep a dead connection by continuously renewing its timeouts. */
ev_timer_stop(main_loop, client->timeout);
ev_timer_set(client->timeout, kill_timeout, 0.0);
ev_timer_start(main_loop, client->timeout);
}
if (result == 0) {
return;
}
/* Shift the buffer to the left and reduce the allocated space. */
client->buffer_size -= (size_t)result;
memmove(client->buffer, client->buffer + result, client->buffer_size);
client->buffer = srealloc(client->buffer, client->buffer_size);
}
/*
* Given a message and a message type, create the corresponding header, merge it
* with the message and append it to the given client's output buffer. Also,
* send the message if the client's buffer was empty.
*
*/
static void ipc_send_client_message(ipc_client *client, size_t size, const uint32_t message_type, const uint8_t *payload) {
const i3_ipc_header_t header = {
.magic = {'i', '3', '-', 'i', 'p', 'c'},
.size = size,
.type = message_type};
const size_t header_size = sizeof(i3_ipc_header_t);
const size_t message_size = header_size + size;
const bool push_now = (client->buffer_size == 0);
client->buffer = srealloc(client->buffer, client->buffer_size + message_size);
memcpy(client->buffer + client->buffer_size, ((void *)&header), header_size);
memcpy(client->buffer + client->buffer_size + header_size, payload, size);
client->buffer_size += message_size;
if (push_now) {
ipc_push_pending(client);
}
}
static void free_ipc_client(ipc_client *client, int exempt_fd) {
if (client->fd != exempt_fd) {
DLOG("Disconnecting client on fd %d\n", client->fd);
close(client->fd);
}
ev_io_stop(main_loop, client->read_callback);
FREE(client->read_callback);
ev_io_stop(main_loop, client->write_callback);
FREE(client->write_callback);
if (client->timeout) {
ev_timer_stop(main_loop, client->timeout);
FREE(client->timeout);
}
free(client->buffer);
for (int i = 0; i < client->num_events; i++) {
free(client->events[i]);
}
free(client->events);
TAILQ_REMOVE(&all_clients, client, clients);
free(client);
}
/*
* Sends the specified event to all IPC clients which are currently connected
* and subscribed to this kind of event.
*
*/
void ipc_send_event(const char *event, uint32_t message_type, const char *payload) {
2010-11-21 22:03:55 +01:00
ipc_client *current;
TAILQ_FOREACH (current, &all_clients, clients) {
2010-11-21 22:03:55 +01:00
for (int i = 0; i < current->num_events; i++) {
if (strcasecmp(current->events[i], event) == 0) {
ipc_send_client_message(current, strlen(payload), message_type, (uint8_t *)payload);
break;
}
}
2010-11-21 22:03:55 +01:00
}
}
/*
* For shutdown events, we send the reason for the shutdown.
*/
static void ipc_send_shutdown_event(shutdown_reason_t reason) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
if (reason == SHUTDOWN_REASON_RESTART) {
ystr("restart");
} else if (reason == SHUTDOWN_REASON_EXIT) {
ystr("exit");
}
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("shutdown", I3_IPC_EVENT_SHUTDOWN, (const char *)payload);
y(free);
}
/*
* Calls shutdown() on each socket and closes it. This function is to be called
* when exiting or restarting only!
*
* exempt_fd is never closed. Set to -1 to close all fds.
*
*/
void ipc_shutdown(shutdown_reason_t reason, int exempt_fd) {
ipc_send_shutdown_event(reason);
2010-11-21 22:03:55 +01:00
ipc_client *current;
while (!TAILQ_EMPTY(&all_clients)) {
current = TAILQ_FIRST(&all_clients);
if (current->fd != exempt_fd) {
shutdown(current->fd, SHUT_RDWR);
}
free_ipc_client(current, exempt_fd);
2010-11-21 22:03:55 +01:00
}
}
/*
2020-04-10 16:41:36 +02:00
* Executes the given command.
*
*/
IPC_HANDLER(run_command) {
2010-11-21 22:03:55 +01:00
/* To get a properly terminated buffer, we copy
* message_size bytes out of the buffer */
char *command = sstrndup((const char *)message, message_size);
LOG("IPC: received: *%.4000s*\n", command);
yajl_gen gen = yajl_gen_alloc(NULL);
CommandResult *result = parse_command(command, gen, client);
2010-11-21 22:03:55 +01:00
free(command);
if (result->needs_tree_render)
tree_render();
command_result_free(result);
const unsigned char *reply;
ylength length;
yajl_gen_get_buf(gen, &reply, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_COMMAND,
(const uint8_t *)reply);
yajl_gen_free(gen);
}
static void dump_rect(yajl_gen gen, const char *name, Rect r) {
ystr(name);
y(map_open);
ystr("x");
y(integer, r.x);
ystr("y");
y(integer, r.y);
ystr("width");
y(integer, r.width);
ystr("height");
y(integer, r.height);
y(map_close);
}
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
static void dump_event_state_mask(yajl_gen gen, Binding *bind) {
y(array_open);
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
for (int i = 0; i < 20; i++) {
if (bind->event_state_mask & (1 << i)) {
switch (1 << i) {
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_SHIFT:
ystr("shift");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_LOCK:
ystr("lock");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_CONTROL:
ystr("ctrl");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_MOD_1:
ystr("Mod1");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_MOD_2:
ystr("Mod2");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_MOD_3:
ystr("Mod3");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_MOD_4:
ystr("Mod4");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_MOD_5:
ystr("Mod5");
break;
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
case XCB_KEY_BUT_MASK_BUTTON_1:
ystr("Button1");
break;
case XCB_KEY_BUT_MASK_BUTTON_2:
ystr("Button2");
break;
case XCB_KEY_BUT_MASK_BUTTON_3:
ystr("Button3");
break;
case XCB_KEY_BUT_MASK_BUTTON_4:
ystr("Button4");
break;
case XCB_KEY_BUT_MASK_BUTTON_5:
ystr("Button5");
break;
case (I3_XKB_GROUP_MASK_1 << 16):
ystr("Group1");
break;
case (I3_XKB_GROUP_MASK_2 << 16):
ystr("Group2");
break;
case (I3_XKB_GROUP_MASK_3 << 16):
ystr("Group3");
break;
case (I3_XKB_GROUP_MASK_4 << 16):
ystr("Group4");
break;
}
}
}
y(array_close);
Use libxkbcommon for translating keysyms, support all XKB groups. fixes #1835 This commit improves the translation of keysyms to keycodes by loading keymaps using libxkbcommon-x11 and using libxkbcommon for figuring out the keymap, depending on each keybinding’s modifiers. This way, the upper layers of complex layouts are now usable with i3’s bindsym directive, such as de_neo’s layer 3 and higher. Furthermore, the commit generalizes the handling of different XKB groups. We formerly had support only for two separate groups, the default group 1, and group 2. While Mode_switch is only one way to switch to group 2, we called the binding option Mode_switch. With this commit, the new names Group1, Group2 (an alias for Mode_switch), Group3 and Group4 are introduced for configuring bindings. This is only useful for advanced keyboard layouts, such as people loading two keyboard layouts and switching between them (us, ru seems to be a popular combination). When grabbing keys, one can only specify the modifier mask, but not an XKB state mask (or value), so we still dynamically unbind and re-bind keys whenever the XKB group changes. The commit was manually tested using the following i3 config: bindsym Group4+n nop heya from group 4 bindsym Group3+n nop heya from group 3 bindsym Group2+n nop heya from group 2 bindsym n nop heya bindsym shift+N nop explicit shift binding bindsym shift+r nop implicit shift binding bindcode Group2+38 nop fallback overwritten in group 2 only bindcode 38 nop fallback …with the following layout: setxkbmap -layout "us,ua,ru,de" -variant ",winkeys,,neo" \ -option "grp:shift_caps_toggle,grp_led:scroll" \ -model pc104 -rules evdev By default (xkb group 1, us layout), pressing “n” will result in the “heya” message appearing. Pressing “a” will result in the “fallback” message appearing. “j” is not triggered. By pressing Shift+CapsLock you switch to the next group (xkb group 2, ua layout). Pressing “a” will result in the “fallback overwritten in group 2 only” message, pressing “n” will still result in “heya”. “j” is not triggered. In the next group (xkb group 3, ru layout), pressing “a” will result in the “fallback” message again, pressing “n” will result in “heya”, “j” is not triggered. In the last group (xkb group 4, de_neo layout), pressing “a” will still result in “fallback”, pressing “n” will result in “heya”, pressing “j” will result in “heya from group 4”. Pressing shift+n results in “explicit shift binding”, pressing shift+r results in “implicit shift binding”. This ensures that keysym translation falls back to looking at non-shift keys (“r” can be used instead of ”R”) and that the order of keybindings doesn’t play a role (“bindsym n” does not override “bindsym shift+n”, even though it’s specified earlier in the config). The fallback behavior ensures use-cases such as ticket #1775 are still covered. Only binding keys when the X server is in the corresponding XKB group ensures use-cases such as ticket #585 are still covered.
2015-08-23 22:49:32 +02:00
}
static void dump_binding(yajl_gen gen, Binding *bind) {
y(map_open);
ystr("input_code");
y(integer, bind->keycode);
ystr("input_type");
ystr((const char *)(bind->input_type == B_KEYBOARD ? "keyboard" : "mouse"));
ystr("symbol");
if (bind->symbol == NULL)
y(null);
else
ystr(bind->symbol);
ystr("command");
ystr(bind->command);
// This key is only provided for compatibility, new programs should use
// event_state_mask instead.
ystr("mods");
dump_event_state_mask(gen, bind);
ystr("event_state_mask");
dump_event_state_mask(gen, bind);
y(map_close);
}
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
2010-11-21 22:03:55 +01:00
y(map_open);
ystr("id");
y(integer, (uintptr_t)con);
2010-11-21 22:03:55 +01:00
ystr("type");
switch (con->type) {
case CT_ROOT:
ystr("root");
break;
case CT_OUTPUT:
ystr("output");
break;
case CT_CON:
ystr("con");
break;
case CT_FLOATING_CON:
ystr("floating_con");
break;
case CT_WORKSPACE:
ystr("workspace");
break;
case CT_DOCKAREA:
ystr("dockarea");
break;
}
Introduce splith/splitv layouts, remove orientation With this commit, the "default" layout is replaced by the splith and splitv layouts. splith is equivalent to default with orientation horizontal and splitv is equivalent to default with orientation vertical. The "split h" and "split v" commands continue to work as before, they split the current container and you will end up in a split container with layout splith (after "split h") or splitv (after "split v"). To change a splith container into a splitv container, use either "layout splitv" or "layout toggle split". The latter command is used in the default config as mod+l (previously "layout default"). In case you have "layout default" in your config file, it is recommended to just replace it by "layout toggle split", which will work as "layout default" did before when pressing it once, but toggle between horizontal/vertical when pressing it repeatedly. The rationale behind this commit is that it’s cleaner to have all parameters that influence how windows are rendered in the layout itself rather than having a special parameter in combination with only one layout. This enables us to change existing split containers in all cases without breaking existing features (see ticket #464). Also, users should feel more confident about whether they are actually splitting or just changing an existing split container now. As a nice side-effect, this commit brings back the "layout toggle" feature we once had in i3 version 3 (see the userguide). AFAIK, it is safe to use in-place restart to upgrade into versions after this commit (switching to an older version will break your layout, though). Fixes #464
2012-08-04 03:04:00 +02:00
/* provided for backwards compatibility only. */
2010-11-21 22:03:55 +01:00
ystr("orientation");
if (!con_is_split(con))
Introduce splith/splitv layouts, remove orientation With this commit, the "default" layout is replaced by the splith and splitv layouts. splith is equivalent to default with orientation horizontal and splitv is equivalent to default with orientation vertical. The "split h" and "split v" commands continue to work as before, they split the current container and you will end up in a split container with layout splith (after "split h") or splitv (after "split v"). To change a splith container into a splitv container, use either "layout splitv" or "layout toggle split". The latter command is used in the default config as mod+l (previously "layout default"). In case you have "layout default" in your config file, it is recommended to just replace it by "layout toggle split", which will work as "layout default" did before when pressing it once, but toggle between horizontal/vertical when pressing it repeatedly. The rationale behind this commit is that it’s cleaner to have all parameters that influence how windows are rendered in the layout itself rather than having a special parameter in combination with only one layout. This enables us to change existing split containers in all cases without breaking existing features (see ticket #464). Also, users should feel more confident about whether they are actually splitting or just changing an existing split container now. As a nice side-effect, this commit brings back the "layout toggle" feature we once had in i3 version 3 (see the userguide). AFAIK, it is safe to use in-place restart to upgrade into versions after this commit (switching to an older version will break your layout, though). Fixes #464
2012-08-04 03:04:00 +02:00
ystr("none");
else {
if (con_orientation(con) == HORIZ)
ystr("horizontal");
else
ystr("vertical");
}
ystr("scratchpad_state");
switch (con->scratchpad_state) {
case SCRATCHPAD_NONE:
ystr("none");
break;
case SCRATCHPAD_FRESH:
ystr("fresh");
break;
case SCRATCHPAD_CHANGED:
ystr("changed");
break;
}
ystr("percent");
if (con->percent == 0.0)
y(null);
else
y(double, con->percent);
2010-11-21 22:03:55 +01:00
ystr("urgent");
2011-07-24 14:54:30 +02:00
y(bool, con->urgent);
ystr("marks");
y(array_open);
mark_t *mark;
TAILQ_FOREACH (mark, &(con->marks_head), marks) {
ystr(mark->name);
2011-08-07 18:42:23 +02:00
}
y(array_close);
2011-08-07 18:42:23 +02:00
2010-11-21 22:03:55 +01:00
ystr("focused");
2011-07-24 15:00:09 +02:00
y(bool, (con == focused));
if (con->type != CT_ROOT && con->type != CT_OUTPUT) {
ystr("output");
ystr(con_get_output(con)->name);
}
2010-11-21 22:03:55 +01:00
ystr("layout");
2011-06-02 17:12:18 +02:00
switch (con->layout) {
case L_DEFAULT:
Introduce splith/splitv layouts, remove orientation With this commit, the "default" layout is replaced by the splith and splitv layouts. splith is equivalent to default with orientation horizontal and splitv is equivalent to default with orientation vertical. The "split h" and "split v" commands continue to work as before, they split the current container and you will end up in a split container with layout splith (after "split h") or splitv (after "split v"). To change a splith container into a splitv container, use either "layout splitv" or "layout toggle split". The latter command is used in the default config as mod+l (previously "layout default"). In case you have "layout default" in your config file, it is recommended to just replace it by "layout toggle split", which will work as "layout default" did before when pressing it once, but toggle between horizontal/vertical when pressing it repeatedly. The rationale behind this commit is that it’s cleaner to have all parameters that influence how windows are rendered in the layout itself rather than having a special parameter in combination with only one layout. This enables us to change existing split containers in all cases without breaking existing features (see ticket #464). Also, users should feel more confident about whether they are actually splitting or just changing an existing split container now. As a nice side-effect, this commit brings back the "layout toggle" feature we once had in i3 version 3 (see the userguide). AFAIK, it is safe to use in-place restart to upgrade into versions after this commit (switching to an older version will break your layout, though). Fixes #464
2012-08-04 03:04:00 +02:00
DLOG("About to dump layout=default, this is a bug in the code.\n");
assert(false);
break;
case L_SPLITV:
ystr("splitv");
break;
case L_SPLITH:
ystr("splith");
2011-06-02 17:12:18 +02:00
break;
case L_STACKED:
ystr("stacked");
break;
case L_TABBED:
ystr("tabbed");
break;
case L_DOCKAREA:
ystr("dockarea");
break;
case L_OUTPUT:
ystr("output");
break;
}
ystr("workspace_layout");
switch (con->workspace_layout) {
case L_DEFAULT:
ystr("default");
break;
case L_STACKED:
ystr("stacked");
break;
case L_TABBED:
ystr("tabbed");
break;
default:
DLOG("About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
assert(false);
break;
}
Introduce splith/splitv layouts, remove orientation With this commit, the "default" layout is replaced by the splith and splitv layouts. splith is equivalent to default with orientation horizontal and splitv is equivalent to default with orientation vertical. The "split h" and "split v" commands continue to work as before, they split the current container and you will end up in a split container with layout splith (after "split h") or splitv (after "split v"). To change a splith container into a splitv container, use either "layout splitv" or "layout toggle split". The latter command is used in the default config as mod+l (previously "layout default"). In case you have "layout default" in your config file, it is recommended to just replace it by "layout toggle split", which will work as "layout default" did before when pressing it once, but toggle between horizontal/vertical when pressing it repeatedly. The rationale behind this commit is that it’s cleaner to have all parameters that influence how windows are rendered in the layout itself rather than having a special parameter in combination with only one layout. This enables us to change existing split containers in all cases without breaking existing features (see ticket #464). Also, users should feel more confident about whether they are actually splitting or just changing an existing split container now. As a nice side-effect, this commit brings back the "layout toggle" feature we once had in i3 version 3 (see the userguide). AFAIK, it is safe to use in-place restart to upgrade into versions after this commit (switching to an older version will break your layout, though). Fixes #464
2012-08-04 03:04:00 +02:00
ystr("last_split_layout");
switch (con->layout) {
case L_SPLITV:
ystr("splitv");
break;
default:
ystr("splith");
break;
}
2010-11-21 22:03:55 +01:00
ystr("border");
switch (con->border_style) {
case BS_NORMAL:
ystr("normal");
break;
case BS_NONE:
ystr("none");
break;
case BS_PIXEL:
ystr("pixel");
break;
}
2010-11-12 19:16:38 +01:00
ystr("current_border_width");
y(integer, con->current_border_width);
dump_rect(gen, "rect", con->rect);
dump_rect(gen, "deco_rect", con->deco_rect);
dump_rect(gen, "window_rect", con->window_rect);
dump_rect(gen, "geometry", con->geometry);
2010-11-21 22:03:55 +01:00
ystr("name");
if (con->window && con->window->name)
ystr(i3string_as_utf8(con->window->name));
else if (con->name != NULL)
ystr(con->name);
else
y(null);
if (con->title_format != NULL) {
ystr("title_format");
ystr(con->title_format);
}
if (con->type == CT_WORKSPACE) {
ystr("num");
y(integer, con->num);
}
2010-11-21 22:03:55 +01:00
ystr("window");
if (con->window)
y(integer, con->window->id);
else
y(null);
2019-09-20 07:58:15 +02:00
ystr("window_type");
if (con->window) {
if (con->window->window_type == A__NET_WM_WINDOW_TYPE_NORMAL) {
ystr("normal");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DOCK) {
ystr("dock");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DIALOG) {
ystr("dialog");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_UTILITY) {
ystr("utility");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_TOOLBAR) {
ystr("toolbar");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_SPLASH) {
ystr("splash");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_MENU) {
ystr("menu");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) {
ystr("dropdown_menu");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_POPUP_MENU) {
ystr("popup_menu");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_TOOLTIP) {
ystr("tooltip");
} else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_NOTIFICATION) {
ystr("notification");
} else {
ystr("unknown");
}
} else
y(null);
if (con->window && !inplace_restart) {
/* Window properties are useless to preserve when restarting because
* they will be queried again anyway. However, for i3-save-tree(1),
* they are very useful and save i3-save-tree dealing with X11. */
ystr("window_properties");
y(map_open);
#define DUMP_PROPERTY(key, prop_name) \
do { \
if (con->window->prop_name != NULL) { \
ystr(key); \
ystr(con->window->prop_name); \
} \
} while (0)
DUMP_PROPERTY("class", class_class);
DUMP_PROPERTY("instance", class_instance);
DUMP_PROPERTY("window_role", role);
if (con->window->name != NULL) {
ystr("title");
ystr(i3string_as_utf8(con->window->name));
}
ystr("transient_for");
if (con->window->transient_for == XCB_NONE)
y(null);
else
y(integer, con->window->transient_for);
y(map_close);
}
2010-11-21 22:03:55 +01:00
ystr("nodes");
y(array_open);
Con *node;
if (con->type != CT_DOCKAREA || !inplace_restart) {
TAILQ_FOREACH (node, &(con->nodes_head), nodes) {
dump_node(gen, node, inplace_restart);
}
2010-11-21 22:03:55 +01:00
}
y(array_close);
ystr("floating_nodes");
y(array_open);
TAILQ_FOREACH (node, &(con->floating_head), floating_windows) {
2010-11-21 22:03:55 +01:00
dump_node(gen, node, inplace_restart);
}
y(array_close);
ystr("focus");
y(array_open);
TAILQ_FOREACH (node, &(con->focus_head), focused) {
y(integer, (uintptr_t)node);
2010-11-21 22:03:55 +01:00
}
y(array_close);
ystr("fullscreen_mode");
y(integer, con->fullscreen_mode);
ystr("sticky");
y(bool, con->sticky);
ystr("floating");
switch (con->floating) {
case FLOATING_AUTO_OFF:
ystr("auto_off");
break;
case FLOATING_AUTO_ON:
ystr("auto_on");
break;
case FLOATING_USER_OFF:
ystr("user_off");
break;
case FLOATING_USER_ON:
ystr("user_on");
break;
}
ystr("swallows");
y(array_open);
Match *match;
TAILQ_FOREACH (match, &(con->swallow_head), matches) {
/* We will generate a new restart_mode match specification after this
* loop, so skip this one. */
if (match->restart_mode)
continue;
2014-01-05 20:30:03 +01:00
y(map_open);
if (match->dock != M_DONTCHECK) {
ystr("dock");
y(integer, match->dock);
ystr("insert_where");
y(integer, match->insert_where);
}
#define DUMP_REGEX(re_name) \
do { \
if (match->re_name != NULL) { \
ystr(#re_name); \
ystr(match->re_name->pattern); \
} \
} while (0)
2014-01-05 20:30:03 +01:00
DUMP_REGEX(class);
DUMP_REGEX(instance);
DUMP_REGEX(window_role);
DUMP_REGEX(title);
#undef DUMP_REGEX
y(map_close);
}
2010-11-21 22:03:55 +01:00
if (inplace_restart) {
if (con->window != NULL) {
y(map_open);
ystr("id");
y(integer, con->window->id);
ystr("restart_mode");
y(bool, true);
2010-11-21 22:03:55 +01:00
y(map_close);
}
2010-11-21 22:03:55 +01:00
}
y(array_close);
if (inplace_restart && con->window != NULL) {
ystr("depth");
y(integer, con->depth);
}
if (inplace_restart && con->type == CT_ROOT && previous_workspace_name) {
ystr("previous_workspace_name");
ystr(previous_workspace_name);
}
2010-11-21 22:03:55 +01:00
y(map_close);
}
static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
if (TAILQ_EMPTY(&(config->bar_bindings)))
return;
ystr("bindings");
y(array_open);
struct Barbinding *current;
TAILQ_FOREACH (current, &(config->bar_bindings), bindings) {
y(map_open);
ystr("input_code");
y(integer, current->input_code);
ystr("command");
ystr(current->command);
ystr("release");
y(bool, current->release == B_UPON_KEYRELEASE);
y(map_close);
}
y(array_close);
}
static char *canonicalize_output_name(char *name) {
/* Do not canonicalize special output names. */
if (strcasecmp(name, "primary") == 0) {
return name;
}
Output *output = get_output_by_name(name, false);
return output ? output_primary_name(output) : name;
}
static void dump_bar_config(yajl_gen gen, Barconfig *config) {
y(map_open);
ystr("id");
ystr(config->id);
if (config->num_outputs > 0) {
ystr("outputs");
y(array_open);
for (int c = 0; c < config->num_outputs; c++) {
/* Convert monitor names (RandR ≥ 1.5) or output names
* (RandR < 1.5) into monitor names. This way, existing
* configs which use output names transparently keep
* working. */
ystr(canonicalize_output_name(config->outputs[c]));
}
y(array_close);
}
if (!TAILQ_EMPTY(&(config->tray_outputs))) {
ystr("tray_outputs");
y(array_open);
struct tray_output_t *tray_output;
TAILQ_FOREACH (tray_output, &(config->tray_outputs), tray_outputs) {
ystr(canonicalize_output_name(tray_output->output));
}
y(array_close);
}
#define YSTR_IF_SET(name) \
do { \
if (config->name) { \
ystr(#name); \
ystr(config->name); \
} \
} while (0)
2015-06-09 10:06:45 +02:00
ystr("tray_padding");
y(integer, config->tray_padding);
YSTR_IF_SET(socket_path);
ystr("mode");
switch (config->mode) {
case M_HIDE:
ystr("hide");
break;
case M_INVISIBLE:
ystr("invisible");
break;
case M_DOCK:
default:
ystr("dock");
break;
}
ystr("hidden_state");
switch (config->hidden_state) {
case S_SHOW:
ystr("show");
break;
case S_HIDE:
default:
ystr("hide");
break;
}
ystr("modifier");
y(integer, config->modifier);
dump_bar_bindings(gen, config);
ystr("position");
if (config->position == P_BOTTOM)
ystr("bottom");
else
ystr("top");
YSTR_IF_SET(status_command);
YSTR_IF_SET(font);
if (config->separator_symbol) {
ystr("separator_symbol");
ystr(config->separator_symbol);
}
ystr("workspace_buttons");
y(bool, !config->hide_workspace_buttons);
ystr("workspace_min_width");
y(integer, config->workspace_min_width);
ystr("strip_workspace_numbers");
y(bool, config->strip_workspace_numbers);
ystr("strip_workspace_name");
y(bool, config->strip_workspace_name);
ystr("binding_mode_indicator");
y(bool, !config->hide_binding_mode_indicator);
ystr("verbose");
y(bool, config->verbose);
#undef YSTR_IF_SET
#define YSTR_IF_SET(name) \
do { \
if (config->colors.name) { \
ystr(#name); \
ystr(config->colors.name); \
} \
} while (0)
ystr("colors");
y(map_open);
YSTR_IF_SET(background);
YSTR_IF_SET(statusline);
YSTR_IF_SET(separator);
YSTR_IF_SET(focused_background);
YSTR_IF_SET(focused_statusline);
YSTR_IF_SET(focused_separator);
YSTR_IF_SET(focused_workspace_border);
YSTR_IF_SET(focused_workspace_bg);
YSTR_IF_SET(focused_workspace_text);
YSTR_IF_SET(active_workspace_border);
YSTR_IF_SET(active_workspace_bg);
YSTR_IF_SET(active_workspace_text);
YSTR_IF_SET(inactive_workspace_border);
YSTR_IF_SET(inactive_workspace_bg);
YSTR_IF_SET(inactive_workspace_text);
YSTR_IF_SET(urgent_workspace_border);
YSTR_IF_SET(urgent_workspace_bg);
YSTR_IF_SET(urgent_workspace_text);
YSTR_IF_SET(binding_mode_border);
YSTR_IF_SET(binding_mode_bg);
YSTR_IF_SET(binding_mode_text);
y(map_close);
y(map_close);
#undef YSTR_IF_SET
}
IPC_HANDLER(tree) {
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
2010-11-21 22:03:55 +01:00
dump_node(gen, croot, false);
setlocale(LC_NUMERIC, "");
2010-11-21 22:03:55 +01:00
const unsigned char *payload;
ylength length;
2010-11-21 22:03:55 +01:00
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_TREE, payload);
2010-11-21 22:03:55 +01:00
y(free);
}
/*
* Formats the reply message for a GET_WORKSPACES request and sends it to the
* client
*
*/
IPC_HANDLER(get_workspaces) {
yajl_gen gen = ygenalloc();
y(array_open);
Con *focused_ws = con_get_workspace(focused);
Con *output;
TAILQ_FOREACH (output, &(croot->nodes_head), nodes) {
if (con_is_internal(output))
continue;
Con *ws;
TAILQ_FOREACH (ws, &(output_get_content(output)->nodes_head), nodes) {
assert(ws->type == CT_WORKSPACE);
y(map_open);
ystr("id");
y(integer, (uintptr_t)ws);
ystr("num");
y(integer, ws->num);
ystr("name");
ystr(ws->name);
ystr("visible");
y(bool, workspace_is_visible(ws));
ystr("focused");
y(bool, ws == focused_ws);
ystr("rect");
y(map_open);
ystr("x");
y(integer, ws->rect.x);
ystr("y");
y(integer, ws->rect.y);
ystr("width");
y(integer, ws->rect.width);
ystr("height");
y(integer, ws->rect.height);
y(map_close);
ystr("output");
ystr(output->name);
ystr("urgent");
y(bool, ws->urgent);
y(map_close);
}
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
y(free);
}
2010-03-19 22:24:52 +01:00
/*
* Formats the reply message for a GET_OUTPUTS request and sends it to the
* client
*
*/
IPC_HANDLER(get_outputs) {
yajl_gen gen = ygenalloc();
y(array_open);
2010-03-19 22:24:52 +01:00
Output *output;
TAILQ_FOREACH (output, &outputs, outputs) {
y(map_open);
2010-03-19 22:24:52 +01:00
ystr("name");
ystr(output_primary_name(output));
2010-03-19 22:24:52 +01:00
ystr("active");
y(bool, output->active);
2010-03-19 22:24:52 +01:00
ystr("primary");
y(bool, output->primary);
ystr("rect");
y(map_open);
ystr("x");
y(integer, output->rect.x);
ystr("y");
y(integer, output->rect.y);
ystr("width");
y(integer, output->rect.width);
ystr("height");
y(integer, output->rect.height);
y(map_close);
2010-03-19 22:24:52 +01:00
ystr("current_workspace");
2010-11-21 22:12:34 +01:00
Con *ws = NULL;
2011-06-10 18:27:20 +02:00
if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
2010-11-21 22:12:34 +01:00
ystr(ws->name);
else
y(null);
y(map_close);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
y(free);
2010-03-19 22:24:52 +01:00
}
2011-08-06 20:23:18 +02:00
/*
* Formats the reply message for a GET_MARKS request and sends it to the
* client
*
*/
IPC_HANDLER(get_marks) {
yajl_gen gen = ygenalloc();
2011-08-06 20:23:18 +02:00
y(array_open);
Con *con;
TAILQ_FOREACH (con, &all_cons, all_cons) {
mark_t *mark;
TAILQ_FOREACH (mark, &(con->marks_head), marks) {
ystr(mark->name);
}
}
2011-08-06 20:23:18 +02:00
y(array_close);
const unsigned char *payload;
ylength length;
2011-08-06 20:23:18 +02:00
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_MARKS, payload);
2011-08-06 20:23:18 +02:00
y(free);
}
/*
* Returns the version of i3
*
*/
IPC_HANDLER(get_version) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("major");
y(integer, MAJOR_VERSION);
ystr("minor");
y(integer, MINOR_VERSION);
ystr("patch");
y(integer, PATCH_VERSION);
ystr("human_readable");
ystr(i3_version);
ystr("loaded_config_file_name");
ystr(current_configpath);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_VERSION, payload);
y(free);
}
/*
* Formats the reply message for a GET_BAR_CONFIG request and sends it to the
* client.
*
*/
IPC_HANDLER(get_bar_config) {
yajl_gen gen = ygenalloc();
/* If no ID was passed, we return a JSON array with all IDs */
if (message_size == 0) {
y(array_open);
Barconfig *current;
TAILQ_FOREACH (current, &barconfigs, configs) {
ystr(current->id);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
y(free);
return;
}
/* To get a properly terminated buffer, we copy
* message_size bytes out of the buffer */
char *bar_id = NULL;
sasprintf(&bar_id, "%.*s", message_size, message);
LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id);
Barconfig *current, *config = NULL;
TAILQ_FOREACH (current, &barconfigs, configs) {
if (strcmp(current->id, bar_id) != 0)
continue;
config = current;
break;
}
free(bar_id);
if (!config) {
/* If we did not find a config for the given ID, the reply will contain
* a null 'id' field. */
y(map_open);
ystr("id");
y(null);
y(map_close);
} else {
dump_bar_config(gen, config);
}
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
y(free);
}
/*
* Returns a list of configured binding modes
*
*/
IPC_HANDLER(get_binding_modes) {
yajl_gen gen = ygenalloc();
y(array_open);
struct Mode *mode;
SLIST_FOREACH (mode, &modes, modes) {
ystr(mode->name);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BINDING_MODES, payload);
y(free);
}
/*
* Callback for the YAJL parser (will be called when a string is parsed).
*
*/
static int add_subscription(void *extra, const unsigned char *s,
ylength len) {
2010-11-21 22:03:55 +01:00
ipc_client *client = extra;
DLOG("should add subscription to extra %p, sub %.*s\n", client, (int)len, s);
2010-11-21 22:03:55 +01:00
int event = client->num_events;
2010-11-21 22:03:55 +01:00
client->num_events++;
2015-08-03 11:50:50 +02:00
client->events = srealloc(client->events, client->num_events * sizeof(char *));
2010-11-21 22:03:55 +01:00
/* We copy the string because it is not null-terminated and strndup()
* is missing on some BSD systems */
client->events[event] = scalloc(len + 1, 1);
2010-11-21 22:03:55 +01:00
memcpy(client->events[event], s, len);
2010-11-21 22:03:55 +01:00
DLOG("client is now subscribed to:\n");
for (int i = 0; i < client->num_events; i++) {
2010-11-21 22:03:55 +01:00
DLOG("event %s\n", client->events[i]);
}
2010-11-21 22:03:55 +01:00
DLOG("(done)\n");
2010-11-21 22:03:55 +01:00
return 1;
}
/*
* Subscribes this connection to the event types which were given as a JSON
* serialized array in the payload field of the message.
*
*/
IPC_HANDLER(subscribe) {
2010-11-21 22:03:55 +01:00
yajl_handle p;
yajl_status stat;
2010-11-21 22:03:55 +01:00
/* Setup the JSON parser */
static yajl_callbacks callbacks = {
.yajl_string = add_subscription,
};
p = yalloc(&callbacks, (void *)client);
stat = yajl_parse(p, (const unsigned char *)message, message_size);
2010-11-21 22:03:55 +01:00
if (stat != yajl_status_ok) {
unsigned char *err;
err = yajl_get_error(p, true, (const unsigned char *)message,
2010-11-21 22:03:55 +01:00
message_size);
ELOG("YAJL parse error: %s\n", err);
yajl_free_error(p, err);
2010-11-21 22:03:55 +01:00
const char *reply = "{\"success\":false}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
2010-11-21 22:03:55 +01:00
yajl_free(p);
return;
}
yajl_free(p);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
if (client->first_tick_sent) {
return;
}
bool is_tick = false;
for (int i = 0; i < client->num_events; i++) {
if (strcmp(client->events[i], "tick") == 0) {
is_tick = true;
break;
}
}
if (!is_tick) {
return;
}
client->first_tick_sent = true;
const char *payload = "{\"first\":true,\"payload\":\"\"}";
ipc_send_client_message(client, strlen(payload), I3_IPC_EVENT_TICK, (const uint8_t *)payload);
}
/*
* Returns the raw last loaded i3 configuration file contents.
*/
IPC_HANDLER(get_config) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("config");
ystr(current_config);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_CONFIG, payload);
y(free);
}
/*
* Sends the tick event from the message payload to subscribers. Establishes a
* synchronization point in event-related tests.
*/
IPC_HANDLER(send_tick) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("first");
y(bool, false);
ystr("payload");
yajl_gen_string(gen, (unsigned char *)message, message_size);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("tick", I3_IPC_EVENT_TICK, (const char *)payload);
y(free);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (const uint8_t *)reply);
DLOG("Sent tick event\n");
}
struct sync_state {
char *last_key;
uint32_t rnd;
xcb_window_t window;
};
static int _sync_json_key(void *extra, const unsigned char *val, size_t len) {
struct sync_state *state = extra;
FREE(state->last_key);
state->last_key = scalloc(len + 1, 1);
memcpy(state->last_key, val, len);
return 1;
}
static int _sync_json_int(void *extra, long long val) {
struct sync_state *state = extra;
if (strcasecmp(state->last_key, "rnd") == 0) {
state->rnd = val;
} else if (strcasecmp(state->last_key, "window") == 0) {
state->window = (xcb_window_t)val;
}
return 1;
}
IPC_HANDLER(sync) {
yajl_handle p;
yajl_status stat;
/* Setup the JSON parser */
static yajl_callbacks callbacks = {
.yajl_map_key = _sync_json_key,
.yajl_integer = _sync_json_int,
};
struct sync_state state;
memset(&state, '\0', sizeof(struct sync_state));
p = yalloc(&callbacks, (void *)&state);
stat = yajl_parse(p, (const unsigned char *)message, message_size);
FREE(state.last_key);
if (stat != yajl_status_ok) {
unsigned char *err;
err = yajl_get_error(p, true, (const unsigned char *)message,
message_size);
ELOG("YAJL parse error: %s\n", err);
yajl_free_error(p, err);
const char *reply = "{\"success\":false}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
yajl_free(p);
return;
}
yajl_free(p);
DLOG("received IPC sync request (rnd = %d, window = 0x%08x)\n", state.rnd, state.window);
sync_respond(state.window, state.rnd);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
}
2010-03-19 22:24:52 +01:00
/* The index of each callback function corresponds to the numeric
* value of the message type (see include/i3/ipc.h) */
handler_t handlers[12] = {
handle_run_command,
2010-11-21 22:03:55 +01:00
handle_get_workspaces,
handle_subscribe,
handle_get_outputs,
2011-08-06 20:23:18 +02:00
handle_tree,
handle_get_marks,
handle_get_bar_config,
handle_get_version,
handle_get_binding_modes,
handle_get_config,
handle_send_tick,
handle_sync,
};
/*
* Handler for activity on a client connection, receives a message from a
* client.
*
* For now, the maximum message size is 2048. Im not sure for what the
* IPC interface will be used in the future, thus Im not implementing a
* mechanism for arbitrarily long messages, as it seems like overkill
* at the moment.
*
*/
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
uint32_t message_type;
uint32_t message_length;
uint8_t *message = NULL;
ipc_client *client = (ipc_client *)w->data;
assert(client->fd == w->fd);
int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message);
/* EOF or other error */
if (ret < 0) {
/* Was this a spurious read? See ev(3) */
if (ret == -1 && errno == EAGAIN) {
FREE(message);
return;
}
2018-04-23 00:02:44 +02:00
/* If not, there was some kind of error. We dont bother and close the
* connection. Delete the client from the list of clients. */
free_ipc_client(client, -1);
FREE(message);
2010-11-21 22:03:55 +01:00
return;
}
if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
DLOG("Unhandled message type: %d\n", message_type);
else {
handler_t h = handlers[message_type];
h(client, message, 0, message_length, message_type);
2010-11-21 22:03:55 +01:00
}
FREE(message);
}
static void ipc_client_timeout(EV_P_ ev_timer *w, int revents) {
/* No need to be polite and check for writeability, the other callback would
* have been called by now. */
ipc_client *client = (ipc_client *)w->data;
char *cmdline = NULL;
#if defined(__linux__) && defined(SO_PEERCRED)
struct ucred peercred;
socklen_t so_len = sizeof(peercred);
if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0) {
goto end;
}
char *exepath;
sasprintf(&exepath, "/proc/%d/cmdline", peercred.pid);
int fd = open(exepath, O_RDONLY);
free(exepath);
if (fd == -1) {
goto end;
}
char buf[512] = {'\0'}; /* cut off cmdline for the error message. */
const ssize_t n = read(fd, buf, sizeof(buf));
close(fd);
if (n < 0) {
goto end;
}
for (char *walk = buf; walk < buf + n - 1; walk++) {
if (*walk == '\0') {
*walk = ' ';
}
}
cmdline = buf;
if (cmdline) {
ELOG("client %p with pid %d and cmdline '%s' on fd %d timed out, killing\n", client, peercred.pid, cmdline, client->fd);
}
end:
#endif
if (!cmdline) {
ELOG("client %p on fd %d timed out, killing\n", client, client->fd);
}
free_ipc_client(client, -1);
}
static void ipc_socket_writeable_cb(EV_P_ ev_io *w, int revents) {
DLOG("fd %d writeable\n", w->fd);
ipc_client *client = (ipc_client *)w->data;
/* If this callback is called then there should be a corresponding active
* timer. */
assert(client->timeout != NULL);
ipc_push_pending(client);
}
/*
* Handler for activity on the listening socket, meaning that a new client
* has just connected and we should accept() him. Sets up the event handler
* for activity on the new connection and inserts the file descriptor into
* the list of clients.
*
*/
void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
2010-11-21 22:03:55 +01:00
struct sockaddr_un peer;
socklen_t len = sizeof(struct sockaddr_un);
int fd;
if ((fd = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) {
if (errno != EINTR) {
perror("accept()");
}
2010-11-21 22:03:55 +01:00
return;
}
/* Close this file descriptor on exec() */
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
ipc_new_client_on_fd(EV_A_ fd);
}
/*
* ipc_new_client_on_fd() only sets up the event handler
* for activity on the new connection and inserts the file descriptor into
* the list of clients.
*
* This variant is useful for the inherited IPC connection when restarting.
*
*/
ipc_client *ipc_new_client_on_fd(EV_P_ int fd) {
set_nonblock(fd);
ipc_client *client = scalloc(1, sizeof(ipc_client));
client->fd = fd;
client->read_callback = scalloc(1, sizeof(struct ev_io));
client->read_callback->data = client;
ev_io_init(client->read_callback, ipc_receive_message, fd, EV_READ);
ev_io_start(EV_A_ client->read_callback);
client->write_callback = scalloc(1, sizeof(struct ev_io));
client->write_callback->data = client;
ev_io_init(client->write_callback, ipc_socket_writeable_cb, fd, EV_WRITE);
DLOG("IPC: new client connected on fd %d\n", fd);
TAILQ_INSERT_TAIL(&all_clients, client, clients);
return client;
}
/*
* Creates the UNIX domain socket at the given path, sets it to non-blocking
* mode, bind()s and listen()s on it.
*
*/
int ipc_create_socket(const char *filename) {
2010-11-21 22:03:55 +01:00
int sockfd;
FREE(current_socketpath);
2010-11-21 22:03:55 +01:00
char *resolved = resolve_tilde(filename);
DLOG("Creating IPC-socket at %s\n", resolved);
char *copy = sstrdup(resolved);
const char *dir = dirname(copy);
if (!path_exists(dir))
mkdirp(dir, DEFAULT_DIR_MODE);
2010-11-21 22:03:55 +01:00
free(copy);
2010-11-21 22:03:55 +01:00
/* Unlink the unix domain socket before */
unlink(resolved);
2010-11-21 22:03:55 +01:00
if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
perror("socket()");
free(resolved);
2010-11-21 22:03:55 +01:00
return -1;
}
2010-11-21 22:03:55 +01:00
(void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_LOCAL;
strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
2010-11-21 22:03:55 +01:00
perror("bind()");
free(resolved);
return -1;
}
set_nonblock(sockfd);
if (listen(sockfd, 5) < 0) {
perror("listen()");
free(resolved);
2010-11-21 22:03:55 +01:00
return -1;
}
current_socketpath = resolved;
2010-11-21 22:03:55 +01:00
return sockfd;
}
/*
* Generates a json workspace event. Returns a dynamically allocated yajl
* generator. Free with yajl_gen_free().
*/
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) {
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
ystr(change);
ystr("current");
if (current == NULL)
y(null);
else
dump_node(gen, current, false);
ystr("old");
if (old == NULL)
y(null);
else
dump_node(gen, old, false);
y(map_close);
setlocale(LC_NUMERIC, "");
return gen;
}
/*
* For the workspace events we send, along with the usual "change" field, also
* the workspace container in "current". For focus events, we send the
* previously focused workspace in "old".
*/
void ipc_send_workspace_event(const char *change, Con *current, Con *old) {
yajl_gen gen = ipc_marshal_workspace_event(change, current, old);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
y(free);
}
2014-02-22 11:52:01 +01:00
2018-04-21 12:02:14 +02:00
/*
2014-02-22 11:52:01 +01:00
* For the window events we send, along the usual "change" field,
* also the window container, in "container".
*/
void ipc_send_window_event(const char *property, Con *con) {
DLOG("Issue IPC window %s event (con = %p, window = 0x%08x)\n",
property, con, (con->window ? con->window->id : XCB_WINDOW_NONE));
2014-02-22 11:52:01 +01:00
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
ystr(property);
ystr("container");
dump_node(gen, con, false);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("window", I3_IPC_EVENT_WINDOW, (const char *)payload);
y(free);
setlocale(LC_NUMERIC, "");
}
2018-04-21 12:02:14 +02:00
/*
* For the barconfig update events, we send the serialized barconfig.
*/
void ipc_send_barconfig_update_event(Barconfig *barconfig) {
DLOG("Issue barconfig_update event for id = %s\n", barconfig->id);
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
dump_bar_config(gen, barconfig);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (const char *)payload);
y(free);
setlocale(LC_NUMERIC, "");
}
/*
* For the binding events, we send the serialized binding struct.
*/
void ipc_send_binding_event(const char *event_type, Binding *bind) {
DLOG("Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->symbol, bind->keycode);
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
ystr(event_type);
ystr("binding");
dump_binding(gen, bind);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("binding", I3_IPC_EVENT_BINDING, (const char *)payload);
y(free);
setlocale(LC_NUMERIC, "");
}
/*
* Sends a restart reply to the IPC client on the specified fd.
*/
void ipc_confirm_restart(ipc_client *client) {
DLOG("ipc_confirm_restart(fd %d)\n", client->fd);
static const char *reply = "[{\"success\":true}]";
ipc_send_client_message(
client, strlen(reply), I3_IPC_REPLY_TYPE_COMMAND,
(const uint8_t *)reply);
ipc_push_pending(client);
}